Compare commits

...

2 Commits

Author SHA1 Message Date
Cory 70c8ff1308 (Completed Nim as part of the tic tac toe lab.)
What I changed
(I made a copy of game_stub.py called game.py and corrected the methods
so that the game would work.)

Why I changed it
(To complete the lab.)

Estimate for remaining time to finish assignment: [Done]
2024-04-08 10:12:37 -04:00
Cory 0a3d7e31f5 Completed checkpoint 3
What I changed
(I gave the computer player the look ahead strategy. This also required importing LookaheadStrategy in player.py.
I also answered the questions in notes.md.)

Why I changed it
(I was working on completing checkpoint 3. I realized I had to do the importing since otherwise it wouldn't let me play.)

Estimate for remaining time to finish assignment: [I am REALLY bad at these estimates. I mean in terms of actual work time, I'm probably not too far off. Fingers crossed, maybe another hour of actual work time?]
2024-03-20 20:13:39 -04:00
8 changed files with 63 additions and 12 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

49
nim/game.py Normal file
View File

@ -0,0 +1,49 @@
class NimGame:
"""A Nim game class based off NimGameStub.
"""
def get_initial_state(self):
''' Constructs the game board and has player 1 start the game. '''
return {
"board": [1, 3, 5, 7],
"first_player": True
}
def get_next_state(self, state, action):
''' Creates a copy of the current board and then makes adjustments
based on the chosen action from a player's turn. '''
new_board = state["board"].copy()
new_board[action[0]] = new_board[action[0]] - action[1]
return {
"board": new_board,
"first_player": not state["first_player"],
}
def get_actions(self, state):
''' Construct the list of actions that can be taken by a player.
Is there a more efficient way of doign this? '''
actions = []
new_board = state["board"].copy()
for i in range(4): # check the four rows of the board
if new_board[i] > 0: # if a row is not empty
for j in range(1,4): # check if you can remove 1, 2, or 3 ticks in the row
if j <= new_board[i]: # if so
actions.append((i,j)) # include that as an option
return actions
def get_reward(self, state):
''' Reports who wins. '''
if state["first_player"]:
return 1 # If it is the player's turn and there is nothing on the board, then it was the robot who crossed off the last line.
return 0 # Otherwise, the first player made the last move and lost.
def is_over(self, state):
''' Reports true if there are no more lines to cross. '''
if all(ticks == 0 for ticks in state["board"]):
return True
return False
def get_objective(self, state):
''' Reports the desired obejctive to help choose the move that
yields the optimal reward under the lookahead_strategy for
computer players. '''
return max if state["first_player"] else min

View File

@ -1,16 +1,16 @@
from nim.game_stub import NimGameStub
from nim.game import NimGame
from strategy.lookahead_strategy import LookaheadStrategy
class HumanNimPlayer:
def __init__(self, name):
self.name = name
self.game = NimGameStub()
self.game = NimGame()
def choose_action(self, state):
actions = self.game.get_actions(state)
for i, action in enumerate(actions):
row, lines_to_remove = action
print(f"{i}. Remove {lines_to_remove} from row {row}.")
print(f"{i}. Remove {lines_to_remove} from row {row+1}.")
choice = self.get_int(len(actions))
return actions[choice]
@ -26,10 +26,10 @@ class HumanNimPlayer:
class ComputerNimPlayer:
def __init__(self, name):
self.name = name
self.strategy = LookaheadStrategy(NimGameStub(), max_depth=3, deterministic=False)
self.strategy = LookaheadStrategy(NimGame(), max_depth=5, deterministic=False)
def choose_action(self, state):
action = self.strategy.choose_action(state)
row, lines_to_remove = action
print(f"{self.name} removes {lines_to_remove} from row {row}")
print(f"{self.name} removes {lines_to_remove} from row {row+1}")
return action

View File

@ -1,9 +1,9 @@
from nim.game_stub import NimGameStub
from nim.game import NimGame
class NimView:
def __init__(self, player0, player1):
self.players = [player0, player1]
self.game = NimGameStub()
self.game = NimGame()
def greet(self):
print(f"{self.players[0].name} and {self.players[1].name}, welcome to Nim.")

View File

@ -37,4 +37,5 @@ For the first one, I would put an X on the rightmost cell in the middle row. Thi
You can get the inital game state using game.get_initial_state().
What is the current and future reward for this state? What does this mean?
The current and future reward for this state is 1. This means the state favors player X assuming both players continue using the same look ahead strategy.

View File

@ -1,11 +1,11 @@
from nim.game_stub import NimGameStub
from nim.game import NimGame
from nim.view import NimView
from nim.player import HumanNimPlayer, ComputerNimPlayer
player0 = HumanNimPlayer(input("What's your name? "))
player1 = ComputerNimPlayer("Robot")
view = NimView(player0, player1)
game = NimGameStub()
game = NimGame()
view.greet()
state = game.get_initial_state()

View File

@ -2,8 +2,8 @@ from ttt.game import TTTGame
from ttt.view import TTTView
from ttt.player import TTTHumanPlayer, TTTComputerPlayer
player0 = TTTHumanPlayer("Player 1")
player1 = TTTHumanPlayer("Player 2")
player0 = TTTHumanPlayer("Pleayer 1")
player1 = TTTComputerPlayer("Robot 1")
game = TTTGame()
view = TTTView(player0, player1)

View File

@ -1,4 +1,5 @@
from click import Choice, prompt
from strategy.lookahead_strategy import LookaheadStrategy
from strategy.random_strategy import RandomStrategy
from ttt.game import TTTGame
import random
@ -24,7 +25,7 @@ class TTTComputerPlayer:
def __init__(self, name):
"Sets up the player."
self.name = name
self.strategy = RandomStrategy(TTTGame())
self.strategy = LookaheadStrategy(TTTGame(),deterministic=False)
def choose_action(self, state):
"Chooses a random move from the moves available."