A compete with code style tournament where each player can submit their strategy to win the most points.
Please read the whole documentation before just using this. 😛
- Clone this repository
- Install requirements
- Create a python file under strategies folder
- Use the following skeleton and populate the functions with your logic
import math
import numpy
import random
from utils.types import History, Move
class Strategy:
def __init__(self):
self.name = ''
self.description = ''
def begin(self) -> Move:
# Logic Here
pass
def turn(self, history: History) -> Move:
# Logic Here
pass
- Run the main file, ensure no errors occur.
You have been invited to a compete against other people for points. At a time you only face off against one other person. Each showdown goes for a predetermined number of rounds.
Each round, both you and your opponent have two options. SPLIT or STEAL.
- Both of you choose to SPLIT -> Both of you get 5 points
- Both of you choose to STEAL -> Both of you get 0 points
- One of you chooses to SPLIT while the other chooses to STEAL -> The one who chose to steal gets 5 points leaving the other with 0.
The catch? You will be facing off using code. Each player in the dilemma will write a strategy that determines their decision to SPLIT or STEAL.
Each strategy will face off against every other strategy and a copy of themselves.
All the points will be tallied up across all showdowns, and the strategy with the highest number of points will win.
Documentation for all the types a user will have to interact with.
Please read this and understand it well before proceeding. Ask a helper if you have any doubts.
An enumeration respresenting the possible moves a player can make in the game. Members:
SPLIT
STEAL
Example:
# Making comparisions
move: Move
if (move == Move.SPLIT):
return Move.STEAL
else:
return Move.SPLIT
A named tuple representing a single entry in the games history. It gives you access to your and your opponents moves. Attributes:
opponent
(Move)you
(Move)
You can only read from HistoryEntry
objects.
Example:
# Accessing moves played by you and your opponent
entry: HistoryEntry
opponents_move: Move = entry.opponent
your_move: Move = entry.you
A type alias for HistoryEntry
objects, representing the game's history as an immutable sequence.
You can only read from the History
object.
Example:
# Accessing moves from history
history: History
history_len: int = len(history) # To access total number of moves
last_entry: HistoryEntry = history[-1]
last_move_opponent: Move = last_entry.opponent
last_move_you: Move = last_entry.you
A base class representing your strategy. It defines how a player makes their moves based on the game's history.
To make decisions you also get access to the following python modules (will probably increase in the future):
- random
- math
- numpy
Attributes:
name
(str): The name of the strategydescription
(str): A short description of your strategy. Try explaining your algorithm
Methods:
begin(self) -> Move
: Defines the move made by the strategy at the beginning of the game. It is called only once that the beginning of each dilemma. It has to return a Move objectturn(self, history: History) -> Move
: Defines the move to make based on the game's history. It is called every time other than the beginning of each dilemma and gives you access to all moves made by you and your opponent throughout the game. It has to return a Move object
Now that we understand all types. Lets create a very simple strategy that simply steals if the opponent steals on the past round. This strategy is also called titfortat.
PS: Check the pre-existing strategies for other examples
Example:
import math
import numpy
import random
# Type imports
from utils.types import History, Move
class Strategy:
def __init__(self):
self.name = 'titfortat'
# The name of your strategy
self.description = 'steals only if the opponent steals, splits everytime else'
def begin(self) -> Move:
"""
Logic for the first move of any showdown.
Is only run once on the initial run.
return
Move
"""
# The titfortat strategy returns SPLIT on the first round no matter what
return Move.SPLIT
def turn(self, history: Histor) -> Move:
"""
Logic for any move in the showdown after the first move.
Is run every time except on the initial run.
arguments
history: History
return
Move
"""
# The titfortat strategy checks if the previous move made by the opponent was a STEAL and if so, STEALS otherwise it always SPLITS
# Accessing last move by opponent
latest_entry = history[-1]
last_move_opponent = latest_entry.opponent
# Let us now check if this move was a STEAL
if (last_move_opponent == Move.STEAL):
# STEAL if so
return Move.STEAL
else:
return Move.SPLIT
# This is a sample strategy and is quite simple
# You can come up with any strategy as simple or complex as you want.
Let us create one more strategy that just returns a random move regardless of history
Example:
import math
import numpy
import random
from utils.types import History, Move
class Strategy:
def __init__(self):
self.name = 'random'
self.description = 'random 😛'
def begin(self) -> Move:
return random.choice([Move.SPLIT, Move.STEAL])
def turn(self, history: History) -> Move:
return random.choice([Move.SPLIT, Move.STEAL])