Created base game with working minimax algorithm, now working on reinforcement learning
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,185 @@
|
||||
import pygame
|
||||
|
||||
from .constants import BLACK, ROWS, GREEN, SQUARE_SIZE, COLS, WHITE
|
||||
from .piece import Piece
|
||||
|
||||
|
||||
class Board:
|
||||
def __init__(self):
|
||||
self.board = []
|
||||
self.greenLeft = self.whiteLeft = 12
|
||||
self.greenKings = self.whiteKings = 0
|
||||
self.createBoard()
|
||||
|
||||
def drawSquares(self, win):
|
||||
win.fill(BLACK)
|
||||
for row in range(ROWS):
|
||||
for col in range(row % 2, ROWS, 2):
|
||||
pygame.draw.rect(win, GREEN, (row * SQUARE_SIZE, col * SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE))
|
||||
|
||||
def createBoard(self):
|
||||
for row in range(ROWS):
|
||||
self.board.append([])
|
||||
for col in range(COLS):
|
||||
if col % 2 == ((row + 1) % 2):
|
||||
if row < 3:
|
||||
self.board[row].append(Piece(row, col, WHITE))
|
||||
elif row > 4:
|
||||
self.board[row].append(Piece(row, col, GREEN))
|
||||
else:
|
||||
self.board[row].append(None)
|
||||
else:
|
||||
self.board[row].append(None)
|
||||
|
||||
def draw(self, win):
|
||||
self.drawSquares(win)
|
||||
for row in range(ROWS):
|
||||
for col in range(COLS):
|
||||
piece = self.board[row][col]
|
||||
if piece is not None:
|
||||
piece.draw(win)
|
||||
|
||||
def move(self, piece, row, col):
|
||||
self.board[piece.row][piece.col], self.board[row][col] = self.board[row][col], self.board[piece.row][piece.col]
|
||||
piece.move(row, col)
|
||||
|
||||
if row == ROWS - 1 or row == 0:
|
||||
piece.makeKing()
|
||||
if piece.colour == WHITE:
|
||||
self.whiteKings += 1
|
||||
else:
|
||||
self.greenKings += 1
|
||||
|
||||
def remove(self, skipped):
|
||||
for piece in skipped:
|
||||
self.board[piece.row][piece.col] = None
|
||||
if piece is not None:
|
||||
if piece.colour == GREEN:
|
||||
self.greenLeft -= 1
|
||||
else:
|
||||
self.whiteLeft -= 1
|
||||
|
||||
def getPiece(self, row, col):
|
||||
return self.board[row][col]
|
||||
|
||||
def winner(self):
|
||||
if self.greenLeft <= 0:
|
||||
return WHITE
|
||||
elif self.whiteLeft <= 0:
|
||||
return GREEN
|
||||
|
||||
return None
|
||||
|
||||
def getValidMoves(self, piece):
|
||||
moves = {}
|
||||
forcedCapture = {}
|
||||
left = piece.col - 1
|
||||
right = piece.col + 1
|
||||
row = piece.row
|
||||
if piece.colour == GREEN:
|
||||
moves.update(self._traverseLeft(row - 1, max(row - 3, -1), -1, piece.colour, left))
|
||||
moves.update(self._traverseRight(row - 1, max(row - 3, -1), -1, piece.colour, right))
|
||||
if piece.colour == WHITE:
|
||||
moves.update(self._traverseLeft(row + 1, min(row + 3, ROWS), 1, piece.colour, left))
|
||||
moves.update(self._traverseRight(row + 1, min(row + 3, ROWS), 1, piece.colour, right))
|
||||
|
||||
if piece.king:
|
||||
moves.update(self._traverseLeft(row - 1, max(row - 3, -1), -1, piece.colour, left))
|
||||
moves.update(self._traverseRight(row - 1, max(row - 3, -1), -1, piece.colour, right))
|
||||
moves.update(self._traverseLeft(row + 1, min(row + 3, ROWS), 1, piece.colour, left))
|
||||
moves.update(self._traverseRight(row + 1, min(row + 3, ROWS), 1, piece.colour, right))
|
||||
|
||||
if len(moves.values()) <= 1:
|
||||
return moves
|
||||
|
||||
movesValues = list(moves.values())
|
||||
movesKeys = list(moves.keys())
|
||||
|
||||
forced = {}
|
||||
|
||||
for i in range(len(movesKeys)):
|
||||
if not movesValues[i]:
|
||||
forced[movesKeys[i]] = moves[movesKeys[i]]
|
||||
if len(forced) != len(moves):
|
||||
forced.clear()
|
||||
for i in range(len(movesKeys)):
|
||||
if movesValues[i]:
|
||||
forced[movesKeys[i]] = moves[movesKeys[i]]
|
||||
if len(forced) != len(moves):
|
||||
for i in range(len(movesKeys)):
|
||||
if movesValues[i]:
|
||||
forcedCapture[movesKeys[i]] = moves[movesKeys[i]]
|
||||
else:
|
||||
forcedCapture = forced
|
||||
else:
|
||||
forcedCapture = forced
|
||||
return forcedCapture
|
||||
|
||||
def scoreOfTheBoard(self):
|
||||
return self.whiteLeft - self.greenLeft
|
||||
|
||||
def getAllPieces(self, colour):
|
||||
pieces = []
|
||||
for row in self.board:
|
||||
for piece in row:
|
||||
if piece is not None and piece.colour == colour:
|
||||
pieces.append(piece)
|
||||
return pieces
|
||||
|
||||
def _traverseLeft(self, start, stop, step, colour, left, skipped=[]):
|
||||
moves = {}
|
||||
last = []
|
||||
for row in range(start, stop, step):
|
||||
if left < 0:
|
||||
break
|
||||
mvs = self._traverse(row, left, skipped, moves, step, last, colour)
|
||||
if mvs is None:
|
||||
break
|
||||
elif isinstance(mvs, list):
|
||||
last = mvs
|
||||
else:
|
||||
moves.update(mvs)
|
||||
left -= 1
|
||||
return moves
|
||||
|
||||
def _traverseRight(self, start, stop, step, colour, right, skipped=[]):
|
||||
moves = {}
|
||||
last = []
|
||||
for row in range(start, stop, step):
|
||||
if right >= COLS:
|
||||
break
|
||||
|
||||
mvs = self._traverse(row, right, skipped, moves, step, last, colour)
|
||||
if mvs is None:
|
||||
break
|
||||
elif isinstance(mvs, list):
|
||||
last = mvs
|
||||
else:
|
||||
moves.update(mvs)
|
||||
|
||||
right += 1
|
||||
return moves
|
||||
|
||||
def _traverse(self, row, col, skipped, moves, step, last, colour):
|
||||
current = self.board[row][col]
|
||||
if current is None:
|
||||
if skipped and not last:
|
||||
return None
|
||||
elif skipped:
|
||||
moves[(row, col)] = last + skipped
|
||||
else:
|
||||
moves[(row, col)] = last
|
||||
|
||||
if last:
|
||||
if step == -1:
|
||||
rowCalc = max(row - 3, 0)
|
||||
else:
|
||||
rowCalc = min(row + 3, ROWS)
|
||||
moves.update(self._traverseLeft(row + step, rowCalc, step, colour, col - 1, skipped=last))
|
||||
moves.update(self._traverseRight(row + step, rowCalc, step, colour, col + 1, skipped=last))
|
||||
return None
|
||||
elif current.colour == colour:
|
||||
return None
|
||||
else:
|
||||
last = [current]
|
||||
return last
|
||||
@@ -0,0 +1,15 @@
|
||||
import pygame
|
||||
|
||||
WIDTH, HEIGHT = 800, 800
|
||||
ROWS, COLS = 8, 8
|
||||
SQUARE_SIZE = WIDTH // COLS
|
||||
|
||||
# RGB color
|
||||
|
||||
GREEN = (144, 184, 59)
|
||||
WHITE = (255, 255, 255)
|
||||
BLACK = (0, 0, 0)
|
||||
BLUE = (0, 0, 255)
|
||||
GREY = (128, 128, 128)
|
||||
|
||||
CROWN = pygame.transform.scale(pygame.image.load("./utilities/assets/crown.png"), (45, 25))
|
||||
@@ -0,0 +1,82 @@
|
||||
import pygame
|
||||
from utilities.board import Board
|
||||
from utilities.constants import GREEN, WHITE, BLUE, SQUARE_SIZE
|
||||
|
||||
class GameManager:
|
||||
def __init__(self, win, colour):
|
||||
self._init(colour)
|
||||
self.win = win
|
||||
|
||||
def _init(self, colour):
|
||||
self.selected = None
|
||||
self.board = Board()
|
||||
self.turn = colour
|
||||
self.validMoves = {}
|
||||
self.legCount = 0
|
||||
|
||||
def update(self):
|
||||
self.board.draw(self.win)
|
||||
self.drawValidMoves(self.validMoves)
|
||||
pygame.display.update()
|
||||
|
||||
def reset(self):
|
||||
self._init(self.turn)
|
||||
|
||||
def select(self, row, col):
|
||||
if self.selected:
|
||||
result = self._move(row, col)
|
||||
if not result:
|
||||
self.selected = None
|
||||
self.select(row, col)
|
||||
piece = self.board.getPiece(row, col)
|
||||
if piece is not None and piece.colour == self.turn:
|
||||
self.selected = piece
|
||||
self.validMoves = self.board.getValidMoves(piece)
|
||||
return True
|
||||
|
||||
def _move(self, row, col):
|
||||
piece = self.board.getPiece(row, col)
|
||||
if self.selected and piece is None and (row, col) in self.validMoves:
|
||||
self.board.move(self.selected, row, col)
|
||||
skipped = self.validMoves[row, col]
|
||||
if self.validMoves[list(self.validMoves.keys())[0]]:
|
||||
if self.validMoves[list(self.validMoves.keys())[0]][0].king:
|
||||
self.selected.makeKing()
|
||||
if skipped:
|
||||
self.board.remove(skipped)
|
||||
if len(self.validMoves) > 1:
|
||||
del self.validMoves[list(self.validMoves.keys())[0]]
|
||||
else:
|
||||
self.changeTurn()
|
||||
else:
|
||||
self.changeTurn()
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
def changeTurn(self):
|
||||
self.validMoves = {}
|
||||
if self.turn == GREEN:
|
||||
self.turn = WHITE
|
||||
else:
|
||||
self.turn = GREEN
|
||||
|
||||
def drawValidMoves(self, moves):
|
||||
for row, col in moves:
|
||||
pygame.draw.circle(self.win, BLUE,
|
||||
(col * SQUARE_SIZE + SQUARE_SIZE // 2, row * SQUARE_SIZE + SQUARE_SIZE // 2), 15)
|
||||
|
||||
def winner(self):
|
||||
return self.board.winner()
|
||||
|
||||
def getBoard(self):
|
||||
return self.board
|
||||
|
||||
def aiMove(self, board):
|
||||
if board is None:
|
||||
# colour = "green" if self.turn == GREEN else "white"
|
||||
# print("no move left for " + colour + " to make")
|
||||
self.changeTurn()
|
||||
return
|
||||
self.board = board
|
||||
self.changeTurn()
|
||||
@@ -0,0 +1,38 @@
|
||||
import pygame.draw
|
||||
|
||||
from utilities.constants import SQUARE_SIZE, GREY, CROWN
|
||||
|
||||
|
||||
class Piece:
|
||||
def __init__(self, row, col, colour):
|
||||
self.row = row
|
||||
self.col = col
|
||||
self.colour = colour
|
||||
self.king = False
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.calcPosition()
|
||||
self.padding = 20
|
||||
self.border = 2
|
||||
|
||||
def calcPosition(self):
|
||||
self.x = SQUARE_SIZE * self.col + SQUARE_SIZE // 2
|
||||
self.y = SQUARE_SIZE * self.row + SQUARE_SIZE // 2
|
||||
|
||||
def makeKing(self):
|
||||
self.king = True
|
||||
|
||||
def draw(self, win):
|
||||
radius = SQUARE_SIZE // 2 - self.padding
|
||||
pygame.draw.circle(win, GREY, (self.x, self.y), radius + self.border)
|
||||
pygame.draw.circle(win, self.colour, (self.x, self.y), radius)
|
||||
if self.king:
|
||||
win.blit(CROWN, (self.x - CROWN.get_width() // 2, self.y - CROWN.get_height() // 2))
|
||||
|
||||
def move(self, row, col):
|
||||
self.row = row
|
||||
self.col = col
|
||||
self.calcPosition()
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.colour)
|
||||
Reference in New Issue
Block a user