[Tutor] Trying to select an input from another Python file & output that input in the main game program

Alan Gauld alan.gauld at yahoo.co.uk
Fri Jun 18 14:10:49 EDT 2021


On 17/06/2021 12:50, D Rochester wrote:

> I have spent many hours trying to solve this problem. 

I suspect in part that's because you are writing very complex
code using lots of global variables as flags to terminate
loops etc. It reminds me of the kind of code we used to
see in primitive BASIC programs.

Others have addressed the issues around your use of a CSV file.

But in your general code you should not need so many test
variables, see below:

> # starts loop for logging in
> while loop == 1:
>     username = input("Enter your username;\n")
>     print(username)
>     if username == userdataList[0][0] or username == userdataList[0][2]:
>         #print(username)
>         print("Verified user. Please enter your password")
>         while True:
>             password = input("Enter your password.\n:")
>             if password == userdataList[0][1] or password ==
> userdataList[0][3]:
>                 print(username,"You have been logged in. Welcome to the
> game.")
>                 loop = 0
>                 break # breaks loop and starts program
>             else:
>                 print("Wrong password.")
>     else:
>         print("No such user registered. Please enter a valid username.")
> game_menu.menu()

You could simplify that by splitting it into two separate loops,
one to get the user name the other for the password. No need for the
nested structure which is harder to read and debug.

while True:
   user = input....
   if valid user
      break

while True:
   pwd = input....
   if valid pwd:
      break

At this point you have a valid user with a valid pwd.
And no need for a loop variable.

> After access is granted the game begins. I have an additional 2 csv files
> called 'scores' & 'songs'. After completing the game the output should
> detail the user that was playing but it doesn't, it always details the 1st
> user ('abc'). I know it's because of the line of code detailed in the
> 'game_menu'; scoredataAdd.writerow([globalpoints, userdataList[0][0]]). The
> latter element references the first point in the csv file but what I need
> it to do is to be able to reference the correct user from the opening file.
> I can make it do that by [0][2] but that's not how it should work, it
> should be automatically pulled into the output.

So use the user data that you captured. Put the game code in a function
that takes a user name as an input argument. Call that function
immediately after a successful login:

start_game(user)

> # variables here
> gameloop1 = 1
> globalpoints = 0
> chances = 2
> rngnum = 0
> 
> # random number generator for random songs (rng)
> def rng():
>     global rngnum
>     rngnum = int(random.randint(0,5))

You don't need the int(), randint already returns an int
And you shouldn't need the global either, instead return
the number and assign the function result:

def rng()
    return random.randint(0,5)

rngnum = rng()

I'll assume you intend to do something more sophisticated later,
otherwise you might as well just do the assignment once:

rngnum = random.randint(0,5)

> def menu():
>     # declare variables global so we can use them in the function
>     global rngnum
>     global gameloop1
>     global globalpoints
>     global chances

This function is not really a menu. It is the whole
game - the start_game() that I described above.

Also you only need to declare variables as global if
you will be changing them. And you only need global
variables if they will be shared between functions
(and even then not always)

Your gameloop should be a local variable since its only
used inside the function. I suspect the same is true
of most/all of the others. Global variables are considered
bad practice, you should do all you can to remove them
from your code.

>     # intro text
>     print("Welcome to the song guessing game.")
>     print("You will be randomly presented with the first letter of each
> song title")
>     print("and each artist of the song.")
>     print("Each one you get correct will add 2 points onto your score, 1 if
> you take 2 guesses.")
>     print("You get 2 chances to guess. Guessing incorrectly on the second
> guess")
>     print("will end the game.")
>     print("At the end, your high score will be displayed.")
>     print("The game will now start.")

You might consider using a triple quoted string for the welcome
message. Easier to read, edit and very slightly more efficient.)

>     # loads song data
>     songdata = open("songs.csv", "r")
>     songdataRead = csv.reader(songdata)
>     songdataList = list(songdataRead)
> 
>     #loads user data
>     userdata = open("users.csv", "r")
>     userdataRead = csv.reader(userdata)
>     userdataList = list(userdataRead)

You already have the user details when they logged in so just
pass them from the login code to this function. Then you
don't need to read it all over again.


>     # appends score data
>     scoredata = open("scores.csv", "a", newline="")
>     scoredataAdd = csv.writer(scoredata)

Up to here you've done a lot of initialization but no menu
has been presented, despite the name of the function....

>     # actual game
>     while gameloop1 == 1:

Just use while True and break statements as needed.

>         rng()
>         print("What song is it?")
>         print(songdataList[rngnum][0][0] + " , by " +
> songdataList[rngnum][1])
>         #print(rngnum)
>         userinputchoice = input(": ")
>         if userinputchoice == songdataList[rngnum][0]:
>             if chances == 2:
>                 globalpoints += 3
>                 print("You have got " + str(globalpoints) + " points.\n")

You don't need the str() conversion of points,
print() does that for you.

>                 chances = 2

This code only executes if chances already equals 2, this
line is therefore pointless.

>             #elif chances == 1:
>                 #globalpoints += 1
>                 #print("You have got " + str(globalpoints) + " points.\n")
>                 #chances = 2
>         else:
>             chances -= 1
>             print("You have " + str(chances) + " chances left.\n")

Again, no need for str()

>             if chances == 0:
>                 gameloop1 = 0
>             gameloop2 = 1
>             while gameloop2 == 1:
>                 print("Guess again.")
>                 userinputchoice2 = input(": ")
>                 if userinputchoice2 == songdataList[rngnum][0]:
>                     if chances == 1:
>                         globalpoints += 1
>                         print("You have got " + str(globalpoints) + "
> points.\n")
>                         chances = 2
>                         gameloop2 = 0
>                 else:
>                     gameloop2 = 0
>                     gameloop1 = 0
> 

Again you don;t need the gameloop variables, they just
complicate things.

>             #print("You have " + str(chances) + " chances left.\n")
>     print("The game has ended.")
>     print("Well done, you have scored", str(globalpoints) + ".")
> 
>     #adds score to table
> 
>     scoredataAdd.writerow([globalpoints, userdataList[0][0]])
> #userdataList[0][0]])# Remember to amend the userdataList here as you have
> added another user
>     scoredata.close()

You should probably put the following code into a separate function.
If you put the login code into a function too then your top level code
would be:

user = login()
play_game(user)
report_stats()


>     print("Top 5 scores nationally:\n")
> 
>     # quickly opens up score data
>     scoreRead = open("scores.csv", "r")
>     scoreReadReader = csv.DictReader(scoreRead)
> 
>     # sorts the list of values
>     newList = sorted(scoreReadReader, key=lambda row: int(row['Score']),
> reverse=True)
> 
>     # prints scores
>     print("Rank | Score | Name\n")
>     for i, r in enumerate(newList[0:50]):
>         print('{} | {} | {}'.format(str(int(i)+1), r['Score'], r['Name']))

Keep the code simple and it will be easier to debug.
Simple code comes from simple data.
You can keep with 3 csv files, but simplify their structure.
Alternatively learn SQLite and use a single database with
3 tables.

If you need an intro to SQLite you could try my tutorial and the
Database section. But for now I'd suggest sticking with the 3 files,
you have enough to do learning good Python idioms.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos




More information about the Tutor mailing list