I am a beginning programmer.
I’ve been writing codes on a mastermind solver in the six-guess algorithm for an assignment.
(More info on mastermind and its algorithms:Mastermind on wiki)
And I figured it out days ago. But our prof set the fixed template, and then I don’t know how to convert my codes into it.
Below is my code. May be awkward but it works and it’s not that slow.
def product(*args, repeat=1):
pools = [list(pool) for pool in args] * repeat
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield list(prod)
def sort_list(total_list):
d0=list()
d1=list()
d2=list()
d3=list()
d4=list()
for x in total_list:
mlist=list()
alist = x
n = 0
while n<4:
m = alist.count(alist[n])
mlist.append(m)
n = n + 1
if max(mlist)==1:
d0.append(alist)
elif max(mlist)==2 and mlist.count(2)==2:
d1.append(alist)
elif max(mlist)==2 and mlist.count(2)>2:
d2.append(alist)
elif max(mlist)==3 :
d3.append(alist)
elif max(mlist)==4 :
d4.append(alist)
total_list = d0+d1+d2+d3+d4
possible = [''.join(p) for p in total_list]
return total_list
def computeFeedback(code,guess):
b = 0
w = 0
inCodeCount = {'A':0,'B':0,'C':0,'D':0, 'E':0, 'F':0}
inGuessCount = {'A':0,'B':0,'C':0,'D':0, 'E':0, 'F':0}
for i in range(0,4):
if code[i] == guess[i]:
b += 1
inCodeCount[code[i]]+=1
inGuessCount[guess[i]]+=1
for ch in inCodeCount:
w+=min(inCodeCount [ch], inGuessCount [ch])
w-=b
feedback = str(w)+'w'+str(b)+'b'
return feedback
guesscount=0
code=input()
while guesscount<8:
guesscount += 1
if guesscount==1:
guess='ABCD'
print("My guess is:",guess)
feedback=computeFeedback(code,guess)
if feedback!='0w4b':
combinations=sort_list([''.join(x) for x in product('ABCDEF',repeat=4)])
overlap=list()
for x in combinations:
fb=computeFeedback(guess,x)
overlap.append(x)
if fb != feedback:
overlap.pop()
common=overlap
overlap=list()
else:
print("Game Over in", guesscount,"steps")
break
if guesscount==2:
guess='BCDE'
print("My guess is:",guess)
feedback=computeFeedback(code,guess)
if feedback!='0w4b':
combinations=sort_list([''.join(x) for x in product('ABCDEF',repeat=4)])
overlap=list()
for x in combinations:
fb=computeFeedback(guess,x)
overlap.append(x)
if fb != feedback:
overlap.pop()
common=[token for token in overlap if token in common]
overlap=list()
else:
print('Game Over in,', guesscount,'steps')
break
if guesscount==3:
guess='CDEF'
print("My guess is:",guess)
feedback=computeFeedback(code,guess)
if feedback!='0w4b':
combinations=sort_list([''.join(x) for x in product('ABCDEF',repeat=4)])
overlap=list()
for x in combinations:
fb=computeFeedback(guess,x)
overlap.append(x)
if fb != feedback:
overlap.pop()
common=[token for token in overlap if token in common]
overlap=list()
else:
print('Game Over in', guesscount,'steps')
break
if guesscount==4:
if common[0]=="acfb".upper():
guess="dcad".upper()
if common[0]=="aebf".upper():
guess="edfd".upper()
if common[0]=='AEFB':
guess='EACC'
if common[0]=='AFBE':
guess='BFCD'
if common[0]=='BAFE':
guess='EADC'
if common[0]=='BEAF':
guess='EDAE'
if common[0]=='BEFA':
guess='EEDA'
if common[0]=='EABF':
guess='FDFB'
if common[0]=='AADB':
guess='BABD'
if common[0]=='ABAE':
guess='BBCC'
if common[0]=='AEAF':
guess='CFFD'
if common[0]=='CAFA':
guess='FDFA'
if common[0]=='AAEE':
guess='DDDF'
else:
guess=common[0]
print("My guess is:",guess)
if len(common)>1:
common.pop(0)
feedback=computeFeedback(code,guess)
if feedback!='0w4b':
combinations=sort_list([''.join(x) for x in product('ABCDEF',repeat=4)])
overlap=list()
for x in combinations:
fb=computeFeedback(guess,x)
overlap.append(x)
if fb != feedback:
overlap.pop()
common=[token for token in overlap if token in common]
overlap=list()
else:
print('Game Over in', guesscount,'steps')
break
else:
print('Game Over in', guesscount,'steps')
break
if guesscount==5:
guess=common[0]
print("My guess is:",guess)
if len(common)>1:
common.pop(0)
feedback=computeFeedback(code,guess)
if feedback!='0w4b':
combinations=sort_list([''.join(x) for x in product('ABCDEF',repeat=4)])
overlap=list()
for x in combinations:
fb=computeFeedback(guess,x)
overlap.append(x)
if fb != feedback:
overlap.pop()
common=[token for token in overlap if token in common]
overlap=list()
else:
print('Game Over in', guesscount,'steps')
break
else:
print('Game Over in', guesscount,'steps')
break
if guesscount==6:
guess=common[0]
print("My guess is:",guess)
if len(common)>1:
common.pop(0)
feedback=computeFeedback(code,guess)
if feedback!='0w4b':
combinations=sort_list([''.join(x) for x in product('ABCDEF',repeat=4)])
overlap=list()
for x in combinations:
fb=computeFeedback(guess,x)
overlap.append(x)
if fb != feedback:
overlap.pop()
common=[token for token in overlap if token in common]
overlap=list()
else:
print('Game Over in', guesscount,'steps')
break
else:
print('Game Over in', guesscount,'steps')
break
if guesscount==7:
guess=common[0]
print("My guess is:",guess)
if len(common)>1:
common.pop(0)
feedback=computeFeedback(code,guess)
if feedback!='0w4b':
combinations=sort_list([''.join(x) for x in product('ABCDEF',repeat=4)])
overlap=list()
for x in combinations:
fb=computeFeedback(guess,x)
overlap.append(x)
if fb != feedback:
overlap.pop()
common=[token for token in overlap if token in common]
overlap=list()
else:
print('Game Over in', guesscount,'steps')
break
else:
print('Game Over in', guesscount,'steps')
break
if guesscount==8:
print('Failure')
Yeah, and here comes the template for both the code-breaker function I have to complete and a mastermind engine to run the function:
Template
class CodeBreaker:
def __init__(self):
def makeGuess(self):
return guess
def getFeedback(self, feedbackStr):
Engine
from mastermind import CodeBreaker
def computeFeedback(code,guess):
# Given a code and guess computes the feedback string
b = 0
w = 0
inCodeCount = {'A':0,'B':0,'C':0,'D':0, 'E':0, 'F':0}
inGuessCount = {'A':0,'B':0,'C':0,'D':0, 'E':0, 'F':0}
for i in range(0,4):
if code[i] == guess [i]:
b += 1
inCodeCount[code[i]] += 1
inGuessCount[guess[i]] += 1
for ch in inCodeCount:
w += min(inCodeCount [ch], inGuessCount [ch])
w -= b
feedback = str(w)+'w'+str(b)+'b'
return feedback
code = input()
while (code != None):
guesscount = 0
myBreaker = CodeBreaker()
while (guesscount < 8):
guess = myBreaker.makeGuess()
print("My guess is:",guess)
guesscount += 1
feedback = computeFeedback(code, guess)
print(feedback)
if feedback == "0w4b":
print("Game Over in", guesscount,"steps")
break
myBreaker.getFeedback(feedback)
if guesscount == 8:
print("Failed to find the solution in 8 steps")
code = input()
I’m bad at Classes. I’ve even no idea on what’s the init should contain. Anyone could help?
Thanks so much!
The simplest way to convert your code into a class is to put all your code into the
getFeedbackmethod, except that instead of computing a guess which you send off to be evaluated, remember the guess in the propertyself.guess, and return that next time themakeGuessfunction is called. You’ll also want to turn all your global variables (likecommon) into properties (likeself.common). Here’s a sketch:I should add that your code is very repetitive. The following changes would be worthwhile:
The Python standard library already contains a function
itertools.productthat does the job of your functionproduct(though it takes its arguments in a different way), so you might as well use that instead.You copy out essentially the same code for each guess (generating the set of combinations, evaluating the combinations against the most recent guess, updating
commonand so on). It should be straightforward to put this code into a method so that you don’t have to copy it out so many times.The code for guesses number 4 and higher is almost identical: surely there’s no need to copy out this code at all (just write
if guesscount >= 4:and handle them all at the same time).You might want to study this class (which uses a similar method to your solution, but with all the repetition cut out) and see if you can figure out how it works:
This algorithm can take up to eight guesses in the worst case, but you have eight guesses available, so that’s OK. If you had only six guesses available, then you’d need a cleverer approach. The following alternative algorithm makes the best guess based on one move of lookahead, and needs at most six guesses. (It runs very slowly, however!) Again, you might find it interesting to study how it works (hint: it takes the minimum of a list of maxima).
And here’s Knuth’s five-guess algorithm (which runs even slower):
P.S. Your professor’s code isn’t perfect, either! Apart from not following conventional Python style (see PEP8), it also seems rather complex and long-winded. Why not take advantage of Python’s
collections.Counterclass to write something short and simple: