이 주제에 대한 이전 게시물: 게임 이론의 미니맥스 알고리즘 게임이론의 평가함수 Tic-Tac-Toe AI – 최적의 움직임 찾기 알파-베타 가지치기 .
Zobrist Hashing은 2인용 보드 게임에서 널리 사용되는 해싱 함수입니다. 전치 테이블에 사용되는 가장 일반적인 해싱 함수입니다. 전치 테이블은 기본적으로 이전 보드 상태의 평가 값을 저장하므로 해당 상태가 다시 발생하면 간단히 전치 테이블에서 저장된 값을 검색합니다. 우리는 이후 기사에서 전치 테이블을 다룰 것입니다. 이 기사에서는 체스판의 예를 들어 이에 대한 해싱 함수를 구현하겠습니다.
유사 코드:
// 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
설명 :
Zobrist Hashing의 기본 개념은 주어진 보드 상태에 대해 주어진 셀에 조각이 있는 경우 테이블의 해당 셀에서 해당 조각의 난수를 사용한다는 것입니다.
난수에 더 많은 비트가 있으면 해시 충돌 가능성이 줄어듭니다. 따라서 64비트 숫자가 일반적으로 표준으로 사용되며 이렇게 큰 숫자에서는 해시 충돌이 발생할 가능성이 거의 없습니다. 테이블은 프로그램 실행 중에 한 번만 초기화되어야 합니다.
또한 Zobrist Hashing이 보드 게임에서 널리 사용되는 이유는 플레이어가 움직일 때 해시 값을 처음부터 다시 계산할 필요가 없기 때문입니다. XOR 연산의 특성으로 인해 해시 값을 다시 계산하기 위해 몇 가지 XOR 연산을 간단히 사용할 수 있습니다.
구현 :
우리는 주어진 보드 구성에 대한 해시 값을 찾으려고 노력할 것입니다.
// 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.
출력 :
The hash value is : 14226429382419125366 The new hash value is : 15124945578233295113 The old hash value is : 14226429382419125366