├── README.md ├── __init__.py ├── checkers ├── board.py ├── constants.py ├── game.py └── piece.py ├── main.py └── requirements.txt /README.md: -------------------------------------------------------------------------------- 1 | # Python-Checkers 2 | 3 | # 💻 Launch Your Software Development Career Today! 4 | 5 | 🎓 **No degree? No problem!** My program equips you with everything you need to break into tech and land an entry-level software development role. 6 | 7 | 🚀 **Why Join?** 8 | - 💼 **$70k+ starting salary potential** 9 | - 🕐 **Self-paced:** Complete on your own time 10 | - 🤑 **Affordable:** Low risk compared to expensive bootcamps or degrees 11 | - 🎯 **45,000+ job openings** in the market 12 | 13 | 👉 **[Start your journey today!](https://techwithtim.net/dev)** 14 | No experience needed—just your determination. Future-proof your career and unlock six-figure potential like many of our students have! 15 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /checkers/board.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from .constants import BLACK, ROWS, RED, SQUARE_SIZE, COLS, WHITE 3 | from .piece import Piece 4 | 5 | class Board: 6 | def __init__(self): 7 | self.board = [] 8 | self.red_left = self.white_left = 12 9 | self.red_kings = self.white_kings = 0 10 | self.create_board() 11 | 12 | def draw_squares(self, win): 13 | win.fill(BLACK) 14 | for row in range(ROWS): 15 | for col in range(row % 2, COLS, 2): 16 | pygame.draw.rect(win, RED, (row*SQUARE_SIZE, col *SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE)) 17 | 18 | def move(self, piece, row, col): 19 | self.board[piece.row][piece.col], self.board[row][col] = self.board[row][col], self.board[piece.row][piece.col] 20 | piece.move(row, col) 21 | 22 | if row == ROWS - 1 or row == 0: 23 | piece.make_king() 24 | if piece.color == WHITE: 25 | self.white_kings += 1 26 | else: 27 | self.red_kings += 1 28 | 29 | def get_piece(self, row, col): 30 | return self.board[row][col] 31 | 32 | def create_board(self): 33 | for row in range(ROWS): 34 | self.board.append([]) 35 | for col in range(COLS): 36 | if col % 2 == ((row + 1) % 2): 37 | if row < 3: 38 | self.board[row].append(Piece(row, col, WHITE)) 39 | elif row > 4: 40 | self.board[row].append(Piece(row, col, RED)) 41 | else: 42 | self.board[row].append(0) 43 | else: 44 | self.board[row].append(0) 45 | 46 | def draw(self, win): 47 | self.draw_squares(win) 48 | for row in range(ROWS): 49 | for col in range(COLS): 50 | piece = self.board[row][col] 51 | if piece != 0: 52 | piece.draw(win) 53 | 54 | def remove(self, pieces): 55 | for piece in pieces: 56 | self.board[piece.row][piece.col] = 0 57 | if piece != 0: 58 | if piece.color == RED: 59 | self.red_left -= 1 60 | else: 61 | self.white_left -= 1 62 | 63 | def winner(self): 64 | if self.red_left <= 0: 65 | return WHITE 66 | elif self.white_left <= 0: 67 | return RED 68 | 69 | return None 70 | 71 | def get_valid_moves(self, piece): 72 | moves = {} 73 | left = piece.col - 1 74 | right = piece.col + 1 75 | row = piece.row 76 | 77 | if piece.color == RED or piece.king: 78 | moves.update(self._traverse_left(row -1, max(row-3, -1), -1, piece.color, left)) 79 | moves.update(self._traverse_right(row -1, max(row-3, -1), -1, piece.color, right)) 80 | if piece.color == WHITE or piece.king: 81 | moves.update(self._traverse_left(row +1, min(row+3, ROWS), 1, piece.color, left)) 82 | moves.update(self._traverse_right(row +1, min(row+3, ROWS), 1, piece.color, right)) 83 | 84 | return moves 85 | 86 | def _traverse_left(self, start, stop, step, color, left, skipped=[]): 87 | moves = {} 88 | last = [] 89 | for r in range(start, stop, step): 90 | if left < 0: 91 | break 92 | 93 | current = self.board[r][left] 94 | if current == 0: 95 | if skipped and not last: 96 | break 97 | elif skipped: 98 | moves[(r, left)] = last + skipped 99 | else: 100 | moves[(r, left)] = last 101 | 102 | if last: 103 | if step == -1: 104 | row = max(r-3, 0) 105 | else: 106 | row = min(r+3, ROWS) 107 | moves.update(self._traverse_left(r+step, row, step, color, left-1,skipped=last)) 108 | moves.update(self._traverse_right(r+step, row, step, color, left+1,skipped=last)) 109 | break 110 | elif current.color == color: 111 | break 112 | else: 113 | last = [current] 114 | 115 | left -= 1 116 | 117 | return moves 118 | 119 | def _traverse_right(self, start, stop, step, color, right, skipped=[]): 120 | moves = {} 121 | last = [] 122 | for r in range(start, stop, step): 123 | if right >= COLS: 124 | break 125 | 126 | current = self.board[r][right] 127 | if current == 0: 128 | if skipped and not last: 129 | break 130 | elif skipped: 131 | moves[(r,right)] = last + skipped 132 | else: 133 | moves[(r, right)] = last 134 | 135 | if last: 136 | if step == -1: 137 | row = max(r-3, 0) 138 | else: 139 | row = min(r+3, ROWS) 140 | moves.update(self._traverse_left(r+step, row, step, color, right-1,skipped=last)) 141 | moves.update(self._traverse_right(r+step, row, step, color, right+1,skipped=last)) 142 | break 143 | elif current.color == color: 144 | break 145 | else: 146 | last = [current] 147 | 148 | right += 1 149 | 150 | return moves -------------------------------------------------------------------------------- /checkers/constants.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | WIDTH, HEIGHT = 800, 800 4 | ROWS, COLS = 8, 8 5 | SQUARE_SIZE = WIDTH//COLS 6 | 7 | # rgb 8 | RED = (255, 0, 0) 9 | WHITE = (255, 255, 255) 10 | BLACK = (0, 0, 0) 11 | BLUE = (0, 0, 255) 12 | GREY = (128,128,128) 13 | 14 | CROWN = pygame.transform.scale(pygame.image.load('assets/crown.png'), (44, 25)) 15 | -------------------------------------------------------------------------------- /checkers/game.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from .constants import RED, WHITE, BLUE, SQUARE_SIZE 3 | from checkers.board import Board 4 | 5 | class Game: 6 | def __init__(self, win): 7 | self._init() 8 | self.win = win 9 | 10 | def update(self): 11 | self.board.draw(self.win) 12 | self.draw_valid_moves(self.valid_moves) 13 | pygame.display.update() 14 | 15 | def _init(self): 16 | self.selected = None 17 | self.board = Board() 18 | self.turn = RED 19 | self.valid_moves = {} 20 | 21 | def winner(self): 22 | return self.board.winner() 23 | 24 | def reset(self): 25 | self._init() 26 | 27 | def select(self, row, col): 28 | if self.selected: 29 | result = self._move(row, col) 30 | if not result: 31 | self.selected = None 32 | self.select(row, col) 33 | 34 | piece = self.board.get_piece(row, col) 35 | if piece != 0 and piece.color == self.turn: 36 | self.selected = piece 37 | self.valid_moves = self.board.get_valid_moves(piece) 38 | return True 39 | 40 | return False 41 | 42 | def _move(self, row, col): 43 | piece = self.board.get_piece(row, col) 44 | if self.selected and piece == 0 and (row, col) in self.valid_moves: 45 | self.board.move(self.selected, row, col) 46 | skipped = self.valid_moves[(row, col)] 47 | if skipped: 48 | self.board.remove(skipped) 49 | self.change_turn() 50 | else: 51 | return False 52 | 53 | return True 54 | 55 | def draw_valid_moves(self, moves): 56 | for move in moves: 57 | row, col = move 58 | pygame.draw.circle(self.win, BLUE, (col * SQUARE_SIZE + SQUARE_SIZE//2, row * SQUARE_SIZE + SQUARE_SIZE//2), 15) 59 | 60 | def change_turn(self): 61 | self.valid_moves = {} 62 | if self.turn == RED: 63 | self.turn = WHITE 64 | else: 65 | self.turn = RED -------------------------------------------------------------------------------- /checkers/piece.py: -------------------------------------------------------------------------------- 1 | from .constants import RED, WHITE, SQUARE_SIZE, GREY, CROWN 2 | import pygame 3 | 4 | class Piece: 5 | PADDING = 15 6 | OUTLINE = 2 7 | 8 | def __init__(self, row, col, color): 9 | self.row = row 10 | self.col = col 11 | self.color = color 12 | self.king = False 13 | self.x = 0 14 | self.y = 0 15 | self.calc_pos() 16 | 17 | def calc_pos(self): 18 | self.x = SQUARE_SIZE * self.col + SQUARE_SIZE // 2 19 | self.y = SQUARE_SIZE * self.row + SQUARE_SIZE // 2 20 | 21 | def make_king(self): 22 | self.king = True 23 | 24 | def draw(self, win): 25 | radius = SQUARE_SIZE//2 - self.PADDING 26 | pygame.draw.circle(win, GREY, (self.x, self.y), radius + self.OUTLINE) 27 | pygame.draw.circle(win, self.color, (self.x, self.y), radius) 28 | if self.king: 29 | win.blit(CROWN, (self.x - CROWN.get_width()//2, self.y - CROWN.get_height()//2)) 30 | 31 | def move(self, row, col): 32 | self.row = row 33 | self.col = col 34 | self.calc_pos() 35 | 36 | def __repr__(self): 37 | return str(self.color) -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # Assets: https://techwithtim.net/wp-content/uploads/2020/09/assets.zip 2 | import pygame 3 | from checkers.constants import WIDTH, HEIGHT, SQUARE_SIZE, RED 4 | from checkers.game import Game 5 | from minimax.algorithm import minimax 6 | 7 | FPS = 60 8 | 9 | WIN = pygame.display.set_mode((WIDTH, HEIGHT)) 10 | pygame.display.set_caption('Checkers') 11 | 12 | def get_row_col_from_mouse(pos): 13 | x, y = pos 14 | row = y // SQUARE_SIZE 15 | col = x // SQUARE_SIZE 16 | return row, col 17 | 18 | def main(): 19 | run = True 20 | clock = pygame.time.Clock() 21 | game = Game(WIN) 22 | 23 | while run: 24 | clock.tick(FPS) 25 | 26 | if game.winner() != None: 27 | print(game.winner()) 28 | run = False 29 | 30 | for event in pygame.event.get(): 31 | if event.type == pygame.QUIT: 32 | run = False 33 | 34 | if event.type == pygame.MOUSEBUTTONDOWN: 35 | pos = pygame.mouse.get_pos() 36 | row, col = get_row_col_from_mouse(pos) 37 | game.select(row, col) 38 | 39 | game.update() 40 | 41 | pygame.quit() 42 | 43 | main() -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pygame 2 | --------------------------------------------------------------------------------