Results 1 to 11 of 11
-
2019-08-08, 02:55 PM (ISO 8601)
- Join Date
- Jan 2010
- Location
- Inside
This smol snek is bamboozling (Python help)
I'm trying to teach myself some coding. Python 3.7. Lots of coffee. Still very new at this, and I'm finding it really hard to wrap my brain around the logic of how and why things work, embarrassingly often. But it's pretty fun. Often infuriating, but fun.
This code (putting it here in it's entirety, sorry for the numerous #comments) has two terms that are used to keep count of things, one that should reset after every loop (las), and one that shouldn't (pis).
What do I have to do to 'pis' to keep it from resetting? I'm quessing at least putting it outside of the loop somewhere, but that's ended in error messages so far, no matter what I try...
Spoiler: Code
Code:from random import * def quessgame(): s = randint(1, 100) #generates a random number q = 0 #this is needed, because terms just have to have a value before you do things with them? las = -1 #sets the starting point for quess count pis = 0 print ("Your secret random number is", s) #displays the random number, so testing code is easier while q != s: las += 1 #same as las = las+1. Bit more confusing this way? Any benefits? print("Quesses:", las) #this shows how many quesses you've had this time q = int(input("Quess the number between 1 - 100:")) if q < s-5: print("Number is higher") elif q > s+5: print("Number is lower") elif q < s: print("Close, but the number is slightly higher") elif q > s: print("Almost, but the number is a bit smaller") else: pis += 1 print("You quessed right,", s ," was correct") print("Correct answers so far: ", pis) #shows the number of right answers.. in theory print(".....................................") return quessgame() #starts the "game" over quessgame()
Last edited by thirsting; 2019-08-08 at 02:58 PM.
Well that was awkward.
-
2019-08-08, 03:41 PM (ISO 8601)
- Join Date
- May 2017
- Gender
Re: This smol snek is bamboozling (Python help)
Note: I'm quite familiar with python 2.7, but the differences with python 3.7 are mostly superficial, and shouldn't matter for this question.
If I understand correctly, 'pis' is supposed to track the total number of times you've won the game, correct?
Currently, you've got a function that seems to run the game once(you call it again at the end of the function to keep going, but fundamentally this function runs it only once), and you define PIS within the function. If you want PIS to keep tracking victories, you need to move it outside of the 'single game' function, as it gets reset whenever the function is called.
A very simple change that should probably work:
Spoiler: Code
Code:from random import * pis = 0 def quessgame(pis): s = randint(1, 100) #generates a random number q = 0 #this is needed, because terms just have to have a value before you do things with them? las = -1 #sets the starting point for quess count print ("Your secret random number is", s) #displays the random number, so testing code is easier while q != s: las += 1 #same as las = las+1. Bit more confusing this way? Any benefits? print("Quesses:", las) #this shows how many quesses you've had this time q = int(input("Quess the number between 1 - 100:")) if q < s-5: print("Number is higher") elif q > s+5: print("Number is lower") elif q < s: print("Close, but the number is slightly higher") elif q > s: print("Almost, but the number is a bit smaller") else: pis += 1 print("You quessed right,", s ," was correct") print("Correct answers so far: ", pis) #shows the number of right answers.. in theory print(".....................................") return quessgame(pis) #starts the "game" over quessgame()
In python 2.7, calling the function in itself will also eventually give you an error related to recursion depth (and I'd expect the same behaviour in 3.7), so I'd create a separate loop that keeps calling your function again and again, rather than re-calling it within the same function.
edit: I did a quick barebones test using code similar to yours, and it might be necessary to end the nested functions to be able to read out 'pis', post game (IE: outside the nested loop), as right now pis never gets returned from the function. That wouldn't matter in game-play, but will give a result of pis=0 if you call up the value of pis after a run for bug-fixing purposes.Last edited by DeTess; 2019-08-08 at 03:47 PM.
Jasnah avatar by Zea Mays
-
2019-08-08, 07:31 PM (ISO 8601)
- Join Date
- Jun 2008
- Location
- New Zealand
- Gender
Re: This smol snek is bamboozling (Python help)
The problem comes down to this line:
Code:return quessgame() #starts the "game" over
One general recommendation is to use longer variable names, real words rather than abbreviations. Faster to type may be nice, but easier to read is more important. It will help you in the long run.
I would also recommend splitting your code up into more functions. Have each function do one thing. Each part should be easier to understand in isolation, and you can get each part working one at a time. An important benefit is reducing the amount of shared state that each line of code has access to. Docstrings are also a good habit to get into.
Below I introduce two new things. First is the "itertools.count(n)" function, which produces a stream of numbers starting from "n", or from zero if not passed an argument. I find it easier to read than having "n += 1" somewhere in the loop body. The second is the "break" keyword, which immediately exits the containing loop. Compared to a while loop, using break in the for loop doesn't require any state to be set up before first entering the loop.
Code:from random import randint from itertools import count def input_guess(): """Prompts for a guess, returning the integer. No error checking yet.""" return int(input("Quess the number between 1 - 100: ")) def compare(guess, goal): """Compares a guess to the goal, printing a message and returning whether it matched.""" if guess < goal - 5: print("Number is higher") return False elif guess > goal + 5: print("Number is lower") return False elif guess < goal: print("Close, but the number is slightly higher") return False elif guess > goal: print("Almost, but the number is a bit smaller") return False else: print("You quessed right,", goal, "was correct") return True def one_round(goal): """Runs a single round, returning true if the guess was matches the given goal.""" guess = input_guess() return compare(guess, goal) def one_game(): """Runs a single game to completion.""" goal = randint(1, 100) print("Debug: the goal is ", goal) for guess_count in count(1): print("Quesses:", guess_count) if one_round(goal): break def game_loop(): """Keeps running games forever.""" for game_count in count(1): one_game() print("Correct answers so far: ", game_count) print(".....................................") game_loop()
Last edited by Excession; 2019-08-08 at 07:41 PM.
-
2019-08-09, 02:31 AM (ISO 8601)
- Join Date
- Jan 2010
- Location
- Inside
Re: This smol snek is bamboozling (Python help)
Wow, thank you. That does look more clear and clean. Now I just don't understand why or how anything works again, unlike in my own attempt which I could understand. :p But it works. Guess got to get tinkering with it until it doesn't seem like magic anymore..
Well that was awkward.
-
2019-08-09, 12:21 PM (ISO 8601)
- Join Date
- Mar 2007
- Location
- Oregon, USA
Re: This smol snek is bamboozling (Python help)
FeytouchedBanana eldritch disciple avatar by...me!
The Index of the Giant's Comments VI―Making Dogma from Zapped Bananas
-
2019-08-09, 12:36 PM (ISO 8601)
- Join Date
- Sep 2016
Re: This smol snek is bamboozling (Python help)
It should be noted that there are some programming styles that do something similar. The second call should always however be something simpler.
E.g
Code:def fib(n): if n<=1: return 1 else: return fib(n-1)+fin(n-2)
Python isn't really set up to make full use of it. Because it makes it harder to track down errors when they do occur, (but for the right kind of function easier to mathematically prove). It's fairly easy to restructure differently for complex cases (which in this case would be much more efficient), and pythons stack is big enough to handle simple uses.
Another thing to mention is classes. Again they break some of the nice assumptions you can make if you keep things functional. But they do provide a bit of a middle ground with regard to variables. You get to wrap things upnicely though in practice choosing the right boundaries is difficult.
Spoiler: TBH a bit forced, they come in their own when things get a bit bigger
Code:from random import randint class Game: from random import randint class Game: """A running (or finished) game""" def __init__(self,mintarget,maxtarget): self.goal=randint(mintarget,maxtarget) self.won=False self.lost=False self.guesses=0 def input_guess(self): """Prompts for a guess, returning the integer. No error checking yet.""" return int(input("Quess the number between 1 - 100: ")) def compare(self,guess): """Compares a guess to the goal, printing a message and returning whether it matched.""" if guess < self.goal - 5: print("Number is higher") return False elif guess > self.goal + 5: print("Number is lower") return False elif guess < self.goal: print("Close, but the number is slightly higher") return False elif guess > self.goal: print("Almost, but the number is a bit smaller") return False else: print("You quessed right,", self.goal, "was correct") return True def takeTurn(self): """Makes a single guess, has an interesting edge case""" self.guesses=self.guesses+1 if self.compare(self.input_guess()): self.won=True if self.guesses>=50: self.lost=True print("You took too long,", self.goal, "was the answer") def stopped(self): return self.won or self.lost class Game_Host: def __init__(self): self.wins=0 self.losses=0 self.currentgame=Game(1,100) def play(self): self.currentgame.takeTurn() if self.currentgame.stopped(): if self.currentgame.won: self.wins=self.wins+1 if self.currentgame.lost: self.losses=self.losses+1 self.currentgame=Game(1,100) def start(self): """plays the game forwever""" while True: print("Current Score is ",self.wins,",",self.losses) print("I don't know why I tell you this each turn") self.play() Game_Host().start()
-
2019-08-11, 03:56 PM (ISO 8601)
- Join Date
- Jun 2008
- Location
- New Zealand
- Gender
Re: This smol snek is bamboozling (Python help)
Working out the best way to split up code is a complex skill to learn. So is reading someone else's code I'm afraid.
Being sure you understand everything and it should all work perfectly is the normal starting point for a long, frustrating hour of debugging. Welcome to the wonderful world of computer programming.
-
2019-08-12, 01:21 AM (ISO 8601)
- Join Date
- Feb 2007
- Location
- Manchester, UK
- Gender
-
2019-08-12, 09:43 AM (ISO 8601)
- Join Date
- Jun 2013
- Location
- Bristol, UK
Re: This smol snek is bamboozling (Python help)
That's a nasty trap, that is very easy to fall into. If you're not 100% uncrazy, it's easy to write bugs so you can spend time finding them, and that's very bad. Binary chop on your code is your friend, it's not exciting, but it gets you to the relevant area fast (won't work that well if you've got two or more areas of code that are only buggy in interaction, but should find random characters).
The end of what Son? The story? There is no end. There's just the point where the storytellers stop talking.
-
2019-08-12, 10:07 AM (ISO 8601)
- Join Date
- Feb 2007
- Location
- Manchester, UK
- Gender
-
2019-08-12, 10:13 AM (ISO 8601)
- Join Date
- Jun 2013
- Location
- Bristol, UK
Re: This smol snek is bamboozling (Python help)
The end of what Son? The story? There is no end. There's just the point where the storytellers stop talking.