Rock Paper Scissors

Rock Paper Scissors:

Do I really have to note which particular player wins? It was feeling so good.

paper = False
scissors = False

print "rock,paper or scissors?"

p1 = raw_input("Player1? ")
p2 = raw_input("Player2? ")

if p1 == p2:
    print "Tie"

if p1 == "rock":
    rock = True
if p2 == "rock":
    rock = True

if p1 == "paper":
    paper = True
if p2 == "paper":
    paper = True

if p1 == "scissors":
    scissors = True
if p2 == "scissors":
    scissors = True
    
if rock and paper:
    print "paper wins"
if rock and scissors:
    print "rock wins"
if scissors and paper:
    print "scissors wins"

if p1 not in ("rock","paper","scissors"):
    print "not valid player 1. Enter rock,paper or scissors"
if p2 not in ("rock","paper","scissors"):
    print "not valid player 2. Enter rock,paper or scissors"

print rock,paper,scissors

This is an orginal algorithm. Tried to make it simple (just couldn’t pass up using “not in”)

@TutorialDoctor - to format your code there are several options. The best way is to add three back ticks on a new line followed by the word python, your code on a new line and finally three back ticks to end things off:

```python
def some_python_code(param):
    print(param)
```

Which will be displayed like this:

def some_python_code(param):
    print(param)

Give it a try :smile:

2 Likes

I forgot we can use markdown. I had used the html code tag.

Here’s my take on it, which wraps the analysis of the input into a function …

# rps.py
# Rock Paper Scissors
def rps(p1, p2):
    # returns an int:
    # 1 if player 1 wins
    # 2 if player 2 wins
    # 0 if it is a tie

    # convert user input to lower case
    # and truncate to one character
    p1 = p1[0].lower()
    p2 = p2[0].lower()

    # player 1 checked in outer conditional blocks;
    # player 2 checked in inner conditional blocks
    if p1 == "r":
        if p2 == "r":
            return 0
        elif p2 == "p":
            return 2
        else:
            return 1
    elif p1 == "p":
        if p2 == "r":
            return 1
        elif p2 == "p":
            return 0
        else:
            return 2
    else:
        if p2 == "r":
            return 2
        elif p2 == "p":
            return 1
        else:
            return 0

print "Rock, Paper, Scissors"
winner = rps(raw_input("Player 1? "), raw_input("Player 2? "))
if winner != 0:
    print "Player " + str(winner) + " wins!"
else:
    print "It's a tie!"

But unlike my approach, @TutorialDoctor’s code simplifies things by checking for a tie first, which is a good idea. If I revise mine, that’s the first idea that I’ll borrow.

Another good feature of @TutorialDoctor’s code is that it checks for invalid input.

Inside of a function I did:

print "rock, paper or scissors?"


def Rules():
	p1 = raw_input("Player1? ")
	p2 = raw_input("Player2? ")

	choices = ["rock","paper","scissors"]
	rock = False
	paper = False 
	scissors = False
	if p1==p2:
		print "Tie"

	if p1=="rock":
		rock=True
	if p2=="rock":
		rock=True

	if p1=="paper":
		paper=True 
	if p2=="paper":
		paper=True 

	if p1=="scissors":
		scissors=True 
	if p2=="scissors":
		scissors=True

	if rock and paper:
		print "paper wins"
	if rock and scissors:
		print "rock wins"
	if scissors and paper:
		print "scissors wins"

	if p1 not in choices:
		print "Not valid player 1"
		Rules()
	elif p2 not in choices:
		print "Not valid player 2"
		Rules()
	else:
		print "Game over"
		
Rules()

This could certainly be made shorter (lots of repeating code), but I wanted to be elaborate for the assignment.

@TutorialDoctor has motivated me to add checking the validity of the players’ input to my code, so here goes …

# rps.py
# Rock Paper Scissors
def rps(p1, p2):
    # returns an int:
    # 1 if player 1 wins
    # 2 if player 2 wins
    # 0 if it is a tie

    # Convert user input to lower case
    # and truncate to one character
    p1 = p1[0].lower()
    p2 = p2[0].lower()

    if p1 == p2:
        # Tie; Credit to @TutorialDoctor
        return 0
    elif p1 == "r":
        if p2 == "p":
            return 2
        else:
            return 1
    elif p1 == "p":
        if p2 == "r":
            return 1
        else:
            return 2
    else:
        if p2 == "r":
            return 2
        else:
            return 1
        
print "Rock, Paper, Scissors"
print "Each player enter r, p, or s."

# Player 1 input
while True:
    p1 = raw_input("Player 1? ")
    if len(p1) > 0 and p1[0].lower() in "rps":
        break

# Player 2 input
while True:
    p2 = raw_input("Player 2? ")
    if len(p2) > 0 and p2[0].lower() in "rps":
        break

# Determine and announce outcome
winner = rps(p1, p2)
if winner != 0:
    print "Player " + str(winner) + " wins!"
else:
    print "It's a tie!"

What I don’t like about my code:

  • The rps function should check the validity of the two values that are passed to it, and raise an exception if either or both are invalid. But, since the function must be called with both players’ input, postponing error checking until the function is called would mean that if player 1 entered invalid input, the program would not react to it until player 2 supplied input. That’s why I implemented validity checking outside the function instead of within. But that bugs me; it does seem right to have the function validate the values that it is passed.
  • Converting the input to lowercase and truncating it to one character both outside and inside
    the rps function is redundant. But, again, it seems that the function should do most of the work, so that it is as convenient as possible to use.

So, please offer suggestions for improvements.

Here’s another version that has the player play against the computer, and loops until the player quits. Note that there is a global variable, history, in there that is not currently used for anything. A tuple is appended to it during each round, that represents the player’s and the computer’s choices. It is there for future development, so that an algorithm can be implemented whereby the computer makes informed guesses regarding the player’s next choice, and biases its own choice accordingly. That algorithm would be implemented in the getComputerInput function.

# rpsloop.py
# Rock Paper Scissors
# May 15, 2015

import random
def rps(p1, p2):
    # returns an int:
    # 1 if player 1 wins
    # 2 if player 2 wins
    # 0 if it is a tie

    # Convert user input to lower case
    # and truncate to one character
    p1 = p1[0].lower()
    p2 = p2[0].lower()
    
    # Check validity of argument values
    if type(p1) != str or type(p2) != str:
        raise TypeError
    if p1 not in "rps" or p2 not in "rps":
        raise ValueError

    # Determine outcome
    if p1 == p2:
        return 0
    elif p1 == "r":
        if p2 == "p":
            return 2
        else:
            return 1
    elif p1 == "p":
        if p2 == "r":
            return 1
        else:
            return 2
    else:
        if p2 == "r":
            return 2
        else:
            return 1
        
def initializeGame():
    global history
    global p1_score
    global p2_score
    global tie_score
    history = [] # list of tuples recording the sequence of plays
    p1_score = 0
    p2_score = 0
    tie_score = 0
    print "Rock, Paper, Scissors"

def getComputerInput():
    # Pick a "random" choice
    global history
    choice = random.randint(0, 2)
    return ["r", "p", "s"][choice]

def getPlayerInput():
    while True:
        player_input = raw_input("Player? (r, p, or s) (q to quit): ")
        if len(player_input) > 0 and player_input[0].lower() in "rpsq":
            return player_input

def processData(p1, p2):
    global history
    global p1_score
    global p2_score
    global tie_score
    # Add the plays to history
    history.append((p1, p2))
    print "Computer: " + {"r": "rock", "p": "paper", "s": "scissors"}[p2] + "   Player: " +  {"r": "rock", "p": "paper", "s": "scissors"}[p1],
    winner = rps(p1, p2)
    if winner == 0:
        print ": Tie"
        tie_score += 1
    elif winner == 1:
        print ": Player wins"
        p1_score += 1
    else:
        print ": Computer wins"
        p2_score += 1
    print "Player: " + str(p1_score) + "  Computer: " + str(p2_score) + "  Tie: " + str(tie_score)

# Set up the game
initializeGame()

# Loop until player quits
while True:
    print # leave a blank line
    # Computer goes first, so that we do not
    # accidentally program it to cheat.
    computer_input = getComputerInput()
    # Player's turn
    player_input = getPlayerInput()
    if player_input == "q":
        print "Game over"
        break
    processData(player_input, computer_input)

That’s neat to include playing against the computer.

The previous version of the game that implements playing against the computer does not present an opportunity for a strategy, because the computer’s choice is determined pseudo-randomly, with an essentially equal chance that it will choose rock, paper, or scissors. But, the getComputerInput function can be modified to take the player’s history into account. The simplest strategy that the computer can employ would be to predict that the player has the same likelihood of making each choice as the proportion that particular choice represents of the total number of choices that the player made previously. For example, if 10 out of 40 choices that the player made in the past were paper, the prediction would be that the player would choose paper 10 out of 40 times in the future. Accordingly, the computer would employ the strategy of choosing scissors in a proportion of about 10 out of 40 rounds, because scissors beats paper.

The following revision of the getComputerInput function implements a strategy that is close to what is described above, but slightly modified to accommodate the first round of the game, when there is no history to consult. The computer picks a number between 1 and the total number of previous rounds + 3. The number that is chosen is mapped to rock, paper, or scissors, based on a proportion related to the player’s history.

To use the new version of the function, which is displayed below, simply copy it, and paste it in place of the original version of the function.

So, what should the player’s strategy be, considering that the computer is using this algorithm? I’m not sure, but would suggest that the player consider what the computer is most likely to choose, based on the player’s past choices. For example, if the player has chosen rock most of the time in the past, then the computer is most likely to choose paper, based on the algorithm. So the player should now begin to favor scissors, in order win by cutting that paper.

Here’s the new version of the function:

def getComputerInput(): # make it generative
    # Pick a "randomized" choice,
    # biased according to the players past choices
    # For example, if the player has picked mostly paper,
    # the computer will favor choosing scissors
    global history
    user_r_count = 0
    user_p_count = 0
    user_s_count = 0
    # Total up choices that user has made duirng previous rounds
    for h in history:
        ch = h[0]
        if ch == "r":
            user_r_count += 1 # rock count
        elif ch == "p":
            user_p_count += 1 # paper count
        else:
            user_s_count += 1 # scissors count
    r = random.randint(1, user_r_count + user_p_count + user_s_count + 3)
    # Bias the computer's randomized choice, based on player history
    if r <= user_r_count + 1:
        return "p"
    elif user_r_count + 1 < r <= user_r_count + user_p_count + 2:
        return "s"
    else:
        return "r"

For fun, a cool rendition of Rock, Paper, Scissors:

http://ludumdare.com/compo/ludum-dare-32/?action=preview&uid=50449