Inhalt  |


Python : kleines elementares Schachprogramm zur Demonstration der Schachspielregeln!

Hier ist ein kleines, elementares Schachprogramm in Python, das:

Nicht implementiert (der Einfachheit halber): Rochade, en passant, Aufgabe, Zeit, Unentschieden nach 50 Zügen etc.

Python-Code

Speichere das z.B. als 2512020748_MinimalesSchachprogramm.py und starte es mit python 2512020748_MinimalesSchachprogramm.py.

Download “2512020748_MinimalesSchachprogramm.py”

from typing import List, Optional, Tuple

Board = List[List[str]]

def initial_board() -> Board:
    """Startaufstellung: Großbuchstaben = Weiß, Kleinbuchstaben = Schwarz"""
    setup = [
        list("rnbqkbnr"),
        list("pppppppp"),
        list("........"),
        list("........"),
        list("........"),
        list("........"),
        list("PPPPPPPP"),
        list("RNBQKBNR"),
    ]
    return setup

def print_board(board: Board) -> None:
    """Einfaches Textbrett anzeigen."""
    print("  +-----------------+")
    for row in range(8):
        print(8 - row, "|", end=" ")
        for col in range(8):
            piece = board[row][col]
            ch = piece if piece != "." else "."
            print(ch, end=" ")
        print("|")
    print("  +-----------------+")
    print("    a b c d e f g h")

def algebraic_to_index(coord: str) -> Optional[Tuple[int, int]]:
    """z.B. 'e2' -> (6, 4)"""
    if len(coord) != 2:
        return None
    file, rank = coord[0], coord[1]
    if file < "a" or file > "h" or rank < "1" or rank > "8":
        return None
    col = ord(file) - ord("a")
    row = 8 - int(rank)
    return row, col

def is_white(piece: str) -> bool:
    return piece.isupper()

def is_black(piece: str) -> bool:
    return piece.islower()

def in_bounds(r: int, c: int) -> bool:
    return 0 <= r < 8 and 0 <= c < 8

def path_clear(board: Board, r1: int, c1: int, r2: int, c2: int) -> bool:
    """Prüft, ob auf der Linie zwischen Start und Ziel Figuren stehen (für Läufer/Turm/Dame)."""
    dr = (r2 - r1)
    dc = (c2 - c1)
    step_r = (dr > 0) - (dr < 0)
    step_c = (dc > 0) - (dc < 0)
    r, c = r1 + step_r, c1 + step_c
    while (r, c) != (r2, c2):
        if board[r][c] != ".":
            return False
        r += step_r
        c += step_c
    return True

def can_piece_move(board: Board, r1: int, c1: int, r2: int, c2: int, white_to_move: bool) -> bool:
    """Grundlegende Zugregeln für jede Figur (ohne Rochade, ohne en passant)."""
    piece = board[r1][c1]
    target = board[r2][c2]

    # Muss eigene Figur sein
    if piece == ".":
        return False
    if white_to_move and not is_white(piece):
        return False
    if not white_to_move and not is_black(piece):
        return False

    # Kein Schlagen eigener Figur
    if target != ".":
        if is_white(piece) == is_white(target):
            return False

    dr = r2 - r1
    dc = c2 - c1
    absdr, absdc = abs(dr), abs(dc)

    # Bauern
    if piece.upper() == "P":
        direction = -1 if is_white(piece) else 1
        start_row = 6 if is_white(piece) else 1
        # einfacher Vorwärtszug
        if dc == 0 and dr == direction and target == ".":
            return True
        # Doppelschritt vom Startfeld
        if dc == 0 and dr == 2 * direction and r1 == start_row and target == ".":
            between_r = r1 + direction
            if board[between_r][c1] == ".":
                return True
        # diagonaler Schlagzug
        if absdc == 1 and dr == direction and target != ".":
            return True
        return False

    # Springer
    if piece.upper() == "N":
        if (absdr, absdc) in [(1, 2), (2, 1)]:
            return True
        return False

    # Läufer
    if piece.upper() == "B":
        if absdr == absdc and absdr != 0 and path_clear(board, r1, c1, r2, c2):
            return True
        return False

    # Turm
    if piece.upper() == "R":
        if (dr == 0 or dc == 0) and (dr != 0 or dc != 0) and path_clear(board, r1, c1, r2, c2):
            return True
        return False

    # Dame
    if piece.upper() == "Q":
        if ((absdr == absdc) or (dr == 0 or dc == 0)) and (dr != 0 or dc != 0) and path_clear(board, r1, c1, r2, c2):
            return True
        return False

    # König (nur 1 Feld in jede Richtung, keine Rochade)
    if piece.upper() == "K":
        if max(absdr, absdc) == 1:
            return True
        return False

    return False

def find_king(board: Board, white: bool) -> Optional[Tuple[int, int]]:
    target = "K" if white else "k"
    for r in range(8):
        for c in range(8):
            if board[r][c] == target:
                return r, c
    return None

def is_square_attacked(board: Board, r: int, c: int, by_white: bool) -> bool:
    """Prüft, ob Feld (r,c) von der angegebenen Seite angegriffen wird."""
    directions = [(-1,0),(1,0),(0,-1),(0,1),(-1,-1),(-1,1),(1,-1),(1,1)]
    knight_moves = [(-2,-1),(-2,1),(-1,-2),(-1,2),(1,-2),(1,2),(2,-1),(2,1)]

    # Läufer, Turm, Dame, König entlang von Linien
    for dr, dc in directions:
        rr, cc = r + dr, c + dc
        while in_bounds(rr, cc):
            p = board[rr][cc]
            if p != ".":
                if by_white == is_white(p):
                    # Gerade Linien: Turm/Dame
                    if dr == 0 or dc == 0:
                        if p.upper() in ("R", "Q"):
                            return True
                    # Diagonalen: Läufer/Dame
                    if dr != 0 and dc != 0:
                        if p.upper() in ("B", "Q"):
                            return True
                    # König direkt daneben
                    if (rr, cc) != (r, c) and max(abs(rr - r), abs(cc - c)) == 1:
                        if p.upper() == "K":
                            return True
                break
            rr += dr
            cc += dc

    # Springer
    for dr, dc in knight_moves:
        rr, cc = r + dr, c + dc
        if in_bounds(rr, cc):
            p = board[rr][cc]
            if p != "." and by_white == is_white(p) and p.upper() == "N":
                return True

    # Bauernangriffe
    direction = -1 if by_white else 1
    for dc in (-1, 1):
        rr, cc = r + direction, c + dc
        if in_bounds(rr, cc):
            p = board[rr][cc]
            if p != "." and by_white == is_white(p) and p.upper() == "P":
                return True

    return False

def in_check(board: Board, white_to_move: bool) -> bool:
    king_pos = find_king(board, white_to_move)
    if not king_pos:
        return False
    r, c = king_pos
    return is_square_attacked(board, r, c, by_white=not white_to_move)

def make_move(board: Board, r1: int, c1: int, r2: int, c2: int) -> Board:
    """Gibt ein neues Brett mit ausgeführtem Zug zurück (inkl. Bauernumwandlung)."""
    new_board = [row[:] for row in board]
    piece = new_board[r1][c1]
    new_board[r1][c1] = "."
    new_board[r2][c2] = piece

    # Automatische Umwandlung Bauer -> Dame
    if piece.upper() == "P":
        if (is_white(piece) and r2 == 0) or (is_black(piece) and r2 == 7):
            new_board[r2][c2] = "Q" if is_white(piece) else "q"

    return new_board

def has_legal_moves(board: Board, white_to_move: bool) -> bool:
    """Gibt es irgendeinen legalen Zug (für Matt/Patt-Prüfung)?"""
    for r1 in range(8):
        for c1 in range(8):
            piece = board[r1][c1]
            if piece == ".":
                continue
            if white_to_move != is_white(piece):
                continue
            for r2 in range(8):
                for c2 in range(8):
                    if (r1, c1) == (r2, c2):
                        continue
                    if not in_bounds(r2, c2):
                        continue
                    if not can_piece_move(board, r1, c1, r2, c2, white_to_move):
                        continue
                    new_board = make_move(board, r1, c1, r2, c2)
                    if not in_check(new_board, white_to_move):
                        return True
    return False

def main():
    board = initial_board()
    white_to_move = True

    while True:
        print_board(board)
        print("Am Zug:", "Weiß" if white_to_move else "Schwarz")

        # Schach / Matt / Patt prüfen
        if in_check(board, white_to_move):
            if not has_legal_moves(board, white_to_move):
                print("Schachmatt! Gewinner:", "Schwarz" if white_to_move else "Weiß")
                break
            else:
                print("Achtung: Schach!")
        else:
            if not has_legal_moves(board, white_to_move):
                print("Patt! Unentschieden.")
                break

        move = input("Zug eingeben (z.B. e2e4 oder 'quit'): ").strip()
        if move.lower() in ("quit", "exit"):
            print("Beendet.")
            break

        if len(move) != 4:
            print("Bitte im Format 'e2e4' eingeben.")
            continue

        src = move[:2]
        dst = move[2:]
        src_idx = algebraic_to_index(src)
        dst_idx = algebraic_to_index(dst)
        if src_idx is None or dst_idx is None:
            print("Ungültige Koordinaten.")
            continue

        r1, c1 = src_idx
        r2, c2 = dst_idx

        if not can_piece_move(board, r1, c1, r2, c2, white_to_move):
            print("Dieser Zug ist nach den Grundregeln nicht erlaubt.")
            continue

        new_board = make_move(board, r1, c1, r2, c2)
        if in_check(new_board, white_to_move):
            print("Eigener König würde im Schach stehen. Zug nicht erlaubt.")
            continue

        board = new_board
        white_to_move = not white_to_move

if __name__ == "__main__":
    main()


Inhalt  |