Min: 0 bitów
Max: 1734 243 bity (4,335 4.401 bitów / płytkę zamortyzowanych)
Spodziewany: 351 177 bitów (4,376 4.430 bitów / płytę zamortyzowanych)
Ponieważ mogę określić dane wejściowe i wyjściowe, postanowiłem jednak zakodować historię gry do tego momentu. Jedną z zalet jest to, że dodatkowa informacja o tym, kto tu jest, en-passant, a kto ma zdolność do blokowania, skąd można uzyskać, a nie zakodować.
Próba 1:
Naiwnie pomyślałem, że mogę zakodować każdy ruch w 12 bitach, 4 trojaczkach formy (początek x, początek y, koniec x, koniec y), gdzie każdy ma 3 bity.
Przyjęlibyśmy pozycję początkową i stamtąd przesuwaliśmy pionki, a białe były pierwsze. Plansza jest ułożona w taki sposób, że (0, 0) jest lewym dolnym rogiem bieli.
Na przykład gra:
e4 e5
Nf3 f6
Nxe5 fxe5
... ...
Zostałby zakodowany jako:
100001 100010 100110 100100
110000 101010 101110 101101
101010 100100 101101 100100
...
Prowadzi to do kodowania 12 m bitów, gdzie m jest liczbą wykonanych ruchów
Z jednej strony może to być naprawdę duże, z drugiej strony każdy ruch można uznać za własną grę, więc każde kodowanie naprawdę koduje m „szachownic”. Jeśli amortyzujesz to, otrzymujesz, że każda „szachownica” ma 12 bitów. Ale czuję, że to trochę oszustwo ...
Próba 2:
Uświadomiłem sobie, że każdy ruch w poprzedniej próbie koduje wiele nielegalnych ruchów. Postanowiłem więc zakodować tylko legalne ruchy. Możliwe ruchy wyliczamy w następujący sposób, numerujemy każdy kwadrat tak, aby (0, 0) → 0, (1, 0) → 1, (x, y) → x + 8 lat. Iteruj przez płytki i sprawdź, czy jest tam kawałek i czy może się poruszyć. Jeśli tak, dodaj pozycje, możesz przejść do listy. Wybierz indeks listy, który jest ruchem, który chcesz wykonać. Dodaj tę liczbę do bieżącej sumy ruchów ważonej przez 1 plus liczbę możliwych ruchów.
Przykład jak wyżej: Z pozycji początkowej pierwszym elementem, który może się poruszyć, jest rycerz na polu 1, może przejść na pole 16 lub 18, więc dodaj je do listy [(1,16),(1,18)]
. Następnie jest rycerz na polu 6, dodaj jego ruchy. Ogólnie otrzymujemy:
[(1,16),(1,18),(6,21),(6,23),(8,16),(8,24),(9,17),(9,25),(10,18),(10,26),(11,19),(11,27),(12,20),(12,28),(13,21),(13,29),(14,22),(14,30),(15,23),(15,31)]
Ponieważ chcemy ruchu (12, 28), kodujemy go jako 13 w bazie 20, ponieważ istnieje 20 możliwych ruchów.
Teraz otrzymujemy numer gry g 0
= 13
Następnie robimy to samo dla czarnych, z wyjątkiem tego, że numerujemy płytki w odwrotnej kolejności (aby ułatwić, nie jest wymagane), aby uzyskać listę ruchów:
[(1,16),(1,18),(6,21),(6,23),(8,16),(8,24),(9,17),(9,25),(10,18),(10,26),(11,19),(11,27),(12,20),(12,28),(13,21),(13,29),(14,22),(14,30),(15,23),(15,31)]
Ponieważ chcemy ruchu (11, 27), kodujemy go jako 11 w bazie 20, ponieważ istnieje 20 możliwych ruchów.
Teraz otrzymujemy numer gry g 1
= (11 ⋅ 20) + 13 = 233
Następnie otrzymujemy następującą listę ruchów dla białych:
[(1,16),(1,18),(3,12),(3,21),(3,30),(3,39),(4,12),(5,12),(5,19),(5,26),(5,33),(5,40),(6,12),(6,21),(6,23),(8,16),(8,24),(9,17),(9,25),(10,18),(10,26),(11,19),(11,27)(13,21),(13,29),(14,22),(14,30),(15,23),(15,31)]
Ponieważ chcemy ruchu (6, 21), kodujemy go jako 13 w bazie 29, ponieważ istnieje 29 możliwych ruchów.
Teraz otrzymujemy numer gry g 2
= ((13 ⋅ 20) + 11) 20 + 13 = 5433
Następnie otrzymujemy następującą listę ruchów dla czarnych:
[(1,11),(1,16),(1,18),(2,11),(2,20),(2,29),(2,38),(2,47),(3,11),(4,11),(4,18),(4,25),(4,32),(6,21),(6,23),(8,16),(8,24),(9,17),(9,25),(10,18),(10,26),(12,20),(12,28),(13,21),(13,29),(14,22),(14,30),(15,23),(15,31)]
Ponieważ chcemy przenieść $ (10, 18) $ (10, 18)
Teraz otrzymujemy numer gry g 3
= (((19 ⋅ 29 + 13) 20) + 11) 20 + 13 = 225833
I kontynuuj ten proces dla wszystkich pozostałych ruchów. Możesz myśleć o g jako o funkcji g (x, y, z) = x y + z. Zatem g 0
= g (1, 1, 13), g 1
= g (g (1, 1, 11), 20, 13), g 2
= g (g (g (1, 1, 13), 20, 11), 20, 13), g 3
= g (g (g (g (1, 1, 19), 29, 13), 20, 11), 20, 13)
Aby zdekodować grę o numerze g 0 , zaczynamy od pozycji początkowej i wyliczamy wszystkie możliwe ruchy. Następnie obliczamy g 1 = g 0 // l , m 0 = g 0 % l , gdzie l jest liczbą możliwych ruchów, „//” jest operatorem podziału liczb całkowitych, a „%” jest operatorem modułu. Powinien przyjąć, że g 0 = g 1 + m 0 . Następnie wykonujemy ruch m 0 i powtarzamy.
W powyższym przykładzie, jeżeli g 0 = 225833 wtedy g 1 = 225833 // 20 = 11291 i m 0 = 225833% 20 = 13. Następnie g 2 = 11291 // 20 = 564 i m 1 = 11.291% 20 = 11. Wtedy g 3 = 11291 = 20 // i 564 m 2 = 11.291% 20 = 11. Dlatego g 4 = 564 // 29 = 19 and_m_ 3 = 564% 29 = 13. W końcu g 5 = 19 // 29 = 0, a m 4 = 19% 29 = 19.
Ile bitów używa się do zakodowania gry w ten sposób?
Dla uproszczenia, powiedzmy, że zawsze jest 20 ruchów na turę, aw najgorszym przypadku zawsze wybieramy największy, 19. Liczba, którą otrzymamy to 19 ⋅ 20 m
+ 19 ⋅ 20 m-1
+ 19 ⋅ 20 m-2
+ ⋯ + 19 ⋅ 20 + 19 = 20 m + 1
- 1 gdzie _m jest liczbą ruchów. Aby zakodować 20 m + 1
- 1, potrzebujemy około log 2
(20 m + 1
) bitów, czyli około (m + 1) ∗ log 2
(20) = 4,3219 ∗ (m + 1)
Średnio m = 80 (40 ruchów na gracza), więc kodowanie zajmuje 351 bitów. Gdybyśmy nagrywali wiele gier, potrzebowalibyśmy uniwersalnego kodowania, ponieważ nie wiemy, ile bitów będzie potrzebować każda liczba
Najgorszy przypadek, gdy m = 400 (200 ruchów na gracza), więc kodowanie zajęłoby 1734 bitów.
Pamiętaj, że pozycja, którą chcemy zakodować, musi zostać nam podana najkrótszą drogą, aby się tam dostać zgodnie z zasadami. Na przykład gra teoretycznie tutaj nie potrzebuje m = 11741, aby zakodować pozycję końcową. Zamiast tego uruchamiamy wyszukiwanie szerokości, aby znaleźć najkrótszą ścieżkę do tej pozycji i zamiast tego ją zakodować. Nie wiem, jak głęboko potrzebowalibyśmy zejść, by wyliczyć wszystkie pozycje w szachach, ale podejrzewam, że 400 to przecenienie.
Szybkie obliczenia:
Istnieje 12 unikatowych elementów lub kwadrat może być pusty, więc ustawienie ich na szachownicy wynosi 13 64 . Jest to ogromne przeszacowanie, ponieważ obejmuje wiele nieprawidłowych pozycji. Kiedy jesteśmy m, przenosimy się do gry, stworzyliśmy około 20 m pozycji. Szukamy więc, kiedy 20 m = 13 64 . Zaloguj obie strony, aby uzyskać m = 64 * log 20 (13) = 54,797. To pokazuje, że powinniśmy być w stanie osiągnąć dowolną pozycję w 55 ruchach.
Teraz, gdy obliczyłem najgorszy przypadek jako m = 55, a nie m = 400, wyedytuję swoje wyniki. Aby zakodować pozycję, w której m = 55 zajmuje 243 bity. Powiem też, że średni przypadek wynosi około m = 40, co wymaga 177 bitów do zakodowania.
Jeśli użyjemy argumentu amortyzacji z wcześniejszego okresu, kodujemy 400 „szachownic” w 1734 bitach, więc otrzymujemy, że każda „szachownica” zajmuje w najgorszym przypadku 4,335 bitów.
Zauważ, że g = 0 oznacza prawidłową grę, tę, w której pionek na najniższym kwadracie przesuwa się na najniższy kwadrat, jaki może.
Dodatkowe uwagi:
Jeśli chcesz odwołać się do określonej pozycji w grze, może być konieczne zakodowanie indeksu. Można to dodać ręcznie, np. Połączyć indeks z grą lub dodać dodatkowy ruch „końcowy” jako ostatni możliwy ruch w każdej turze. Może to teraz uwzględniać graczy ustępujących lub 2 z rzędu, oznaczających graczy, którzy zgodzili się na remis. Jest to konieczne tylko wtedy, gdy gra nie zakończyła się matą lub patem na podstawie pozycji, w tym przypadku jest to sugerowane. W tym przypadku liczba potrzebnych bitów wynosi średnio 356, aw najgorszym przypadku 1762.