Recreating MasterMind game in Python? - python

EDIT:
Hi, earlier, I posted this question in a way that very lengthy. I am new to this site and did not know about the customs of posting. I will try again and be more specific with my question.
I moved a bit of my code into a tester file and this part returns an error. It seems that my count for blackpegs is not increasing because local variable 'blackpegs' was references before assignment.
blackpegs = 0
def test_guess(code,guess):
for x,y in zip(code,guess):
if x==y:
blackpegs += 1
return blackpegs
First, what does this mean? Secondly, how do I fix it?

You should move the variable definition to within the function definition. I'm guessing you also want the "return" statement to be indented at the same level as the if statement, so that it goes through the for loop rather than exiting after the first instance where x==y.
def test_guess(code,guess):
blackpegs = 0
for x,y in zip(code,guess):
if x==y:
blackpegs += 1
return blackpegs

Related

When returning a value from a function in python, it comes back empty

I am making a minmax algorithm for a simple board game. When the findparent function returns data, sometimes it works fine, othertimes it comes back empty for some reason. Please help.
Below is the malfunctioning part of the code.
from sys import maxsize
class Node(object):
def __init__(self,idepth,iplayernum,iboard):
self.idepth=idepth
self.iplayernum=iplayernum
self.iboard=iboard
self.children=[]
self.createchildren()
def createchildren(self):
if self.idepth>=0:
for x in range(0,4):
if self.iboard[x]>0:
for y in range(1,self.iboard[x]+1):
xiboard=self.iboard.copy()
xiboard[x]-=y
self.children.append(Node(self.idepth-1,-self.iplayernum,xiboard))
def checknodes(node,turn,ibestvalue,bestchoice):
for n in range(len(node.children)):
nchild=node.children[n]
childarr=[nchild,nchild.iboard]
for z in range(0,(idepth-nchild.idepth)):
childarr=findparent(childarr[0],inode)
print(childarr,'after return')
bestchoice=childarr[1]
if nchild.idepth>0:
checknodes(nchild,turn*-1,ibestvalue,bestchoice)
return(bestchoice)
def findparent(fnode,node):
for n in range(len(node.children)):
nhild=node.children[n]
if nhild==fnode and nhild.iboard==fnode.iboard:
print([node,node.iboard],'before return')
return [node,node.iboard]
elif nhild.idepth>0:
findparent(fnode,nhild)
iboardstart=[7,5,3,1]
idepth=3
icurplayer=1
row=int(input('The board is\n{}\n{}\n{}\n{}\nWhat row would you like to take from?'.format(iboardstart[0],iboardstart[1],iboardstart[2],iboardstart[3])))-1
amount=int(input('\nHow many would you like to take?'))
iboardstart[row]-=amount
icurplayer*=-1
inode=Node(idepth,icurplayer,iboardstart)
bestchoice=-100
ibestvalue=-icurplayer*maxsize
bestchoice=checknodes(inode,-1,ibestvalue,bestchoice)
iboardstart=bestchoice
print('Computer plays\n{}\n{}\n{}\n{}'.format(iboardstart[0],iboardstart[1],iboardstart[2],iboardstart[3]))
icurplayer*=-1
If you run it just input 1 for row and 1 for amount and see what it prints out.
Hope you can help me guys, I would really appreciate it.
Your issue is that findparent doesn't actually return anything from its recursive call.
However it's not as simple as return findparent(fnode,nhild) as this has the possibility of returning None if it's searching in the wrong branch. So you would need to get the value from the recursive call, check that the value exists, and then return it if it does.
You might try something like this:
def findparent(fnode, node):
value = None
for nchild in node.children:
if nchild is fnode and nchild.iboard == fnode.iboard:
print([node, node.iboard], 'before return')
value = [node, node.iboard]
elif nchild.idepth > 0:
value = findparent(fnode, nchild)
if value:
return value
As a side note, when looping through elements of a list, it's better to use
for nchild in node.children:
instead of
for n in range(len(node.children)):
nchild=node.children[n]
It seems there is a typo in checknodes method :
Try changing
childarr=findparent(childarr[0],inode)
into
childarr=findparent(childarr[0],node)

builtins.NameError: name 'guess' is not defined

I was working on a lab assignment and I've been struggling with an error for days. I coded return as well in my function and it keeps saying there's a NameError: and I didn't define it.
Here's the code I'm working on and it's all messed up since I'm not done. But I'd love to know what did I messed up and how can I fix the name error. Thanks!
import random
def main():
instructions = display_instructions("instructions.txt")
#display instructions
display_instructions(instructions)
list_of_words = ['apple', 'banana', 'watermelon', 'kiwi', 'pineapple',
'mango']
correct_word=random.choice(list_of_words)
answer = list(correct_word)
puzzle = []
puzzle.extend(answer)
display_puzzle_string(puzzle)
play_game(puzzle, answer)
display_result(is_win, answer)
input('Press enter to end the game.')
def display_instructions(filename):
instruction_file=open("instructions.txt","r")
file_contents=instruction_file.read()
instruction_file.close()
print(file_contents)
def display_puzzle_string(puzzle):
for i in range(len(puzzle)):
puzzle[i] = '_'
print('The answer so far is '+" ".join(puzzle))
def play_game(puzzle, answer):
num_guesses = 4
while num_guesses > 0:
get_guess(num_guesses)
update_puzzle_string(puzzle, answer, guess)
display_puzzle_string(puzzle)
is_word_found(puzzle)
def get_guess(num_guesses):
guess=input('Guess a letter '+'('+str(num_guesses)+' guesses remaining):')
return guess
def update_puzzle_string(puzzle, answer, guess):
for i in range(len(answer)):
if guess.lower() == answer[i]:
puzzle[i] = guess.lower()
num_guesses += 1
return puzzle
def is_word_found(puzzle):
if puzzle == answer:
return is_win
def display_result(is_win, answer):
if is_win:
print('Good job! You found the word '+correct_word+'!')
else:
print('Not quite, the correct word was '+correct_word+
'. Better luck next time')
main()
In the function play_game, you have the line get_guess(num_guesses) which returns the variable guess. However, you are not assigning the guess to a variable in the function. You can fix this by changing that line to guess = get_guess(num_guesses). The error tells you exactly what is wrong. You have not defined the variable guess so far.
Your code has different flaws. The main errors are related to indentation and function scopes. Keep in mind that Python uses indentation to group statements. Use 4 spaces consistently as indentation for grouping statements, e.g. to indent the function body, for-loop body etc.
Furthermore, there are many undefined name errors in your code, since you refer to names that are not defined in the current scope. Consider your function is_word_function(puzzle):
def is_word_found(puzzle):
if puzzle == answer:
return is_win
The name answer is defined in main(), whereas is_win is not defined at all (you are passing it to display_result() in main(), but have not defined it before). A better function declaration would look like this
def is_word_found(puzzle, answer):
return puzzle == answer
Note that this suggestion aims to be educational, I don't think that you necessarily need a function for this.
Generally, in order for names to be available in the current (function) scope, you have to either pass arguments to the function, or put them at module level, or - even better - consider looking into OOP (which, since this is a lab assignment, I suppose you haven't done yet).
Once you fixed these errors and your code compiles, you need to work on the logic of your game.
For example in play_game, you have the loop while num_guesses > 0 which will run infinitely, since you never decrease the num_guesses counter (in fact, you increase it in update_puzzle_string. A better loop would look like this:
def play_game(puzzle, answer, ..):
num_guesses = 4
while num_guesses and not is_word_found(puzzle, answer):
# logic
num_guesses -= 1
# or, alternatively
def play_game(puzzle, answer, ..):
num_guesses = 4
for _ in range(num_guesses):
# logic
if is_word_found(puzzle, answer):
# break or return
Consider to use flake8 in order to validate your code, detect errors and non-pythonic code constructs in the future.
>>> pip3 install flake8
>>> flake8 your_file.py

Decorator - changing variable name

I am learning the concepts of decorators in Python. While I think I have covered lots of blogs and have got some basic understanding how decorators work and why would we need one.
While doing so, I encountered a tutorial (totally lost the reference to this), where while explaining about decorators, the author wrote the following:
def call_counter(func):
def helper(x):
helper.calls += 1
return func(x)
helper.calls = 0
return helper
def succ(x):
return x + 1
succ = call_counter(succ)
print(succ.calls)
for i in range(10):
succ(i)
print(succ.calls)
Output:
0
10
As I mentioned earlier, I thought I understand how a decorator works and basic Python but suddenly am doubting myself here.
In helper function, the author is incrementing helper.calls variable by 1 (which should be, as per my previous understanding, just an ordinary variable and helper. is only to show this variable is inside helper function), but has only defined helper.calls after using it here , towards the end.
Similarly, towards end, after calling the decorator function, the author has suddenly used succ.calls variable - which is even printing expected result - but without any definition anywhere.
P.S. I have tried doing my research but could not even put this behaviour in proper words to find anything appropriate.
P.P.S. Could not come up with a more precise header as totally unfamiliar with the actual phenomenon happening.
succ = call_counter(succ) # succ.calls = 0 when function is called (succ = helper)
print(succ.calls) # prints 0
for i in range(10):
succ(i) # As succ = helper now, this becomes helper(i) and helper.i is incremented by 1 each iteration, succ(x) is then returned after as func = succ and x + 1 is returned from succ(x)
print(succ.calls) # prints 10 as helper.calls is incremented 10 times within the loop
The same output would have been achieved if succ(x) had returned no value as it was not used anywhere else, you can see your code visualized on http://www.pythontutor.com/visualize.html#mode=edit

python class doesn't work for different variable

dear expert i am trying to write a simulation and in my code i have a class like this:
... (some def are here)
class multipole:
global xxp,yyp,zzp,x,y,z,xp,yp,zp,t,tm,h
xxp,yyp,zzp,x,y,z,xp,yp,zp =xxpyypzzp() # some initial values calling
#staticmethod
def quad(f1, f2,f3):
global t,h,mass,ksimax
while t < ksimax:
rk4_two(t,h,mass, f1, f2, f3, xxp, yyp, zzp) # rk function for new xxp, yyp and zzp
t = t + h
tm.append(t)
xp.append(xxp[1])
x.append(xxp[0])
yp.append(yyp[1])
y.append(yyp[0])
zp.append(zzp[1])
z.append(zzp[0])
return xp, x, yp,y,zp,z,tm
if __name__ == "__main__":
qp=multipole()
quxp, qux, quyp,quy,quzp,quz,qutm=qp.quad(0.,0.,0.)
hxp, hx, hyp,hy,hzp,hz,htm =qp.quad(0.022,0.,0.)
oxp, ox, oyp,oy,ozp,oz,otm =qp.quad(-0.023,-0.032,0.0 )
my question is this code only calculate (quxp, qux, quyp,quy,quzp,quz,qutm), but not others (others will turn same value of quxp, qux, quyp,quy,quzp,quz,qutm) could you please tell me why? i am new in python any comments will be appreciated.
Ignoring the fact that this code is... somewhat flawed. I think that the problem is that you are using t which is apparently global but you don't reset it anywhere - so this loop:
while t < ksimax:
...
Will only run once, unless you reset t somewhere. Some pseudo code to explain why this happens:
counter = 0
def do_something():
global counter
print "Starting at", counter
while counter <= 10:
print counter
counter += 5
print "Done"
do_something()
# Starting at 0
# 0
# 5
# 10
# Done
do_something() # Called again, the counter is at 10 now:
# Starting at 10
# Done
As others have mentioned, your code could benefit from some heavy refactoring. Some starting points:
Naming! What does xxpyypzzp even mean? Even if it's obvious to you today, it must be hard to read even for you and unless you have Rainman-like memory you will not understand this next week. Try using descriptive names and if you find yourself adding prefixes or suffixes to variables because you run out of names - think about encapsulating some of this complexity in a class. It seems like the suffixes xp, x, yp, y, zp, z and tm are used a lot. At least create a named tuple to hold these values.
Global variables is generally considered harmful. They make it hard to reason about code - which is why you got this bug in the first place. If you are sprinkling global statements over your code there is time to redesign it. Think about which part of your code should "own" which parts of the state.
Python has a coding standard, called PEP8 - read it and try to follow it.

while loop in python issue

I started learning python few weeks ago (no prior programming knowledge) and got stuck with following issue I do not understand. Here is the code:
def run():
count = 1
while count<11:
return count
count=count+1
print run()
What confuses me is why does printing this function result in: 1?
Shouldn't it print: 10?
I do not want to make a list of values from 1 to 10 (just to make myself clear), so I do not want to append the values. I just want to increase the value of my count until it reaches 10.
What am I doing wrong?
Thank you.
The first thing that you do in the while loop is return the current value of count, which happens to be 1. The loop never actually runs past the first iteration. Python is indentation sensitive (and all languages that I know of are order-sensitive).
Move your return after the while loop.
def run():
count = 1
while count<11:
count=count+1
return count
Change to:
def run():
count = 1
while count<11:
count=count+1
return count
print run()
so you're returning the value after your loop.
Return ends the function early, prohibiting it from going on to the adding part.

Categories

Resources