added files
This commit is contained in:
parent
c69f4e2713
commit
50b61cd32b
5
Readme.md
Normal file
5
Readme.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Pygame Checkers
|
||||
This is a Checkers game programmed in python using the pygame library. This program will be perfect for training a deeplearning ai on how to play checkers.
|
||||
|
||||
# Credits
|
||||
This code is based on the code from https://github.com/Btsan/CheckersBot and the video explaining how it works https://www.youtube.com/playlist?list=PLzMcBGfZo4-lkJr3sqpikNyVzbNZLRiT3 . Check out his code and videos.
|
0
__init__.py
Normal file
0
__init__.py
Normal file
BIN
assets/crown.png
Normal file
BIN
assets/crown.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
0
checkers/__init__.py
Normal file
0
checkers/__init__.py
Normal file
150
checkers/board.py
Normal file
150
checkers/board.py
Normal file
@ -0,0 +1,150 @@
|
||||
import pygame
|
||||
from .constants import BLACK, ROWS, RED, SQUARE_SIZE, COLS, WHITE
|
||||
from .piece import Piece
|
||||
|
||||
class Board:
|
||||
def __init__(self):
|
||||
self.board = []
|
||||
self.red_left = self.white_left = 12
|
||||
self.red_kings = self.white_kings = 0
|
||||
self.create_board()
|
||||
|
||||
def draw_squares(self, win):
|
||||
win.fill(BLACK)
|
||||
for row in range(ROWS):
|
||||
for col in range(row % 2, COLS, 2):
|
||||
pygame.draw.rect(win, RED, (row*SQUARE_SIZE, col *SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE))
|
||||
|
||||
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.make_king()
|
||||
if piece.color == WHITE:
|
||||
self.white_kings += 1
|
||||
else:
|
||||
self.red_kings += 1
|
||||
|
||||
def get_piece(self, row, col):
|
||||
return self.board[row][col]
|
||||
|
||||
def create_board(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, RED))
|
||||
else:
|
||||
self.board[row].append(0)
|
||||
else:
|
||||
self.board[row].append(0)
|
||||
|
||||
def draw(self, win):
|
||||
self.draw_squares(win)
|
||||
for row in range(ROWS):
|
||||
for col in range(COLS):
|
||||
piece = self.board[row][col]
|
||||
if piece != 0:
|
||||
piece.draw(win)
|
||||
|
||||
def remove(self, pieces):
|
||||
for piece in pieces:
|
||||
self.board[piece.row][piece.col] = 0
|
||||
if piece != 0:
|
||||
if piece.color == RED:
|
||||
self.red_left -= 1
|
||||
else:
|
||||
self.white_left -= 1
|
||||
|
||||
def winner(self):
|
||||
if self.red_left <= 0:
|
||||
return WHITE
|
||||
elif self.white_left <= 0:
|
||||
return RED
|
||||
|
||||
return None
|
||||
|
||||
def get_valid_moves(self, piece):
|
||||
moves = {}
|
||||
left = piece.col - 1
|
||||
right = piece.col + 1
|
||||
row = piece.row
|
||||
|
||||
if piece.color == RED or piece.king:
|
||||
moves.update(self._traverse_left(row -1, max(row-3, -1), -1, piece.color, left))
|
||||
moves.update(self._traverse_right(row -1, max(row-3, -1), -1, piece.color, right))
|
||||
if piece.color == WHITE or piece.king:
|
||||
moves.update(self._traverse_left(row +1, min(row+3, ROWS), 1, piece.color, left))
|
||||
moves.update(self._traverse_right(row +1, min(row+3, ROWS), 1, piece.color, right))
|
||||
|
||||
return moves
|
||||
|
||||
def _traverse_left(self, start, stop, step, color, left, skipped=[]):
|
||||
moves = {}
|
||||
last = []
|
||||
for r in range(start, stop, step):
|
||||
if left < 0:
|
||||
break
|
||||
|
||||
current = self.board[r][left]
|
||||
if current == 0:
|
||||
if skipped and not last:
|
||||
break
|
||||
elif skipped:
|
||||
moves[(r, left)] = last + skipped
|
||||
else:
|
||||
moves[(r, left)] = last
|
||||
|
||||
if last:
|
||||
if step == -1:
|
||||
row = max(r-3, 0)
|
||||
else:
|
||||
row = min(r+3, ROWS)
|
||||
moves.update(self._traverse_left(r+step, row, step, color, left-1,skipped=last))
|
||||
moves.update(self._traverse_right(r+step, row, step, color, left+1,skipped=last))
|
||||
break
|
||||
elif current.color == color:
|
||||
break
|
||||
else:
|
||||
last = [current]
|
||||
|
||||
left -= 1
|
||||
|
||||
return moves
|
||||
|
||||
def _traverse_right(self, start, stop, step, color, right, skipped=[]):
|
||||
moves = {}
|
||||
last = []
|
||||
for r in range(start, stop, step):
|
||||
if right >= COLS:
|
||||
break
|
||||
|
||||
current = self.board[r][right]
|
||||
if current == 0:
|
||||
if skipped and not last:
|
||||
break
|
||||
elif skipped:
|
||||
moves[(r,right)] = last + skipped
|
||||
else:
|
||||
moves[(r, right)] = last
|
||||
|
||||
if last:
|
||||
if step == -1:
|
||||
row = max(r-3, 0)
|
||||
else:
|
||||
row = min(r+3, ROWS)
|
||||
moves.update(self._traverse_left(r+step, row, step, color, right-1,skipped=last))
|
||||
moves.update(self._traverse_right(r+step, row, step, color, right+1,skipped=last))
|
||||
break
|
||||
elif current.color == color:
|
||||
break
|
||||
else:
|
||||
last = [current]
|
||||
|
||||
right += 1
|
||||
|
||||
return moves
|
14
checkers/constants.py
Normal file
14
checkers/constants.py
Normal file
@ -0,0 +1,14 @@
|
||||
import pygame
|
||||
|
||||
WIDTH, HEIGHT = 800, 800
|
||||
ROWS, COLS = 8, 8
|
||||
SQUARE_SIZE = WIDTH//COLS
|
||||
|
||||
# rgb
|
||||
RED = (255, 0, 0)
|
||||
WHITE = (255, 255, 255)
|
||||
BLACK = (0, 0, 0)
|
||||
BLUE = (0, 0, 255)
|
||||
GREY = (128,128,128)
|
||||
|
||||
CROWN = pygame.transform.scale(pygame.image.load('assets/crown.png'), (44, 25))
|
73
checkers/game.py
Normal file
73
checkers/game.py
Normal file
@ -0,0 +1,73 @@
|
||||
import pygame
|
||||
from .constants import RED, WHITE, BLUE, SQUARE_SIZE
|
||||
from checkers.board import Board
|
||||
|
||||
class Game:
|
||||
def __init__(self, win):
|
||||
self._init()
|
||||
self.win = win
|
||||
|
||||
|
||||
|
||||
def _init(self):
|
||||
self.selected = None
|
||||
self.board = Board()
|
||||
self.turn = RED
|
||||
self.valid_moves = {}
|
||||
self.row = -1
|
||||
self.col = -1
|
||||
|
||||
def update(self):
|
||||
self.board.draw(self.win)
|
||||
self.draw_valid_moves(self.row, self.col)
|
||||
pygame.display.update()
|
||||
|
||||
def winner(self):
|
||||
return self.board.winner()
|
||||
|
||||
def reset(self):
|
||||
self._init()
|
||||
|
||||
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.get_piece(row, col)
|
||||
if piece != 0 and piece.color == self.turn:
|
||||
self.selected = piece
|
||||
self.valid_moves = self.board.get_valid_moves(piece)
|
||||
|
||||
self.row = row
|
||||
self.col = col
|
||||
return True
|
||||
self.row = -1
|
||||
self.col = -1
|
||||
return False
|
||||
|
||||
def _move(self, row, col):
|
||||
row = row
|
||||
col = col
|
||||
piece = self.board.get_piece(row, col)
|
||||
if self.selected and piece == 0 and (row, col) in self.valid_moves:
|
||||
self.board.move(self.selected, row, col)
|
||||
skipped = self.valid_moves[(row, col)]
|
||||
if skipped:
|
||||
self.board.remove(skipped)
|
||||
self.change_turn()
|
||||
else:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def draw_valid_moves(self, row, col):
|
||||
pygame.draw.circle(self.win, BLUE, (col * SQUARE_SIZE + SQUARE_SIZE//2, row * SQUARE_SIZE + SQUARE_SIZE//2), 15)
|
||||
|
||||
def change_turn(self):
|
||||
self.valid_moves = {}
|
||||
if self.turn == RED:
|
||||
self.turn = WHITE
|
||||
else:
|
||||
self.turn = RED
|
39
checkers/piece.py
Normal file
39
checkers/piece.py
Normal file
@ -0,0 +1,39 @@
|
||||
from .constants import RED, WHITE, SQUARE_SIZE, GREY, CROWN
|
||||
import pygame
|
||||
|
||||
class Piece:
|
||||
PADDING = 15
|
||||
OUTLINE = 2
|
||||
|
||||
def __init__(self, row, col, color):
|
||||
self.row = row
|
||||
self.col = col
|
||||
self.color = color
|
||||
self.king = False
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.calc_pos()
|
||||
|
||||
def calc_pos(self):
|
||||
self.x = SQUARE_SIZE * self.col + SQUARE_SIZE // 2
|
||||
self.y = SQUARE_SIZE * self.row + SQUARE_SIZE // 2
|
||||
|
||||
def make_king(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.OUTLINE)
|
||||
pygame.draw.circle(win, self.color, (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.calc_pos()
|
||||
|
||||
def __repr__(self):
|
||||
return f'Piece({self.x}, {self.y}, {self.color})'
|
||||
|
||||
|
41
main.py
Normal file
41
main.py
Normal file
@ -0,0 +1,41 @@
|
||||
import pygame
|
||||
from checkers.constants import WIDTH, HEIGHT, SQUARE_SIZE, RED, BLUE
|
||||
from checkers.game import Game
|
||||
|
||||
FPS = 60
|
||||
|
||||
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||
pygame.display.set_caption('Checkers')
|
||||
|
||||
def get_row_col_from_mouse(pos):
|
||||
x, y = pos
|
||||
row = y // SQUARE_SIZE
|
||||
col = x // SQUARE_SIZE
|
||||
return row, col
|
||||
|
||||
def main():
|
||||
run = True
|
||||
clock = pygame.time.Clock()
|
||||
game = Game(WIN)
|
||||
|
||||
while run:
|
||||
clock.tick(FPS)
|
||||
|
||||
if game.winner() != None:
|
||||
print(game.winner())
|
||||
run = False
|
||||
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
run = False
|
||||
|
||||
if event.type == pygame.MOUSEBUTTONDOWN:
|
||||
pos = pygame.mouse.get_pos()
|
||||
row, col = get_row_col_from_mouse(pos)
|
||||
game.select(row, col)
|
||||
|
||||
game.update()
|
||||
|
||||
pygame.quit()
|
||||
|
||||
main()
|
Loading…
Reference in New Issue
Block a user