Skip to content

Commit

Permalink
Merge pull request #2 from DanielBarton446/random_agent
Browse files Browse the repository at this point in the history
random agent
  • Loading branch information
DanielBarton446 authored Apr 21, 2024
2 parents bbf6b9e + 8cbd79b commit 2aa2a51
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 2 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pylint
pip install black
pip install -r requirements.txt
pip install -r dev_requirements.txt
- name: Analysing the code with pylint
run: |
pylint $(git ls-files '*.py')
black $(git ls-files '*.py')
- name: Ensuring type hints exist with mypy
run: |
mypy shogi-ai --disable-error-code=import-untyped
3 changes: 3 additions & 0 deletions dev_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
black
pylint
flameprof
mypy
isort
48 changes: 48 additions & 0 deletions shogi-ai/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""
Agent class is the base class for all agents.
"""

from environment import Environment
from shogi import Board


class Agent:
"""
Agent is not a class itself, it is a base class for all agents.
Agent should not be used for anything other than inheritance.
"""

def __init__(self, env: Environment, strategy=None):
self._env = env
self.strategy = strategy

def select_action(self):
"""
Select an action based on the state of the environment.
NotImplementedError: This method must be implemented by the subclass
"""
raise NotImplementedError("select_action method must be implemented")

def action_space(self):
"""
Get the action space of the environment.
Returns:
action_space: The action space of the environment.
"""
return self._env.action_space

@classmethod
def from_board(cls, board: Board):
"""
Generate an agent from a shogi board.
"""
raise NotImplementedError("from_board method must be implemented")

@property
def env(self):
"""
env: The environment the agent operates in.
"""
return self._env
47 changes: 47 additions & 0 deletions shogi-ai/environment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""
You can use the Environment class to generate an environment from a shogi board
```
from shogi import Board
from environment import Environment
board = Board()
env = Environment(board)
```
"""

from typing import List

from shogi import Board


class Environment:
"""
Environment class for a shogi board.
"""
def __init__(self, board: Board):
self.board = board
self._moves: List = []
self._last_state = board.piece_bb

@property
def action_space(self):
"""
generate all legal moves if we haven't already and
return them
"""
if self._moves and (self.board == self._last_state):
return self._moves

self._moves = []
self._last_state = self.board.piece_bb
for move in self.board.legal_moves:
self._moves.append(move)
return self._moves

def from_board(self, board: Board):
"""
currently just is another constructor basically.
"""
return Environment(board)
42 changes: 42 additions & 0 deletions shogi-ai/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""
This is the main function for an example of how you can have two
agents play against each other. The agents are random agents, so
the game will be random.
This example with random moves also serves as a good example of
how viable monte carlo tree search would be for this game.
"""

import shogi
from environment import Environment
from random_agent import RandomAgent
from shogi import Board, Move


def main() -> None:
"""
Main function for the example.
"""
board: Board = shogi.Board()

agent1: RandomAgent = RandomAgent.from_board(board)
env: Environment = agent1.env
agent2: RandomAgent = RandomAgent(env)

while not board.is_game_over():
agent1_action: Move = agent1.select_action()
board.push(agent1_action)
if board.is_game_over():
break

agent2_action: Move = agent2.select_action()
board.push(agent2_action)

print("Final State of board:")
print(board)
print(f"Number of moves {len(board.move_stack)}")


if __name__ == "__main__":
main()
41 changes: 41 additions & 0 deletions shogi-ai/random_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""
Random Agent:
- This agent selects a random move from the action space.
- This agent will be used for monte carlo tree search.
"""

import random

from agent import Agent
from environment import Environment
from shogi import Board
from shogi.Move import Move


class RandomAgent(Agent):
"""
Random Agent class for shogi.
```
from shogi import Board
from random_agent import randomAgent
board = Board()
agent = randomAgent.from_board(board)
move: Move = agent.select_action(board)
```
"""

def __init__(self, env: Environment, strategy=None):
strategy = "random"
super().__init__(env, strategy)

def select_action(self) -> Move:
legal_moves = self._env.action_space
return random.choice(legal_moves)

@classmethod
def from_board(cls, board: Board):
return RandomAgent(Environment(board))

0 comments on commit 2aa2a51

Please sign in to comment.