MIT 6.189 Homework 1 Programming Exercises


#1

I thought some participants might like to discuss the exercises from MIT 6.189 Homework 1. Here’s what I have for Exercise 1.5 – User input …

# hw_1_user_input.py
# May 3, 2015
first_name = raw_input("Enter your first name: ")
last_name = raw_input("Enter your first name: ")
print "Enter your date of birth:"
month = raw_input("Month? ")
day = raw_input("Day? ")
year = raw_input("Year? ")
# concatenate user input strings to output the result
print first_name + " " + last_name + " was born on " + month + " " + day + ", " + year + "."

Notice that when the the raw_input function takes input from the user, that input is considered to be a string, even if it contains all numerals, as is the case with the day and the year in this example. Because the values are strings, here, we can use the + operator to concatenate those strings, in order to compose the output.

If we wanted, instead, to use the user input as numbers, we would need to take the strings and convert them to numbers, in order to perform mathematical operations with them.


#2

Hey, I am having trouble with printing the tic tac to board in the homework.
How do you print more than one string consecutively and with line breaks?

If I try and run all my code at once, I always get an error and if I past them
separately, I have lines of code between my tic tac to board…


#3

To do this one, you should save a set of lines of code as a Python script, then run that script.

You have a number of choices for how to do this. In each case, print one row of characters at a time, representing each row as a string.

Here’s one way to do it …

# TicTacToe.py
print "  |  |"
print "--------"
print "  |  |"
print "--------"
print "  |  |"

Another approach could be to define two functions, each specializing in drawing a particular type of board component, and then to call the functions alternately to draw the board …

# TicTacToe.py
def verticals():
    print "  |  |"

def horizontals():
    print "--------"

verticals()
horizontals()
verticals()
horizontals()
verticals()

But, if you would like to print the board by using the command line instead of a script, you can do it this way …

>>> print "  |  |\n--------\n  |  |\n--------\n  |  |"

Output …

  |  |
--------
  |  |
--------
  |  |
>>> 

In a string, the "\n" character represents a line break.


#4

Is anyone here working on 6.189 Homework 1: Exercise OPT.2 – Secret Messages? If so, one of the key concepts is how modular arithmetic works, which is implemented as the modulus, or remainder, operator, %. It’s like a clock, especially a 24-hour one, as it cycles repeatedly through the same series of times each day. It’s useful to note that the cycle continues uninterrupted even if we go negative, that is, if the left operand goes from 1 to 0 to -1, etc.

Following is a 24-hour clock example, using a modulus of 24. It will execute until the user enters 0. Enter positive or negative integers as input, or 0, when you get bored …

# TwentyFourHourClock.py
import random
while True:
    t = random.randint(0, 23)
    print "The clock says " + str(t) + "."
    delta = int(raw_input("By how many hours should be change the time? "))
    if delta == 0:
        print "Bye!"
        break
    new_t = (t + delta) % 24
    print "The clock now says " + str(new_t) + "."

Here’s some interaction with IDLE, with a modulus of 26, the number of letters in the alphabet, as a segue into the Secret Message problem …

>>> 4 % 26
4
>>> 3 % 26
3
>>> 2 % 26
2
>>> 1 % 26
1
>>> 0 % 26
0
>>> -1 % 26
25
>>> -2 % 26
24
>>> -3 % 26
23
>>>

While it is obvious how to handle remainders with positive numbers, the above verifies that as we turn the clock backwards, or the alphabet, in this case, the cycle continues. So, we can easily cycle through X, Y, Z, A, B, C …, or the reverse, as in C, B, A, Z, Y, X …, etc. This can help us handle both positive and negative shift values.

The given example output is …

Enter sentence to encrypt: Mayday! Mayday!
Enter shift value: 4
The encoded phrase is: Qechec! Qechec!

So M shifts forward by 4 letters to Q, and y goes forward by 4 letters, and wraps around, like a clock, to c.

Here is a solution to the Secret Messages problem, open for discussion …

# SecretMessages.py
# MIT 6.189 Homework 1 Exercise OPT.2
phrase = raw_input("Enter sentence to encrypt: ")
# Ask for shift value; convert user input string to int
shift = int(raw_input("Enter shift value: "))
# Start with an empty string for the encoded phrase
encoded_phrase = ""
asc_a = ord("a")
asc_A = ord("A")
# Loop through each character in the phrase; use c to represent it
for c in phrase:
    # Get the ascii code for the character
    asc = ord(c)
    if asc_a <= asc <= asc_a + 26:
        # c is a lowercase letter; encode it.
        asc_enc = asc_a + (asc - asc_a + shift) % 26
    elif asc_A <= asc <= asc_A + 26:
        # c is an uppercase letter; encode it.
        asc_enc = asc_A + (asc - asc_A + shift) % 26
    else:
        # c is not a letter; do not encode it.
        asc_enc = asc
    # Add the character to the encoded phrase.
    encoded_phrase = encoded_phrase + chr(asc_enc)

print "The encoded phrase is: " + encoded_phrase

Output, using a negative shift value …

>>> 
Enter sentence to encrypt: Mechanical MOOC!
Enter shift value: -1
The encoded phrase is: Ldbgzmhbzk LNNB!
>>>

The line that performs the shifting of the ascii value for lowercase letters is this one …

asc_enc = asc_a + (asc - asc_a + shift) % 26

We calculate the difference between the ascii code of the letter being encoded and the ascii code for a. Then we add in the shift value and apply the % operator using 26 as the divisor. The result gets added to the ascii code for a. That gives us the ascii code of the letter that will be put into the encrypted message in place of the original letter.


#5

Another approach is use some math for how many dash.

print "-" * 8  #multiplies the dash eight times

The most concise way I think I have found without turning it into a user function.

a = "  |  |  "
b = "-" * 8 

print a, "\n", b, "\n", a, "\n", b, "\n", a

But as Glenn pointed out, if you plan on reusing that code more than once in your script, making it a defined function would be best.


#6

I like @bkglass’s approach, using string multiplication. It comes in handy when a string needs to be created that contains repeats of the same character, or of the same sequence of characters.

Thanks, @bkglass, for posting that example. It’s great to have an opportunity to see how other people approach a programming task, and hopefully other participants will also be showing us their solutions to problems.


#7

Thanks @Glenn! The funny thing is I actually use, print '-' * 10 ,a lot when running scripts in PowerShell just to break things up visually.


#8

@Glenn your post for Homework Exercise OPT. 2 was helpful for me to get the math right! It was driving me nuts.

The biggest difference in my code is I used .isalpha() , .isupper() and .islower() methods to eval if the character in the string was True or False before doing the fancy math business.

Basically, anyone reading this that is not familiar with these methods:
.isalpha() - checks if it is a ‘alphabetical letter’, returns ‘True’ if it is, returns ‘False’ if not.
.isupper() - checks if ‘letter’ is uppercase, returns ‘True’ or ‘False’
.islower() - checks if ‘letter’ is lowercase, returns ‘True’ or ‘False’

In the code below, the first ‘if’ statement will run if the character in the string is both a ‘letter’ and is uppercase.

phrase = raw_input("Enter phrase: ")
shift = int(raw_input("Enter shift value: "))

encode_phrase = ''

for c in phrase:
    if c.isalpha() and c.isupper():
        c = ord("A") + (ord(c) - ord("A") + shift) % 26
        encode_phrase = encode_phrase + chr(c)
    elif c.isalpha() and c.islower():
        c = ord("a") + (ord(c) - ord("a") + shift) % 26
        encode_phrase = encode_phrase + chr(c)
    else:
        encode_phrase = encode_phrase + c 
    
print "The encoded phrase is: ", encode_phrase

#9

As for the tic tac toe board, while I appreciate the use of string multiplication, I think I would prefer having the whole thing typed out, as @Glenn wrote it the first time. That way, while reading the source code it is clearer what exactly is printed. “Readability counts”.

I agree with putting it into a single function, since that makes it easier to use in other places


#10

Homework 1, Exercise OPT. 1 - Zeller’s Algorithm

For anyone interested, this is what I did for exercise OPT.1. I wanted to let the user check different dates without having to re-run the script. It is not the most elegant thing… It could use some ‘try/except’ statements to catch bad user inputs, but it works…

And there is a slight bug in this script which is caused by the ‘type’ casting int().

The flaw is caused by entering ‘01’, ‘02’, ‘03’, …,‘09’ on this line:

c = int(raw_input("Enter year in century(e.g. 89 for the year 1989): "))

I should fix it… But it is also interesting see what the flaw is caused by the ‘type’ casting.

#Script shows the day of the week for a date
#These print statements visually gives user NUMBER needed for month
print '-' * 12
print "  March = 1" 
print "  April = 2" 
print "  May = 3"
print "  June = 4"
print "  July = 5"
print "  August = 6" 
print "  September = 7" 
print "  October = 8" 
print "  November = 9"
print "  December = 10" 
print "  January = 11" 
print "  February = 12"
print '-' * 12
print " "

def day_of_week():
    month = ["March", "April", "May", "June", "July", "August", "September", 
    "October", "November", "December", "January", "February"]

    day = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", 
    "Saturday", "Sunday"]
    
    a = int(raw_input("Enter NUMBER from above list for Month of the Year: "))
    print "Month : ", month[a - 1] 
    print " "

    b = int(raw_input("Enter day the month (e.g. 1, 2, 3, ..., 30, 31): "))
    print "Day : ", b
    print " "

    c = int(raw_input("Enter year in the century (e.g. 89 for the year 1989): "))
    print "Year : ", c
    print " "
    if a == 11 or a == 12:
        c = c - 1 
    else: 
        c = c        

    d = int(raw_input("Enter the century (e.g 19 for the year 1989): "))
    print "Century : ", d 
    print " "

    w = (13 * a - 1) / 5 
    x = c / 4 
    y = d / 4 
    z = w + x + y + b + c - 2 * d 
    r = z % 7

    print "  ", month[a - 1], str(b) + ",", str(d) + str(c),"was: ", day[r],"!!"
    print " "
    
day_of_week()

print "Do you want to enter another date?" 
again = raw_input("Enter y for yes, n for done: ")
print " "

while again == "y" and again != "n":
    day_of_week()
    print "Do you want to enter another date?" 
    again = raw_input("Enter y for yes, n for done: ")
else:
    print "Done checking dates... Time for some coffee!"

#11

@Cedar_Mora I agree ‘readability’ is important, but it can be good to see other ways in which things are done… Readability is in the eyes of the beholder. :smile:


#12

@bkglass, you’re right.


#13

My solution for the Zeller’s algorithm problem was done during a previous run of the MMOOC, on October 31, 2013, which fell on a … let’s see … Thursday. It is modified so that January = 1, February = 2, etc.

Here’s the code …

# Zellers.py
# October 31, 2013
# G.A.R.
# See http://www.timeanddate.com/calendar/
# Valid for Gregorian Calendar (September 14, 1752 or later)
daysOfWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
print("Enter date")
month = int(input("Month (1 - 12, 1 = January): "))
day = int(input("Day: "))
year = int(input("Year (4 digits): "))
if month < 3:
    yr = year - 1
else:
    yr = year
a = (month + 9) % 12 + 1
b = day
c = yr % 100
d = yr // 100
w = (13 * a - 1) // 5
x = c // 4
y = d // 4
z = w + x + y + b + c - 2 * d

r = z % 7
dayOfWeek = daysOfWeek[r]
print(months[month - 1] + " " + str(day) + ", " + str(year) + " falls on a " + dayOfWeek + ".")

#14

It’s true, readability is important.

A good place to use string (and list) multiplication would be in a function, where the function uses a value passed to it via a parameter to determine the number of times that a character or list item is to be repeated.

With a list, it might be one that is used for storage of the configuration of a game board. The function may include parameters that represent the dimensions of the board, and the board might be initialized to some repeated value.


#15

Following are solutions to Exercise 1.8 - For & While Loops, open for discussion.

# Exercise 1.8 - 1
# fractions.py
for i in range(2, 11):
    print "1/" + str(i) + " = " + str(1.0 / i)

Notes: For the above, 1.0 needed to be be used for the numerator, rather than simply 1, so that floating point division would be performed for each fraction.


# Exercise 1.8 - 2
# countdown.py
print "Countdown!"
start = int(raw_input("Starting number: "))
if start < 0:
    print("Let's not be so negative!")
else:
    for i in range(start, -1, -1):
        print i

Notes: For the above, the user input, which is stored as a string, needed to be converted to an int. in the for loop header, we need an end value of -1 so that we stop at 0 as we count down from above, and a step or stride value of -1 so that we count downward instead of upward.


# Exercise 1.8 - 3
# exponentials.py
base = int(raw_input("Enter a base: "))
exponent = int(raw_input("Enter an exponent: "))
result = 1
if exponent > 0:
    for i in range(exponent):
        result *= base
elif exponent < 0:
    for i in range(-exponent):
        result /= float(base)
print result

Notes: In the above, user input is converted to int type. When using an accumulator (result in this example) to calculate a project or quotient, we need to initialize it to a value of 1. Then, for a positive base, we use repeated multiplication, and for a negative base, we use repeated division.


# Exercise 1.8 - 4
# getting_even.py
import random
messages = ["We need something even, Steven! ",
            "We're going to have to get even with you! ",
            "Even novices can conjure up even numbers! "]
message = "How's about you enter an even number? "
while True:
    num = int(raw_input(message))
    if num % 2 == 0:
        print "That reveals sheer genius!"
        break
    else:
        message = messages[random.randint(0, len(messages) - 1)]

Notes: To test for even divisibility by 2, we look for a remainder of 0 with the % operator. After the first prompt for an even number, all subsequent ones are selected pseudo-randomly from a list named messages. The while loop, with its condition of True, runs forever until a break is executed in response to an even number’s having been entered.


#16

@alexhascodex - have you been able to get your tic-tac-toe board printing?


#17

Just finished both optional exercises, here’s the code if anybody is interested. I may have used things we haven’t learned yet, as I have some experience with Python.

Any advice you are willing to give to improve the code is welcome.


Optional Exercise 1:

#Last modified: May 12, 2015

print "Enter a date to find what day of the week it was.\n\n"
print "March = 1\n"
print "April = 2\n"
print "May = 3\n"
print "June = 4\n"
print "July = 5\n"
print "August = 6\n"
print "September = 7\n"
print "October = 8\n"
print "November = 9\n"
print "December = 10\n"
print "January = 11 (NOTE January and February months\n"
print "February = 12 should be written as if from the previous year.)\n"
month = raw_input("Month? ")
day = raw_input("Day? ")
year = raw_input("Year? ")

######## Zeller's Algorithm ########
A = int(month)
B = int(day)
C = int(year[2:4]) #C and D only work for dates 1000-9999. Should be fine.
D = int(year[0:2]) #We'll probably have abolished weekdays by then anyways.

W = (13*A - 1) / 5
X = C / 4
Y = D / 4
Z = W + X + Y + B + C - 2*D
R = Z % 7 #R = Day of the week, 0 = Sunday, 1 = Monday...

day_of_week = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday","Friday", "Saturday"]

final_answer = day_of_week[R]
##########################################

print "This date occurred on a " + final_answer + "."

Given the choice, I would have written Zeller’s Algorithm with January being the first month to make user input simpler, but I decided to save my own time instead.


Optional Exercise 2:

#Last modified: May 12, 2015

phrase = raw_input("What phrase would you like to encode? ")
shift_value = int(raw_input("What shift value would you like? "))

encoded_phrase = ""

for character in phrase:
        if character.isalpha():
                if character.islower():
                        #'a' == 97, 'z' == 122
                        char_code = ord(character) - 97 #After processing, a == 0, b == 1...
                        #Encoding and returning to Unicode value.
                        encoded_char = chr((char_code + shift_value) % 26 + 97)
                        encoded_phrase = encoded_phrase + encoded_char
                elif character.isupper():
                        #'A' == 65, 'Z' = 90
                        char_code = ord(character) - 65 #After processing, A == 0, B == 1...
                        #Encoding and returning to Unicode value.
                        encoded_char = chr((char_code + shift_value) % 26 + 65)
                        encoded_phrase = encoded_phrase + encoded_char
        else:
                encoded_phrase = encoded_phrase + character

print encoded_phrase

I think it may have been unwise of me to use “magic numbers” like 65, 97, or 26, but somehow it seemed to keep things simpler not to create further variables to store them.

The character.upper() and character.lower() sections seemed really similar to me, but I couldn’t figure out how to combine them into one section.


Fin.


#18

@Glenn I like the simplicity. I think I overthought this one.

x = "|"
y = “-”

print " “,” “,” ", x, " “,” ", x
print " “,” “,” ", x, " ", " ",x
print " “,” “,” ", x, " “,” ", x
print y,y,y,y,y,y,y,y,y,y
print " “,” “,” ", x, " “,” ", x
print " “,” “,” ", x, " ", " ",x

print y,y,y,y,y,y,y,y,y,y
print " “,” “,” ", x, " “,” ", x
print " “,” “,” ", x, " ", " ",x
print " “,” “,” ", x, " “,” ", x

or perhaps didn’t think enough.


#19

@Everyone,

Thanks for the code.

See @dirk’s response to @TutorialDoctor in the Rock Paper Scissors topic discussion regarding how to format Python code for posting.

(I see that some have now formatted their code - thanks).

In the Codecademy Q&A, one of the most common challenges regarding understanding other users’ posted code is that much of it has not been formatted. This is mainly because there’s a constant stream of new users flowing through the Python track.

When there is a bug that relates to something like a return statement inadvertently placed in a loop, or to other issues concerning blocks of code, the lack of formatting makes it hard to spot.

I don’t see any bugs in the code that you posted, but mention this in case you delve into the Codecademy Q&A.


#20

@Cedar_Mora it is nice to see different approaches. I don’t think using numbers like 65 and 97 is unwise… It does keep things more simple. It was good that you added comments so someone would know what those numbers represent.