5
\$\begingroup\$

I will post 2 scripts that are doing (supposedly) the same thing. First one is the script i created, second one is the solution from the course.

What would you consider wrong (if anything) with the script that i made? Should i think scripts more like the second one, with functions and so?

My script

import random

print(art.logo)
print("Welcome to the number guessing game! ")
print("I'm thinking of a number between 1 and 100.")

difficulty = input("Choose a difficulty. Type 'easy' or 'hard': ")

ATTEASY = 10
ATTHARD = 5
playAgain = True

while playAgain :
  numberIs = random.randint(0,100)
  atteasy = ATTEASY
  atthard = ATTHARD
  
  while atteasy and atthard != 0 :  
    if difficulty == "easy" :
      print(f"You have {atteasy} attempts remaining to guess the number. ")
      guess = input("Make a guess: ")
      if int(guess) == numberIs : 
        print(f"You are right! The number was indeed {numberIs}")
        break
      else : 
        if int(guess) > numberIs :
          print("To high.")
        else : 
          print("To low.")
        atteasy = atteasy - 1
        if atteasy != 0 : 
          print("Guess again.")
    else :
      print(f"You have {atthard} attempts remaining to guess the number. ")
      guess = input("Make a guess: ")
      if int(guess) == numberIs : 
        print(f"You are right! The number was indeed {numberIs}")
        break
      else : 
        if int(guess) > numberIs :
          print("To high.")
        else : 
          print("To low.")  
        atthard = atthard - 1
        if atthard != 0 : 
          print("Guess again.")
        
  if atteasy or atthard == 0 :
    print(f"You lost. The numbers was {numberIs}")
  break

Script from the course

For comparison, not for review:

from random import randint

EASY_LEVEL_TURNS = 10
HARD_LEVEL_TURNS = 5

#Function to check user's guess against actual answer.
def check_answer(guess, answer, turns):
  """checks answer against guess. Returns the number of turns remaining."""
  if guess > answer:
    print("Too high.")
    return turns - 1
  elif guess < answer:
    print("Too low.")
    return turns - 1
  else:
    print(f"You got it! The answer was {answer}.")

#Make function to set difficulty.
def set_difficulty():
  level = input("Choose a difficulty. Type 'easy' or 'hard': ")
  if level == "easy":
    return EASY_LEVEL_TURNS
  else:
    return HARD_LEVEL_TURNS

def game():
  #Choosing a random number between 1 and 100.
  print("Welcome to the Number Guessing Game!")
  print("I'm thinking of a number between 1 and 100.")
  answer = randint(1, 100)
  print(f"Pssst, the correct answer is {answer}") 

  turns = set_difficulty()
  #Repeat the guessing functionality if they get it wrong.
  guess = 0
  while guess != answer:
    print(f"You have {turns} attempts remaining to guess the number.")

    #Let the user guess a number.
    guess = int(input("Make a guess: "))

    #Track the number of turns and reduce by 1 if they get it wrong.
    turns = check_answer(guess, answer, turns)
    if turns == 0:
      print("You've run out of guesses, you lose.")
      return
    elif guess != answer:
      print("Guess again.")

game()
\$\endgroup\$

2 Answers 2

7
\$\begingroup\$

Your script

First of all, it won't run since art is undefined. I'm going to assume that this is some kind of ASCII art you didn't include in the question.

Avoid putting all of your code right into the global namespace; use functions instead.

playAgain should be named play_again.

Your logic dividing up atteasy and atthard has a lot of repeated code. Why not just make one attempt variable that's conditionally assigned before your loop?

Grammar: to high and to low should be too high and too low.

Your int(guess) assumes that the user entered an integer which may not be the case; this would benefit from validation.

You should indent at four spaces and not two.

What should be done instead

  • indent at four spaces instead of two
  • add functions, and add type hints to the signature of those functions
  • write subroutines such as a check_answer that compares the answer and guess, and returns a boolean indicating whether the guess was successful
  • All #comments that you add should have a space between the hash and the text.
  • Add """docstrings""" to the first line inside your functions. No other comments before the functions are necessary.
  • Consider writing a subroutine to set the number of guesses based on a difficulty lookup dictionary
  • Your entry point should be wrapped in a __main__ guard

Suggested

Based roughly on the "course" script.

from random import randint

DIFFICULTIES = {
    'easy': 10,
    'hard': 5,
}


def check_answer(guess: int, answer: int) -> bool:
    """checks answer against guess. Returns true if the guess was correct."""

    if guess == answer:
        print(f"You got it! The answer was {answer}.")
        return True

    if guess > answer:
        direction = "high"
    else:
        direction = "low"

    print(f"Too {direction}.")
    return False


def set_difficulty() -> int:
    names = ', '.join(DIFFICULTIES.keys())
    while True:
        level = input(f"Choose a difficulty. Type one of: {names}: ")
        difficulty = DIFFICULTIES.get(level)
        if difficulty is not None:
            return difficulty


def game() -> None:
    print("Welcome to the Number Guessing Game!")
    print("I'm thinking of a number between 1 and 100.")
    answer = randint(1, 100)
    print(f"Pssst, the correct answer is {answer}")

    turns = set_difficulty()

    for turn in range(turns, 0, -1):
        print(f"You have {turn} attempts remaining to guess the number.")

        while True:
            try:
                guess = int(input("Make a guess: "))
                break
            except ValueError:
                print("Invalid number.")

        if check_answer(guess, answer):
            return

    print("You've run out of guesses, you lose.")


if __name__ == '__main__':
    game()
\$\endgroup\$
6
  • 2
    \$\begingroup\$ This review has useful content and I upvoted it. But it lacks a definitive statement that the scripts' problems are not equivalently serious. So I guess I'll make that statement here: put your code in functions, folks. \$\endgroup\$
    – FMc
    Feb 27, 2022 at 4:34
  • \$\begingroup\$ Woa. This is amazing. Exactly what i was looking for. Thank you very much ! \$\endgroup\$
    – perj
    Feb 27, 2022 at 5:24
  • \$\begingroup\$ @FMc Thank you for your answer. But can you explain why? Why shoul i put my code into functions? \$\endgroup\$
    – perj
    Feb 27, 2022 at 5:27
  • \$\begingroup\$ The site rules forbid reviewing third-party code. Could you either rephrase the critique of the course's code as advice for the poster, or delete that part of your answer? \$\endgroup\$ Feb 27, 2022 at 5:29
  • 1
    \$\begingroup\$ @200_success Sure; I've modified my language \$\endgroup\$
    – Reinderien
    Feb 27, 2022 at 14:12
1
\$\begingroup\$

I think here are two examples where you either do not fully understand Python syntax or should maybe make it more explicit what you mean:

while atteasy and atthard != 0 :

and

if atteasy or atthard == 0 :

Python parses the latter as:

if (atteasy) or (atthard == 0):

and not as

if (atteasy == 0) or (atthard == 0):

In Python non-zero integers are truthy and zero is falsey, so if atteasy and if atteasy != 0 are the same, as long as the variable is an integer. See these examples:

a, b = 1, 4
if a and b == 4:
    print("This will print")

c, d = 0, 4
if c or d == 0:
    print("This will not print")

Either you wanted it to be this way, then you should probably make it explicit:

if atteasy != 0 or atthard == 0:

Or you did not mean it and you should fix it with one of these (in this case) equivalent ways:

if atteasy == 0 or atthard == 0:
if not atteasy or not atthard:
if not (atteasy and atthard):
if 0 in (atteasy, atthard):
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.