Alpha-Chess: the Ultimate Cheat Code

by ElectraFlame in Design > Software

69 Views, 1 Favorites, 0 Comments

Alpha-Chess: the Ultimate Cheat Code

Screenshot 2025-06-10 171219.png
Alpha-chess - GUI 2 - Made with Clipchamp
ALPHA-CHESS - CLI
**Note : The project made is currently in form of a software... further development of turning it into a wearable and unrecognizable bot is in progress.**


Ever lost to ur friend in a chess tournament ... frustrating I know....what if u are wearing a cap in the tournament and u have sun sickness.... if that's a thing, and the whole time, underneath it is the ULTIMATE CHEAT CODE!! yes... that's the bot and which is barely noticeable by anyone. and who is it to help you with it? me. ElectraFlame, and wait is the bot trained by me? partly, and how will it recognize moves? well we have our own special guest who ill introduce to you later on. but hey, a hint won't render your brain to recognize who it might be,

our special guest is a chess board with four squares and a fish on it.


Before we begin, I would like you to take a look at the following website created by me and my personal AI which describes the features of my project -

https://elecramadness.github.io/AlphaChess.github.io/


The main website URL is not developed due to file size handling issues while deploying, but for output viewing the video provided above and codes can be utilized.


Ready to turn the tables on your chess nemesis? Let's build the future of "totally legitimate" chess strategy together!

Disclaimer: Use responsibly and maybe don't actually cheat in real tournaments. But hey, practicing against friends? Fair game.

Planning the Project

First off, we need to plan our way of input and output, since we have to conceal our bot.

Input-Output planning

  1. first method is input and output in textual basis, we type our move to the bot and our bot returns its move back in textual manner. (a simple prompt system, most helpful if its a software)
  2. second basis of input is through voice commands: - train your own RNN model to recognize only your commands, my pc will become a fired potato OR use a readymade model such as WHISPER to recognize voice input, THE CATCH, it recognizes literally everything in background
  3. Third yet most difficult option - Input using camera. Yes, we shall be using computer vision to make my potato understand moves and where they are done.


Now that the first two methods are easy to take on as a software we shall explore them first, however if we have the need of incorporating them as a wearable as promised, they are not feasible options.


If the provided codes have indentation issues, don't worry i shall provide code in files at the end!!


Lets get into making the first part - textual conversation!

Executing Textual Conversation

Screenshot 2025-06-10 165238.png
Screenshot 2025-06-10 165810.png

I think now might be the right time to introduce our guest

STOCKFISH! V17.1


so since we are doing text based conversation with our bot [ stockfish v17.1 ] the approach is pretty simple

  1. load stockfish into PyCharm project (recommended)
  2. initialize stockfish
  3. take text input
  4. feed it to stockfish
  5. print the move by stockfish


Installing stockfish

you can install stockfish from PyCharm directly or install from website and load it into your directory

https://stockfishchess.org/download/


Writing the code

  1. importing necessary libraries - chess, chess.engine
  2. first we shall declare a variable which serves as the location where stockfish is located and initialize the engine
  3. set the board dimensions
  4. ask input for the side they shall choose - black / white - b/w
  5. play the game


The code


import chess
import chess.engine


def print_board(board):
"""Print the current board state in a readable format."""
print("\n" + "=" * 50)
print("Current Board:")
print("=" * 50)
print(board)
print("=" * 50)


def get_player_move(board):
"""Get a valid move from the player."""
while True:
try:
print(f"\nIt's {'White' if board.turn else 'Black'}'s turn.")
move_input = input("Enter your move (e.g., e2e4) or 'quit' to exit: ").strip().lower()

if move_input == 'quit':
return None

# Try to parse the move
move = chess.Move.from_uci(move_input)

# Check if the move is legal
if move in board.legal_moves:
return move
else:
print("Invalid move! That move is not legal in the current position.")
print("Legal moves:", [move.uci() for move in board.legal_moves])

except ValueError:
print("Invalid move format! Please use UCI notation (e.g., e2e4, g1f3)")


def get_engine_move(engine, board, time_limit=1.0):
"""Get the best move from Stockfish."""
try:
result = engine.play(board, chess.engine.Limit(time=time_limit))
return result.move
except Exception as e:
print(f"Engine error: {e}")
return None


def main():
# Initialize chessboard and engine
board = chess.Board()

try:
# Initialize Stockfish engine
engine = chess.engine.SimpleEngine.popen_uci("stockfish-windows-x86-64-avx2") # Update path to Stockfish
print("Stockfish engine loaded successfully!")
except Exception as e:
print(f"Error loading Stockfish: {e}")
print("Make sure Stockfish is installed and in your PATH")
return

print("Welcome to Text-Based Chess vs Stockfish!")
print("Enter moves in UCI notation (e.g., e2e4 for pawn from e2 to e4)")
print("Type 'quit' at any time to exit the game")

# Ask who goes first
while True:
player_color = input("\nDo you want to play as White or Black? (w/b): ").strip().lower()
if player_color in ['w', 'white']:
player_is_white = True
break
elif player_color in ['b', 'black']:
player_is_white = False
break
else:
print("Please enter 'w' for White or 'b' for Black")

print_board(board)

# Main game loop
while not board.is_game_over():
if (board.turn == chess.WHITE and player_is_white) or (board.turn == chess.BLACK and not player_is_white):
# Player's turn
move = get_player_move(board)
if move is None: # Player chose to quit
print("Thanks for playing!")
break

board.push(move)
print(f"\nYou played: {move.uci()}")
print_board(board)

else:
# Engine's turn
print(f"\nStockfish is thinking...")
engine_move = get_engine_move(engine, board)

if engine_move is None:
print("Engine error occurred. Ending game.")
break

board.push(engine_move)
print(f"Stockfish played: {engine_move.uci()}")
print_board(board)

# Game over
if board.is_game_over():
print("\n" + "=" * 50)
print("GAME OVER!")
print("=" * 50)

result = board.result()
if result == "1-0":
print("White wins!")
elif result == "0-1":
print("Black wins!")
else:
print("It's a draw!")

# Show the reason for game over
if board.is_checkmate():
print("Checkmate!")
elif board.is_stalemate():
print("Stalemate!")
elif board.is_insufficient_material():
print("Insufficient material!")
elif board.is_seventyfive_moves():
print("75-move rule!")
elif board.is_fivefold_repetition():
print("Fivefold repetition!")

# Clean up
engine.quit()
print("Engine closed. Goodbye!")


if __name__ == "__main__":
main()


Speech Based Approach

1_KndD0pTUyTHI8p9-f_u_6g.png
Screenshot 2025-06-11 123941.png

Speech based approach would be a bit difficult since my pc doesn't meet the hardware requirements for training with only my voice. so instead we are gonna use pretrained model, in our case its whisper. one major issue that can occur as highlighted above can be that the system not only takes our input but also the surroundings one, so his approach my only work in clean and noiseless surroundings.


make sure to install whisper from web as well as in PyCharm.


To succeed in speech recognition we can follow these steps

  1. import whisper model along with other libraries
  2. download small model
  3. use it to identify our speech
  4. transcribe the speech and feed it to stockfish
  5. let the computer speak via speakers the move made by stockfish.


the code for the same is as follows -


**One major issue while writing the code is that vosk recognizes moves as e four not e4 and stockfish is unable to interpret what move this could be so it returns invalid move, in order to fix this issue parsing can be used -

declaring dictionaries for each word to numeric [ {"four": 4} ], defining strings to check if that's what vosk transcribed and converting them to move suitable for stockfish, using phonetic alphabetical letters such as ALPHA - "A", BRAVO - "B" [ the approach i have used ] etc.**



try:
import whisper
import sounddevice as sd
import numpy as np

WHISPER_AVAILABLE = True
print("OpenAI Whisper loaded successfully")
except ImportError as e:
print(f"Whisper import error: {e}")
print("Falling back to speech_recognition library")
import speech_recognition as sr

WHISPER_AVAILABLE = False
import pyttsx3
import chess
import chess.engine
import threading
import queue
import re
import tempfile
import wave
from typing import Optional


class VoiceChessBot:
def __init__(self, stockfish_path: str, whisper_model: str = "base"):
"""
Initialize the Voice Chess Bot with Whisper or fallback

Args:
stockfish_path: Path to stockfish executable
whisper_model: Whisper model size ("tiny", "base", "small", "medium", "large")
"""
# Initialize chess board
self.board = chess.Board()

# Initialize Stockfish engine
try:
self.engine = chess.engine.SimpleEngine.popen_uci(stockfish_path)
print("Stockfish engine initialized successfully")
except Exception as e:
print(f"Error initializing Stockfish: {e}")
raise

# Initialize speech recognition
if WHISPER_AVAILABLE:
try:
print(f"Loading Whisper model '{whisper_model}'... This may take a moment.")
self.whisper_model = whisper.load_model(whisper_model)
self.speech_method = "whisper"
print("Whisper speech recognition initialized successfully")
except Exception as e:
print(f"Error initializing Whisper: {e}")
print("Falling back to speech_recognition library")
self.speech_method = "sr"
self.recognizer = sr.Recognizer()
self.microphone = sr.Microphone()
else:
self.speech_method = "sr"
self.recognizer = sr.Recognizer()
self.microphone = sr.Microphone()
print("Using speech_recognition library")

# Initialize text-to-speech
self.tts_engine = pyttsx3.init()
self.tts_engine.setProperty('rate', 150) # Adjust speech rate

# Audio settings
self.sample_rate = 16000
self.channels = 1

# Control flags
self.listening = False
self.game_active = True

print("Voice Chess Bot initialized successfully!")
self.speak("Welcome to Voice Chess! I'm ready to play. You are white, make your first move.")

def speak(self, text: str):
"""Convert text to speech"""
print(f"Bot: {text}")
self.tts_engine.say(text)
self.tts_engine.runAndWait()

def record_audio(self, duration: int = 4) -> np.ndarray:
"""Record audio using sounddevice"""
print(f"Recording for {duration} seconds... Speak now!")
try:
audio = sd.rec(int(duration * self.sample_rate),
samplerate=self.sample_rate,
channels=self.channels,
dtype=np.float32)
sd.wait() # Wait until recording is finished
return audio.flatten()
except Exception as e:
print(f"Error recording audio: {e}")
return np.array([])

def transcribe_with_whisper(self, audio: np.ndarray) -> str:
"""Transcribe audio using Whisper"""
try:
if len(audio) == 0:
return ""

# Whisper expects audio in specific format
result = self.whisper_model.transcribe(audio, language="en")
text = result["text"].strip()
print(f"Whisper heard: '{text}'")
return text
except Exception as e:
print(f"Error transcribing audio: {e}")
return ""

def parse_move_from_speech(self, speech_text: str) -> Optional[str]:
"""
Parse chess move from speech text
Handles various speech formats like:
- "e two to e four" -> "e2e4"
- "e2 to e4" -> "e2e4"
- "knight f3" -> finds knight move to f3
- "castle kingside" -> "O-O"
- "castle queenside" -> "O-O-O"
"""
speech = speech_text.lower().strip()

if not speech:
return None

# Convert spoken numbers to digits
number_words = {
'one': '1', 'two': '2', 'three': '3', 'four': '4',
'five': '5', 'six': '6', 'seven': '7', 'eight': '8'
}

# Replace number words with digits
for word, digit in number_words.items():
speech = speech.replace(word, digit)

# Handle castling
if "castle" in speech or "castling" in speech:
if "kingside" in speech or "king side" in speech or "short" in speech:
if chess.Move.from_uci("e1g1") in self.board.legal_moves:
return "e1g1"
elif chess.Move.from_uci("e8g8") in self.board.legal_moves:
return "e8g8"
elif "queenside" in speech or "queen side" in speech or "long" in speech:
if chess.Move.from_uci("e1c1") in self.board.legal_moves:
return "e1c1"
elif chess.Move.from_uci("e8c8") in self.board.legal_moves:
return "e8c8"

# Handle standard algebraic notation spoken
# Look for patterns like "e2 to e4", "e2 e4", etc.
move_pattern = r'([a-h][1-8])\s*(?:to\s*)?([a-h][1-8])'
match = re.search(move_pattern, speech)

if match:
from_square = match.group(1)
to_square = match.group(2)
move_str = from_square + to_square

# Check if it's a valid move
try:
move = chess.Move.from_uci(move_str)
if move in self.board.legal_moves:
return move_str
except:
pass

# Handle piece moves like "knight f3", "bishop c4"
piece_names = {
'knight': chess.KNIGHT, 'horse': chess.KNIGHT,
'bishop': chess.BISHOP,
'rook': chess.ROOK, 'castle': chess.ROOK,
'queen': chess.QUEEN,
'king': chess.KING,
'pawn': chess.PAWN
}

for piece_name, piece_type in piece_names.items():
if piece_name in speech:
# Look for destination square
square_pattern = r'([a-h][1-8])'
squares = re.findall(square_pattern, speech)
if squares:
target_square = squares[-1] # Take the last square mentioned

# Find legal moves for this piece type to this square
for move in self.board.legal_moves:
piece = self.board.piece_at(move.from_square)
if (piece and piece.piece_type == piece_type and
chess.square_name(move.to_square) == target_square):
return str(move)

# Handle pawn moves like "pawn e4" (assuming from e2)
pawn_pattern = r'(?:pawn\s+)?([a-h])(?:\s+to\s+)?([a-h]?[1-8])'
match = re.search(pawn_pattern, speech)
if match:
file_or_square = match.group(1)
target = match.group(2) if match.group(2) else ""

# If target has both file and rank
if len(target) == 2:
target_square = target
else:
# Assume it's a file move (like "e4")
target_square = file_or_square + (target if target else "4")

# Find legal pawn move to this square
for move in self.board.legal_moves:
piece = self.board.piece_at(move.from_square)
if (piece and piece.piece_type == chess.PAWN and
chess.square_name(move.to_square) == target_square and
chess.square_name(move.from_square)[0] == file_or_square):
return str(move)

# Try to find any valid move that matches the speech
for move in self.board.legal_moves:
move_str = str(move)
# Check if the speech contains the move components
if all(part in speech.replace(" ", "") for part in [move_str[:2], move_str[2:4]]):
return move_str

return None

def get_stockfish_move(self) -> Optional[str]:
"""Get best move from Stockfish"""
try:
result = self.engine.play(self.board, chess.engine.Limit(time=1.5))
return str(result.move)
except Exception as e:
print(f"Error getting Stockfish move: {e}")
return None

def move_to_speech(self, move_str: str) -> str:
"""Convert move notation to natural speech"""
try:
move = chess.Move.from_uci(move_str)
except:
return f"I move {move_str}"

# Handle castling
if move_str in ["e1g1", "e8g8"]:
return "I castle kingside"
elif move_str in ["e1c1", "e8c8"]:
return "I castle queenside"

from_square = chess.square_name(move.from_square)
to_square = chess.square_name(move.to_square)

piece = self.board.piece_at(move.from_square)
if piece:
piece_name = {
chess.PAWN: "pawn",
chess.ROOK: "rook",
chess.KNIGHT: "knight",
chess.BISHOP: "bishop",
chess.QUEEN: "queen",
chess.KING: "king"
}.get(piece.piece_type, "piece")

# Check for captures
captured_piece = self.board.piece_at(move.to_square)
if captured_piece:
return f"I take with {piece_name} from {from_square} to {to_square}"
else:
return f"I move {piece_name} from {from_square} to {to_square}"

return f"I move from {from_square} to {to_square}"

def listen_for_move(self) -> Optional[str]:
"""Listen for user's move via Whisper speech recognition"""
max_attempts = 3

for attempt in range(max_attempts):
try:
print(f"\nListening for your move (attempt {attempt + 1}/{max_attempts})...")
self.speak("Your turn. Please say your move.")

# Record audio
audio = self.record_audio(duration=4)

if len(audio) == 0:
print("No audio recorded")
continue

# Transcribe with Whisper
text = self.transcribe_with_whisper(audio)

if text:
# Parse the move
move = self.parse_move_from_speech(text)
if move:
return move
else:
print(f"Could not parse move from: '{text}'")
if attempt < max_attempts - 1:
self.speak("I didn't understand that move. Please try again.")
else:
print("No speech detected")
if attempt < max_attempts - 1:
self.speak("I didn't hear anything. Please speak louder.")

except Exception as e:
print(f"Error in speech recognition: {e}")
if attempt < max_attempts - 1:
self.speak("There was an error. Let me try again.")

self.speak("I'm having trouble understanding. You can type your move if needed.")
return None

def display_board(self):
"""Display current board position"""
print("\nCurrent board position:")
print(self.board)
print()

def play_game(self):
"""Main game loop"""
try:
while self.game_active and not self.board.is_game_over():
self.display_board()

# Player's turn (White)
print("=" * 50)
user_move = self.listen_for_move()

if user_move:
try:
move = chess.Move.from_uci(user_move)
if move in self.board.legal_moves:
self.board.push(move)
move_desc = self.move_to_speech(user_move).replace("I move", "You moved").replace("I take",
"You took")
self.speak(move_desc)

# Check if game is over
if self.board.is_game_over():
break

# Bot's turn (Black)
print("Thinking...")
self.speak("Let me think...")
bot_move = self.get_stockfish_move()

if bot_move:
move_obj = chess.Move.from_uci(bot_move)
self.board.push(move_obj)

move_speech = self.move_to_speech(bot_move)
self.speak(move_speech)
else:
self.speak("I cannot find a move. Something went wrong.")
break
else:
self.speak("That's not a legal move. Please try again.")
except Exception as e:
print(f"Error processing move: {e}")
self.speak("I didn't understand that move. Please try again.")
else:
# Fallback to text input
try:
text_move = input("Enter your move (e.g., e2e4): ").strip()
if text_move:
move = chess.Move.from_uci(text_move)
if move in self.board.legal_moves:
self.board.push(move)
self.speak(f"You played {text_move}")

if not self.board.is_game_over():
bot_move = self.get_stockfish_move()
if bot_move:
move_obj = chess.Move.from_uci(bot_move)
self.board.push(move_obj)
move_speech = self.move_to_speech(bot_move)
self.speak(move_speech)
else:
print("Illegal move!")
except:
print("Invalid move format!")

# Game over
self.display_board()
result = self.board.result()

if result == "1-0":
self.speak("Congratulations! You won the game!")
elif result == "0-1":
self.speak("I won this game! Good game, well played!")
else:
self.speak("The game ended in a draw! Good game!")

except KeyboardInterrupt:
print("\nGame interrupted by user")
self.speak("Game ended. Thanks for playing!")

finally:
self.cleanup()

def cleanup(self):
"""Clean up resources"""
self.listening = False
self.game_active = False
if hasattr(self, 'engine'):
self.engine.quit()
print("Resources cleaned up")


def main():
# Configuration
STOCKFISH_PATH = "stockfish-windows-x86-64-avx2" # Your Stockfish location
WHISPER_MODEL = "base" # Options: "tiny", "base", "small", "medium", "large"

print("Voice Chess Bot with Whisper")
print("=" * 40)
print("Whisper Models available:")
print("- tiny: Fastest, least accurate")
print("- base: Good balance (recommended)")
print("- small: Better accuracy")
print("- medium: High accuracy, slower")
print("- large: Best accuracy, slowest")
print("=" * 40)

try:
# Create and start the chess bot
bot = VoiceChessBot(STOCKFISH_PATH, WHISPER_MODEL)
bot.play_game()

except Exception as e:
print(f"Error starting chess bot: {e}")
print("\nMake sure you have:")
print("1. Stockfish installed and path configured correctly")
print("2. Required Python packages installed:")
print(" pip install openai-whisper sounddevice pyttsx3 python-chess numpy")
print("3. A working microphone")


if __name__ == "__main__":
main()


For the above code to work there needs to be clear surroundings and good microphone. The above code uses whisper to recognize the move and works fine, but the main problem that arises is that the whisper model is not able to recognize the voice properly sometimes so the move needs to be clearly spoken.

Computer Vision Integration

Screenshot 2025-06-11 123335.png


Considering the third option -

"True chess mastery isn't just about making moves; it's about understanding your opponent and planning strategically—here, that means grasping the computer vision that allows the PC to interpret the game."
- ElectraFlame -


so saying that using computer vision to make your pc comprehend the game is like writing sorry in air (totally relatable)

no!! here comes the actual obstacle - using computer vision can help the pc to identify chessboard AS A WHOLE meaning it wont be able to grasp the moves happening.....due to it treating the board as one whole object.


The best approach i can take -

  1. get the computer to identify individual chess pieces.
  2. get the computer to identify the board's corners
  3. make the computer divide the board into 64 boxes
  4. Determine the current board state
  5. Identify what move was made by your opponent
  6. get our special guest to generate counter move


Again, we cant just turn my potato pc into a fried one by training with yolov5. so we'll use roboflow to definitely NOT FORK datasets!! Choose the dataset that is suitable for your chessboard and verify it's pieces and check if they match yours. now that we have the dataset, upload your own images to roboflow and train it based on various features roboflow provides.


with the training complete lets move onto letting the pc divide our board into 64 pieces. This step shall set us into coding computer vision part.


WARNING - my pc has camera issues unable to detect things but works well in other device, but the problem is that the filming of the demonstration is done on the device with camera issues.


now lets begin with coding -


import cv2
import numpy as np
import chess
import chess.engine
import requests
import json
import time
from typing import Optional, Tuple, List
import base64

class ChessBot:
def __init__(self, roboflow_api_key: str, roboflow_model_url: str, stockfish_path: str = None):
"""
Initialize the chess bot

Args:
roboflow_api_key: Your Roboflow API key
roboflow_model_url: Your deployed Roboflow model URL
stockfish_path: Path to Stockfish engine (None for online engine)
"""
self.api_key = roboflow_api_key
self.model_url = roboflow_model_url
self.board = chess.Board()
self.engine = None
self.cap = None
self.previous_board_state = None

# Initialize Stockfish
if stockfish_path:
try:
self.engine = chess.engine.SimpleEngine.popen_uci(stockfish_path)
except:
print("Failed to initialize local Stockfish, using online API")
self.engine = None

print("Chess Bot initialized!")
print(f"Current board:\n{self.board}")

def initialize_camera(self, camera_index: int = 0) -> bool:
"""Initialize camera capture"""
try:
self.cap = cv2.VideoCapture(camera_index)
if not self.cap.isOpened():
print("Error: Could not open camera")
return False

# Set camera properties for better quality
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
self.cap.set(cv2.CAP_PROP_FPS, 30)

print("Camera initialized successfully")
return True
except Exception as e:
print(f"Error initializing camera: {e}")
return False

def capture_board_image(self) -> Optional[np.ndarray]:
"""Capture current board image from camera"""
if not self.cap:
print("Camera not initialized")
return None

ret, frame = self.cap.read()
if not ret:
print("Failed to capture frame")
return None

return frame

def detect_pieces_roboflow(self, image: np.ndarray) -> Optional[dict]:
"""
Send image to Roboflow API for piece detection

Args:
image: OpenCV image (BGR format)

Returns:
Dictionary with detection results
"""
try:
# Convert BGR to RGB
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

# Encode image to base64
_, buffer = cv2.imencode('.jpg', image_rgb)
img_base64 = base64.b64encode(buffer).decode('utf-8')

# Prepare the request
headers = {
'Content-Type': 'application/json',
}

data = {
'api_key': self.api_key,
'image': img_base64
}

# Make request to Roboflow
response = requests.post(self.model_url, json=data, headers=headers)

if response.status_code == 200:
return response.json()
else:
print(f"Roboflow API error: {response.status_code}")
print(response.text)
return None

except Exception as e:
print(f"Error in Roboflow detection: {e}")
return None

def parse_board_from_detections(self, detections: dict) -> Optional[List[List[str]]]:
"""
Parse the board state from Roboflow detections

Args:
detections: Roboflow API response

Returns:
8x8 board representation as list of lists
"""
try:
# Initialize empty board
board_state = [['.' for _ in range(8)] for _ in range(8)]

if 'predictions' not in detections:
return board_state

# Process each detection
for detection in detections['predictions']:
piece_class = detection['class']
confidence = detection['confidence']

# Only consider high-confidence detections
if confidence < 0.5:
continue

# Get bounding box center
x_center = detection['x']
y_center = detection['y']

# Convert pixel coordinates to board coordinates (0-7)
# This assumes your camera captures the full board
# You may need to adjust these calculations based on your setup
board_x = int((x_center / detections['image']['width']) * 8)
board_y = int((y_center / detections['image']['height']) * 8)

# Ensure coordinates are within bounds
board_x = max(0, min(7, board_x))
board_y = max(0, min(7, board_y))

# Map piece class to chess notation
piece_symbol = self.map_piece_class_to_symbol(piece_class)
board_state[board_y][board_x] = piece_symbol

return board_state

except Exception as e:
print(f"Error parsing board state: {e}")
return None

def map_piece_class_to_symbol(self, piece_class: str) -> str:
"""
Map Roboflow piece class to chess piece symbol
Adjust this mapping based on your model's classes
"""
mapping = {
'white_pawn': 'P', 'black_pawn': 'p',
'white_rook': 'R', 'black_rook': 'r',
'white_knight': 'N', 'black_knight': 'n',
'white_bishop': 'B', 'black_bishop': 'b',
'white_queen': 'Q', 'black_queen': 'q',
'white_king': 'K', 'black_king': 'k',
# Add more mappings based on your model
}
return mapping.get(piece_class, '.')

def detect_move_from_board_states(self, previous_state: List[List[str]],
current_state: List[List[str]]) -> Optional[str]:
"""
Detect the move made by comparing board states

Returns:
Move in UCI format (e.g., 'e2e4') or None
"""
try:
changes = []

for row in range(8):
for col in range(8):
if previous_state[row][col] != current_state[row][col]:
square = chr(ord('a') + col) + str(8 - row) # Convert to chess notation
changes.append({
'square': square,
'from_piece': previous_state[row][col],
'to_piece': current_state[row][col]
})

# Analyze changes to determine move
if len(changes) == 2:
# Normal move: one square emptied, one square filled
from_square = None
to_square = None

for change in changes:
if change['from_piece'] != '.' and change['to_piece'] == '.':
from_square = change['square']
elif change['from_piece'] == '.' and change['to_piece'] != '.':
to_square = change['square']

if from_square and to_square:
return from_square + to_square

# Handle castling and other special moves here if needed

return None

except Exception as e:
print(f"Error detecting move: {e}")
return None

def get_stockfish_move(self, move_uci: str = None) -> Optional[str]:
"""
Get best move from Stockfish

Args:
move_uci: The opponent's move in UCI format

Returns:
Best move in UCI format
"""
try:
# Apply opponent's move if provided
if move_uci:
move = chess.Move.from_uci(move_uci)
if move in self.board.legal_moves:
self.board.push(move)
print(f"Opponent played: {move_uci}")
else:
print(f"Invalid move detected: {move_uci}")
return None

if self.engine:
# Use local Stockfish engine
result = self.engine.play(self.board, chess.engine.Limit(time=2.0))
best_move = str(result.move)
else:
# Use online Stockfish API (alternative)
best_move = self.get_online_stockfish_move()

if best_move:
# Apply our move to the board
move = chess.Move.from_uci(best_move)
self.board.push(move)
print(f"Stockfish suggests: {best_move}")
return best_move

return None

except Exception as e:
print(f"Error getting Stockfish move: {e}")
return None

def get_online_stockfish_move(self) -> Optional[str]:
"""
Get move from online Stockfish API (backup method)
"""
try:
# Using lichess API as example
url = "https://lichess.org/api/cloud-eval"
params = {
'fen': self.board.fen(),
'multiPv': 1,
'variant': 'standard'
}

response = requests.get(url, params=params)
if response.status_code == 200:
data = response.json()
if 'pvs' in data and len(data['pvs']) > 0:
moves = data['pvs'][0]['moves'].split()
if moves:
return moves[0]

return None

except Exception as e:
print(f"Error with online Stockfish: {e}")
return None

def display_move_on_image(self, image: np.ndarray, move: str) -> np.ndarray:
"""
Display the suggested move on the camera image
"""
if not move or len(move) < 4:
return image

try:
from_square = move[:2]
to_square = move[2:4]

# Add text overlay
font = cv2.FONT_HERSHEY_SIMPLEX
text = f"Play: {from_square} -> {to_square}"
cv2.putText(image, text, (10, 30), font, 1, (0, 255, 0), 2)

# You can add arrows or highlights here
# This would require mapping chess coordinates to pixel coordinates

except Exception as e:
print(f"Error displaying move: {e}")

return image

def run(self):
"""
Main loop for the chess bot
"""
if not self.initialize_camera():
return

print("Chess bot is running!")
print("Press 'q' to quit, 'r' to reset board, 'c' to capture current state")

current_board_state = None
waiting_for_opponent = True

while True:
# Capture frame
frame = self.capture_board_image()
if frame is None:
continue

# Detect pieces using Roboflow
detections = self.detect_pieces_roboflow(frame)
if detections:
current_board_state = self.parse_board_from_detections(detections)

# Check if opponent made a move
if self.previous_board_state and current_board_state and waiting_for_opponent:
detected_move = self.detect_move_from_board_states(
self.previous_board_state, current_board_state
)

if detected_move:
print(f"Detected move: {detected_move}")

# Get Stockfish response
our_move = self.get_stockfish_move(detected_move)
if our_move:
frame = self.display_move_on_image(frame, our_move)
waiting_for_opponent = False

# Update previous state
self.previous_board_state = current_board_state.copy()

# Display the frame
cv2.imshow('Chess Bot', frame)

# Handle key presses
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
elif key == ord('r'):
self.board = chess.Board()
self.previous_board_state = None
waiting_for_opponent = True
print("Board reset!")
elif key == ord('c'):
if current_board_state:
self.previous_board_state = current_board_state.copy()
waiting_for_opponent = True
print("Current state captured!")
elif key == ord(' '): # Spacebar to acknowledge our move
waiting_for_opponent = True
print("Waiting for opponent's move...")

# Cleanup
self.cleanup()

def cleanup(self):
"""Cleanup resources"""
if self.cap:
self.cap.release()
if self.engine:
self.engine.quit()
cv2.destroyAllWindows()
print("Chess bot stopped.")

# Usage example
if __name__ == "__main__":
# Configuration
ROBOFLOW_API_KEY = "YOUR_ROBOFLOW_API_KEY" # Replace with your API key
ROBOFLOW_MODEL_URL = "YOUR_ROBOFLOW_MODEL_URL" # Replace with your model URL
STOCKFISH_PATH = "stockfish" # Path to Stockfish executable or None for online

# Create and run the chess bot
bot = ChessBot(
roboflow_api_key=ROBOFLOW_API_KEY,
roboflow_model_url=ROBOFLOW_MODEL_URL,
stockfish_path=STOCKFISH_PATH
)

bot.run()

Making an App - WINDOWS

EHHH....we can use two ways, use python [ tkinter, customtkinter, kivymd, kivy ] or html [ reactjs ]

im gonna go for html approach using flask

lets plan making the app first -

  1. integrate all three features into a app
  2. make it interactive
  3. idk

by planning the app i mean the layout, its up to you... i made it basic and animated, so its your choice in making it.

we are gonna make a website that contains all these features, so for that we shall develop a UI a simple one not to complex, yet functional


we shall use flask to deploy our website locally....


folder structure -


alpha_chess_flask/

├── app.py

|----- stockfish.exe

├── static/

│ ├── style.css

│ └── script.js

└── templates/

└── index.html



But remember to use ur roboflow model api, project id, version. and stockfish location


since we have such a setup, it is now far easier for us to integrate our 3 versions to js.

we can start taking help of personal ai tools you like according to your choices to convert the python code into a js one.


FLASK comes in handy when we need to import models like stockfish, whisper etc. we import these in main.py define functions that handle input and output i the main.py itself and update js to link it to our main.py.


Deploy the App

Screenshot 2025-06-26 154030.png

To deploy our app, we shall use PYTHONANYWHERE as a web hosting service

first we upload all our files into a repository and navigate to pages tab, we enable a hosting service and then done!! or website is deployed into the url.


Making the Hardware Part

Well since this instructables shall become too long, and I am currently developing the hardware, so we are just gonna be discussing the plans for doing so.


BUT DONT WORRY I SHALL BE MAKING A SECOND INSTRUCTABLES FOR THE SAME


We have the software, what does the hardware require? a proper way to conceal our project. to achieve such a task, we shall discuss three options -

  1. using a cap we hide the whole circuit and everything and place the camera on the side
  2. making a specs - we make a specs which displays the move in oled in front - INSPIRED FROM DARKFLAME must see his projects too - DarkFLAME do check our collaborated account - Binary_Flame.....
  3. using Ear Pods - to speak our moves and transmit opponent moves to ears


Stay tuned for part 2 THANK your for viewing this instructable... hope u enjoyed!

Files