 # MIT 6.189 Homework 2 Programming Exercises

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

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 `append`ed to the list.

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

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.``````

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

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))
``````

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.

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 angle_test
print ceiling.test

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

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

``````

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.

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.

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.

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
print ceiling_test
``````

The output is …

``````17.5539788165
``````

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

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.

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 , which is one of the factors that makes the MMOOC fun. The tuition rate is also ideal , 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
# 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
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