MIT 6.189 Homework 2 Programming Exercises


#1

Following is a solution to MIT 6.189 Homework 2, Exercise 2.7 – Working With Lists, for discussion:

# cumulative_sum.py
def cumulative_sum(number_list):
    # number_list is a list of numbers

    ##### YOUR CODE HERE #####
    cum_sum = 0 # keeps a cumulative sum
    cum_sum_list = [] # the list to be returned
    for num in number_list:
        cum_sum += num
        cum_sum_list.append(cum_sum)
    return cum_sum_list

numbers = [4, 2, 9, 7, 3, 8, 6]
print cumulative_sum(numbers)

A cum_sum variable is initialized to 0. In a loop, it keeps track of the cumulative sum.

A cum_sum_list variable is initialized to an empty list. As each cumulative sum is computed within the loop, that sum is appended to the list.

After all items in the original list have been processed, the cum_sum_list is returned.


#2

Just finished Exercise 2.6, thought I’d share code.

def play_nims(pile, max_stones):
        '''
        An interactive two-person game; also known as Stones.
        @param pile: the number of stones in the pile to start
        @param max_stones: the maximum number of stones you can take on one turn
        There is a pile of 100 stones in front of two players. Players take turns removing between 1 and max_stones from the pile. Whoever removes the last stone wins.
        '''

    ## Basic structure of program (feel free to alter as you please):

        while pile > 0:

                #Player 1's turn
                move_valid = False #Must be false to run while loop.
                while move_valid == False:
                        move = raw_input("(P1) How many stones? (1-%s)" % (max_stones))
                        move = int(move)
                        if move < 1 or move > max_stones:
                                move_valid = False
                        else:
                                move_valid = True
                pile -= move
                if pile < 0:
                        print "Player 1 wins!"
                        return
                print "There are %s stones left." % (pile)


                #Player 2's turn
                move_valid = False #Must be false to run while loop.
                        move = raw_input("(P2) How many stones? (1-%s)" % (max_stones))
                        move = int(move)
                        if move < 1 or move > 5:
                                move_valid = False
                        else:
                                move_valid = True
                pile -= move
                if pile < 0:
                        print "Player 2 wins!"
                        return
                print "There are %s stones left." % (pile)
        print "Game over"

play_nims(100, 5)

It kind of got complicated a little more than I intended. As I tried to improve clarity through abstraction, I might have increased complexity, reducing clarity. So oops I guess. Here’s my first, simpler version.

def play_nims(pile, max_stones):

        while pile > 0:

                #Player 1's turn
                move = 0 #Must be false to run loop below.
                while move < 1 or move > max_stones:
                        move = raw_input("(P1) How many stones? (1-%s)" % (max_stones))
                        move = int(move)
                pile -= move
                if pile < 0:
                        print "Player 1 wins!"
                else:
                        print "There are %s stones left." % (pile)


                #Player 2's turn
                move = 0 #Must be false to run loop below.
                while move < 1 or move > max_stones:
                        move = raw_input("(P2) How many stones? (1-%s)" % (max_stones))
                        move = int(move)
                pile -= move
                if pile < 0:
                        print "Player 2 wins!"
                else:
                        print "There are %s stones left." % (pile)
        print "Game over"

play_nims(100, 5)

Actually, I just rethought it and realized that redundancy is bad, so I rewrote it again. <hr ``` def play_nims(pile, max_stones): player_turn = 1 #Whose turn it is. Player 1 first
    while pile > 0:
            move = 0 #Must be false to run loop below.
            while move < 1 or move > max_stones:
                    move = raw_input("(P%s) How many stones? (1-%s)" % (player_turn, max_stones))
                    move = int(move)
            pile -= move
            if pile < 0:
                    print "Player %s wins!" % (player_turn)
            else:
                    print "There are %s stones left." % (pile)
            if player_turn == 1:
                    player_turn = 2
            else:
                    player_turn = 1

    print "Game over"

play_nims(100, 5)

<hr>

Also note that none of these versions handle bad input very well. However, I guess they haven't really taught us that yet.

#3

Here’s what I recently did for nims.py

# nims.py
# May 12, 2015
# G.A.R.
def play_nims(pile, max_stones):
    '''
    An interactive two-person game; also known as Stones.
    @param pile: the number of stones in the pile to start
    @param max_stones: the maximum number of stones you can take on one turn
    '''

    ## Basic structure of program (feel free to alter as you please):

    while pile > 0:
        stones = 0
        while stones < 1 or stones > min(max_stones, pile):
            stones = int(raw_input("Player 1 - Number to remove (1 to " + str(min(max_stones, pile)) + "): "))
        pile -= stones
        print(str(pile) + " remain")
        if pile == 0:
            player = "1"
            break
        stones = 0
        while stones < 1 or stones > min(max_stones, pile):
            stones = int(raw_input("Player 2 - Number to remove (1 to " + str(min(max_stones, pile)) + "): "))
        pile -= stones
        print(str(pile) + " remain")
        if pile == 0:
            player = "2"
            break

    print("Game over. Player " + player + " wins.")

play_nims(48, 7)

Concerning invalid input, it does not check whether the input can be converted to int; it assumes that it can. The checking is here …

while stones < 1 or stones > min(max_stones, pile):

So, valid moves are between 0 and max_stones, inclusive, as long as the pile contains at least max_stones. After that, a valid move is between 0 and pile, inclusive. But, of course, that occurs only when a player is in a position to immediately win the game.

But during a previous run of the MMOOC, I was less lazy, and put more effort into this exercise, distilling the two players into a single loop, and checking the input more rigorously. To check for non-integer input, it uses a try - except structure.

# nims_rand.py
# Last modified November 5, 2013

import random
def play_nims(pile, max_stones):
    '''
    An interactive two-person game; also known as Stones.
    @param pile: the number of stones in the pile to start
    @param max_stones: the maximum number of stones you can take on one turn
    '''
    print("maximum number of stones that can be taken in one turn: " + str(max_stones))
    player = 1
    while pile > 0:
        ans = 0
        print(str(pile) + " stones remaining")
        # Get input; loop until valid
        while not 1 <= ans <= max_stones:
            try:
                ans = int(raw_input("Player " + str(player) + " > Number of stones (1 - " + str(max_stones) + "): "))
            except:
                ans = 0
        pile -= ans
        print()
        max_stones = min(pile, max_stones)
        # Switch players
        player = player % 2 + 1
    print("Game over")
    print("Player " + str(player % 2 + 1) + " wins!")
# Choose, randomly, the game parameters
play_nims(random.randint(21, 31), random.randint(5, 8))

#4

Thanks for the reply.

I especially appreciate the approach with error handling. I feel like that’s something that is much more important in real world programming, and thus is something worth learning.

I was a bit confused at first in the first example as to what the min() function did, but after researching what min() does, it made more sense. Personally, I might have used the format string operator for clarity.

I do appreciate the attention to detail in the first example using the min() function to make sure that the last moves displayed the correct available moves. it’s a nice touch.

Thanks for the code to look over, your activism means something to me.


#6

I’m having some frustrating issues figuring out exercise 2.3: math modules. It has been a few days since I’ve practiced python but I’m missing something. Thank you in advance.
When I try to run this program, I get a syntax error saying that “angle_test is not defined.”

import math
radians = (90.0/360.0) * 2 * math.pi
print math.sin(radians)

def multadd(a,b,c):
        print angle_test
        print ceiling.test

def angle_test
        sin(pi/4) + cos(pi/4)/2

def ceiling.test:
        (276/19) + 2 log_7(12)

print multadd(2,3,4)

#7

Hey @Rose_Ketring

A typical function is defined like

def function_name(variable_name):
    print(variable_name)

function_name must start with a letter (iow a-z or A-Z) or an underscore _. It can contain numbers as long as it doesn’t start with a number.

variable_name is optional, but the brackets and the : that follows are not.

Have another look at your code and see if you can fix the problems. If not, feel free to ask again here.


#8

had a real problem with math.ceil function when called. Returned a float error. The second part was 2 log_7(12). I got angle_test and roll_dice to run.


#9

While not sure about this, I think the intent of Exercise 2.3 – Math Module is to have you write mult_add as a very short function that has three parameters, a, b, and c, just as you have it, but does nothing more than multiply a by b, add c to that, and return the result. If that is the case, then it would look like this …

def mult_add(a, b, c):
    return a * b + c

Then, part of the challenge becomes how to express the calculations that follow as three terms, namely, two that get multiplied together, and a third one that gets added to that product. To calculate the result, pass the three terms to the mult_add function in the correct order. The other part of the challenge is to decide how functions from the math module could be used to help compute the results.

I think angle_test and ceiling.test should be variables, rather than functions, that you assign the result of calling the mult_add function.

The yikes function should also be short, consisting of a call to the mult_add, aided by some calls to functions from the math module. See the documentation at 9.2. math — Mathematical functions for information about functions that compute logarithms, ceilings, and the like.


#10

Hi, @Rose_Ketring,
For the ceiling_test, or any of the other components of Exercise 2.3 – Math Module, you can break the expression into three parts, a, b, and c, to prepare to call the mult_add function. To do this, you need to decide what two parts will be multiplied together, and which one will be added to that product.

Assuming that we have the mult_add function, we can break up the ceiling_test problem, as follows …

# Break the expression into three parts
# See https://docs.python.org/2/library/math.html
# for documentation on the math functions used here
a = 2.0
b = math.log(12.0, 7.0)
c = math.ceil(276.0 / 19.0)
# Now, pass the three parts to the mult_add function
ceiling_test = mult_add(a, b, c)
print ceiling_test

The output is …

17.5539788165

#11

Ahh I was trying to create those into functions. :slight_smile: Feel much better…thank
you


#12

I had no idea that was what they wanted @Glenn, whenever I did 2.3. The way you did it makes a lot more sense.


#13

To a large degree, it doesn’t matter whether we misinterpreted the intention of the exercise, as long as we learned something by trying it. After all, it’s not being graded :slight_smile: , which is one of the factors that makes the MMOOC fun. The tuition rate is also ideal :wink: , during this era of mounting student loan debt. We can each put most of our effort into the parts we like the most.

Below is what I have. If nothing else, the exercise gives us an opportunity to play with the functions from the math module. The online documentation for that module was very helpful to me, so I have included the address in the code, as a comment.

# mult_add.py
# Exercise 2.3 - Math Module
# See https://docs.python.org/2/library/math.html
import math
def mult_add(a, b, c):
    # multiply a and b, and add c
    return a * b + c

# In each case, break the expression into three parts
# Assign the parts to a, b, and c to make it clear
# which parts will get multiplied (a and b),
# and which will get added (c)
# when we call the mult_add function
# See https://docs.python.org/2/library/math.html
# for documentation on the math functions used here

a = math.cos(math.pi / 4.0)
b = 1.0 / 2.0
c = math.sin(math.pi / 4)
# Now, pass the three parts to the mult_add function
angle_test = mult_add(a, b, c)
print angle_test

a = 2.0
b = math.log(12.0, 7.0)
c = math.ceil(276.0 / 19.0)
# Now, pass the three parts to the mult_add function
ceiling_test = mult_add(a, b, c)
print ceiling_test

def yikes(x):
    a = x
    b = math.e ** -x
    c = math.sqrt(1.0 - math.e ** -x)
    # Now, pass the three parts to the mult_add function
    return mult_add(a, b, c)

print yikes(5.0)