Skip to content

Dragjon/connectide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Connectide Game Documentation

Overview

The connectide module provides a class-based implementation of the Connect-4 game. This module includes various functionalities to represent the game board, manage game state, and perform operations like move generation, checking for wins, adding and undoing moves, and running performance tests.

Constants

  • noPce = 0: Represents an empty spot on the board.
  • red = 1: Represents a red piece on the board.
  • yellow = 2: Represents a yellow piece on the board.

Board Class

Initialization

class Board:
    def __init__(self, board=None, turn=red):
        if board is None:
            self.board = [[noPce for _ in range(7)] for _ in range(6)]
        else:
            self.board = board
        self.turn = turn
  • board: A 6x7 matrix representing the game board. Defaults to an empty board if not provided.
  • turn: Indicates the current player's turn. Defaults to red.

Methods

isConnect4

def isConnect4(self, row: int, col: int) -> bool:
    board = self.board
    pce = board[row][col]

    if pce is not noPce:
        if row >= 3 and board[row - 1][col] == pce and board[row - 2][col] == pce and board[row - 3][col] == pce:
            return True
        if row <= 2 and board[row + 1][col] == pce and board[row + 2][col] == pce and board[row + 3][col] == pce:
            return True
        if col <= 3 and board[row][col + 1] == pce and board[row][col + 2] == pce and board[row][col + 3] == pce:
            return True
        if col >= 3 and board[row][col - 1] == pce and board[row][col - 2] == pce and board[row][col - 3] == pce:
            return True
        if row >= 3 and col <= 3 and board[row - 1][col + 1] == pce and board[row - 2][col + 2] == pce and board[row - 3][col + 3] == pce:
            return True
        if row <= 2 and col <= 3 and board[row + 1][col + 1] == pce and board[row + 2][col + 2] == pce and board[row + 3][col + 3] == pce:
            return True
        if row >= 3 and col >= 3 and board[row - 1][col - 1] == pce and board[row - 2][col - 2] == pce and board[row - 3][col - 3] == pce:
            return True
        if row <= 2 and col >= 3 and board[row + 1][col - 1] == pce and board[row + 2][col - 2] == pce and board[row + 3][col - 3] == pce:
            return True

    return False
  • row: The row of the square.
  • col: The column of the square.
  • Returns True if the square is part of a 4-in-a-row, otherwise False.

isCheckmate

def isCheckmate(self) -> bool:
    for row in range(6):
        for col in range(7):
            if self.isConnect4(row, col):
                return True
    return False
  • Returns True if a 4-in-a-row is present on the board, otherwise False.

pseudoLegalMoveGen

def pseudoLegalMoveGen(self) -> list[int]:
    moves = []
    board = self.board
    for col in range(7):
        if board[0][col] == noPce:
            moves.append(col)
    return moves
  • Returns a list of pseudo-legal moves (legal columns), which includes moves even after a board is in checkmate.

moveGen

def moveGen(self) -> list[int]:
    moves = []
    if not self.isCheckmate():
        board = self.board
        for col in range(7):
            if board[0][col] == noPce:
                moves.append(col)
    return moves
  • Returns a list of legal moves (legal columns).

addPiece

def addPiece(self, col: int):
    pce = self.turn
    for row in range(6):
        if self.board[row][col] != noPce:
            self.board[row - 1][col] = pce
            self.turn = 3 - pce
            break
        if row == 5 and self.board[row][col] == noPce:
            self.board[row][col] = pce
            self.turn = 3 - pce
            break
  • col: The column to add a piece.

undoMove

def undoMove(self, col: int):
    for row in range(6):
        if self.board[row][col] != noPce:
            self.board[row][col] = noPce
            self.turn = 3 - self.turn
            break
  • col: The column from which to undo a move.

getNumMoves

def getNumMoves(self) -> int:
    moves = 0
    for i in range(6):
        for j in range(7):
            if self.board[i][j] != noPce:
                moves += 1
    return moves
  • Returns the number of pieces on the board.

show

def show(self, debug: bool = False):
    board = self.board
    for i in range(6):
        for j in range(7):
            pce = board[i][j]
            pceChar = "-" if pce == noPce else "R" if pce == red else "Y"
            print(pceChar, end=" ")
        if i != 5:
            print()
    print("\n-------------")
    print("1 2 3 4 5 6 7 ")
    if debug:
        print(f"Turn: {'red' if self.turn == red else 'yellow'}")
        print(f"Moves Played: {self.getNumMoves()}")
        print(f"Checkmate Status: {'True' if self.isCheckmate() else 'False'}")
    print()
  • debug (optional): Whether to print additional debug information. Defaults to False.

chash

def chash(self) -> str:
    fen = ""
    for i in range(len(self.board)):
        for j in range(len(self.board[0])):
            fen += str(self.board[i][j])
    return fen + str(self.turn)
  • Returns a simple hash of the board position.

flatten

def flatten(self) -> list[int]:
    flat = []
    for i in range(len(self.board)):
        for j in range(len(self.board[0])):
            flat.append(self.board[i][j])
    return flat
  • Returns the flattened board array as a 1D list.

parse

def parse(self, string: str):
    i = 0
    j = 0
    count = 0

    for char in string:
        count += 1
        if count == 43:
            self.turn = int(char)
            break
        if i == 7:
            i = 0
            j += 1

        self.board[j][i] = int(char)
        i += 1
  • string: The string board representation created by chash.

perfD

def perfD(self, depth: int) -> int:
    if depth == 0:
        return 1
    nodes = 0
    legals = self.moveGen()
    for col in legals:
        self.addPiece(col)
        nodes += self.perfD(depth - 1)
        self.undoMove(col)
    return nodes
  • depth: The depth to search to.
  • Returns the number of nodes at a specified depth.

perfT

def perfT(self, maxDepth: int):
    startTime = time.time()
    for depth in range(1, maxDepth + 1):
        nodes = self.perfD(depth)
        elapsed = time.time() - startTime
        print(
            f"info string perft depth {depth} time {int(elapsed*1000)} nodes {nodes} nps {int(nodes / (elapsed + 0.000000001))}"
        )
  • maxDepth: The maximum depth to run for this test.
  • Initiates a performance test.

Example Usage

board = Board()
board.show()
board.parse("0000000000000000000000000000000000000000012")
board.perfT(7)

Perft test

info string perft depth 1 time 0 nodes 7 nps 7000000000
info string perft depth 2 time 2 nodes 49 nps 16381
info string perft depth 3 time 5 nodes 343 nps 62905
info string perft depth 4 time 17 nodes 2401 nps 137464
info string perft depth 5 time 101 nodes 16807 nps 165664
info string perft depth 6 time 678 nodes 117649 nps 173408
info string perft depth 7 time 4826 nodes 823536 nps 170629
info string perft depth 8 time 34460 nodes 5673234 nps 164630

About

A complete connect-4 python module

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages