Introduction to Computer Science II

Homework 2

Due by 11:50am on Tuesday, January 18

Reading

Read chapter 8 and the week 2 lecture notes.

Problems

Solve the following by implementing the corresponding functions in homework2.py. When done, submit that file through D2L.

1.    Implement a class Polygon that abstracts regular polygons and supports class methods:
Note: The area of a regular polygon with n sides of length s is

s**2 * n / (4 * tan(pi/n))

where pi is the mathematical constant Pi and tan is the trig function tan().
Usage:
>>> p = Polygon(4,1)
>>> p.perimeter()
4
>>> p.area()
1.0000000000000002
>>> p = Polygon(6,1)
>>> p.area()
2.5980762113533165
>>> p.perimeter()
6
>>> p = Polygon()
>>> p.perimeter()
3
>>> p.area()
0.43301270189221946
>>> p = Polygon(n=4)
>>> p.area()
1.0000000000000002
>>> p.perimeter()
4


2.    Overload appropriate operators for class Card so that you can compare cards based on rank. Use the following ranking: 2 < 3 < 4 < 5< 6 < 7 < 8 < 9 < 10 < J < Q < K < A.
Usage:
>>> d = Deck()
>>> d.shuffle()
>>> a = d.dealCard()
>>> b = d.dealCard()
>>> c = d.dealCard()
>>> a
Card('8', '♣')
>>> b
Card('2', '♡')
>>> c
Card('7', '♣')
>>> a < b
False
>>> c > b
True
>>> a <= a
True
>>> a >= c
True


3.   Develop a class BankAccount that supports these methods:
Usage:
>>> x = BankAccount(700)
>>> x.balance()
700
>>> x.withdraw(70)
>>> x.balance()
630
>>> x.deposit(7)
>>> x.balance()
637

4.   Develop a class Craps that allows you to play craps on your computer. (The craps rules are described in homework assignment 1.) Your class will support methods:
Usage:
>>> c = Craps()
Throw total: 11. You won!
>>> c = Craps()
Throw total: 2. You lost!
>>> c = Craps()
Throw total: 5. Throw for Point.
>>> c.forPoint()
Throw total: 6. Throw for Point.
>>> c.forPoint()
Throw total: 5. You won!
>>> c = Craps()
Throw total: 4. Throw for Point.
>>> c.forPoint()
Throw total: 7. You lost!

5.    Implement class Random that implements a linear congruential pseudorandom number generator. In other words, it is used to generate a sequence of pseudorandom integers using a linear congruential generator approach.

The linear congruential method generates a sequence of numbers (or seeds) starting from a given seed number x. Each number (seed) in the sequence will be obtained by applying a (math) function f (x) on the previous number (seed) x in the sequence. The precise function f (x) is defined by three numbers: a (the multiplier), c (the increment), and m (the modulus):
f(x) = (ax + c) mod m
For example, if m = 31, a = 17, and c = 7, the linear congruential method would generate the next sequence of numbers (seeds) starting from seed x = 12:
12,25,29,4,13,11,8,19,20, . . .
because f (12) = 25, f (25) = 29, f (29) = 4, and so on.

The class Random should support methods:
Usage:
>>> r = Random(12, 17, 7, 31)
>>> r.rand()
25
>>> r.rand()
29
>>> r.rand()
4
>>> r.rand()
13
>>> r.rand()
11

6.
    The numbers 17, 7, and 31 used for a (the multiplier), c (the increment), and m (the modulus) in the above example do not result in a good pseudorandom number generator. Much better values, used by the gcc C compiler library, are a=1103515245, c=12345, and m=231 (2 to the power 31). These number will generate pseudorandom numbers in the range from 0 to 231-1 with very good "random properties". Also, while good for debugging your implementation, it is inconvenient to have to provide a seed to the pseudorandom number generator. Much better would be to use an integer related to the current time, in nanoseconds. The time() function in the Python standard library module time gives the number of seconds since January 1, 1970:
>>> import time
>>> time.time()
1579100035.550304
>>> time.time()
1579100036.813396

To get the number of nanoseconds since January 1, 1970 as an integer we need to multiply time.time() by a billion and convert to int:
>>> int(time.time()*10**9)
1579099881394504960
>>> int(time.time()*10**9)
1579099882719621888
Modify your class Random so that default values, as specified above, for the seed, the multiplier, the increment, and the modulus are used when no values are passed when constructing the Random object.
Usage:
>>> r = Random()
>>> r.rand()
1435472185
>>> r.rand()
2004247422
>>> r.rand()
1630335199
>>> r.rand()
592381941
(NOTE: because the seed will be a function of the current time when executing the constructor, your output will necessarily be different)

7.
    Augment your Random class with two additional methods:
Usage:
>>> r.randint(1, 6)
4
>>> r.randint(1, 6)
3
>>> r.randint(1, 6)
6
>>> r.randint(1, 6)
5
>>> r.randint(1, 6)
4
>>> r.random()
0.2017026348039508
>>> r.random()
0.4628330278210342
>>> r.random()
0.09002611227333546
>>> r.random()
0.34171303221955895
>>> r.random()
0.2796304449439049
>>> r.random()
0.9617379498668015
>>> r.random()
0.37306692358106375
>>> r.random()
0.5769595871679485
>>> r.random()
0.18874327652156353