This lab provides practice defining classes, recursion, doing file I/O, and regular expressions.
Instructions:
Modify this notebook by adding the Python code described below.
Test your code using the menu item Cell ► Run All
Save the notebook (the .ipynb file) and upload it to the appropriate Assignment folder on the course web site.
Define a class (type) named die
. The constructor takes one argument, the number of die faces, with a default value of 6. The type has one method, roll()
, that returns a random integer between 1 and the number of faces.
For example:
d = die(4)
print(d.roll(),d.roll())
would print two pseudo-random numbers between 1 and 4.
Hints: (1) random.randint(a,b)
returns a (pseudo-)random integer between a
and b
. (2) Objects in the class namespace, including imported modules, will be in the self
namespace when a method is called.
class die():
from random import randint
def __init__(self,sides=6):
self.sides = sides
def roll(self):
return self.randint(1,self.sides)
d = die(4)
print(d.roll(),d.roll())
2 1
Write a recursive function, rsearch(t)
that searches through an object t
composed of nested two-element tuples. Each element of these tuples may be an integer or another two-element tuple. The data structure contains only one non-zero integer. Your function should return the value of this non-zero integer.
For example, rsearch((0,((33,0),(0,0))))
should return 33.
def rsearch(t):
l,r = t
if type(l) == tuple:
l = rsearch(l)
if type(r) == tuple:
r = rsearch(r)
return max(l,r)
rsearch((0,((33,0),(0,0))))
33
Write a function named partnums()
that opens a file named partnums.txt
and returns a list of all the words (as defined by the str.split()
method) that consist of:
The lab check code will create the file named partnums.txt
in the same directory as this notebook before calling partnums()
.
import re
def partnums():
r = []
for l in open('partnums.txt'):
for s in l.split():
if re.match(r'[ABC]\d{3,4}[-:]([a-z]{2}|[0-9]{2})$',s):
r.append(s)
return r
# lab validation code; do not modify
def labcheck():
import copy, random, re, string, types
from random import randint
def checkre(pat,ok,nok):
for s in ok:
assert re.fullmatch(pat,s), \
f"pattern '{pat}'\n did not match string '{s}'"
for s in nok:
assert not re.fullmatch(pat,s), \
f"pattern '{pat}'\n matched string '{s}'"
def randwords(n,chars=string.ascii_lowercase,nl=(2,5)):
l = set()
while len(l)<n:
l |= set((''.join([chars[randint(0,len(chars)-1)] for i in range(randint(*nl))]),))
return list(l)
def q1():
n = randint(2,10)
on = copy.deepcopy(n)
c = die(n)
minr, maxr = c.roll(), c.roll()
for i in range(10000):
r = c.roll()
minr = min(minr,r)
maxr = max(maxr,r)
assert minr==1 and maxr==on, \
f"After 10,000 rolls die({on}) roll() returned values from {minr} to {maxr}"
def q2():
n = randint(6,10)
nt = randint(1,n)
v = randint(1,999)
def rantuple(n):
nonlocal nt
if n <= 1:
nt -= 1
return v if not nt else 0
i = randint(1,n-1)
j = n - i
return (rantuple(i),rantuple(j))
t = rantuple(n)
ot = copy.deepcopy(t)
r = rsearch(t)
assert r == v,f"rsearch({ot}) returns {r}"
def q3():
import string
ok, nok = [], []
np = 4
nw = 10
dorl = [string.digits,string.ascii_lowercase]
for i in range(nw):
s=[]
s += [random.sample("ABC",k=1)[0]]
s += [''.join(random.sample(string.digits,k=random.randint(3,4)))]
s += [':' if random.random()>0.5 else '-']
s += [''.join(random.sample(dorl[randint(0,1)],k=2))]
ok.append(s)
for i in range(nw):
s=[]
s += [random.sample("abcDEF",k=1)[0]]
s += [''.join(random.sample(string.digits,k=random.sample([1,2,5,6,8],k=1)[0]))]
s += ["!=*"[randint(0,2)]]
k=random.sample([1,3],k=1)[0]
s += [''.join(random.sample(dorl[randint(0,1)],k=k))]
nok.append(s)
okw = [''.join(l) for l in ok]
ich = [j%np for j in range(nw)]
random.shuffle(ich)
nokw = [''.join([nok[j][i] if i == ich[j] else ok[j][i] for i in range(np)]) for j in range(nw)]
f = open('partnums.txt','w')
words = okw+nokw
random.shuffle(words)
for s in [w+(' ' if randint(0,1) else '\n') for w in words]:
f.write(s)
f.close()
r = partnums()
shouldnot = set(r) & set(nokw)
shouldnot = f"which should not include {shouldnot}" if shouldnot else ""
should = set(okw) - set(r)
should = f"which should include {should}" if should else ""
assert set(okw) == set(r),f"partnums({words}) returns {r} {shouldnot} {should}"
for s,i in [(s,s[1:]) for s in locals().keys() if re.search(r'q\d+',s)]:
try:
locals()[s]()
print(f"Question {i} OK.")
except Exception as e:
print(f"Failed check for Question {i}: {e}")
labcheck()
Question 1 OK. Question 2 OK. Question 3 OK.