From 243dcdf49c2ade7efe13a92a2292d3fb5c56f379 Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Tue, 12 May 2015 16:54:29 -0400 Subject: [PATCH 1/5] initial commit --- hard_mode.py | 33 +++++++++++++ sticks.py | 70 +++++++++++++++++++++++++++ sticks_ui.py | 126 +++++++++++++++++++++++++++++++++++++++++++++++++ test_sticks.py | 59 +++++++++++++++++++++++ 4 files changed, 288 insertions(+) create mode 100644 hard_mode.py create mode 100644 sticks.py create mode 100644 sticks_ui.py create mode 100644 test_sticks.py diff --git a/hard_mode.py b/hard_mode.py new file mode 100644 index 0000000..b93cd7d --- /dev/null +++ b/hard_mode.py @@ -0,0 +1,33 @@ +from sticks import Computer + +import random + +proto = {} +end = {} +for i in range(101): + proto[i] = [1,2,3] + end[i] = [] + +class HardComputer(Computer): + + def __init__(self,name='Megatron'): + super().__init__(name) + self.start_hats = proto + self.end_hats = end + + def reset(self): + self.end_hats = end + + def turn(self, sticks): + num = random.choice(self.start_hats[sticks]) + while not (1 <= num <= 3 and sticks - num >= 0): + num = random.choice(self.start_hats[sticks]) + + self.end_hats[sticks].append(num) + return num + + def finish(self): + for key, val in self.end_hats.items(): + if val is not []: + self.start_hats[key].append(val) + self.start_hats[key].append(val) diff --git a/sticks.py b/sticks.py new file mode 100644 index 0000000..f310d62 --- /dev/null +++ b/sticks.py @@ -0,0 +1,70 @@ +import random + + +class Game: + def __init__(self): + self.players = [] + + def start(self, sticks): + self.sticks = sticks + self.removed_sticks = 0 + + def set_players(self, *players): + self.players = list(players) + self.current_player = random.choice(self.players) + + def set_num_sticks(self, num): + self.sticks = num + + def switch_player(self): + if self.current_player is self.players[0]: + self.current_player = self.players[1] + else: + self.current_player = self.players[0] + + def is_done(self): + return self.sticks == 0 + + def remove_sticks(self, num): + self.sticks -= num + self.removed_sticks = num + + def turn(self): + self.remove_sticks(self.current_player.turn(self.sticks)) + + def status(self): + return self.current_player.name, self.removed_sticks, self.sticks + +class Player: + def __init__(self, name): + self.name = name + + +class Human(Player): + + def turn(self, sticks): + num = input('How many sticks do you take (1-3)? ') + + if num.strip().isdigit(): + num = int(num) + else: + print('Invalid choice! Try again.') + return self.turn(sticks) + + if 0 < num < 4 and sticks - num >= 0: + return num + else: + print('Invalid choice! Try again.') + return self.turn(sticks) + + +class Computer(Player): + + def __init__(self,name='Starscream'): + super().__init__(name) + + def turn(self, sticks): + num = random.randint(1,3) + while not (0 < num < 4 and sticks - num >= 0): + num = random.randint(1,3) + return num diff --git a/sticks_ui.py b/sticks_ui.py new file mode 100644 index 0000000..81c0faf --- /dev/null +++ b/sticks_ui.py @@ -0,0 +1,126 @@ +from sticks import Game, Human, Computer +from hard_mode import HardComputer + +import os +import random + +class Talker: + + def __init__(self): + self.game = Game() + self.get_names() + self.play() + + def get_players(self): + number = input('Single Player? [y]es or [n]o: ') + + if number.lower()[0] in 'yn': + return number.lower()[0] == 'y' + else: + print('Try again! Answer [yes] or [no].') + number = self.get_players(self) + + def get_names(self): + + os.system('clear') + players = [] + + if not self.get_players(): + players.append(input('Enter Player 1\'s name: ')) + players.append(input('Enter Player 2\'s name: ')) + + else: + players.append(Human(input('Enter your name: '))) + players.append(self.set_mode()) + + self.game.set_players(*players) + os.system('clear') + + def set_mode(self): + mode = input('What mode? [E]asy [H]ard [U]nicron: ') + mode = mode.lower()[0] + if mode in 'ehu': + if mode == 'e': + return Computer() + if mode == 'h': + return HardComputer() + if mode == 'u': + + new_game = Game() + unicron1 = HardComputer('Unicron') + unicron2 = HardComputer('Unicron') + + new_game.set_players(unicron1, unicron2) + wins = {unicron1:0, unicron2:0} + for _ in range(1000): + wins[self.quick_play(new_game)] += 1 + + return max(wins, key=lambda x: x[1]) + + + def get_sticks(self): + number = input("How many sticks are on the table (10-100)? ") + if number.isdigit(): + if number not in list(range(10, 101)): + number = self.get_sticks() + else: + number = self.get_sticks() + + return number + + def quick_play(self, game): + game.start(random.randint(10,101)) + + while not game.is_done(): + game.turn() + game.switch_player() + + game.current_player.finish() # learn + game.current_player.reset() # get ready for next round + game.switch_player() + game.current_player.reset() + + game.switch_player() + return game.current_player + + + def play(self): + self.game.start(self.get_sticks()) + self.loop() + + while self.play_again(): + self.game.start(self.get_sticks()) + self.loop() + + def play_again(self): + yes_no = input("Would you like to play again? [Y]es or [N]o: ") + if yes_no.lower()[0] in 'yn': + os.system('clear') + return yes_no.lower()[0] == 'y' + else: + return self.play_again() + + def update(self, *args): + os.system('clear') + print("{} took {} sticks. {} left!".format(*args)) + + def loop(self): + + while not self.game.is_done(): + + self.game.turn() + self.update(*self.game.status()) + self.game.switch_player() + + self.winner(self.game.current_player) + + if isinstance(self.game.current_player, HardComputer): + self.game.current_player.finish() + self.game.current_player.reset() + + def winner(self, player): + print("{} won the game!".format(player.name)) + + +if __name__ == '__main__': + talker = Talker() diff --git a/test_sticks.py b/test_sticks.py new file mode 100644 index 0000000..1523074 --- /dev/null +++ b/test_sticks.py @@ -0,0 +1,59 @@ +from sticks import Game, Human, Computer + +import nose + + +def test_set_remove_sticks(): + game = Game() + + game.set_num_sticks(5) + assert game.sticks == 5 + + game.remove_sticks(1) + assert game.sticks == 4 + +def test_set_switch_players(): + player1 = Human('Elf') + player2 = Computer() + game = Game() + game.set_players(player1, player2) + + assert game.players[0] is player1 + assert game.players[1] is player2 + + if game.current_player is not player1: + game.switch_player() + assert game.current_player is player1 + + if game.current_player is not player2: + game.switch_player() + assert game.current_player is player2 + +def test_game_is_done(): + game = Game() + game.set_num_sticks(5) + assert not game.is_done() + game.set_num_sticks(0) + assert game.is_done() + +def test_game_status(): + game = Game() + game.set_num_sticks(5) + player1 = Human('Alf') + player2 = Human('Bertram') + game.set_players(player1, player2) + game.remove_sticks(2) + assert list(game.status()) == [game.current_player.name, 2, 3] + +def test_turn(): + game = Game() + game.set_num_sticks(5) + player1 = Computer() + player2 = Computer() + game.set_players(player1, player2) + game.turn() + assert 2 <= game.sticks <=4 + + +if __name__ == '__main__': + nose.main() From dbdc82c9e69c45440881030710c5d29a276d8e6c Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Tue, 12 May 2015 17:28:23 -0400 Subject: [PATCH 2/5] made ui more testable --- hard_mode.py | 21 ++++++++++++--------- sticks_ui.py | 15 +++++++++++---- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/hard_mode.py b/hard_mode.py index b93cd7d..742c17f 100644 --- a/hard_mode.py +++ b/hard_mode.py @@ -3,10 +3,11 @@ import random proto = {} -end = {} +end = [0 for _ in range(101)] + for i in range(101): proto[i] = [1,2,3] - end[i] = [] + class HardComputer(Computer): @@ -16,18 +17,20 @@ def __init__(self,name='Megatron'): self.end_hats = end def reset(self): - self.end_hats = end + for i in range(101): + self.end_hats[i] = 0 def turn(self, sticks): num = random.choice(self.start_hats[sticks]) - while not (1 <= num <= 3 and sticks - num >= 0): + + while not 1 <= num <= 3 or not sticks - num >= 0: num = random.choice(self.start_hats[sticks]) - self.end_hats[sticks].append(num) + self.end_hats[sticks] = num return num def finish(self): - for key, val in self.end_hats.items(): - if val is not []: - self.start_hats[key].append(val) - self.start_hats[key].append(val) + for indx, val in enumerate(self.end_hats): + if val is not 0: + self.start_hats[indx].append(val) + self.start_hats[indx].append(val) diff --git a/sticks_ui.py b/sticks_ui.py index 81c0faf..ef27bd9 100644 --- a/sticks_ui.py +++ b/sticks_ui.py @@ -8,6 +8,8 @@ class Talker: def __init__(self): self.game = Game() + + def go(self): self.get_names() self.play() @@ -18,7 +20,7 @@ def get_players(self): return number.lower()[0] == 'y' else: print('Try again! Answer [yes] or [no].') - number = self.get_players(self) + number = self.get_players() def get_names(self): @@ -52,15 +54,19 @@ def set_mode(self): new_game.set_players(unicron1, unicron2) wins = {unicron1:0, unicron2:0} - for _ in range(1000): + + for _ in range(10000): wins[self.quick_play(new_game)] += 1 - return max(wins, key=lambda x: x[1]) + if wins[unicron1] > wins[unicron2]: + return unicron1 + return unicron2 def get_sticks(self): number = input("How many sticks are on the table (10-100)? ") if number.isdigit(): + number = int(number) if number not in list(range(10, 101)): number = self.get_sticks() else: @@ -69,7 +75,7 @@ def get_sticks(self): return number def quick_play(self, game): - game.start(random.randint(10,101)) + game.start(random.randint(10,100)) while not game.is_done(): game.turn() @@ -124,3 +130,4 @@ def winner(self, player): if __name__ == '__main__': talker = Talker() + talker.go() From 3f57641923187ed7c0b074503719f798c48bbee5 Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Tue, 12 May 2015 17:42:18 -0400 Subject: [PATCH 3/5] fixed up unicron --- hard_mode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hard_mode.py b/hard_mode.py index 742c17f..797b836 100644 --- a/hard_mode.py +++ b/hard_mode.py @@ -33,4 +33,4 @@ def finish(self): for indx, val in enumerate(self.end_hats): if val is not 0: self.start_hats[indx].append(val) - self.start_hats[indx].append(val) + From d8ced3a213225fbfe9c99244b3f8bb6c0a72be0b Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Wed, 13 May 2015 08:49:37 -0400 Subject: [PATCH 4/5] PEP8 check --- hard_mode.py | 5 ++--- sticks.py | 7 ++++--- sticks_ui.py | 15 +++++++++------ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/hard_mode.py b/hard_mode.py index 797b836..c01ebe5 100644 --- a/hard_mode.py +++ b/hard_mode.py @@ -6,12 +6,12 @@ end = [0 for _ in range(101)] for i in range(101): - proto[i] = [1,2,3] + proto[i] = [1, 2, 3] class HardComputer(Computer): - def __init__(self,name='Megatron'): + def __init__(self, name='Megatron'): super().__init__(name) self.start_hats = proto self.end_hats = end @@ -33,4 +33,3 @@ def finish(self): for indx, val in enumerate(self.end_hats): if val is not 0: self.start_hats[indx].append(val) - diff --git a/sticks.py b/sticks.py index f310d62..2eb659c 100644 --- a/sticks.py +++ b/sticks.py @@ -35,6 +35,7 @@ def turn(self): def status(self): return self.current_player.name, self.removed_sticks, self.sticks + class Player: def __init__(self, name): self.name = name @@ -60,11 +61,11 @@ def turn(self, sticks): class Computer(Player): - def __init__(self,name='Starscream'): + def __init__(self, name='Starscream'): super().__init__(name) def turn(self, sticks): - num = random.randint(1,3) + num = random.randint(1, 3) while not (0 < num < 4 and sticks - num >= 0): - num = random.randint(1,3) + num = random.randint(1, 3) return num diff --git a/sticks_ui.py b/sticks_ui.py index ef27bd9..30f1148 100644 --- a/sticks_ui.py +++ b/sticks_ui.py @@ -4,6 +4,7 @@ import os import random + class Talker: def __init__(self): @@ -53,7 +54,7 @@ def set_mode(self): unicron2 = HardComputer('Unicron') new_game.set_players(unicron1, unicron2) - wins = {unicron1:0, unicron2:0} + wins = {unicron1: 0, unicron2: 0} for _ in range(10000): wins[self.quick_play(new_game)] += 1 @@ -62,7 +63,6 @@ def set_mode(self): return unicron1 return unicron2 - def get_sticks(self): number = input("How many sticks are on the table (10-100)? ") if number.isdigit(): @@ -75,21 +75,20 @@ def get_sticks(self): return number def quick_play(self, game): - game.start(random.randint(10,100)) + game.start(random.randint(10, 100)) while not game.is_done(): game.turn() game.switch_player() - game.current_player.finish() # learn - game.current_player.reset() # get ready for next round + game.current_player.finish() # learn + game.current_player.reset() # get ready for next round game.switch_player() game.current_player.reset() game.switch_player() return game.current_player - def play(self): self.game.start(self.get_sticks()) self.loop() @@ -98,6 +97,10 @@ def play(self): self.game.start(self.get_sticks()) self.loop() + # if isinstance(self.game.players[1], HardComputer): + # for key, item in self.game.players[1].start_hats.items(): + # print(item) + def play_again(self): yes_no = input("Would you like to play again? [Y]es or [N]o: ") if yes_no.lower()[0] in 'yn': From a59d06daef4789c05b027052eaeb8031e998b3b3 Mon Sep 17 00:00:00 2001 From: Jeremy Gresham Date: Wed, 13 May 2015 08:53:56 -0400 Subject: [PATCH 5/5] readme written --- README.md | 316 +----------------------------------------------------- 1 file changed, 2 insertions(+), 314 deletions(-) diff --git a/README.md b/README.md index b44d083..f9f2d39 100644 --- a/README.md +++ b/README.md @@ -1,315 +1,3 @@ # Game of Sticks - -## Description - -Create a version of the Game of Sticks where human and AI players can play -against each other. - -In the Game of Sticks there is a heap of sticks on a board. On their turn, -each player picks up 1 to 3 sticks. The one who has to pick the final stick -will be the loser. - -The following is an example of the game of sticks. - -* The game starts with 20 sticks on the board. -* Marvin takes 3 sticks, there are 17 sticks remaining. -* Hal takes 2 sticks, there are 15 sticks remaining. -* Marvin takes 1 stick, there are 14 sticks remaining. -* Hal takes 3 sticks, there are 11 sticks remaining. -* Marvin takes 2 sticks, there are 9 sticks remaining. -* Hal takes 2 sticks, there are 7 sticks remaining. -* Marvin takes 3 sticks, there are 4 sticks remaining. -* Hal takes 1 stick, there are 3 sticks remaining. -* Marvin takes 2 sticks, there is 1 stick remaining. -* Hal has to take the final stick and loses. - -This assignment is split into four parts: - -1. Implementing the game as a two-player game. -2. Adding an AI that can be played against. -3. Adding an option for training the AI against another AI. -4. Performing mathematical analysis of the problem based on information - gathered from the AI. - -## Objectives - -### Learning Objectives - -After completing this assignment, you should understand: - -* Lists and tuples - -### Performance Objectives - -After completing this assignment, you should be able to: - -* Use functions effectively -* Build a simple AI - -## Details - -### Deliverables - -* A Git repo called game-of-sticks containing at least: - * `README.md` file explaining how to run your project - * a `requirements.txt` file - * a suite of tests for your project - -### Requirements - -* Passing unit tests -* No PEP8 or Pyflakes warnings or errors - -## Normal Mode - -### Player vs Player - -Create a game where two players can play against each other. The two examples -below demonstrate how the game should behave. - -Example 1: - -``` -Welcome to the Game of Sticks! -How many sticks are there on the table initially (10-100)? 10 - -There are 10 sticks on the board. -Player 1: How many sticks do you take (1-3)? 3 - -There are 7 sticks on the board. -Player 2: How many sticks do you take (1-3)? 3 - -There are 4 sticks on the board. -Player 1: How many sticks do you take (1-3)? 3 - -There is 1 stick on the board. -Player 2: How many sticks do you take (1-3)? 1 -Player 2, you lose. -``` - -Example 2: - -``` -Welcome to the Game of Sticks! -How many sticks are there on the table initially (10-100)? 500 -Please enter a number between 10 and 100. -How many sticks are there on the table initially (10-100)? 3 -Please enter a number between 10 and 100. -How many sticks are there on the table initially (10-100)? 50 - -There are 50 sticks on the board. -Player 1: How many sticks do you take (1-3)? 3 - -There are 47 sticks on the board. -Player 2: How many sticks do you take (1-3)? 55 -Please enter a number between 1 and 3 -Player 2: How many sticks do you take (1-3)? 3 - -There are 44 sticks on the board. -Player 1: How many sticks do you take (1-3)? 3 -... - -There is 1 stick on the board. -Player 1: How many sticks do you take (1-3)? 1 -Player 1, you lose. -``` - -### Player vs AI - -Let's create an artificial intelligence player for the Game of Sticks. Instead -of creating an AI based off knowledge of the optimal strategy, we'll create -an AI that can learn from games it wins and loses, and then we can look at it -to figure out the best strategy. - -Consider the functionality of the AI using the following description: - -* An AI has a number of hats, one hat for each possible amount of sticks on the -table. Initially, each hat contains three balls that are numbered from 1 to 3. - -* At every step of the game that the AI plays, the AI takes a random ball out of -the hat that matches the amount of sticks currently on the board. When the AI -takes a ball out of a hat, it places it next to the hat for waiting, reads the -number on the ball, and takes the amount of sticks that the ball indicates. - -* If the AI wins the game, it puts two balls of the type to each hat that has a -ball next to it. Both balls have the same number. If the AI loses, it will -throw away the balls that are next to the hats (note: A hat must always have at -least one ball of each number, hence the last ball of a specific number cannot -be thrown away and must be put back to the hat). - -* As more and more games are played, there will be more balls that indicate a -good number of sticks to take. This means that as balls are taken at random, it -becomes more likely that the AI is able to play well. - -**Example**: - -Let us consider an example where there are 10 sticks at the beginning. The hat -contents for the AI are as follows: - - | | | | | | | | | | -------- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- -hat | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 -content | 1,2,3 | 1,2,3 | 1,2,3 | 1,2,3 | 1,2,3 | 1,2,3 | 1,2,3 | 1,2,3 | 1,2,3 | 1,2,3 - -The game may proceed as follows: - -1. Player takes 3 sticks, there are 7 sticks remaining. -2. AI randomly picks up ball 2 from the hat 7. This means that the AI takes 2 sticks, and there are 5 sticks remaining. -3. Player takes 1 stick, there are 4 sticks remaining. -4. AI randomly picks up ball 3 from hat 4. This means that AI takes 3 sticks, and there is 1 stick remaining. -5. Player has to take the final stick and loses. - -Now, the situation with the AI is as follows: - - | | | | | | | | | | -------- | ----- | ----- | ----- | --- | ----- | ----- | --- | ----- | ----- | ----- -hat | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 -content | 1,2,3 | 1,2,3 | 1,2,3 | 1,2 | 1,2,3 | 1,2,3 | 1,3 | 1,2,3 | 1,2,3 | 1,2,3 -beside | | | | 3 | | | 2 | | | - -As the AI wins the game, it will put the balls that are next to the hats back to the hats with extra balls. The situation is now as follows: - - | | | | | | | | | | -------- | ----- | ----- | ----- | ------- | ----- | ----- | ------- | ----- | ----- | ----- -hat | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 -content | 1,2,3 | 1,2,3 | 1,2,3 | 1,2,3,3 | 1,2,3 | 1,2,3 | 1,2,2,3 | 1,2,3 | 1,2,3 | 1,2,3 - -Now the AI will more likely take 3 sticks in the case of four sticks remaining on the board, and 2 sticks in case there are 7 sticks remaining on the board. - -Your task is to modify the human vs. human version of the game so that the player can choose to play against an AI that works as described above. After each game, the AI will update the contents of its hats. The AI will play relatively randomly at first, but you will notice that it will start to learn a strategy as you play against it. - -The following example displays how the program should behave after you have finished this step. - -``` -Welcome to the Game of Sticks! -How many sticks are there on the table initially (10-100)? 10 -Options: - Play against a friend (1) - Play against the computer (2) -Which option do you take (1-2)? 2 - -There are 10 sticks on the board. -Player 1: How many sticks do you take (1-3)? 3 - -There are 7 sticks on the board. -AI selects 2. - -There are 5 sticks on the board. -Player 1: How many sticks do you take (1-3)? 3 - -There are 2 sticks on the board. -AI selects 2. -AI loses. -Play again (y/n)? y - -There are 10 sticks on the board. -Player 1: How many sticks do you take (1-3)? 1 - -There are 9 sticks on the board. -AI selects 1. - -There are 8 sticks on the board. -Player 1: How many sticks do you take (1-3)? 3 - -There are 5 sticks on the board. -AI selects 3. - -There are 2 sticks on the board. -Player 1: How many sticks do you take (1-3)? 2 -You lose. -Play again (y/n)? y - -There are 10 sticks on the board. -Player 1: How many sticks do you take (1-3)? 3 - -There are 7 sticks on the board. -AI selects 2. - -There are 5 sticks on the board. -Player 1: How many sticks do you take (1-3)? 3 - -There are 2 sticks on the board. -AI selects 2. -AI loses. -Play again (y/n)? n -``` - -## Hard Mode - -In addition to the requirements from **Normal Mode**: - -### AI vs AI - -In the previous part we created an AI that is able to learn from playing -against the player. As we play against it, we notice that it takes a -considerable amount of time before the AI is able to perform against a human -player. In this assignment, you need to modify the program so that the player -can choose to play either against a naive AI or a pre-trained AI. - -In order to pre-train an AI, you need to create a program that allows two AIs -to battle against each others -- say a hundred thousand times (after the -training is working, try out different numbers as well!) -- and after that the -player will be set to play against the AI that is ready to battle the player. - -The following example shows how the game would work with the trained AI option. - -``` -Welcome to the Game of Sticks! -How many sticks are there on the table initially (10-100)? 10 -Options: - Play against a friend (1) - Play against the computer (2) - Play against the trained computer (3) -Which option do you take (1-3)? 3 -Training AI, please wait... - -There are 10 sticks on the board. -Player 1: How many sticks do you take (1-3)? 3 - -There are 7 sticks on the board. -AI selects 2. - -There are 5 sticks on the board. -Player 1: How many sticks do you take (1-3)? 1 - -There are 4 sticks on the board. -AI selects 3. - -There is 1 stick on the board. -Player 1: How many sticks do you take (1-3)? 1 -You lose. -Play again (y/n)? y - -There are 10 sticks on the board. -Player 1: How many sticks do you take (1-3)? 2 - -There are 8 sticks on the board. -AI selects 3. - -There are 5 sticks on the board. -Player 1: How many sticks do you take (1-3)? 2 - -There are 3 sticks on the board. -AI selects 2. - -There is 1 stick on the board. -Player 1: How many sticks do you take (1-3)? 1 -You lose. -Play again (y/n)? n -``` - -### Mathematical analysis - -The AI can play very well -- but what is its strategy? - -You can find the strategy by looking at the contents of the hats that the AI is -using. What is the strategy and can you show mathematically why it works? - -## Nightmare Mode - -Use the same strategy to create a game of Tic-Tac-Toe with a trained AI player. -[This paper](http://aitopics.org/sites/default/files/classic/Machine_Intelligence_2/MI2-Ch9-MichieChambers.pdf) may help. - -## Credit - -This assignment is taken from [Stanford's Nifty Assignments 2014](http://nifty.stanford.edu/2014/laaksonen-vihavainen-game-of-sticks/). +'python3 sticks_ui.py' to run the game +[u]nicron mode is a pre-trained Hard mode AI