dámajáték
Kiejtés
- IPA: [ ˈdaːmɒjaːteːk]
Főnév
dámajáték
A dámajáték egy klasszikus kétszemélyes stratégiai játék, amelyet egy 8x8-as táblán játszanak. A cél az, hogy az ellenfél összes bábuját leüssük, vagy mozgásképtelenné tegyük. Az alábbiakban bemutatom a játék szabályait, adatstruktúráját, algoritmusát, valamint egy egyszerű Python és C++ implementációt.
1. Dámajáték szabályai
- Tábla és bábuk:
- Egy 8x8-as sakktáblát használnak, de csak a sötét mezőkön játszanak.
- Minden játékos 12 bábút kap, amelyek a tábla sötét mezőire kerülnek az első három sorba.
- Mozgás:
- A bábuk előre átlós irányban mozognak egy mezőt.
- Ha egy ellenfél bábuja mögött üres mező van, akkor át lehet ugrani rajta, így leütve azt. Az ugrás kötelező, ha lehetséges.
- Dáma:
- Ha egy bábu eléri az ellenfél hátsó sorát, „dáma” lesz, és ezután előre és hátra is léphet átlós irányban.
- Játék vége:
- Egy játékos veszít, ha az összes bábuját elveszíti, vagy ha nincs érvényes lépése.
2. Adatstruktúra
Táblázatos reprezentáció:
A tábla 8x8-as mátrixként tárolható: - 0
: üres mező. - 1
: az első játékos bábuja. - 2
: az első játékos dámája. - -1
: a második játékos bábuja. - -2
: a második játékos dámája.
Példa egy táblaállapotra:
[[ 0, -1, 0, -1, 0, -1, 0, -1], [ -1, 0, -1, 0, -1, 0, -1, 0], [ 0, -1, 0, -1, 0, -1, 0, -1], [ 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 0, 0], [ 1, 0, 1, 0, 1, 0, 1, 0], [ 0, 1, 0, 1, 0, 1, 0, 1], [ 1, 0, 1, 0, 1, 0, 1, 0]]
Bábuk pozíciójának tárolása:
Alternatív megközelítésként egy lista használható a bábuk pozícióinak tárolására:
player1_pieces = [(5, 0), (5, 2), (5, 4), (5, 6), ...] # Első játékos bábui
player2_pieces = [(2, 1), (2, 3), (2, 5), (2, 7), ...] # Második játékos bábui
3. Algoritmus
Lépések generálása:
- Egyszerű lépés: Minden bábu számára vizsgáljuk az átlós irányokat (előre és hátra dámák esetében).
- Ugrások: Vizsgáljuk, hogy van-e ellenfél bábuja mögött üres mező. Az ugrások kötelezőek.
Értékelési függvény:
- Bábuk száma: Több bábu = jobb pozíció.
- Pozíció: A középső mezők értékesebbek.
- Dámák száma: A dáma bábuk értékesebbek.
Lépés kiválasztása:
- Min-Max algoritmus Alpha-Beta metszéssel:
- Rekurzív keresés a lehetséges lépéseken.
- Az ellenfél legrosszabb helyzete és a saját legjobb helyzet kiválasztása.
4. Dámajáték implementáció
Python kód
class Checkers:
def __init__(self):
# 8x8 tábla
self.board = [
[ 0, -1, 0, -1, 0, -1, 0, -1],
[-1, 0, -1, 0, -1, 0, -1, 0],
[ 0, -1, 0, -1, 0, -1, 0, -1],
[ 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0],
[ 1, 0, 1, 0, 1, 0, 1, 0],
[ 0, 1, 0, 1, 0, 1, 0, 1],
[ 1, 0, 1, 0, 1, 0, 1, 0],
]
def print_board(self):
for row in self.board:
print(row)
def generate_moves(self, player):
"""Lépések generálása egy játékos számára."""
moves = []
for i in range(8):
for j in range(8):
if self.board[i][j] == player:
# Vizsgáljuk az átlós irányokat
directions = [(-1, -1), (-1, 1)] if player == 1 else [(1, -1), (1, 1)]
for dx, dy in directions:
x, y = i + dx, j + dy
if 0 <= x < 8 and 0 <= y < 8 and self.board[x][y] == 0:
moves.append(((i, j), (x, y))) # Egyszerű lépés
return moves
# Használat
game = Checkers()
game.print_board()
print("Lépések az első játékosnak:", game.generate_moves(1))
C++ kód
#include <iostream>
#include <vector>
using namespace std;
class Checkers {
private:
vector<vector<int>> board;
public:
Checkers() {
board = {
{ 0, -1, 0, -1, 0, -1, 0, -1},
{-1, 0, -1, 0, -1, 0, -1, 0},
{ 0, -1, 0, -1, 0, -1, 0, -1},
{ 0, 0, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0},
{ 1, 0, 1, 0, 1, 0, 1, 0},
{ 0, 1, 0, 1, 0, 1, 0, 1},
{ 1, 0, 1, 0, 1, 0, 1, 0},
};
}
void printBoard() {
for (const auto& row : board) {
for (int cell : row) {
cout << cell << " ";
}
cout << endl;
}
}
vector<pair<pair<int, int>, pair<int, int>>> generateMoves(int player) {
vector<pair<pair<int, int>, pair<int, int>>> moves;
for (int i = 0; i < 8; ++i) {
for (int j = 0; j < 8; ++j) {
if (board[i][j] == player) {
vector<pair<int, int>> directions = player == 1 ? vector<pair<int, int>>{{-1, -1}, {-1, 1}} : vector<pair<int, int>>{{1, -1}, {1, 1}};
for (auto [dx, dy] : directions) {
int x = i + dx, y = j + dy;
if (x >= 0 && x < 8 && y >= 0 && y < 8 && board[x][y] == 0) {
moves.push_back({{i, j}, {x, y}});
}
}
}
}
}
return moves;
}
};
int main() {
Checkers game;
game.printBoard();
auto moves = game.generateMoves(1);
cout << "Lépések az első játékosnak:" << endl;
for (const auto& move : moves) {
cout << "(" << move.first.first << "," << move.first.second << ") -> (" << move.second.first << "," << move.second.second << ")" << endl;
}
return 0;
}
Ezek az implementációk az alapokhoz szükségesek. Egy teljes solver implementációjához Min-Max algoritmust Alpha-Beta metszéssel, illetve heurisztikákat kell alkalmazni. Egy dámajáték solver Pythonban a Min-Max algoritmus és az Alpha-Beta metszés segítségével implementálható. Az alábbiakban bemutatom, hogyan lehet létrehozni egy egyszerű, de működőképes solver-t.
Dámajáték solver Pythonban
Teljes kód: Min-Max alapú solver Alpha-Beta metszéssel
import copy
class Checkers:
def __init__(self):
self.board = [
[ 0, -1, 0, -1, 0, -1, 0, -1],
[-1, 0, -1, 0, -1, 0, -1, 0],
[ 0, -1, 0, -1, 0, -1, 0, -1],
[ 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 0],
[ 1, 0, 1, 0, 1, 0, 1, 0],
[ 0, 1, 0, 1, 0, 1, 0, 1],
[ 1, 0, 1, 0, 1, 0, 1, 0],
]
def print_board(self):
for row in self.board:
print(row)
print()
def generate_moves(self, player):
moves = []
directions = [(-1, -1), (-1, 1)] if player == 1 else [(1, -1), (1, 1)]
for i in range(8):
for j in range(8):
if self.board[i][j] == player:
for dx, dy in directions:
x, y = i + dx, j + dy
if 0 <= x < 8 and 0 <= y < 8 and self.board[x][y] == 0:
moves.append(((i, j), (x, y)))
return moves
def make_move(self, move, player):
"""Végrehajt egy lépést."""
start, end = move
self.board[start[0]][start[1]] = 0
self.board[end[0]][end[1]] = player
def undo_move(self, move, player):
"""Visszavon egy lépést."""
start, end = move
self.board[start[0]][start[1]] = player
self.board[end[0]][end[1]] = 0
def evaluate(self):
"""Egyszerű értékelési függvény."""
score = 0
for row in self.board:
for piece in row:
if piece == 1:
score += 1
elif piece == -1:
score -= 1
return score
def minmax(self, depth, maximizing_player, alpha, beta):
"""Min-Max algoritmus Alpha-Beta metszéssel."""
if depth == 0 or not self.has_moves(maximizing_player):
return self.evaluate()
if maximizing_player:
max_eval = float('-inf')
moves = self.generate_moves(1)
for move in moves:
self.make_move(move, 1)
eval = self.minmax(depth - 1, False, alpha, beta)
self.undo_move(move, 1)
max_eval = max(max_eval, eval)
alpha = max(alpha, eval)
if beta <= alpha:
break # Beta metszés
return max_eval
else:
min_eval = float('inf')
moves = self.generate_moves(-1)
for move in moves:
self.make_move(move, -1)
eval = self.minmax(depth - 1, True, alpha, beta)
self.undo_move(move, -1)
min_eval = min(min_eval, eval)
beta = min(beta, eval)
if beta <= alpha:
break # Alpha metszés
return min_eval
def has_moves(self, player):
"""Ellenőrzi, hogy a játékosnak van-e érvényes lépése."""
return len(self.generate_moves(player)) > 0
def best_move(self, depth, player):
"""Legjobb lépés kiválasztása."""
best_eval = float('-inf') if player == 1 else float('inf')
best_move = None
moves = self.generate_moves(player)
for move in moves:
self.make_move(move, player)
eval = self.minmax(depth - 1, player == -1, float('-inf'), float('inf'))
self.undo_move(move, player)
if (player == 1 and eval > best_eval) or (player == -1 and eval < best_eval):
best_eval = eval
best_move = move
return best_move
# Dámajáték használat
game = Checkers()
game.print_board()
# Első játékos legjobb lépése
best = game.best_move(depth=3, player=1)
print("Az első játékos legjobb lépése:", best)
if best:
game.make_move(best, player=1)
game.print_board()
Kódmagyarázat
- Táblastruktúra:
- A tábla 8x8-as mátrixként van tárolva, ahol a pozitív számok az első játékos, a negatív számok a második játékos bábuit jelölik.
- Lépések generálása:
- Az
generate_moves
függvény visszaadja az összes lehetséges lépést a megadott játékos számára (egyszerű lépésekkel).
- Az
- Értékelési függvény (
evaluate
):- Egy egyszerű pontozási függvény, amely a bábuk számát hasonlítja össze.
- Min-Max algoritmus Alpha-Beta metszéssel:
- Optimalizálja a keresést azáltal, hogy bizonyos ágazatokat kizár.
- Rekurzívan keres a lehetséges lépések között, és a legjobb pontszámot választja.
- Legjobb lépés kiválasztása (
best_move
):- Meghatározza a legjobb lépést a megadott mélység alapján.
Példa futtatás eredménye
Az alap táblaállapot:
[0, -1, 0, -1, 0, -1, 0, -1] [-1, 0, -1, 0, -1, 0, -1, 0] ... [1, 0, 1, 0, 1, 0, 1, 0] [0, 1, 0, 1, 0, 1, 0, 1]
Legjobb lépés például:
Az első játékos legjobb lépése: ((5, 0), (4, 1))
Tábla frissítése a lépés után.
Ez a kód működőképes alapot ad egy dámajáték solverhez. Az optimalizáció és a további szabályok (pl. ugrás, dáma) bővíthetők a kódhoz.