| Inhalt |
Hier ist ein kleines, elementares Schachprogramm in Python, das:
e2e4 nimmtNicht implementiert (der Einfachheit halber): Rochade, en passant, Aufgabe, Zeit, Unentschieden nach 50 Zügen etc.
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 |