Skip to content

Commit

Permalink
- Moved files into separate directories board/engine/gui
Browse files Browse the repository at this point in the history
- Cleaned up gui.py to contain all its logic in a class and renamed the file to app.py
- Moved out color definitions to a separate file colors.py
- Moved out board & engine constants to a separate file board/constants.py
  • Loading branch information
AngelVI13 committed Apr 27, 2019
1 parent e4771ca commit 9468d59
Show file tree
Hide file tree
Showing 13 changed files with 404 additions and 412 deletions.
Empty file added board/__init__.py
Empty file.
21 changes: 4 additions & 17 deletions board.py → board/base_board.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,9 @@
PLAYER_X = 1
PLAYER_O = -1
NO_PLAYER = 0

STR_MATRIX = {
PLAYER_X: 'X',
PLAYER_O: 'O',
NO_PLAYER: '-'
}

ROWS = 3
BOARD_SIZE = ROWS*ROWS

LOSS = 0.0
DRAW = 0.5
WIN = 1.0
from board.constants import *


class BaseBoard:
"""Defines the general structure which a board implementation
must implement
must implement in order to be compatible with the MCTS game engine
"""

def __str__(self):
Expand All @@ -41,6 +26,8 @@ def get_result(self, player_jm):


class Board:
"""Board implementation for a single NxN board"""

def __init__(self):
self.pos = [0] * BOARD_SIZE

Expand Down
20 changes: 20 additions & 0 deletions board/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""Defines various constants used in the base and ultimate board implementations such as values for each player,
their string representation for outputting to console and the value of a win/loss/draw for the MCTS engine.
"""

PLAYER_X = 1
PLAYER_O = -1
NO_PLAYER = 0

STR_MATRIX = {
PLAYER_X: 'X',
PLAYER_O: 'O',
NO_PLAYER: '-'
}

ROWS = 3
BOARD_SIZE = ROWS*ROWS

LOSS = 0.0
DRAW = 0.5
WIN = 1.0
23 changes: 14 additions & 9 deletions ultimate_board.py → board/ultimate_board.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import random
from collections import deque, namedtuple
from pprint import pprint
from typing import List, Tuple

from board import *
from board.base_board import *


Move = namedtuple('Move', ['board_idx', 'move_idx'])


class UltimateBoard(BaseBoard):
"""Board implementation for ultimate tic tac toe. Supports any NxN size board."""

def __init__(self):
self.pos = [Board() for _ in range(BOARD_SIZE)]
# indicates where (which board) the next move should be done
Expand Down Expand Up @@ -66,25 +67,29 @@ def make_move(self, move: int, board: int = None):

self.pos[board].make_move(move, self.playerJustMoved)
self.history.append(Move(board_idx=board, move_idx=move))
# todo if nextBoard points to a board that is already final => nextBoard could be all available boards
self.nextBoard = move # the move on the board represents the next board
return

# otherwise the forced board, doesn't have a result and the new move
# must be played on it
self.pos[self.nextBoard].make_move(move, self.playerJustMoved)
self.history.append(Move(board_idx=self.nextBoard, move_idx=move))
# todo if nextBoard points to a board that is already final => nextBoard could be all available boards
self.nextBoard = move
return

# if board is not None but nextBoard is None (i.e. start of game)
self.pos[board].make_move(move, self.playerJustMoved)
self.history.append(Move(board_idx=board, move_idx=move))
# todo if nextBoard points to a board that is already final => nextBoard could be all available boards
self.nextBoard = move

def take_move(self):
move = self.history.pop()
self.pos[move.board_idx].take_move(move.move_idx)
# todo need to update self.nextBoard
# todo if nextBoard points to a board that is already final => nextBoard could be all available boards
self.nextBoard = move.board_idx # update nextBoard to be the one forced

def get_all_moves(self) -> List[Tuple[int, int]]:
"""Get all possible moves in the form of a list of tuples
Expand Down Expand Up @@ -130,7 +135,7 @@ def get_moves(self):

return all_moves

def get_result(self, player_jm): # todo use player_jm instead of self.
def get_result(self, player_jm):
# build a list containing the results from each individual board
# where there is no result i.e. None => replace with 0
result_board = [board.get_result() for board in self.pos]
Expand All @@ -144,7 +149,7 @@ def get_result(self, player_jm): # todo use player_jm instead of self.
# if there is no winner and no available moves => DRAW
return DRAW
elif result in (self.playerJustMoved, -self.playerJustMoved):
return WIN if result == self.playerJustMoved else LOSS
return WIN if result == player_jm else LOSS


if __name__ == '__main__':
Expand All @@ -153,10 +158,10 @@ def get_result(self, player_jm): # todo use player_jm instead of self.
print('\n\n')
player = -ub.playerJustMoved
while ub.get_result(ub.playerJustMoved) is None:
moves = ub.get_moves()
board, move = random.choice(moves)
print(board, move)
ub.make_move(move, board)
moves_list = ub.get_moves()
target_board, move_idx = random.choice(moves_list)
print(target_board, move_idx)
ub.make_move(move_idx, target_board)
print(ub)
print('\n\n')

Expand Down
Empty file added engine/__init__.py
Empty file.
File renamed without changes.
Loading

0 comments on commit 9468d59

Please sign in to comment.