3
\$\begingroup\$

This is a simple Rock - Paper - Scissor game. I'm trying to find a better way to write the algorithm and keeping the scoreboard.

#!/usr/bin/python
#
import random
import os
import json
import pprint
#-------------------------------------------------#
def main():
    user, sys = 0, 0
    name = os.getlogin()
    while True:
        dictionary  = {1:'Rock', 2:'Paper', 3:'Scissors'}
        sysChoice   = random.choice(dictionary.keys())
        try:
            userChoice  = int(raw_input("Select One [1:Rock, 2:Paper, 3:Scissors, 0:Exit] : "))
            if (userChoice in (1,2,3)):
                print "Computer Choice is   : ", sysChoice,  dictionary[sysChoice]
                print "Your Choice is       : ", userChoice, dictionary[userChoice]
                result = rockPaperScissors(sysChoice, userChoice)
                print "Result               : ", result
                if (result == 'Win'):
                    user    = user + 1
                    sys     = 0
                    scoreBoard(user, sys, name)
                elif (result == 'Lose'):
                    user    = 0
                    sys     = sys + 1
                    scoreBoard(user, sys, name)
                else:
                    sys, user = 0, 0
                    scoreBoard(user, sys, name)
            elif(userChoice == 0):
                topScore()
                break
            else:
                continue
        except ValueError:
            continue
#-------------------------------------------------#
def rockPaperScissors (a, b):
    if ((a) % 3 + 1 == b):
        return "Win";
    elif ((b) % 3 + 1 == a):
        return "Lose"
    else:
        return "Draw"
#-------------------------------------------------#
def scoreBoard(u, s, name):
    if (os.path.isfile("score.json")): 
        jsonFile = open("score.json", "r")
        data     = json.load(jsonFile)
        jsonFile.close()
        if name in data:
            print "Current Score        : ", u, s
            print "Top Score            : ", data[name]["user"], data[name]["sys"]
            if (u > (data[name]["user"])):
                data[name]["user"] = u
            if (s > (data[name]["sys"])):
                data[name]["sys"] = s
        else:
            data.update({name:{'user':0,'sys':0}})
        jsonFile = open("score.json", "w+")
        json.dump(data, jsonFile, indent=4)
        jsonFile.close()
    else:
        data = {name:{"user":0, "sys":0}}
        jsonFile = open("score.json", "w")
        json.dump(data, jsonFile, indent=4)  
        jsonFile.close()
        os.chmod("score.json", 0666)
#-------------------------------------------------#
def topScore():
    if (os.path.isfile("score.json")):
        jsonFile = open("score.json", "r")
        data     = json.load(jsonFile)
        jsonFile.close()
        dicts = [{k: v} for (k,v) in data.items()]
        dicts.sort(key=lambda d: (d.values()[0]['user'], d.values()[0]['sys'],))
        dicts.reverse()
        print "Top Score : "
        for item in dicts:
            for key in item:
                print '{0:<10} {1:>2} {2:>2}'.format(key, item[key]['user'], item[key]['sys'])
#-------------------------------------------------#
if __name__ == '__main__':main()
#-------------------------------------------------#
# EOF

JSON file for keeping score:

    {
        "user1": {
            "sys": 2, 
            "user": 2
        }, 
        "user2": {
            "sys": 3, 
            "user": 3
        }, 
        "user3": {
            "sys": 0, 
            "user": 6
        }
    }
\$\endgroup\$
1

3 Answers 3

2
\$\begingroup\$

You use a variable named dictionary. This is not helpful, as it's just the variable's type. Use meaningful variable names, how about handsigns or shapes or commands.

There are really three things being associated: the move names, the user input, and whatever internal representation you use. You currently have the user input being equivalent to the internal representation; that's okay. Initially I was against the idea of using a dictionary, but doing so allows you to use any user input.

Whatever variable name and type you use, the data structure does not need to be reinitialized in each loop. Set it once and leave it (though this may not affect your speed)

userChoice = int(raw_input("Select One [1:Rock, 2:Paper, 3:Scissors, 0:Exit] : ")) I don't like this, because it duplicates the contents of your dictionary structure. You should just have one copy of the mapping, and refer to it here.

if (userChoice in (1,2,3)): same thing with this. You should just check if it's one of the keys.

           print "Computer Choice is   : ", sysChoice,  dictionary[sysChoice]
           print "Your Choice is       : ", userChoice, dictionary[userChoice]

This is duplicated code. Factor it out into a new function.

user and sys are poor variable names. It took a while before I realized that they meant the length of the user's and computer's current winning streaks. The variable name should reflect its purpose.

Why do you have else and except blocks that do literally nothing?

\$\endgroup\$
0
1
\$\begingroup\$

If you want to learn Json this is a nice exercise to do so, but otherwise I suggest plain text files for simplicity:

def write_score(user, user_score, cpu_score):
    with open(LOG_FILE, 'a') as f:
        f.write("{}: {}, {}\n".format(
            user, user_score, cpu_score))

def retrieve_score(user):
    with open(LOG_FILE) as f:
        lines = f.readlines()

    user_line = [line for line in lines if line.startswith(user)]

    if not user_line:
        raise ValueError("User does not exist")

    name, points = user_line[0].replace('\n','').split(':')
    scores = points.split(',')
    return {'cpu_score' : int(scores[0]),
            'player_score' : int(scores[1])
            }
\$\endgroup\$
1
  • \$\begingroup\$ Yes, I wanted to use Json for learning it. \$\endgroup\$
    – rpeter
    Commented Apr 19, 2015 at 17:28
0
\$\begingroup\$

The one thing I notice, is every call to scoreBoard is opening a file (reading a value) and storing an updated value. Maybe this is best done once you exit the while loop. ie: open/read/update at the end only once. instead on each user input.

\$\endgroup\$
2
  • \$\begingroup\$ I agree, i was trying to avoid the situation users doing [Ctrl + C] and not updating the score. \$\endgroup\$
    – rpeter
    Commented Apr 19, 2015 at 17:30
  • \$\begingroup\$ You have already stated that user has to input 0 to exit. If the user chooses to ignore an hit ^c... that falls under validating your inputs. I wouldn't design my solution around that one aspect. Validation is important no doubt, but its a seperate issue. \$\endgroup\$
    – Pradyot
    Commented Apr 20, 2015 at 21:26

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.