Infineon TeamMaysa Ouaja
Published © MIT

Chess Comes Alive: The Magic of Automation

Play magic chess against the computer on a real chessboard, everything built from scratch and documented step-by-step!

ExpertFull instructions provided24 hours1,711

Things used in this project

Hardware components

KIT XMC47 RELAX LITE V1
Infineon KIT XMC47 RELAX LITE V1
×1
KIT XMC1300 IFX9201 Stepper Shield
Infineon KIT XMC1300 IFX9201 Stepper Shield
×2
S2GO HALL TLE4964-3M
Infineon S2GO HALL TLE4964-3M
×4
Raspberry Pi 3 Model B
Raspberry Pi 3 Model B
×1
WS2812B Digital RGB LED Flexi-Strip 144 LED - 1 Meter
Seeed Studio WS2812B Digital RGB LED Flexi-Strip 144 LED - 1 Meter
×1
Grove - Electromagnet
Seeed Studio Grove - Electromagnet
×1
Stepper Motor
×2
Bench Power Supply, Linear DC
Bench Power Supply, Linear DC
×1

Software apps and online services

Arduino IDE
Arduino IDE
Raspbian
Raspberry Pi Raspbian
Stockfish Library

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Wood panels
Steel linear axis
Timing belts

Story

Read more

Custom parts and enclosures

Chess pieces

API Request

X-AXE

Sketchfab still processing.

Joint/Leg

Sketchfab still processing.

Chess Numbers

Sketchfab still processing.

Chess Letters

Sketchfab still processing.

Sliding Box for Hardware

Sketchfab still processing.

Ches Squares 20x20

Sketchfab still processing.

Trolley

Sketchfab still processing.

Schematics

Chess Schematics

Code

Arduino code

C/C++
#include <IFX9201_XMC1300_StepperMotor.h>
#include <Wire.h>
#include "LEDs.hpp"
#define Hall_switch_pin_X_left 0
#define Hall_switch_pin_Y_bottom 1
#define Hall_switch_pin_X_right 2 // Pin connected to Hall switch for X-axis
#define Hall_switch_pin_Y_top 3 // Pin connected to Hall switch for Y-axis
// Define pins for Motor 1 (X-axis)
#define DIR_PIN_1 6   // Pin connected to DIR of first motor
#define STP_PIN_1 12  // Pin connected to STP of first motor
#define DIS_PIN_1 5   // Pin connected to DIS of first motor
#define POS_0_X_define 100 //liegt untera1
#define POS_0_Y_define 100


// Define pins for Motor 2 (Y-axis)
#define DIR_PIN_2 IFX9201_STEPPERMOTOR_STD_DIR // Custom pin for second motor DIR
#define STP_PIN_2 IFX9201_STEPPERMOTOR_STD_STP // Custom pin for second motor STP
#define DIS_PIN_2 IFX9201_STEPPERMOTOR_STD_DIS // Custom pin for second motor DIS

#define SLAVE_ADDRESS 0x08



// Define pin for Electromagnet
#define ELECTROMAGNET_PIN 8 // Pin connected to electromagnet control circuit
bool newDataAvailable = false;
bool magnet_active = true;

// Define steps per revolution and square
const int stepsPerRevolution = 200; // Steps for a full revolution (adjust if necessary)
const int stepsPerSquare = 225;     // Steps needed to move one chess square (5 cm)


// Create stepper motor objects
Stepper_motor motor1(stepsPerRevolution, DIR_PIN_1, STP_PIN_1, DIS_PIN_1); // X-axis motor
Stepper_motor motor2(stepsPerRevolution, DIR_PIN_2, STP_PIN_2, DIS_PIN_2); // Y-axis motor
bool x_read=false;
bool motor_moving=false;
int value=LOW;
int curValue = value;

char receivedP1[3]={0,0,0};
char receivedP2[3]={0,0,0};

void moveMotor(Stepper_motor& motor, int steps) {
  for(int i = 0; i < abs(steps); i++) {
    if (!isSafeToMove()) {
      Serial.println("Safety stop: Hall switch triggered");
      break;
    }
    if (steps > 0) {
      motor.step(1); // Move forward
    } else {
      motor.step(-1); // Move backward
    }
  }
}



void init_pos()
{
  do
  {
  curValue = digitalRead(Hall_switch_pin_X_left);   
    if(curValue  != value)
    {
        value = curValue;
        if(value == LOW)
        {
            digitalWrite(LED_BUILTIN, HIGH);
        }
        else if(value == HIGH)
        {
            digitalWrite(LED_BUILTIN, LOW);
            
        }
    }
    motor1.step(-1);
  }
  while(value == HIGH);


  do
  {
  curValue = digitalRead(Hall_switch_pin_Y_bottom);   
    if(curValue  != value)
    {
        value = curValue;
        if(value == LOW)
        {
            digitalWrite(LED_BUILTIN, HIGH);
        }
        else if(value == HIGH)
        {
            digitalWrite(LED_BUILTIN, LOW);
            
        }
    }
    motor2.step(-1);
  }
  while(value == HIGH);
      
      
      
  motor1.step(POS_0_X_define);
  motor2.step(POS_0_Y_define+300);
  
  Serial.println("Motors initialized to zero position.");     
}
void setup() {
  
  Wire.begin(SLAVE_ADDRESS);

  Wire.onRequest(sendData);
  Wire.onReceive(receiveData);
  motor1.begin();
  motor2.begin();
  motor1.setSpeed(60); // Set motor1 speed in RPM
  motor2.setSpeed(60); // Set motor2 speed in RPM
  pixels.begin();
  pixels.clear();
  pixels.show();
// Initialize the motors and electromagnet


  pinMode(ELECTROMAGNET_PIN, OUTPUT);     // Set electromagnet pin as output
  digitalWrite(ELECTROMAGNET_PIN, LOW);  // Ensure the electromagnet is OFF initially


  // Initialize the serial port for debugging
  Serial.begin(9600);
  delay(6000);
  
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.println("LED1 Initialized");
    
  pinMode(Hall_switch_pin_X_left, INPUT_PULLUP);
  pinMode(Hall_switch_pin_Y_bottom, INPUT_PULLUP);
  Serial.println("Output Pin Initialized");
  Serial.println();

  init_pos(); // Initialize motors to zero position
}

int x=0;
int y=0;
bool move_pending = false; // New flag to trigger movement

void processMove() {
  // Only process if move_pending is true
  if (!move_pending) return;
  //motor_moving = true;
  move_pending = false;
  Serial.print("Received X = ");
  Serial.print(x);
  Serial.print(" , Received y = ");
  Serial.println(y);
  Serial.print("Motor moving: ");
  Serial.println(motor_moving);
  // Diagonal movement
  if(abs(x)==abs(y)){
    if(magnet_active==true)
    {
      activateElectromagnet();
    }
    motor_moving = true;
    Serial.println("Moving diagonally");
    moveDiagonal(x*stepsPerSquare, y*stepsPerSquare);
    motor_moving = false;
    deactivateElectromagnet();
  }
  else if(x == 0 && y != 0){ //Vertical Movement
    if(magnet_active==true)
    {
      activateElectromagnet();
    }
    
    motor_moving = true;
    moveMotor(motor2,y*stepsPerSquare);
    motor_moving = false;
    deactivateElectromagnet();
  }
  else if(x != 0 && y == 0){ //horizontal Movement
    if(magnet_active==true)
    {
      activateElectromagnet();
    }
    motor_moving = true;
    moveMotor(motor1,x*stepsPerSquare);
    motor_moving = false;
    deactivateElectromagnet();
  }
  // Knight's L-shaped movement
  else if ((abs(x) == 2 && abs(y) == 1) || (abs(x) == 1 && abs(y) == 2)) {
    if(magnet_active==true)
    {
      activateElectromagnet();
    }
    motor_moving = true;
    Serial.println("Performing knight move");
    moveKnight(x,y);
    motor_moving = false;
    deactivateElectromagnet();

  }
  else {
    // Für alle anderen Kombinationen: erst X, dann Y bewegen
    Serial.println("Ungültige Kombination, führe X- und dann Y-Bewegung aus.");
    //activateElectromagnet();
    motor_moving = true;
    if (x != 0) moveMotor(motor1, x*stepsPerSquare);
    if (y != 0) moveMotor(motor2, y*stepsPerSquare);
    motor_moving = false;
  }
  //activateElectromagnet(); // Turn ON the electromagnet
}

void loop() {
  //activateElectromagnet();

  // --- Serielle Befehle auswerten ---
  // (Serielle Steuerung entfernt, nur noch I2C)

  if(newDataAvailable)
  { 
   Serial.print("Empfangen (");
    Serial.print(" Bytes): x=");
    Serial.print(x);
    Serial.print(", y=");
    Serial.print(y);
    Serial.print(", a1=");
    Serial.print(receivedP1);
    Serial.print(", b2=");
    Serial.println(receivedP2);
    
     int squareIndex = -1;
    String test=receivedP1;
    for (int i = 0; i < NUMSQUARES; i++) {
      if (test.equalsIgnoreCase(squareNames[i])) {
        squareIndex = i;
        break;
      }
    }


    if (squareIndex != -1) {
      pixels.clear();
      bool dim = isDimSquare(squareNames[squareIndex]);
      for (int i = 0; i < 4; i++) {
        if (squareLEDs[squareIndex][i] != 0) {
          if (dim) {
            pixels.setPixelColor(squareLEDs[squareIndex][i] - 1, pixels.Color(0, 20, 0)); // Dim green
          } else {
            pixels.setPixelColor(squareLEDs[squareIndex][i] - 1, pixels.Color(0, 225, 0)); // Bright green
          }
        }
      }
      test=receivedP2;
     for (int i = 0; i < NUMSQUARES; i++) {
      if (test.equalsIgnoreCase(squareNames[i])) {
        Serial.println(i);
        squareIndex = i;
        break;
      }
    }

    if (squareIndex != -1) {
      pixels.clear();
      bool dim = isDimSquare(squareNames[squareIndex]);
      for (int i = 0; i < 4; i++) {
        if (squareLEDs[squareIndex][i] != 0) {
          if (dim) {
            pixels.setPixelColor(squareLEDs[squareIndex][i] - 1, pixels.Color(0, 20, 0)); // Dim green
          } else {
            pixels.setPixelColor(squareLEDs[squareIndex][i] - 1, pixels.Color(0, 225, 0)); // Bright green
          }
        }
      }
      pixels.show();
    } else {
      Serial.println("Invalid square name. Please enter a valid name like a1, b2, h8.");
    }

    newDataAvailable = false;
    move_pending=true;
    processMove();
    motor_moving = false;
  
  }
 // Serial.println("Hier");
}
}

// Safety function: checks if it's safe to move in the given direction
// xDir: -1 for left, 1 for right, 0 for no X movement
// yDir: -1 for down, 1 for up, 0 for no Y movement
bool isSafeToMove() {
  // Read Hall switch states
  int xLeft = digitalRead(Hall_switch_pin_X_left);
  int xRight = digitalRead(Hall_switch_pin_X_right);
  int yBottom = digitalRead(Hall_switch_pin_Y_bottom);
  int yTop = digitalRead(Hall_switch_pin_Y_top);

  // If moving left and left switch is triggered, not safe
  if (xLeft == LOW) 
  {
    motor1.step(POS_0_X_define);
    return false;
  }
  // If moving right and right switch is triggered, not safe
  if (xRight == LOW) 
  {
    motor1.step(-POS_0_X_define);
    return false;
  }
  // If moving down and bottom switch is triggered, not safe
  if (yBottom == LOW)
  {
    motor2.step(POS_0_X_define);
    return false;
  } 
  // If moving up and top switch is triggered, not safe
  if (yTop == LOW) 
  {
  motor2.step(-POS_0_X_define);
  return false;
  }
  return true;
}

///////////////////////////////////////
// Custom Movement Functions
///////////////////////////////////////


// Function to activate the electromagnet
void activateElectromagnet() {
  digitalWrite(ELECTROMAGNET_PIN, HIGH); // Turn ON the electromagnet
 //Serial.println("Electromagnet activated");
}

void deactivateElectromagnet() {
  digitalWrite(ELECTROMAGNET_PIN, LOW); // Turn ON the electromagnet
 //Serial.println("Electromagnet activated");
}


// Function to deactivate the electromagnet
//
// Function to move a motor a specified number of steps



// Function to move diagonally
void moveDiagonal(int x, int y) {
  int xDir = (x > 0) ? 1 : -1;
  int yDir = (y > 0) ? 1 : -1;
  for(int i = 0; i < abs(x); i++){
    if (!isSafeToMove()) {
      Serial.println("Safety stop: Hall switch triggered (diagonal)");
      break;
    }
    if(x > 0 && y > 0){
      motor1.step(1); // Positive X-axis
      motor2.step(1); // Positive Y-axis
    }
    else if(x > 0 && y < 0){
      motor1.step(1); // Positive X-axis
      motor2.step(-1); // Negative Y-axis
    }
    else if(x < 0 && y > 0){
      motor1.step(-1); // Negative X-axis
      motor2.step(1); // Positive Y-axis
    }
    else{
      motor1.step(-1); // Negative X-axis
      motor2.step(-1); // Negative Y-axis
    }
  }
}


// Function to perform a knight's L-shaped move in two segments: half square, then 1.5 squares
void moveKnight(int x, int y) {
  // Determine which axis is "2" and which is "1"
  int dirX = (x > 0) ? 1 : -1;
  int dirY = (y > 0) ? 1 : -1;

  if (abs(x) == 1 && abs(y) == 2) {
    // Move half square along X, then 1.5 squares along Y, then the rest along X
    motor1.step(dirX * stepsPerSquare / 2);         // Half square X
    motor2.step(dirY * stepsPerSquare * 1.5);       // 1.5 squares Y
    motor1.step(dirX * stepsPerSquare /2);       // Remaining X
    motor2.step(dirY * stepsPerSquare /2);       // Remaining Y


    } else if (abs(x) == 2 && abs(y) == 1) {
    // Move half square along Y, then 1.5 squares along X, then the rest along Y
    motor2.step(dirY * stepsPerSquare / 2);         // Half square Y
    motor1.step(dirX * stepsPerSquare * 1.5);       // 1.5 squares X
    motor2.step(dirY * stepsPerSquare/2);       // Remaining Y
    motor1.step(dirX * stepsPerSquare/2);       // Remaining X
  }
  motor_moving = false;
  Serial.println("Knight move complete");
}


void receiveData(int bytecount)
{

  if (Wire.available() >= 7) { // 1 Command + 6 Daten
    Wire.read(); // Command ignorieren
    x =(int8_t)Wire.read();
    y =(int8_t)Wire.read();
    
    receivedP1[0] = (char)Wire.read();  //a
    receivedP1[1] = (char)Wire.read();   //2
    receivedP1[2] = '\0';
    receivedP2[0] = (char)Wire.read(); //a
    receivedP2[1] = (char)Wire.read();  //4
    receivedP2[2] = '\0';
    motor_moving = true;
    newDataAvailable = true;
    magnet_active= !magnet_active;
    digitalWrite(22, HIGH);
  }
}

void sendData()
{   

  Wire.write(motor_moving);
  
}

LED code

C/C++
#include <LED.h>
#include <Adafruit_NeoPixel.h>

#define PIN    7  
#define NUMPIXELS 390  // Total number of LEDs
#define NUMSQUARES 64
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
int squareLEDs[NUMSQUARES][4] = {
  {310, 311, 351, 350}, // a1
  {266, 267, 306, 307}, // a2
  {222, 223, 263, 262}, // a3
  {179, 178, 218, 219}, // a4
  {134, 135, 175, 174}, // a5
  {90, 91, 130, 131},   // a6
  {46, 47, 87, 86},     // a7
  {2, 3, 42, 43},       // a8

  {313, 314, 348, 347}, // b1
  {269, 270, 303, 304}, // b2
  {225, 226, 260, 259}, // b3
  {182, 181, 215, 216}, // b4
  {138, 137, 172, 171}, // b5
  {94, 93, 128, 127},   // b6
  {50, 49, 83, 84},     // b7
  {5, 6, 40, 39},       // b8

  {316, 315, 345, 346}, // c1
  {271, 272, 302, 301}, // c2
  {227, 228, 257, 258}, // c3
  {184, 183, 213, 214}, // c4
  {140, 139, 170, 169}, // c5
  {95, 96, 126, 125},   // c6
  {51, 52, 82, 81},     // c7
  {7, 8, 38, 37},       // c8

  {318, 343, 319, 342}, // d1
  {274, 299, 275, 298}, // d2
  {231, 254, 230, 255}, // d3
  {186, 187, 210, 211}, // d4
  {143, 142, 167, 166}, // d5
  {99, 98, 123, 122},   // d6
  {55, 54, 78, 79},     // d7
  {11, 10, 34, 35},     // d8

  {320, 321, 341, 340}, // e1
  {276, 277, 297, 296}, // e2
  {233, 252, 232, 253}, // e3
  {189, 188, 209, 208}, // e4
  {144, 145, 164, 165}, // e5
  {100, 101, 120, 121}, // e6
  {57, 56, 77, 76},     // e7
  {12, 13, 32, 33},     // e8

  {323, 324, 337, 338}, // f1
  {279, 280, 293, 294}, // f2
  {235, 236, 250, 249}, // f3
  {192, 191, 205, 206}, // f4
  {147, 148, 162, 161}, // f5
  {104, 103, 117, 118}, // f6
  {60, 59, 73, 74},     // f7
  {16, 15, 30, 29},     // f8

  {325, 326, 335, 336}, // g1
  {282, 281, 291, 292}, // g2
  {239, 238, 247, 246}, // g3
  {194, 193, 203, 204}, // g4
  {149, 150, 160, 159}, // g5
  {105, 106, 116, 115}, // g6
  {63, 62, 70, 71},     // g7
  {19, 18, 26, 27},     // g8

  {328, 329, 332, 333}, // h1
  {285, 288, 284, 289}, // h2
  {241, 240, 244, 245}, // h3
  {197, 196, 201, 200}, // h4
  {153, 152, 156, 157}, // h5
  {108, 109, 112, 113}, // h6
  {65, 64, 68, 69},     // h7
  {20, 21, 25, 24},     // h8
};

const char* squareNames[NUMSQUARES] = {
  "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8",
  "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8",
  "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8",
  "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8",
  "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8",
  "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8",
  "g1", "g2", "g3", "g4", "g5", "g6", "g7", "g8",
  "h1", "h2", "h3", "h4","h5","h6","h7","h8"
};


// Squares with lower brightness
const char* dimSquares[] = {"a2", "a4", "a6", "a8", "b1", "b3", "b5", "b7","c2","c4","c6","c8","d1","d3","d5","d7","e2","e4","e6","e8","f1","f3","f5","f7","g2","g4","g6","g8","h1","h3","h5","h7"};
const int numDimSquares = sizeof(dimSquares) / sizeof(dimSquares[0]);

// Function to check if a square is in the dimmed list
bool isDimSquare(const char* square) {
  for (int i = 0; i < numDimSquares; i++) {
    if (strcasecmp(square, dimSquares[i]) == 0) { // Case-insensitive comparison
      return true;
    }
  }
  return false;
}

api_requests.py

Python
import requests

"""
url = "http://127.0.0.1:8000/moves/?move=d1h6"

response = requests.post(url)

print(response.json())
"""
 

url = "http://127.0.0.1:8000/moves/"

response = (requests.get(url)).json()

print(response[len(response)-1])

i2c_master.py

Python
from smbus import SMBus
import time
import struct
addr = 0x08
bus = SMBus(1)
motor_moving = 0
counter = 0

def send_i2c(x, y, a1, b2):
    if len(a1) != 2 or len(b2) != 2:
        print("Strings mssen je 2 Zeichen lang sein!")
        return
    # x und y als signed Byte, Strings als ASCII
    data = [
        x & 0xFF if x < 0 else x,  # x als Byte ok passt
        y & 0xFF if y < 0 else y,  # y als Byte ok passt
        ord(a1[0]), ord(a1[1]),
        ord(b2[0]), ord(b2[1])
    ]
    try:
        bus.write_i2c_block_data(addr, 0, data)
        print(f"Gesendet: x={x}, y={y}, a1={a1}, b2={b2}")
    except Exception as e:
        print(f"Fehler beim Senden: {e}")
    
def receive_i2c():
    data = bus.read_byte(addr)
    print(f"Received data: {data}")
    return data  # Return the received byte directly
    
    
"""
motor_moving = receive_i2c()
send_i2c(0,-1)

while(receive_i2c()):  # Wait until the motor is not moving
    print("Motor is moving, waiting...")

#send_i2c(0,2)
motor_moving = receive_i2c()
print(f"Motor moving: {motor_moving}")
time.sleep(3)  # Wait for a short time before sending the next command
motor_moving = receive_i2c()
print(f"Motor moving: {motor_moving}")

"""

main.py

Python
from fastapi import FastAPI

app = FastAPI()
moves = []

@app.post("/moves/")
async def create_move(move : str):
    moves.append(move)
    return move

@app.get("/moves/")
async def read_moves():
    return moves

@app.get("/moves/{move_id}")
async def read_move(move_id : int):
    return moves[move_id]

wizard_chess.py

Python
You can start this project by typing in "python wizard_chess.py".
import chess
from stockfish import Stockfish
from i2c_master import *

time.sleep(2)

#Initialization
board = chess.Board()
stock = Stockfish(path="/bin/stockfish",depth=18, parameters={"Threads": 2, "Minimum Thinking Time": 5})
stock.set_depth(20)
stock.set_skill_level(1)

#Global Variables
checkmate = board.is_checkmate()
motor_location = "a1" #Motor location variable, e.g. "e4" for the center of the board
to_src_move = "a1"
to_dest_move = "a1"

#Docking Station Location Variables
sq_to_docking = 2 #Go to original location of piece in reset, then move back by INT squares
in_capture = False #True: Capture logic, False: Normal move logic

pawn_rl_counter_w = "a" #Pawn right-left counter-White
pawn_rl_counter_b = "a" #Pawn right-left counter-Black

rook_left_empty_w = True #True: Left position to be filled, False: Right position to be filled-White
knight_left_empty_w = True #True: Left position to be filled, False: Right position to be filled-White
bishop_left_empty_w = True #True: Left position to be filled, False: Right position to be filled-White

rook_left_empty_b = True #True:True: Left position to be filled, False: Right position to be filled-Black
knight_left_empty_b = True #True Left position to be filled, False: Right position to be filled-Black
bishop_left_empty_b = True #True: Left position to be filled, False: Right position to be filled-Black

# Zhler fr weie und schwarze Docking-Pltze
docking_counter_w = 0
docking_counter_b = 0

#Functions
  
def motor_to_src(move):
    global to_src_move, motor_location
    to_src_move = motor_location + (move[0]+ move[1])
    print(f"[Motor] Motor last location: {motor_location}")
    motor_location = (move[0]+ move[1])
    print(f"[Motor] Moving to source: {to_src_move}")

def src_to_dest(move):
    global to_dest_move, motor_location
    to_dest_move = motor_location + (move[2]+move[3])
    motor_location = (move[2]+move[3])
    print(f"[Motor] Moving source to destination: {to_dest_move}")


def execute_move(move, turn):
    x , y = calculate_squares(move)
    global in_capture
    if(in_capture):
        if(turn): #White team turn, docking a black piece
            y += sq_to_docking #For capture of a black piece
        else: #Black team turn, docking a white piece
            y -= sq_to_docking
        in_capture = False
    
    #motor_moving = receive_i2c() #Check if motor is moving
    while receive_i2c(): #Wait if motor is moving
        print("[I2C] Motor is moving, waiting...")
        time.sleep(0.1) #Sleep for a short time to avoid busy waiting
    print(x, y, move[0:2], move[2:4])
    send_i2c(x, y, move[0:2], move[2:4]) #Send coordinates to motor
    print(f"[I2C] Coordinates sent: x={x}, y={y}")



def calculate_squares(move):
    x = ord(move[2]) - ord(move[0])
        
    y = ord(move[3]) - ord(move[1])

    return x , y

def docking_station_calculator(piece_type, turn):
    global docking_counter_w, docking_counter_b
    global in_capture
    in_capture = True #Capture logic

    # Zielreihe und Zhler je nach Farbe
    if turn:
        # Wei
        if docking_counter_w >= 8:
            print("[Docking] Alle weien Parkpltze (a0-h0) sind voll! Bitte Figuren entfernen.")
            docking_counter_w = 0  # Optional: zurcksetzen, falls gewnscht
        docking_dest = chr(ord('a') + docking_counter_w) + "0"
        docking_counter_w += 1
    else:
        # Schwarz
        if docking_counter_b >= 8:
            print("[Docking] Alle schwarzen Parkpltze (a9-h9) sind voll! Bitte Figuren entfernen.")
            docking_counter_b = 0  # Optional: zurcksetzen, falls gewnscht
        docking_dest = chr(ord('a') + docking_counter_b) + "9"
        docking_counter_b += 1

    return docking_dest


#Main Loop

while(not checkmate):
    #Play player move
    player_move = input("What is your move? Please provide the move in algebraic chess form: 'a1a1' in lower case.\n")
    #Check valid move
    is_legal_move = chess.Move.from_uci(player_move) in board.legal_moves
    if(not is_legal_move):
        print("[Error] Illegal move, try again!")
        continue
    
    move_obj = chess.Move.from_uci(player_move)
    if move_obj in board.legal_moves and board.is_castling(move_obj):
        # Kurze Rochade Wei
        if player_move == "e1g1":
            # 1. Turm von h1 nach h0 (Parkplatz)
            motor_to_src("h1h0")
            execute_move(to_src_move, board.turn)
            src_to_dest("h1h0")
            execute_move(to_dest_move, board.turn)
            # 2. Knig von e1 nach g1
            motor_to_src("e1g1")
            execute_move(to_src_move, board.turn)
            src_to_dest("e1g1")
            execute_move(to_dest_move, board.turn)
            # 3. Turm von h0 nach f1 (ber Parkplatzreihe)
            motor_to_src("h0f1")
            execute_move(to_src_move, board.turn)
            src_to_dest("h0f1")
            execute_move(to_dest_move, board.turn)
            board.push(move_obj)
            continue
        # Lange Rochade Wei
        if player_move == "e1c1":
            # 1. Turm von a1 nach a0 (Parkplatz)
            motor_to_src("a1a0")
            execute_move(to_src_move, board.turn)
            src_to_dest("a1a0")
            execute_move(to_dest_move, board.turn)
            # 2. Turm von a0 nach d0 (ber Parkplatzreihe)
            motor_to_src("a0d0")
            execute_move(to_src_move, board.turn)
            src_to_dest("a0d0")
            execute_move(to_dest_move, board.turn)
            # 3. Knig von e1 nach c1
            motor_to_src("e1c1")
            execute_move(to_src_move, board.turn)
            src_to_dest("e1c1")
            execute_move(to_dest_move, board.turn)
            # 4. Turm von d0 nach d1 (auf Zielfeld)
            motor_to_src("d0d1")
            execute_move(to_src_move, board.turn)
            src_to_dest("d0d1")
            execute_move(to_dest_move, board.turn)
            board.push(move_obj)
            continue
        # Kurze Rochade Schwarz
        if player_move == "e8g8":
            # 1. Turm von h8 nach h9 (Parkplatz)
            motor_to_src("h8h9")
            execute_move(to_src_move, board.turn)
            src_to_dest("h8h9")
            execute_move(to_dest_move, board.turn)
            # 2. Knig von e8 nach g8
            motor_to_src("e8g8")
            execute_move(to_src_move, board.turn)
            src_to_dest("e8g8")
            execute_move(to_dest_move, board.turn)
            # 3. Turm von h9 nach f8 (ber Parkplatzreihe)
            motor_to_src("h9f8")
            execute_move(to_src_move, board.turn)
            src_to_dest("h9f8")
            execute_move(to_dest_move, board.turn)
            board.push(move_obj)
            continue
        # Lange Rochade Schwarz
        if player_move == "e8c8":
            # 1. Turm von a8 nach a9 (Parkplatz)
            motor_to_src("a8a9")
            execute_move(to_src_move, board.turn)
            src_to_dest("a8a9")
            execute_move(to_dest_move, board.turn)
            # 2. Turm von a9 nach d9 (ber Parkplatzreihe)
            motor_to_src("a9d9")
            execute_move(to_src_move, board.turn)
            src_to_dest("a9d9")
            execute_move(to_dest_move, board.turn)
            # 3. Knig von e8 nach c8
            motor_to_src("e8c8")
            execute_move(to_src_move, board.turn)
            src_to_dest("e8c8")
            execute_move(to_dest_move, board.turn)
            # 4. Turm von d9 nach d8 (auf Zielfeld)
            motor_to_src("d9d8")
            execute_move(to_src_move, board.turn)
            src_to_dest("d9d8")
            execute_move(to_dest_move, board.turn)
            board.push(move_obj)
            continue

    #Check if the move results in a capture    
    if(board.is_capture(chess.Move.from_uci(player_move))):
        print("[Capture] Capture logic triggered.")
        #Capture Logic
        capture_move = player_move[2]+player_move[3]+player_move[0]+player_move[1] #Make destination of player move as source
        motor_to_src(capture_move) #Create move: Motor previous location to Captured piece location
        execute_move(to_src_move, board.turn) #Motor goes to captured piece
        
        captured_piece_type = board.piece_type_at(chess.parse_square(player_move[2] + player_move[3]))
        docking_dest = docking_station_calculator(captured_piece_type, not board.turn)
        src_to_dest(motor_location + docking_dest) #Create move: Motor previous location (captured) to Captured piece location in docking
        execute_move(to_dest_move, board.turn) #Motor moves captured piece to its docking location

    
    #Non-capture logic

    #Updates to_src_move with move of motor to source square
    motor_to_src(player_move) 
    #Motor goes to source square
    execute_move(to_src_move, board.turn) 
    
    #Updates to_dest_move with move of motor to destination square
    src_to_dest(player_move) 
    #Motor goes to destination square
    execute_move(to_dest_move, board.turn) 


    #Mimic motor motion in virtual board
    board.push_san(player_move) 
    
    if(board.is_checkmate()):
        print("[Game] WINNER IS TEAM WHITE!")
        break
    
    #Get Computer Move
    stock.set_fen_position(board.fen())
    
    #Parse Computer Move
    best_move=list(str(stock.get_best_move()))
    computer_move=best_move[0]+best_move[1]+best_move[2]+best_move[3]                      
    print(f"[Computer] Best Move: {computer_move}")
    #Check if the move results in a capture    
    if(board.is_capture(chess.Move.from_uci(computer_move))):
        print("[Capture] Capture logic triggered.")
        #Capture Logic
        capture_move = computer_move[2]+computer_move[3]+computer_move[0]+computer_move[1] #Make destination of player move as source
        motor_to_src(capture_move) #Create move: Motor previous location to Captured piece location
        execute_move(to_src_move, board.turn) #Motor goes to captured piece
        
        captured_piece_type = board.piece_type_at(chess.parse_square(computer_move[2] + computer_move[3]))
        docking_dest = docking_station_calculator(captured_piece_type, not board.turn)
        src_to_dest(motor_location + docking_dest) #Create move: Motor previous location (captured) to Captured piece location in docking
        execute_move(to_dest_move, board.turn) #Motor moves captured piece to its docking location
    
    #Non-capture logic
    #Updates to_src_move with move of motor to source square
    motor_to_src(computer_move) 
    #Motor goes to source square
    execute_move(to_src_move, board.turn) 
    
    #Updates to_dest_move with move of motor to destination square
    src_to_dest(computer_move) 
    #Motor goes to destination square
    execute_move(to_dest_move, board.turn) 


    #Mimic motor motion in virtual board
    board.push_san(computer_move)
    
    checkmate = board.is_checkmate()
    if(checkmate):
        print("[Game] WINNER IS TEAM BLACK")
        break
    print(f"[Board]\n{board}")

Credits

Infineon Team
111 projects • 182 followers
Maysa Ouaja
1 project • 2 followers
Thanks to SteedMaker, Roaa Ahmed, and Eric Schulze.

Comments