Python Forum
Rock paper scissors in python with "algorithm"
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Rock paper scissors in python with "algorithm"
#11
Very good code, it would greatly simplify the one I have, but I insist that I can only use the new code, I only need to create the get_winner, which now I do not understand because I have to enter the new parameter.
Reply
#12
This is a fairly simple programming task. You have a list of opponent plays. You need to determine which play appears most often in the list. This is your prediction of what the opponent will play next. You chose a play that defeats this play.

Write out the algorithm any way you want (other than using Python). Use natural language, pseudo code, draw pictures. Once the algorithm is defined well enough that you can describe it to others, implement the algorithm in Python. Programming and coding are two different tasks.

Don't let despair make a mountain out of this molehill.
Agat0 likes this post
Reply
#13
I understand but I've been like this for several days and I can't, I don't know how to create it.
Reply
#14
Write the algorithm and post it here. Don't worry about what you partner wrote, just focus on what needs to be done to pick a move that beats the most common move made by the opponent.

After doing that, convert it to Python and write a standalone test program to verify it works. Something like this:
def get_winning_move(history):
    # your code goes here
    return selected_move

print(get_winning_move([1, 1, 1, 0, 0]), "should be 2: scissors")
print(get_winning_move([1, 2, 1, 2, 0]), "should be 0: rock")
print(get_winning_move([1, 0, 2, 0, 0]), "should be 1: paper")
Once you have that working it should be easier to see how this code can be integrated with the existing code.

For entertainment purposes the program below plays Rock, Paper, Scissors, Lizard, Spock using a history based AI. It can also play Rock, Paper, Scissors or any other similarly constructed game based on rules you provide. Notice the lack of aggravating enumerated types and rediculously long function and variable names.
""" Rock-Paper-Scissors like rule based game creator."""

import random
 
class Player:
    """A human player.  Human players enter play by typing in a one letter abbreviation"""
    def __init__(self, plays, name=None):
        self.name = "Player" if name is None else name
        self.abbr = {play.abbr:play for play in plays.values()}
        prefix = "Select" if name is None else f"{name} select"
        self.prompt = f"{prefix} {', '.join([play.menu_name for play in plays.values()])}: "
 
    def choice(self, _):
        """Get player choice"""
        while True:
            abbr = input(self.prompt).upper()
            if abbr in self.abbr:
                return self.abbr[abbr]
            print(f"{abbr} is not a valid selection")
 
 
class Computer:
    """A computer player.  The computer's choice is based on opponent's move history"""
    def __init__(self, plays, name="Computer"):
        self.name = name
        self.plays = plays
        self.play_names = list(plays.keys())
 
    def choice(self, history=[]):
        """Predict what opponent will do based on history.  Select move that defeats predicted move"""
        opp_choice = self.plays[random.choice(self.play_names + history)]
        winning_plays = [play for play in self.plays.values() if play.beats(opp_choice)]
        return random.choice(winning_plays)
 
 
class Play:
    """A play in a Rock/Paper/Scissor type game"""
    def __init__(self, name, plays):
        self.rules = {}
        self.name = name
        self.key = name.upper()
        # Pick a unique abbreviation for player selection
        abbr = [play.abbr.upper() for play in plays.values()]
        for index, self.abbr in enumerate(self.key):
            if self.abbr not in abbr:
                break
        self.menu_name = name.replace(name[index], f"({name[index]})", 1)
 
    def add_rule(self, loser, rule):
        """Tell me how I beat other moves"""
        self.rules[loser.upper()] = rule
 
    def beats(self, other):
        """Return rule if I beat other, else None"""
        return self.rules.get(other.key, None)
 
 
class Game:
    """
    Create a Rock/Paper/Scissor type game based on a list of rules
    in the form: MOVE_A defeats MOVE_B
    """
    def __init__(self, rules):
        # Create plays.  Rules start and end with a play name.
        self.plays = {}
        for rule in rules:
            words = rule.split()
            winner = words[0]
            loser = words[-1]
            key = winner.upper()  # Make case insensitive
            if key not in self.plays:
                self.plays[key] = Play(winner, self.plays)
            self.plays[key].add_rule(loser, rule)
 
    def play(self, rounds=-1, p1=None, p2=None):
        """Play the game.
        Use rounds to set how many rounds are played.  if < 0, play til someone wins
        Use p1 to set player 1 name.  If None, player name is "Player".
        Use p2 to set select player 2 type. If None, player 2 is Computer, else  Player(p1)"""
        player = [Player(self.plays, p1), Computer(self.plays) if p2 is None else Player(self.plays, p2)]
        results = {
            player[0].name: 0,
            player[1].name: 0,
            "Draw":0
        }
        history = []
 
        # Play game
        while rounds != 0:
            rounds -= 1
            play = [p.choice(history) for p in player]
            history.append(play[0].key)  # TBD: Change to only record player[0] wins?

            if play[0] == play[1]:
                results["Draw"] += 1
                print("Both player select {play[0].name.  Draw.\n")
            else:
                winner, rule = 0, play[0].beats(play[1])
                if rule is None:
                    winner, rule = 1, play[1].beats(play[0])
                results[player[winner].name] += 1
                print(
                    f"{player[0].name} selects {play[0].name}, "
                    f"{player[1].name} selects {play[1].name}. "
                    f"{rule}. {player[winner].name} wins!\n")
                if rounds < 0:
                    return  # Game was play until winner
 
        print("\nResults")
        for name, count in results.items():
            print(f"{name:10} : {count}")
 
# Single player Rock/Paper/Scissors/Lizard/Spock game
Game([
    "Rock crushes scissors",
    "Rock crushes lizard",
    "Paper covers rock",
    "Paper disproves Spock",
    "Scissors cuts paper",
    "Scissors decapitates lizard",
    "Lizard eats paper",
    "Lizard poisons Spock",
    "Spock smashes scissors",
    "Spock vaporizes Rock",
]).play(-1)
 
# Bert and Ernie play Rock/Paper/Scissors 3 times
# Game(["Rock crushes scissors", "Paper covers rock", "Scissors cuts Paper"]).play(3, "Bert", "Ernie")
Agat0 likes this post
Reply
#15
In the end I was able to do it thanks to what I was looking for through the dictionary of victory made
Reply
#16
Please post entire error trace.

You get an error because computer_action is an integer, not a GameAction.
from enum import IntEnum

class GameAction(IntEnum):
    Piedra = 0
    Papel = 1
    Tijeras = 2
    Lagarto = 3
    Spock = 4

x = 1
y = GameAction(x)

print(x, y)
Output:
1 GameAction.Papel
x is an int, y is a GameAction. You need to convert the computed computer_action from int to a GameAction.
Agat0 likes this post
Reply
#17
In the end I was able to do it thanks to what I was looking for through the dictionary of victory madeon]
Reply
#18
In the end I was able to do it thanks to what I was looking for through the dictionary of victory made
Reply
#19
Trying to stay within the restraints of the original code I would write the code like this:
import random
from enum import IntEnum

class GameResults(IntEnum):
    Win = 0
    Lose = 1
    Draw = 2


class GameAction(IntEnum):
    Piedra = 0
    Papel = 1
    Tijeras = 2

    def __str__(self):
        """Return str more suited for program."""
        return f"{self.name}[{self.value}]"


winning_results = {
    (GameAction.Piedra, GameAction.Tijeras) : "Piedra smashes tijeras",
    (GameAction.Papel, GameAction.Piedra) : "Papel covers piedra",
    (GameAction.Tijeras, GameAction.Papel) : "Tijeras cuts Papel",
}


def get_user_action():
    """Get user selection"""
    prompt = f"""\nPick {", ".join([str(action) for action in GameAction])}: """
    while True:
        try:
            action = input(prompt)
            return GameAction(int(action))
        except ValueError:
            print(f"{action} is not a valid choice")


def get_computer_action():
    """Get computer selection"""
    return random.choice(list(GameAction))


def assess_game(user_action, computer_action):
    if user_action == computer_action:
        return GameResults.Draw, ""
    if (user_action, computer_action) in winning_results:
        return GameResults.Win, winning_results[(user_action, computer_action)]
    return GameResults.Lose, winning_results[(computer_action, user_action)]


def main():
    """Play a game of rock, paper, scissors"""
    while True:
        user_action = get_user_action()
        computer_action = get_computer_action()
        result, rule = assess_game(user_action, computer_action)
        if result == GameResults.Draw:
            print("Player and computer pick {}.  Draw".format(user_action.name))
        elif result == GameResults.Win:
            print("Player picks {}, computer picks {}.  {}.  Player wins!".format(
                user_action.name, computer_action.name, rule))
        else:
            print("Player picks {}, computer picks {}.  {}.  Computer wins.".format(
                user_action.name, computer_action.name, rule))

        if input("\nAnother round? (y/n): ").upper() != "Y":
            break


if __name__ == "__main__":
    main()
I don't think the enumerated types add value, but they aren't too onerous.

Adding in the history based AI is just a few new lines.
import random
from enum import IntEnum

class GameResults(IntEnum):
    Win = 0
    Lose = 1
    Draw = 2


class GameAction(IntEnum):
    Piedra = 0
    Papel = 1
    Tijeras = 2

    def __str__(self):
        """Return str more suited for program."""
        return f"{self.name}[{self.value}]"


winning_results = {
    (GameAction.Piedra, GameAction.Tijeras) : "Piedra smashes tijeras",
    (GameAction.Papel, GameAction.Piedra) : "Papel covers piedra",
    (GameAction.Tijeras, GameAction.Papel) : "Tijeras cuts Papel",
}


def get_user_action():
    """Get user selection"""
    prompt = f"""\nPick {", ".join([str(action) for action in GameAction])}: """
    while True:
        try:
            action = input(prompt)
            return GameAction(int(action))
        except ValueError:
            print(f"{action} is not a valid choice")


def get_computer_action(history=[]):
    """Get computer selection.  Use history to predict what user will do"""
    user_action = random.choice(history + list(GameAction))
    computer_actions = [action for action in list(GameAction) if (action, user_action) in winning_results]
    return random.choice(computer_actions)


def assess_game(user_action, computer_action):
    if user_action == computer_action:
        return GameResults.Draw, ""
    if (user_action, computer_action) in winning_results:
        return GameResults.Win, winning_results[(user_action, computer_action)]
    return GameResults.Lose, winning_results[(computer_action, user_action)]


def main():
    """Play a game of rock, paper, scissors"""
    history = []
    while True:
        user_action = get_user_action()
        computer_action = get_computer_action(history)
        result, rule = assess_game(user_action, computer_action)
        if result == GameResults.Draw:
            print("Player and computer pick {}.  Draw".format(user_action.name))
        elif result == GameResults.Win:
            print("Player picks {}, computer picks {}.  {}.  Player wins!".format(
                user_action.name, computer_action.name, rule))
        else:
            print("Player picks {}, computer picks {}.  {}.  Computer wins.".format(
                user_action.name, computer_action.name, rule))

        if input("\nAnother round? (y/n): ").upper() != "Y":
            break

        history.append(user_action)


if __name__ == "__main__":
    main()
Adding lizard and Spock is easy with the right infrastructure.
import random
from enum import IntEnum

class GameResults(IntEnum):
    Win = 0
    Lose = 1
    Draw = 2


class GameAction(IntEnum):
    Piedra = 0
    Papel = 1
    Tijeras = 2
    Lagarto = 3
    Spock = 4

    def __str__(self):
        """Return str more suited for program."""
        return f"{self.name}[{self.value}]"


winning_results = {
    (GameAction.Tijeras, GameAction.Papel) : "Tijeras cuts Papel",
    (GameAction.Papel, GameAction.Piedra) : "Papel covers piedra",
    (GameAction.Piedra, GameAction.Lagarto) : "Piedra crushes lagarto",
    (GameAction.Lagarto, GameAction.Spock) : "Lagarto poisons Spock",
    (GameAction.Spock, GameAction.Tijeras) : "Spock smashes tijeras",
    (GameAction.Tijeras, GameAction.Lagarto) : "Tijeras decapitates lagarto",
    (GameAction.Lagarto, GameAction.Papel) : "Lagarto eats papel",
    (GameAction.Papel, GameAction.Spock) : "Papel disproves Spock",
    (GameAction.Spock, GameAction.Piedra) : "Spock vaporizes piedra",
    (): "\nand as it always has\n",
    (GameAction.Piedra, GameAction.Tijeras) : "Piedra smashes tijeras",


def get_user_action():
    """Get user selection"""
    prompt = f"""\nPick {", ".join([str(action) for action in GameAction])}: """
    while True:
        try:
            action = input(prompt)
            return GameAction(int(action))
        except ValueError:
            print(f"{action} is not a valid choice")


def get_computer_action(history=[]):
    """Get computer selection.  Use history to predict what user will do."""
    user_action = random.choice(history + list(GameAction))
    computer_actions = [action for action in list(GameAction) if (action, user_action) in winning_results]
    return random.choice(computer_actions)


def assess_game(user_action, computer_action):
    if user_action == computer_action:
        return GameResults.Draw, ""
    if (user_action, computer_action) in winning_results:
        return GameResults.Win, winning_results[(user_action, computer_action)]
    return GameResults.Lose, winning_results[(computer_action, user_action)]


def main():
    """Play a game of rock, paper, scissors"""
    print("\n".join(["\nRules of the game:\n"] + [rule for rule in winning_results.values()]))
    history = []
    while True:
        user_action = get_user_action()
        computer_action = get_computer_action(history)
        result, rule = assess_game(user_action, computer_action)
        if result == GameResults.Draw:
            print("Player and computer pick {}.  Draw".format(user_action.name))
        elif result == GameResults.Win:
            print("Player picks {}, computer picks {}.  {}.  Player wins!".format(
                user_action.name, computer_action.name, rule))
        else:
            print("Player picks {}, computer picks {}.  {}.  Computer wins.".format(
                user_action.name, computer_action.name, rule))

        if input("\nAnother round? (y/n): ").upper() != "Y":
            break

        history.append(user_action)


if __name__ == "__main__":
    main()
Agat0 likes this post
Reply
#20
You should be getting the most frequent USER action, not COMPUTER action. get_winning_action() will return an action that defeats the predicted user action.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Algorithm for extracting comments from Python source code Pavel1982 6 760 Feb-28-2024, 09:52 PM
Last Post: Pavel1982
  Rock Paper Scissors Project in Python ankitdixit 8 5,035 Feb-23-2024, 03:14 PM
Last Post: DPaul
  Trying to create a visual rock paper scissors game urmom33 1 1,118 Dec-03-2022, 09:12 PM
Last Post: deanhystad
  Problem restricting user input in my rock paper scissors game ashergreen 6 4,761 Mar-25-2021, 03:54 AM
Last Post: deanhystad
  Odd behavior with Rock Paper Scissor game DustinKlent 2 2,031 Aug-27-2020, 03:55 PM
Last Post: DustinKlent
  Trying to implement Best of 3 logic in rock paper scissors game ShAhCh 5 3,494 May-11-2020, 04:31 PM
Last Post: ShAhCh
  Rock Paper Scissors with dictionaries ewgreht 2 3,990 May-01-2020, 03:19 PM
Last Post: deanhystad
  Rock, Paper, Scissors.. Help..hidden bug xxunknownxx 4 2,770 Mar-19-2020, 02:46 AM
Last Post: jefsummers
  POS receipt print cannot make paper cut using python AP_Development 1 2,837 Dec-12-2019, 08:48 AM
Last Post: buran
  Problem with Basic Rock Paper Scissors code BirinderSingh 3 2,577 Sep-13-2019, 03:28 PM
Last Post: ichabod801

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020