Checkers-Python
Over the last two days I have spent a few hours programming a simply checkers onto python. Overall, the project has definitely taught me many lessons about organising my variables and also the use of decorators although none of them got into the final code of the application. If anyone is trying to make the application themselves, I would recommend you take the grid code and then try implement the code yourself. In order to improve the efficiency of your code, I would also recommend you to not have a separate 2d array in order to conduct all of your checks; instead, challenge yourself and run everything on the grid array which holds all of the pieces. The source code will be included below:
import pygame
import random
import sys
from itertools import combinations
WIDTH = 800
ROWS = 8
RED= pygame.image.load('red.png')
GREEN= pygame.image.load('green.png')
REDKING = pygame.image.load('redKing.png')
GREENKING = pygame.image.load('greenKing.png')
WHITE = (255,255,255)
BLACK = (0,0,0)
ORANGE = (235, 168, 52)
BLUE = (76, 252, 241)
pygame.init()
WIN = pygame.display.set_mode((WIDTH,WIDTH))
pygame.display.set_caption('Checkers')
priorMoves=[]
class Node:
def __init__(self, row, col, width):
self.row = row
self.col = col
self.x = int(row * width)
self.y = int(col * width)
self.colour = WHITE
self.piece = None
def draw(self, WIN):
pygame.draw.rect(WIN, self.colour, (self.x, self.y, WIDTH / ROWS, WIDTH / ROWS))
if self.piece:
WIN.blit(self.piece.image, (self.x, self.y))
def update_display(win, grid, rows, width):
for row in grid:
for spot in row:
spot.draw(win)
draw_grid(win, rows, width)
pygame.display.update()
def make_grid(rows, width):
grid = []
gap = width// rows
count = 0
for i in range(rows):
grid.append([])
for j in range(rows):
node = Node(j,i, gap)
if abs(i-j) % 2 == 0:
node.colour=BLACK
if (abs(i+j)%2==0) and (i<3):
node.piece = Piece('R')
elif(abs(i+j)%2==0) and i>4:
node.piece=Piece('G')
count+=1
grid[i].append(node)
return grid
def draw_grid(win, rows, width):
gap = width // ROWS
for i in range(rows):
pygame.draw.line(win, BLACK, (0, i * gap), (width, i * gap))
for j in range(rows):
pygame.draw.line(win, BLACK, (j * gap, 0), (j * gap, width))
class Piece:
def __init__(self, team):
self.team=team
self.image= RED if self.team=='R' else GREEN
self.type=None
def draw(self, x, y):
WIN.blit(self.image, (x,y))
def getNode(grid, rows, width):
gap = width//rows
RowX,RowY = pygame.mouse.get_pos()
Row = RowX//gap
Col = RowY//gap
return (Col,Row)
def resetColours(grid, node):
positions = generatePotentialMoves(node, grid)
positions.append(node)
for colouredNodes in positions:
nodeX, nodeY = colouredNodes
grid[nodeX][nodeY].colour = BLACK if abs(nodeX - nodeY) % 2 == 0 else WHITE
def HighlightpotentialMoves(piecePosition, grid):
positions = generatePotentialMoves(piecePosition, grid)
for position in positions:
Column,Row = position
grid[Column][Row].colour=BLUE
def opposite(team):
return "R" if team=="G" else "G"
def generatePotentialMoves(nodePosition, grid):
checker = lambda x,y: x+y>=0 and x+y<8
positions= []
column, row = nodePosition
if grid[column][row].piece:
vectors = [[1, -1], [1, 1]] if grid[column][row].piece.team == "R" else [[-1, -1], [-1, 1]]
if grid[column][row].piece.type=='KING':
vectors = [[1, -1], [1, 1],[-1, -1], [-1, 1]]
for vector in vectors:
columnVector, rowVector = vector
if checker(columnVector,column) and checker(rowVector,row):
#grid[(column+columnVector)][(row+rowVector)].colour=ORANGE
if not grid[(column+columnVector)][(row+rowVector)].piece:
positions.append((column + columnVector, row + rowVector))
elif grid[column+columnVector][row+rowVector].piece and\
grid[column+columnVector][row+rowVector].piece.team==opposite(grid[column][row].piece.team):
if checker((2* columnVector), column) and checker((2* rowVector), row) \
and not grid[(2* columnVector)+ column][(2* rowVector) + row].piece:
positions.append((2* columnVector+ column,2* rowVector+ row ))
return positions
"""
Error with locating opssible moves row col error
"""
def highlight(ClickedNode, Grid, OldHighlight):
Column,Row = ClickedNode
Grid[Column][Row].colour=ORANGE
if OldHighlight:
resetColours(Grid, OldHighlight)
HighlightpotentialMoves(ClickedNode, Grid)
return (Column,Row)
def move(grid, piecePosition, newPosition):
resetColours(grid, piecePosition)
newColumn, newRow = newPosition
oldColumn, oldRow = piecePosition
piece = grid[oldColumn][oldRow].piece
grid[newColumn][newRow].piece=piece
grid[oldColumn][oldRow].piece = None
if newColumn==7 and grid[newColumn][newRow].piece.team=='R':
grid[newColumn][newRow].piece.type='KING'
grid[newColumn][newRow].piece.image=REDKING
if newColumn==0 and grid[newColumn][newRow].piece.team=='G':
grid[newColumn][newRow].piece.type='KING'
grid[newColumn][newRow].piece.image=GREENKING
if abs(newColumn-oldColumn)==2 or abs(newRow-oldRow)==2:
grid[int((newColumn+oldColumn)/2)][int((newRow+oldRow)/2)].piece = None
return grid[newColumn][newRow].piece.team
return opposite(grid[newColumn][newRow].piece.team)
def main(WIDTH, ROWS):
grid = make_grid(ROWS, WIDTH)
highlightedPiece = None
currMove = 'G'
while True:
for event in pygame.event.get():
if event.type== pygame.QUIT:
print('EXIT SUCCESSFUL')
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
clickedNode = getNode(grid, ROWS, WIDTH)
ClickedPositionColumn, ClickedPositionRow = clickedNode
if grid[ClickedPositionColumn][ClickedPositionRow].colour == BLUE:
if highlightedPiece:
pieceColumn, pieceRow = highlightedPiece
if currMove == grid[pieceColumn][pieceRow].piece.team:
resetColours(grid, highlightedPiece)
currMove=move(grid, highlightedPiece, clickedNode)
elif highlightedPiece == clickedNode:
pass
else:
if grid[ClickedPositionColumn][ClickedPositionRow].piece:
if currMove == grid[ClickedPositionColumn][ClickedPositionRow].piece.team:
highlightedPiece = highlight(clickedNode, grid, highlightedPiece)
update_display(WIN, grid,ROWS,WIDTH)
main(WIDTH, ROWS)
When it comes to programming the logic of the game, nothing is overly complicated and this game is almost a simplification of the chess game which I have made before however there are specific complexities added to this program in that we need to add addition moves to the players if they kill a piece and we need to change the potential moves of a piece if they are able to kill a piece. I did attempt to split my code into functions as much as I could to make it understandable for anyone surveying the code.
Using decorators, it is possible for you to add the functionality of checking when a player has won the game. You can do this by having a static method which will count the amount of pieces of each side after a move after if the count is 0 then the opposite team has won. If you have never heard of decorators
In essence, all a decorator is doing added extra functionality onto a function you have already created.
Note: If you are going to copy my source code, you will need to find some new pieces to display on the board and name them green.png, red.png etc. Also note that I used a background remover on my images which you can easily find online and you can drop the dimensions of your images through paint.
If you have any questions about the code, then do drop a comment and I will reply with any guidance that you may need. I hope this article comes in useful!