Korábbi bejegyzések ebben a témában: Minimax algoritmus a játékelméletben Értékelési funkció a játékelméletben Tic-Tac-Toe AI – Optimális mozgás megtalálása Alfa-béta metszés .
A Zobrist Hashing egy kivonatoló funkció, amelyet széles körben használnak 2 játékos társasjátékokban. Ez a leggyakrabban használt hash-függvény az átültetési táblázatban. A transzpozíciós táblák alapvetően a korábbi táblaállapotok kiértékelt értékeit tárolják, így ha ismét találkozunk velük, egyszerűen lekérjük a tárolt értéket a transzponálási táblából. Az átültetési táblázatokkal egy későbbi cikkben fogunk foglalkozni. Ebben a cikkben a sakktábla példáját vesszük, és ehhez egy hash funkciót alkalmazunk.
Pszeudokód:
// A matrix with random numbers initialized once Table[#ofBoardCells][#ofPieces] // Returns Zobrist hash function for current conf- // iguration of board. function findhash(board): hash = 0 for each cell on the board : if cell is not empty : piece = board[cell] hash ^= table[cell][piece] return hash
Magyarázat:
A Zobrist Hashing mögött az az elképzelés áll, hogy egy adott táblaállapothoz, ha van egy darab egy adott cellában, a tábla megfelelő cellájának véletlenszámát használjuk.
Ha több bit van a véletlen számban, akkor kisebb a hash ütközés esélye. Ezért általában 64 bites számokat használnak szabványként, és nagyon valószínűtlen, hogy ilyen nagy számokkal hash ütközés következzen be. A táblát csak egyszer kell inicializálni a programok végrehajtása során.
Szintén az az oka annak, hogy a Zobrist Hashing-et széles körben használják a társasjátékokban, mert amikor egy játékos egy lépést tesz, nem szükséges a hash értékét a semmiből újraszámolni. Az XOR művelet természetéből adódóan egyszerűen csak kevés XOR műveletet használhatunk a hash érték újraszámítására.
Megvalósítás:
Megpróbálunk egy hash értéket találni az adott tábla konfigurációhoz.
// A program to illustrate Zobrist Hashing Algorithm #include using namespace std; unsigned long long int ZobristTable[8][8][12]; mt19937 mt(01234567); // Generates a Random number from 0 to 2^64-1 unsigned long long int randomInt() { uniform_int_distribution<unsigned long long int> dist(0 UINT64_MAX); return dist(mt); } // This function associates each piece with // a number int indexOf(char piece) { if (piece=='P') return 0; if (piece=='N') return 1; if (piece=='B') return 2; if (piece=='R') return 3; if (piece=='Q') return 4; if (piece=='K') return 5; if (piece=='p') return 6; if (piece=='n') return 7; if (piece=='b') return 8; if (piece=='r') return 9; if (piece=='q') return 10; if (piece=='k') return 11; else return -1; } // Initializes the table void initTable() { for (int i = 0; i<8; i++) for (int j = 0; j<8; j++) for (int k = 0; k<12; k++) ZobristTable[i][j][k] = randomInt(); } // Computes the hash value of a given board unsigned long long int computeHash(char board[8][9]) { unsigned long long int h = 0; for (int i = 0; i<8; i++) { for (int j = 0; j<8; j++) { if (board[i][j]!='-') { int piece = indexOf(board[i][j]); h ^= ZobristTable[i][j][piece]; } } } return h; } // Main Function int main() { // Uppercase letters are white pieces // Lowercase letters are black pieces char board[8][9] = { "---K----" "-R----Q-" "--------" "-P----p-" "-----p--" "--------" "p---b--q" "----n--k" }; initTable(); unsigned long long int hashValue = computeHash(board); printf("The hash value is : %llun" hashValue); //Move the white king to the left char piece = board[0][3]; board[0][3] = '-'; hashValue ^= ZobristTable[0][3][indexOf(piece)]; board[0][2] = piece; hashValue ^= ZobristTable[0][2][indexOf(piece)]; printf("The new hash value is : %llun" hashValue); // Undo the white king move piece = board[0][2]; board[0][2] = '-'; hashValue ^= ZobristTable[0][2][indexOf(piece)]; board[0][3] = piece; hashValue ^= ZobristTable[0][3][indexOf(piece)]; printf("The old hash value is : %llun" hashValue); return 0; }
Java // A Java program to illustrate Zobrist Hashing Algorithm import java.util.*; public class GFG { public static List<List<List<Integer>>> ZobristTable = new ArrayList<>(); // mt19937 mt(01234567); public static void initialise() { for (int i = 0; i < 8; i++) { ZobristTable.add(new ArrayList<>()); for (int j = 0; j < 8; j++) { ZobristTable.get(i).add(new ArrayList<>()); for (int k = 0; k < 12; k++) { ZobristTable.get(i).get(j).add(0); } } } } // Generates a Random number from 0 to 2^64-1 public static long randomLong() { long min = 0L; long max = (long) Math.pow(2 64); Random rnd = new Random(); return rnd.nextLong() * (max - min) + min; } // This function associates each piece with a number public static int indexOf(char piece) { if (piece=='P') return 0; if (piece=='N') return 1; if (piece=='B') return 2; if (piece=='R') return 3; if (piece=='Q') return 4; if (piece=='K') return 5; if (piece=='p') return 6; if (piece=='n') return 7; if (piece=='b') return 8; if (piece=='r') return 9; if (piece=='q') return 10; if (piece=='k') return 11; else return -1; } // Initializes the table public static void initTable() { for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { for (int k = 0; k < 12; k++) { Random rnd = new Random(); ZobristTable.get(i).get(j).set(k (int) randomLong()); } } } } // Computes the hash value of a given board public static int computeHash(List<List<Character>> board) { int h = 0; for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { if (board.get(i).get(j) != '-') { int piece = indexOf(board.get(i).get(j)); h ^= ZobristTable.get(i).get(j).get(piece); } } } return h; } public static void main(String[] args) { // Main Function // Uppercase letters are white pieces // Lowercase letters are black pieces List<List<Character>> board = new ArrayList<>(); board.add(new ArrayList<>(Arrays.asList('-' '-' '-' 'K' '-' '-' '-' '-'))); board.add(new ArrayList<>(Arrays.asList('-' 'R' '-' '-' '-' '-' 'Q' '-'))); board.add(new ArrayList<>(Arrays.asList('-' '-' '-' 'K' '-' '-' '-' '-'))); board.add(new ArrayList<>(Arrays.asList('-' '-' '-' '-' '-' '-' '-' '-'))); board.add(new ArrayList<>(Arrays.asList('-' 'P' '-' '-' '-' '-' 'p' '-'))); board.add(new ArrayList<>(Arrays.asList('-' '-' '-' '-' '-' 'p' '-' '-'))); board.add(new ArrayList<>(Arrays.asList('-' '-' '-' '-' '-' '-' '-' '-'))); board.add(new ArrayList<>(Arrays.asList('p' '-' '-' '-' 'b' '-' '-' 'q'))); board.add(new ArrayList<>(Arrays.asList('-' '-' '-' '-' 'n' '-' '-' 'k'))); initialise(); initTable(); int hashValue = computeHash(board); System.out.println('The hash value is : ' + hashValue); // Move the white king to the left char piece = board.get(0).get(3); board.get(0).set(3 '-'); hashValue ^= ZobristTable.get(0).get(3).get(indexOf(piece)); board.get(0).set(2 piece); hashValue ^= ZobristTable.get(0).get(2).get(indexOf(piece)); System.out.println('The new hash value is : ' + hashValue); // Undo the white king move piece = board.get(0).get(2); board.get(0).set(2 '-'); hashValue ^= ZobristTable.get(0).get(2).get(indexOf(piece)); board.get(0).set(3 piece); hashValue ^= ZobristTable.get(0).get(3).get(indexOf(piece)); System.out.println('The new hash value is : ' + hashValue); } } // This code is contributed by Vaibhav
Python3 # A program to illustrate Zobrist Hashing Algorithm # python code implementation import random # mt19937 mt(01234567); # Generates a Random number from 0 to 2^64-1 def randomInt(): min = 0 max = pow(2 64) return random.randint(min max) # This function associates each piece with # a number def indexOf(piece): if (piece=='P'): return 0 elif (piece=='N'): return 1 elif (piece=='B'): return 2 elif (piece=='R'): return 3 elif (piece=='Q'): return 4 elif (piece=='K'): return 5 elif (piece=='p'): return 6 elif (piece=='n'): return 7 elif (piece=='b'): return 8 elif (piece=='r'): return 9 elif (piece=='q'): return 10 elif (piece=='k'): return 11 else: return -1 # Initializes the table def initTable(): # 8x8x12 array ZobristTable = [[[randomInt() for k in range(12)] for j in range(8)] for i in range(8)] return ZobristTable # Computes the hash value of a given board def computeHash(board ZobristTable): h = 0 for i in range(8): for j in range(8): if (board[i][j] != '-'): piece = indexOf(board[i][j]) h ^= ZobristTable[i][j][piece] return h # Main Function # Uppercase letters are white pieces # Lowercase letters are black pieces board = [ '---K----' '-R----Q-' '--------' '-P----p-' '-----p--' '--------' 'p---b--q' '----n--k' ] ZobristTable = initTable() hashValue = computeHash(board ZobristTable) print('The hash value is : ' + str(hashValue)) #Move the white king to the left piece = board[0][3] board[0] = list(board[0]) board[0][3] = '-' board[0] = ''.join(board[0]) hashValue ^= ZobristTable[0][3][indexOf(piece)] board[0] = list(board[0]) board[0][2] = piece board[0] = ''.join(board[0]) hashValue ^= ZobristTable[0][2][indexOf(piece)] print('The new hash value is : ' + str(hashValue)) # Undo the white king move piece = board[0][2] board[0] = list(board[0]) board[0][2] = '-' board[0] = ''.join(board[0]) hashValue ^= ZobristTable[0][2][indexOf(piece)] board[0] = list(board[0]) board[0][3] = piece board[0] = ''.join(board[0]) hashValue ^= ZobristTable[0][3][indexOf(piece)] print('The old hash value is : ' + str(hashValue))
C# using System; using System.Collections; using System.Collections.Generic; using System.Linq; // C# program for the above approach // A program to illustrate Zobrist Hashing Algorithm // javascript code implementation class HelloWorld { public static List<List<List<int>>> ZobristTable = new List<List<List<int>>>(); // mt19937 mt(01234567); public static void initialise(){ for(int i = 0; i < 8; i++){ ZobristTable.Add(new List<List<int>>()); for(int j = 0; j < 8; j++){ ZobristTable[i].Add(new List<int>()); for(int k = 0; k < 12; k++){ ZobristTable[i][j].Add(0); } } } } // Generates a Random number from 0 to 2^64-1 public static int randomInt() { int min = 0; int max = (int)Math.Pow(2 64); Random rnd = new Random(); return rnd.Next() * (max - min) + min; } // This function associates each piece with // a number public static int indexOf(char piece) { if (piece=='P') return 0; if (piece=='N') return 1; if (piece=='B') return 2; if (piece=='R') return 3; if (piece=='Q') return 4; if (piece=='K') return 5; if (piece=='p') return 6; if (piece=='n') return 7; if (piece=='b') return 8; if (piece=='r') return 9; if (piece=='q') return 10; if (piece=='k') return 11; else return -1; } // Initializes the table public static void initTable() { for (int i = 0; i<8; i++){ for(int j = 0; j < 8; j++){ for(int k = 0; k < 12; k++){ Random rnd = new Random(); ZobristTable[i][j][k] = rnd.Next(); } } } } // Computes the hash value of a given board public static int computeHash(List<List<char>> board) { int h = 0; for (int i = 0; i<8; i++) { for (int j = 0; j<8; j++) { if (board[i][j]!='-') { int piece = indexOf(board[i][j]); h ^= ZobristTable[i][j][piece]; } } } return h; } static void Main() { // Main Function // Uppercase letters are white pieces // Lowercase letters are black pieces List<List<char>> board = new List<List<char>>(); board.Add(new List<char>(){'-' '-' '-' 'K' '-' '-' '-' '-'}); board.Add(new List<char>(){'-' 'R' '-' '-' '-' '-' 'Q' '-'}); board.Add(new List<char>(){'-' '-' '-' 'K' '-' '-' '-' '-'}); board.Add(new List<char>(){'-' '-' '-' '-' '-' '-' '-' '-'}); board.Add(new List<char>(){'-' 'P' '-' '-' '-' '-' 'p' '-'}); board.Add(new List<char>(){'-' '-' '-' '-' '-' 'p' '-' '-' }); board.Add(new List<char>(){'-' '-' '-' '-' '-' '-' '-' '-'}); board.Add(new List<char>(){'p' '-' '-' '-' 'b' '-' '-' 'q'}); board.Add(new List<char>(){'-' '-' '-' '-' 'n' '-' '-' 'k'}); initialise(); initTable(); int hashValue = computeHash(board); Console.WriteLine('The hash value is : ' + hashValue); //Move the white king to the left char piece = board[0][3]; board[0][3] = '-'; hashValue ^= ZobristTable[0][3][indexOf(piece)]; board[0][2] = piece; hashValue ^= ZobristTable[0][2][indexOf(piece)]; Console.WriteLine('The new hash value is : ' + hashValue); // Undo the white king move piece = board[0][2]; board[0][2] = '-'; hashValue ^= ZobristTable[0][2][indexOf(piece)]; board[0][3] = piece; hashValue ^= ZobristTable[0][3][indexOf(piece)]; Console.WriteLine('The old hash value is : ' + hashValue); } } // The code is contributed by Nidhi goel.
JavaScript // A program to illustrate Zobrist Hashing Algorithm // javascript code implementation let ZobristTable = new Array(8); for(let i = 0; i < 8; i++){ ZobristTable[i] = new Array(8); } for(let i = 0; i < 8; i++){ for(let j = 0; j < 8; j++){ ZobristTable[i][j] = new Array(12); } } // mt19937 mt(01234567); // Generates a Random number from 0 to 2^64-1 function randomInt() { let min = 0; let max = Math.pow(2 64); return Math.floor(Math.random() * (max - min) + min); } // This function associates each piece with // a number function indexOf(piece) { if (piece=='P') return 0; if (piece=='N') return 1; if (piece=='B') return 2; if (piece=='R') return 3; if (piece=='Q') return 4; if (piece=='K') return 5; if (piece=='p') return 6; if (piece=='n') return 7; if (piece=='b') return 8; if (piece=='r') return 9; if (piece=='q') return 10; if (piece=='k') return 11; else return -1; } // Initializes the table function initTable() { for (let i = 0; i<8; i++) for (let j = 0; j<8; j++) for (let k = 0; k<12; k++){ ZobristTable[i][j][k] = randomInt(); } } // Computes the hash value of a given board function computeHash(board) { let h = 0; for (let i = 0; i<8; i++) { for (let j = 0; j<8; j++) { if (board[i][j]!='-') { let piece = indexOf(board[i][j]); h ^= ZobristTable[i][j][piece]; } } } return h; } // Main Function // Uppercase letters are white pieces // Lowercase letters are black pieces let board = [ '---K----' '-R----Q-' '--------' '-P----p-' '-----p--' '--------' 'p---b--q' '----n--k' ]; initTable(); let hashValue = computeHash(board); console.log('The hash value is : ' + hashValue); //Move the white king to the left let piece = board[0][3]; board[0] = board[0].split(''); board[0][3] = '-'; board[0] = board[0].join(''); hashValue ^= ZobristTable[0][3][indexOf(piece)]; board[0] = board[0].split(''); board[0][2] = piece; board[0] = board[0].join(''); hashValue ^= ZobristTable[0][2][indexOf(piece)]; console.log('The new hash value is : ' + hashValue); // Undo the white king move piece = board[0][2]; board[0] = board[0].split(''); board[0][2] = '-'; board[0] = board[0].join(''); hashValue ^= ZobristTable[0][2][indexOf(piece)]; board[0][3] = piece; hashValue ^= ZobristTable[0][3][indexOf(piece)]; console.log('The old hash value is : ' + hashValue); // The code is contributed by Nidhi goel.
Kimenet:
The hash value is : 14226429382419125366 The new hash value is : 15124945578233295113 The old hash value is : 14226429382419125366