173
POLITECHNIKA WARSZAWSKA WYDZIAŁ ELEKTRONIKI I TECHNIK INFORMACYJNYCH INSTYTUT AUTOMATYKI I INFORMATYKI STOSOWANEJ PRACA DYPLOMOWA MAGISTERSKA Jadwiga Sałacka „Szybkie algorytmy przeszukiwania drzew rozwiązań w celu znalezienia sekwencji ruchów ścianami kostki Rubika.” Opiekun pracy: prof. nzw. dr hab. Cezary Zieliński Rok akademicki 2006/2007

PRACA DYPLOMOWA MAGISTERSKA

  • Upload
    trannga

  • View
    264

  • Download
    1

Embed Size (px)

Citation preview

Page 1: PRACA DYPLOMOWA MAGISTERSKA

POLITECHNIKA WARSZAWSKA

WYDZIAŁ ELEKTRONIKI I TECHNIK INFORMACYJNYCH

INSTYTUT AUTOMATYKI I INFORMATYKI STOSOWANEJ

PRACA DYPLOMOWA MAGISTERSKA

Jadwiga Sałacka

„Szybkie algorytmy przeszukiwania drzew rozwiązań w celu znalezienia sekwencji

ruchów ścianami kostki Rubika.”

Opiekun pracy:

prof. nzw. dr hab. Cezary Zieliński

Rok akademicki 2006/2007

Page 2: PRACA DYPLOMOWA MAGISTERSKA
Page 3: PRACA DYPLOMOWA MAGISTERSKA

Specjalność: Automatyka

Data urodzenia: 23 kwietnia 1980r.

Data rozpoczęcia studiów: 1 październik 2003r.

śyciorys

Urodziłam się dnia 23 kwietnia 1980 roku w Gdańsku. Tam teŜ ukończyłam szkołę

podstawową. Naukę kontynuowałam w III Liceum Ogólnokształcącym w Gdyni, gdzie w 1999

roku zdałam egzamin maturalny. W październiku 1999 roku rozpoczęłam studia na Wydziale

Elektroniki i Technik Informacyjnych na Politechnice Warszawskiej. Studia inŜynierskie

ukończyłam na Instytucie Informatyki w zakresie budowy i oprogramowania komputerów.

Dodatkowo spełniłam wymagania programowe specjalności dodatkowych: zarządzanie

sieciami i usługami telekomunikacyjnymi oraz inŜynieria oprogramowania i systemy

informacyjne. Pracę inŜynierską obroniłam we wrześniu 2003r.. Dotyczyła ona przetwarzania

obrazów przy uŜyciu akceleratorów graficznych. Studia magisterskie rozpoczęłam w

październiku 2003r. w instytucie Automatyki i Informatyki Stosowanej na specjalności

Automatyka. Od 2001r. pracuję zawodowo na pograniczu informatyki i biznesu. Zajmuję się

analizą i modelowaniem procesów oraz wdraŜaniem systemów.

....................................................................

Podpis

EGZAMIN DYPLOMOWY

ZłoŜyła egzamin dyplomowy w dniu ............................................................................. 2007r.

z wynikiem ...............................................................................................................................

Ogólny wynik studiów ..............................................................................................................

Dodatkowe wnioski i uwagi Komisji .........................................................................................

....................................................................................................................................................

....................................................................................................................................................

Page 4: PRACA DYPLOMOWA MAGISTERSKA
Page 5: PRACA DYPLOMOWA MAGISTERSKA

STRESZCZENIE

„Szybkie algorytmy przeszukiwania drzew rozwiązań

w celu znalezienia sekwencji ruchów ścianami kostki Rubika.”

Niniejsza praca została opracowana w ramach projektu budowy systemu robota układającego kostkę Rubika, stanowiącego prezentację moŜliwości sterowników MRROC++ dla robotów usługowych. Istotą niniejszej pracy było zbudowanie programu znajdującego optymalne bądź sub-optymalne rozwiązanie dla kostki Rubika w ograniczonym czasie i zintegrowanie go z system robota. Niniejszy dokument zawiera szczególły dotyczące tego zadania oraz szczegółowe wprowadzenie w tematykę znajdywania rozwiązania kostki Rubika. Analizuje on strukturę i operatory kostki Rubika, opisuje jej model i wyjaśnia podstawy kombinatoryki w kostce. Praca stanowi równieŜ wprowadzenie do zagadnień algorytmów przeszukiwania drzew rozwiązań – zarówno prostych jak i zorientowanych. Algorytm IDA* i implementacja funkcji heurystycznej jako bazy danych wzorców, jak najbardziej uŜyteczne dla rozwaŜanego problemu, zostały opisane ze szczególną uwagą. Praca prezentuje równieŜ algorytmy przeznaczone tylko do rozwiązywania kostki Ruika i kilka implementacji tychŜe algorytmów. Dokument zawiera takŜe krótki opis struktury i pracy systemu robota zbudowanego przez Zespół Programowania Robotów.

Słowa kluczowe: kostka Rubika, algorytm IDA*, baza danych wzorców, robot usługowy

„Fast search strategies using solution tree

finding sequence of moves of Rubik’s cube faces.”

This thesis has been accomplished as a part of the project to build a robotic system solving the Rubik’s cube, which is a benchmark of MRROC++ experimental service robot controller. The main part of this thesis was to create the program to find optimal or sub-optimal solution of Rubik’s cube in limited time and to integrate it with the robotic system. This document contains all the details of this task and also in-detailed introduction to the problem of solving Rubik’s cube. It analizes structure and operators of Rubik’s cube, describes its model and explains mathematic basis of combinatorials in the cube. Document also introduces search strategies using search tree – both uninformed and informed. IDA* algorithm and implementation of heuristic function as pruning table, being most usable strategy for Rubik’s cube, has been described in more detail. Document presents also other algorithms dedicated for solving Rubik’s Cube and a few implementations of solvers. Document contains brief description of structure and main task of the robotic system built by Robot Control Team.

Key words: Rubik’s cube, IDA* algorithm, pruning table, service robot

Page 6: PRACA DYPLOMOWA MAGISTERSKA
Page 7: PRACA DYPLOMOWA MAGISTERSKA

Spis treści

1

Spis treści

Spis treści .............................................................................................................................. 1

0. Wstęp............................................................................................................................. 3 0.1. Organizacja pracy .................................................................................................................. 4

1. Puzzle ............................................................................................................................ 5 1.1. Układanki – słownik ............................................................................................................... 5 1.2. Galeria układanek .................................................................................................................. 6 1.3. Układanka o przesuwanych kafelkach................................................................................... 8 1.4. Kostka Rubika ...................................................................................................................... 11

2. Matematyka w układankach ......................................................................................... 25 2.1. Zbiory i funkcje..................................................................................................................... 25 2.2. Grupy ................................................................................................................................... 26 2.3. Permutacje ........................................................................................................................... 31 2.3.1. Podstawy na przykładzie Przesuwanki ....................................................................... 31 2.3.2. Koniugacja i komutacja na przykładzie kostki Rubika................................................. 39

3. Algorytmy..................................................................................................................... 49 3.1. God’s Algorithm.................................................................................................................... 49 3.2. Ręczne rozwiązywanie ........................................................................................................ 50 3.3. Algorytm Thistlethwaite’a ..................................................................................................... 51 3.4. Przeszukiwanie drzewa ....................................................................................................... 52 3.4.1. Słownik ........................................................................................................................ 52 3.4.2. Struktury danych ......................................................................................................... 53 3.4.3. Szkielet algorytmu ....................................................................................................... 54 3.4.4. Proste algorytmy ......................................................................................................... 55 3.4.5. Algorytmy zorientowane (poinformowane).................................................................. 58

3.5. Funkcja heurystyczna .......................................................................................................... 61 3.5.1. Wymagania ................................................................................................................. 61 3.5.2. Proste funkcje.............................................................................................................. 62 3.5.3. Baza danych wzorców................................................................................................. 63

3.6. Algorytm Kociemby .............................................................................................................. 66

4. Rozwiązania................................................................................................................. 67 4.1. Rozwiązanie Korfa ............................................................................................................... 67 4.2. Rozwiązanie Reida .............................................................................................................. 67 4.3. Rozwiązanie Kociemby........................................................................................................ 68

5. Program rozwiązujący kostkę Rubika........................................................................... 71 5.1. Budowa i zasady działania programu .................................................................................. 71 5.1.1. Elementy kombinatoryki .............................................................................................. 71 5.1.2. Fizyczne właściwości kostki Rubika............................................................................ 75 5.1.3. Wiedza o kostce Rubika.............................................................................................. 79 5.1.4. Model i algorytm Korfa ................................................................................................ 81 5.1.5. Model i algorytm Kociemby ......................................................................................... 86

5.2. Praca z programem ............................................................................................................. 92

Page 8: PRACA DYPLOMOWA MAGISTERSKA

Spis treści

2

5.2.1. Szukanie rozwiązania kostki Rubika ........................................................................... 93 5.2.2. Testy jednostkowe programu ...................................................................................... 94 5.2.3. Testy wydajnościowe programu .................................................................................. 95 5.2.4. Sprawdzenie znaczenia kodu zwracanego przez program......................................... 96

5.3. Wyniki pracy ......................................................................................................................... 96 5.3.1. Porównanie działania algorytmów Korfa i Kociemby................................................... 96 5.3.2. Dokładniejsza analiza jakości i wydajności algorytmu Kociemby ............................. 100 5.3.3. Wielkość bazy danych wzorców i czasu trwania procesu inicjalizacji ....................... 102

6. Systemem robota układającego kostkę Rubika .......................................................... 105 6.1. Krótki opis robota ............................................................................................................... 105 6.2. Praca robota....................................................................................................................... 106 6.2.1. Operacje podstawowe ............................................................................................... 106 6.2.2. Operacje złoŜone....................................................................................................... 111 6.2.3. Główne zadanie robota.............................................................................................. 116

6.3. Warianty integracji.............................................................................................................. 117 6.4. Realizacja integracji ........................................................................................................... 119 6.4.1. Opis dodanych klas ................................................................................................... 119 6.4.2. Opis dodanych plików................................................................................................ 121

7. Podsumowanie........................................................................................................... 123

Dodatek A – Dokumentacja programu CubeSolver ............................................................ 125

Dodatek B – Opis programu FOSP .................................................................................... 149

Dodatek C – Krótki opis UML............................................................................................. 161

Dodatek D – Diagramy znajdywania rozwiązania............................................................... 163

Dodatek E – Płyta CD ........................................................................................................ 165

Bibliografia ......................................................................................................................... 167

Page 9: PRACA DYPLOMOWA MAGISTERSKA

Wstęp

3

0. Wstęp Niniejsza praca magisterska przygotowana została z myślą o grancie prowadzonym w Zespole Robotyki w Instytucie Automatyki i Informatyki Stosowanej na Politechnice Warszawskiej. Przedmiotem grantu są zagadnienia związane ze sterowaniem robotów usługowych. Do prezentacji wyników wybrano system układający kostkę Rubika. Celem budowy takiego robota jest opracowanie mechanizmów sterowania osprzętem robota (chwytakiem, ramionami, kamerami, głośnikami) w celu ich późniejszego wykorzystania do budowy bardziej zaawansowanych i przydatnych w Ŝyciu codziennym robotów. Schemat budowanego systemu moŜna przedstawić następująco [[13]]:

System ten składa się z dwóch efektorów (ramion) oraz kilku czujników. Jądrem tego systemu jest MP (ang. Master Process). Wykorzystuje on informacje z czujników oraz koordynuje pracę ramion w celu wykonania zadania. Algorytm układania koski Rubika stanowi jego podproces. Budowa MP jest zaleŜna jedynie od zadania do wykonania, a niezaleŜna od sprzętu. Tutaj koncentruje się zdolność planowania działań systemu, a więc jego inteligencja. Odpowiednio realizacją działań pojedynczych robotów (ramion) zajmuje się ECP (ang. Effector Control Process). Są one równieŜ zaleŜne od zadania i niezaleŜne od sprzętu. Działają jednak na niŜszym poziomie abstrakcji i dotyczą ruchów ramion. Z ich punktu widzenia nieistotne są konkretne ruchy, jakie mają wykonać stawy ramienia, ale trajektorie, jakie ma wykonać końcówka ramienia, i ruchy, jakie ma ona wykonać (np. chwytanie, przesunięcia, obroty). Proste i odwrotne zadanie kinematyki realizowane jest w EDP (ang. Effector Driver Process). EDP jest silne zaleŜne od sprzętu. Nie zaleŜy on jednak od realizowanego przez robota zadania, przez co stanowi prawie niezmienną część sterownika. Prawidłowa implementacja

Page 10: PRACA DYPLOMOWA MAGISTERSKA

Wstęp

4

EDP dla jednego systemu pozwala na późniejsze wykorzystanie go w innych systemach wykorzystujących danego robota bez konieczności wprowadzania w nim zmian. Obok procesów EDP w systemie istnieją procesy wirtualnych czujników VSP (ang. Virtual Sensor Process). Wykorzystywane są one przez MP oraz ECP do pobierania i agregacji informacji z czujników. Podobnie jak EDP są one zaleŜne od sprzętu i niezaleŜne od zadania, przez co są prawie niezmienne. Przekształcają one informacje uzyskiwane bezpośrednio z czujników w postaci sygnałów elektrycznych bądź danych cyfrowych na dane moŜliwe do interpretacji przez moduły wyŜszego poziomu. Dzięki przyjętej modułowej architekturze systemu moŜliwe będzie wykorzystanie procesów EDP i VSP do realizacji innych zadań. Przedmiotem niniejszej pracy magisterskiej jest algorytm układania kostki Rubika oraz program realizujący go. Program ten jest częścią składową MP. Praca ta nie ogranicza się jednak do samego algorytmu. Wprowadza ona równieŜ w bogaty i ciekawy świat układanek permutacyjnych i algorytmów ich rozwiązywania. Szczególna uwaga została poświęcona układance o przesuwnych kafelkach (przesuwance). Układanka ta, jako prostszy problem, często wykorzystywana była do badania algorytmów, które później uŜyte miały zostać do rozwiązywania kostki Rubika. Dzięki swojej prostocie, układanka ta jest równieŜ bardzo przydatna do prezentacji podstaw matematycznych układanek oraz róŜnych algorytmów znajdywania rozwiązania.

0.1. Organizacja pracy

Praca zorganizowana jest w siedem integralnych części oraz dwa dodatki. Rozdział pierwszy stanowi wprowadzenie w tematykę układanek permutacyjnych. Definiuje on podstawowe terminy, przedstawia dwie układanki będące przedmiotem dalszych badań oraz moŜliwości ich implementacji. Rozdział drugi wykłada matematyczne podstawy układanek permutacyjnych. Omawia on podstawowe pojęcia, przede wszystkim grupy i permutacje. Ciekawsze zagadnienia przedstawione są na przykładach przesuwanki oraz kostki Rubika. W rozdziale trzecim przedstawiony został rozwój algorytmów stosowanych do rozwiązywania układanek. Algorytmy te dotyczą w głównej mierze kostki Rubika. Bardzo szczegółowo zostały przedstawione algorytmy przeszukiwania drzewa rozwiązań. Algorytmy te uŜywane są w wielu innych bardziej zaawansowanych algorytmach oraz są bardzo uniwersalne, co pozwala na uŜycie ich w wielu problemach. Rozdział czwarty dotyczy konkretnych realizacji algorytmów układania kostki Rubika. Przedstawione zostały w nim trzy rozwiązania, które stanowią podstawę niniejszej pracy. W piątym rozdziale opisana została zrealizowana w ramach pracy magisterskiej implementacja algorytmów rozwiązywania kostki Rubika. Dodatkowo przedstawione zostały wyniki działania zaimplementowanych algorytmów oraz porównanie ich działania. NajwaŜniejsza część pracy zawarta jest w szóstym rozdziale. Opisuje on pracę robota oraz sposób integracji zaimplementowanych algorytmów z MP robota. Rozdział siódmy stanowi wnioski z niniejszej pracy. Dodatki do pracy zawierają wyjątki z dokumentacji przygotowanych programów.

Page 11: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

5

1. Puzzle Podstawowym przedmiotem niniejszej pracy magisterskiej jest kostka Rubika. Przedmiot pracy został jednak rozszerzony o kostkę o przesuwnych kafelkach, nazywaną tutaj przesuwanką. Głównym argumentem przemawiającym za tym była moŜliwość uproszczenia badanego problemu, a co za tym idzie samych badań i ich opisu w niniejszej pracy. Zabieg ten jest często stosowany podczas implementacji nowych algorytmów. Przesuwanka się świetnie do tego nadawała ze względu na zbliŜoną naturę problemu oraz znacznie uproszczony model, czyli mniejszą liczbę stanów, a ponadto popularność tej układanki. Rozszerzenie tematu pracy ma równieŜ bardzo poŜyteczne skutki. Przedstawiana teoria jest na tyle szeroka, a algorytmy na tyle elastyczne, Ŝe wiedza przedstawiona w niniejsze pracy moŜe z łatwością zostać wykorzystana do rozwiązywania wielu podobnych problemów.

1.1. Układanki – słownik

Niniejsza praca korzysta ze słownictwa dotyczącego układanek. PoniŜej zdefiniowane są podstawowe terminy przydatne podczas lektury niniejszej pracy.

Układanka (ang. Puzzle)

Obiekt złoŜony z elementów o określonym stanie końcowym i wielu moŜliwych stanach pośrednich. Stany układanki określone są przez ułoŜenie jej elementów.

Układanka permutacyjna

Układanka, w której wszystkie dozwolone stany pośrednie mogą być osiągnięte przez stosowanie ograniczonego zestawu operatorów na stanie reprezentującym ułoŜoną układankę. Układanka ta ma ograniczoną liczbę stanów. W dalszej części pracy w skrócie nazywana po prostu układanką.

Stan układanki UłoŜenie elementów układanki względem siebie.

Operacja wykonywana na

układance

Zmiana ułoŜenia elementów układanki. Zmiana ta następuje przez ruch części jej elementów. Ruch ten jest ograniczony budową układanki i powinien zostać wykonany w całości tak, aby moŜliwe było wykonanie innego ruchu na układance.

Przesuwanka, układanka o

przesuwnych kafelkach (ang. Sliding-Tile Puzzle)

Układanka, której zestaw operatorów złoŜony jest z czterech operatorów przesuwania elementów. Układanka ta składa się z kwadratowego obszaru, w którym znajdują się kwadratowe kafelki jednakowej wielkości i jedno puste pole. Zmiana stanu obiektu odbywa się przez przesunięcie kafelka graniczącego z pustym polem na to pole.

Kostka Rubika (ang. Rubik’s Cube)

Układanka ta jest sześcianem złoŜonym z sześciennych klocków. Jej zestaw operatorów złoŜony jest z obrotów pewnego zestawu elementów. Operatory róŜnią się między sobą osią obrotu, kierunkiem i zestawem obracanych elementów. Zmiana stanu obiektu odbywa się przez obrót ściany kostki.

Page 12: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

6

1.2. Galeria układanek

Układanki moŜna podzielić na kilka grup. Niniejsza praca zajmuje się tylko układanką o przesuwnych kafelkach i kostką Rubika. PoniŜej przedstawione są jednak róŜne pokrewne układanki, dla których mogłyby zostać zastosowane podobne algorytmy rozwiązania. Ponadto poniŜsza galeria stanowi ciekawe wprowadzenie w tematykę układanek, ich róŜnorodność, ale takŜe i podobieństwa między nimi [[2]].

Rodzina Opis Przykłady

Czworościenne (Tetrahedral)

(4 osie, 4 ściany)

Czworościan, z jednokolorowymi

trójkątnymi ścianami podzielonymi na 9

identycznych mniejszych ścian trójkątnych.

Ruchem jest obrót pod-czworościanu.

Pyraminx:

Tetraminx:

Meier-Halpern pyramid:

Cube (3):

Pochodne

Cube (3):

Cube (2):

Cube (4):

Kubiczne (Cubical)

(3 osie, 6 ścian)

Kostka złoŜona z 6 jednokolorowych ścian podzielonych na 4,9 lub 16 części. Ruchem jest obrót odpowiednio 4, 9 lub 16 elementów na

jednej ścianie.

Układanki kubiczne mają wiele pochodnych, których kształt nie przypomina kostek. Istotną ich cechą jest posiadanie trzech

ortogonalnych osi, wokół których obracane są

ściany.

Cube (5):

Page 13: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

7

Ośmiościenne (Octahedral)

(4 osie, 8 ścian)

Bryła złoŜona z ośmiu ścian. Ruchem jest obrót jednej ze ścian wokół osi przechodzącej przez jej

środek.

1

12-ścienne (Dodecahedral) (6 osi, 12 ścian)

Bryła złoŜona z 12 ścian. Ruchem jest obrót ściany wokół osi przechodzącej

przez jej środek.

Dihedral

Bryła, której istotną cechą jest jej podział na dwie części, a ruch dotyczy

jednej z nich.

Bandaged

Bryła kształtem przypominająca

klasyczne układanki, ale róŜniąca się od nich osiami obrotów ścian.

Z pustymi miejscami

Istotą tej układanki jest puste miejsce

umoŜliwiające ruch. Ruchem jest przesuwanie elementu układanki na to

puste pole.

Płaskie bez pustych miejsc

Układanie tych układanek moŜliwe jest, gdyŜ na jednym elemencie układanki moŜna

wykonać kilka róŜnych ruchów – przesunięć w róŜnych kierunkach albo

obrotów.

1 Mimo iŜ układanka ta wygląda jak sześcian, ma ona 4 osie i wobec tego osiem ścian. Ścianą w tym przypadku jest bryła o pięciu ścianach – prostokątnej podstawie, dwóch kwadratowych i dwóch trójkątnych ścianach.

Page 14: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

8

1.3. Układanka o przesuwanych kafelkach

Przesuwanka została wymyślona przez Sama Loyda w 1870 roku [[6]]. Szybko zaczęła cieszyć się duŜą popularnością i pojawiła się w prasie naukowej. W duŜym stopniu przyczyniła się do tego nagroda w wysokości $1000 zaoferowana przez Loyda za opracowanie transformacji przekształcającej dowolny początkowy w dowolny stan końcowy. Jak zostało jednak później udowodnione, nie jest moŜliwa taka transformacja [[6]].

Budowa

Pierwotnie układanka ta składała się z 15 jednakowej wielkości kafelków, skąd pochodzi jej nazwa Fifteen Puzzle. Kafelki te ponumerowane są od 1 do 15. UłoŜone są one na planszy, która mogłaby pomieścić dokładnie 16 takich kafelków. Brak jednego kafelka umoŜliwia przesuwanie kafelków po planszy, skąd pochodzi nazwa całej rodziny układanek – Sliding-Tile Puzzle.

1 2 3

4 5 6 7

8 9 10 11

12 13 14 15

Stany

Stanem układanki jest ułoŜenie jej kafelków na planszy, czyli kolejność kafelków. Stanem docelowym jest ułoŜenie kafelków w kolejności rosnącej ich numerów i umieszczenie pustego pola w określonym rogu (lewym górnym). Liczba moŜliwości ułoŜenia 15 klocków na planszy o 16 polach wynosi 16!. Okazuje się jednak, Ŝe nie wszystkie stany są osiągalne. Układankę cechuje dychotomia – jej stany podzielić moŜna na parzyste i nieparzyste. Przestrzenie tych stanów są rozdzielne. Dlatego teŜ stanów moŜliwych do osiągnięcia w tej

układance jest dwa razy mniej, czyli 1410046.12

!16⋅≈ .

Operatory

Operatorem przekształcającym stany układanki jest operacja przesunięcie kafelka na graniczące z nim puste pole. MoŜna ją umownie określić jako przesuwanie pustego pola. WyróŜnić moŜna cztery operatory – przesunięcie pustego pola w górę, w dół, w lewo i w prawo. Nie wszystkie operatory są moŜliwe do zastosowania na wszystkich stanach. W szczególności, w stanach, gdzie puste pole umieszczone jest na rogu planszy dostępne są jedynie dwa operatory.

Ręczne układanie przesuwanki

Istnieje kilka przesłanek ułatwiających ułoŜenie przesuwanki. Dla układanek duŜych rozmiarów moŜna wykorzystać metodę „dziel i rządź”. W tym celu naleŜy podzielić stan układanki na dwie składowe – odpowiadającą stanowi układanki o mniejszym rozmiarze i ułoŜeniu pozostałych elementów.

Page 15: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

9

3

7

11

12 13 14 15

1 2 3

4 5 6 7

8 9 10 11

12 13 14 15

Po ułoŜeniu pozostałych elementów na docelowe ich miejsca, do rozwiązania pozostaje jedynie układanka o mniejszym rozmiarze, a co za tym idzie - o mniejszym stopniu trudności.

Inne wersje układanki

Układanka przesuwna produkowana była w róŜnych wersjach. Z punktu widzenia znajdywania rozwiązania najwaŜniejszą róŜnicą była ilość klocków układanki. I tak powstała układanka

- o 8 klockach na planszy o wymiarach 3x3 (Eight Puzzle), - o 24 klockach na planszy o wymiarach 5x5 (Twenty-Four Puzzle).

MoŜna sobie oczywiście wyobrazić układanki o jeszcze większej liczbie klocków.

MoŜliwości implementacji układanki

Nasuwającym się sposobem implementacji modelu układanki o przesuwnych kafelkach jest tabela, w której kaŜdemu polu odpowiada jedno miejsce na planszy. Liczba wpisana w polu tabeli prezentuje kafelek umieszczony w odpowiednim miejscu układanki. Reprezentacja ta jest bardzo prosta i intuicyjna. Jest ona jednak bardzo nieekonomiczna i nieuŜyteczna z algorytmicznego punktu widzenia. Korzystniejszym, ale trochę trudniejszym do implementacji rozwiązaniem jest przedstawienie stanu układanki jako permutacji2. Stan układanki prezentowany jest przy pomocy jednej liczby – numeru porządkowego permutacji, czyli spakowanej permutacji3. Dodatkowo zapewniona jest poprawność tego stanu, gdyŜ przy pomocy spakowanej permutacji moŜna zapisać jedynie permutacje. Kryterium Tabela Spakowana permutacja3

Prostota Tak Nie

Ekonomiczność Nie Tak

Standardowe rozwiązanie (wspomagane w C/C++)

Tak Nie

Zabezpieczenie przed nieprawidłowymi stanami

Nie Tak

Wykonanie operacji na stanie Zamiana zawartości dwóch pól tabeli

Rozpakowanie permutacji, wykonanie operacji i spakowanie permutacji bądź wykorzystanie tablic przekształceń

2 Termin permutacji i jego znaczenie w kontekście układanek został dokładnie przedstawiony w drugim rozdziale niniejszej pracy. 3 Spakowana permutacja liczona jest jako numer kolejny permutacji. Permutacji liczb ustawionych według rosnącej wartości odpowiada liczba zero, a permutacji liczb ustawionych według malejącej wartości odpowiada maksymalna liczba.

Page 16: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

10

Przykład Tabela Spakowana permutacja4

Przykład 1:

1 2 3

4 5 6 7

8 9 10 11

12 13 14 15

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

0

Przykład 2:

1 2 3

4 5 6 7

8 9 10 11

12 13 14 15

1 0 2 3 4 5 6 7 8 9 10 11 12 13 14 15

1 307 674 368 000

Przykład 3

15 14 13 12

11 10 9 8

7 6 5 4

3 2 1

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

20 922 789 887 999

Przykład 4:

15 14 13 12

11 10 9 8

7 6 5 4

3 2 1

15 14 13 12 11 10 9 8 7 6 5 4 3 2 0 1

20 922 789 887 998

4 Dokładny algorytm obliczania spakowanej permutacji przedstawiony jest w rozdziale 5.1.1.

Page 17: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

11

1.4. Kostka Rubika

Erno Rubik wymyślił słynną kostkę w 1974. Pierwsze kostki Rubika były produkowane przez firmę Ideal Toys w latach 80. Cieszyły się one duŜym powodzeniem. Szacuje się, Ŝe wyprodukowano ich ponad 100 milionów, a i nadal są one w produkcji. Kostka doczekała się wielu swoich wariacji. [[2]] Podobnie jak przesuwanka sto lat wcześniej, tak kostka Rubika w latach osiemdziesiątych ubiegłego wieku była światową sensacją zarówno pośród dzieci i dorosłych układających ją jak i matematyków badających jej matematyczne podstawy.

Budowa

Kostka Rubika jest sześcianem o krawędzi długości 55mm. Z zewnątrz patrząc złoŜona jest ona z 27 małych sześcianów. Powierzchnie sześcianów widoczne na zewnątrz pomalowane są na sześć kolorów: czerwony, zielony, niebieski, Ŝółty, biały i pomarańczowy.

Rysunek perspektywiczny: [[3]] Rysunek poglądowy:

Dla odróŜnienia wprowadza się pojęcia ścian i ścianek. Pierwsze oznaczają ściany całego sześcianu, które po jego ułoŜeniu są jednokolorowe. Ścianki natomiast są to ściany małych sześcianów, widoczne na zewnątrz. Ścianki ze swej natury są jednokolorowe. Na kaŜdej ściance przyklejona jest dokładniej jedna nalepka w jednym z sześciu kolorów.

Ściana: Ścianka:

KaŜda ściana i ścianka kostki ma swoją nazwę. Nazwy te są zaleŜne od umieszczenia kostki w trójwymiarowej przestrzeni, jednym rogiem w początku układu współrzędnych, a kostką w dodatniej ósmej części układu. Ściany noszą intuicyjne nazwy, czyli np. ściana połoŜona na płaszczyźnie xy, to ściana dolna, a równoległa do niej to ściana górna.

Page 18: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

12

x

z y

Symbol Nazwa

angielska Nazwa polska

PołoŜenie w trójwymiarowym układzie współrzędnych

F Front Przednia y = 0

R Right Prawa x = 1

U Up Górna z = 1

B Back Tylna y = 1

L Left Lewa x = 0

D Down Dolna z = 0

Kostka produkowana była w wielu wersjach kolorystycznych i w róŜnych źródłach moŜna znaleźć róŜne ustalenia co do kolorowania ścian, co wprowadza spore zamieszanie. Na potrzeby niniejszej pracy magisterskiej ustalone zostało jednoznaczne przyporządkowanie symbolu ściany do jego kolorowania:

Ściana Kolor

F Biały

R Niebieski

U Czerwony

B śółty

L Zielony

D Pomarańczowy

Ścianki w obrębie ściany są ponumerowane od 1 do 9. Numeracja prowadzona jest rzędami, począwszy od lewego górnego do prawego dolnego rogu ściany. Na ich nazwę składa się symbol ściany i numer ścianki w obrębie ściany. [[1]]

Page 19: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

13

L1 L2 L3

L4 L5 L6

L7 L8 L9

F1 F2 F3

F4 F5 F6

F7 F8 F9

D1 D2 D3

D4 D5 D6

D7 D8 D9

B1 B2 B3

B4 B5 B6

B7 B8 B9

U1 U2 U3 U4 U5 U6

U7 U8 U9 R1 R2 R3

R4 R5 R6

R7 R8 R9

W rzeczywistości kostka Rubika składa się z trzech typów elementów:

- trzonu, - klocków naroŜnych, - klocków na krawędziach.

Rysunek perspektywiczny: [[3]]

Trzon klocków to 6 klocków (środkowy klocek kaŜdej ścianki) połączonych ze sobą. Trzon kostki jest nieruchomy. Klocki nie zmieniają swojego wzajemnego połoŜenia. Kręcą się jedynie wokół własnych osi, aby umoŜliwić obroty pozostałym klockom. Wokół trzonu poruszają się pozostałe elementy kostki.

Rysunek perspektywiczny: [[3]] Rysunek poglądowy:

Page 20: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

14

Klocków naroŜnych jest 8. Mają one pomalowane 3 ścianki. Elementy te mogą się znajdować jedynie na rogach kostki. Klocków na krawędziach jest 16. Mają one pomalowane 2 ścianki. Elementy te mogą się znajdować jedynie na rogach kostki.

Rogi - Rysunek poglądowy: Krawędzie - Rysunek poglądowy:

KaŜdy ruchomy klocek (róg i krawędź) ma swoją nazwę. Składa się ona z symboli ścian, do których naleŜą ścianki danego klocka. I tak rogi mają trzyliterowe nazwy, a krawędzie dwuliterowe.

Rogi Krawędzie

URF UR

UFL UF

ULB UL

UBR UB

DFR DR

DLF DF

DBL DL

DRB DB

FR

FL

BL

BR

Istnieje kilka moŜliwości nazywania elementów kostki (uporządkowania literek oznaczających ściany w nazwie). W niniejszej pracy przyjęto nazewnictwo opierające się na kilku regułach:

- Nazwa krawędzi: U i D występują zawsze na początku nazwy L i R występują zawsze na końcu nazwy R i F występują bądź za U i D, bądź przed L i R.

- Nazwa rogu: U i D występują zawsze na początku nazwy Pozostałe dwie literki występują w kolejności ich występowania w kierunku

zgodnym z ruchem wskazówek zegara wokół osi przechodzącej przez rozpatrywany róg.

Page 21: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

15

Elementy kostki moŜna podzielić na 3 warstwy: dolną, środkową i górną. Podział ten jest zaleŜny od stanu i połoŜenia kostki. Jest on uŜyteczny do słownego opisu ruchów wykonywanych na kostce.

Warstwa górna Warstwa środkowa Warstwa dolna

Stany

Stanem kostki Rubika jest ułoŜenie ruchomych elementów kostki względem nieruchomych, czyli rogów i krawędzi względem trzonu. Częściami składowymi ułoŜenia oprócz pozycji elementów jest takŜe ich rotacja. I tak kaŜdy róg moŜe być zorientowany na trzy sposoby, a krawędź na dwa.

Róg: Krawędź:

Dobrze zorientowany:

Pojedynczo obrócony:

Podwójnie obrócony:

Dobrze zorientowana:

Odwrócona:

URF FUR RFU FR RF

Dzięki precyzyjnym regułom nazewnictwa elementów kostki moŜliwe jest rozróŜnienie zorientowania elementów juŜ na poziomie ich nazwy. Dla uproszczenia dalszych rozwaŜań przyjmijmy ponadto numerację elementów i ich orientacji: Krawędzie: 0 1 2 3 4 5 6 7 8 9 10 11

0 Dobrze zorientowane UR UF UL UB DR DF DL DB FR FL BL BR

1 Odwrócone RU FU LU BU RD FD LD BD RF LF LB RB

Rogi: 0 1 2 3 4 5 6 7

0 Dobrze zorientowane URF UFL ULB UBR DFR DLF DBL DRB

1 Pojedynczo obrócone FUR LUF BUL RUB RDF FDL LDB BDR

2 Podwójnie obrócone RFU FLU LBU BRU FRD LFD BLD RBD

Pozycja i rotacja rogów i krawędzi są od siebie niezaleŜne. Wobec tego liczba stanów kostki Rubika jest iloczynem liczby kombinacji tych czterech składowych, które są przedstawione w poniŜszej tabeli:

Page 22: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

16

Rodzaj elementu

Element ułoŜenia

Liczba moŜliwości (dla danego elementu)

Liczba moŜliwości (dla wszystkich elementów tego typu)

Róg Pozycja 8 8! = 40 320

Róg Rotacja 3 37 = 2 187

Krawędź Pozycja 12 12! = 479 001 600

Krawędź Rotacja 2 211 = 2 048

Jako Ŝe w kostce Rubika, podobnie jak w przesuwance, występuje zjawisko dychotomii, kostka Rubika ma około 19103252.4 ⋅ stanów, czyli dwa razy mniej niŜ wynika z wymnoŜenia liczb z powyŜszej tabelki. Jest to jeden z nielicznych przypadków, gdy rzeczywistość przerosła nawet slogany reklamowe. Kostka Rubika była bowiem reklamowana jako dająca miliony moŜliwości ułoŜenia, co stanowi niewielki procent rzeczywistej liczby moŜliwości.

Operatory

Operatorem przekształcającym permutacje kostki jest obrót jednej ściany wokół osi prostopadłej do tej ściany o zwrocie w kierunku kostki, o zadany kąt. MoŜliwe kąty obrotu to 90º, 180º i -90º (obrót w przeciwnym kierunku). W związku z tym operatorów jest 18. KaŜdy z nich ma swoją nazwę składającą się z symbolu obracanej ściany oraz informacji o kącie obrotu. Obroty o 90º oznaczone są pojedynczą literą obracanej ściany, obroty o 180º zawierają symbol 2, a o -90º apostrof (’) [[4]].

Przykładowe obroty:

Obrót F: Obrót R2: Obrót U’:

WaŜnym pojęciem związanym z ruchami jest metryka, czyli zdefiniowanie, co stanowi pojedynczy ruch. NajwaŜniejsze wyróŜniane metryki to:

- QTM (Quarter Turn Metric), gdzie pojedynczym ruchem jest obrót o ±90 stopni - HTM, FTM (Half / Face Turn Metric) – obrót jednej ściany o dowolny z trzech

dopuszczalnych kątów - STM (Slice Turn Metric) – obrót dowolnej warstwy kostki (równieŜ środkowej)

o dowolny kąt. Z przyjętej metryki wynika sposób obliczania jakości rozwiązania, czyli liczby ruchów w nim. I tak na przykład rozwiązanie składające się z ruchów U2D2F2B2R2L2 będzie oznaczało 12 ruchów w metryce QTM, 6 w HTM, a tylko 3 w STM. Badania opisywane w niniejszej pracy wykonane zostały na potrzeby robota układającego kostkę Rubika. Ruch kostką będzie się składał zatem z dwóch zasadniczych faz – chwycenia przez robota odpowiednich warstw kostki (jednym chwytakiem jednej warstwy, a drugim - dwóch) i wykonaniu obrotu. Pierwsza z tych czynności jest duŜo bardziej skomplikowana. Sam obrót zaś moŜe się odbywać o dowolny kąt. Dlatego teŜ w pracy została przyjęta metryka FTM jako odpowiednia dla problemu.

Page 23: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

17

Symetrie

Stan kostki zdefiniowany jest jako wzajemne ułoŜenie jej elementów zupełnie niezaleŜne od jej zorientowania w układzie trójwymiarowym. Np. ułoŜona kostka obrócona o 90˚ wokół własnej osi równoległej do osi z układu współrzędnych reprezentuje nadal ten sam stan kostki.

x

z y

x

z y

Jako Ŝe nazewnictwo ścian jest zaleŜne od połoŜenia kostki, nastąpiła jedynie zmiana odwzorowania nazw ścian na kolory:

Ściana Kolor pierwotny Kolor po

przekształceniu Ściana odpowiadająca nowemu kolorowi w

pierwotnym odwzorowaniu

F Biały Niebieski R

R Niebieski śółty B

U Czerwony Czerwony U

B śółty Zielony L

L Zielony Biały F

D Pomarańczowy Pomarańczowy D

Na podstawie powyŜszej tabeli moŜna zapisać to przekształcenie symbolicznie jako:

F←R, R←B, U←U, B←L, L←F, D←D, GdyŜ w istocie ściana niebieska, która pierwotnie była ścianą prawą, po przekształceniu stała się ścianą przednią, itd. Nie ma zatem znaczenia obrót całej kostki wokół własnej osi. Stany kostki powstały w wyniku obrotu kostki wokół własnej osi to w istocie ten sam stan, a przekształcenie takie moŜna nazwać symetrią. Symetria ta ma bardzo waŜne znaczenia dla algorytmów rozwiązywania kostki. Pozwala ona bowiem na znalezienie odpowiadających sobie ruchów w symetrycznych stanach. Wyobraźmy sobie na przykład stan kostki oddalony od stanu ułoŜenia tylko o ruch R i przekształćmy go tak jak w poprzednim przykładzie (przez obrócenie całej kostki o 90˚ wokół osi kostki równoległej do osi z układu współrzędnych, w którym się on znajduje).

x

z y

x

z y

Page 24: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

18

ZauwaŜmy, Ŝe w pierwszym stanie wystarczy ruch R, aby ułoŜyć kostkę, a drugim F. ZauwaŜmy równieŜ, Ŝe jest to zgodne z symbolicznym opisem przekształcenia kostki. Czyli Ŝe symetria odwzorowuje zarówno stany jak i ruchy potrzebne do ich przekształcenia w stan końcowy. Zdefiniujmy 4 podstawowe symetrie kostki jako:

- odbicia lustrzane względem płaszczyzny prostopadłej do osi z i przechodzącej przez środek środkowej warstwy kostki,

- obrotu o 90˚ wokół własnej osi kostki równoległej do osi z, - obrotu o 180˚ wokół własnej osi kostki równoległej do osi y, - obrotu o 120˚ wokół osi przechodzącej przez rogi FDL i BUR.

Schemat Przekształ-

cenie Stan początkowy Stan przekształcony

Sym

etria 1

F←F’ R←R’ U←D B←B’ L←L’ D←U

Ruch U

Ruch D’

Sym

etria 2

F←R R←B U←U B←L L←F D←D

Ruch U

Ruch U

Sym

etria 3

F←F R←L U←D B←B L←R D←U

Ruch U

Ruch D

Sym

etria 4

F←D R←B U←R B←U L←F D←L

Ruch U

Ruch B

Page 25: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

19

Symetrie kostki to oczywiście permutacje5 stanu kostki. MoŜna je zatem zapisać w postaci cyklu przekształcającego ściany na siebie. Ponadto moŜna obliczyć ich rząd. Symetria Opis permutacji w postaci cyklu Rząd permutacji / Liczba moŜliwości

1 (UD)(F)(R)(B)(L) 2

2 (FRBL)(U)(D) 4

3 (UD)(RL)(F)(B) 2

4 (FDL)(BUR) 3

Przy uŜyciu tak zdefiniowanych symetrii podstawowych kostki moŜna wyróŜnić 48 złoŜonych symetrii kostki, otrzymanych w wyniku złoŜenia symetrii podstawowych. Ich liczba to oczywiście iloczyn liczby symetrii podstawowych. Symetria podstawowa 1

0 1

Symetria podst. 2 Symetria podst. 2

0 1 2 3 0 1 2 3

0 1 7 13 19 25 31 37 43

1 2 8 14 20 26 32 38 44 0

SP4

2 3 9 15 21 27 33 39 45

0 4 10 16 22 28 34 40 46

1 5 11 17 23 29 35 41 47

Sym

. podst. 3

1

SP4

2 6 12 18 24 30 36 42 48

5 Szczegółowe wprowadzenie w tematykę permutacji zawierające informacje na temat ich interpretacji, podziału na cykle i obliczenia rzędu znajduje się w rozdziale drugim niniejszej pracy.

Page 26: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

20

Ręczne układanie kostki

Ręczne układanie kostki polega na stosowaniu określonych makrooperatorów w odpowiedniej kolejności z uwzględnieniem cech szczególnych kolejnych stanów pośrednich kostki. Makrooperatory są to ciągi operatorów, które zastosowane w ściśle określonej kolejności przekształcają w określony sposób stan kostki. WyróŜnione zostały makrooperatory słuŜące do ułoŜenia klocków krawędzi podstawy dolnej, klocków naroŜnych podstawy dolnej, klocków krawędzi ścian bocznych, klocków krawędzi podstawy górnej oraz klocków naroŜnych podstawy górnej. KaŜdy następny makrooperator jest coraz bardziej złoŜony. Stosowanie ich w odpowiedniej kolejności i na odpowiednich klockach gwarantuje ułoŜenie kostki. Rozwiązanie kostki tą metodą składa się średnio z 86 ruchów. Dokładny opis metody rozwiązywania kostki Rubika moŜna znaleźć w [[4]].

Inne wersje kostki

Podstawowa wersja kostki jest wymiaru 3x3x3. Wyprodukowane zostały równieŜ kostki o wymiarach 2x2x2, 4x4x4 i 5x5x5. Kostki te produkowane były równieŜ w formie znacznie

Page 27: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

21

odbiegającej wyglądem od kostki np. w kształcie głowy Mickey Mouse albo ze ściętymi rogami. Ponadto stworzona została zmodyfikowana wersja kostki, w której obroty wykonywane są wokół osi nieortogonalnych [[2]].

MoŜliwości implementacji układanki

Najprostszym sposobem zapamiętania stanu kostki Rubika jest przechowywanie informacji o kolorach ścianek w z góry określonej kolejności. KaŜdej ściance moŜna nadać numer od 0 do 53 i zapisać je w 54-elementowej tabeli w kolejności np. FRUBLD. Zapis taki jest bardzo prosty do zrozumienia i ręcznych przekształceń. MoŜna go bardzo szybko przekształcić na obraz kostki bez uŜycia pomocniczych narzędzi. KaŜdy ruch na kostce zdefiniowany jest jako zamiana miejscami kilku pozycji w tabeli. Stanem końcowym jest natomiast tabela wypełniona w kolejności według rosnącej wartości. Model taki ma jednak bardzo powaŜne wady – zajmuje on duŜo miejsca w pamięci i nie zabezpiecza przed nieprawidłowymi stanami. Dlatego teŜ jest on zupełnie nieprzydatny do algorytmów przechowujących w pamięci wiele stanów. Świetnie się natomiast nadaje do interfejsu między uŜytkownikiem a programem komputerowym. Pozwala na stosunkowo proste wprowadzenie stanu i sprawdzenie jego poprawności. Poprawność weryfikowana jest przez sprawdzenie liczby ścianek w kaŜdym kolorze i poprawności kolorów na rogach i krawędziach kostki. MoŜliwa jest oczywiście optymalizacja tego modelu pod kątem zajętości pamięci. Liczby przechowywane w tabeli są z zakresu 0-53. MoŜliwe jest zatem przechowanie ich na 6 bitach. Potrzeba wtedy 54*6 = 324 bitów, czyli 324/32 = 11 podwójnych słów na zapisanie informacji, która uprzednio przechowywana była na 54 podwójnych słowach. Dzięki temu zabiegowi zmniejsza się prawie 5-krotnie zuŜycie pamięci, ale i zwiększa nakład obliczeń na kaŜdy dostęp do danych o kostce (konieczne jest wyciąganie kilku bitów z jednego albo dwóch podwójnych słów). Zabieg taki jest oczywiście teoretycznie opłacalny, ale istnieją duŜo efektywniejsze moŜliwości opisu kostki, więc się go nie stosuje. Modelem odzwierciedlającym rzeczywistość jest przedstawienie kostki jako zbioru jej elementów, czyli rogów i krawędzi. Przechowywane informacje o elementach to ich pozycja i orientacja. MoŜna więc przechowywać (np. w formie tabeli) 40 liczb odpowiadających 8 i 12 parom liczb prezentujących pozycję i orientację odpowiednio rogów i krawędzi kostki. Przekształcenia stanów polegają na wykonywaniu operacji na kilku elementach kostki, których dane przekształcenie dotyczy. Model ten umoŜliwia obiektową implementację kostki, gdzie zarówno róg jak i krawędź byłyby osobnymi obiektami. KaŜdy z tych obiektów miałby metodę przesunięcia oraz odpowiednio obrotu i odwrócenia. Taka implementacja zwiększa bezpieczeństwo przekształceń kostki, gdyŜ zachowuje niezmiennik obiektów na poziomie elementów kostki.

Page 28: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

22

MoŜna sobie równieŜ wyobrazić nieco inne podejście do problemu i optymalizację ze względu na zajętość pamięci, a nie bezpieczeństwo. PoniŜej przedstawione są wymagania co do pamięci dla poszczególnych przechowywanych informacji:

Informacja Zakres wartości Potrzebna liczba bitów

Liczba przechowywanych

informacji

Łączna potrzebna liczba bitów

Pozycja rogu 0-7 3 8 24

Orientacja rogu 0-2 2 8 16

Pozycja krawędzi 0-11 4 12 48

Orientacja krawędzi 0-1 1 12 12

100

Łącznie potrzeba zatem 100 bitów, czyli 4 podwójnych słów zamiast 40 liczb (np. bajtów), co stanowi ponad dwukrotną oszczędność. Model ten stosowany jest do niektórych mniej zaawansowanych algorytmów rozwiązywania kostki Rubika. Najbardziej zaawansowaną metodą opisu stanu kostki Rubika jest zastosowanie współrzędnych nowo zdefiniowanych wymiarów:

- Orientacja rogów - Orientacja krawędzi - Permutacja rogów - Permutacja krawędzi.

Wymiar konstruowany jest jako ograniczony zbiór liczb całkowitych dodatnich. Najmniejszą wartością w wymiarze jest 0 i oznacza on stan ułoŜony, czyli np. dobrze zorientowane wszystkie rogi. Liczba pozycji w wymiarze określona jest jako liczba związanych z nimi kombinacji, czyli np. liczba wszystkich moŜliwych sposobów orientacji rogów. Przy pomocy tak zdefiniowanych wymiarów, kaŜdy stan kostki da się opisać w ich układzie współrzędnych, jako czwórkę liczb.

Współrzędna Zakres wartości współrzędnej

Optymalny system zapisu

Orientacji rogów 0 ÷ 37-1 Trójkowy

Orientacji krawędzi 0 ÷ 211-1 Binarny

Permutacji rogów 0 ÷ 8!-1 O podstawie o zmiennej długości

Permutacji krawędzi 0 ÷ 12!-1 O podstawie o zmiennej długości

A zatem do opisu stanu kostki w tym przypadku potrzebne są 4 podwójne słowa. Ponadto współrzędne są wartościami całkowitymi (int) i jako takie mogą słuŜyć do indeksowania tabel, co jest bardzo przydatne podczas poszukiwania rozwiązań kostki bardziej zaawansowanymi metodami. Operacje na stanie są bardzo czasochłonne, poniewaŜ wymagają przekształcenia współrzędnych kostki na pozycje i orientacje rogów i krawędzi, wykonanie przekształcenia na nich i następnie przekształcenie wyniku na współrzędne kostki. Mimo to model ten jest bardzo uŜyteczny i uŜywany w algorytmach wykorzystujących tabele mieszające. Ponadto warto zauwaŜyć, Ŝe podczas szukania rozwiązania nie potrzebna jest zamiana postaci rozpatrywanego stanu z czysto matematycznej na fizyczną. WaŜne jest tylko znalezienie rozwiązania, a nie moŜliwość szybkiej prezentacji wyglądu kaŜdego rozpatrywanego stanu. Najbardziej zaawansowane metody układania kostki Rubika definiują dodatkowe wymiary kostki Rubika i odpowiadające im współrzędne.

Page 29: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

23

Współrzędna Zakres wartości współrzędnej

Opis

Symetrii 0 ÷ 47 Numer symetrii zastosowanej na stanie określonym przez pozostałe współrzędne.

UDSlice 0 ÷ 14

12−

Pozycje 4 krawędzi ze środkowej warstwy UD

FlipUDSlice 0 ÷ 14

12212 −

⋅ Orientacja krawędzi oraz pozycje 4 krawędzi ze

środkowej warstwy UD

UDEdgePermutation 0 ÷ 1!8− Permutacja 8 krawędzi z warstw U i D

UDSliceSorted 0 ÷ 1!44

12−⋅

Permutacja i orientacja 4 krawędzi ze środkowej

warstwy UD

PoniŜej znajduje się krótkie porównanie omówionych metod implementacji opisu stanu kostki Rubika.

Kryterium Tabela ścianek

Zbiór elementów Współrzędne

Prostota Tak Tak / Nie Nie

Ekonomiczność Nie Nie Tak

Standardowe rozwiązanie (wspomagane w C/C++)

Tak Tak / Nie Nie

Zabezpieczenie przed nieprawidłowymi stanami

Nie Tak Tak

MoŜliwość indeksowania tabel

Nie Nie Tak

Wykonanie operacji na stanie

Zamiana zawartości 12 lub 21 pól tabeli.

Zamiana zawartości 8 lub 16 wartości pól

tabeli.

Przekształcenie współrzędnych na tabele, wykonanie operacji na

tabelach i przekształcenie wyniku na współrzędne.

Page 30: PRACA DYPLOMOWA MAGISTERSKA

Puzzle

24

PoniŜej przedstawione są dwa przykłady implementacji stanu kostki Rubika:

Przykład 1 Przykład 2

Stan

Tabela ścianek

(F) 0 1 2 3 4 5 6 7 8 (R) 9 10 11 12 13 14 15 16 17 (U) 18 19 20 21 22 23 24 25 26 (B) 27 28 29 30 31 32 33 34 35 (L) 36 37 38 39 40 41 42 43 44 (D) 45 46 47 48 49 50 51 52 53

(F) 36 37 38 3 4 5 6 7 8 (R) 0 1 2 12 13 14 15 16 17 (U) 20 23 26 19 22 25 18 21 24 (B) 9 10 11 30 31 32 33 34 35 (L) 27 28 29 39 40 41 42 43 44 (D) 45 46 47 48 49 50 51 52 53

Zbiór elem

entów

(PołoŜenie)

(Orientacja)

(PołoŜenie)

(Orientacja)

(URF) 0 0 (UR) 0 0 (UFL) 1 0 (UF) 1 0 (ULB) 2 0 (UL) 2 0 (UBR) 3 0 (UB) 3 0 (DFR) 4 0 (DR) 4 0 (DLF) 5 0 (DF) 5 0 (DBL) 6 0 (DL) 6 0 (DRB) 7 0

(DB) 7 0 (FR) 8 0 (FL) 9 0 (BL) 10 0

(BR) 11 0

(PołoŜenie)

(Orientacja)

(PołoŜenie)

(Orientacja)

(URF) 3 0 (UR) 3 0 (UFL) 0 0 (UF) 0 0 (ULB) 1 0 (UL) 1 0 (UBR) 2 0 (UB) 2 0 (DFR) 4 0 (DR) 4 0 (DLF) 5 0 (DF) 5 0 (DBL) 6 0 (DL) 6 0 (DRB) 7 0

(DB) 7 0 (FR) 8 0 (FL) 9 0 (BL) 10 0

(BR) 11 0

Współrz.

6 (Orientacji rogów) 2 186 (Orientacji krawędzi) 2 047 (Permutacji rogów) 40 319 (Permutacji krawędzi) 479 001 599

(Orientacji rogów) 2 186 (Orientacji krawędzi) 2 047 (Permutacji rogów) 40 300 (Permutacji krawędzi) 479 001 580

6 Dokładny algorytm obliczania spakowanej permutacji i kombinacji przedstawiony jest w rozdziale 5.1.1.

Page 31: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

25

2. Matematyka w układankach Zaawansowane algorytmy rozwiązywania układanek, opierają się na matematycznych podstawach. Dziedziną związaną z układankami jest teoria mnogości. W tym rozdziale zostały przedstawione podstawowe pojęcia, na których bazują algorytmy rozwiązywania układanek. Dokładniej omówione zostały permutacje jako podstawa opisu stanu i operacji na układankach.

2.1. Zbiory i funkcje

Podstawowym pojęciem w teorii mnogości zwanej równieŜ teorią zbiorów jest zbiór. Zbiór jest pojęciem pierwotnym. Oznacza nieuporządkowaną kolekcję odróŜnialnych elementów. Zapisuje się go w postaci },...,,{ 21 nxxxX = .

W przypadku układanek często mówi się o zbiorze stanów układanki. Stanem określa się konkretne ułoŜenie klocków układanki.

Funkcja f odwzorowująca zbiór X w zbiór Y ( YXf →: ) to takie przyporządkowanie, które kaŜdemu elementowi Xx∈ przyporządkowuje dokładnie jeden element Yy∈ .

Ruch wykonany na układance jest rozpatrywany jako funkcja na zbiorze stanów układanki. Występują tu jednak pewne ograniczenia, gdyŜ nie w kaŜdej układance moŜna wykonać kaŜdy ruch w kaŜdym stanie. Na przykład w układance Sliding-Tile Puzzle moŜliwość wykonania danego ruchu zaleŜy od umiejscowienia pustego pola.

Przekształcenie YXf →: jest róŜnowartościowe i nazywa się injekcją, jeŜeli przeciwobraz kaŜdego punktu Yy∈ składa się najwyŜej z jednego punktu. Przekształcenie YXf →: jest na i nazywa się surjekcją, jeŜeli przeciwobraz kaŜdego punktu Yy∈ składa się co najmniej z jednego punktu. Przekształcenie jest wzajemnie jednoznaczne i nazywa się bijekcją, gdy jest jednocześnie injekcją i surjekcją, czyli gdy przeciwobraz kaŜdego punktu Yy∈ składa się dokładnie z jednego punktu.

Wszystkie układanki są oczywiście bijekcjami. Wynika to z ich fizycznej postaci. KaŜdy ruch wykonany na układance przekształca dokładnie jeden stan w dokładnie jeden stan.

Dla funkcji, która jest bijekcją, moŜna znaleźć funkcję odwrotną ( XYf →− :1 ), która odpowiada odwrotnemu przyporządkowaniu.

W układankach kaŜdy ruch posiada swoją odwrotność, czyli ruch w przeciwnym kierunku. W przypadku kostki Rubika będzie to obrót tą samą ścianą, ale w przeciwnym kierunku (np. funkcją odwrotną do ruchu F jest ruch 'F ). W przypadku przesuwanki natomiast przesunięcie kafelka z przeciwnej strony na puste pole, czyli przesunięcie pustego pola w przeciwnym kierunku (np. funkcją odwrotną do ruchu Up jest ruch Down ).

Page 32: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

26

ZłoŜeniem funkcji YXf →: z funkcją ZYg →: jest funkcja ZXh →: określona wzorem ))(())(()( xfgxfgxh == o .

Wykonywanie kolejnych ruchów na układance to oczywiście składanie funkcji odpowiadających tym ruchom. Podczas rozwiązywania układanek najczęściej rozpatruje się funkcję przez pryzmat wyniku działania złoŜenia jej ruchów, a nie ruchy, z których jest złoŜona. Wynika to z faktu, iŜ róŜne złoŜenia funkcji mogą mieć ten sam efekt, a interesujące jest tylko najprostsze (złoŜone z najmniejszej liczby ruchów).

Funkcja identycznościowa to funkcja odwzorowująca elementy zbioru na dokładnie te same elementy.

Identycznością w przypadku układanek jest brak ruchu, bądź zastosowanie złoŜenia ruchów, które nie ma w rezultacie Ŝadnego wpływu na układankę.

Funkcja identycznościowa jest wynikiem złoŜenia funkcji ze swoją odwrotnością.

Rozwiązywanie układanki to nic innego jak poszukiwanie najprostszego złoŜenia funkcji, które będzie odwrotne do funkcji zastosowanej na ułoŜonej układance, która przekształciła ją do aktualnego stanu. ZłoŜenie tych dwóch funkcji daje oczywiście funkcję identycznościowa, która odpowiada przekształceniu ułoŜonej kostce w nią samą.

Odwrotnością złoŜenia dwóch funkcji jest 111)( −−− = fggf oo

Aby wykonać ruch odwrotny na układance do złoŜenia kilku ruchów, naleŜy wykonać ruchy przeciwne w odwrotnej kolejności.

2.2. Grupy

Grupa jest to niepusty zbiór G , w którym określone jest działanie (wewnętrzne) GhgGGhg ∈•→×∈• ),(: , mające następujące własności:

- jest łączne )()(,, khgkhgGkhg ••=••∀ ∈ ,

- ma element neutralny e : geggeGgGe =•=•∀∃ ∈∈ ,

- kaŜdy element Gg∈ ma element odwrotny (symetryczny) Gg ∈' :

eggggGgGg =•=•∃∀ ∈∈ ''' .

Działanie grupowe • wprowadza w zbiorze G strukturę grupy. Zbiór G z działaniem grupowym • oznaczamy niekiedy symbolem pary ),( •G . [[11],[12]]

W przypadku kostki Rubika grupą jest zbiór ruchów wykonywanych na stanie układanki wraz z operacją złoŜenia funkcji. Do grupy tej naleŜą wszystkie podstawowe ruchy na układance oraz wszystkie moŜliwe ich kombinacje. Wynika to z faktu, iŜ działanie • jest działaniem wewnętrznym i jego wynik na dwóch elementach z grupy zawsze znajduje się w grupie. Elementem identycznościowym tej grupy jest brak ruchu. Odwrotnością ruchu jest ruch w

Page 33: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

27

przeciwnym kierunku, a odwrotnością ruchu złoŜonego jest odwrotność tych ruchów w odwrotnej kolejności. Grupą jest równieŜ zbiór stanów układanki jako efektów wykonanych ruchów na stanie ułoŜonym z operacją ich złoŜenia. W zbiorze G znajdują się zatem wszystkie osiągalne stany układanki. KaŜdy taki stan jest matematycznie reprezentowany przez najprostsze złoŜenie funkcji, które prowadzi ze stanu początkowego (ułoŜonej układanki) do niego właśnie. Działaniem • jest wobec tego składanie tych złoŜeń funkcji.

Grupa jest skończona, gdy posiada skończoną liczbę elementów. Miarą wielkości grupy jest jej rząd oznaczany jako ||G . Oprócz tego moŜna określić rząd elementu grupy (oznaczany przez )(go ). Jest on zdefiniowany jako najmniejsza liczba naturalna n

spełniająca zaleŜność Ig n = . JeŜeli nie istnieje taka liczba, to rząd elementu jest nieskończony. W grupie skończonej wszystkie elementy są skończonego rzędu.

Grupa ruchów na stanach układanki jest nieskończona, gdyŜ nieskończona jest liczba kombinacji ruchów. Skończona jest natomiast grupa stanów układanki jako efektów wykonanych ruchów. Dlatego teŜ niniejsze opracowanie dotyczy właśnie niej. Grupa ta nazywana jest grupą kostki (ang. cube group). Dla uproszczenia nazewnictwa element tej grupy będzie nazywany ruchem. Zgodnie z wprowadzoną definicją chodzi o stan układanki będący wynikiem przekształcenia stanu początkowego (ułoŜonego) układanki przy uŜyciu tego właśnie ruchu.

Niepusty podzbiór H zbioru G jest podgrupą grupy ),( •G , jeŜeli jest on zamknięty ze względu na działanie grupowe • grupy G spełniającą warunki określone dla grupy [[12]]. Szczególnym przypadkiem podgrupy jest grupa zawierająca podzbiór }...,,{ 12 −= mgggeH , gdzie Gg∈ , ggg o=2 , a )(gom = Podgrupa taka jest grupą cykliczną rzędu mgoH == )(|| . Element g jest natomiast nazywany generatorem tej grupy. Grupa taka jest najczęściej opisywana jako: >< g . Grupa moŜe mieć równieŜ kilka generatorów i jest wtedy opisywana jako: >< nggg ,..., 21 .

Jest to najmniejsza grupa posiadająca wszystkie generatory i spełniająca wymagania grupy.

Grupa układanki generowana jest przez wszystkie podstawowe, moŜliwe do wykonania na układance ruchy (a ściślej stany będące efektem przekształcenia stanu odpowiadającego ułoŜonej układance przy uŜyciu podstawowych ruchów). Podgrupy układanki generowane są przez podzbiór ruchów (ściślej – odpowiadających im stanów) moŜliwych dla układanki. Stosowanie ruchów z podgrupy na ułoŜonej układance, prowadzi do ograniczonego zbioru stanów. Podgrupy takie są więc uŜyteczne podczas rozwiązywania układanki. Zadanie ułoŜenia moŜna bowiem przy ich pomocy przedstawić jako przechodzenie od grupy G (zawierającej wszystkie osiągalne stany układanki) do podgrupy I (zawierającej jedynie stan odpowiadający ułoŜonej układance).

Page 34: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

28

Grupa kostki Rubika generowana jest przez podstawowe ruchy, czyli

>=< DLBURFG ,,,,, . Dokładniej rzecz biorąc wystarczy dowolne pięć spośród tych ruchów do wygenerowania grupy kostki, gdyŜ kaŜdy z tych ruchów moŜna przedstawić jako złoŜenie pięciu pozostałych

(np. 'PUPD = , gdzie 2222222222 ULFLRBRULRP = ). W grupie kostki moŜna wyróŜnić szereg uŜytecznych podgrup zdefiniowanych przez pryzmat ich działania:

- Grupa ruchów nie ruszających rogów - Grupa ruchów nie ruszających krawędzi - Grupa ruchów jedynie obracających rogi - Grupa ruchów jedynie odwracających krawędzie - Grupa ruchów nie ruszających kosteczek w dwóch (na przykład) górnych warstwach - U-grupa (ang. U-group) – zbiór ruchów poruszających tylko elementy z warstwy U,

a pozostawiających pozostałe warstwy niezmienione. MoŜna równieŜ wyróŜnić podgrupy przez pryzmat ich generatorów:

- Grupa dwu-generatorowa (ang. Two-generator group) – np. >< RF , , >< RF ,2 - Grupa trój-generatorowa (ang. Three-generator group) – np. >< URF ,, - Grupa kwadratowa (ang. Square group) – np. >< 2,2,2,2,,2 DLBURF - Grupa środkowej warstwy (ang. Slice group) – >< ',',' UDRLFB - Grupa przeciwna do środkowej warstwy (ang. Anti-slice group) – >< UDRLFB ,,

Ponadto dla kostki Rubika określić moŜna nadgrupę (ang. Supergroup). Jest to grupa, gdzie rozróŜnialna jest orientacja elementów środków ścian. Grupa ta jest 2048 razy większa od grupy kostki. Reprezentacją tej grupy jest na przykład układanka róŜniąca się od kostki Rubika tylko tym, Ŝe na elementach środków ścian umieszczony jest obrazek, a ułoŜona układanka musi mieć wszystkie takie obrazki skierowane w z góry określonym kierunku.

Grupa symetryczna AS jest zbiorem funkcji róŜnowartościowych przekształcających zbiór A w A razem z operacją złoŜenia funkcji. JeŜeli zbiór A jest skończony, to grupę tą określa się jako nS , gdzie n jest licznością zbioru A , a elementy grupy nazywa się

permutacjami.

Ruchy moŜliwe do wykonania na układance tworzą oczywiście grupę symetryczną, gdyŜ przekształcają zbiór stanów układanki w tenŜe zbiór. Dlatego teŜ zarówno stany jak i ruchy na stanach określane są często mianem permutacji.

Homomorfizm jest to funkcja odwzorowująca jedną grupę w drugą ),(),(: oHG →•τ , która przeprowadza kaŜdą operację • grupy G w operację o grupy H . )()()( 2121, 21

ggggGgg τττ o=•∀ ∈ .

Ponadto homomorfizm wprowadza następujące zaleŜności: - jeŜeli Ge jest elementem neutralnym w ),( •G , to )( GH ee τ= w ),( oH

- 11 )()( −− = gg ττ dla Gg∈ - )(Gτ jest podgrupą ),( oH .

Page 35: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

29

Homomorfizm zachowuje strukturę grupy, ale nie musi być róŜnowartościowy. Jądro mówi, co zostanie zaniedbane podczas przejścia z grupy G do )(Gτ . Istnieje homomorfizm między grupą układanki o większym wymiarze a grupą układanki tego samego rodzaju o mniejszym wymiarze. Wynika to z faktu, iŜ wszystkie ruchy układanki o większym wymiarze mogą być wykonane na układance o mniejszym wymiarze, ale w uproszczonej formie. Weźmy pod uwagę kostkę Rubika i jej uproszczoną formę:

Na obu kostkach moŜna wykonać te same operacje, czyli wszystkie permutacje grupy kostki:

>=< DLBURFG ,,,,, . Podczas gdy na kostce Rubika w wyniku operacji będzie się zmieniało ustawienie zarówno rogów jak i krawędzi, w uproszczonej kostce – jedynie rogów. Wynika to oczywiście z faktu, iŜ kostka ta w ogóle nie ma krawędzi. Dla przykładu operacja R zmienia ustawienie 4 rogów i 4 krawędzi kostki Rubika, a tylko 4 rogów uproszczonej kostki:

Oznacza to, Ŝe homomorfizm przekształcając działania z grupy kostki w działania z grupy uproszczonej kostki zaniedbuje przekształcenia krawędzi. Homomorfizm ten moŜna równieŜ zinterpretować jako układanie jedynie rogów kostki Rubika. Krawędzi traktowane są wtedy jako nierozróŜnialne (na rysunku oznaczono to szarym kolorem). Dla powyŜszego przykładu po wykonaniu operacji R , kostka Rubika z nierozróŜnialnymi krawędziami wyglądałaby następująco:

Page 36: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

30

KaŜdy homomorfizm wyznacza relację równowaŜności ~ w zbiorze A jako: )()(~, babaAba ττ =⇐∀ ∈ .

Relacja ta nazywana jest równieŜ jądrem homomorfizmu i w przypadku homomorfizmu grup moŜe być wyznaczona jako przeciwobraz elementu neutralnego He grupy ),( oH w tym homomorfizmie: )(1 He

−τ [12].

Relacja równowaŜności grupuje elementy o takich samych cechach. Relacja wyznaczona przez rozwaŜany homomorfizm grupuje stany kostki Rubika, które mają takie same ustawienie rogów. Stany te rozwaŜa się jako podstany reprezentujące jedynie ustawienie rogów a pomijające ustawienie krawędzi. Wykonanie na takim podstanie operacji z jądra homomorfizmu nie zmieni tego stanu. Jądrem tego homomorfizmu będą zatem wszystkie operacje przekształcające jedynie krawędzie kostki Rubika. ZłoŜonym przykładem jest tu permutacja superflip7 zmieniająca ustawienie wszystkich krawędzi kostki Rubika, która wykonana na uproszczonej kostce stanowi permutację identycznościową:

Klasą abstrakcji elementu Aa∈ względem relacji równowaŜności ~ w zbiorze A nazywamy podzbiór elementów Ab∈ będących w relacji z a : }~|{][ abAba ∈= . KaŜdy element zbioru, na którym określona jest dana relacja równowaŜności, naleŜy do dokładnie jednej klasy abstrakcji względem tej relacji [Wiki]. Klasę abstrakcji nazywamy równieŜ klasą równowaŜności bądź warstwą. W przypadku grup definiuje się natomiast orbitę prawostronnego działania grupy G na elemencie Aa∈ jako zbiór: }:)({ GgagaG ∈= .

Klasa abstrakcji relacji równowaŜności zdefiniowanej przez rozwaŜany homomorfizm, to oczywiście zbiór wszystkich stanów kostki, które mają takie same ustawienie rogów. KaŜda klasa abstrakcji zawiera stany kostki o innym ułoŜeniu rogów. Klasy te są rozłączne, gdyŜ kostka w danym momencie moŜe mieć tylko jedno ułoŜenie rogów. Klas abstrakcji będzie natomiast tyle, ile jest moŜliwości ułoŜenia rogów. Podział zbioru na klasy abstrakcji stosowany jest do ograniczenia potrzebnych obliczeń i zmniejszenia stopnia złoŜoności układanki. Większość algorytmów rozwiązywania kostki Rubika opiera się na zbiorach warstw. W kolejnych etapach rozwiązywania część klocków jest nieistotna – traktowana jakby wszystkie te klocki były nierozróŜnialne. Dany etap polega na ułoŜeniu pozostałych elementów układanki.

7 Operacja superflip jest dokładniej opisaną w następnym podrozdziale.

Page 37: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

31

2.3. Permutacje

2.3.1. Podstawy na przykładzie Przesuwanki

Permutacją (ang. permutation) n -elementowego zbioru uporządkowanego }...{ 1 nxxX = jest kaŜdy n -wyrazowy zbiór uporządkowany złoŜony ze wszystkich

elementów zbioru X , czyli kaŜde uporządkowanie tego zbioru. Liczba wszystkich permutacji bez powtórzeń zbioru X o n róŜnych elementach jest równa !nPn = .

Inaczej mówiąc permutacja jest to ciąg utworzony z elementów pewnego zbioru. Permutacją jest ułoŜenie kafelków układanki Sliding-Tile Puzzle, ułoŜenie etykiet (kolorowych nalepek) na ściankach kostki Rubika oraz ułoŜenie elementów kostki Rubika.

Operator uporządkowania p umoŜliwia zapisanie kolejności elementów zbioru.

Prezentacja stanu jako permutacji kafelków

Na potrzeby niniejszego opracowania ustalmy, Ŝe miejsca, w których znajdować się mogą kafelki w przesuwance oraz kafelki układanki numerowane są w następujący sposób:

Miejsca: Kafelki:

0 1 2

3 4 5

6 7 8

0 1 2

3 4 5

6 7 8

Ustala to kolejność zapisu kafelków. Stan odpowiadający ułoŜonej przesuwance będzie odpowiadał kafelkom ułoŜonym w kolejności rosnącej od 0 (puste pole) do 8. Zdefiniujmy wobec tego zbiór miejsc przesuwanki jako }9..1{,1:}{ ∈−== iimmM ii .

Dodatkowo zdefiniujmy zbiór kafelków układanki jako }8..0{:}{ ∈= ii kkK , gdzie 0=i

k

reprezentuje puste pole.

Page 38: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

32

RozwaŜmy stan przesuwanki przedstawiony na poniŜszym rysunku:

3 2 5

7 1 8

4 6

MoŜna go zapisać przy uŜyciu operatorów uporządkowania jako:

604817523 pppppppp . Zapis ten określa kolejność występowania kafelków na podstawce zgodnie z przyjętą konwencją kolejności. Oznacza on, Ŝe kafelek z numerem 3 leŜy w lewym górnym rogu układanki, po jego prawej leŜy kafelek z numerem 2, itd. PowyŜszą permutację moŜna równieŜ przedstawić w postaci tabelki o dwóch rzędach. W polach pierwszego rzędu umieszczone są numery miejsc na podstawce przesuwanki. W drugim rzędzie znajdują się numery kafelków, które znajdują się na tych miejscach.

Miejsce im 0 1 2 3 4 5 6 7 8

Kafelek ik 3 2 5 7 1 8 4 0 6

ZauwaŜmy, Ŝe wartości w pierwszym rzędzie odpowiadają ustawieniu kafelków, gdy przesuwanka jest ułoŜona. Taka interpretacja jest zgodna z przyjętą definicją grupy układanki jako zbioru stanów reprezentowanych przez złoŜenie podstawowych ruchów na układance. Przedstawiany stan odpowiada sekwencji ruchów DRDLURURDDL. Stan przesuwanki moŜemy zapisać jako uporządkowany zbiór elementów zbioru K , gdzie }8..0{∈ik

odpowiada kafelkowi na pozycji i . Przedstawiona wyŜej tabela odpowiada natomiast funkcji KKS →: określonej jako )(: ij kSk = , gdzie }8..0{, ∈ji .

Funkcję tę, a co za tym idzie równieŜ stan układanki, moŜna przedstawić w formie grafu:

Punkty u góry grafu prezentują kafelki w ułoŜonej kolejności, punkty na dole – kafelki w kolejności, w której występują w rozwaŜanym stanie. Strzałki prezentują przesunięcie kafelków z pozycji początkowej do aktualnej. Przedstawiona powyŜej permutacja jest permutacją w grupie stanów układanki. Nazywana będzie dalej permutacją stanu lub po prostu stanem i oznaczana jako S . W niniejszej pracy uŜywana jest ona, gdy waŜne jest ułoŜenie układanki, a nie ciąg ruchów, który do niego doprowadził.

0 1 2 8 3 4 5 6 7

3 2 5 7 1 8 4 0 6

Page 39: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

33

Prezentacja ruchu jako permutacji miejsc

RozwaŜmy zmianę stanu przesuwanki w wyniku operacji przesunięcia kafelka ze środka układanki na puste dolne środkowe pole:

3 2 5

7 8

4 6

1

MoŜemy ją zapisać jako zmianę permutacji reprezentującej stan układanki:

0S 0 1 2 3 4 5 6 7 8

1S 3 2 5 7 1 8 4 0 6

2S 3 2 5 7 0 8 4 1 6

RozwaŜane stany róŜnią się jedynie zawartością pól o numerach 4 i 7. Ruch przesunięcia kafelka moŜemy zapisać wobec tego jako permutację zamieniającą zawartość miejsc8 o numerze 4 i 7, czyli:

M 0 1 2 3 4 5 6 7 8

C 0 1 2 3 7 5 6 4 8

Oczywiście w przypadku przesuwanki operacja ta jest dozwolona tylko, jeŜeli albo pole o numerze 4 albo pole o numerze 7 jest puste. Jest to jednak jedynie fizyczne ograniczenie układanki nie wpływające na matematyczną reprezentację ruchu. Przedstawiona powyŜej permutacja jest permutacją w grupie ruchów układanki. Nazywana będzie dalej permutacją ruchu albo po prostu ruchem i oznaczana jako R . W niniejszej pracy uŜywana jest, do opisania ciągu ruchów, a nie konkretnego ułoŜenia układanki. Matematycznie permutacja stanu (na kafelkach) i permutacja ruchu (na miejscach) się oczywiście zupełnie od siebie nie róŜnią. Obie stanowią uporządkowany zbiór cyfr. Dla odróŜnienia moŜna jednak określić, Ŝe permutacja stanu jest permutacją bezwzględną, określającą róŜnicę między stanem początkowym 0S a aktualnym stanem 1S . Permutacja

ruchu określa natomiast róŜnicę w ułoŜeniu kafelków, jaka wystapi po wykonaniu zadanego ruchu. Oznacza to, Ŝe permutacja ta moŜe być rozumiana jako względna, przyrostowa. Co więcej w wyniku złoŜenia bezwzględnej permutacji stanu 1S i przyrostowej permutacji ruchu

1R , otrzyma się bezwzględną permutację stanu 2S . W wyniku złoŜenia dwóch przyrostowych

permutacji ruchu 1R i 2R , otrzyma się natomiast przyrostową permutacją ruchu 3R ,

reprezentującą wykonanie kolejno tych dwóch ruchów. Przy pomocy permutacji ruchu 8 Stan zawartości miejsca przesuwanki oznaczony jest literą C (od angielskiego content).

Page 40: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

34

moŜna, zatem, opisać róŜnicę miedzy dowolnymi dwoma stanami. Opisuje ona jednak jedynie róŜnicę w ułoŜeniu tych dwóch stanów, a nie sekwencję ruchów do wykonania. Sekwencja ruchów do wykonania, czyli uporządkowana lista nazw ruchów do wykoania, jest równieŜ permutacją. Wynika to z faktu, iŜ kaŜdą taką sekwencję da się zapisac w postaci przyrostowej permutacji ruchu (na miejscach). Sekwencja ruchów jest jednak zapisem nieograniczonym. Przy jej pomocy moŜna stworzyć nieskończoną listę nazw ruchów. Co więcej, kilka sekwencji ruchów moŜe reprezentować jedną i tą samą permutację ruchu. Np. sekwencja:

przesunięcie kafelka w dół

oraz sekwencja: przesunięcie kafelka w dół, przesunięcie kafelka w górę, przesunięcie kafelka w dół

stanowią jedną i tą samą permutację ruchu odpowiadającą pojedynczej zamianie zawartości dwóch miejsc układanki.

Punkty stałe permutacji f przekształcającej zbiór X zdefiniowane są następująco:

})(:{)( iiiX xxfXxfFIX =∈= .

Punkty stałe permutacji ruchu

RozwaŜana permutacja ruchu reprezentująca przesunięcie kafelka ze środkowego pola w dół, posiada następujące punkty stałe.

}8,6,5,3,2,1,0{)( =RFIX X . Są to elementy, które nie zostały przesunięte w wyniku wykonania ruchu na układance. W naszym przykładzie były to kafelki na polach 0, 1, 2, 3, 5, 6 i 8, czyli wszystkie kafelki oprócz kafelka o numerze 1.

ZłoŜenie permutacji (ang. combination) f i g operujących na tym samym zbiorze X zdefiniowane jest następującym wzorem: ))(())(( xfgxfg =o .

ZłoŜenie permutacji

RozwaŜany poprzednio ruch na układance jest oczywiście złoŜeniem permutacji stanu, reprezentującej stan 604817523 pppppppp , z permutacją ruchu przesunięcia środkowego kafelka w dół. W wyniku otrzymujemy permutację stanu

614807523 pppppppp .

Stan ( 1S ): Ruch ( R ): Wynik ( 2S ):

3 2 5

7 1 8

4 6

3 2 5

7 8

4 1 6

Page 41: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

35

Jak widać pojęcia permutacji stanu i permutacji ruchu są tu rozróŜniane jedynie ze względu na kontekst, w którym występują. Informacja, którą posiadają, jest jednak identyczna. Prezentuje ona jedynie przyporządkowanie zbioru 9 cyfr na siebie. W zaleŜności od sytuacji łatwiej jednak to przyporządkowanie wyobrazić sobie jako ruch albo jako stan. Permutacja stanu 614807523 pppppppp jest zatem równieŜ permutacją ruchu, którą moŜna zapisać jako złoŜenie wielu ruchów prowadzących od ułoŜonej kostki do ułoŜenia przedstawionego na rysunku. Jest to jednak opis duŜo mniej intuicyjny i zrozumiały. RozwaŜaną operację tą moŜna zapisać przy uŜyciu grafów w następujący sposób:

Graf prezentuje kolejne przekształcenia zbioru. W pierwszym rzędzie punkty reprezentują permutację stanu początkowego (uporządkowanego) układanki. Strzałki symbolizują permutację ruchu przekształcającego układankę do rozwaŜanej permutacji stanu, zapisanej w środkowym rzędzie. Ostatni rząd prezentuje permutację stanu będącą wynikiem permutacji ruchu przesunięcia kafelka ze środkowego miejsca w dół. Operacja ta dotyczy jedynie dwóch kafelków, a dokładniej kafelka i pustego miejsca. Wyraźnie jest to zaznaczone, gdyŜ strzałki prezentujące zamianę tych dwóch jako jedyne nie są pionowe. Reprezentacja tablicowa róŜni się znacznie od reprezentacji przy uŜyciu grafu. Operacje prezentowane są tutaj od końca (zgodnie z definicją złoŜenia permutacji) - najpierw permutacja ruchu przesunięcia środkowego kafelka w dół, a potem permutacja stanu reprezentującego ułoŜenie z obrazka:

M 0 1 2 3 4 5 6 7 8 R

C 0 1 2 3 7 5 6 4 8

M 0 1 2 3 4 5 6 7 8 1S

1K 3 2 5 7 1 8 4 0 6

R - permutacja operacji przesunięcia środkowego kafelka w dół (zamiana

zawartości C na miejscach M )

1S - permutacja stanu przesuwanki przed

wykonaniem operacji R (ułoŜenie

kafelków 1K na miejscach M )

co daje w rezultacie:

M 0 1 2 3 4 5 6 7 8 2S

2K 3 2 5 7 0 8 4 1 6

2S - permutacja stanu przesuwanki po

wykonaniu operacji R (ułoŜenie kafelków

2K na miejscach M )

0 1 2 8 3 4 5 6 7

3 2 5 7 0 8 4 1 6

0S - stan początkowy, ułoŜona przesuwanka

1S - stan przesuwanki, ułoŜenie z rysunku

2S - stan przesuwanki po przesunięciu środkowego

kafelka w dół

( 0R - ciąg ruchów prowadzący ze stanu 0S do 1S .)

(R - przesunięcie środkowego kafelka w dół.)

Page 42: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

36

Inwersją permutacji jest kaŜda para elementów zbioru X , które w wyniku permutacji zamienione są miejscami, czyli: elementy ji xx , uporządkowane ji xx p , w wyniku

permutacji uporządkowane są przeciwnie: ij xx p .

Liczbę inwersji permutacji f (ang. crossing number) oznacza się przez )( fI . Na jej podstawie moŜna wyznaczyć znak permutacji, który definiuje się jako: )()1()sgn( fIf −= . Permutacja jest parzysta, gdy 1)sgn( =f oraz nieparzysta w przeciwnym przypadku. Permutacja identycznościowa jest zawsze parzysta. Podczas składania permutacji ich parzystości są dodawane.

Gdy permutacja prezentowana jest jako graf, inwersję oznacza kaŜde przecięcie się strzałek prezentujących przekształcenia elementów. Liczbą inwersji jest po prostu liczba przecięć tych strzałek. Dla permutacji z poprzedniego przykładu, przecięć takich jest 5, co oznacza, Ŝe permutacja ta jest nieparzysta.

Cykl jest to minimalny uporządkowany podzbiór XX i ⊂ taki, Ŝe ii XxfXx ∈⇒∈ )( ,

gdzie X jest zbiorem, na którym wykonywana jest permutacja. Długość cyklu nazywana jest równieŜ mocą zbioru iX . Ze względu na nią, cykle

nazywane są n -cyklami (2-cycle, 3-cycle…). Permutację moŜna podzielić na rozłączne cykle. Operacja ta nazywana jest rozkładem permutacji na cykle (ang. disjoint cycle notation). Przedstawia ona permutację X w postaci sumy cykli. Typ permutacji jest opisany jako >< nλλλ ,...,, 21 ,

jeśli w rozkładzie na cykle permutacja ma iλ cykli długości i dla ni ,...,2,1= .

MoŜna to zapisać symbolicznie jako nnλλλ ...21 21 opuszczając ii

λ , gdy 1=iλ .

Rozkład permutacji na rozłączne cykle

W rozwaŜanej wcześniej permutacji ruchu

M 0 1 2 3 4 5 6 7 8

C 0 1 2 3 7 5 6 4 8

3 2 5 7 0 8 4 1 6

Page 43: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

37

cyklem jest zamiana miejscami klocków na miejscu 4 i 7. Wynika to z faktu, iŜ jeŜeli element numer 4 naleŜy do podzbioru iX (cyklu), to musi do niego naleŜeć równieŜ element numer 7,

gdyŜ 7)4( =f . Jako Ŝe 4)7( =f do cyklu naleŜą tylko te dwa elementy. Jest to zatem 2-cykl. Wykonany dwukrotnie jest toŜsamy z permutacją identycznościową. Całą permutację moŜna przedstawić jako rozłączne cykle o postaci:

)8)(6)(5)(3)(2)(1)(0)(7,4( . Zapis ten oznacza, Ŝe elementy o numerach 4 i 7 zamieniają się w wyniku wykonania tej permutacji miejscami, a pozostałe elementy pozostają nie ruszone. W praktyce omija się w zapisie cykle o długości 1, gdyŜ nie wnoszą one Ŝadnej informacji. Jak wynika z zapisu permutacji w formie rozłącznych cyklów, permutacja jest typu 1721 . DuŜo ciekawsza sytuacja występuje w permutacji stanu układanki:

3 2 5

7 1 8

4 6

0s 0 1 2 3 4 5 6 7 8

1s 3 2 5 7 1 8 4 0 6

Tutaj rozkład na cykle nie jest taki oczywisty ani prosty. Aby go otrzymać naleŜy prześledzić przekształcenia elementów, czyli określić, które elementy zastępują które w wyniku zastosowania tej permutacji na układance:

680746851473522130 ←←←←←←←←← Następnie moŜna podzielić powyŜsze operacje na łańcuchy przekształceń:

680746851473522130 321 ←←←←←←←←←decfba

Łatwo moŜna zauwaŜyć, Ŝe w wyniku permutacji element 0 jest zastępowany przez element 3 (oznaczone cyfrą 1), ten natomiast przez element 7 (ozn. 2), który jest zastępowany przez element 0 (ozn. 3). ZaleŜność ta odpowiada cyklowi

)7,3,0( . Analogicznie odnaleźć moŜna drugi cykl, którego składowe przekształcenia oznaczone są literkami od a do f:

)4,6,8,5,2,1( . Razem w obu łańcuchach znajdują się wszystkie elementy. Wobec tego permutację tę moŜna przedstawić jako

Page 44: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

38

)4,6,8,5,2,1)(7,3,0( . Permutacja ta jest oczywiście typu 1163 .

Rzędem permutacji (ang. order of permutation) jest liczba powtórzeń tej permutacji, które trzeba złoŜyć, aby otrzymać identyczność IPPP

fo

=⋅⋅ 43421)(

... .

Jak łatwo się domyślić operację zamiany zawartości miejsc przesuwanki wystarczy powtórzyć, aby otrzymać permutację identycznościową. Fizycznie oznacza to oczywiście inną operację - przesunięcie kafelka w przeciwną stronę. Matematycznie jest to jednak dokładnie ta sama permutacja ruchu operacji zamiany zawartości na miejscach:

Wynika to z faktu, iŜ permutacja ta jest typu 1721 , czyli jest 2-cyklem. Permutację stanowiącą pojedynczy cykl o długości n wystarczy powtórzyć n razy, aby otrzymać permutację identycznościową. Operację z przykładu moŜna przedstawić na grafie jako:

Bardziej złoŜona sytuacja występuje w permutacji prezentującej stan układanki:

3 2 5

7 1 8

4 6

0s 0 1 2 3 4 5 6 7 8

1s 3 2 5 7 1 8 4 0 6

Permutacja ta jest typu 1163 , czyli jest złoŜeniem 3-cyklu i 6-cyklu. 3-cykl wystarczy powtórzyć 3 razy, aby otrzymać permutację identycznościową. Po powtórzeniu go o kaŜdą wielokrotność liczby 3, równieŜ otrzyma się permutację identycznościowa. 6-cykl naleŜy

0 1 2 8 3 4 5 6 7

0 1 2 3 4 5 6 7 8

Page 45: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

39

oczywiście powtórzyć 6 razy, aby otrzymac permutację identycznościową. Oznacza to, Ŝe rząd rozwaŜanej permutacji równy jest 6. MoŜna to pokazać jako ciąg przekształceń:

0s 0 1 2 3 4 5 6 7 8 UłoŜona układanka

1s 3 2 5 7 1 8 4 0 6

2s 7 5 8 0 2 6 1 3 4

3s 0 8 6 3 5 4 2 7 1 Elementy 3-cyklu (0,3,7) są ułoŜone

4s 3 6 4 7 8 1 5 0 2

5s 7 4 1 0 6 2 8 3 5

0s 0 1 2 3 4 5 6 7 8 Elementy obu cyklów są ułoŜone

Rząd permutacji moŜna obliczyć jako najmniejszą wspólną wielokrotność długości rozłącznych cyklów.

Na podstawie tej definicji łatwo obliczyć, Ŝe permutacje z poprzednich przykładów typu 1721 i 1163 są odpowiednio rzędu 2 i rzędu 6. Oznacza to, Ŝe drugą permutację naleŜy powtórzyć 6 razy, aby otrzymać permutację identycznościową. Natomiast pierwszą permutację wystarczy wykonać tylko 2 razy. Oznacza to równieŜ, Ŝe permutacja ta jest swoją odwrotnością.

Odwrotnością permutacji f (ang. inverse) jest permutacją g , która po złoŜeniu

z permutacją f daje identyczność: Igf =o . Oznacza się ją jako 1−f .

2.3.2. Koniugacja i komutacja na przykładzie kostki Rubika

Podstawową operacją na kostce Rubika jest obrót jednej jej ściany. Operację taką moŜna zapisać jako permutację kosteczek kostki. RozwaŜmy obrót F wykonany na ułoŜonej kostce:

a b c

h d

e f g

a b c

h d

e f g

W wyniku tej operacji w ośmiu miejscach kostki zmieniły się kosteczki. Pozycje te zostały symbolicznie oznaczone literami od a do g. W poniŜszych tabelach przedstawione są początkowe elementy na tych pozycjach, oraz elementy znajdujące się tam po wykonaniu obrotu. Ponadto tabele te zawierają zarówno nazwę elementów jak i ich opis tabelaryczny (składający się z typu i numeru elementu oraz jego orientacji zdefiniowanego w rozdziale 1.4 punkt Stany).

Page 46: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

40

Nazwa Typ Numer Orien.

a UFL Róg 1 0

b UF Krawędź 1 0

c URF Róg 0 0

d FR Krawędź 8 0

e DFR Róg 4 0

f DF Krawędź 5 0

g DLF Róg 5 0

h FL Krawędź 9 0

Nazwa Typ Numer Orien.

LFD Róg 5 2

LF Krawędź 9 1

LUF Róg 1 1

FU Krawędź 1 1

RFU Róg 0 2

RF Krawędź 8 1

RDF Róg 4 1

FD Krawędź 5 1 Korzystając z numerycznego opisu kosteczek (zapisanego według wzoru ‘numer.orientacja’), operację obrotu moŜna zapisać jako następujące przekształcenia elementów kostki:

1.50.91.80.51.81.11.90.1:

1.40.52.00.41.10.02.50.1:

←←←←

←←←←

Krawedzie

Rogi

Przekształcenia rogów są oczywiście niezaleŜne od przekształceń krawędzi, gdyŜ jak wynika z budowy kostki są to zupełnie róŜne fizycznie elementy, których nie da się zastąpić miejscami. Biorąc więc pod uwagę jedynie pozycjonowanie kosteczek, moŜna by operację obrotu zapisać jako złoŜenie dwóch rozłącznych cykli:

KrawedzieRogiF )8,5,9,1()4,5,1,0(=

Pierwszy cykl dotyczy rogów kostki i oznacza, Ŝe w wyniku obrotu róg 0 zostaje zastąpiony rogiem 1, róg 1 – rogiem 5, róg 5 – rogiem 4 i róg 4 – rogiem 0. Podobnie drugi cykl opisuje, które krawędzie się wzajemnie zastępują w wyniku wykonywanej operacji obrotu. Bardziej obrazowo moŜna opisać tą operację przy uŜyciu symbolicznych nazw ścian:

),,,)(,,,( FRDFFLUFDFRDLFUFLURFF = . Permutacja ta jest parzysta. Oznacza to więc, Ŝe nie wszystkie stany kostki są osiągalne ze stanu ułoŜenia przez obroty ściankami. W szczególności niemoŜliwe jest osiągnięcie stanu róŜniącego się od stanu ułoŜonej kostki tylko orientacją jednego elementu. Oczywiście obroty są jedynymi dozwolonymi ruchami podczas układania kostki, co ogranicza przestrzeń poszukiwań do stanów parzystych. Fakt, Ŝe tylko połowa moŜliwych do wyobraŜenia stanów układanki jest rzeczywiście osiągalna dla kostki Rubika, nazywany jest dychotomią. PowyŜsze rozwaŜania i uzyskany zapis nie odzwierciedlają jednak do końca prawdy. Jak wynika z przedstawionych wcześniej tabel, róg UFL jest zastępowany rogiem LFD , a nie DLF , jak jest zapisane w powyŜszym wzorze. Jest to oczywiście ten sam fizyczny element, tylko inaczej zorientowany. Konieczne jest zatem wprowadzenie zapisu orientacji klocków. Stanowi to oczywiście rozszerzenie przedstawionego tutaj zapisu stosowanego dla permutacji Szczegółowy sposób opisu przekształceń z uwzględnieniem rotacji zostanie przedstawiony w dalszej części rozdziału. ZłoŜenie dwóch ruchów na kostce to oczywiście złoŜenie permutacji. RozwaŜmy złoŜenie obrotów F i R , wykonanych w tej właśnie kolejności.

Page 47: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

41

a b c

h d

e f g

i

m

j

k

l

Permutację wynikową moŜna zapisać w postaci tabel: Nazwa Typ Elem. Orien

a UFL Róg 1 0

b UF Krawędź 1 0

c URF Róg 0 0

d FR Krawędź 8 0

e DFR Róg 4 0

f DF Krawędź 5 0

g DLF Róg 5 0

h FL Krawędź 9 0

i UR Krawędź 0 0

j UBR Róg 3 0

k BR Krawędź 11 0

l DRB Róg 7 0

m DR Krawędź 4 0

Nazwa Typ Elem Orien

LFD Róg 5 2

LF Krawędź 9 1

FUR Róg 0 1

DR Krawędź 4 0

BDR Róg 7 1

RF Krawędź 8 1

RDF Róg 4 1

FD Krawędź 5 1

FU Krawędź 1 1

FLU Róg 1 2

UR Krawędź 0 0

BRU Róg 3 2

BR Krawędź 11 0 Pomijając orientację elementów kostki, moŜna zapisać permutację FR jako:

KrawedzieRogiRogiFR )11,4,8,5,9,1,0()3,7,4,5,1()0(= ,

albo w symbolicznej postaci:

),,,,,,)(,,,,( BRDRFRDFFLUFURUBRDRBDFRDLFUFLFR = . Permutacja ta jest typu 1175 oraz rzędu oczywiście 35. Permutacją odwrotną do obrotu F jest obrót w przeciwnym kierunku, czyli 'F . Permutacją odwrotną do złoŜenia permutacji FR jest natomiast ''FR .

Koniugacją (ang. conjugation) dwóch permutacji P i Q jest element 'PQP .

Idea koniugacji jest bardzo uŜyteczna podczas rozwiązywania układanek. Oznacza ona, Ŝe jeŜeli wiadomo jak zamienić miejscami dwa klocki, to moŜna tą samą operację wykonać na dwóch innych. Wystarczy przesunąć je w odpowiednie miejsce, wykonać operację zamiany a następnie operację odwrotną do przesunięcia.

Page 48: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

42

Koniugacja

Wiadomo, Ŝe permutacja 2'2' URLLFRQ = zamienia miejscami trzy krawędzie:

a

b

c

Czyli moŜna ją zapisać w postaci cyklu:

),,( DFUFUBQ = . Aby wykonać podobną operację na trzech innych krawędziach np.

),,(2 UFURULQ = , naleŜy przygotować operację przesunięcia i zastosować operację koniugacji. Operacją przesunięcia w przedstawionym przypadku będzie

UFP 2= , operacją do niej odwrotną oczywiście jest:

.2'' FUP = , Koniugacja 'PQP będzie miała następujący efekt (przestawiony w kolejnych krokach):

P PQ 'PQP

b c

a

a

b

c

c

a

b

a b

c

Komutacją (ang. commutation) dwóch permutacji P i Q jest element ''QPQP . Element ten nazywany jest komutatorem (ang. commutator). JeŜeli permutacje P i Q są rozłączne, to komutator będzie permutacją identycznościową I.

Page 49: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

43

Bardzo przydatnym do układania układanek jest komutator prawie rozłącznych permutacji. Ma on wtedy bardzo ograniczony wpływ na stan układanki. Jego uŜywanie jest wystarczające do pozycjonowania kosteczek.

Prosta komutacja

Przykładem bardzo prostego komutatora jest operacja RFFR '' . Dotyczy ona jedynie siedmiu elementów kostki:

a b c

d e

f

g

Nazwa Element Orientacja

a UFL 1 0

b UF 1 0

c URF 0 0

d UR 0 0

e UBR 3 0

f FR 8 0

g DFR 4 0

Pojedyncze jej zastosowanie na ułoŜonej kostce daje w wyniku poniŜszy stan:

a b c

d e

f

g

Nazwa Element Orientacja

a RUB 3 1

b RU 0 1

c FRD 4 2

d FR 8 0

e LUF 1 1

f FU 1 1

g RFU 0 2

Operację tę moŜna zatem zapisać jako przekształcenie następujących elementów kostki:

1.10.80.80.01.00.1:

2.00.41.10.32.40.01.30.1:

←←←

←←←←

Krawedzie

Rogi,

co moŜna dalej pogrupować na:

)1.10.80.80.01.00.1(:

)2.00.42.40.0()1.10.31.30.1(:

←←←

←←←←

Krawedzie

Rogi

Oznacza to, Ŝe rogi o numerach 1 i 3 zamieniają się miejscami oraz obracają w kierunku zgodnym z ruchem wskazówek zegara. Pełen cykl przekształceń tych dwóch rogów wygląda więc następująco:

...0.12.31.10.32.11.30.1 ←←←←←←

Page 50: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

44

W skrócie wystarczy natomiast zapisać część tego cyklu oraz określić jego stosunek do całości:

−)1.3,0.1( . Zapis ten naleŜy interpretować w ten sposób, Ŝe przekształcenie podane stricte w cyklu (czyli

1.30.1 ← ) dokładnie odzwierciedla operację. Natomiast przekształcenie odwrotne (czyli 0.11.3 ← ) trzeba jeszcze zmodyfikować o orientację (zapisaną jako znak minus

w supersktypcie cyklu), czyli otrzymany element obrócić w kierunku przeciwnym do ruchu wskazówek zegara. PowyŜszy zapis cyklu opisuje równieŜ przekształcenie na wszystkich pozostałych zorientowanych elementach 1 i 3, a nie występujących w tym zapisie bezpośrednio. I tak np. korzystając z dwóch informacji: Ŝe element 2.1 to obrócony w kierunku przeciwnym do kierunku ruchu wskazówek zegara element 0.1 oraz Ŝe 1.30.1 ← , moŜna wywnioskować, Ŝe 0.32.1 ← . PowyŜszy cykl moŜna zapisać symbolicznie jako:

−),( RUBUFL . Podobnie rogi 0 i 4 zamieniają się miejscami, ale obracają się w kierunku przeciwnym do kierunku ruchu wskazówek zegara. Pełen zapis przekształceń wygląda następująco:

...0.01.42.00.41.02.40.0 ←←←←←← , co moŜna w skrócie zapisać jako:

+)2.4,0.0( , a symbolicznie:

+),( FRDURF . Ostatnią operacją wchodzącą w skład rozwaŜanej komutacji jest zamiana miejscami krawędzi 0,1 i 8 i dodatkowa ich rotacja. Występują tu dwa pokrewne ciągi przekształceń:

...1.00.11.81.0

...0.01.10.80.0

←←←

←←←.

Jako Ŝe posiadają one tylko trzy istotnie róŜne elementy moŜna je wspólnie zapisać jako:

)1.10.80.0( , a symbolicznie:

),,( FUFRUR . W efekcie rozwaŜaną operację komutacji moŜna zapisać formalnie w postaci rozłącznych cykli:

),,(),(),('' FUFRURFRDURFRUBUFLRFFR +−= . Po ponownym zastosowaniu powyŜszej komutacji otrzymuje się następujący stan:

Page 51: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

45

Nazwa Element Orientacja

a FLU 1 2

b RF 8 1

c FUR 0 1

d FU 1 1

e BRU 3 2

f UR 0 0

g RDF 4 1

Permutację tą moŜna zapisać w postaci rozłącznych cykli:

),,()()()()()''( 2 FRURFUDFRURFUBRUFLRFFR ++−−= , co moŜna wyprowadzić bezpośrednio z zapisu komutacji ''RFRF w postaci rozłącznych cykli:

),,()()()()(

)),,)(,,)(),(),)((),(),((

)),,(),(),))((,,(),(),((

)'')(''()''( 2

FRFUURDFRURFUBRUFL

FUFRURFUFRURFRDURFFRDURFRUBUFLRUBUFL

FUFRURFRDURFRUBUFLFUFRURFRDURFRUBUFL

RFFRRFFRRFFR

++−−

++−−

+−+−

=

==

==

==

Równość −−−− = )()(),(),( UBRUFLRUBUFLRUBUFL moŜna natomiast udowodnić rozpisując te cykle na ciągi przekształceń:

...0.12.31.10.32.11.30.1)1.3,0.1(),( ←←←←←←≡≡ −−RUBUFL Permutacja −),( RUBUFL podniesiona do drugiej potęgi będzie więc odpowiadała parze ciągów przekształceń:

...0.31.32.30.3

...0.11.12.10.1

←←←

←←←,

co w skrócie moŜna zapisać jako obracanie tych dwóch elementów:

−− )0.3()0.1( , a symbolicznie:

−− )()( UBRUFL Podwójnie zastosowana komutacja ''RFRF ma węŜsze działanie na stanie kostki. Obraca ona cztery rogi wokół ich osi oraz zamienia miejscami trzy krawędzie.

Page 52: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

46

Potrójne zastosowanie rozpatrywanej komutacji pozwala na osiągnięcie następującego stanu, gdy zostanie zastosowane na ułoŜonej kostce:

Nazwa Element Orientacja

a UBR 3 0

b UF 1 0

c DFR 4 0

d UR 0 0

e UFL 1 0

f FR 8 0

g URF 0 0

Odpowiada to permutacji:

),)(,()''( 3 DFRURFUBRUFLRFFR = Permutacja ta w swoim rozkładzie na rozłączne cykle nie posiada członu dotyczącego krawędzi. Wynika to z faktu, iŜ cykl obejmujący krawędzie był rzędu 3 i przy podniesieniu całej permutacji do trzeciej potęgi został zredukowany. Dzięki temu otrzymana permutacja zamienia parami cztery rogi. Permutacja ta moŜe być bardzo przydatna przy ręcznym układaniu kostki. Stanowi ona jeden z makrooperatorów, przy uŜyciu których moŜna ułoŜyć całą kostkę.

Komutacje oparte na permutacji monotwist

Komutatory oparte na permutacji monotwist są bardziej skomplikowane, ale i bardziej specjalistyczne niŜ proste komutatory. Operacja monotwist obraca pojedynczy róg kostki nie zmieniając przy tym innych elementów w jednej warstwie (w której się znajduje dany róg). Zmienia ona natomiast elementy w pozostałych dwóch warstwach. Nie ma to jednak znaczenia przy prezentowanych dalej zastosowaniach tej permutacji. Przykładową operację monotwist moŜna zapisać następująco:

+== )('' URFDRFDFRP …

Po komutacji z prostą operacją obrotu górnej warstwy, monotwist daje zaskakujące rezultaty:

−+== )()(''''''''' UBRURFRUDRFUFDDRFDFRUPUP .

Page 53: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

47

Podobne rezultaty daje komutacja permutacji monotwist z pozostałymi dwoma obrotami górnej warstwy:

−+

−+

=

=

)()(''

)()('2'2

UFLURFUPPU

ULBURFUPPU.

Komutacje te pozwalają zatem na obracanie rogu URF oraz dowolnego drugiego rogu z górnej warstwy. MoŜna oczywiście zdefiniować operację monotwist dla kaŜdego innego rogu kostki oraz komutować ją z obrotami warstwy, której ta operacja nie zmienia.

Komutacje oparte na permutacji monoflip

Komutatorem podobnym do monotwist, ale operującym na krawędziach jest monoflip. Odwraca on jedną krawędź, pozostawia niezmienione pozostałe elementy z jednej warstwy i miesza elementy w pozostałych dwóch warstwach. Np.:

+== )(222' FURUDULFUDP .

Podobnie jak monotwist, monoflip komutowane z obrotem niezmienionej warstwy daje ciekawe efekty – moŜliwość odwracania dwóch krawędzi kostki przy niezmienionych pozostałych.

Superflip

Ciekawą permutacją związaną z komutacja jest superflip. Permutacja ta komutuje z kaŜdą inną permutacją na kostce. Opisać ją moŜna jako

34 ])[( ccm DRUR ,

gdzie:

mR oznacza ruch środkową krawędzią R w kierunku wskazówek zegara,

cR obrót całą kostką tak jak przebiega obrót R,

Page 54: PRACA DYPLOMOWA MAGISTERSKA

Matematyka w układankach

48

cD obrót całą kostką tak jak przebiega obrót D.

mR cR cD

Stosując przyjęte w niniejszym dokumencie nazewnictwo operacji na kostce, operację superflip moŜna przedstawić jako:

FLFDBFRBFUBUFBURDUBDULDLUDLBRLDRLFRR '''''''''''' Wykonana na ułoŜonej kostce daje w rezultacie:

Wszystkie elementy w powyŜszej kostce są na swoich miejscach, przy czym rogi są prawidłowo zorientowane, a krawędzie odwrócone. Stan ten uznawany jest za najbardziej skomplikowany stan kostki. Jego rozwiązanie optymalne wynosi 20 obrotów:

UUBDRUBLRDFUUBRRFFBU 222''2'2222 Rozwiązanie to zostało znalezione przez Dika T. Wintera [[18]]. Jego minimalność została natomiast udowodniona przez Michaela Reida [[19]]. Dodatkowo permutacja ta wykorzystywana jest do „magicznych sztuczek”. Korzysta się w nich z faktu, iŜ permutacja ta jest tylko drugiego rzędu, czyli podwójnie wykonana daje permutację identycznościowa, a stan osiągany dzięki niej wygląda na pozornie zupełnie pomieszany.

Page 55: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

49

3. Algorytmy Problem układania układanek, w tym w szczególności przesuwani i kostki Rubika rozwaŜany był na wiele róŜnych sposobów. Zajmowały się nim dzieci, dla których zabawki te zostały stworzone, dorośli zainteresowani układankami, a w końcu i naukowcy. Problem ułoŜenia istniał teŜ w wielu wymiarach. Dla najmłodszych waŜne było po prostu ułoŜenie układanki, dla starszych zapamiętanie metody rozwiązywania, a dla naukowców zrozumienie istoty problemu i znalezienie optymalnego algorytmu rozwiązania go. Ponadto organizowane były konkursy na jak najszybsze ułoŜenie np. kostki Rubika, wielokrotnie bite były w nich rekordy czasowe. Ponadto w erze Internetu zainteresowanie budzi stworzenie wirtualnych puzzli do układania dla Internautów, przygotowanie dla nich stanów niebanalnych do ułoŜenia, a czasem nawet podpowiadanie im jak rozwiązać problem. Wszystkie te aspekty sprawiły, Ŝe wymyślono kilka róŜnych algorytmów rozwiązywania układanek. Część z nich jest uniwersalna i moŜe być zastosowana do wszystkich rodzajów układanek. Najbardziej skomplikowane jednak dotyczą juŜ konkretnej układanki. Jako Ŝe praca ta dotyczy kostki Rubika w rozdziale tym przedstawione zostaną algorytmy uŜywane do układania właśnie niej.

3.1. God’s Algorithm

Najbardziej ogólnym algorytmem jest „Algorytm Boga”. Jest to jednak algorytm czysto teoretyczny (idealistyczny). Zwraca on zawsze najkrótsze rozwiązanie. Realizowany jest jako duŜa baza danych przechowująca pary stanów. Na podstawie tej bazy algorytm dla kaŜdego stanu is zwraca stan 1+is o krok bliŜszy do rozwiązania. Pozyskane w ten sposób pary

stanów, tworzą rozwiązanie. Dla kaŜdej pary naleŜy na układance zastosować ruch im

prowadzący z pierwszego stanu do drugiego 1+=⋅ iii sms . Znalezienie tego ruchu to po prostu

identyfikacja permutacji, która złoŜona z pierwszym stanem da w wyniku drugi. MoŜna ją obliczyć jako złoŜenie odwrotności pierwszego stanu z drugim stanem: 1' +⋅= iii ssm

Baza danych „Algorytmu Boga” tworzona jest wstecz. Pierwszym rozpatrywanym stanem jest więc stan odpowiadający rozwiązaniu. Do bazy wpisywana jest kaŜda moŜliwa para tego stanu ze stanem oddalonym od niego o jeden krok. Następnie wpisywane są pary coraz bardziej oddalone od rozwiązania. Algorytm ten ma bardzo duŜe wymagania pamięciowe. Nie moŜe być wobec tego stosowany dla kostki Rubika ze względu na liczbę jej stanów ( 19103.4 ⋅ ). Przy obecnym poziomie rozwoju komputerów podstawowym problemem jest tu brak wystarczającej ilości pamięci oraz niezerowa długość czasu dostępu do niej. Gdy technologia pokona pierwsze ograniczenia, to okaŜe się prawdopodobnie, Ŝe czas potrzebny na znalezienie szukanego stanu w bazie będzie za długi, aby algorytm mógł konkurować z bardziej zaawansowanymi. Algorytm ten ma jednak bardzo duŜe znaczenie. W wielu innych, bardziej zaawansowanych algorytmach stosowane są jego róŜne modyfikacje. Mają one na celu przede wszystkim zmniejszenie zajętości pamięci przez wspomnianą bazę danych. Wykorzystują do tego takie techniki jak indeksowanie danych, kompresja danych, wykorzystanie symetrii.

a) Indeksowanie tablicy Baza danych w God’s algorithm ma przechowywać pary stanów. WaŜne jest, aby umoŜliwiała ona szybkie wyszukanie rozpatrywanego stanu, dla którego szukany jest następca. Stosowanym rozwiązaniem w takich przypadkach jest indeksowanie. Zamiast wyszukiwać w bazie danych stanu, porównując kaŜdy stan po kolei z rozpatrywanym, moŜna tym stanom przyporządkować liczby i je właśnie wyszukiwać. Liczby staną się zatem indeksami, a baza danych przybierze formę tabeli jednowymiarowej.

Page 56: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

50

b) Przechowywanie mniejszej ilości danych

Kolejną modyfikacją bazy danych jest uproszczenie danych przechowywanych w tabeli. Podobnie jak wyszukiwane mogą być liczby reprezentujące stany, tak samo przechowywane w tabeli mogą być po prostu liczby. W najprostszej postaci liczby te, podobnie jak indeksy, odpowiadają stanom. W celu dalszej redukcji zajmowanej pamięci, przechowywać moŜna jedynie odległość danego stanu od rozwiązania. W celu znalezienia więc najlepszego następnego ruchu, wystarczy sprawdzić w jakiej odległości od rozwiązania są wszystkie stany osiągalne z rozpatrywanego stanu w wyniku wykonania pojedynczego ruchu. Wybrany zostanie oczywiście stan mający w tabeli najmniejsza wartość odległości od rozwiązania. Warto przy tym zauwaŜyć, Ŝe jeŜeli wszystkie ruchy na układance mają wartość jednego kroku, to kaŜdy ruch moŜe przybliŜyć o jeden rozwiązanie, oddalić je o jeden, bądź nie zmienić odległości od niego. Są więc zasadniczo tylko 3 róŜne wartości, które muszą być przechowywane w tabeli, bez straty istotnej dla algorytmu informacji. Dzięki temu moŜna znaczniej zredukować wielkość tabeli i przechowywać w jej polach odległość do rozwiązania modulo 3. Wartość tą da się zapisać na tylko 2 bitach. MoŜna się równieŜ pokusić o kompresję.

c) Podział stanu na podstany i dodanie wymiarów tabeli Stan układanek moŜe się składać z kilku niezaleŜnych podstanów. Np. w przypadku kostki Rubika, gdzie ułoŜenie i pozycjonowanie rogów i krawędzi są od siebie niezaleŜne, moŜna wyróŜnić 4 takie podstany. Dzięki temu moŜna zwiększyć liczbę wymiarów tabeli danych do 2 bądź nawet 4 i przechowywać dane dotyczące jednego stanu na przecięciu się podstanów. Zabieg ten redukuje liczbę potrzebnych indeksów. Jest to bardzo istotne w przypadku problemów, dla których liczba stanów jest większa niŜ maksymalna liczba moŜliwa do zapisania na 4 bajtach.

d) Zastosowanie symetrii w celu redukcji wielkości tabeli. Następną istotną techniką jest wykorzystanie symetrii. Jak zostało opisane w pierwszym rozdziale ruchy na układankach są często symetryczne. To samo dotyczy takŜe ich złoŜeń. Wobec tego moŜna znacznie zredukować wielkość tabeli danych, przechowując w niej tylko reprezentanta grupy toŜsamości. Konieczne jest wtedy jednak wprowadzenie kolejnego wymiaru tabeli danych informującego o grupie toŜsamości.

e) Stworzenie tabeli rozwiązań do zadanej głębokości W przypadku znacznych ograniczeń pamięci moŜna stworzyć bazę danych jedynie do pewnej głębokości (odległości od rozwiązania). Pomysł ten znacznie odbiega od idei God’s algorithm, ale jest bardzo przydatny i często uŜywany.

3.2. Ręczne rozwiązywanie

Zupełnie innym, a wręcz przeciwnym podejściem do rozwiązywania układanek jest ich ręczne rozwiązywanie. Jest to metoda czysto praktyczna. Do jej opanowania nie jest konieczna głęboka wiedza ani przechowywanie bazy danych w pamięci. Metoda ta nie jest wykorzystywana w komputerowym poszukiwaniu rozwiązania układanek. Miała ona jednak duŜe znaczenie podczas tworzenia bardziej zaawansowanych algorytmów. Ponadto waŜna jest podstawowa wiedza na temat tego rozwiązania, podstawy matematyczne stanowiące jego istotę oraz świadomość, Ŝe jest to rozwiązanie odpowiednie dla i uŜywane tylko przez człowieka. Algorytm ręcznego rozwiązywania kostki Rubika oparty jest na makrooperacjach. Makrooperacja złoŜona jest z kilku, kilkunastu, a czasem nawet kilkudziesięciu ruchów. Ma

Page 57: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

51

ona bardzo ograniczone działanie. Realizuje operacje dotyczące małej liczby kosteczek – na ogół jednej bądź dwóch. Działanie makrooperacji oparte jest na własnościach koniugacji i komutacji. Algorytm ręcznego układania kostki podzielony jest na kilka etapów. Etapy te mają za zadanie ułoŜyć kolejno wszystkie elementy kostki począwszy od krawędzi dolnej warstwy, a skończywszy na rogach górnej. Na początku układane są krawędzie dolnej warstwy – jednocześnie ustawiane są one we właściwej pozycji i orientacji. Operacje słuŜące do tego są bardzo proste, składają się z najwyŜej kilku ruchów. Wynika to z faktu, iŜ operacje te skupiają się na czterech krawędziach, a pozostałe elementy traktują jako nierozróŜnialne. Następnym etapem jest ułoŜenie rogów dolnej warstwy. Podobnie jak poprzednio – jednocześnie ich pozycji i orientacji. W wyniku otrzymuje się kostkę z ułoŜoną jedną warstwą. Warto zauwaŜyć, Ŝe jest to więcej niŜ ułoŜona jedna ścianka (często jedyny osiągalny cel układania kostki przez dzieci). W przypadku ułoŜonej ścianki moŜe wystąpić sytuacja, Ŝe krawędzie nie znajdują się na swoich miejscach. WaŜne jest tylko, aby na jednej ściance znalazły się nalepki jednego koloru. Trzecim etapem ręcznego układania kostki jest pozycjonowanie i orientacja krawędzi znajdujących się w środkowej warstwie. Jest to ostatni etap, do którego wielu graczy jest w stanie dojść metodą prób i błędów. Makrooperacje składają się tutaj juŜ z prawie dziesięciu operacji. Ponadto oprócz ułoŜenia jednego elementu muszą pozostawić niezmienionych co najmniej osiem. Mimo Ŝe po tym etapie większość kosteczek jest juŜ na swoich miejscach, do wykonania pozostają jeszcze najtrudniejsze etapy. W etapach tych wykonuje się większość operacji koniecznych do ułoŜenia kostki. Etapy te polegają kolejno na pozycjonowaniu krawędzi, ich orientacji, a następnie pozycjonowaniu rogów i na samym końcu ich orientacji. Makrooperacje w tych etapach są juŜ bardzo złoŜone. Ponadto kaŜda pomyłka grozi koniecznością układania kostki od początku. Wynika to z faktu, iŜ makrooperacje powinny być wykonane w całości i dopiero wtedy widoczny jest ich efekt. Po wykonaniu tylko części operacji, kostka jest zupełnie pomieszana. Rozwiązanie uzyskiwane metodą ręcznego układania kostki jest oczywiście bardzo dalekie od optymalnego. Średnio składa się ono z ok. 80 ruchów. Jest ono jednak moŜliwe do zapamiętania i daje gwarancje rozwiązania.

3.3. Algorytm Thistlethwaite’a

We wczesnych latach osiemdziesiątych Morwen B. Thistlethwaite w oparciu o algorytm ręcznego układani kostki opracował swój własny algorytm. Jego idea jest zbliŜona do poprzedniego, tyle tylko, Ŝe etapy algorytmu wyznaczone są na matematycznych, a nie wizualnych podstawach. Algorytm podzielony jest na 4 etapy. Ponadto wyróŜnionych zostało 5 grup stanów kostki:

- G0=<U,D,R,L,F,B> - G1=<U,D,R2,L2,F,B> - orientacja krawędzi - G2=<U,D,R2,L2,F2,B2> - G3=<U2,D2,R2,L2,F2,B2> - G4=I.

Grupa G0 jest to grupa kostki. Znajdują się w niej wszystkie moŜliwe stany kostki. Kolejne grupy zawierają coraz mniej stanów. Ich wizualna reprezentacja nie jest tak łatwa, jak w przypadku poprzedniego algorytmu. Grupa G1 zawiera na przykład tylko stany kostki o dobrze zorientowanych krawędziach. Stany takie nie są łatwe do obserwacji (przez człowieka), gdyŜ krawędzie nie muszą być na swoich miejscach i nie zawsze widać czy są wobec tego dobrze zorientowane czy nie.

Page 58: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

52

KaŜda następna grupa, zdefiniowana dla algorytmu, zawarta jest w poprzedniej. Jej generatorem jest coraz bardziej zawęŜony zbiór operatorów. Ostatnia grupa, G4, zawiera juŜ tylko 1 element, czyli identyczność odpowiadającą ułoŜonej kostce. Celem kaŜdego etapu jest przeprowadzenie stanu kostki do następnej grupy przy pomocy dostępnych w danej grupie operatorów. Rozwiązanie uzyskiwane w tej metodzie wynosi w najgorszym przypadku 45 ruchów, odpowiednio 7, 10, 13 i 15 ruchów w etapie. Średnim wynikiem są zaś 31 ruchy (4.6+7.8+8.8+10.1=31.3).

3.4. Przeszukiwanie drzewa

Bardzo uniwersalną i często stosowaną metodą rozwiązywania róŜnego rodzaju zadań jest przeszukiwanie drzewa rozwiązań. Polega ona na tworzeniu drzewa zawierającego stany problemu i rozwijaniu go w kierunku rozwiązania. Istnieje wiele strategii przeszukiwania drzewa mających na celu dotarcie do rozwiązania jak najmniejszym kosztem. Przeszukiwanie drzewa w wielu publikacjach rozpatrywane było jako najlepsza metoda znajdywania rozwiązania układanek – przesuwanki i kostki Rubika. Później opracowane bardziej efektywne algorytmy równieŜ korzystają z tej metody. Dlatego teŜ algorytmy przeszukiwania drzewa zostały dokładnie opisane w niniejszej pracy.

3.4.1. Słownik

Dla ustalenia uwagi, poniŜej zdefiniowane są podstawowe pojęcie stosowane podczas opisywania algorytmów przeszukiwania drzewa.

Drzewo rozwiązań – (ang. Search tree), drzewo, w którym węzły reprezentują stany, a gałęzie – operatory prowadzące ze stanu rodzica do stanu dziecka. Korzeniem drzewa jest stan początkowy obiektu, do którego przypisane jest dane drzewo.

Rozwiązanie – (ang. Solution), węzeł odpowiadający stanowi końcowemu. Węzeł ten określa jednoznacznie ścieŜkę ze stanu początkowego

Przeszukiwanie drzewa rozwiązań – znalezienie w drzewie rozwiązań węzła odpowiadającego stanowi końcowemu spełniającemu zadane kryteria. Częstym kryterium jest minimalny koszt ścieŜki. Wyszukiwanie odbywa się przy uŜyciu algorytmu wyszukiwania.

Strategia przeszukiwania – (ang. Search Strategy), metoda wybierania kolejnego węzła do sprawdzania, czy odpowiada on stanowi końcowemu. RozwaŜa się cztery kryteria algorytmu

Stany

Operatory Rodzic

Dziecko

Korzeń

Liście

Page 59: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

53

przeszukiwania: zupełność, złoŜoność czasowa, złoŜoność pamięciowa i optymalność.

Zorientowany algorytm przeszukiwania – (ang. Informed Search Strategy), algorytm przeszukiwania, w którym decyzja o wyborze kolejnego węzła do rozwinięcia zaleŜy od znanych właściwości obiektu, którego dotyczy. Właściwości te wyraŜone są w postaci matematycznej przez funkcję heurystyczną.

Funkcja heurystyczna – (ang. Heuristic Function), funkcja znajdująca przybliŜony koszt ścieŜki od zadanego stanu do stanu końcowego w drzewie rozwiązań obiektu. Aby otrzymać rozwiązanie optymalne, koszt ten nie moŜe być większy od faktycznego.

Baza danych wzorców – (ang. Pattern Database), zestaw kosztów ścieŜki odpowiadających stanom obiektu w ograniczonej przestrzeni stanów.

3.4.2. Struktury danych

Wyszukiwanie rozwiązań w drzewie wymaga określonych struktur danych. NajwaŜniejszymi z nich są: węzeł drzewa, kolejka przechowująca węzły do rozwinięcia oraz samo drzewo. Ponadto reprezentowane muszą być: sam rozwiązywany problem oraz stany obiektu, którym się on zajmuje.

Stan

struct STATE { // przechowuje dane opisujące stan rozwaŜanego obiektu }

Stan przechowuje dane obiektu, specyficzne dla rozwiązywanego problemu. Struktura stanu jednoznacznie opisuje stan, w którym znajduje się obiekt.

Problem

struct PROBLEM { STATE initial_state; //stan początkowy STATE goal_state; //stan docelowy OPER* GetValidOpers(STATE state); //zwraca operacje moŜliwe do

//wykonania na danym stanie STATE Execute(STATE state, OPER oper); //wykonuje zadaną operację na

//zadanym stanie }

Problem musi w szczególności mieć wyspecyfikowany stan początkowy i docelowy. Ponadto przy uŜyciu tej klasy konieczna jest moŜliwość stosowania operatorów na stanach i uzyskiwanie kolejnych stanów.

Węzeł (Liść, ang. a node)

struct NODE { STATE state; //stan w przestrzeni stanów, któremu odpowiada węzeł NODE parent_node; //rodzic OPERATOR operator; //operator, przy pomocy którego został

//wygenerowany węzeł INT depth //głębokość, odległość węzła od korzenia

Page 60: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

54

INT path_cost //koszt ścieŜki od stanu początkowego do węzła Init(STATE state, OPERATOR operator=NULL, INT depth=0, INT

path_cost=0); //tworzy węzeł na podstawie podanych argumentów }

Węzeł drzewa przechowuje informacje o odpowiadającym mu stanie kostki, operacji, przy pomocy której został stworzony ze swojego rodzica, oraz o długości i koszcie ścieŜki, która prowadzi do tego stanu.

Kolejka (ang. queue, fringe, frontier)

struct QUEUE<ELEM> { VECTOR<ELEM> elements; //ułoŜone elementy kolejki Init(ELEM *elems, FNC enqueue); //tworzy kolejkę z określonymi

//elementami i strategią wkładania nowych węzłów do kolejki BOOLEAN IsEmpty(); //sprawdza czy kolejka jest pusta ELEM PopFront(); //usuwa i zwraca element z początku kolejki Enqueue(ELEM elem); //wkłada element do kolejki zgodnie ze

//strategią kolejki }

Kolejka przechowuje stany, które będą w przyszłości po kolei sprawdzane w algorytmie, czy nie są stanami docelowymi. W przypadku negatywnej weryfikacji będą one rozwijane, a ich potomkowie dołączani do kolejki. Kolejka umoŜliwia: sprawdzenie, czy posiada ona elementy, wyjęcie z niej pierwszego elementu oraz dołoŜenie elementów. WaŜne jest, w jaki sposób dołączane są te elementy. KaŜdy algorytm uŜywa róŜnej implementacji metody Enqueue.

Drzewo (ang. Tree)

struct TREE<NODE> { NODE root; //korzeń drzewa TREE<NODE> children; //potomkowie - poddrzewa Init(NODE root); //tworzy drzewo o określonym korzeniu Add(NODE child, NODE parent); //dodaje węzeł do wskazanego rodzica Delete(NODE child); //usuwa węzeł i całe poddrzewo, którego jest on

//korzeniem }

Drzewo przechowuje wszystkie węzły, w szczególności korzeń, czyli węzeł początkowy. Ponadto umoŜliwia ono wstawienie nowego węzła oraz wyszukanie i usunięcie wskazanego węzła.

3.4.3. Szkielet algorytmu

Wiele algorytmów przeszukiwania drzewa rozwiązań opiera się na następującym szkielecie algorytmu:

function SEARCH_SOLUTION_TREE(PROBLEM problem, FNC enqueue) : NODE { TREE<NODE> tree; //drzewo węzłów QUEUE<NODE> queue; //kolejka węzłów NODE node; //rozwaŜany węzeł

Page 61: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

55

OPER* opers; //operacje moŜliwe do wykonania na aktualnym stanie STATE state; //kolejny stan NODE child; //węzeł tworzony dla kolejnego stanu node.Init(problem.initial_state); tree.Init(node); queue.Init(node, enqueue); loop do { // brak rozwiązania If queue.IsEmpty() then return NULL; // sprawdzenie czy następny element z kolejki jest rozwiązaniem node = queue.PopFront(); If node.state = problem.goal_state then return node; // rozwinięcie rozwaŜanego węzła opers = problem.GetValidOpers(node.state); for each oper in opers do { state = problem.Execute(node.state, oper); child.Init(state,oper,node.depth+1,node.path_cost+oper.cost); tree.Add(child, node); queue.Enqueue(child); } } }

Przeszukiwanie drzewa polega na przeszukiwanie węzłów drzewa w celu sprawdzenia, czy nie określają one stanu docelowego. Pierwszym branym pod uwagę węzłem jest korzeń, a następnie jego dzieci. Kolejność sprawdzania dzieci wyznaczana jest przez kolejność, w jakiej dzieci ustawione są w kolejce. Po sprawdzeniu, czy węzeł związany jest ze stanem docelowym następuje zwrócenie wyniku (w przypadku pozytywnej weryfikacji) bądź kontynuacja poszukiwań (w przeciwnym przypadku). Kontynuacja polega na dołączeniu potomków rozpatrywanego węzła do kolejki oraz sprawdzeniu, czy następny element jest docelowym. Przeszukiwanie odbywa się aŜ do znalezienia rozwiązania (sukces) bądź bezskutecznego wyczerpania wszystkich moŜliwości (poraŜka). Wynikiem wyszukiwania w przypadku sukcesu jest węzeł odpowiadający rozwiązaniu. Jako Ŝe kaŜdy węzeł zna swojego rodzica i operację tworzącą go, znana jest równieŜ sekwencja operacji prowadząca ze stanu początkowego do rozwiązania. Algorytm wyszukiwania rozwiązań w drzewie oceniany jest ze względu na kryteria:

- Zupełności (ang. completeness) – czy na pewno znajdzie rozwiązanie, jeśli ono istnieje,

- ZłoŜoności czasowej (ang. time complexity) – jak długo będzie szukać, - ZłoŜoności pamięciowej (ang. space complexity) – jak duŜo pamięci będzie

potrzebować, - Optymalności (ang. optimality) – czy znajduje najlepsze rozwiązanie, jeśli jest ich

kilka.

3.4.4. Proste algorytmy

Proste (ślepe) algorytmy przeszukiwania drzewa przeszukują drzewo rozwiązań bez posiadania Ŝadnych dodatkowych informacji o właściwościach obiektu. Opierają się one głównie na szkielecie algorytmu wyszukiwania rozwiązań w drzewie. RóŜnice między nimi

Page 62: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

56

wynikają z zastosowania róŜnych implementacji funkcji dołączania nowych elementów do kolejki węzłów czekających na sprawdzenie. PoniŜej krótko opisane są algorytmy z tej grupy.

a) Szukanie wszerz (ang. breadth-first search) Algorytm polega na przeszukiwaniu węzłów drzewa kolejno rzędami, czyli w kolejności według odległości od korzenia. W celu realizacji tego algorytmu funkcja Enqueue dołącza kolejne eksplorowane stany na koniec kolejki stanów do rozpatrzenia.

b) Szukanie według najniŜszego kosztu (ang. uniform cost search)

Metoda ta odnosi się do problemów, które mają przypisany koszt do operacji. MoŜe to być na przykład długość drogi w km między miastami dla problemu komiwojaŜera. Wtedy celem jest wybranie ścieŜki, która minimalizuje właśnie ten koszt. W tym celu po dodaniu nowego stanu do kolejki, wszystkie elementy w kolejce sortowane są według rosnącego kosztu ścieŜki. Dzięki tej operacji najwcześniej eksplorowane są stany o najmniejszym koszcie. Stwierdzenie to jest oczywiście prawdziwe, gdy koszt kaŜdej operacji jest nieujemny.

c) Szukanie w głąb (ang. depth-first search)

W przeciwieństwie do strategii szukania wszerz, tutaj stany badane są gałęziami (kolumnami), a nie rzędami. Funkcja Enqueue dołącza wobec tego kolejne eksplorowane stany na początku kolejki. Strategia ta ma sens jedynie w przypadku skończonych problemów, których drzewo rozwiązań jest rzeczywiście skończonym drzewem oraz nie jest grafem z cyklami9. Ponadto nie daje ona gwarancji znalezienia najlepszego rozwiązania.

9 Problem cykliczności grafu moŜna rozwiązać przez modyfikację metody rozszerzania drzewa tak, aby nie były do niego wstawiane juŜ rozpatrzone węzły.

1 (cost = 0)

2 (c=15) 4 (c=25)

3 (c=20) 6 (c=35) 5 (c=30)

25 15

5 20 5

1

2 3

4 5 6

Page 63: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

57

d) Szukanie w głąb do ograniczonej głębokości (ang. depth-limited-search)

Algorytm ten oparty jest o poprzedni algorytm. Rozwiązuje on problem przeszukiwania jednej gałęzi w nieskończoność. Określa on bowiem pewną głębokość, poniŜej której nie rozwija węzłów. Problemem pozostaje jednak określenie tej głębokości.

e) Iteracyjne szukanie w głąb do ograniczonej głębokości (ang. iterative deepening search)

Określenie głębokości, do której algorytm ma szukać rozwiązania, co jest konieczne dla poprzedniego przypadku, jest bardzo kłopotliwe. Szukając rozwiązania na ogół nie wiadomo gdzie ono moŜe być. Algorytm iteracyjnego szukania w głąb do określonej głębokości nie korzysta z poprzedniego statycznego określenia maksymalnej głębokości, tylko dynamicznie zwiększa ją wraz z bezowocnym przeszukiwaniem warstw wyŜszych. Algorytm ten stanowi hybrydę algorytmów breadth-first i depth-first. Posiada ich zalety, czyli wyszukuje optymalne rozwiązanie zajmując jednocześnie mało pamięci.

f) Wyszukiwanie dwukierunkowe (ang. bidirectional search) Algorytm ten polega na przeszukiwaniu dwóch drzew dotyczących tego samego problemu, ale o róŜnych korzeniach – stanu początkowego i końcowego. Wyszukiwanie odbywa się zatem jednocześnie w dwóch kierunkach. Algorytm kończy się, gdy w jednym i drugim drzewie wystąpi ten sam stan. Algorytm ten moŜna zastosować tylko do niektórych problemów. Ponadto problemem moŜe być ciągłe sprawdzanie, czy w obu drzewach nie wystąpił juŜ wspólny stan. Dla porównania poniŜej przedstawione jest zestawienie podstawowych algorytmów wyszukiwania i ich oceny według podstawowych kryteriów.

Kryterium Breadth-First

Uniform-Cost

Depth-First Depth-Limited

Iterative Deepening

Bidirectional

Czas bd bd bm bl bd bd/2

Pamięć bd bd bm bl bd bd/2

Optymalność Tak Tak Nie Nie Tak Tak

Zupełność Tak Tak Nie Tak, jeśli l≥d

Tak Tak

Do oszacowania czasu i pamięci potrzebnej w danym algorytmie, uŜyte zostały następujące parametry:

- b – (ang. branching factor) oznacza średnią liczbę gałęzi jednego węzła w drzewie, - d – (ang. depth of solution) oznacza głębokość, na której znajduje się rozwiązanie, - m – (ang. maximum depth) oznacza maksymalną głębokość drzewa rozwiązań, - l – (ang. depth limit) oznacza graniczną głębokość algorytmu.

1

2 5

3 4 6

Page 64: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

58

Parametry b, d i m zaleŜą oczywiście od rozwiązywanego problemu. W przypadku kostki Rubika wynoszą one:

- b =18, gdyŜ na kaŜdym stanie moŜna wykonać 18 ruchów, - d≈20, co stanowi długość rozwiązania permutacji Superflip, która uznana jest za

najbardziej skomplikowany stan kostki, - m→∝, jako Ŝe grupa kostki jest nieskończona, - l=d, aby znaleźć rozwiązanie.

MoŜna wobec tego następująco oszacować koszt algorytmów prostego przeszukiwania drzewa w celu znalezienia rozwiązania kostki Rubika:

Kryterium Breadth-First

Uniform-Cost

Depth-First Depth-Limited

Iterative Deepening

Bidirectional

Czas 1.27e25 1.27e25 ∝ 1.27e25 1.27e25 3.57e12

Pamięć 1.27e25 1.27e25 ∝ 360 360 3.57e12

Z punktu widzenia układania rozwaŜanych układanek powyŜsze algorytmy są więc zupełnie nie przydatne. Układanki te posiadają tak duŜą ilość stanów, Ŝe złoŜoność pamięciowa tych algorytmów jest za duŜa dla współczesnych komputerów.

3.4.5. Algorytmy zorientowane (poinformowane)

Algorytmy zorientowane róŜnią się od prostych faktem posiadania przez nie informacji o problemie. Na podstawie tej informacji do sprawdzania wybierają węzeł bliŜszy rozwiązaniu. NajwaŜniejsze algorytmy z tej grupy to:

- algorytm zachłanny (ang. greedy search) - algorytm A*, A z gwiazdką (ang. A* (star) search) - algorytm IDA*, iteracyjnego pogłębiania algorytmu A* (ang. iterative deepening A*

search) - algorytm SMA* (ang. Simplified Memory-Bounded A*)10

Algorytm zachłanny i algorytm A* opierają się na szkielecie algorytmu przeszukiwania drzewa. W przypadku algorytmu zachłannego węzły w kolejce porządkowane są według przewidywanej długości ścieŜki od tego węzła do rozwiązania, określanej funkcją )(nh , gdzie n oznacza węzeł.

10 Algorytm ten nie został opisany w niniejszej pracy.

Page 65: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

59

Algorytm A* uwzględnia ponadto koszt ścieŜki od korzenia do rozpatrywanego węzła – funkcję )(ng . Węzły w kolejce ustawia on według sumy wartości tych funkcji –

)()()( nhngnf += . Ponadto nakłada on dodatkowe ograniczenia na funkcję f (musi być ona monotoniczna) oraz funkcję h zwaną funkcją heurystyczną, co zostało szczegółowo opisane w następnym podrozdziale.

Algorytm zachłanny nie jest ani zupełny ani optymalny. PodąŜa on ścieŜką o najmniejszym przewidywanym koszcie, która moŜe być nieskończona. Ponadto znajduje pierwsze napotkane rozwiązanie. W przeciwieństwie do niego, dobrze skonstruowany algorytm A* (funkcja heurystyczna), który jest na nim oparty, jest zarówno optymalny jak i zupełny. JednakŜe duŜym problemem związanym z oboma algorytmami jest ich złoŜoność pamięciowa. Pamiętają one wszystkie odwiedzone i rozwinięte stany. Algorytm IDA* wykorzystuje algorytm A*, podobnie jak było to w przypadku algorytmów przeszukiwania w głąb i iteracyjnego przeszukiwania w głąb do określonej głębokości. Dzięki temu zabiegowi jest on zupełny i optymalny, a jednocześnie nie przechowuje wszystkich stanów w pamięci. Algorytm IDA* jest najczęściej stosowanym algorytmem do szukania rozwiązań dla układanek:

1 (f=g+h=0+15)

2 (5+10) 4 (15+15)

3 (10+5) 5 (20+10) 6 (25+5)

15 5

5 15 10

- (50+0)

40

- (45+5)

25

- (35+5)

10

7 (30+0)

5

1 (h=15)

2 (h=10) - (h=15)

3 (h=5) - (h=10) - (h=5)

15 5

5 15 10

4 (h=0)

40

- (h=5)

25

- (h=5)

10

- (h=0)

5

Page 66: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

60

function IDA*(PROBLEM problem) : NODE { INT f_limit; //aktualne ogranicznenie kosztu rozwiązania NODE root; //korzeń drzewa NODE solution; //odnalezione rozwiązanie root.Init(problem.initial_state) f_limit = f(root); //przewidywany koszt rozwiązania loop do { solution, f_limit = IDA*_ITERATE(root, f_limit); //wywołanie

//iteracji algorytmu if solution != NULL then return solution; //znalezione rozwiązanie if f_limit = ∞ then return NULL; //nie ma rozwiązania } }

function IDA*_ITERATE(PROBLEM problem, NODE root, INT f_limit) : NODE, INT

{ INT f_limit_next=∞; //następny graniczny koszt rozwiązania INT f_limit_new; //proponowany w poddrzewach nastepny graniczny

koszt rozwiązania NODE node; //węzeł drzewa NODE solution; //odnalezione rozwiązanie // ustalenie nowego f_limit, jeŜeli niemoŜliwe znalezienie // rozwiązania w obecnym if f(node) > f_limit then return NULL, f(node); //jeśli graniczny koszt rozwiązania jest

//większy od przewidywanego kosztu dla tej iteracji, to //naleŜy przeprowadzić kolejną iterację ze zwiększonym //granicznym kosztem

// zwrócenie rozwiązania, jeŜeli znalezione if problem.goal_state = node.state then return node, f_limit; //znalezione rozwiązania // rozwinięcie rozwaŜanego węzła opers = problem.GetValidOpers(node.state); for each oper in opers do { state = problem.Execute(node.state, oper); child.Init(state,oper,node.depth+1,node.path_cost+oper.cost); solution, f_limit_new = IDA*_ITERATE (problem, child, f_limit);

//szukanie w podrzewie if solution != NULL then return solution, f_limit; //znalezione rozwiazanie f_limit_next = MIN(f_limit_next, f_limit_new); //znalezienie

//minimalnego nastepnego ograniczneia kosztu rozwiązania } // ustalenie nowego limitu, jeŜeli nieznalezione rozwiązanie return NULL, f_limit_next; }

Algorytm ten rozpoczyna szukanie z ograniczeniem kosztu rozwiązania równym przewidywanemu kosztowi rozwiązania dla korzenia. Następnie kaŜda iteracja wyszukiwania

Page 67: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

61

wywoływana jest z coraz większą wartością ograniczenia. Wartość ta odpowiada minimalnej znalezionej wśród nowo-odwiedzonych węzłów przewidywanej wartości kosztu rozwiązania. MoŜe się zdarzyć tak, Ŝe kolejne wartości będą się od siebie róŜnić o bardzo małe wartości i w kaŜdej kolejnej iteracji rozwijany będzie tylko jeden dodatkowy węzeł. Aby uniknąć takiej sytuacji moŜna wprowadzić minimalną róŜnicę między kolejnymi wartościami ograniczenia kosztu rozwiązania. Iteracja algorytmu polega na rekurencyjnym przeszukaniu drzewa w celu znalezienia rozwiązania w obrębie konturu wyznaczonego przez graniczną wartość kosztu rozwiązania. Na podstawie wartości funkcji f węzłów znajdujących się tuŜ za konturem wyliczana jest wartość graniczna do następnej iteracji. Znalezienie optymalnego rozwiązania gwarantowane jest dzięki sprawdzaniu węzłów na tej samej głębokości w kolejności według minimalnej wartości funkcji f (nie jest to zaznaczone w pseudokodzie). Na poniŜszym rysunku zaznaczone zostały dwie iteracje przeszukiwania drzewa oznaczone jako czerwone kreski. W pierwszej iteracji kontur wyznaczony został jako 15, a w drugiej – 30. Węzły znajdujące się w obrębie konturu (powyŜej kreski) zostały rozwinięte, węzły znajdujące się tuŜ poza konturem (poniŜej kreski), zostały jedynie zbadane i odrzucone ze względu na zbyt duŜa wartość funkcji szacującej koszt całego rozwiązania.

3.5. Funkcja heurystyczna

Funkcja heurystyczna, jak zostało wcześniej powiedziane, jest estymacją kosztu rozwiązania. Dla kaŜdego stanu daje optymistyczną ocenę odległości od (kosztu) rozwiązania. Wykorzystywana jest ona w algorytmach A* i IDA*. Projektowana jest ona dla kaŜdego problemu osobno. W niej bowiem zawarta jest wiedza o rozwiązywanym problemie, która ma posłuŜyć do efektywnego wyszukiwania rozwiązania.

3.5.1. Wymagania

Podstawą do poprawnego działania algorytmu A*, a co za tym idzie takŜe IDA* jest poprawnie skonstruowana funkcja heurystyczna (ang. admissible heuristic). Funkcja ta nigdy nie moŜe zawyŜać przewidywanego kosztu ścieŜki. W przeciwnym przypadku moŜe się tak zdarzyć, Ŝe optymalne rozwiązanie znajdzie się poza rozpatrywanym konturem. Musi ona być wobec tego zawsze niedoszacowana.

1 (f=g+h=0+15)

2 (5+10) 4 (15+15)

3 (10+5) 5 (20+10) 6 (25+5)

15 5

5 15 10

- (50+0)

40

- (45+5)

25

- (35+5)

10

7 (30+0)

5

Page 68: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

62

MoŜliwe jest łączenie kilku funkcji heurystycznych. W takim przypadku rozpatrywana jest największa wartość funkcji składowej: )...)(),(()( 21 nfnfMAXnf = .

3.5.2. Proste funkcje

Wartość prostej funkcji heurystycznej moŜna wyliczyć na podstawie samego stanu. W prostych układankach oznacza to, Ŝe wartość funkcji heurystycznej wynika z ułoŜenia klocków. Do jej wyliczenia nie są potrzebne Ŝadne dodatkowe dane. Kilka prostych funkcji zostało opracowanych dla układanki o przesuwnych klockach.

Manhattan Distance

Najprostszą funkcją heurystyczną przewidującą koszt rozwiązania przesuwanki jest odległość Manhattan (ang. Manhattan Distance). Jest to suma odległości wszystkich klocków od swoich miejsc docelowych. Jako, Ŝe zmiana stanu przesuwanki oznacza zmianę połoŜenia dokładnie jednego klocka, oczywiste jest, Ŝe tak wyliczony koszt ścieŜki nie będzie przeszacowany.

Stan aktualny, dla którego

szacowany koszt rozwiązania

3 1 2

6 5 4

8 7

Stan docelowy reprezentujący

ułoŜoną przesuwankę

0 1 2

3 4 5

6 7 8

Kafelek Odległość od miejsca

docelowego

1 0

2 0

3 1

4 1

5 1

6 1

7 1

8 1

Manhattan Distance = 6

1 (f=g+h=0+15)

2 (5+10) 4 (15+15)

3 (10+5) 5 (20+10) - (25+30)

15 5

5 15 10

6 (50+0)

40

- (45+5)

25

- (35+5)

10

- (30+0)

5

Page 69: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

63

Linear Conflict Enhancement

Lepsze przybliŜenie do rzeczywistego kosztu ścieŜki moŜna osiągnąć uwzględniając konflikt liniowości (ang. linear conflict enhancement). Polega on na tym, Ŝe jeŜeli dwa klocki leŜą w swoim wierszu docelowym (kolumnie docelowej), ale są zamienione miejscami, to konieczne będzie, aby jeden z nich „zszedł” z drogi, gdy drugi będzie przechodził na swoje miejsce. Dlatego teŜ do przewidywanego kosztu rozwiązania konieczne jest dodanie liczby 2 dla kaŜdej takiej pary klocków.

Stan aktualny, dla którego

szacowany koszt rozwiązania

3 1 2

6 5 4

8 7

Stan docelowy reprezentujący

ułoŜoną przesuwankę

0 1 2

3 4 5

6 7 8

Kafelek Odległość od miejsca

docelowego

1 0

2 0

3 1

4 1+2

5 1

6 1

7 1+2

8 1

Manhattan Distance = 10

3.5.3. Baza danych wzorców

Baza danych wzorców jest bardziej skomplikowanym typem funkcji heurystycznej. Jest to wcześniej przygotowana tabela otrzymana w oparciu o dane stanów a takŜe operacji na nich wykonanych. Przechowuje wobec tego większą wiedzę na temat problemu. Przewidywany koszt nie jest tutaj obliczany na bieŜąco, ale sprawdzany w tabeli. Tabela ta zawiera na ogół koszt rozwiązania podstanu obiektu. Dzięki temu moŜliwe jest przechowywanie w pamięci informacji, która, mimo iŜ niekompletna, stanowi duŜą wiedzę o problemie i umoŜliwia efektywne znalezienie rozwiązania. Omawiana tablica zajmuje jednak sporo miejsca w pamięci i musi być przygotowana przed uŜyciem w algorytmie. Tablica taka oczywiście jest przygotowana tylko raz, a potem wielokrotnie uŜywana. Rozpatrywanych moŜe być kilka takich tablic, z których wybierana będzie maksymalna wartość dla rozpatrywanego stanu. Bazę danych wzorców tworzy się na ogół dla pewnego podzbioru stanów problemu. Liczba stanów problemu w wybranym podzbiorze jest znana, więc moŜna obliczyć wielkość bazy danych wzorców. Tworzy się dla niej odpowiedniej wielkości tablicę. W pola tabeli wpisuje się heurystykę, czyli odległość danego podstanu od rozwiązania. Wartości te otrzymuje się w wyniku przeszukiwania drzewa rozwiązań wszerz rozpoczynając od korzenia reprezentującego rozwiązanie. Do tabeli dodawane są jedynie róŜne, z punktu widzenia bazy danych, stany. Algorytm przeszukiwania drzewa powinien zatrzymać się w momencie wypełnienia wszystkich pól tabeli. Podczas rozwiązywania problemu z wykorzystaniem tabeli wzorców, znajduje się w tejŜe tabeli wpis odpowiadający rozpatrywanemu stanowi. Traktuje się go jako estymację kosztu rozwiązania.

Page 70: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

64

Sliding-Tile Puzzle

W przypadku przesuwanki baza danych wzorców oparta jest o ograniczony stan układanki, czyli stan rozróŜniający tylko kilka kafelków. Ograniczony stan definiuje połoŜenie tylko wybranych kafelków, a cała reszta go nie interesuje. MoŜna go porównać ze stanem układanki, której kilku kafelkom zdrapano numerki i są one wobec tego nierozróŜnialne. Przechowuje on wobec tego kombinacje wybranych połoŜeń kafelków na większej liczbie pól. Pozostałe pola wypełnione są przez „inne kafelki” z punktu widzenia tego stanu. Liczba ograniczonych stanów dla danego problemu jest oczywiście duŜo mniejsza niŜ odpowiednia liczba stanów. W zaleŜności od wielkości problemu i zasobów sprzętowych moŜna zastosować róŜny stopień ograniczenia stanu zdefiniowanego jako stosunek liczby nierozróŜnialnych kafelków do liczby wszystkich kafelków. Najczęściej stosowane są jednak dwa rodzaje ograniczeń. Odpowiednio nie rozróŜniają one:

- kafelków na krawędziach prawej i dolnej

1 2

4 5 6

8 9 10

- ostatnich 12 −n kafelków, gdzie n to długość krawędzi

1 2 3

4 5 6 7

8

Oznacza to w praktyce, Ŝe z punktu widzenia bazy danych wzorców pierwszego typu, na przykład, następujące dwa stany są nierozróŜnialne:

10 4 9 3

12 1 11

8 15 6 2

7 5 14 13

10 4 9 11

12 1 3

8 15 6 2

7 5 14 13

Page 71: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

65

Rubik’s Cube

Jak zostało wcześniej opisane kostka Rubika posiada dwa rodzaje klocków: rogi i krawędzie, których zbiory są rozłączne i moŜliwa jest zamiana ich miejsc jedynie wewnątrz tych zbiorów. Dlatego teŜ warto stworzyć tablice w oparciu o częściową specyfikację permutacji (stanów), którą będziemy w tym przypadku nazywać permutacja części klocków. Rogów jest 8. KaŜdy z nich moŜe znajdować się w jednym z ośmiu rogów kostki i dodatkowo w jednym z 3 połoŜeń (obrotów). Wynika z tego, Ŝe moŜliwych jest 8!⋅37=88 179 840 stanów takiego pod-obiektu. Do ułoŜenia klocków naroŜnych wystarczy 11 ruchów. Dlatego teŜ na przechowywanie kosztu rozwiązania przeznaczyć moŜna tylko 4 bity. W związku z tym na przechowanie całej tabeli potrzebne są około 44MB pamięci, na co dzisiejsze komputery mogą sobie pozwolić. Krawędzi jest 12. KaŜda z nich moŜe się znajdować w jednym z 12 miejsc i dodatkowo w jednym z 2 połoŜeń (obrotów). Wynika z tego, Ŝe moŜliwych jest 12!⋅211=980 995 276 800 stanów takiego pod-obiektu. Jest to za duŜo do wygenerowania tabeli. Dlatego teŜ moŜna rozwaŜyć dwa dwukrotnie mniejsze pod-stany reprezentujące ułoŜenie połowy krawędzi. KaŜda z wybranych 6 krawędzi moŜe być umieszczonych w jednym z 12 miejsc i ponadto w jednym z dwóch połoŜeń (obrotów). Pod-obiekt połowy klocków krawędziowych ma zatem

66 2!6

!122

6

12⋅=⋅

=42 577 920 stanów. Maksymalny koszt ułoŜenia takiego pod-obiektu to 10

ruchów i moŜe być przechowany na 4 bitach. Do przechowania wszystkich wartości potrzebna będzie tablica o wielkości około 20MB.

Rogi: Połowa krawędzi: Druga połowa krawędzi:

PowyŜsze podejście zostało przedstawione w artykułach Korfa. Jest ono oczywiście poprawne i umoŜliwia wykorzystanie wiedzy o kostce do jej rozwiązania. Jest to jednak najprostsze podejście z tej grupy. Istnieje kilka modyfikacji tego pomysłu. Stan kostki moŜe być podzielony na podstany według innej reguły, np. orientacje i permutacje rogów i krawędzi będą rozpatrywane z osobna. MoŜna równieŜ zdefiniować funkcję heurystyczną jako odległość nie tylko od stanu rozwiązania, ale od jakiejś grupy stanów ,w której się on znajduje. Dodatkowo w przedstawionej bazie danych wzorców nie została uwzględniona waŜna cecha kostki - jej symetryczność. W oparciu o tę cechę moŜna znacznie zredukować liczbę przechowywanych informacji.

Tablice przekształceń

WaŜną i godną uwagi techniką w kontekście tablic funkcji heurystycznych są tablice przekształceń. Są to tabele przechowujące stan, który zostanie otrzymany w wyniku wykonania zadanej operacji na zadanym stanie. Są więc one dwuwymiarowe. Ich wymiarami są stany i operatory, natomiast wartościami w polach stany. Stan przechowywany jest oczywiście w postaci liczby.

Page 72: PRACA DYPLOMOWA MAGISTERSKA

Algorytmy

66

Tablice te pozwalają na redukcję obliczeń w kaŜdym węźle. Dzięki nim nie jest konieczne kaŜdorazowe rozpakowywanie stanu, wykonywanie na nim operacji i ponowne pakowanie. Wystarczy wynik operacji znaleźć w tabeli.

3.6. Algorytm Kociemby

Najbardziej zaawansowanym , najszybszym i najciekawszym, chociaŜ nieoptymalnym algorytmem rozwiązywania kostki Rubika jest stworzony przez H.Kociembę algorytm dwufazowy [[1]]. Algorytm ten łączy poprzednie pomysły. Podobnie jak algorytm Thistlethwaite’a, wydziela on etapy poszukiwań. Jednocześnie korzysta on z drzewa rozwiązań i funkcji heurystycznych. W algorytmie Kociemby wydzielone są dwa etapy, skąd pochodzi nazwa tego algorytmu – algorytm dwufazowy. Podział na etapy dokonany jest ze względu na grupę pośrednią

>=< 2,2,2,2,,1 BFLRDUG . Stany tej grupy mają prawidłowo zorientowane krawędzie i rogi oraz odizolowane krawędzie środkowej warstwy UD. Algorytm polega na znalezieniu rozwiązania etapu 1 prowadzącego do stanu z grupy 1G oraz optymalnego rozwiązania etapu 2 prowadzącego z tego stanu do rozwiązania. Pierwsze znalezione rozwiązanie jest optymalne dla obu tych etapów, ale nie koniecznie musi być optymalne dla całego problemu. Dlatego teŜ po znalezieniu pierwszego rozwiązania, algorytm kontynuuje poszukiwania w celu znalezienia lepszego rozwiązania – suboptymalnego rozwiązania etapu 1 oraz optymalnego rozwiązania etapu 2. W efekcie rozwiązanie takie równieŜ nie musi być optymalne, ale wystarczy, Ŝe jest jemu bliŜsze. Rozwiązanie uzyskane w tym algorytmie jest nie gorsze niŜ 30 ruchów (12 i 18). Średnio rozwiązania te są zbliŜone do optymalnych (średnio oddalone są on nich o odpowiednio 1 i 2 operacje). Ponadto rozwiązanie to znajdywane jest bardzo szybko.

Page 73: PRACA DYPLOMOWA MAGISTERSKA

Rozwiązania

67

4. Rozwiązania Jako Ŝe kostka Rubika cieszyła się ogromną popularnością wśród matematyków, a co za tym idzie równieŜ informatyków, stworzono wiele programów znajdujących jej rozwiązanie. Opis niektórych dostępny jest w formie publikacji naukowych. Gros jest jednak dostępne w Internecie na stronach domowych ich twórców. Do niektórych programów dostępne są równieŜ ich źródła.

4.1. Rozwiązanie Korfa

Dostępność rozwiązania

Źródłem informacji o tym rozwiązaniu są publikacje Richarda Korfa [[6]-[8]]. Są one dostępne w Internecie. Samo rozwiązanie jednak nie jest. Korf swoje rozwaŜania zaczął od problemu mniej skomplikowanego, czyli Sliding-Tile Puzzle. Przedstawił pomysł wykorzystania algorytmu IDA* oraz funkcji heurystycznej w postaci tabeli do jego rozwiązania. Następnie opisał zastosowanie powyŜszego rozwiązania równieŜ dla kostki Rubika. Publikacje Korfa są podstawą wielu innych rozwiązań.

Zastosowane algorytmy i struktury danych

Program przedstawiony przez R.Korfa stosuje algorytm IDA* oraz funkcje heurystyczne (nazywane przez niego pattern database). Stan kostki dla funkcji heurystycznej opisywany jest przy pomocy trzech współrzędnych:

- Współrzędnej ułoŜenia rogów ( 881798403!8 7 =⋅ stanów)

- Dwóch współrzędnych ułoŜenia połowy krawędzi ( 4257792026

12 6 =⋅

stanów).

Jako Ŝe odległość od rozwiązania dla obu tych współrzędnych moŜna zapisać na połowie bajta, do zapisu tych tabel potrzebne jest odpowiednio 44Mb i 22Mb. Rozwiązanie uzyskiwane tą metodą jest optymalne. Cechuje je jednak długi czas przygotowania tabel, a długość obliczeń jest silnie uzaleŜniona od stanu początkowego. Korf przeprowadził badania na 10 stanach, otrzymanych przez wykonanie 100 losowych ruchów na kostce. Otrzymał średnie rozwiązanie 17.5 ruchów.

4.2. Rozwiązanie Reida

Dostępność rozwiązania

Program Michaela Reida jest w całości dostępny w Internecie pod nazwą optimal. Program napisany jest w języku C. Jego źródło dostępne jest na stronie domowej Reida [[15]] wraz z plikiem README opisującym pracę z tym programem. Dodatkowo Reid wysłał dokładny opis uŜytego algorytmu do grupy [email protected] (5.06.1997).

Interfejs uŜytkownika

Program optimal posiada interfejs tekstowy. Pobiera on od uŜytkownika stan kostki w postaci ciągu liter oznaczających elementy kostki. Elementy te muszą być ustawione w ściśle określonej kolejności. W przypadku ułoŜonej kostki wejście wyglądałoby w następujący sposób:

UF UR UB UL DF DR DB DL FR FL BR BL UFR URB UBL ULF DRF DFL DLB DBR

Wyjściem programu jest ciąg nazw obrotów, które naleŜy wykonać, aby ułoŜyć kostkę.

Page 74: PRACA DYPLOMOWA MAGISTERSKA

Rozwiązania

68

Zastosowane algorytmy i struktury danych

Program wykorzystuje algorytm IDA*, funkcje heurystyczne (pattern database) oraz tablice przekształceń. Oparty jest on o pomysł R.Korfa, ale posiada kilka ulepszeń. Funkcja heurystyczna zwraca odległość nie tylko do rozwiązania, ale do grupy

>=< 2,2,,2,2,1 LBDRFUG . Ponadto zbudowana jest ona w oparciu o inne współrzędne kostki:

- Współrzędną orientacji rogów ( 218737 = ), - Współrzędną orientacji krawędzi ( 2048211 = ),

- Współrzędną pozycji krawędzi z warstwy środkowej UD ( 4954

12=

).

Współrzędne te zostały dalej zredukowane ze względu na 16 symetrycznych stanów kostki, które zachowują oś U-D (czyli symetrie 1,2 i 3 opisane w pierwszym rozdziale). W wyniku tej redukcji stany kostki w tabeli funkcji heurystycznej prezentowane są jako trójka współrzędnych:

- współrzędna orientacji rogów (niezmieniona), - nowa współrzędna krawędzi (złoŜona z poprzedniej współrzędnej orientacji krawędzi i

pozycji krawędzi warstwy środkowej, zredukowanych przez symetrie), - indeks symetrii stanu.

Ostatnia symetria kostki (obrót o 120 stopni wokół osi przechodzącej przez przeciwległe rogi UDF i DBL równieŜ została wykorzystana w przedstawianym rozwiązaniu. Dzięki jej zastosowaniu moŜliwe jest wykorzystanie utworzonej bazy danych wzorców do znalezienia odległości rozwaŜanego stanu od grup >=< 2,,2,2,,22 LBDRFUG oraz

>=< LBDRFUG ,2,2,,2,23 . W algorytmie wartością funkcji heurystycznej jest oczywiście maksymalna wartość odległości do tych grup. PowyŜsze zabiegi znacznie zmniejszyły zajętość pamięci i przyspieszyły algorytm. Rozwiązanie uzyskane tym algorytmem jest oczywiście optymalne.

4.3. Rozwiązanie Kociemby

Dostępność rozwiązania

Program „Cube Explorer” dostępny jest na stronie domowej Herberta Kociemby [[1]] w postaci pliku wykonywalnego EXE. Niestety nie są udostępnione źródła tego programu. W przeszłości udostępnione były jednak źródła wcześniejszych wersji tego programu (napisane w Pascalu). Zostały one wykorzystane do stworzenia programów rozwiązujących kostkę w innych językach programowania i w tej przerobionej postaci są dostępnej w Internecie. Takie właśnie źródła posłuŜyły jako podstawa programu napisanego w ramach niniejszej pracy.

Interfejs uŜytkownika

Program „Cube Explorer” udostępnia graficzny interfejs do wykonywania operacji na wirtualnej kostce. Wystarczy zatem graficznie wprowadzić stan kostki, przez zakolorowanie odpowiednich ścianek na dostępne kolory.

Zastosowane algorytmy i struktury danych

Program „Cube Explorer” znajduje suboptymalne rozwiązanie kostki Rubika przy uŜyciu algorytmu dwufazowego. Algorytm ten został opisany w poprzednim rozdziale. Realizuje on dwuetapowe przeszukiwanie IDA*, uŜywa ztablicowanych funkcji heurystycznych oraz tablic przekształceń. Tablice zredukowane są ze względu na symetrie kostki, a część obliczeń odbywa się równolegle. Stan kostki opisywany jest przez kilka dostosowanych do etapu współrzędnych. Są to odpowiednio:

Page 75: PRACA DYPLOMOWA MAGISTERSKA

Rozwiązania

69

- W pierwszym etapie:

współrzędna orientacji rogów - (Error! Objects cannot be created from editing field codes.stanów zapisanych w systemie trójkowym),

współrzędna orientacji krawędzi - ( 112 - w systemie binarnym),

współrzędna UDSlice – pozycje 4 krawędzi ze środkowej warstwy UD (

4

12).

- W drugim etapie: współrzędna permutacji rogów - ( !8 - zapis w systemie o podstawie o zmiennej

długości) współrzędna FlipUDSlice – orientacja krawędzi oraz pozycje 4 krawędzi ze

środkowej warstwy UD ( 1224

12⋅

stanów),

współrzędna UDEdgePermutation – permutacja 8 krawędzi z warstw U i D ( !8 stanów),

współrzędna UDSliceSorted – permutacja i orientacja 4 krawędzi ze środkowej

warstwy UD ( !44

12⋅

stanów).

RóŜny dobór stanów do etapu wynika z róŜnych stanów dostępnych w danych etapie algorytmu. W pierwszym etapie brane pod uwagę róŜnice stanów dotyczą orientacji rogów i krawędzi oraz stopnia izolacji 4 krawędzi ze środkowej warstwy w tejŜe warstwie. Stan docelowy posiada zorientowane wszystkie elementy oraz wyizolowane krawędzie środkowej warstwy. Dlatego teŜ w drugim etapie stany są nierozróŜnialne ze względu na te współrzędne. Są one opisane przy uŜyciu pozostałych parametrów kostki, czyli permutacji wszystkich elementów.

Page 76: PRACA DYPLOMOWA MAGISTERSKA
Page 77: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

71

5. Program rozwiązujący kostkę Rubika W ramach pracy magisterskiej stworzone zostały dwa programy. Pierwszy z nich tworzony był z załoŜeniem uniwersalności, czyli tak, aby mógł być stosowany do wielu róŜnych problemów. Ponadto niesie on wartości merytoryczne, gdyŜ przedstawia działanie róŜnych algorytmów przeszukiwania drzewa. Jako Ŝe nie stanowi celu niniejszej pracy, omówiony jest on w załączniku. Prawdziwym efektem pracy jest drugi program (nazwany CubeSolver). Przeznaczony jest on do pracy jako część robota układającego kostkę Rubika, który jest budowany w Zakładzie Robotyki. Został on oparty na opisie algorytmów Korfa i Kociemby oraz na znalezionym w Internecie programie do rozwiązywania kostki Rubika. Program ten napisany był w Javie. Stanowił on tłumaczenie z Pascala starszej wersji programu Kociemby. W ramach niniejszej pracy został zaprojektowany i zbudowany zupełnie nowy program. PoniŜej opisane zostały: sposób działania programu, wyniki jego pracy oraz sposób jego integracji z systemem robota. Dokładny opis elementów programu znajduje się w załączniku do niniejszej pracy.

5.1. Budowa i zasady działania programu

Program składa się z kilku logicznie wydzielonych modułów: - elementy kombinatoryki (Combinatorials), - fizyczne właściwości kostki Rubika (Cube), - wiedza o kostce Rubika, - implementacja modelu i algorytmu Korfa, - implementacja modelu i algorytmu Kociemby.

KaŜdy moduł reprezentuje inny obszar wiedzy, dzięki czemu jest spójny logicznie i łatwy do wyodrębnienia. KaŜdy z modułów posiada osobną klasę błędu i testera. Testy jednostkowe zostały przeprowadzone właśnie na poziomie modułów. PoniŜej znajduje się opis modułów i ich elementów.

5.1.1. Elementy kombinatoryki

Podstawowym elementem programu są klasy reprezentujące permutację, kombinację i wariację. Wykorzystywane są one dalej do róŜnych reprezentacji kostki Rubika. Przy ich pomocy wykonywane są operacje na kostce. Wszystkie trzy klasy stanowią implementację klasy abstrakcyjnej kolekcji. Kolekcja reprezentuje ciąg liczb o zdefiniowanej długości i maksymalnych wartościach. Kolekcja posiada równieŜ metody dostępowe do swoich elementów. Definiuje równieŜ operację obliczenia numeru kolejnego kolekcji oraz odtworzenia kolekcji na podstawie tego numeru. Metody obliczania numeru kolejnego kolekcji zaimplementowane są w klasach potomnych, gdyŜ róŜnią się one dla róŜnych zbiorów kombinatorycznych.

Permutacja:

Liczba permutacji zbioru n -elementowego wynosi !n . Oznacza to, Ŝe kaŜdej permutacji zbioru n -elementowego moŜna jednoznacznie przypisać liczbę naturalną ze zbioru }1!..0{ −n . RozwaŜmy permutację zbioru 4-elementowego }3,2,1,0{ . Stwórzmy permutacje tego zbioru układając jego elementy w kolejności od najmniejszych wartości. Przed ułoŜeniem pierwszego elementu (o wartości 0) mamy 24!4! ==n moŜliwości ułoŜenia wszystkich elementów, a element ten moŜemy ułoŜyć w czterech miejscach:

0 Pozycja bezwzględna 1 2 3 4

0 1 2 3 4

0 1 2 3 4

0 1 2 3 4

Page 78: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

72

Po ułoŜeniu pierwszego elementu (np. na pozycji drugiej) zawęŜa nam się liczba moŜliwości ułoŜenia wszystkich elementów. Wynosi ona juŜ tylko 6!3)!1( ==−n moŜliwości, a drugi element moŜna ułoŜyć tylko na trzech pustych miejscach, które moŜna nazwać pozycjami względnymi, powstałymi przez odrzucenie zajętego miejsca:

1 0 Pozycja bezwzględna 1 2 3 4 Pozycja względna 1 - 2 3

0 1 1 2 3 4 1 - 2 3

0 1 1 2 3 4 1 - 2 3

UłoŜenie drugiego elementu (np. na pozycji bezwzględnej trzeciej, czyli względnej drugiej) zmniejszyło liczbę moŜliwości ułoŜenia wszystkich elementów do 2, co oznacza, Ŝe ułoŜenie trzeciego (przedostatniego) elementu to juŜ wybór tylko między dwoma miejscami:

2 0 1 1 2 3 4 1 - - 2

0 1 2 1 2 3 4 1 - - 2

Dla ostatniego elementu nie ma juŜ wyboru, bo pozostało jedno niezapełnione miejsce.

2 0 1 3 1 2 3 4 - - - 1

Do zapisania powyŜszej permutacji wystarczy uŜyć pozycji względnych kolejnych elementów, czyli wartości 2,2,1,1. Ostatnią wartość moŜna pominąć, gdyŜ wynosi ona zawsze 1. Aby jednoznacznie określić ułoŜenie i -tego elementu w permutacji, wystarczy przemnoŜyć względną pozycję tego elementu przez liczbę moŜliwych permutacji wszystkich elementów po ułoŜeniu i elementów. Czyli w naszym przypadku będą to odpowiednio liczby: !32 ⋅ , !22 ⋅ i !11⋅ . Suma tych liczba stanowi natomiast numer porządkowy permutacji. Formalnie moŜna to zapisać:

∑∈

−−⋅−}..1{

))!(1()1)((ni

ivnip , gdzie:

}..1{)( nip ∈ jest względną pozycją i -tego elementu, }1..0{)( −∈ niv - wartością tego elementu, a

n - liczba elementów w permutacji. W przypadku rozwaŜanej permutacji liczba ta wynosi:

826!00!10!21!31)!33()11()!23()11()!13()12()!03()12(

))!(3()1)(())!(1()1)((}4..1{

4

}..1{

=+=⋅+⋅+⋅+⋅=−⋅−+−⋅−+−⋅−+−⋅−=

=−⋅−→−−⋅− ∑∑∈

=

∈ i

n

ni

ivipivnip

Kombinacja

Liczba k -elementowych kombinacji bez powtórzeń zbioru n -elementowego wynosi

k

n.

Oznacza to, Ŝe kaŜdej k -elementowej kombinacji bez powtórzeń zbioru n -elementowego

moŜna jednoznacznie przypisać liczbę naturalną ze zbioru }1..0{ −

k

n.

Page 79: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

73

RozwaŜmy 2-elementową kombinację zbioru 5-elementowego }4,3,2,1,0{ . Stwórzmy kombinację tego zbioru decydując, czy element naleŜy do tej kombinacji w kolejności od najmniejszych wartości. Kolejne decyzje przedstawmy na grafie. Na osi x zaznaczona jest liczba juŜ rozwaŜonych elementów, a na osi y liczba elementów dodanych do kombinacji. Węzłem początkowym grafu jest brak decyzji, czyli zarówno rozwaŜonych elementów jak i elementów dodanych do kombinacji jest 0. Węzłem końcowym jest natomiast stworzona kombinacja, czyli wszystkie elementy rozpatrzone i 2 dodane do kombinacji. ŚcieŜki między punktem początkowym a końcowym reprezentują moŜliwe kombinacje. Zaczynając od elementu o wartości 0, mamy dwie moŜliwości do wyboru – dodać albo nie element do kombinacji. Dodanie go do kombinacji zwiększy liczbę elementów w kombinacji, nie dodanie – pozostawi tę liczbę niezmienioną.

Węzły (1,0) i (1,1) reprezentują podjętą decyzję, czyli rozpatrzony pierwszy element zbioru. Łuk do punktu (1,1) oznacza dodanie do kombinacji pierwszego elementu, natomiast łuk do (1,0) – nie dodanie go. Wybierzmy pierwszą decyzję – pozostały jeszcze 4 elementy do rozwaŜenia i 1 element do dodania. W węźle (1,1) mamy znowu dwie moŜliwości – dodać drugi element do kombinacji albo nie.

MoŜliwości te reprezentowane są przez łuki prowadzące do węzłów (2,1) i (2,2). Wybierzmy drugą moŜliwość – pozostały jeszcze 3 elementy i 0 elementów do dodania. Oznacza to, Ŝe nie ma juŜ Ŝadnych decyzji do podjęcia, gdyŜ pozostałe 3 elementy nie mogą być dodane do kombinacji.

ŚcieŜka ta reprezentuje kombinację }1,0{ . RozwaŜmy teraz wszystkie pozostałe kombinacje. Dodatkowo zauwaŜmy, Ŝe tylko w niektórych węzłach moŜna podjąć decyzje, co do wybrania bądź nie kolejnych elementów. Punkty decyzyjne są wyróŜnione na grafie.

(0,0)

(1,1)

(2,2)

dodany

dodany (5,2) (3,2) (4,2)

nie dodany nie dodany nie dodany

(0,0)

(1,1)

(2,2)

(2,1)dodany

dodany

nie dodany

(1,0)

dodany

nie dodany (0,0)

(1,1)

(pierwszy rozwaŜony, pierwszy nie dodany)

(pierwszy rozwaŜony, pierwszy dodany)

Page 80: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

74

ŚcieŜek przejścia z punktu (0,0) do punktu (5,2) jest 9, czyli dokładnie tyle, co 2-elementowej kombinacji zbioru 5-elementowego. Na przykład kombinacja }4,2{ odpowiada ścieŜce:

Do opisu kombinacji wystarczy podać ścieŜkę w grafie. ŚcieŜka ta wynika z podjętych decyzji. Istotne są tylko decyzje rzeczywiście podjęte, a nie narzucone, czyli dotyczące tylko punktów decyzyjnych. Ponadto wystarczy zapamiętać tylko jeden rodzaj decyzji, np. te, nie dodające elementu do kombinacji. KaŜdej z tych decyzji (łukowi) moŜemy przypisać

wartością liczbową równą

−<

−=

−>

−−

−−

10

11

11

1

kydla

kydla

kydlayk

xn

, gdzie yx, to współrzędne punktu,

z którego prowadzi łuk. Pozostałym łukom przypisujemy wartość 0. W rozwaŜanym przykładzie będą to wartości:

Numerem kolejnym kombinacji odpowiadającej ścieŜce od węzła początkowego do węzła końcowego jest suma kosztów łuków wchodzących w skład tej ścieŜki.

Wariacja

Liczba k -elementowych wariacji z powtórzeniami zbioru n -elementowego wynosi kn . Oznacza to, Ŝe kaŜdej k -elementowych kombinacji z powtórzeniami zbioru n -elementowego

(0,0)

(1,1)

(2,0) (3,0)

(2,2)

(2,1) (3,1)

(5,2)

(1,0)

(4,1)

(3,2) (4,2)

(0,0)

(1,1)

(2,0) (3,0)

(2,2)

(2,1) (3,1)

(5,2)

(1,0)

(4,1)

(3,2) (4,2)

0 0 0 0

0 0

2

0 0

3 4

1 1

0

1

0 0

0 1 2 3 4 5

0

1

2

x

y

(0,0)

(1,1)

(2,0) (3,0)

(2,2)

(2,1) (3,1)

(5,2)

(1,0)

(4,1)

(3,2) (4,2)

Page 81: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

75

moŜna jednoznacznie przypisać liczbę naturalną ze zbioru }1..0{ −kn . Wybór elementów wariacji jest niezaleŜny i kaŜdy z nich moŜna zapisać jako liczbę naturalną ze zbioru

}1..0{ −n . Całą wariację moŜna zapisać jako liczbę w systemie o podstawie n złoŜoną z cyfr oznaczających pojedyncze elementy. RozwaŜmy następującą 8-elementową wariację zbioru 3-elementowego:

2 0 1 1 2 0 0 2

KaŜdy element tej wariacji moŜna zapisać za pomocą liczby ze zbioru }2..0{ :

2,0,1,1,2,0,0,2 Całą wariację moŜna zapisać jako liczbę w systemie trójkowym złoŜoną z liczb prezentujących elementy:

)3(20112002 .

W systemie dziesiętnym liczba ta równa jest:

)10(

01234567)3(

475312272811243121872

323030323131303220112002

=⋅+⋅+⋅+⋅+⋅=

=⋅+⋅+⋅+⋅+⋅+⋅+⋅+⋅=

5.1.2. Fizyczne właściwości kostki Rubika

Fizyczne właściwości kostki określone są przez jej wygląd zewnętrzny, budowę i moŜliwe do wykonania ruchy. Na ich podstawie moŜna zbudować podstawowy model kostki11, a dalej definiować bardziej złoŜone – przydatne do znajdywania rozwiązania. Ponadto umoŜliwiają one zamianę zapisu stanu kostki zrozumiałego dla człowieka i uŜytecznego w interfejsie uŜytkownika, na zapis matematyczny.

Wygląd zewnętrzny kostki Rubika, czyli zbiór ścianek

Klasa wyglądu zewnętrznego kostki Rubika stworzona została głównie na potrzeby interfejsu uŜytkownika. Dzięki niej łatwo wprowadzić stan kostki jako zbiór kolejnych ścianek. WaŜne jest jedynie zachowanie kolejności ścianek. Klasa definiuje podstawowe stałe takie jak liczba ścian, ścianek i ścianek w ściance. Ponadto dla kaŜdej ściany zdefiniowany jest numer, litera ją oznaczająca oraz standardowy kolor jej naklejek. Stan kostki przechowywany jest jako zbiór 54 numerów oznaczający rozmieszczenie ścianek w kostce. NajwaŜniejsze metody umoŜliwiają przetworzenie tego stanu w ciąg znaków zrozumiały dla uŜytkownika oraz przekształcenie odwrotne. Podczas próby zamiany ciągu znaków na stan kostki sprawdzana jest zewnętrzna poprawność stanu. Oznacza to, Ŝe wprowadzany stan powinien zawierać 54 ścianki, po 9 ścianek z kaŜdej ściany oraz 6 róŜnych ścianek środkowych. Ciąg znaków akceptowanych przez klasę jako stan kostki wygląda następująco dla ułoŜonej kostki:

U:wwwwwwwww,F:bbbbbbbbb,R:rrrrrrrrr,D:yyyyyyyyy,B:ggggggggg,L:ooooooooo

Oznaczenia ścianek prezentowane są w następującej kolejności:

11 Budowa i moŜliwe implementacje zostały pokrótce opisane i porównane w rozdziale 1.3. W programie CubeSolver zostały one zaimplementowane. W niniejszym rozdziale znajduje się ich krótki opis techniczny.

Page 82: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

76

L1 L2 L3

L4 L5 L6

L7 L8 L9

F1 F2 F3

F4 F5 F6

F7 F8 F9

D1 D2 D3

D4 D5 D6

D7 D8 D9

B1 B2 B3

B4 B5 B6

B7 B8 B9

U1 U2 U3 U4 U5 U6

U7 U8 U9 R1 R2 R3

R4 R5 R6

R7 R8 R9

Kolejność ścian nie ma znaczenia. Za oznaczenia ścian przyjmuje się odpowiednie oznaczenia środkowych ścianek. Nie muszą to być kolory, jednakŜe takie rozwiązanie wydaje się najprostsze. Klasa nie implementuje ruchów na kostce, gdyŜ nie wnosiłoby to niczego do problemu szukania rozwiązania. Wykonywanie ruchu na poziomie ścianek jest wysoce nieefektywne i nie umoŜliwia zastosowania bardziej zaawansowanych algorytmów. W celu obrazowego przedstawienia działania zaimplementowanych klas, w dalszej części rozdziału rozwaŜany będzie stan przedstawiony na poniŜszym rysunku.

Stan ten moŜna zapisać przy pomocy poniŜszego ciągu znaków:

F:gggwwrwwr,R:ryybbbbbb,U:rrorroyyy,B:bggoyyoyy,L:wwobggbgg,D:oowoowrrw,

Budowa kostki Rubika, czyli zbiór elementów

Klasa budowy wewnętrznej kostki Rubika została stworzona jako fizyczna podstawa działania kostki. Definiuje ona moŜliwe stany kostki oraz umoŜliwia wykonywanie ruchów na stanach kostki. Klasa definiuje elementy kostki, czyli numery i moŜliwe orientacje rogów i krawędzi. Stan kostki zdefiniowany jest jako permutacja i orientacja wszystkich rogów i krawędzi kostki. Zapisany jest on przy pomocy opisanych wcześniej obiektów klas kombinatorycznych. Sprawdzenie poprawności stanu kostki odbywa się przez porównanie parzystości permutacji rogów i krawędzi. Operacje na kostce to natomiast wykonanie złoŜenia cyklicznych permutacji określających obroty z permutacjami i orientacjami określającym stan kostki. Klasa kostki umoŜliwia ponadto zapisanie stanu jako ciąg znaków określających kolejno jej

Page 83: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

77

permutację i orientację rogów a potem krawędzi. Dzięki temu moŜliwe jest przekształcanie innych modeli kostki Rubika, na ten, traktowany jako podstawowy i referencyjny. RozwaŜany w niniejszym rozdziale stan moŜna przedstawić przy uŜyciu następujących permutacji i wariacji:

P(08,08)=[02,06,01,07,00,05,03,04] V(08,03)=[02,01,00,00,02,00,00,01] P(12,12)=[07,10,01,02,08,05,06,03,00,09,11,04] V(12,02)=[00,00,00,00,00,00,00,00,00,00,00,00]

Oznaczają one kolejno: ośmioelementową permutację rogów kostki, ośmioelementową wariację orientacji rogów, które mogą przyjmować trzy wartości, dwunastoelementową permutację krawędzi kostki oraz dwunastoelementową wariację orientacji krawędzi, które mogą przyjmować dwie wartości. Permutacje opisują jakie elementy znajdują się na kolejnych pozycjach w kostce, orientacje opisują natomiast w jaki sposób są one ułoŜone. Na przykład na pierwszej pozycji rogowej, na której powinien się znajdować róg o numerze 0, czyli URF, znajduje się róg o numerze 2, czyli ULB.

P(08,08)=[02,06,01,07,00,05,03,04]

Dodatkowo jest on podwójnie obrócony, czyli ostatecznie moŜna go zapisać jako LBU.

V(08,03)=[02,01,00,00,02,00,00,01]

Szczegółowe rozszyfrowanie ułoŜenia wszystkich elementów kostki znajduje się w tabelkach poniŜej. Permutacja i orientacja rogów:

Numer pozycji 0 1 2 3 4 5 6 7

Numer rogu 2 6 1 7 0 5 3 4

Numer orientacji 2 1 0 0 2 0 0 1

Oznaczenie pozycji URF UFL ULB UBR DFR DLF DBL DRB

Oznaczenie rogu ULB DBL UFL DRB URF DLF UBR DFR

Zorientowany róg LBU LDB UFL DRB RFU DLF UBR RDF

Permutacja i orientacja krawędzi: Numer pozycji 0 1 2 3 4 5 6 7 8 9 10 11

Numer krawędzi 7 10 1 2 8 5 6 3 0 9 11 4

Numer orientacji 0 0 0 0 0 0 0 0 0 0 0 0

Oznaczenie pozycji UR UF UL UB DR DF DL DB FR FL BL BR

Oznaczenie krawędzi DB BL UF UL FR DF DL UB UR FL BR DR

Zorientowana krawędź DB BL UF UL FR DF DL UB UR FL BR DR

Page 84: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

78

Na podstawie powyŜszych tabel stan kostki wygląda następująco:

Pozycja Zorientowany

róg Pozycja

Zorientowana krawędź

URF LBU UR DB

UFL LDB UF BL

ULB UFL UL UF

UBR DRB UB UL

DFR RFU DR FR

DLF DLF DF DF

DBL UBR DL DL

DRB RDF DB UB

FR UR

FL FL

BL BR

BR DR

Ruchy moŜliwe do wykonania na kostce Rubika

Klasa ruchów na kostce Rubika została stworzona, aby zdefiniować wszystkie ruchy i ich krotności moŜliwe do wykonania na kostce oraz umoŜliwić ich prezentację uŜytkownikowi. Klasa definiuje numery i nazwy ruchów oraz numery (krotności) obrotów. Ponadto umoŜliwia ona znalezienie ruchu przeciwną ścianą oraz ruchu przeciwnego do zadanego.

Związek wyglądu kostki z jej budową

Klasa związku budowy kostki z jej wyglądem zewnętrznym stworzona została ze względu na interfejs uŜytkownika. Operacje na kostce wykonywane są na klasach budowy kostki. Aby zaprezentować wyniki uŜytkownikowi konieczne jest przetłumaczenie niezrozumiałych dla człowieka numerów permutacji i orientacji na zbiór ścianek. Klasa definiuje mapowanie rogów i krawędzi na numery ścianek, które wchodzą w ich skład. Dzięki temu moŜliwe jest zarówno przekształcenie zbioru ścianek na zbiór elementów jak i przekształcenie odwrotne. Dla rozwaŜanego stanu kostki powyŜsza klasa umoŜliwia przekształcenie wyglądu kostki

F:gggwwrwwr,R:ryybbbbbb,U:rrorroyyy,B:bggoyyoyy,L:wwobggbgg,D:oowoowrrw,

na budowę tejŜe kostki

P(08,08)=[02,06,01,07,00,05,03,04] V(08,03)=[02,01,00,00,02,00,00,01] P(12,12)=[07,10,01,02,08,05,06,03,00,09,11,04] V(12,02)=[00,00,00,00,00,00,00,00,00,00,00,00]

i na odwrót. Zamiana polega na przemapowaniu oznaczeń ścinek kostki na połoŜenie elementów kostki. Oznacza to, Ŝe dla kaŜdej pozycji, w której mogą się znajdować elementy kostki naleŜy odczytać oznaczenia ścianek elementu znajdującego się w danej pozycji, sprawdzić jaki element zawiera te oznaczenia oraz w jakiej orientacji się znajduje. Np. dla pozycji, w której powinien znajdować się róg URF znajdują się ścianki oznaczone ‘y’, ‘’r’ i ‘g’.

F:gggwwrwwr,R:ryybbbbbb,U:rrorroyyy,B:bggoyyoyy,L:wwobggbgg,D:oowoowrrw,

Oznaczenia takie zawiera róg ULB o numerze porządkowym 2.

Page 85: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

79

P(08,08)=[02,06,01,07,00,05,03,04]

Gdy róg ten jest dobrze zorientowany, jego oznaczenia występują w kolejności ‘’r’, ‘’g’ i ‘y’. Oznacza to, Ŝe w rozwaŜanym stanie róg ten jest podwójnie obrócony.

V(08,03)=[02,01,00,00,02,00,00,01]

Szczegółowa operacja identyfikacji ułoŜenia wszystkich elementów kostki na podstawie jej wyglądu przedstawiona jest w tabelkach poniŜej. Ścianki wchodzące w skład rogów:

F:gggwwrwwr,R:ryybbbbbb,U:rrorroyyy,B:bggoyyoyy,L:wwobggbgg,D:oowoowrrw,

Wyznaczenie permutacji i orientacji rogów: Numer pozycji 0 1 2 3 4 5 6 7

Oznaczenie pozycji URF UFL ULB UBR DFR DLF DBL DRB

Ścianki elementu U9R1F3 U7F1L3 U1L1B3 U3B1R3 D3F9R7 D1L9F7 D7B9L7 D9R9B7

Oznaczenia ścianek yrg ygo rwg oby wrb ogw ryb wbo

Oznaczenie rogu ULB DBL UFL DRB URF DLF UBR DFR

Numer rogu 2 6 1 7 0 5 3 4

Zorientowany róg BUL BLD UFL DRB FUR DLF UBR FRD

Orientacja rogu 2 1 0 0 2 0 0 1

Permutacja i orientacja rogów:

P(08,08)=[02,06,01,07,00,05,03,04] V(08,03)=[02,01,00,00,02,00,00,01]

Ścianki wchodzące w skład krawędzi:

F:gggwwrwwr,R:ryybbbbbb,U:rrorroyyy,B:bggoyyoyy,L:wwobggbgg,D:oowoowrrw,

Wyznaczanie permutacji i orientacji krawędzi: Numer pozycji 0 1 2 3 4 5 6 7 8 9 10 11

Oznaczenie pozycji UR UF UL UB DR DF DL DB FR FL BL BR

Ścianki elementu U6R2 U8F2 U4L2 U2B2 D6R8 D2F8 D4L8 D8B8 F6R4 F4L6 B6L4 B4R6

Oznaczenia ścianek oy yg rw rg wb ow og ry rb wg yb ob

Oznaczenie krawędzi DB BL UF UL FR DF DL UB UR FL BR DR

Numer krawędzi 7 10 1 2 8 5 6 3 0 9 11 4

Zorientowana krawędź DB BL UF UL FR DF DL UB UR FL BR DR

Orientacja krawędzi 0 0 0 0 0 0 0 0 0 0 0 0

Permutacja i orientacja krawędzi:

P(12,12)=[07,10,01,02,08,05,06,03,00,09,11,04] V(12,02)=[00,00,00,00,00,00,00,00,00,00,00,00]

5.1.3. Wiedza o kostce Rubika

Na potrzeby bardziej złoŜonych modeli kostki i algorytmów jej rozwiązywanie stworzone zostały klasy przechowujące wiedzę o kostce.

Page 86: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

80

Tablica przekształceń kostki Rubika

Klasa tablicy przekształceń współrzędnych kostki przez obroty została stworzona na potrzeby modeli kostki opisujących stan kostki przez zbiór współrzędnych. W ich przypadku obliczenie wyniku, jaki da wykonanie obrotu na kostce, oznacza konieczność zamiany stanu na stan w modelu budowy wewnętrznej kostki, wykonanie obrotu i powrót do modelu współrzędnych. Jest to oczywiście bardzo czasochłonne. Optymalnym rozwiązaniem jest wobec tego przechowywanie w pamięci wyniku przekształceń kaŜdej współrzędnej niezaleŜnie przez podstawowe obroty moŜliwe do wykonania na kostce (często obroty jednokrotne). Klasa tablicy przekształceń zawiera oczywiście tablicę. Wielkość tej tablicy zdefiniowana jest jako iloczyn wielkości przekształcanej współrzędnej i liczby podstawowych ruchów (6). Tablica wypełniana jest na podstawie przekształceń stanu kostki w modelu budowy wewnętrznej. Dla kaŜdej moŜliwej wartości przekształcanej współrzędnej wykonywane są kolejno: zamiana współrzędnej na stan określający budowę wewnętrzną kostki, ruch na tym stanie oraz przekształcenie odwrotne zwracające współrzędną wynikową. Klasa tablicy przekształceń udostępnia oczywiście metodę dostępu do swoich pól jako wyników przekształceń współrzędnej przez ruch. Klasa tablicy przekształceń jest abstrakcyjną klasą bazową dla wszystkich uŜywanych w programie tablic przekształceń. Jej klasy pochodne musza definiować metody przekształcenia współrzędnej w stan budowy wewnętrznej kostki oraz przekształcenia odwrotnego.

Baza danych wzorców kostki Rubika

Klasa bazy danych wzorców została stworzona do oszacowania odległości od rozwiązania na potrzeby modeli kostki opisujących stan kostki przez zbiór współrzędnych oraz algorytmu IDA* uŜywanego w programie. Przechowuje ona odległość od rozwiązania dla jednej współrzędnej kostki, czyli odległość częściową. Minimalną ogólną odległość od rozwiązania moŜna oszacować jako maksimum z częściowych odległości. Klasa bazy danych wzorców zakłada, Ŝe maksymalna częściowa odległość od rozwiązania jest nie większa niŜ 14. Klasa zawiera tablicę definiującą odległość od rozwiązania kaŜdej wartości współrzędnej kostki. Tablica wypełniania jest w drodze przeszukiwania drzewa rozwiązań kostki wszerz począwszy od korzenia (wartości współrzędnej dla ułoŜonej kostki). Odległość od rozwiązania korzenia wynosi oczywiście 0 i jest ona wypełniania w tablicy jako pierwsza. Następnie iteracyjnie dla kaŜdej głębokości drzewa znajdywane są dzieci węzłów znajdujących się na tej głębokości. Ich odległość od rozwiązania to oczywiście odległość rodzica zwiększona o 1. W celu zwiększenia szybkości znajdywania odległości stanów od rozwiązania, został zastosowany algorytm wyszukiwania dwukierunkowego. Po wypełnieniu połowy tablicy dla kaŜdej następnej głębokości zamiast wyszukiwania stanów z juŜ obliczaną odległością od rozwiązania, wyszukiwane są te bez. Dla kaŜdego takiego stanu następuje wyszukanie odległości od rozwiązania jego rodzica w tablicy. JeŜeli odległość rodzica jest ustawiona, to odległość dziecka jest oczywiście ustawiana jako o 1 większa. W przeciwnym przypadku, jeŜeli odległość rodzica nie została jeszcze ustawiona, odległość jego dzieci pozostaje nieustawiona i zostanie znaleziona dopiero w kolejnych iteracjach. Klasa bazy danych wzorców udostępnia metody znalezienia odległości od rozwiązania dla współrzędnej. Klasa bazy danych wzorców jest abstrakcyjną klasą bazową dla wszystkich uŜywanych w programie baz danych wzorców. Jej klasy pochodne musza definiować wartość współrzędnej dla ułoŜonej kostki oraz metodę przekształcenia współrzędnej w stan budowy wewnętrznej kostki.

Rozwiązanie kostki Rubika

Rozwiązanie kostki Rubika to ciąg obrotów (ruchów i ich krotności), które naleŜy wykonać w podanej kolejności na rozwiązywanej kostce, aby uzyskać stan początkowy. Dodatkowo

Page 87: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

81

rozwiązanie moŜe mieć określone dodatkowe parametry: czy jest to rozwiązanie puste i czy jest optymalne. Klasa opisująca rozwiązanie kostki Rubika zawiera tablicę ruchów na kostce. Ponadto udostępnia metody zarządzania jej zawartością i ustawiania dodatkowych parametrów.

Znajdywanie rozwiązania kostki Rubika

Klasa szukająca rozwiązania kostki Rubika implementuje algorytm IDA*. Działa ona w oparciu o kontekst rozwiązywania koski, który dla kaŜdej iteracji algorytmu A* określa aktualny numer iteracji rozwiązania, aktualną głębokość, aktualną i nową wartość progową funkcji heurystycznej oraz liczbę rozwiniętych węzłów. Klasa umoŜliwia równieŜ szukanie następnego rozwiązania i wobec tego w kontekście zdefiniowany jest fakt szukania następnego rozwiązań, poprzednie znalezione rozwiązanie oraz minimalna długość poszukiwanego następnego rozwiązania. Klasa znajdywania rozwiązania kostki jest abstrakcyjną klasą bazową dla wszystkich uŜywanych w programie klas szukających rozwiązania kostki. Jej klasy pochodne musza definiować metodę szacowania odległości stanu kostki od rozwiązania.

5.1.4. Model i algorytm Korfa

W ramach programu zaimplementowane zostało rozwiązywanie kostki Rubika według algorytmu opisanego przez Korfa. Implementacja składa się z modelu kostki oraz klas pochodnych wiedzy o kostce dotyczących tego modelu.

Model kostki Rubika wg pomysłu Korfa

Kostka Rubika według pomysłu Korfa, moŜe zostać opisana jako zbiór trzech współrzędnych: ułoŜenia rogów oraz pierwszej i drugiej połowy krawędzi. Przekształcenie stanu kostki odbywa się przy uŜyciu tablic przekształceń współrzędnych kostki. Z powodu duŜego zakresu wartości współrzędnych, tablice przekształceń nie zostały wyznaczone dla współrzędnych, a jedynie dla ich składowych. I tak współrzędną ułoŜenia rogów moŜna określić jako złoŜenie numerów określających permutację i orientację rogów, a współrzędną ułoŜenia krawędzi - jako złoŜenie numerów kombinacji określających wybór połowy krawędzi oraz ich permutację i orientację. Klasa kostki Rubika definiuje stałe określające liczbę permutacji i orientacji rogów i połowy krawędzi oraz liczbę kombinacji wybrania połowy krawędzi. Definiuje ona równieŜ przekształcenie wartości kombinatorycznych opisujących kostkę na współrzędne w modelu kostki według Korfa. Klasa zawiera wszystkie niezbędne do wykonania ruchu tablice przekształceń, czyli zdefiniowane dla: permutacji rogów, orientacji rogów, wyboru i permutacji krawędzi oraz wyboru i orientacji krawędzi. Klasa udostępnia operacje na kostce oraz zamianę z i na stan w modelu budowy wewnętrznej koski. RozwaŜany stan kostki Rubika

moŜna zapisać przy pomocy trzech współrzędnych:

Page 88: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

82

(69 331 774, 35 067 363, 7 465 328)

Współrzędne te oznaczają kolejno ułoŜenie rogów, pierwszej i drugiej połowy krawędzi. Wylicza się je na podstawie permutacji ułoŜenia rogów, wariacji orientacji rogów, kombinacji wyboru połowy krawędzi oraz ich permutacji ułoŜenia i wariacji orientacji. Dla rozwaŜanego stanu o budowie:

P(08,08)=[02,06,01,07,00,05,03,04] V(08,03)=[02,01,00,00,02,00,00,01] P(12,12)=[07,10,01,02,08,05,06,03,00,09,11,04] V(12,02)=[00,00,00,00,00,00,00,00,00,00,00,00]

powyŜsze dane kombinatoryczne to:

P(08,08)=[02,06,01,07,00,05,03,04] // permutacja rogów V(08,03)=[02,01,00,00,02,00,00,01] // orientacja rogów C(06,12)=[02,03,05,07,08,11] // wybór krawędzi z pierwszej połowy P(06,06)=[01,02,05,03,00,04] // permutacja krawędzi z pierwszej połowy V(06,02)=[00,00,00,00,00,00] // orientacja krawędzi z pierwszej połowy C(06,12)=[00,01,04,06,09,10] // wybór krawędzi z drugiej połowy P(06,06)=[01,04,02,00,03,05] // permutacja krawędzi z drugiej połowy V(06,02)=[00,00,00,00,00,00] // orientacja krawędzi z drugiej połowy

Do konstrukcji współrzędnych według pomysłu Korfa uŜywa się oczywiście numerów porządkowych powyŜszych danych kombinatorycznych. Dla rozwaŜanego stanu wynoszą one:

(cp,co) = (21694,1719) // permutacja i orientacja rogów (e1c,e1p,c1o) = (761,483,0) // wybór, permutacja i orientacja krawędzi // z pierwszej połowy (e2c,e2p,c2o) = (162,368,0) // wybór, permutacja i orientacja krawędzi //z drugiej połowy

Współrzędne w modelu Korfa wylicza się dla nich następująco:

c = cp + 40320 * co // współrzędna rogów e1 = e1c*64*720 + e1p + e1o*924 // współrzędna pierwszej połowy krawędzi e2 = e2c*64*720 + e2p + e2o*924 // współrzędna drugiej połowy krawędzi

Wartości liczbowe uŜyte w powyŜszych wzorach to maksymalne ilości róŜnych permutacji, kombinacji i wariacji:

Zbiór kombinatoryczny Liczba moŜliwości

Permutacja ułoŜenia ośmiu rogów !8 =40 320

Wariacja orientacji ośmiu rogów 73 =2 187

Kombinacja wyboru sześciu krawędzi spośród dwunastu

6

12=924

Permutacja ułoŜenia sześciu krawędzi !6 =720

Wariacja orientacji sześciu krawędzi 62 =64

Dla rozwaŜanego stanu współrzędne wynoszą:

c = 21694+ 40320 * 1719 = 69 331 774 e1 = 761*64*720 + 483+ 0*924 = 35 067 363 e2 = 162*64*720 + 368 + 0*924 = 7 465 328

Page 89: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

83

Tablice przekształceń

Na potrzeby modelu kostki Rubika według Korfa zdefiniowane zostały cztery klasy tablic przekształceń. KaŜda z nich definiuje metodę przekształcenia wartości współrzędnej, z którą jest związana, na stan kostki w modelu budowy wewnętrznej kostki. Dla przykładu rozwaŜmy wykonanie obrotu F1 na rozwaŜanym stanie kostki. W tym celu naleŜy przekształcić współrzędne stanu kostki na współrzędne tabeli przekształceń, znaleźć odpowiednie przekształcenie w tabelach i przekształcić otrzymane wartości z powrotem na współrzędne stanu kostki. Dla rozwaŜanego stanu kostki współrzędne stanu w modelu Korfa wynoszą:

(c,e1,e2) = (69331774,35067363,7465328)

Rozbijając je na numery porządkowe składowych zbiorów kombinatorycznych otrzymujemy następujące wartości:

(cp,co) = (21694,1719) (e1c,e1p,e1o) = (761,483,0) (e2c,e2p,e2o) = (162,368,0)

Współrzędne czterech tabel przekształceń obliczamy jako:

cp = cp // współrzędna kombinacji rogów co = co // współrzędna orientacji rogów eXcp = eXc+eXp*924 // współrzędna kombinacji dowolnej połowy krawędzi eXco = eXc+eXo*924 // współrzędna orientacji dowolnej połowy krawędzi

Dla stanu z przykładu otrzymujemy wobec tego:

cp = 21 694 co = 1 719 e1cp = 761+483*924 = 447 053 e1co = 761+0*924 = 761 e2cp = 162+368*924 = 340 194 e2co = 162+0*924 = 162

Z odpowiednich tablic przekształceń pobieramy współrzędne po przekształceniu przez ruch F:

F (0) R (1) U (2) B (3) L (4) D (5) F (0) R (1) U (2) B (3) L (4) D (5)… …21 693 27 095 923 22 531 23 871 20 899 36 813 1 718 2 1 736 584 1 933 1 960 1 72621 694 27 092 920 22 535 23 872 20 903 36 814 1 719 246 270 585 1 936 2 051 1 70221 695 27 093 921 22 534 23 873 20 902 36 815 1 720 247 289 586 1 909 2 132 1 704… …

F (0) R (1) U (2) B (3) L (4) D (5) F (0) R (1) U (2) B (3) L (4) D (5)… …

340 193 333 052 438 137 340 571 458 395 451 085 229 339 161 9 652 161 539 7 483 173 187340 194 338 344 207 688 340 572 342 036 569 221 229 340 162 16 792 712 540 2 004 37 188340 195 338 345 325 933 340 573 458 396 451 076 229 341 163 16 793 685 541 7 484 164 189… …

447 052 223 446 3 010 468 850 349 179 542 223 447 026 760 10 002 238 382 10 995 759 734447 053 223 447 3 907 468 851 348 191 402 826 447 027 761 10 003 211 383 18 323 886 735447 054 1 435 447 054 468 852 349 180 431 334 447 028 762 31 927 762 384 10 996 750 736… …… …

Tabela przekształceń orientacji połowy krawędzi

Tabela przekształceń permutacji rogów Tabela przekształceń orientacji rogów

Tabela przekształceń permutacji połowy krawędzi

Otrzymujemy następujące współrzędne:

cp = 27 092 co = 246

Page 90: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

84

e1cp = 223 447 e1co = 10 003 e2cp = 338 344 e2co = 16 792

które moŜna rozbić na następujące wartości porządkowe zbiorów kombinatorycznych:

(cp,co) = (27092,246) (e1c,e1p,e1o) = (763,241,10) (e2c,e2p,e2o) = (160,366,18)

z czego prosto moŜna wyliczyć współrzędne stanu w modelu Korfa:

(c,e1,e2) = (9 945 812, 35 166 481, 7 386 126).

Otrzymany stan moŜna równieŜ zapisać w postaci wyglądu zewnętrznego kostki:

F:wwgwwgrrg,R:yyyybbybb,U:rrorroggo, B:bggoyyoyy,L:wwobgobgw,D:bbroowrrw,

budowy kostki:

P(08,08)=[06,05,01,07,02,00,03,04] V(08,03)=[00,01,00,00,00,01,00,01] P(12,12)=[07,09,01,02,08,00,06,03,10,05,11,04] V(12,02)=[00,01,00,00,00,01,00,00,01,01,00,00]

oraz rysunku poglądowego:

Bazy danych wzorców

Na potrzeby szukania rozwiązania kostki według Korfa zdefiniowane zostały dwie klasy baz danych wzorców: dla rogów i dla połowy krawędzi. Obie korzystają z odpowiednich tablic przekształceń kostki i wobec tego muszą zamieniać wartości kombinatoryczne w nich zawarte na współrzędne, na których same operują. Dla przykładu znajdźmy oszacowanie odległości od rozwiązania otrzymanego w poprzednim punkcie stanu opisanego w modelu Korfa jako:

(9 945 812, 35 166 481, 7 386 126).

W tym celu naleŜy znaleźć w bazach wzorców odległości od rozwiązania dla kaŜdej współrzędnej z osobna, a następnie wybrać ich maksimum:

Page 91: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

85

Indeks tabeli … …Dane w tabeli … …Współrzędna 9 945 810 9 945 811 9 945 812 9 945 813 9 945 814 4 972 908

Odległość od rozwiązania 10 7 4 8 4 8

Indeks tabeli …Dane w tabeli …Współrzędna 35 166 478 35 166 479 35 166 480 35 166 481

Odległość od rozwiązania 7 4 7 4

Indeks tabeli … …Dane w tabeli … …Współrzędna 7 386 124 7 386 125 7 386 126 7 386 127 7 386 128 7 386 129

Odległość od rozwiązania 6 6 4 5 4 5

Baza danych wzorców dla rogów

3 693 062102

Baza danych wzorców dla pierwszej połowy krawędzi

Baza danych wzorców dla drugiej połowy krawędzi

4 972 907

17 583 239 17 583 240

84 84

4 972 905 4 972 906

3 693 063 3 693 064

122 132 132

71 71

Czyli szacowana odległość rozwaŜanego stanu od rozwiązania to 4 ruchy.

Szukanie rozwiązania

Szukanie rozwiązania w algorytmie Korfa oparte jest na trzech bazach danych wzorców: dla rogów oraz pierwszej i drugiej połowy krawędzi. Wartość funkcji heurystycznej dla algorytmu IDA* określana jest jako maksimum z odległości otrzymanych z tych baz. Znajdywane rozwiązanie jest zawsze optymalne. Wobec tego nie ma potrzeby szukania następnego rozwiązania. Przykład znajdywania rozwiązania przedstawiony został na dołączonym diagramie12. KaŜdy przeszukiwany stan reprezentowany tam jest w postaci:

ilustracja stanu

opis statusu stanu – stan startowy, stan sprawdzany, stan nie sprawdzany gdyŜ ruch prowadzący do niego jest zabroniony

stan jako wygląd zewnetrzny

stan jako budowa kostki

współrzędne stanu budowy kostki

współrzędne stanu w modelu Korfa

odległości częściowe od rozwiązania

ograniczenie kosztu przeszukiwanych stanów dla kolejnej iteracji IDA* (dotyczy tylko stanu początkowego)

głębokość, odległość od rozwiązania i koszt całkowity rozwaŜanego węzła

zaznaczenie rozwijanego węzła bądź znalezionego rozwiązania

12 Dodatek D do niniejszej pracy.

Page 92: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

86

5.1.5. Model i algorytm Kociemby

W ramach programu zaimplementowane zostało rozwiązywanie kostki Rubika według algorytmu opisanego przez Kociembę. Implementacja składa się z modelu kostki oraz klas pochodnych wiedzy o kostce dotyczących tego modelu.

Model kostki Rubika wg pomysłu Kociemby

Algorytm Kociemby opiera się na pomyśle zdefiniowania dwóch oddzielnych modeli kostki Rubika. Drugi model (dla drugiej fazy algorytmu) określa stany z poprawnie zorientowanymi wszystkimi rogami i krawędziami oraz krawędziami ze środkowej warstwy znajdującymi się kaŜda we właściwej krawędzi. Pierwszy model (dla pierwszej fazy algorytmu) określa wszystkie pozostałe stany. Model kostki dla pierwszej fazy algorytmu złoŜony jest z trzech współrzędnych określających orientację rogów i krawędzi oraz wybór krawędzi w środkowej warstwie. Model kostki dla drugiej fazy algorytmu złoŜony jest z trzech innych współrzędnych, które określają permutację rogów, krawędzi ze środkowej warstwy oraz krawędzi z dwóch pozostałych warstw przy załoŜeniu, Ŝe wszystkie współrzędne z pierwszej fazy mają wartości początkowe. Na potrzeby obu modeli zdefiniowane zostały stałe określające liczbę permutacji rogów, krawędzi z jednej i z dwóch warstw, liczbę orientacji rogów i krawędzi oraz liczbę kombinacji wybrania krawędzi z jednej warstwy. Oba modele zawierają tabele przekształceń zdefiniowane dla swoich współrzędnych. Przy ich uŜyciu wykonywane są ruchy na stanach kostki. Oba modele umoŜliwiają równieŜ przekształcenie do i z modelu budowy kostki. RozwaŜany stan kostki Rubika

nie znajduje się w grupie >=< 2,2,2,2,,1 BFLRDUG . Stany kostki znajdujące się w tej grupie mają wszystkie rogi i krawędzie dobrze zorientowane. Dodatkowo wszystkie krawędzie ze środkowej warstwy znajdują się w tej warstwie. Sprawdzenie czy stan kostki posiada powyŜsze właściwości najłatwiej wykonać przy uŜyciu opisu budowy kostki:

P(08,08)=[02,06,01,07,00,05,03,04] V(08,03)=[02,01,00,00,02,00,00,01] P(12,12)=[07,10,01,02,08,05,06,03,00,09,11,04] V(12,02)=[00,00,00,00,00,00,00,00,00,00,00,00]

Widać w nim wyraźnie, Ŝe nie wszystkie rogi są poprawnie zorientowane, oraz Ŝe dwie krawędzie ze środkowej warstwy się w niej nie znajdują.

P(08,08)=[02,06,01,07,00,05,03,04] V(08,03)=[02,01,00,00,02,00,00,01] P(12,12)=[07,10,01,02,08,05,06,03,00,09,11,04] V(12,02)=[00,00,00,00,00,00,00,00,00,00,00,00]

Page 93: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

87

W związku z powyŜszym rozwaŜany stan kostki moŜna zapisać jedynie w modelu Kociemby dla fazy pierwszej algorytmu. W modelu tym określa się jedynie wariację orientacji rogów, kombinację wyboru krawędzi znajdujących się w środkowej warstwie oraz wariację orientacji krawędzi. Wyprowadzone są one z budowy kostki. Odpowiednie zbiory kombinatoryczne dla rozwaŜanego przykładu wyglądają następująco:

V(08,03)=[02,01,00,00,02,00,00,01] C(04,12)=[01,04,09,10] V(12,02)=[00,00,00,00,00,00,00,00,00,00,00,00]

Numery porządkowe powyŜszych zbiorów stanowią współrzędne stanu w modelu Kociemby dla pierwszej fazy algorytmu. Tutaj wynoszą one:

(1 719, 247, 0)

Warto zauwaŜyć, Ŝe opis ten nie jest jednoznaczny. Zawiera on jedynie informacje o orientacji elementów i krawędziach znajdujących się w środkowej warstwie. Gubi jednak informacje o permutacji wszystkich elementów. Dlatego teŜ po przekształceniu powyŜszego stanu z powrotem do opisu wyglądu i budowy kostki otrzymamy:

P(08,08)=[00,01,02,03,04,05,06,07] V(08,03)=[02,01,00,00,02,00,00,01] P(12,12)=[00,08,01,02,09,03,04,05,06,10,11,07] V(12,02)=[00,00,00,00,00,00,00,00,00,00,00,00]

czyli

F:gbbywowyo,R:rbbgbywgy,U:rrrrrrwww,B:ygyoyyowy,L:gwrbgggbg,D:orboowoob,

wyglądający następująco:

(oryginalnie: ).

Na rysunkach cięŜko zauwaŜyć jakiekolwiek cechy wspólne tych dwóch stanów. Widać je natomiast wyraźnie w opisie ich budowy – oryginalnego stanu:

P(08,08)=[02,06,01,07,00,05,03,04] V(08,03)=[02,01,00,00,02,00,00,01] P(12,12)=[07,10,01,02,08,05,06,03,00,09,11,04] V(12,02)=[00,00,00,00,00,00,00,00,00,00,00,00]

i stanu po przekształceniu do modelu Kociemby dla pierwszej fazy algorytmu:

P(08,08)=[00,01,02,03,04,05,06,07] V(08,03)=[02,01,00,00,02,00,00,01] P(12,12)=[00,08,01,02,09,03,04,05,06,10,11,07] V(12,02)=[00,00,00,00,00,00,00,00,00,00,00,00]

Dane dotyczące orientacji są oczywiście w obu opisach takie same:

V(08,03)=[02,01,00,00,02,00,00,01] V(12,02)=[00,00,00,00,00,00,00,00,00,00,00,00]

Page 94: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

88

Po przekształceniu stanu do modelu Kociemby dla pierwszej fazy algorytmu zupełnie tracona jest informacja o permutacji rogów. Aby przekształcić stan z tego modelu do opisu budowy, zakłada się, Ŝe rogi są ustawione we właściwych pozycjach:

P(08,08)=[02,06,01,07,00,05,03,04] // oryginalny opis P(08,08)=[00,01,02,03,04,05,06,07] // opis po przekształceniu

Podobnie tracona jest informacja o permutacji krawędzi. Tutaj model przechowuje jedynie informacje, gdzie znajdują się krawędzie ze środkowej warstwy. Nie posiada jednak informacji, w jakiej kolejności są one ułoŜone, ani w jakiej kolejności są ustawione pozostałe krawędzie:

P(12,12)=[07,10,01,02,08,05,06,03,00,09,11,04] P(12,12)=[00,08,01,02,09,03,04,05,06,10,11,07]

Stan kostki moŜna zapisać w modelu Kociemby dla drugiej fazy algorytmu jedynie, jeśli ma on dobrze zorientowane wszystkie elementy oraz krawędzie środkowej warstwy znajdują się w tej warstwie, czyli naleŜy on do grupy >=< 2,2,2,2,,1 BFLRDUG . Własności te spełnia następujący stan:

którego wygląd zewnętrzny moŜna opisać jako:

F:wwwwwwwww,R:bbgbbgbbg,U:ooorrrrrr,B:yyyyyyyyy,L:bggbggbgg,D:oooooorrr,

a budowę jako:

P(08,08)=[00,01,07,06,04,05,03,02] V(08,03)=[00,00,00,00,00,00,00,00] P(12,12)=[00,01,02,07,04,05,06,03,08,09,11,10] V(12,02)=[00,00,00,00,00,00,00,00,00,00,00,00]

Istotnymi własnościami stanu w drugiej fazie algorytmu Kociemby są permutacje wszystkich jego elementów. Wyprowadza się je bezpośrednio z budowy kostki. Dla rozwaŜanego przykładu są to:

P(08,08)=[00,01,07,06,04,05,03,02] // permutacja rogów P(04,04)=[00,01,03,02] // permutacja krawędzi w środkowej warstwie P(08,08)=[00,01,02,07,04,05,06,03] // permutacja pozostałych krawędzi

Numery porządkowe powyŜszych zbiorów kombinatorycznych stanowią współrzędne stanu w modelu Kociemby dla drugiej fazy algorytmu. Dla podanego przykładu wynoszą one:

(713, 1, 105)

Tablice przekształceń

Na potrzeby modelu kostki Rubika według Kociemby zdefiniowane zostały dwie klasy tablic przekształceń – po jednej dla kaŜdej fazy algorytmu. KaŜda z nich definiuje metodę przekształcenia wartości współrzędnej, z którą jest związana, na stan kostki w modelu

Page 95: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

89

budowy wewnętrznej kostki. Tablica dla kaŜdej ze współrzędnych identyfikowana jest po numerze współrzędnej. Tablice przekształceń indeksowane są współrzędnymi stanu w modelu Kociemby. Wykonanie ruchu na stanie w tym modelu to zatem tylko znalezienie odpowiednich wpisów w trzech tabelach. Dla rozwaŜanego stanu pierwszej fazy opisanego jako

(713, 1, 105)

wykonanie ruchu F1 następuję przez odczyt odpowiednich wartości z tabel przekształceń

F (0) R (1) U (2) B (3) L (4) D (5)…1 718 2 1 736 584 1 933 1 960 1 7261 719 246 270 585 1 936 2 051 1 7021 720 247 289 586 1 909 2 132 1 704…

F (0) R (1) U (2) B (3) L (4) D (5)…246 436 20 330 204 246 277247 245 281 331 241 174 278248 246 244 332 205 239 279

F (0) R (1) U (2) B (3) L (4) D (5)0 550 0 0 137 0 01 551 65 1 1 256 1

Tabela przekształceń orientacji krawędzi

Tabela przekształceń kombinacji krawędzi ze środkowej warstwy

Tabela przekształceń orientacji rogów

w wyniku czego otrzymuje się stan

(246, 245, 550)

czyli

o budowie:

P(08,08)=[00,01,02,03,04,05,06,07] V(08,03)=[00,01,00,00,00,01,00,01] P(12,12)=[00,08,01,02,09,03,04,05,11,06,10,07] V(12,02)=[00,01,00,00,00,01,00,00,01,01,00,00]

Na rozwaŜanym stanie drugiej fazy

(713, 1, 105)

nie moŜna wykonać ruchu F1, gdyŜ nie naleŜy od do grupy >=< 2,2,2,2,,1 BFLRDUG . MoŜna natomiast wykonać ruch F2. Odpowiednie tabele przekształceń zawierają:

Page 96: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

90

F (0) R (1) U (2) B (3) L (4) D (5)…712 28 782 36 106 6 473 1 4 213 574713 28 783 36 107 6 472 0 4 212 575714 28 779 36 115 6 476 11 4 204 564

F (0) R (1) U (2) B (3) L (4) D (5)0 6 21 0 1 2 01 7 20 1 0 3 12 8 23 2 4 0 2

F (0) R (1) U (2) B (3) L (4) D (5)…104 3 108 21 098 5 984 1 593 92105 3 109 21 099 5 985 0 592 93106 3 113 21 100 5 986 3 588 94

Tabela przekształceń permutacji rogów

Tabela przekształceń permutacji krawędzi ze środkowej warstwy

Tabela przekształceń permutacji pozostałych krawędzi

co daje w rezultacie stan

(28 783, 7, 3 109),

czyli

o budowie:

P(08,08)=[05,04,07,06,01,00,03,02] V(08,03)=[00,00,00,00,00,00,00,00] P(12,12)=[00,05,02,07,04,01,06,03,09,08,11,10] V(12,02)=[00,00,00,00,00,00,00,00,00,00,00,00]

Tabele przekształceń dla drugiej fazy algorytmu dotyczą najmniejszych dozwolonych obrotów kaŜdego ruchu, czyli odpowiednio U,D,R2,L2,F2 i B2. Wszystkie inne tabele przekształceń stworzone są dla ruchów z obrotem o 90º.

Bazy danych wzorców

Na potrzeby szukania rozwiązania kostki według Kociemby zdefiniowane zostały dwie klasy baz danych wzorców – po jednej dla kaŜdej fazy algorytmu. Określają one odległość rozwiązania uwzględniając dwie z trzech współrzędne stanu kostki. Identyfikowane są przez numery tych współrzędnych i korzystają z odpowiednich tablic przekształceń kostki. Ze względu na duŜą liczbę wartości współrzędnych drugiej fazy określających permutację rogów i krawędzi z dwóch warstw, w programie nie jest wykorzystywana baza danych wzorców oparta na tych dwóch współrzędnych. Szacunkowy koszt rozwiązania dla stanu z pierwszej fazy

Page 97: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

91

(246, 245, 550)

obliczony na podstawie danych z odpowiednich baz danych wzorców

… 243 244 245 246… …

Indeks wewn tabeliDane w tabeli

533 872 533 873 533 874 533 875 Współrzędna

6 6 6 6 Odległość od rozwiązania

536 058 536 059 536 060 536 061

5 3 5 3

538 246 538 247 538 248 538 249

6 5 5 5

… …

… 243 244 245 246… …

1 200 906 1 200 907 1 200 908 1 200 909

7 6 7 6

Indeks wewn tabeliDane w tabeli

1 203 094 1 203 095 1 203 096 1 203 097 Współrzędna

6 5 3 5 Odległość od rozwiązania

1 205 280 1 205 281 1 205 282 1 205 283

7 7 7 7

… …

… 243 244 245 246… …

Indeks wewn tabeliDane w tabeli

271 998 271 999 272 000 272 001 Współrzędna5 4 7 5 Odległość od rozwiązania

272 492 272 493 272 494 272 495

6 3 6 3

272 988 272 989 272 990 272 991

6 7 7 6

… …

Baza danych wzorców dla orientacji rogów i krawędzi

Baza danych wzorców dla orientacji rogów i wyboru krawędzi środkowej warstwy

Baza danych wzorców dla wyboru krawędzi środkowej warstwyi orientacji krawędzi

551

136 495 136 496118 103

550

136 247 136 24854 54

549

136 000 136 00169 87

… …

… …

… …

551

602 641 602 642119 119

… …

246

269 124 269 12586 85

244

245

268 030 268 03153 53

102 102

… …

266 937 266 938

549

600 454 600 455103 103

550

601 548 601 54986 83

… wynosi 3. Szacunkowy koszt rozwiązania dla stanu z drugiej fazy

(28 783, 7, 3 109)

obliczony na podstawie danych z odpowiednich baz danych wzorców

Page 98: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

92

… 28 781 28 782 28 783 28 784… …

Indeks wewn tabeliDane w tabeli

270 701 270 702 270 703 270 704 Współrzędna13 6 13 6 Odległość od rozwiązania

311 020 311 021 311 022 311 023

11 2 11 2

351 341 351 342 351 343 351 344

11 6 11 6

… …

… 5 6 7 8 9 10 …… … …

74 597 74 598 74 599 74 600 74 601 74 602

5 8 5 8 8 5

74 620 74 621 74 622 74 623 74 624 74 625

10 2 10 2 4 11

37 30188

37 313180

3109

37 311 37 31242 42

3108

37 299 37 300133 133

Baza danych wzorców dla permutacji rogów i krawędzi ze środkowej warstwy

Baza danych wzorców dla permutacji krawędzi ze środkoweji z dwóch pozostałych warstw

… …

6

135 351 135 352109 109

7

155 511 155 512

…43 43

8

175 671 175 672107 107

… …

… …

wynosi 2.

Szukanie rozwiązania

Algorytm szukania rozwiązania kostki według pomysły Kociemby polega na znalezieniu rozwiązania w pierwszym modelu kostki, przetłumaczenia otrzymanego stanu na stan w drugim modelu i znalezienie dla niego rozwiązania. Rozwiązaniem jest wtedy suma rozwiązań otrzymanych dla faz algorytmu. Rozwiązanie znalezione w ten sposób z załoŜenia nie musi być optymalne. Dlatego teŜ moŜliwe jest szukanie następnego rozwiązania jako następnego rozwiązania pierwszej fazy i związanego z nim rozwiązania drugiej fazy. JeŜeli rozwiązanie którejś fazy jest zerowej długości, to rozwiązanie kostki jest optymalne. Szukanie optymalnego rozwiązania polega zatem na znalezieniu dla kostek drugiego modelu pierwszego rozwiązania, a dla kostek pierwszego modelu – rozwiązania, które prowadzi do rozwiązania równieŜ w drugim modelu. Przykład znajdywania rozwiązania przedstawiony został na dwóch dołączonych diagramach13 – po jednym dla kaŜdej fazy algorytmu.

5.2. Praca z programem

Program CubeSolver wywoływany jest z linii poleceń. Akceptuje argumenty i na ich podstawie wykonuje operację, której wynik wyświetla na ekranie. Argumentami programu CubeSolver są nazwa metody i parametry, które przyjmuje. CubeSolver wykonuje cztery operacje:

- znajduje rozwiązanie kostki Rubika, - wykonuje testy jednostkowe, - wykonuje testy wydajnościowe, - zwraca znaczenie zwracanego przez siebie kodu błędu.

13 Dodatek D do niniejszej pracy.

Page 99: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

93

Pierwsza operacja stanowi cel niniejszej pracy. Pozostałe trzy są operacjami administracyjnymi. UmoŜliwiają one sprawdzenie poprawności i jakości zaimplementowanego rozwiązania.

5.2.1. Szukanie rozwiązania kostki Rubika

W celu znalezienia rozwiązania stanu kostki Rubika naleŜy uŜyć następującej składni:

./CubeSolver_CE/CubeSolver -m=Solve_Cube -a=Algorithm -c=CubeState [-s=PrevSolution] [-l=Log]

Operacja szukania rozwiązania wymaga podania dwóch parametrów – stanu kostki oraz algorytmu, przy uŜyciu którego ma zostać znalezione rozwiązanie. Stan kostki naleŜy wprowadzić jako ciąg znaków reprezentujący ścianki kostki:

X:xxxxxxxxx,X:xxxxxxxxx,X:xxxxxxxxx,X:xxxxxxxxx,X:xxxxxxxxx,X:xxxxxxxxx,

gdzie: - X oznacza ścianę i moŜe przyjąć jedną z wartości: F, R, U, B, L, D. Ponadto wartość

ta oczywiście nie moŜe się powtórzyć w zakresie jednego stanu. Kolejność ścian nie ma znaczenia.

- x oznacza ściankę kostki. Polecane wartości to oznaczenie kolorów ścian kostki: b (blue - niebieski), r (red - czerwony), w (white - biały), g (green - zielony), o (orange - pomarańczowy) i y (yellow - Ŝółty). KaŜde oznaczenie powinno wystąpić dokładnie 9 razy. Oznaczenie na środkach ścian (na pozycji piątej w ścianie) nie mogą się powtarzać. Ponadto ciąg znaków powinien reprezentować dozwolony stan kostki. W przeciwnym przypadku program zwróci kod błędu oznaczający niepoprawność stanu kostki, a rozwiązanie nie zostanie znalezione. Kolejność ścianek w ściance określona jest na poniŜszym rysunku:

L1 L2 L3

L4 L5 L6

L7 L8 L9

F1 F2 F3

F4 F5 F6

F7 F8 F9

U1 U2 U3

U4 U5 U6

U7 U8 U9

B1 B2 B3

B4 B5 B6

B7 B8 B9

R1 R2 R3 R4 R5 R6

R7 R8 R9 R1 R2 R3

R4 R5 R6

R7 R8 R9

Stan odpowiadający ułoŜonej kostce moŜna zapisać jako:

U:wwwwwwwww,F:bbbbbbbbb,R:rrrrrrrrr,D:yyyyyyyyy,B:ggggggggg,L:ooooooooo

a stan osiągnięty po wykonaniu na niej ruchu R1 jako:

U:wwbwwbwwb,F:bbybbybby,R:rrrrrrrrr,D:yygyygyyg,B:wggwggwgg,L:ooooooooo

Page 100: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

94

Szukanie rozwiązania moŜe się odbyć według jednego z trzech zaimplementowanych algorytmów:

- algorytmu Korfa (Korf) zwracającego optymalne rozwiązanie. Niestety czas szukania tego rozwiązania silnie zaleŜy od odległości tego rozwiązania. Jedynie w przypadku rozwiązań o długości do 15 ruchów, rozwiązanie znajdywane jest w racjonalnym czasie (w przeciągu kilku sekund). W przypadku bardziej złoŜonych rozwiązań, rozwiązywanie problemu moŜe trwać godziny a nawet dni.

- algorytmu Kociemby (Kociemba) zwracającego rozwiązanie sub-optymalne. Czas szukania tego rozwiązania to ułamki sekund. Niestety, co za tym idzie, jakość tego rozwiązania jest duŜo niŜsza od rozwiązania optymalnego. Maksymalna długość rozwiązania znalezionego tym algorytmem wynosi 32 ruchy. W rzeczywistości wacha się ona w okolicach 22-24 ruchów.

- wielokrotnego uŜycia algorytmu Kociemby aŜ do znalezienia rozwiązania optymalnego (KociembaOptimal). W algorytmie tym znajdywane jest rozwiązanie pierwszej fazy algorytmu Kociemby, które jest jednocześnie rozwiązaniem całego problemu. Algorytm ten został zaimplementowany głównie w celu porównania z algorytmem Korfa. Znajduje on rozwiązania o tej samej długości, ale w duŜo dłuŜszym czasie.

Rozwiązanie, znalezione w wyniku działania programu, zwracane jest w postaci listy ruchów (nazwy i krotności) przedzielonych przecinkiem. Dla ułatwienia zapisu wszystkie ruchy prezentowane są w postaci dwóch znaków: litery oznaczającej ścianę i cyfry oznaczającej kąt obrotu. Ściana moŜe przyjąć jedną z wartości F, R, U, B, L, D, oznaczającą odpowiednio ścianę przednią, prawą, górną, tylną, lewą i dolną. Kąt obrotu przyjmuje jedną z wartości: 1, 2, 3, oznaczające odpowiednio obrót o 90º, 180º i 270º. Np.:

R3,U3,R2,F2

W przypadku rozwiązania znalezionego algorytmem Kociemby dodatkowo przy uŜyciu nawiasów wydzielone są części rozwiązania odpowiadające rozwiązaniom obu faz algorytmu. Pierwsza część przeprowadza kostkę do stanu z grupy pośredniej

>=< 2,2,2,2,,1 BFLRDUG . Druga część ostatecznie rozwiązuje kostkę, przy uŜyciu jedynie operacji z grupy G1. Np.:

(R3),(U3,R2,F2)

W przypadku algorytmu Kociemby moŜliwe jest dodatkowo podanie poprzednio znalezionego rozwiązania. Wtedy poszukiwane będzie następne rozwiązanie. Rozwiązanie musi zostać dostarczone w postaci, w jakiej program je zwraca.

5.2.2. Testy jednostkowe programu

W celu sprawdzenia poprawności działania modułów programu, zaprojektowane zostały testy jednostkowe. Pozwalają one sprawdzić, czy wszystkie zaimplementowane metody działają poprawnie. Jest to szczególnie uŜyteczne podczas przenoszenia kodu programu na inną platformę bądź kompilator, gdyŜ mogą się one między sobą róŜnić. Ponadto podczas rozwijania programu, umoŜliwiają one szybkie sprawdzenie czy podstawowe funkcje programu nie zostały zepsute. Testy jednostkowe moŜna wykonać wywołując polecenie:

./CubeSolver_CE/CubeSolver -m=Test_Unit [-u=Unit] -r=Repetitions [-l=Log]

Page 101: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

95

Testy rozpoznają 4 moduły do testowania: - Combinatorials – elementy kombinatoryki - Cube – podstawowe modele kostki Rubika i zamiana jednego na drugi - Korf – model i algorytm Korfa - Kociemba – model i algorytm Kociemby

Testy jednostkowe mogą zostać wykonane dla jednego albo kilku modułów (wtedy naleŜy je rozdzielić przecinkiem). W przypadku nie podania nazwy modułu, zostaną wykonane testy wszystkich czterech modułów. Testy jednostkowe sprawdzają poprawność działania kaŜdej metody klas wchodzących w zakres danego modułu. Sprawdzane jest zarówno działanie przy poprawnych warunkach wejściowych jak i niepoprawnych, kiedy rzucany jest wyjątek. Na potrzeby testów ustalone zostały zarówno warunki wejściowe jak i poŜądane wyniki. Testy kończą się sukcesem w przypadku zwrócenia poprawnego wyniku we wszystkich testowanych przypadkach. Testy te sprawdzają poprawność zaimplementowanych obiektów i algorytmów. Są bardzo uŜyteczne podczas implementacji jak i podczas przenoszenia kodu na inną platformę. Dzięki nim moŜna bardzo szybko ustalić problemy występujące w oprogramowaniu i zdefiniować róŜnice implementacji języka C++ na róŜnych platformach. W ramach niniejszej pracy kod testowany był na pod system operacyjnym Windows z kompilatorem mingw, następnie przeniesiony na system operacyjny Unix z kompilatorem gcc, a ostatecznie uruchomiony pod systemem QNX z kompilatorem QCC. Dzięki testom jednostkowym szybko udało się ustalić róŜnice implementacji operacji na łańcuchach znaków oraz obsługi sytuacji wyjątkowych między róŜnymi kompilatorami.

5.2.3. Testy wydajnościowe programu

Najciekawszą funkcją stworzonego programu jest moŜliwość porównania jakości i czasu pracy zaimplementowanych algorytmu. MoŜna to zrobić wywołując polecenie:

./CubeSolver_CE/CubeSolver -m=Test_Performance [-a=Algorithm] -n=MovesNumber -r=Repetitions

W jego następstwie zostanie przeprowadzony szereg testów tworzących losowy stan kostki i szukający jego rozwiązania róŜnymi algorytmami. Zbadany zostanie czas szukania rozwiązania oraz zapisany zostanie kontekst pracy algorytmu, czyli przede wszystkim liczba przeszukanych i rozwiniętych węzłów. Testy wydajnościowe mogą zostać wykonane dla jednego bądź kilku algorytmów. W przypadku braku argumentu oznaczającego algorytm, testy zostaną przeprowadzone dla wszystkich zaimplementowanych algorytmów. Warunki testów określone są przez dodatkowe dwa parametry:

- liczba ruchów tworzących losowy stan kostki. NaleŜy podać liczbę ruchów dla pierwszego oraz ostatniego testu. Dodatkowo moŜna podać krok testu. Domyślnie zostanie on przyjęty jako równy 1.

- liczba powtórzeń testu dla określonej liczby ruchów. NaleŜy podać liczbę powtórzeń testu dla kaŜdej liczby ruchów generujących stan początkowy.

Dla kaŜdego stanu kostki zostanie przeprowadzony test początkowy zwracający informacje o kontekście algorytmu oraz czas znajdywania rozwiązania. Na podstawie pierwszego pomiaru czasu dobierana jest liczba powtórzeń testu w celu dokładniejszego zbadania czasu pracy algorytmu. Takie podejście zostało przyjęte ze względu na bardzo róŜniące się czasy trwania szukania rozwiązania w zaleŜności od stanu początkowego kostki. RóŜnice te to nawet kilka rzędów wielkości. Dlatego teŜ aby poprawnie zbadać czas trwania szukania rozwiązania prostego stanu, test naleŜy powtórzyć milion razy, a w przypadku złoŜonego rozwiązania – jeden raz w zupełności wystarczy.

Page 102: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

96

5.2.4. Sprawdzenie znaczenia kodu zwracanego przez program

Dodatkową metodą programu, czysto administracyjną, jest sprawdzenie znaczenia kodu zwracanego przez program. Jest ona wywoływana w następujący sposób:

./CubeSolver_CE/CubeSolver -m=Error_Code -e=Error

5.3. Wyniki pracy

W ramach pracy przeprowadzone zostały testy wydajności zaimplementowanych algorytmów. Ich głównym celem było określenie, czy i który algorytm moŜe być wykorzystany do znajdowania rozwiązania kostki Rubika w systemie robota. Badania dotyczyły około 300 stanów. Obliczenia zostały wykonane na komputerze z procesorem Athlon XP 1800 z 1GB pamięci, systemem operacyjnym Linux Debian Etch (jądro 2.6.19) i kompilatorem gcc 3.4.6.

5.3.1. Porównanie działania algorytmów Korfa i Kociemby

W ramach pracy zaimplementowane zostały dwa algorytmy znajdowania rozwiązania kostki Rubika – Korfa i Kociemby. Aby zadecydować, który z nich i jak naleŜy uŜyć w systemie sterowania robota, naleŜy je porównać. NajwaŜniejszymi parametrami są czas obliczeń i jakość znajdywanego rozwiązania. Czas obliczeń nie powinien przekraczać kilku sekund, najwyŜej minut. Jest to bowiem czas, kiedy robot po obejrzeniu kostki zastanawia się jak ją rozwiązać. Jakość rozwiązania natomiast przekłada się na czas, w jakim robot będzie układał kostkę. Im więcej ruchów będzie musiał wykonać, tym dłuŜej mu to zajmie. Konieczne jest wobec tego znalezienie optymalnego rozwiązania, z jednocześnie zminimalizowanym czasem poszukiwania rozwiązania i zminimalizowaną długością otrzymanego rozwiązania. W ramach badań porównana została jakość rozwiązania, czas jego znalezienia oraz liczba węzłów przeszukana i rozwinięta w tym celu. Badania prowadzone były dla coraz bardziej złoŜonych stanów. Stany tworzone były przez wykonanie na ułoŜonej kostce coraz większej ilości ruchów. Ilość wykonanych ruchów stanowiła oczywiście szacunkową złoŜoność stanu. Dla kaŜdej złoŜoności problemu wykonanych zostało 20 testów. Test składał się z szacunkowego pomiaru czasu szukania rozwiązania i jednoczesnego zbadania jakości rozwiązania oraz z dokładniejszego pomiaru czasu szukania rozwiązywania. Testy zostały przerwane przy złoŜoności 16 ruchów. Czas znajdywania rozwiązania optymalnego wynosił wtedy więcej niŜ kilkanaście minut i nie było sensu kontynuować testów. Porównanie jakości rozwiązania znajdywanego algorytmem Korfa i Kociemby, dla przebadanych stanów, znajduje się na poniŜszych wykresach.

Page 103: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

97

0

5

10

15

20

25

30

0 4 8 12 16

Długość rozwiązania optymalnego

Długość znalezionego

rozw

iązania

Korf (optymalne) Kociemba

0

5

10

15

20

25

30

0 4 8 12 16

Długość rozwiązania optymalnego

Średnia długość znalezionego

rozw

iązania

Korf (optymalne) Kociemba (średnie)

Na wykresie po lewej stronie zaznaczona została jakość wszystkich znalezionych rozwiązań. Algorytm Korfa znajduje zawsze rozwiązanie optymalne. Na wykresach przedstawione jest ono w postaci niebieskiej prostej. Jakość rozwiązania znajdywanego algorytmem Kociemby jest oczywiście, co najwyŜej taka sama. Na ogół jest jednak niŜsza, gdyŜ algorytm ten z załoŜenia zwraca rozwiązanie suboptymalne. Jak widać na wykresie po lewej stronie, jakość tego rozwiązania ma bardzo duŜą rozpiętość juŜ dla prostych stanów kostki. Dla stanów o złoŜoności 4, algorytm znalazł rozwiązania o długości od 4 do 16. Najgorsze rozwiązanie jest 4 razy gorsze od optymalnego. Jakość rozwiązania rośnie wraz ze stopniem złoŜoności problemu. Dla stanów o złoŜoności 12, algorytm znalazł rozwiązania o długości od 13 do 25. Najgorsze rozwiązanie jest juŜ tylko 2 razy gorsze optymalnego. Prawdopodobnie dla jeszcze bardziej złoŜonych problemów, jakość rozwiązania znalezionego algorytmem Kociemby będzie bardziej zbliŜona do optymalnego. Algorytm ten znajduje rozwiązania nie dłuŜsze niŜ 30 ruchów, a najbardziej złoŜone stany kostki Rubika szacowane są na 22-23. Rozwiązanie znalezione dla nich algorytmem Kociemby moŜe być więc maksymalnie 1,3 razy gorsze od optymalnego. Średnia jakość rozwiązania znalezionego algorytmem Kociemby, jak widać na prawym wykresie, jest około 1,5 gorsza od rozwiązania optymalnego. Porównanie czasu szukania rozwiązania znajdywanego algorytmem Korfa i Kociemby, dla przebadanych stanów, znajduje się na poniŜszych wykresach. Ponadto przebadany został czas znajdywania rozwiązania optymalnego algorytmem Kociemby. Wykresy dotyczą kolejno algorytmu Korfa,

Page 104: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

98

1,00E-05

1,00E-04

1,00E-03

1,00E-02

1,00E-01

1,00E+00

1,00E+01

1,00E+02

1,00E+03

1,00E+04

0 4 8 12 16

Długość rozwiązania optymalnego

Czas szukania rozw

iązania [s]

Korf Time

algorytmu Kociemby

1,00E-05

1,00E-04

1,00E-03

1,00E-02

1,00E-01

1,00E+00

1,00E+01

1,00E+02

1,00E+03

1,00E+04

0 4 8 12 16

Długość rozwiązania optymalnego

Czas szukania rozw

iązania [s]

Kociemba Time

i zmodyfikowanego algorytmu Kociemby znajdującego rozwiązanie optymalne.

1,00E-05

1,00E-04

1,00E-03

1,00E-02

1,00E-01

1,00E+00

1,00E+01

1,00E+02

1,00E+03

1,00E+04

0 4 8 12 16

Długość rozwiązania optymalnego

Czas szukania rozw

iązania [s]

Kociemba Optimal Time

Na wykresach przedstawiony został czas szukania rozwiązania stanu kostki w zaleŜności od długości jego optymalnego rozwiązania. Ze względu na bardzo duŜe róŜnice trwania obliczeń zastosowana została skala logarytmiczna. Jest to szczególnie uŜyteczne w przypadku algorytmu Korfa, dla którego czas znajdywania rozwiązania dla prostego stanu (złoŜoności 1) jest rzędu 10e-5 sekund, a dla średniego stanu (złoŜoności 16) juŜ 10e3 sekund. Czas pracy tego algorytmu rośne zatem wykładniczo i moŜna oszacować, Ŝe dla najtrudniejszych problemów (złoŜoności 22) moŜe być rzędu 10e6 sekund czyli około 11,5 dnia. Podobnie wygląda złoŜoność znajdywania optymalnego rozwiązania algorytmem Kociemby. Jedynie

Page 105: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

99

przy uŜyciu algorytmu Kociemby, rozwiązanie znajdywane jest w czasie nie przekraczającym 10 sekund. Jest to na tyle krótki czas, Ŝe moŜna by jeszcze spróbować znaleźć kolejne, krótsze rozwiązanie algorytmem Kociemby. Dla porównanie uśrednione czasy znajdywania rozwiązania stanu porównywanymi algorytmami został przedstawione na poniŜszym wykresie w zaleŜności od rzeczywistej złoŜoności stanu.

1,00E-06

1,00E-05

1,00E-04

1,00E-03

1,00E-02

1,00E-01

1,00E+00

1,00E+01

1,00E+02

1,00E+03

1,00E+04

1,00E+05

0 4 8 12 16

Długość rozwiązania optymalnego

Średni czas szukania rozw

iązania [s]

Korf Kociemba Kociemba Optimal

Na powyŜszym wykresie dokładnie widać róŜnicę złoŜoności porównywanych algorytmów. Czas znajdywania rozwiązania algorytmem Korfa jest silnie uzaleŜniony od złoŜoności rozwiązywanego stanu. W przypadku algorytmu Kociemby, zaleŜność ta nie jest taka silna. Dodatkowo w ramach testów porównana została liczba węzłów przeszukiwanych przez algorytm Korfa i Kociemby. Porównanie znajduje się na poniŜszych wykresach.

1,E+00

1,E+01

1,E+02

1,E+03

1,E+04

1,E+05

1,E+06

1,E+07

1,E+08

1,E+09

0 4 8 12 16

Długość rozwiązania optymalnego

Liczba rozw

iniętych węzłów

Korf

Kociemba

1,E+00

1,E+01

1,E+02

1,E+03

1,E+04

1,E+05

1,E+06

1,E+07

1,E+08

1,E+09

0 4 8 12 16

Długość rozwiązania optymalnego

Liczba sprawdzonych węzłów

Korf

Kociemba

Wyniki badań potwierdzają wcześniejsze obserwacje o duŜo większej złoŜoności algorytmu Korfa oraz o jego wykładniczej zaleŜności od złoŜoności stanu. Dodatkowo, na poniŜszym wykresie, przedstawiającym uśrednioną liczbę rozwijanych i przeszukiwanych węzłów w obu

Page 106: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

100

algorytmach, wyraźnie widać, Ŝe liczba rozwijanych węzłów jest o rząd wielkości mniejsza niŜ liczba przeszukiwanych węzłów. Wynika to z zastosowania algorytmu przeszukiwania drzewa algorytmem IDA*, które przeszukuje jedynie węzły znajdujące się w obrębie konturu poszukiwań. Wszystkie moŜliwe ruchy są sprawdzane, ale ruchy oddalające od rozwiązania nie są rozwijane.

1,E+00

1,E+01

1,E+02

1,E+03

1,E+04

1,E+05

1,E+06

1,E+07

1,E+08

1,E+09

0 4 8 12 16

Długość rozwiązania optymalnego

Liczba węzłów

Korf (rozw inięte w ęzły) Kociemba (rozw inięte w ęzły)Korf (spraw dzone w ęzły) Kociemba (spraw dzone w ęzły)

Liczba rozwijanych węzłów decyduje oczywiście o duŜych potrzebach pamięciowych programu. Niemniej jednak w przypadku obu algorytmów wymagania te są zaspokajane przez średniej klasy komputer stacjonarny (z 512MB pamięci). Zasobem stanowiącym główne ograniczenie pracy algorytmów jest procesor. Na podstawie powyŜszych badań czasu i jakości znajdywanych rozwiązań, moŜna stwierdzić, Ŝe optymalnym algorytmem jest algorytm Korfa dla prostych stanów i algorytm Kociemby dla bardziej złoŜonych stanów. Granica między stanami prostymi a złoŜonymi to około 13 ruchów, w zaleŜności od środowiska pracy. Problemem jest oczywiście ocena złoŜoności stanu. MoŜna to zrobić na podstawie baz danych wzorców. Ocena ta będzie jednak bardzo niedoszacowana, gdyŜ maksymalna odległość w bazach danych wzorców wynosi 15. Innym rozwiązaniem jest po prostu próba znalezienia rozwiązania algorytmem Korfa i jeŜeli ta się nie powiedzie w określonym czasie (np. 30s), zastosowanie pewnego, choć zwracającego subptymalne rozwiązania, algorytmu Kociemby.

5.3.2. Dokładniejsza analiza jakości i wydajności algorytmu Kociemby

Analiza działania zaimplementowanych algorytmów, przeprowadzona w poprzednim punkcie, wykazała, Ŝe dla złoŜonych stanów kostki naleŜy zastosować algorytm Kociemby. Działanie algorytmu dla złoŜonych stanów nie zostało jednak przebadane w poprzednim punkcie ze względu na długi czas obliczeń w algorytmie Korfa. Oznacza to równieŜ, Ŝe obiektywna ocena jakości algorytmu Kociemby (w zaleŜności od rozwiązania optymalnego) nie jest moŜliwa. Dlatego teŜ przeprowadzone zostały badania statystyczne dla potencjalnie bardzo złoŜonych stanów kostki Rubika. Wygenerowanych zostało około 200 stanów kostki. KaŜdy stan powstał w wyniku wykonania 100 losowych ruchów na ułoŜonym stanie kostki. Dla kaŜdego stanu został zbadany czas szukania rozwiązania, długość rozwiązania oraz liczba rozwijanych i przeszukiwanych węzłów.

Page 107: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

101

Najciekawszym wynikiem powyŜszych badań jest jakość rozwiązania. Znalezione zostały rozwiązania o długości od 20 do 26 ruchów. Średnia długość rozwiązania to 23-24 ruchy. Jest to bardzo pozytywny wynik w porównaniu do szacunków z poprzedniego punktu. Maksymalna długość rozwiązania znajdywanego algorytmem Kociemby wynosi 32 ruchy, a w trakcie testów na 200 stanach, najdłuŜsze rozwiązanie wynosiło tylko 26 ruchów. Wynik badania przedstawiony jest na poniŜszym wykresie:

0

10

20

30

40

50

60

20 22 24 26

Długość znalezionego rozwiązania

Liczba znalezionych

rozw

iązań

Badania złoŜoności algorytmu Kociemby potwierdziły wcześniejsze obserwacje. Rozwiązanie znajdywane jest w krótkim czasie (do 2s). Ponadto ani czas znajdywania rozwiązania ani liczba rozwijanych węzłów nie zaleŜą silnie od złoŜoności rozwiązywanego problemu.

0

0,2

0,4

0,6

0,8

1

1,2

1,4

1,6

20 22 24 26

Długość znalezionego rozwiązania

Czas szukania rozw

iązania [s]

1,E+02

1,E+03

1,E+04

1,E+05

1,E+06

20 22 24 26

Długość znalezionego rozwiązania

Liczba rozw

iniętych węzłów

ZaleŜność taka oczywiście istnieje, ale jest ona raczej liniowa.

Page 108: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

102

00,10,20,3

0,40,50,60,7

20 22 24 26

Długość znalezionego rozwiązania

Średni czas szukania

rozw

iązania [s]

0

20000

40000

60000

80000

100000

20 22 24 26

Długość znalezionego rozwiązania

Liczba rozw

iniętych

węzłów

5.3.3. Wielkość bazy danych wzorców i czasu trwania procesu inicjalizacji

Oba porównywane algorytmy korzystają z baz danych wzorców, czyli ztablicowanych funkcji heurystycznych. Opierają się one jednak na róŜnym opisie stanu kostki, czyli na róŜnym wyborze współrzędnych do opisu stanu kostki. W jednym i drugim algorytmie tablice tworzone są przed procesem znajdywania rozwiązania, czyli w trakcie inicjalizacji narzędzia. Tablice te mogą być wygenerowanie tylko raz i zapisane na dysku. Przy kaŜdym następnym uruchomieniu programu tablice te będą odczytywane z plików, co znaczenie oszczędza czas.

Zajętość pamięci [kB] Czas stworzenia [s] Czas wczytania [s]

Korf 119 592 953 7

Kociemba 6 160 31 1

Jak wynika z powyŜszej tabeli róŜnica wydajności tablic w obu algorytmach jest znaczna. Po pierwsze tablice z algorytmu Korfa zajmują prawie 20 razy więcej pamięci. Po drugie czas ich tworzenia jest ponad 30 krotnie dłuŜszy. Pierwszy problem nie jest tak powaŜny jak drugi, gdyŜ 119MB nie jest aŜ tak wielką ilością pamięci dla współczesnych komputerów. Jednak zmuszenie uŜytkownika do czekania 15 minut na wygenerowanie tablic jest juŜ bardzo duŜym problemem. Dlatego teŜ tworzenie tabel naleŜy rozpatrywać jako osobny proces wchodzący w skład inicjacji systemu. Zostanie ono wykonane tylko raz, a potem tabele zostaną zapisane na twardym dysku i będą wykorzystywane przy kaŜdym kolejnym szukaniu rozwiązania kostki Rubika. PoniŜej przedstawione jest zestawienie tabel uŜywanych w obu algorytmach. Dla kaŜdej tabeli znajduje się w nim:

- nazwa pliku, w którym przechowywana jest tabela na dysku, - wielkość tego pliku, - liczba kombinacji współrzędnej, na której oparta jest tabela, - symboliczny zapis tej kombinacji,

Page 109: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

103

- opis zawartości tabeli.

Nazwa Na

dysku [kB]

Liczba kombinacji

Kombinacja

Opis

KC_CO.mtb 52 2 187 73 Tablica przekształceń współrzędnej orientacji rogów, uŜywana w pierwszej fazie algorytmu Kociemby.

KC_EO.mtb 12 2 048 112 Tablica przekształceń współrzędnej orientacji krawędzi, uŜywana w pierwszej fazie algorytmu Kociemby.

KC_EMC.mtb 48 495

4

12

Tablica przekształceń współrzędnej wyboru krawędzi środkowej warstwy, uŜywana w pierwszej fazie algorytmu Kociemby.

KC_CP.mtb 945 40 320 !8 Tablica przekształceń współrzędnej ułoŜenia rogów, uŜywana w drugiej fazie algorytmu Kociemby.

KC_ENP.mtb 945 40 320 !8

Tablica przekształceń współrzędnej ułoŜenia krawędzi z dwóch skrajnych warstw, uŜywana w drugiej fazie algorytmu Kociemby.

KC_EMP.mtb 1 24 !4

Tablica przekształceń współrzędnej ułoŜenia krawędzi ze środkowej warstwy, uŜywana w drugiej fazie algorytmu Kociemby.

KC_CO_EO.ptb 2 187 4 478 976 117 23 ⋅

Baza danych wzorców odległości od rozwiązania współrzędnych orientacji rogów i krawędzi, uŜywana w pierwszej fazie algorytmu Kociemby.

KC_CO_EMC.ptb 529 1 082 565

⋅4

1237

Baza danych wzorców odległości od rozwiązania współrzędnych orientacji rogów i wyboru krawędzi środkowej warstwy, uŜywana w pierwszej fazie algorytmu Kociemby.

KC_EMC_EO.ptb 495 1 013 760

⋅4

12211

Baza danych wzorców odległości od rozwiązania współrzędnych orientacji krawędzi i wyboru krawędzi środkowej warstwy, uŜywana w pierwszej fazie algorytmu Kociemby.

KC_CP_EMP.ptb 473 967 680 !4!8 ⋅

Baza danych wzorców odległości od rozwiązania współrzędnych ułoŜenia rogów i krawędzi środkowej warstwy, uŜywana w drugiej fazie algorytmu Kociemby.

Tablice uŜywane w algorytm

ie Kociemby

KC_EMP_ENP.ptb 473 967 680 !4!8 ⋅

Baza danych wzorców odległości od rozwiązania współrzędnych ułoŜenia krawędzi środkowej i dwóch pozostałych warstw, uŜywana w drugiej fazie algorytmu Kociemby.

6160

Page 110: PRACA DYPLOMOWA MAGISTERSKA

Program rozwiązujący kostkę Rubika

104

Nazwa

Na dysku [kB]

Liczba kombinacji

Kombinacja

Opis

KR_CO.mtb 52 2 187 73 Tablica przekształceń współrzędnej orientacji rogów, uŜywana w algorytmie Korfa.

KR_CP.mtb 945 40 320 !8 Tablica przekształceń współrzędnej ułoŜenia rogów, uŜywana w algorytmie Korfa.

KR_E1CO.mtb 1 386 59 136 62

6

12⋅

Tablica przekształceń współrzędnej orientacji pierwszej połowy krawędzi, uŜywana w algorytmie Korfa.

KR_E1CP.mtb 15 593 665 280 !66

12⋅

Tablica przekształceń współrzędnej ułoŜenia pierwszej połowy krawędzi, uŜywana w algorytmie Korfa.

KR_E2CO.mtb 1 386 59 136 62

6

12⋅

Tablica przekształceń współrzędnej orientacji drugiej połowy krawędzi, uŜywana w algorytmie Korfa.

KR_E2CP.mtb 15 593 665 280 !66

12⋅

Tablica przekształceń współrzędnej ułoŜenia drugiej połowy krawędzi, uŜywana w algorytmie Korfa.

KR_C.ptb 43 057 88 179 840 73!8 ⋅

Baza danych wzorców odległości od rozwiązania współrzędnych ułoŜenia i orientacji rogów, uŜywana w algorytmie Korfa.

KR_EFH.ptb 20 790 42 577 920 62

6

12⋅

Baza danych wzorców odległości od rozwiązania współrzędnych ułoŜenia i orientacji pierwszej połowy krawędzi, uŜywana w algorytmie Korfa.

Tablice uŜywane w algorytm

ie Korfa

KR_ESH.ptb 20 790 42 577 920 62

6

12⋅

Baza danych wzorców odległości od rozwiązania współrzędnych ułoŜenia i orientacji drugiej połowy krawędzi, uŜywana w algorytmie Korfa.

119 592

Page 111: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

105

6. Systemem robota układającego kostkę Rubika Celem niniejszej pracy jest stworzenie modułu znajdującego rozwiązanie kostki Rubika, który będzie pracował wewnątrz sterownika systemu robota. W niniejszym rozdziale opisany został sposób działania robota z punktu widzenia operacji na kostce oraz przedstawiony został sposób integracji programu CubeSolver z MRROC++.

6.1. Krótki opis robota

W niniejszym podrozdziale opisana została praca robota z punktu widzenia pracy z kostką Rubika, czyli na bardzo wysokim poziomie abstrakcji. Najmniejsza operacja rozwaŜana tutaj dotyczy manipulacji kostką. Operacja taka jest oczywiście wynikiem złoŜonej pracy manipulatorów. Nie jest to jednak istotne dla niniejszej pracy. Ponadto szczegóły pracy robota oraz jego oprogramowania zostały szczegółowo opisane w innych pracach dyplomowych oraz dokumentacji systemu MRROC++. System robotów układających kostkę Rubika składa się z dwóch robotów-ramion – Tracka i Postumenta. Oba ramiona zakończone są chwytakami, które stabilnie chwytają kostkę. W chwytakach umieszczone są kamery, dzięki którym moŜliwe jest rozpoznanie obecności i stanu kostki.

Chwytaki – końcówki ramion poruszają się w przestrzeni trójwymiarowej. Przemieszczenie ich w konkretne miejsce jest wynikiem zadania kinematyki odwrotnej, wyliczającej odpowiednie przemieszczenie przegubów robotów. Track posiada 7 takich przegubów, a co za tym idzie 7 stopni swobody. Przedstawione są one na poniŜszych rysunkach. Postument posiada o jeden stopień swobody mniej, gdyŜ stoi on nieruchomo na podłoŜu.

Page 112: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

106

Pierwszy stopień swobody – końcówka chwytaka obraca się wokół własnej osi, co umoŜliwia obrót kostki

wokół jej osi

Drugi stopień swobody – obrót główką chwytaka umoŜliwia chwycenie kostki z róŜnych stron:

od przodu i tyłu

Trzeci stopień swobody - obrót główką chwytaka umoŜliwia chwycenie kostki z róŜnych stron:

od góry i dołu

Czwarty stopień swobody –

przemieszczenie ramienia do góry i w dół w obrębie pola pracy obu robotów

Piąty stopień swobody – przemieszczenie ramienia do

przodu i tyłu w obrębie pola pracy obu robotów

Szósty stopień swobody – obrót ramienia między

polem pracy obu robotów a operatorem

Siódmy stopień swobody – przemieszczenie całego Tracka w

kierunku Postumenta

6.2. Praca robota

6.2.1. Operacje podstawowe

Robot rozwiązujący kostkę Rubika wykonuje cztery podstawowe operacje na kostce: - approach_op - odbiera kostkę od operatora - face_change_op - przekłada kostkę z Postumenta do Tracka - face_turn_op - wykonuje obrót ścianką trzymaną przez Postument i przekłada kostkę z

Tracka do Postumenta - departure_op - oddaje kostkę operatorowi.

Operacje approach_op i departure_op przemieszczają chwytaki między polem pracy obu robotów, gdzie następuje oglądanie i układanie kostki Rubika, a stanowiskiem operatora. Pozycje docelowe chwytaków przedstawione są na rysunkach poniŜej.

Page 113: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

107

Chwytaki przy stanowisku operatora. Taka pozycja umoŜliwia podanie kostki Trackowi, albo

odebranie jej od niego.

Chwytaki w polu pracy obu robotów. Taka pozycja umoŜliwia przechwytywanie kostki i

wykonywanie na niej obrotów.

Operacja oddania kostki operatorowi jest najprostszą operacją systemu robotów. Polega ona jedynie na przemieszczeniu ramion robotów tak, aby końcówka chwytaka znajdowała się przy stanowisku pracy operatora. Operator moŜe wtedy wyjąć kostkę z chwytaka. Robot nie musi wykonywać przy tym juŜ Ŝadnych operacji. DuŜo bardziej złoŜona jest operacja odebrania kostki od operatora. Zanim ramiona robota moŜna przemieścić do pola pracy, konieczne jest znalezienie kostki oraz jej chwycenie. W tym celu wykorzystywane są zarówno kamery umieszczone w chwytaku jak i czujniki siły. Dodatkowo po odebraniu kostki od operatora następuje jeszcze poprawienie uchwytu. W momencie odebrania kostki od operatora następuje równieŜ oznaczenie ścian. Zidentyfikowane są one względem tracka: ściana najbliŜej tracka to ściana przednia, ściana skierowana do góry to ściana dolna, a ściana po prawej stronie z punktu widzenia Tracka to ściana lewa. Podczas przemieszczenia kostki w pole pracy Track obraca kostkę o 180º tak, Ŝe ściana górna skierowana jest rzeczywiście w górę (w kierunku sufitu) a ściana lewa w lewo.

Operacje face_change_op oraz face_turn_op to współpraca obu ramion robota. Obejmuje ona przemieszczanie ramion, obracanie chwytaków oraz chwytanie i puszczanie kostki. Dodatkowo wymaga ona koordynacji ruchów obu ramion.

Page 114: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

108

Operacja face_change_op to przełoŜenie kostki z Postumenta do Tracka. Operacja ta umoŜliwia obrót kostki i chwycenie kostki za inną ścianę. Dodatkowo operacja ta ma cztery warianty odpowiadające czterem moŜliwym kątom obrotu ściany: o 0 º, 90 º, 180 º i 270 º. Dzięki temu moŜliwe jest zarówno obejrzenie wszystkich ścian kostki, jak i wykonanie obrotu dowolną ścianą kostki. Operacja face_change_op jest wynikiem skomplikowanej współpracy obu chwytaków oraz wykonania złoŜonych trajektorii przez Tracka. Dodatkowo duŜe znaczenie ma sama praca chwytaków – zaciskanie się i zwalnianie przez nie uchwytu na kostce. Szczegółowo, operacja przebiega w następujących etapach:

- start – operacja rozpoczyna się, gdy oba ramiona znajdują się w swoich pozycjach wyjściowych w polu pracy robota, a Postument trzyma kostkę.

- pre – Postument i Track przygotowują się do operacji zbliŜając się do siebie. W tym celu uruchamiany jest generator ECP_GEN_TEACH_IN czekający na wykonanie trajektorii dojścia przez oba ramiona. Trajektorie te zaleŜne są od wariantu operacji (kąta obrotu). Postument wykonuje trajektorię oznaczoną jako irp6p_fchange_ap_XXX.trj, gdzie XXX odpowiada kątowi obrotu. Trajektorie te róŜnią się między sobą jedynie na 6-tej pozycji (czyli kącie obrotu chwytaka). Track przemieszcza się po trajektorii oznaczonej jako irp6ot_fchange_ap_XXX.trj. Zasadniczo są to dwie trajektorie – jedna dla 0º i 180º a druga dla 90º i 270º, które róŜnią się między sobą jedynie na 7-mej pozycji (czyli kącie obrotu chwytaka).

- grab – chwytak Tracka zaciska się na kostce. Następuje to w wyniku uruchomienia kilku kolejnych generatorów: generatora chwycenia kostki ECP_GEN_TFF_RUBIK_GRAB dla dwóch faz wstępnego zacisku RCSC_RG_FCHANGE_PHASE_1 i RCSC_RG_FCHANGE_PHASE_2, generatora zbliŜenia chwytaka do kostki ECP_GEN_TFF_GRIPPER_APPROACH oraz generatora chwycenia kostki ECP_GEN_TFF_RUBIK_GRAB dla trzeciej fazy zacisku chwytaka na kostce RCSC_RG_FCHANGE_PHASE_3.

- open – chwytak Postumenta zwalnia zacisk na kostce, jednocześnie Track ostatecznie wzmacnia uchwyt. Następuje to w wyniku uruchomienia kilku kolejnych generatorów: generatora zwolnienia uchwytu RCSC_GRIPPER_OPENING dla pierwszej rozwarcia RCSC_GO_VAR_1, generatora chwycenia kostki ECP_GEN_TFF_RUBIK_GRAB dla czwartej i ostatniej fazy zacisku RCSC_RG_FCHANGE_PHASE_4 oraz generatora zwolnienia uchwytu RCSC_GRIPPER_OPENING dla drugiej i ostatecznej fazy rozwarcia chwytaka RCSC_GO_VAR_2.

- post – Postument i Track wracają do swoich pozycji wyjściowych. W tym celu uruchamiany jest generator ECP_GEN_TEACH_IN czekający na zakończenie przemieszczania się ramion po zadanych trajektoriach. Dla Tracka zdefiniowane są dwie zasadniczo róŜne trajektorie irp6ot_fchange_de_XXX.trj – pierwsza dla wariantu z obrotem o 0º i 180º, a druga dla 90º i 270º - róŜniące się między sobą jedynie na 7 pozycji (czyli kącie obrotu chwytaka). Postument, aby wrócić do swojej pozycji wyjściowej, musi wykonać obrót przeciwny do wykonanego w fazie pre. Zdefiniowane są zatem cztery trajektorie irp6p_fchange_de_XXX.trj róŜniące się między sobą na 6 pozycji (czyli kącie obrotu chwytaka).

- end - operacja kończy się, gdy oba ramiona znajdują się w swoich pozycjach wyjściowych w polu pracy robota, a Track trzyma kostkę

- remap – po zakończeniu fizycznej operacji konieczne jest jeszcze przemapowanie ścian. Podczas operacji zmieniło się połoŜenie kostki względem Tracka. Konieczne jest zatem odzwierciedlenie tego w modelu kostki w programie. Operacja ta jest oczywiście zaleŜna od wariantu operacji przechwycenia, czyli kąta obrotu.

Page 115: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

109

Szczegółowa ilustracja kolejnych faz operacji face_change_op przedstawiona jest w poniŜszej tabelce. Opisuje ona przechwycenie ułoŜonej kostki w czterech wariantach. Dodatkowo definiuje permutację stanu kostki, która następuje w wyniku tych operacji.

PrzełoŜenie kostki

z obrotem o 0º z obrotem o 90º z obrotem o 180º z obrotem o 270º

start – pozycja początkowa – Postument trzyma kostkę

pre (1) -przesunięcie chwytaka Tracka

pre (2) - obrót przygotowawczy Tracka

obrót o 90º

obrót o 180º

obrót o 90º

obrót o 180º

pre (3) – zadany obrót Postumenta

obrót o 0º

obrót o 90º

obrót o 180º

obrót o -90º

grab – chwycenie kostki przez Tracka – widok od przodu i od tyłu

open - zwolnienie uchwytu przez Postument

post (1) – powrotny obrót chwytaka Postumenta

obrót o 0º

obrót o -90º

obrót o 180º

obrót o 90º

post (2) – powrót Tracka do pozycji wyjściowej

Page 116: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

110

post (3) – obrót chwytaka Tracka do pozycji wyjściowej

obrót o -90º

obrót o 180º

obrót o -90º

obrót o 180º

remap - mapowanie kolorów na ścianach: UDFBLR (oryginalnie BGROYW)

ROYWBG (odpowiada FBLRUD)

YWBGRO (odpowiada LRUDFB)

ROWYGB (odpowiada FBRLDU)

WYGBRO (odpowiada RLDUFB)

Permutacja stanu kostki odpowiadająca przechwyceniu

))((0 BRDFLUC = ))((90 BDRFULC = ))((180 BLDFRUC = ))((270 BURFDLC =

Operacja face_turn_op to wykonanie obrotu ścianą trzymaną przez Postument i następujące po nim przełoŜenie kostki z Tracka do Postumenta. Operacja występuje w czterech wariantach odpowiadających moŜliwym kątom obrotu ściany kostki, czyli 0º, 90º, 180º i 270º. Pierwszy wariant nie stanowi oczywiście obrotu, a jedynie przełoŜenie kostki z Tracka do Postumenta. Operacja face_turn_op, podobnie jak face_change_op, jest wynikiem precyzyjnej współpracy obu ramion robota i podzielona jest na kolejne fazy:

- start – operacja rozpoczyna się, gdy oba ramiona znajdują się w swoich pozycjach wyjściowych w polu pracy robota, a Track trzyma kostkę.

- pre – Postument i Track przygotowują się do operacji zbliŜając się do siebie. W tym celu uruchamiany jest generator ECP_GEN_TEACH_IN czekający na przemieszczenie się ramion po zadanych trajektoriach. Trajektoria dla Postumenta irp6p_fturn_ap_XXX.trj jest zasadniczo identyczna dla wszystkich wariantów operacji. Trajektoria dla Tracka irp6ot_fturn_ap_XXX.trj róŜni się na 7 pozycji (czyli kącie obrotu chwytaka). Chwytak Tracka wykonuje obrót przygotowawczy, w przeciwny do zadanego. W dalszej części operacji wykona on zadany obrót. Złączenie tych dwóch obrotów stanowi oczywiście operację identycznościową. Dzięki takiej sekwencji ruchów po zakończeniu operacji nie jest konieczne przemalowanie ścian kostki, gdyŜ pozostają one w niezmienionym ułoŜeniu względem Tracka.

- grab - Postument chwyta kostkę. Operacja wykonywana jest w dwóch fazach RCSC_RG_FROM_OPEARTOR_PHASE_1 i RCSC_RG_FROM_OPEARTOR_PHASE_2 zarządzanych przez generator ECP_GEN_TFF_RUBIK_GRAB.

- turn – Track wykonuje obrót dwoma trzymanymi warstwami o kąt odpowiadający wariantowi operacji. Jest on oczywiście równoznaczny obrotowi ścianą trzymaną przez Postument. Ruch wykonany jest w efekcie wywołania generatora ECP_GEN_TFF_RUBIK_FACE_ROTATE dla odpowiedniego zadania RCSC_XXX, gdzie XXX oznacza wariant wykonywanej operacji.

- open – Track zwalnia uchwyt chwytaka na kostce. Przebieg tej fazy jest duŜo prostszy niŜ przebieg adekwatnej fazy w operacji face_change_op. Wynika to z faktu, iŜ uchwyt tutaj jest duŜo prostszy i chwytaki naciskają na kostkę w jednej płaszczyźnie, dzięki czemu niebezpieczeństwo upuszczenia przez nie kostki jest duŜo mniejsze. W fazie tej wykonywane jest tylko jedno zadanie RCSC_GO_VAR_2 nadzorowane przez generator RCSC_GRIPPER_OPENING.

Page 117: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

111

- post – Track wraca do swojej pozycji wyjściowej. Zadanie to jest identyczne dla kaŜdego wariantu operacji. Wywoływany jest generator ECP_GEN_TEACH_IN, który nadzoruje przemieszczenie się Tracka po trajektorii irp6ot_fturn_de.trj.

- end - operacja kończy się, gdy oba ramiona znajdują się w swoich pozycjach wyjściowych w polu pracy robota, a Postument trzyma kostkę

Szczegółowa ilustracja kolejnych faz operacji face_turn_op przedstawiona jest w poniŜszej tabelce. Opisuje ona wykonanie obrotu w czterech wariantach na ułoŜonej kostce. Wykonanie obrotu na kostce

o 0º o 90º o 180º o 270º

start – pozycja początkowa – Track trzyma kostkę

pre – obrót przeciwny do zadanego Tracka

obrót o 0º

obrót o -90º

obrót o 180º

obrót o 90º

grab - chwycenie kostki przez postument

turn - zadany obrót Tracka

obrót o 0º

obrót o 90º

obrót o 180º

obrót o -90º

open - zwolnienie uchwytu przez Tracka

6.2.2. Operacje złoŜone

Robot rozwiązujący kostkę Rubika wykonuje dodatkowo trzy operacje złoŜone na kostce, składające się z sekwencji operacji podstawowych:

- manipulate – wykonanie obrotu wybraną ścianką kostki - identify_colors – odczytanie stanu kostki - find_rcs – znajduje rozwiązanie kostki (nie korzysta z operacji podstawowych)

Operacja face_turn_op wykonuje jedynie obrót ścianką trzymaną przez Postument, czyli ścianką tylną (B). Aby wykonać obrót inną ścianką konieczne jest wykonanie sekwencji przełoŜeń kostki. W jej wyniku ścinka do obrócenia musi się znaleźć naprzeciw Tracka. W tym celu zdefiniowana została złoŜona operacja manipulate. UmoŜliwia ona wykonanie obrotów wszystkimi sześcioma ścianami o trzy moŜliwe kąty. Stanowi ona złoŜenie operacji

Page 118: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

112

face_change_op i face_turn_op. Rozpoczyna się i kończy, gdy Postument trzyma kostkę. W poniŜszej tabeli zilustrowane jest jej działanie dla obrotu poszczególnych ścian o 90º.

Wykonanie obrotu o 90º ścianą

F B U D L R

pre change – wstępne przechwycenie kostki

z obrotem o 0º

pre turn – wstępny obrót kostką

obrót o 0º

start – Postument trzyma kostkę

change – przechwycenie kostki z obrotem

o 90º

o -90º

o 90º

o -90º

o 0º

o 180º

turn – wykonanie obrotu (o 90º)

Zanim robot zacznie układać kostkę, musi najpierw odczytać jej stan. W tym celu ogląda kaŜdą jej ścianę i zapisuje kolory ścianek na niej. Operacja ta nazywa się identify_colors i jest złoŜona z podstawowych operacji przekładania kostki. Dodatkowo korzysta ona z czujnika – kamery zamocowanej w Tracku. Sterownik kamery robi zdjęcie kostce oraz rozpoznaje kolory w określonych miejscach tego zdjęcia, w których znajdują się środki ścianek. Jako odczyt zwraca tylko 9 kolorów kolejnych ścianek w ścianie. Operacja rozpoczyna się, gdy Track trzyma kostkę. Operacja wykonuje sześć razy – dla kaŜdej ściany raz – następujący ciąg operacji:

- face_turn_op – przełoŜenie kostki z Tracka do Postumenta bez wykonywania obrotu - get_reading – odczytanie kolorów ścianek ze ściany przedniej kostki oraz zapisanie

ich do odpowiednich pól struktury przechowującej stan kostki - face_change_op – przełoŜenie kostki z Postumenta do Tracka z wykonaniem

zadanego obrotu. Operacja została zaprojektowana tak, aby w jak najmniejszej liczbie ruchów obejrzeć całą kostkę. W tym celu przekładanie kostki wykonywane jest kolejno w następujących wariantach: 0º, 0º, 180º, 0º, 180º i 0º.

Operacja kończy się, gdy Track trzyma kostkę. W wyniku operacji zmieniło się oczywiście mapowanie ścian, co wynika z faktu, iŜ kaŜda operacja face_change_op je zmienia. Kolejne mapowania ścian moŜna wyliczyć w następujący sposób:

Page 119: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

113

Kolejna operacja Permutacja odpowiadająca wszystkim złoŜeniu wszystkich operacji aŜ do rozwaŜanej

0 Stan początkowy IP =0

1 Przechwyt z obrotem o 0º ))(())((001 BRDFLUBRDFLUICPP === oo

2 Przechwyt z obrotem o 0º ))(())(())((012 BDRFULBRDFLUBRDFLUCPP === oo

3 Przechwyt z obrotem o 180º UDRLFBBLDFRUBDRFULCPP ))(())(())((18023 === oo

4 Przechwyt z obrotem o 0º ))(())(())((034 BLUFRDBRDFLUUDRLFBCPP === oo

5 Przechwyt z obrotem o 180º ))(())(())((18045 BURFDLBLDFRUBLUFRDCPP === oo

6 Przechwyt z obrotem o 0º ))(())(())((056 UDLRFBBRDFLUBURFDLCPP === oo

Oznacza to, Ŝe po wykonaniu operacji identify_colors kostka ułoŜona jest do góry nogami względem swojej początkowej pozycji. UłoŜenie to jest równieŜ traktowane jako wyjściowe do układania kostki. PoniŜej przedstawione jest ułoŜenie początkowe i końcowe dla przykładowego stanu kostki: Stan początkowy Stan końcowy

Mapowanie kolorów ścian kostki

U L F R B D

UDFBLR = BGROWY

U L F R B D

UDFBLR = BGORWY

Przykładowy stan

Permutacja IP =0 ))((6 UDLRFBP =

Page 120: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

114

PoniŜej znajduje się ilustracja sześciu kolejnych odczytów kolorów ścian dla stanu kostki z powyŜszego przykładu:

PrzełoŜenie kostki bez obrotu

face_turn_op

Odczyt z kamery

Kolejność odczytu ścianek względem stanu

końcowego

Mapowanie kolorów ścian

kostki

Permutacja względem stanu początkowego

Przechwycenie kostki z odpowiednim

obrotem face_change_op

1-sza ściana

WRRWRRWRR

1 2 3 4 5 6 7 8 9 obr. o 0º

U L F R B D

Stan początkowy, czyli permutacja identycznościowa:

FBLRBD

Przechwyt z obrotem o 0º, czyli permutacja

(FLU)(BRD)

2-ga ściana

YYRYYRGGG

7 4 1 8 5 2 9 6 3 obr. o 90º

U L F R B D

Jeden przechwyt z obrotem o 0º, czyli (FLU)(BRD)

Przechwyt z obrotem o 0º, czyli permutacja

(FLU)(BRD)

3-cia ściana

BBRBBYBBY

3 6 9 2 5 8 1 4 7 obr. o -90º

U L F R B D

ZłoŜenie dwóch przechwytów z obrotem o 0º, czyli (FUL)(BDR)

Przechwyt z obrotem o 180º, czyli permutacja

(FRU)(BLD)

4-ta ściana

OOOOOOYYY

1 2 3 4 5 6 7 8 9 obr. o 0º

U L F R B D

ZłoŜenie poprzedniego z przechwytem z obrotem o 180º, czyli (FB)(RL)UD

Przechwyt z obrotem o 0º, czyli permutacja

(FLU)(BRD)

Page 121: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

115

5-ta ściana

BBBWW?WW?

14

7 4 1 8 5 2 9 6 3 obr. o 90º

U L F R B D

ZłoŜenie poprzedniego z przechwytem z obrotem o 0º,

czyli (FRD)(BLU)

Przechwyt z obrotem o 180º, czyli permutacja

(FRU)(BLD)

6-ta ściana

GGWGGWGG?

7 4 1 8 5 2 9 6 3 obr. o 90º

U L F R B D

ZłoŜenie poprzedniego z przechwytem z obrotem o 180º, czyli (FDL)(BUR)

Przechwyt z obrotem o 0º, czyli permutacja

(FLU)(BRD)

W wyniku operacji identify_colors system robotów poznaje stan kostki. Zapisany jest w tablicy o 54 polach. KaŜdemu polu odpowiada kolor ścianki. Jak wynika z powyŜszej analizy, ściany odczytywane są w następującej kolejności i obrocie: Kolejność odczytu ścian i kąt, o jaki jest obrócona ściana podczas odczytu

Kolejność odczytu ścianek (stan z rozwaŜanego przykładu)

Odczytany stan (z rozwaŜanego przykładu)

52 49 46 53 50 47 54 51 48 43 40 37 1 2 3 16 13 10 28 29 30 44 41 38 4 5 6 17 14 11 31 32 33 45 42 39 7 8 9 18 15 12 34 35 36 21 24 27 20 23 26 19 22 25

WRRWRRWRR YYRYYRGGG BBRBBYBBY OOOOOOYYY BBBWWOWWO GGWGGWGGO

Znalezieniem rozwiązania dla odczytanego stanu kostki zajmuje się operacja find_rcs. Wykorzystuje ona ciąg znaków, reprezentujący stan kostki, uzyskany w wyniku operacji identify_colors. Jako Ŝe stan ten jest zapisany w niestandardowy sposób, konieczne jest jego unormowanie. Ściany powinny być opisane w kolejności URFDLB. Ścianki w ścianach powinny być opisane w tej samej, nie obróconej kolejności. Do opisu ścianek powinny zostać uŜyte nazwy ścianek, a nie ich kolory.

14 W przypadku, gdy sterownik kamery nie zidentyfikował koloru ścianki, zwraca on znak zapytania zamiast litery koloru. Proces główny systemu robotów w dalszym przetwarzaniu potraktuje to natomiast jako kolor pomarańczowy.

1

6

2

3

45

Page 122: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

116

Stan odczytany przez identify_colors Stan unormowany

Kolejność odczytu ścian i kąt, o jaki jest obrócona

ściana podczas odczytu

Kolejność odczytu ścianek (stan z

rozwaŜanego przykładu)

52 49 46 53 50 47 54 51 48 43 40 37 1 2 3 16 13 10 28 29 30 44 41 38 4 5 6 17 14 11 31 32 33 45 42 39 7 8 9 18 15 12 34 35 36 21 24 27 20 23 26 19 22 25

1 2 3 4 5 6 7 8 9 37 38 39 19 20 21 10 11 12 46 47 48 40 41 42 22 23 24 13 14 15 49 50 51 43 44 45 25 26 27 16 17 18 52 53 54 28 29 30 31 32 33 34 35 36

Odczytany stan (z rozwaŜanego przykładu)

WRRWRRWRR YYRYYRGGG BBRBBYBBY OOOOOOYYY BBBWWOWWO GGWGGWGGO

UUUUUUBLL URRURRUFF LFFLFFLFF FRRDDDDDD LLDLLDBBD BBBBBBRRR

W celu znalezienia rozwiązania kostki operacja find_rcs korzysta z zewnętrznego względem głównego procesu systemu robota programu znajdującego rozwiązanie. W tym momencie zaimplementowane są dwa rozwiązania – korzystające z programu udostępnionego na serwerze Windows oraz korzystające z programu CubeSolver zintegrowanego z systemem MRROC++, które jest dokładniej opisane w dalszej części niniejszej pracy. Oba zwracają sekwencję ruchów prowadzącą do rozwiązania w postaci łańcucha znaków reprezentujących naprzemiennie ściankę i kat obrotu. Dla rozwaŜanego przykładu jest to F3D3, co oznacz konieczność wykonania dwóch obrotów: F' i D'. Operacja find_rcs tłumaczy te ruchy na operacje zrozumiałe dla systemu robota, czyli operujące na kolorach ścianek. W rozwaŜanym przypadku będą to: O3G3. Zapis ten ma dodatkowo taką zaletę, Ŝe jest niezaleŜny od ułoŜenia kostki względem Tracka. Na koniec operacje do wykonania zapisywane są do listy manipulacji do wykonania przez robota na kostce. Operacja informuje proces główny robota o konieczności dalszej pracy i wykonania ruchów z listy manipulacji - metoda zwraca false. Zwrócenie wartości true, informuje system robota o konieczności zakończenia pracy przez oddanie kostki operatorowi. MoŜe to wystąpić w dwóch przypadkach: gdy podana kostka jest ułoŜona i nie trzeba wykonywać na niej Ŝadnych operacji bądź gdy ciąg znaków odczytany w operacji identify_colors nie reprezentuje poprawnego stanu kostki.

6.2.3. Główne zadanie robota

Głównym zadaniem systemu robotów jest ułoŜenie podanej mu kostki Rubika. Do wykonania tego zadania wykorzystywane są wszystkie wcześniej opisane operacje w następującej kolejności:

- approach_op – system robota odbiera kostkę od operatora, - identify_colors – system ogląda kostkę ze wszystkich stron w celu odczytania jej

stanu, - find_rcs – system znajduje rozwiązanie kostki

JeŜeli rozwiązanie zostało znalezione, to wykonywana jest następująca sekwencja operacji: - face_turn_op – przełoŜenie kostki z Tracka do Postumenta bez obrotu,

3

1

2

4

65 1

6

2

3

4 5

Page 123: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

117

- execute_manipulation_sequence – wykonanie wszystkich operacji (manipulate) z listy manipulacji ustawionej przez find_rcs,

- face_change_op – przełoŜenie kostki z Postumenta do Tracka bez obrotu, NiezaleŜnie od tego czy rozwiązanie zostało odnalezione czy nie, na zakończenie pracy wykonywana jest operacja:

- departure_op – system oddaje kostkę operatorowi.

6.3. Warianty integracji

Główną częścią niniejszej pracy było zintegrowanie programu CubeSolver z MRROC++. MoŜliwych jest kilka wariantów integracji. PoniŜej przedstawione są najciekawsze. Znajdywanie rozwiązania kostki Rubika jest w stosunku do systemu robota zewnętrznym źródłem informacji. Dlatego teŜ moŜna rozpatrywać je jako zewnętrzny czujnik (VSP). Inicjalizacją pomiaru takiego czujnika jest zadanie mu stanu kostki do rozwiązania. Wynikiem pomiaru jest oczywiście rozwiązanie tego stanu. Takie podejście do problemu umoŜliwia wyłącznie złoŜonego procesu liczenia z modułu sterowania i wykonywanie go na odrębnych maszynach. Ponadto moŜliwych jest wiele róŜnych sposobów zdefiniowania i podłączenie takiego czujnika do systemu. W systemie zaimplementowane są trzy rodzaje powłok do komunikacji z czujnikami: interaktywna z oczekiwaniem, interaktywna bez oczekiwania oraz nieinteraktywna. JeŜeli czujnik podłączony jest do systemu przy uŜyciu powłoki interaktywnej z oczekiwaniem, podczas wykonywania pomiaru sterowanie przekazane jest do czujnika. Oznacza to, Ŝe operacja pomiaru jest synchroniczna i jądro oczekuje na jej zakończenie. Asynchroniczna operacja pomiaru zaimplementowana jest w powłoce interaktywnej bez oczekiwania. Natomiast w przypadku, gdy czujnik pracuje w powłoce nieinteraktywnej, operacja pomiaru wykonywana jest w pętli, a wynik pomiaru zapisywany w sterowniku. Odczyt pomiaru moŜe zostać wykonany w kaŜdej chwili, a zwrócona zostanie ostatnio zapisana wartość.

Wariant I – prosty czujnik

Najprostszym sposobem integracji programu CubeSolver z system robota jest zbudowanie prostego czujnika w powłoce interaktywnej z oczekiwaniem.

Do rozpoczęcia pomiaru, czujnik potrzebuje otrzymać stan kostki i algorytm, którym ma zostać znalezione rozwiązanie. Proces obliczeń jest synchroniczny, wobec czego proces sterujący robotem czeka na wynik pracy czujnika. Taka implementacja jest oczywiście najprostsza. Zmusza ona proces sterujący do podjęcia decyzji o wyborze algorytmu. Czujnik, posiadający wiedzę o kostce, zupełnie nie wykorzystuje wniosków płynących z testów

Page 124: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

118

wydajnościowych wykonanych w niniejszej pracy a tylko wykonuje prosto zdefiniowane zadanie obliczeń.

Wariant II – zaawansowany czujnik

Integracja, wykorzystująca wnioski z testów zaimplementowanych algorytmów, moŜe oznaczać zaimplementowanie złoŜonego czujnika.

Czujnik taki oprócz obliczeń wykonuje prostą operację optymalizacji szukania rozwiązania przy zadanych ograniczeniach. Ograniczeniem jest czas i długość rozwiązania. Czujnik pracuje na wątkach i jednocześnie próbuje znaleźć rozwiązanie kostki algorytmem Korfa i Kociemby. Taka implementacja narzuca mocne rozbudowanie klasy wirtualnego sterownika znajdującego rozwiązanie kostki Rubika, a i tak pozostawia cięŜar doboru ograniczeń rozwiązania na procesie sterującym robotem. Co więcej, proces sterujący po przekazaniu sterowania do czujnika, nie ma kontroli nad procesem znajdywania rozwiązania.

Wariant III – dwa specjalizowane czujniki

Trzecim wariantem integracji programu z niniejszej pracy z systemem robota jest zbudowanie dwóch specjalizowanych czujników.

Dla kaŜdego algorytmu zbudowany jest osobny czujnik. Jako Ŝe algorytmy róŜnią się między sobą, czujniki są róŜnie zdefiniowane. Algorytm Korfa znajduje jedno optymalne rozwiązanie, ale w bliŜej nieokreślonym czasie. Dlatego teŜ czujnik z nim związany zaimplementowany jest w powłoce interaktywnej bez oczekiwania. Po rozpoczęciu pomiaru

Page 125: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

119

sterowanie wraca do procesu sterowania robotem. JeŜeli rozwiązanie nie zostanie znalezione w odpowiednim czasie, proces sterowania przerwie proces pomiaru. Czujnik dla algorytmu Kociemby pracuje w powłoce nieinteraktywnej. Problem do rozwiązania zadaje się mu podczas konfiguracji. Po niej czujnik zaczyna pracę i szuka kolejnych, bliŜszych optymalnemu rozwiązań. Zapisuje ostatnio znalezione rozwiązanie. Pierwsze rozwiązanie znajdywane jest w przeciągu 2s. Do procesu sterowania naleŜy jedynie decyzja, kiedy przerwać poszukiwania kolejnych, lepszych rozwiązań i wykorzystać ostatnio znalezione. Do realizacji wybrany został wariant III jako rozwiązanie najbardziej elastyczne i uniwersalne.

6.4. Realizacja integracji

W ramach niniejszej pracy zaimplementowane zostały dwa wirtualne czujniki i rozszerzone zostało główne zadanie systemu. Dodatkowo stworzone zostało zadanie do testowania pracy samych czujników. Kod źródłowy programu CubeSolver został dołączony do systemu MRROC++. Korzystają z niego oba stworzone czujniki.

6.4.1. Opis dodanych klas

Klasa wirtualnego sterownika czujnika dla algorytmu Korfa

Czujnik znajdujący rozwiązanie kostki przy uŜyciu algorytmu Korfa został zdefiniowany jako SENSOR_RCS_KORF. Dla sterownika została stworzona klasa vsp_rcs_korf. Posiada ona dodatkowe pola przechowujące stan kostki do rozwiązania i znalezione rozwiązanie. Sterownik pracuje w powłoce interaktywnej bez oczekiwanie i udostępnia następujące metody:

- konstruktor vsp_rcs_korf – ustawia czujnik jako niezainicjalizowany i bez gotowego odczytu. Dodatkowo ustawia puste wartości pól i odczytu.

- destruktor ~vsp_rcs_korf - zwalnia pamięć zajmowana przez struktury pomocnicze czyli tabele przekształceń wykorzystywane w CubeSolver

- configure_sensor – konfiguruje czujnik. Udostępniony jest jeden tryb konfiguracji: RCS_BUILD_TABLES. W ramach konfiguracji CubeSolver zczytuje z katalogu, zdefiniowanego w pliku konfiguracyjnym, tablice przekształceń i odległości od rozwiązania. Konfiguracja moŜe trwać kilka sekund do kilku minut w zaleŜności od umieszczenia katalogu. Czujnik naleŜy skonfigurować przed wykonaniem z niego pierwszego odczytu.

- initiate_reading – inicjuje proces odczytu, czyli przekazuje stan kostki, dla którego czujnik ma znaleźć rozwiązanie. W ramach tej metody wywołane zostaje szukanie rozwiązania przez CubeSolver. Poszukiwanie moŜe trwać bardzo długo (kilka godzin a nawet dni). Dlatego teŜ czujnik ten pracuje w powłoce interaktywnej bez oczekiwania. Nawet, jeŜeli czujnik będzie cały czas szukał rozwiązania, moŜliwe będzie odpytanie go, czy rozwiązanie juŜ jest dostępne i podjęcie właściwych kroków na podstawie uzyskanej odpowiedzi.

- get_reading – zwraca znalezione rozwiązanie. Rozwiązanie składa się z dwóch części – informacji, czy zostało ono znalezione i jeŜeli tak, to dodatkowo ciągu operacji do wykonania.

Klasa wirtualnego sterownika czujnika dla algorytmu Kociemby

Czujnik znajdujący rozwiązanie kostki przy uŜyciu algorytmu Kociemby został zdefiniowany jako SENSOR_RCS_KOCIEMBA. Dla sterownika została stworzona klasa vsp_rcs_kociemba. Posiada ona dodatkowe pola przechowujące stan kostki do rozwiązania i ostatnie znalezione rozwiązanie. Sterownik pracuje w powłoce nieinteraktywnej i udostępnia następujące metody:

Page 126: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

120

- konstruktor vsp_rcs_kociemba – ustawia czujnik jako niezainicjalizowany i bez gotowego odczytu. Dodatkowo ustawia puste wartości pól i odczytu.

- destruktor ~vsp_rcs_kociemba - zwalnia pamięć zajmowana przez struktury pomocnicze, czyli tabele przekształceń wykorzystywane w CubeSolver

- configure_sensor – konfiguruje czujnik. Udostępnione są dwa tryby konfiguracji: RCS_BUILD_TABLES i RCS_CUBE_STATE. Czujnik naleŜy skonfigurować najpierw w trybie RCS_BUILD_TABLES, a następnie w trybie RCS_CUBE_STATE przed wykonaniem z niego pierwszego odczytu. W ramach pierwszego trybu konfiguracji, CubeSolver zczytuje z katalogu, zdefiniowanego w pliku konfiguracyjnym, tablice przekształceń i odległości od rozwiązania. Konfiguracja ta moŜe trwać kilka to kilkunastu sekund w zaleŜności od umieszczenia katalogu. Drugi tryb konfiguracji to ustawienie stanu kostki, dla którego czujnik ma znaleźć rozwiązanie. Od razu po wykonaniu tej operacji czujnik rozpoczyna szukanie rozwiązania w ramach metody initiate_reading.

- initiate_reading – inicjuje proces odczytu, czyli wywołuje szukanie pierwszego albo kolejnego rozwiązania stanu kostki przez CubeSolver. Znalezione rozwiązanie zapisuje do odpowiedniego pola klasy. Poszukiwanie pierwszego rozwiązania trwa kilka sekund. JeŜeli ostatnio znalezione rozwiązanie jest optymalne, metoda nie szuka juŜ następnego. Operacja ta jest wykonywana w pętli nieskończonej na zmianę z metodą wait_for_event.

- wait_for_event – oczekuje na zdarzenie. Metoda ta w zaleŜności od tego, czy zostało juŜ znalezione rozwiązanie optymalne i proces szukania następnych rozwiązań został zakończony, czeka 1 albo 10 sekund. Operacja ta jest wykonywana w pętli nieskończonej na zmianę z metodą initiate_reading.

- get_reading – zwraca znalezione rozwiązanie. Rozwiązanie składa się z dwóch części – informacji, czy zostało ono znalezione i jeŜeli tak, to dodatkowo ciągu operacji do wykonania.

Klasy zarządzania komunikacją ze sterownikami czujników

Jako Ŝe sterowniki czujników wirtualnych mogą pracować na osobnych komputerach, konieczna jest implementacja klas umoŜliwiających procesowi głównemu komunikację z nimi. W ramach niniejszej pracy zaimplementowane zostały dwie klasy: ecp_mp_rcs_korf i ecp_mp_rcs_kociemba odpowiednio dla czujników SENSOR_RCS_KORF i SENSOR_RCS_KOCIEMBA. Klasy te udostępniają po trzy metody: configure_sensor, initiate_reading i get_reading. Metody te słuŜą do przekazania odpowiednich rozkazów z procesu głównego do sterownika czujnika oraz odebrania wyniku ich wykonania. Dodatkowo obsługują błędy odczytu i zapisu oraz wyjątki CubeSolver. Na szczególną uwagę tutaj zasługuje jedynie metoda initiate_reading. RóŜni się ona od standardowej implementacji inicjalizacji odczytu w systemie MRROC++ tym, Ŝe zwraca status operacji. Jest to konieczne w przypadku zbudowanych czujników, gdyŜ ich konfiguracja moŜe trwać nawet kilka minut. Dopóki się ona nie skończy nie moŜna zainicjalizować kostki. Inicjalizacja kończy się w takim przypadku błędem i trzeba ją powtarzać aŜ do skutku.

Klasa zadania do testowania czujników

W celu przetestowania działania obu czujników, stworzone zostało zadanie testowe mp_task_rcs_test. Zadanie to nie dotyczy systemu robota. Pracuje jedynie z dwoma czujnikami znajdującymi rozwiązanie kostki Rubika. Podczas inicjalizacji zadania tworzone i konfigurowane są oba czujnika. Samo zadanie polega na przekazaniu czujnikom stanu kostki do rozwiązania i odczytania rozwiązań, które znalazły. Stworzenie tego zadania umoŜliwiło dokładne przetestowanie pracy czujników bez konieczności uruchamiania systemu robota.

Page 127: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

121

Klasa głównego zadania systemu

Do klasy mp_task_rubik_cube_solver została dodana metoda rozwiązująca kostkę Rubika find_rcs_with_VSP. Dotychczasowa funkcjonalność korzystająca z serwera Windows została przeniesiona do metody find_rcs_with_windows_solver. Metoda find_rcs na podstawie konfiguracji korzysta z jednej bądź drugiej. Metoda find_rcs_with_VSP znajduje rozwiązanie przy uŜyciu dwóch specjalizowanych czujników wirtualnych: SENSOR_RCS_KOCIEMBA i SENSOR_RCS_KORF. Czujniki te są tworzone i inicjalizowane podczas inicjalizacji robota. Po wykonaniu operacji identify_colors, stan kostki zostaje przekazany do obu czujników. Główne zadanie czeka na rozwiązanie znalezione algorytmem Korfa (znajdywane przez SENSOR_RCS_KORF), zadaną w pliku konfiguracyjnym ilość czasu. JeŜeli w tym czasie rozwiązanie zostało znalezione, wykorzystuje je do rozwiązania kostki. JeŜeli nie, to wykorzystuje rozwiązanie znalezione algorytmem Kociemby (znajdywane przez SENSOR_RCS_KOCIEMBA). Dodatkowo rozpoznawane są dwa szczególne przypadki – gdy odczytany stan kostki jest niepoprawny i gdy kostka jest juŜ ułoŜona. Dla obu tych przypadków system robota informowany jest o moŜliwości zakończenia swojej pracy.

6.4.2. Opis dodanych plików

Pełen wykaz plików dodanych i zmienionych w systemie MRROC++ znajduje się poniŜej: ŚcieŜka i nazwa pliku Zmiana Opis

/configs/rcs_test.ini Dodane Plik konfiguracyjny dla zadania rcs_test.

/configs/rcs.ini Dodane Plik konfiguracyjny dla zadania rcs.

/data/rcs.txt Dodane Plik tekstowy opisujący konieczność dodania danych dla CubeSolver.

/data/rcs Do ręcznego dodania

Folder, w którym naleŜy umieścić tablice przekształceń i odległości od rozwiązania dla CubeSolver.

/include/common/sensor.h Zmienione

Definicja czujników SENSOR_RCS_KORF i SENSOR_RCS_KOCIEMBA. Unia obrazu czujnika rozszerzona o strukturę do przesyłania rozwiązania kostki Rubika. Unia bufora komunikacyjnego rozszerzona o strukturę do przesyłania stanu kostki. Tryby konfiguracji oraz kody zakończenia inicjalizacji i odczytu z czujnika.

/include/ecp_mp/ecp_mp_s_rcs_kociemba.h

Dodane Deklaracja klasy do komunikacji między MP a VSP ecp_mp_rcs_kociemba.

/include/ecp_mp/ecp_mp_s_rcs_korf.h

Dodane Deklaracja klasy klasy do komunikacji między MP a VSP ecp_mp_rcs_korf.

/include/mp/mp_t_rcs_test.h Dodane Deklaracja zmodyfikowanej klasy zadania głównego mp_task_rubik_cube_solver.

/include/mp/mp_t_rcs.h Dodane Deklaracja klasy zadania testowego mp_task_rcs_test.

/include/vsp/vsp_rcs_kociemba.h Dodane Deklaracja klasy VSP vsp_rcs_kociemba.

/include/vsp/vsp_rcs_korf.h Dodane Deklaracja klasy VSP vsp_rcs_korf.

/src/ecp_mp/ecp_mp_s_rcs_kociemba.cc

Dodane Implementacja klasy do komunikacji między MP a VSP ecp_mp_rcs_kociemba.

/src/ecp_mp/ecp_mp_s_rcs_korf.cc Dodane Implementacja klasy klasy do komunikacji między MP a VSP ecp_mp_rcs_korf.

/src/mp/mp_t_rcs_test.cc Dodane Implementacja zmodyfikowanej klasy zadania głównego mp_task_rubik_cube_solver.

/src/mp/mp_t_rcs.cc Dodane Implementacja klasy zadania testowego

Page 128: PRACA DYPLOMOWA MAGISTERSKA

Systemem robota układającego kostkę Rubika

122

mp_task_rcs_test.

/src/mp/Makefile Zmienione Instrukcje do zbudowania dodanych zadań: mp_task_rubik_cube_solver i mp_task_rcs_test.

/src/vsp/rcs/… Dodane Folder zawierający pliki źródłowe CubeSolver.

/src/vsp_rcs_kociemba/Makefile Dodane Instrukcje do zbudowania czujnika SENSOR_RCS_KOCIEMBA w powłoce nieinteraktywnej.

/src/vsp_rcs_kociemba/vsp_rcs_kociemba.cc

Dodane Deklaracja klasy VSP vsp_rcs_kociemba.

/src/vsp_rcs_korf/Makefile Dodane Deklaracja klasy VSP vsp_rcs_korf.

/src/vsp_rcs_korf/vsp_rcs_korf.cc Dodane Instrukcje do zbudowania czujnika SENSOR_RCS_KORF w powłoce interaktywnej bez oczekiwania.

Page 129: PRACA DYPLOMOWA MAGISTERSKA

Podsumowanie

123

7. Podsumowanie W ramach niniejszej pracy przeanalizowane i zaimplementowane zostały dwa algorytmy znajdywania rozwiązania kostki Rubika. Zostały one zintegrowane z systemem MROCC++ i uruchomione na systemie robota rozwiązującego kostkę Rubika. System robota poprawnie znajduje rozwiązanie. Dodatkowo identyfikuje niepoprawne stany kostki i stan reprezentujący ułoŜoną kostkę. Niemniej jednak poszukiwanie rozwiązania zajmuje znaczną ilość czasu, w trakcie którego robot stoi bezczynnie. Dodatkowo zupełnie niewykorzystany jest czas, w którym robot wykonuje kolejne obroty ścian kostki. MoŜliwy jest zatem szereg ulepszeń dla pracy zarówno samego algorytmu znajdywania rozwiązania kostki Rubika jak i robota układającego kostkę.

a) Odczyt stanu kostki przy uŜyciu dwóch kamer Proces odczytu stanu kostki Rubika przez robota jest obecnie bardzo czasochłonny. System wykonuje w nim 6 przełoŜeń kostki. KaŜda ściana odczytywana jest przy uŜyciu kamery znajdującej się w chwytaku Tracka. Chwytak Postumenta równieŜ zawiera kamerę. UŜycie jej do odczytu stanu kostki skróciłoby cały proces dwukrotnie, co znacznie by przyspieszyło i ułatwiło pracę i testy systemu.

b) Implementacja transmitera Program znajdujący rozwiązanie kostki Rubika został zintegrowany z systemem MRROC++ przy uŜyciu klas przeznaczonych dla czujników wirtualnych. Sposób ten został wykorzystany ze względu na istniejącą juŜ w systemie i moŜliwą do wykorzystanie funkcjonalność czujników. Budzi on jednak pewne wątpliwości. Program rozwiązujący kostkę Rubika oczywiście nie jest ani nie korzysta z Ŝadnego czujnika. Nienaturalne jest zatem stosowanie dla niego metod konfiguracji czujnika oraz inicjalizacji i pobrania odczytu. Program ten powinien pracować raczej jako zewnętrzny proces przetwarzania danych. Interfejs do niego powinien natomiast stanowić transmiter wysyłający dane wejściowe (stan kostki) i odbierający dane wyjściowe (rozwiązanie).

c) Wykorzystanie wszystkich dostępnych programów znajdujących rozwiązanie W chwili obecnej w systemie rozwiązanie koski Rubika znajdywane jest na trzy sposoby – przy uŜyciu czujników realizujących algorytm Korfa i Kociemby (rozwiązania zaimplementowane w ramach niniejszej pracy) oraz z wykorzystaniem udostępnionego na serwerze Windows programu znajdującego rozwiązanie kostki (rozwiązanie wcześniej uŜywane). System mógłby oczywiście wykorzystywać wszystkie trzy metody znajdujące rozwiązanie i wybierać najlepsze rozwiązanie spośród znalezionych.

d) Ocena rozwiązania pod względem długości i złoŜoności ruchów System wybiera najlepsze rozwiązanie spośród znalezionych na podstawie długości (liczby ruchów koniecznych do wykonania). Podobnie oceniane są kolejne rozwiązania znajdywane przez algorytm Kociemby. W przypadku systemu robota ocena taka nie jest do końca słuszna. ZłoŜoność ruchów jest róŜna. Aby wykonać ruch ścianką przeciwną do aktualnej konieczne jest wykonanie dwóch przełoŜeń. Oznacza to, Ŝe wykonanie takiego obrotu odpowiada złoŜonością wykonaniu dwóch obrotów dowolnymi innymi ścianami. NaleŜałoby uwzględnić tą właściwość sytemu przy ocenie i znajdywaniu kolejnych rozwiązań.

e) Szukanie kolejnych rozwiązań, gdy robot układa kostkę według nieoptymalnego rozwiązania

Dla bardzo złoŜonych stanów system na ogół nie znajduje rozwiązania optymalnego, a jedynie suboptymalne. Szukanie rozwiązania ma miejsce tylko zaraz po obejrzeniu kostki.

Page 130: PRACA DYPLOMOWA MAGISTERSKA

Podsumowanie

124

Następnie system zajmuje się jedynie wykonywaniem ruchów na kostce – przełoŜeń i obrotów ścianami. MoŜna by jednak i wtedy wykorzystać zdolności obliczeniowe robota i szukać lepszych rozwiązań dla kolejnych stanów kostki. Po znalezieniu rozwiązania suboptymalnego, robot zacząłby wykonywać pierwszy obrót i jednocześnie szukać rozwiązania kostki dla stanu po wykonaniu tego obrotu. JeŜeli znalezione rozwiązanie byłoby krótsze od aktualnie wykonywanego, robot podmieniłby sobie listę operacji do wykonania.

f) Wykorzystanie symetrii kostki podczas znajdywania rozwiązania W niniejszej pracy opisane zostały symetrie kostki oraz moŜliwość ich wykorzystania w celu znalezienia rozwiązania. Właściwość ta została wykorzystana w algorytmie Reida. Algorytm ten nie został zaimplementowany w ramach niniejszej pracy. Podczas dalszych prac nad programem do rozwiązywania kostki Rubika moŜna zaimplementować ten algorytm i porównać jego działanie z algorytmami juŜ zaimplementowanymi.

Page 131: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

125

Dodatek A – Dokumentacja programu CubeSolver15

General – klasy pomocnicze

DataTable - Abstrakcyjna klasa bazowa dla klas tablic przekształceń i wartości heurystycznych. Dostarcza mechanizm inicjalizacja oraz zapisu i odczytu z/do pliku. W klasach pochodnych musi zostać zdefiniowana metoda wypełniania tabeli danymi.

Pola chronione: iSize: int - Wielkość tabeli iaTable: int* - Wskaźnik do tabeli bLog: bool = false - Znacznik czy wyswietlać komentarze sFolderName: char* = NULL - Nazwa folderu, do którego zapisywane są wszystkie tabele danych.

Metody publiczne: DataTable(int size) - Konstruktor. Alokuje odpowiednią ilość pamięci na tabelę. DataTable(DataTable& table) - Konstruktor kopiujący. ~DataTable() - Destruktor. Zwalnia pamięć zaalokowaną na tabelę. DataTable& operator=(DataTable& table) - Konstruktor kopiujący. void Init() - Inicjalizuje tabelę. JeŜeli tabela (tableName) została wcześniej stworzona i zapisana do pliku (fileName),

to tylko ją odczytuje. W przeciwnym przypadku generuje ją i zapisuje do pliku. const char* GetName() - Zwraca nazwę pliku, w którym zapisana jest zawartość tabeli. const char* GetDescription() - Zwraca opis danych tabeli. const char* GetExtention() - Zwraca rozszerzenie pliku, w którym zapisana jest zawartość tabeli. void SetFolderName(const char* folder) - Ustawia nazwę folderu, do którego zapisywane są wszystkie tabele

danych. const char* GetFolderName() - Zwraca nazwę folderu, do którego zapisywane są wszystkie tabele danych. void ClearFolderName() - Zwalnia pamięć zaalokowaną dla nazwy folderu. void SetLog(bool log) - Ustawia znacznik logowania wiadomości na ekran.

Metody chronione: int GetData(int coord) - Udostępnia wpis z tabeli o współrzędnej coord. void SetData(int coord, int data) - Wpisuje dane do tabeli o współrzędnej coord.

Metody prywatne: void Generate() - Generuje tabelę. Dla kaŜdej wartości wspołrzędnej obliczane i zapisywane do tabeli jest jej

przekształcenie przez 6 podstawowych ruchów. void Load(FILE * inputStream) - Odczytuje tablicę ze strumienia wejściowego pliku inputStream. void Save(FILE * outputStream) - Zapisuje tablicę do strumienia wyjściowego pliku outputStream.

Exception - Klasa bazowa dla wszystkich błędów. Pola chronione:

iError: int - Kod błędu.

Metody publiczne: const char* GetType() - Zwraca typ klasy. Exception* Clone() - Kopiuje błąd. Zwraca nowy błąd, dla którego alokuje pamięć. char* ToString() - Zrzuca zawartość błędu do łańcucha znaków. Zajmuje pamięć dla zwracanego łańcucha, która

naleŜy później zwolnić. const char* GetErrorText() - Zwraca tekst błędu. const int GetError() -

15 Dokumentacja stworzona jest w UML. Krótki opis tego języka zawarty jest w dodatku C do niniejszej pracy.

Page 132: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

126

Metody chronione: Exception(int error) - Konstruktor. Tworzy obiekt dla określonego błędu.

Tester - Klasa testów. Pola chronione:

bLog: bool = false

iRep: int = 10

Metody publiczne: bool Test()

void SetLog(bool log)

void SetRepetitions(int rep)

Metody chronione: const char* ResultText(bool result)

Combinatorials – operacje kombinatoryczne

Collection - Abstrakcyjna klasa kolekcji elementów. UmoŜliwia podstawowe operacje na sobie Klasa bazowa dla wszystkich klas kombinatorycznych.

Pola chronione: bValidation: bool = true - Znacznik trybu pracy - z walidacją stanu czy bez. iaElems: int* - Tabele zawierająca elementy kolekcji. iCollSize: int - Wielkość kolekcji. iSetSize: int - Wielkość zbioru, na którym utworzona jest kolekcja.

Metody publiczne: void SetValidation(bool on) - Ustawia tryb pracy. ~Collection() - Destruktor. Zwalnia pamięć tabeli elementów kolekcji. int operator==(const Collection& coll) - Operator porówniania dwóch kolekcji. Zwraca 0, jeŜeli kolekcje są takie

same. Collection* Clone() - Tworzy kopie kolekcji i zwraca do niej wskaźnik. void SetInitState() - Ustawia stan początkowy kolekcji. void FromOrdinal(int ord) - Ustawia stan kolekcji odpowiadający numerowi ord, który jednoznacznie identyfikuje

kolekcję. Metoda nie zwraca Ŝadnych wartości. Metoda rzuca wyjątkiem w przypadku nieprawidłowego argumentu.

int ToOrdinal() - Zwraca numer jednoznacznie identyfikujący kolekcję.

Page 133: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

127

void FromTable(const int [] tab) - Ustawia stan kolekcji odpowiadający ułoŜeniu elementów w tabeli tab Tabela musi być odpowiedniej długości (iCollSize). Metoda nie zwraca Ŝadnych wartości. Metoda rzuca wyjątkiem, jeŜeli elementy w tabeli nie reprezentują poprawnej kolekcji.

void ToTable(int [] tab) - Wypełnia tabelę tab elementami kolekcji. Tabela musi być odpowiedniej wielkości (iCollSize).

int Parity() - Zwraca parzystość kolekcji. void Composite(Collection& coll) - Składa kolekcję z kolekcją coll. Kolekcje muszą być równoliczne. Ponadto coll

musi pozwalać na składanie jej. W przypadku niezgodności metoda rzuca wyjątkiem. bool AllowComposition() - Zwraca przyzwolenie albo jego brak na składanie kolekcji z inną kolekcją. char* ToString() - Zamienia kolekcję na łańcuch znaków reprezentujący ją. Alokuje pamięć na łańcuch, która trzeba

później zwolnić. Zwraca tenŜe łańcuch znaków.

Metody chronione: Collection(int collSize, int setSize, int maxCollSize, int maxSetSize) - Konstruktor. Tworzy kolekcję o size

elementach. Alokuje pamięć dla tabeli swoich elementów. Rzuca wyjątkiem w przypadku nieprawidłowego argumentów.

Collection(const Collection& coll) - Konstruktor kopiujący. Tworzy kolekcję jako kopię kolekcji coll. Collection& operator=(const Collection& coll) - Konstruktor przypisania. char GetType() - Zwraca literę oznaczającą typ kolekcji. Metoda uŜywana w ToString. void CheckTable(const int [] tab) - Sprawdza w tabeli tab zapisana jest poprawna kolekcja. W przypadku

negatywnego wyniku rzuca odpowiednim wyjątkiem. void ValidateSize(int size, int max, bool zero = false) - Sprawdza poprawność wielkości kolekcji i wielkości

zbioru, z którego utworzona jest kolekcja. Wielkości te powinny być z zakresu od 1 do max. Do niektórych operacji dozwolona jest równieŜ wartość size równa 0.

void ValidateOrdinal(int ord, int max) - Sprawdza poprawność numer ord, który jednoznacznie reprezentuje kolekcję zbioru o size elementach. Numer ord powinien przyjmować wartości z zakresu 0 do max-1. Dla innych wartości metoda rzuca wyjątkiem.

void ValidateCollection(const int [] tab, int collSize, int setSize) - Sprawdza poprawność kolekcji zapisanej w tabeli tab. Kolekcja powinna być wielkości colSize i powinna zawierać elementy zbioru o setSize elementach. W przypadku niepomyślnej weryfikacji rzuca wyjątkiem.

Combination - Klasa kombinacji bez powtórzeń. UmoŜliwia podstawowe operacje na sobie. Dziedziczy po Collection.

Klasa bazowa: Collection Pola publiczne:

MAX_COLL_SIZE: const int = 8 - Zwraca maksymalną obsługiwaną wielkość kolekcji. MAX_SET_SIZE: const int = 16 - Zwraca maksymalną obsługiwaną wielkość zbioru, z którego stworzona jest

kolekcja.

Metody publiczne: Combination(int collSize, int setSize) - Konstruktor. Tworzy permutację identycznościową zbioru N-elementowego

oraz typu type. Alokuje pamięć dla tabeli elementów permutacji. Rzuca wyjątkiem w przypadku nieprawidłowego argumentów.

Combination(const Combination& comb) - Konstruktor kopiujący. Tworzy permutację jako kopię permutacji perm.

Collection* Clone() - Tworzy kopie kolekcji i zwraca do niej wskaźnik. void SetInitState() - Ustawia permutację identycznościową. void FromOrdinal(int ord) - Ustawia permutację odpowiadającą numerowi ord, który jednoznacznie identyfikuje

permutację. Metoda nie zwraca Ŝadnych wartości. Rzuca wyjątkiem w przypadku nieprawidłowego typu permutacji bądź argumentu.

int ToOrdinal() - Zwraca numer jednoznacznie identyfikujący permutację. int Parity() - Zwraca parzystość permutacji. bool AllowComposition() - Zwraca przyzwolenie albo jego brak na składanie kolekcji z inną kolekcją. int NUMBER(int collSize, int setSize) - Wylicza liczbę róŜnych permutacji zbioru o size elementach. Rzuca

//wyjątkiem w przypadku nieprawidłowego argumentu.

Metody chronione: char GetType() - Zwraca literę oznaczającą typ kolekcji. Metoda uŜywana w ToString. void CheckTable(const int [] tab) - Sprawdza czy w tabeli tab zapisana jest poprawna kombinacja. W przypadku

negatywnego wyniku rzuca odpowiednim wyjątkiem.

Metody prywatne: void ValidateCombination(const int [] comb, int collSize, int setSize) - Sprawdza poprawność tabeli comb

reprezentującej kombinację zbioru o collSize elementach. Elementy comb powinny przyjmować róŜne wartości ze zbioru 0 do setSize-1. W przypadku niepomyślnej weryfikacji metoda rzuca wyjątkiem.

Permutation - Klasa permutacji bez powtórzeń. UmoŜliwia podstawowe operacje na sobie. Klasa bazowa: Collection

Page 134: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

128

Pola publiczne: MAX_SIZE: const int = 12 - Zwraca maksymalną obsługiwaną wielkość kolekcji i jednocześnie wielkość zbioru, z

którego stworzona jest kolekcja.

Metody publiczne: Permutation(int size) - Konstruktor. Tworzy permutację identycznościową zbioru o size elementach. Alokuje

pamięć dla tabeli elementów permutacji. Rzuca wyjątkiem w przypadku nieprawidłowego argumentu. Permutation(const Permutation& perm) - Konstruktor kopiujący. Tworzy permutację jako kopię permutacji perm. Collection* Clone() - Tworzy kopie permutacji i zwraca do niej wskaźnik. void SetInitState() - Ustawia permutację identycznościową. void FromOrdinal(int ord) - Ustawia permutację odpowiadającą numerowi ord, który jednoznacznie identyfikuje

permutację. Metoda nie zwraca Ŝadnych wartości. Rzuca wyjątkiem w przypadku nieprawidłowego argumentu. int ToOrdinal() - Zwraca numer jednoznacznie identyfikujący permutację. int Parity() - Zwraca parzystość permutacji. bool AllowComposition() - Zwraca przyzwolenie albo jego brak na składanie permutacji z inną kolekcją. int NUMBER(int size) - Wylicza liczbę róŜnych permutacji zbioru o size elementach. Rzuca wyjątkiem w

przypadku nieprawidłowego argumentu. void FromCycle(const int [] cycle, int C) - Ustawia permutację odpowiadającą C-cyklowi cycle. Rzuca wyjątkiem

w przypadku niepoprawnego cyklu. void Inverse() - Zamienienia permutację na swoja odwrotność.

Metody chronione: char GetType() - Zwraca literę oznaczającą permutację. Metoda uŜywana w ToString. void CheckTable(const int [] tab) - Sprawdza czy w tabeli tab zapisana jest poprawna permutacja. W przypadku

negatywnego wyniku rzuca odpowiednim wyjątkiem.

Metody prywatne: void ValidateCycle(const int [] cycle, int C, int N) - Sprawdza poprawność C-cyklu w permutacji zbioru o size

elementach. Cykl powinien byc długości 1 do size, a jego elementy powinny przyjmować róŜne wartości ze zbioru 0 do size-1. W przypadku niepomyślnej weryfikacji metoda rzuca wyjątkiem.

void ValidatePermutation(const int [] perm, int size) - Sprawdza poprawność tabeli perm reprezentującej permutację zbioru o size elementach. Elementy perm powinny przyjmować róŜne wartości ze zbioru 0 do size-1. W przypadku niepomyślnej weryfikacji metoda rzuca wyjątkiem.

Variation - Klasa wariacji z powtórzeniami. UmoŜliwia podstawowe operacje na sobie. Klasa bazowa: Collection Pola publiczne:

MAX_COLL_SIZE: const int = 12 - Zwraca maksymalną obsługiwaną wielkość kolekcji. MAX_SET_SIZE: const int = 6 - Zwraca maksymalną obsługiwaną wielkość zbioru, z którego stworzona jest

kolekcja.

Metody publiczne: Variation(int collSize, int setSize) - Konstruktor. Tworzy wariację złoŜoną z elementów o wartości. Alokuje pamięć

dla tabeli elementów wariacji. Rzuca wyjątkiem w przypadku nieprawidłowych argumentów. Variation(const Variation& vari) - Konstruktor kopiujący. Tworzy wariację jako kopię wariacji vari. Collection* Clone() - Tworzy kopie wariacji i zwraca do niej wskaźnik. void SetInitState() - Ustawia wariację zawierającą jedynie elementy o wartości 0. void FromOrdinal(int ord) - Ustawia wariację odpowiadającą numerowi ord, który jednoznacznie identyfikuje

wariację. Metoda nie zwraca Ŝadnych wartości. Rzuca wyjątkiem w przypadku nieprawidłowego argumentu. int ToOrdinal() - Zwraca numer jednoznacznie identyfikujący wariację. int Parity() - Zwraca parzystość wariacji. bool AllowComposition() - Zwraca przyzwolenie albo jego brak na składanie wariacji z inną kolekcją. int NUMBER(int collSize, int setSize) - Wylicza liczbę róŜnych wariacji o długości collSize zbioru o setSize

elementach. Rzuca wyjątkiem w przypadku nieprawidłowych argumentów. void ChooseNext(int pos, bool bigger = true) - Na pozycji pos wariacji wybiera element o wartości o 1 większej

bądź mniejszej (w zaleŜności od parametru bigger) od aktualnie wybranego. Metoda rzuca wyjątkiem w przypadku nieprawidłowego argumentu.

Metody chronione: char GetType() - Zwraca literę oznaczającą wariację. Metoda uŜywana w ToString. void CheckTable(const int [] tab) - Sprawdza czy w tabeli tab zapisana jest poprawna wariacja. W przypadku

negatywnego wyniku rzuca odpowiednim wyjątkiem.

Metody prywatne: void ValidatePosition(int pos, int size) - Sprawdza czy pozycja pos istnieje w wariacji długości size. Pozycja w

wariacji numerowane są od 0 do size-1. W przypadku niepomyślnej weryfikacji metoda rzuca wyjątkiem.

CombinatorialsException - Klasa wyjątków operacji kombinatorycznych. Klasa bazowa: Exception

Page 135: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

129

Agregacje prywatne: Collection* pColl – obiekt, w którym wystąpił błąd

Pola publiczne: TYPE: const char* = "Combinatorials" - Stała określająca ciąg znaków reprezentujący typ klasy.

Pola prywatne: iValue: int - Wartość, która powoduje błąd. ErrorText: char * [] - wiadomosci błędów

Metody publiczne: const char* GetType() - Zwraca typ klasy. CombinatorialsException(Collection* coll, int value, int error) - Konstruktor. Tworzy obiekt dla określonego

błędu. CombinatorialsException(const CombinatorialsException& exp) - Konstruktor kopiujący. ~CombinatorialsException() - Destruktor. Zwalnia zajmowaną pamięć. CombinatorialsException& operator=(const CombinatorialsException& exp) - Operator przypisania. Exception* Clone() - Kopiuje błąd. Zwraca nowy błąd, dla którego alokuje pamięć. char* ToString() - Zrzuca zawartość błędu do łańcucha znaków. Zajmuje pamięć dla zwracanego łańcucha, która

naleŜy później zwolnić. Zwraca tenŜe łańcuch.

Metody chronione: const char* GetErrorText() - zwraca wiadomość błędu

Klasy zagnieŜdŜone: enum eError - Zwracane kody błędów

CombinatorialsTester - Klasa wyjątków operacji kombinatorycznych. Klasa bazowa: Tester Metody publiczne:

CombinatorialsTester()

~CombinatorialsTester()

bool Test() -

Metody prywatne: bool TestPermutation()

bool TestCombination()

bool TestVariation()

bool TestPermutationCreateException(int size)

bool TestPermutationOrdinalException(int size, int ordinal)

bool TestPermutationTableException(int size, const int [] tab)

bool TestPermutationCreate(int size, int ordinal)

bool TestPermutationOrdinal(int size, int ordinal)

bool TestPermutationInverse(int size, int ordinal)

bool TestPermutationCycle(int size, int ordinal, int csize, int cordinal)

bool TestCombinationCreateException(int colSize, int setSize)

bool TestCombinationOrdinalException(int colSize, int setSize, int ordinal)

bool TestCombinationTableException(int colSize, int setSize, const int [] tab)

bool TestCombinationCreate(int colSize, int setSize, int ordinal)

bool TestCombinationOrdinal(int colSize, int setSize, int ordinal)

bool TestVariationCreateException(int colSize, int setSize)

bool TestVariationOrdinalException(int colSize, int setSize, int ordinal)

bool TestVariationTableException(int colSize, int setSize, const int [] tab)

bool TestVariationCreate(int colSize, int setSize, int ordinal)

bool TestVariationOrdinal(int colSize, int setSize, int ordinal)

void Print(const char * desc, Collection* coll)

void Print(const char * desc, Collection* coll, int ordinal)

void Print(const char * desc, CombinatorialsException* exp)

Page 136: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

130

Cube – wygląd i budowa kostki Rubika

Cube - Interfejs definiujący podstawowe metody na Kostce Rubika. Pola publiczne:

TYPE: const char* = "Cube" - Stała określająca ciąg znaków reprezentujący typ klasy.

Pola chronione: bValidation: bool = true - Znacznik trybu pracy - z walidacją stanu czy bez.

Metody publiczne: const char* GetType() - Zwraca typ klasy. ~Cube() Cube* Clone() - Kopiuje stan kostki. Zwraca nowy stan, dla ktorego alokuje pamiec. void SetInitState() - Ustawia stan kostki jako ułoŜony. Nie zwraca Ŝadnej wartości. char* ToString() - Zamienia stan kostki na łańcuch znaków reprezentujący go. Zwraca tenŜe łańcuch znaków.

Alokuje pamięć na łańcuch, która trzeba później zwolnić. void Move(CubeMove::eMove move, CubeMove::eTurn turn) - Wykonuje ruch o numerze move na kostce. Nie

zwraca Ŝadnej wartości. bool IsAllowed(CubeMove::eMove move, CubeMove::eTurn turn) - Sprawdza, czy moŜna na kostce wykonać

ruch move o obrocie turn. void SetValidation(bool on) - Ustawia tryb pracy.

Page 137: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

131

CubieCube - Klasa opisująca kostkę Rubika na poziomie kosteczek. Zawiera ona permutację i orientację 12 krawędzi i 8 rogów kostki. UmoŜliwia sprawdzanie poprawności stanu kostki.

Klasa bazowa: Cube Agregacje prywatne:

Permutation cornerPermutation – UłoŜenie rogów kostki. Permutation edgePermutation – UłoŜenie krawędzi kostki. Variation cornerOrientation – Orientacja rogów kostki. Variation edgeOrientation – Orientacja krawędzi kostki.

Pola publiczne: TYPE: const char* = "CubieCube" - Stała określająca ciąg znaków reprezentujący typ klasy. CORNER_NUMBER: const int = 8 - Liczba rogów. TWIST_NUMBER: const int = 3 CORNER_IN_FACE_NUMBER: const int = 4 - Liczba rogów w ścianie. MOVE_CORNERS: const int [][] - Rogi naleŜące do ścian kostki MOVE_TWIST: const bool [] - Czy ruch obraca rogi naleŜące do ścian kostki EDGE_NUMBER: const int = 12 - Liczba krawędzi. FLIP_NUMBER: const int = 2 EDGE_IN_FACE_NUMBER: const int = 4 - Liczba rogów w ścianie. MOVE_EDGES: const int [][] - Krawędzi naleŜące do ścian kostki MOVE_FLIP: const bool [] - Czy ruch obraca krawędzi naleŜące do ścian kostki

Metody publiczne: const char* GetType() - Zwraca typ klasy. void CORNER_TWIST(int& ori, bool clockwise) - Obrócenie rogu void FACE_CORNERS_ROTATE(FaceletCube::eFace face, bool clockwise) - Rotacja rogów w ścianie. void EDGE_FLIP(int& ori) - Obrócenie rogu void FACE_EDGES_ROTATE(FaceletCube::eFace face, bool clockwise) - Rotacja krawędzi w ścianie. CubieCube() - Konstruktor domyślny. Tworzy ułoŜoną kostkę. CubieCube(const CubieCube& cube) - Konstruktor kopiujący. Tworzy nowy stan równy stanowi cube. Cube* Clone() - Kopiuje stan kostki. Zwraca nowy stan, dla które alokuje pamięć. ~CubieCube() - Destruktor. int operator==(const CubieCube& cube) - Operator porównia. Porównuje ze stanem kostki cube. void SetInitState() - Ustawia stan kostki jako ułoŜony. Nie zwraca Ŝadnej wartości. void FromTable(const int [] cube) - Pobiera stan kostki z tabeli reprezentującej go. Rzuca wyjątkiem w przypadku

niepowodzenia. void ToTable(int [] cube) - Zapisuje stan kostki do tabeli char* ToString() - Zamienia stan kostki na łańcuch znaków reprezentujący go. Zwraca tenŜe łańcuch znaków.

Alokuje pamięć na łańcuch, która trzeba później zwolnić. void Move(CubeMove::eMove move, CubeMove::eTurn turn) - Wykonuje ruch o numerze move na kostce. Nie

zwraca Ŝadnej wartości.

Metody prywatne: void Validate() - Sprawdza poprawność stanu kostki. Orientacja rogów i krawędzi powinna być parzysta.

Dodatkowo parzystość permutacji rogów i krawędzi powinny być sobie równe. void MoveCubies(CubeMove::eMove move, bool clockwise) - Wykonuje obrót move zgodnie z bądź przeciwnie

do (w zaleŜności od wartości parametry clockwise) ruchu wskazówek zegara.

Klasy zagnieŜdŜone: enum eCorner - Numery rogów. enum eEdge - Numery krawędzi. enum eTwist – Numery obrotów rogów. enum eFlip – Numery obrotów krawędzi.

FaceletCube - Klasa opisująca kostkę Rubika na poziomie ścianek kostki. Zawiera ona zawartość 54 ścian kostki. UmoŜliwia sprawdzanie poprawności stanu kostki.

Klasa bazowa: Cube Agregacje prywatne:

eFace iaFacelets - Unikalne numery ścian kostki.

Pola publiczne: TYPE: const char* = "FaceletCube" - Stała określająca ciąg znaków reprezentujący typ klasy. FACE_NUMBER: const int = 6 - Liczba ścian kostki. FACELET_IN_FACE_NUMBER: const int = 9 - Liczba ścianek w ścianie. FACELET_NUMBER: const int = 54 - Liczba ścianek w kostce. FACE_NAMES: const char * = "FRUBLD" - 1-literowe nazwy ścian kostki. FACE_COLORS: const char * = "wbrygo" - 1-literowe kolory ścian kostki.

Pola prywatne:

Page 138: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

132

caMarkings: char [FACE_NUMBER] - Oznakowanie 6 ścian kostki na podstawie zawartości środkowych ścianek.

Metody publiczne: const char* GetType() - Zwraca typ klasy. FaceletCube() - Konstruktor domyślny. Tworzy ułoŜoną kostkę. FaceletCube(FaceletCube& cube) - Konstruktor kopiujący. Kopiuje zawartość cube. Cube* Clone() - Kopiuje stan kostki. Zwraca nowy stan, dla które alokuje pamięć. ~FaceletCube() - Destruktor. Pusty. int operator==(const FaceletCube& cube) - Operator porównia. Porównuje ze stanem kostki cube. void SetInitState() - Ustawia stan kostki jako ułoŜony. Nie zwraca Ŝadnej wartości. void FromTable(const int [] cube) - Pobiera stan kostki z tabeli reprezentującej go. Rzuca wyjątkiem w przypadku

niepowodzenia. void ToTable(int [] cube) - Zapisuje stan kostki do tabeli void FromString(const char* sCube) - Pobiera stan kostki z łańcucha znaków reprezentującego go. Rzuca

wyjątkiem w przypadku niepowodzenia. char* ToString() - Zamienia stan kostki na łańcuch znaków reprezentujący go. Zwraca tenŜe łańcuch znaków.

Alokuje pamięć na łańcuch, która trzeba później zwolnić. void Move(CubeMove::eMove move, CubeMove::eTurn turn) - Wykonuje ruch o numerze move na kostce. Nie

zwraca Ŝadnej wartości.

Metody prywatne: void CheckTable(const int [] cube) - Sprawdza wartości elementów tabeli, w których zapisany jest stan kostki. void CheckFormat(const char* sCube) - Sprawdza format łańcucha znaków, w którym zapisany jest stan kostki. void Validate() - Sprawdza czy stan kostki jest poprawny. Rzuca wyjątkiem jeŜeli stan jest niepoprawny. Nie zwraca

Ŝadnych wartości. void ValidateCenters() - Sprawdza czy oznaczenia środków są prawidłowe. Oznaczenie kaŜdego środki powinno

być inne. Oznaczenia te są zapamiętywane jako oznaczenia całych ścianek. void ValidateFacelets() - Sprawdza czy oznaczenia ścianek są prawidłowe. Oznaczenia powinny być tylko takie jak

oznaczenia ścian. Ponadto kaŜde oznaczenie powinno wystąpic dokładnie 9 razy. eFace FaceNameToFace(char name) - Znajduje ścianę o nazwie name. Zwraca numer ściany. Rzuca wyjątkiem,

jeŜeli ściana o nazwie name nie występuje w kostce. eFace MarkingToFace(char marking) - Znajduje ścianę o oznakowaniu marking. Zwraca numer ściany. Rzuca

wyjątkiem, jeŜeli oznakowanie marking nie występuje w kostce.

CubeMove

Pola publiczne: MOVE_NUMBER: const int = 6 MOVE_NAMES: const char [] = "FRUBLD" - nazwy obrotów TURN_NUMBER: const int = 3 TURN_NAMES: const char [] = "123" - nazwy krotności

Metody publiczne: eMove MOVE_NUMBER_FROM_NAME(char name)

eTurn TURN_NUMBER_FROM_NAME(char name)

eMove OPPOSITE_FACE_MOVE(eMove move)

eTurn REVERSE_TURN(eTurn turn)

Klasy zagnieŜdŜone: enum eMove – Numery ruchów na kostce. enum eTurn – Numery krotności ruchów na kostce.

CubeTranslator - Klasa opisująca kostkę Rubika na poziomie ścianek kostki. Zawiera ona zawartość 54 ścian kostki. UmoŜliwia sprawdzanie poprawności stanu kostki.

Pola publiczne: CORNER_MAP: const int [][] - Numery ścianek naleŜących do rogów. EDGE_MAP: const int [][] - Numery ścianek naleŜących do krawędzi.

Metody publiczne: void FaceletToCubie(FaceletCube& fCube, CubieCube& cCube) – Tłumaczy wygląd zewnętrzny kostki na jej

budowę. void CubieToFacelet(FaceletCube& fCube, CubieCube& cCube) – Tłumaczy budowę kostki na jej wygląd

zewnętrzny.

CubeException - Klasa błędu opisu kostki Rubika. Klasa bazowa: Exception Agregacje prywatne:

Cube* pCube - Opis, w którym występuje błąd.

Pola publiczne:

Page 139: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

133

TYPE: const char* = "Cube" - Stała określająca ciąg znaków reprezentujący typ klasy.

Pola chronione: sCube: char* - Łańcuch reprezentujący niepoprawny stan kostki. iValue: int - Wartość, która powoduje błąd.

Pola prywatne: ErrorText: char * [] - Wiadomosci błędów.

Metody publiczne: const char* GetType() - Zwraca typ klasy. CubeException(Cube* pCube, const char * sCube, int val, int error) - Konstruktor. Tworzy obiekt dla

określonego błędu. CubeException(Exception* pExc, int error) - Konstruktor. Tworzy obiekt z wyjątku tworzącego go. CubeException(const CubeException& exp) - Konstruktor kopiujący. ~CubeException() - Destruktor. Zwalnia zajmowaną pamięć. CubeException& operator=(const CubeException& exp) - Operator przypisania. Exception* Clone() - Kopiuje błąd. Zwraca nowy błąd, dla którego alokuje pamięć. char* ToString() - Zrzuca zawartość błędu do łańcucha znaków. Zajmuje pamięć dla zwracanego łańcucha, która

naleŜy później zwolnić.

Metody chronione: const char* GetErrorText()

Klasy zagnieŜdŜone: enum eError - Zwracane kody błędów

CubeTester - Klasa wyjątków operacji kombinatorycznych. Klasa bazowa: Tester Metody publiczne:

CubeTester()

~CubeTester()

bool Test() -

Metody prywatne: bool TestFaceletCube()

bool TestCubieCube()

bool TestTranslator()

bool TestFaceletCubeStringException(const char* scube)

bool TestFaceletCubeTableException(const int [] icube)

bool TestFaceletCubeMoveException()

bool TestFaceletCubeCreate()

bool TestFaceletCubeString(const char* scube)

bool TestFaceletCubeTables()

bool TestCubieCubeTableException(const int [] icube)

bool TestCubieCubeCreate()

bool TestCubieCubeTables()

bool TestCubieCubeMoves()

bool TestTranslatorConst()

bool TestTranslatorTranslateException(const char* scube)

bool TestTranslatorTranslate()

void GetMoves(CubeMove::eMove * moves, CubeMove::eTurn * turns, Cube* ref, int number)

void Move(Cube* cube, CubeMove::eMove * moves, CubeMove::eTurn * turns, int number, bool forward)

void Print(CubeMove::eMove * moves, CubeMove::eTurn * turns, int number)

void Print(const char * desc, Cube* cube)

void Print(const char * desc, CubeException* exp)

Page 140: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

134

CubeSolver

CubeSolver - Klasa abstrakcyjna definiujaca metody klas znajdujacych rozwiazanie kostki. Pola chronione:

bLog: bool = false - Znacznik czy wyswietlac komentarze bTest: bool = false - Znacznik czy wyswietlac wartości dla testów

Metody publiczne: ~CubeSolver() - Destruktor. CubeSolution* FindSolution(Cube* scrambledCube) - Znajduje rozwiazanie kostki. Zwraca kod sukcesu lub

porazki. Ustawia kod błędu i kod ostrzeŜenia. void Solve(Cube* scrambledCube, const CubeSolution& solution) void SetLog(bool log) - Ustawia znacznik wyświetlania komentarzy. void SetTest(bool test) - Ustawia znacznik wyświetlania wartości dla testów.

Metody chronione: CubeSolver() - Konstruktor. void Init() - Inicjalizuje klasę. CubeSolution* FindNextSolution(Cube* scrambledCube, const CubeSolution& solution) int Search(CubeSolverContext& context, Cube* cube, int parent_totalcost) - Rekurencyjne przeszukiwanie

drzewa według strategi IDA* int SearchNext(CubeSolverContext& context, Cube* cube, int parent_totalcost) - Rekurencyjne przeszukiwanie

drzewa według strategi IDA* int Heuristic(Cube* cube) - Funkcja heurystyczna

Klasy zagnieŜdŜone: CubeSolverContext - Klasa kontekstu rozwiązywanego problemu.

CubeSolution - Klasa opisująca rozwiązanie kostki. Agregacje prywatne:

eMove* iaMoves – Ruchy tworzące rozwiązanie.

Page 141: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

135

eTurn* iaTurns – Krotności ruchów tworzących rozwiązanie.

Pola publiczne: DELIM: const char = ','

Pola prywatne: iLength: int - Długość rozwiązania iMaxLength: int - Maksymalna długość rozwiązania przy aktualnych tabelach. iInfo: int - Maska dodatkowych błędów, ostrzeŜeń i komentarzy

Metody publiczne: CubeSolution() - Konstruktor. Tworzy puste rozwiązanie. CubeSolution(const CubeSolution& sol) - Konstruktor kopiujący. CubeSolution* Clone() - Kopiuje stan kostki. Zwraca nowy stan, dla które alokuje pamięć. ~CubeSolution() - Destruktor. CubeSolution& operator=(const CubeSolution& sol) - Operator przypisania. void SetMove(int pos, CubeMove::eMove move, CubeMove::eTurn turn) - Ustawia ruch na pozycji pos. void GetMove(int pos, CubeMove::eMove& move, CubeMove::eTurn& turn) - Pobiera ruch z pozycji pos. int GetLength() - Zwraca długość rozwiązania. bool IsAllowed() void FromString(const char* sSol) - Pobiera rozwiązanie z łańcucha znaków reprezentującego je. Rzuca wyjątkiem

w przypadku niepowodzenia. char* ToString() - Zwraca rozwiązanie jako łańcuch nazw ruchów rozdzielonych separatorem. void SetInfo(const eInfo info, bool on)

bool GetInfo(const eInfo info) -

Metody prywatne: void Extend()

void CheckFormat(const char* sSol)

Klasy zagnieŜdŜone: enum eInfo – Dodatkowa informacja o rozwiązaniu.

CubeSolutionException - Klasa błędu opisu kostki Rubika. Klasa bazowa: Exception Pola publiczne:

TYPE: const char* = "CubeSolution" - Stała określająca ciąg znaków reprezentujący typ klasy.

Pola chronione: sSol: char* - Łańcuch reprezentujący niepoprawne rozwiązanie. iValue: int - Wartość, która powoduje błąd.

Pola prywatne: ErrorText: char * [] - Wiadomosci błędów.

Metody publiczne: const char* GetType() - Zwraca typ klasy. CubeSolutionException(const char * sSol, int val, int error) - Konstruktor. Tworzy obiekt dla określonego błędu. CubeSolutionException(const CubeSolutionException& exp) - Konstruktor kopiujący. ~CubeSolutionException() - Destruktor. Zwalnia zajmowaną pamięć. CubeSolutionException& operator=(const CubeSolutionException& exp) - Operator przypisania. Exception* Clone() - Kopiuje błąd. Zwraca nowy błąd, dla którego alokuje pamięć. char* ToString() - Zrzuca zawartość błędu do łańcucha znaków. Zajmuje pamięć dla zwracanego łańcucha, która

naleŜy później zwolnić.

Metody chronione: const char* GetErrorText()

Klasy zagnieŜdŜone: enum eError - Zwracane kody błędów

CubeMoveTable - Abstrakcyjna klasa bazowa dla klas tablic przekształceń. Dostarcza mechanizm tworzenia. W klasach pochodnych muszą zostać zdefiniowane metody dotyczące konwersji między stanem kostki a jego wspołrzędną.

Klasa bazowa: DataTable Pola prywatne:

iCoordSize: int

Metody publiczne: CubeMoveTable(int coordSize) - Konstruktor. CubeMoveTable(const CubeMoveTable& table) - Konstruktor kopiujący. ~CubeMoveTable() - Destruktor.

Page 142: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

136

CubeMoveTable& operator=(const CubeMoveTable& table) - Konstruktor kopiujący. int Get(int coord, CubeMove::eMove move) - Udostępnia wpis z tabeli określający przekształcenie wspołrzędnej

coord przez ruch move. int GetSize() - Zwraca wielkość tabeli. const char* GetExtention() - Zwraca rozszerzenie pliku, w którym zapisana jest zawartość tabeli. CubeMove::eTurn GetTurn(CubeMove::eMove move) - Zwraca domyślny obrót dla ruchu move.

Metody chronione: int GetCoord() - Pobiera wspołrzędną z lokalnego obiektu kostki pCube. void SetCoord(int coord) - Ustawia stan lokalnego obiektu kostki pCube zgodnie ze wspołrzędna coord. void PreGenerate() - Wykonuje operacje przed generowaniem tablicy. void PostGenerate() - Wykonuje operacje po wygenerowaniu tablicy.

Metody prywatne: void Generate() - Generuje tabelę. Dla kaŜdej wartości wspołrzędnej obliczane i zapisywane do tabeli jest jej

przekształcenie przez 6 podstawowych ruchów. int GetDataCoord(int coord, CubeMove::eMove move)

CubePruningTable - Klasa odległości częściowych stanów kostki od rozwiązania. Klasa konstruowana jest na podstawie dwóch tablic przeksztalceń. Przechowuje odleglość od rozwiązania dla kaŜdej kombinacji współrzędnych z obu tabel.

Klasa bazowa: DataTable Pola prywatne:

iCoordSize: int

MAX_DEPTH: const int = 0x0f

Metody publiczne: CubePruningTable(int coordSize) - Konstruktor. ~CubePruningTable() - Destruktor. int Get(int coord) - Udostępnienie wartości z pola o indeksie index.

Metody chronione: int GetInitCoord() - Pobiera wspołrzędną z lokalnego obiektu kostki pCube. int GetCoord(int coord, CubeMove::eMove move, CubeMove::eTurn turn) - Ustawia stan lokalnego obiektu

kostki pCube zgodnie ze wspołrzędna coord. bool IsAllowed(CubeMove::eMove move, CubeMove::eTurn turn) - Sprawdza czy dozwolony jest ruch. void PreGenerate() - Wykonuje operacje przed generowaniem tablicy. void PostGenerate() - Wykonuje operacje po wygenerowaniu tablicy. const char* GetExtention() - Zwraca rozszerzenie pliku, w którym zapisana jest zawartość tabeli.

Metody prywatne: void Generate() - Generuje tabelę. Dla kaŜdej wartości wspołrzędnej obliczane i zapisywane do tabeli jest jej

przekształcenie przez 6 podstawowych ruchów. void Set(int coord, int value) - Udostępnienie wartości z pola o indeksie index. int GetDataCoord(int coord)

int GetInDataPos(int coord)

Page 143: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

137

Kociemba – rozwiązywanie kostki algorytmem Kociemby

Page 144: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

138

KociembaCube - Klasa opisująca Kostkę Rubika na poziomie współrzędnych.

Klasa bazowa: Cube Pola publiczne:

TYPE: const char* = "KociembaCube" - Stała określająca ciąg znaków reprezentujący typ klasy. EDGE_SLICE_NUMBER: const int

CORNER_PERMUTATION_NUMBER: const int

CORNER_ORIENTATION_NUMBER: const int

EDGE_SLICE_COMBINATION_NUMBER: const int

EDGE_SLICE_PERMUTATION_NUMBER: const int

EDGE_TWO_SLICES_PERMUTATION_NUMBER: const int

EDGE_ORIENTATION_NUMBER: const int

Metody publiczne: const char* GetType() - Zwraca typ klasy. void FromCubieCube(CubieCube& cube) - Pobiera stan kostki z tabeli reprezentującej go. Rzuca wyjątkiem w

przypadku niepowodzenia. void ToCubieCube(CubieCube& cube) - Zapisuje stan kostki do tabeli void FromCoords(int [] coords) - Pobiera stan kostki ze współrzędnych reprezentujących go. Rzuca wyjątkiem w

przypadku niepowodzenia. void ToCoords(int [] coords) - Zapisuje stan kostki do współrzędnych

Metody chronione: void InitCoords(int [] coords) - Ustawia współrzędne stanu początkowego. void CubieCubeToCoords(CubieCube& cube, int [] coords) - Pobiera stan kostki z tabeli reprezentującej go.

Rzuca wyjątkiem w przypadku niepowodzenia. void CoordsToCubieCube(CubieCube& cube, int [] coords) - Zapisuje stan kostki do tabeli

KociembaPhase1Cube - Klasa opisująca Kostkę Rubika na poziomie współrzędnych. Klasa bazowa: KociembaCube Agregacje prywatne:

KociembaPhase1MoveTable mtCO - Tabela przekształceń współrzędnych orientacji rogów przez obroty uŜywana w pierwszej fazie algorytmu

KociembaPhase1MoveTable mtEMC - Tabela przekształceń współrzędnych kombinacji pozycji krawędzi środkowej warstwy przez obroty uŜywana w pierwszej fazie algorytmu

KociembaPhase1MoveTable mtEO - Tabela przekształceń współrzędnych orientacji krawędzi przez obroty uŜywana w pierwszej fazie algorytmu

Pola publiczne: TYPE: const char* = "KociembaPhase1Cube" - Stała określająca ciąg znaków reprezentujący typ klasy.

Pola prywatne: cornerOrientationCoord: int

edgeMidSliceCombinationCoord: int

edgeOrientationCoord: int

bInitialized: bool = false

Metody publiczne: const char* GetType() - Zwraca typ klasy. void SInit()

void SClear() KociembaPhase1Cube() - Konstruktor domyślny. Tworzy ułoŜoną kostkę. KociembaPhase1Cube(const KociembaPhase1Cube& cube) - Konstruktor kopiujący. Tworzy nowy stan równy

stanowi cube. ~KociembaPhase1Cube() - Destruktor. Cube* Clone() - Kopiuje stan kostki. Zwraca nowy stan, dla które alokuje pamięć. int operator==(const KociembaPhase1Cube& cube) - Operator porównia. Porównuje ze stanem kostki cube. void SetInitState() - Ustawia stan kostki jako ułoŜony. Nie zwraca Ŝadnej wartości. void FromCubieCube(CubieCube& cube) - Pobiera stan kostki z tabeli reprezentującej go. Rzuca wyjątkiem w

przypadku niepowodzenia. void ToCubieCube(CubieCube& cube) - Zapisuje stan kostki do tabeli void FromCoords(int [] coords) - Pobiera stan kostki ze współrzędnych reprezentujących go. Rzuca wyjątkiem w

przypadku niepowodzenia. void ToCoords(int [] coords) - Zapisuje stan kostki do współrzędnych char* ToString() - Zamienia stan kostki na łańcuch znaków reprezentujący go. Zwraca tenŜe łańcuch znaków.

Alokuje pamięć na łańcuch, która trzeba później zwolnić. void Move(CubeMove::eMove move, CubeMove::eTurn turn) - Wykonuje ruch o numerze move na kostce. Nie

zwraca Ŝadnej wartości.

Metody prywatne:

Page 145: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

139

void MoveCoords(CubeMove::eMove move)

KociembaPhase2Cube - Klasa opisująca Kostkę Rubika na poziomie współrzędnych. Klasa bazowa: KociembaCube Agregacje prywatne:

KociembaPhase2MoveTable MTP - Tabela przekształceń współrzędnych permutacji rogów przez obroty uŜywana w drugiej fazie algorytmu

KociembaPhase2MoveTable temp - Tabela przekształceń współrzędnych permutacji krawędzi środkowej warstwy przez obroty uŜywana w drugiej fazie algorytmu

KociembaPhase2MoveTable mtENP - Tabela przekształceń współrzędnych permutacji krawędzi górnej i dolnej warstwy przez obroty uŜywana w drugiej fazie algorytmu

Pola publiczne: TYPE: const char* = "KociembaPhase2Cube" - Stała określająca ciąg znaków reprezentujący typ klasy.

Pola prywatne: cornerPermutationCoord: int

edgeMidSlicePermutationCoord: int

edgeNonMidSlicePermutationCoord: int

bInitialized: bool = false

Metody publiczne: const char* GetType() - Zwraca typ klasy. void SInit()

void SClear() KociembaPhase2Cube() - Konstruktor domyślny. Tworzy ułoŜoną kostkę. KociembaPhase2Cube(const KociembaPhase2Cube& cube) - Konstruktor kopiujący. Tworzy nowy stan równy

stanowi cube. ~KociembaPhase2Cube() - Destruktor. Cube* Clone() - Kopiuje stan kostki. Zwraca nowy stan, dla które alokuje pamięć. int operator==(const KociembaPhase2Cube& cube) - Operator porównia. Porównuje ze stanem kostki cube. void SetInitState() - Ustawia stan kostki jako ułoŜony. Nie zwraca Ŝadnej wartości. void FromCubieCube(CubieCube& cube) - Pobiera stan kostki z tabeli reprezentującej go. Rzuca wyjątkiem w

przypadku niepowodzenia. void ToCubieCube(CubieCube& cube) - Zapisuje stan kostki do tabeli void FromCoords(int [] coords) - Pobiera stan kostki ze współrzędnych reprezentujących go. Rzuca wyjątkiem w

przypadku niepowodzenia. void ToCoords(int [] coords) - Zapisuje stan kostki do współrzędnych char* ToString() - Zamienia stan kostki na łańcuch znaków reprezentujący go. Zwraca tenŜe łańcuch znaków.

Alokuje pamięć na łańcuch, która trzeba później zwolnić. void Move(CubeMove::eMove move, CubeMove::eTurn turn) - Wykonuje ruch o numerze move na kostce. Nie

zwraca Ŝadnej wartości. bool IsAllowed(CubeMove::eMove move, CubeMove::eTurn turn) - Sprawdza, czy moŜna na kostce wykonać

ruch move o obrocie turn.

Metody prywatne: void MoveCoords(CubeMove::eMove move)

KociembaSolver - Klasa znajdująca rozwiązanie kostki algorytmem dwufazowym Kociemby. Klasa bazowa: CubeSolver Metody publiczne:

void Init()

int Heuristic(Cube* ) CubeSolution* FindSolution(Cube* scrambledCube) - Znajduje rozwiazanie kostki. Zwraca kod sukcesu lub

porazki. Ustawia kod błędu i kod ostrzeŜenia. CubeSolution* FindNextSolution(Cube* scrambledCube, const KociembaSolution& solution)

CubeSolution* FindOptimalSolution(Cube* scrambledCube) void SInit() - Inicjalizuje tablice przekształceń i odległości.

Metody prywatne: CubeSolution* GetPhase1Solution(const KociembaSolution& solution)

bool IsFullSolution(CubieCube* scrambledCube, const CubeSolution& solution)

KociembaPhase1Solver - Klasa znajdująca rozwiązanie kostki algorytmem dwufazowym Kociemby. Klasa bazowa: CubeSolver Agregacje prywatne:

KociembaPhase1PruningTable ptCOnEMC - Tabela odległości częściowych stanów złoŜonych ze współrzędnych orientacji i permutacji rogów od rozwiązania

Page 146: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

140

KociembaPhase1PruningTable ptCOnEO - Tabela odległości częściowych stanów złoŜonych ze współrzędnych orientacji i kombinacji pierwszej połowy krawędzi od rozwiązania

KociembaPhase1PruningTable ptEMCnEO - Tabela odległości częściowych stanów złoŜonych ze współrzędnych orientacji i kombinacji drugiej połowy krawędzi od rozwiązania

Pola prywatne: bInitialized: bool = false - Znacznik inicjalizacji tabel.

Metody publiczne: KociembaPhase1Solver() - Konstruktor domyślny. ~KociembaPhase1Solver() - Destruktor. void SInit() - Inicjalizuje tablice przekształceń i odległości. void SClear() CubeSolution* FindSolution(Cube* scrambledCube) - Znajduje rozwiazanie kostki. Zwraca kod sukcesu lub

porazki. Ustawia kod błędu i kod ostrzeŜenia. CubeSolution* FindNextSolution(Cube* scrambledCube, const CubeSolution& solution) -

Metody chronione: int Heuristic(Cube* cube) - Funkcja heurystyczna void Init() - Inicjalizuje tablice przekształceń i odległości.

KociembaPhase2Solver - Klasa znajdująca rozwiązanie kostki algorytmem dwufazowym Kociemby. Klasa bazowa: CubeSolver Agregacje prywatne:

KociembaPhase2PruningTable ptCPnEMP - Tabela odległości częściowych stanów złoŜonych ze współrzędnych orientacji i permutacji rogów od rozwiązania

KociembaPhase2PruningTable ptEMPnENP - Tabela odległości częściowych stanów złoŜonych ze współrzędnych orientacji i kombinacji pierwszej połowy krawędzi od rozwiązania

Pola prywatne: bInitialized: bool = false - Znacznik inicjalizacji tabel.

Metody publiczne: KociembaPhase2Solver() - Konstruktor domyślny. ~KociembaPhase2Solver() - Destruktor. void SInit() - Inicjalizuje tablice przekształceń i odległości. void SClear() CubeSolution* FindSolution(Cube* scrambledCube) - Znajduje rozwiazanie kostki. Zwraca kod sukcesu lub

porazki. Ustawia kod błędu i kod ostrzeŜenia.

Metody chronione: int Heuristic(Cube* cube) - Funkcja heurystyczna void Init() - Inicjalizuje tablice przekształceń i odległości.

KociembaSolution - Klasa opisująca rozwiązanie kostki. Klasa bazowa: CubeSolution Pola prywatne:

iPhase1Length: int - długość rozwiązania znalezionego w pierwszej fazie

Metody publiczne: KociembaSolution() - Konstruktor. Tworzy puste rozwiązanie. KociembaSolution(const KociembaSolution& sol) - Konstruktor kopiujący. KociembaSolution(const CubeSolution& sol1, const CubeSolution& sol2) - Konstruktor. Tworzy rozwiązanie

jako sumę dwóch innych rozwiązań. KociembaSolution& operator=(const KociembaSolution& sol) - Operator przypisania. KociembaSolution* Clone() - Kopiuje stan kostki. Zwraca nowy stan, dla które alokuje pamięć. void FromString(const char* sSol) - Pobiera rozwiązanie z łańcucha znaków reprezentującego je. Rzuca wyjątkiem

w przypadku niepowodzenia. char* ToString() - Zwraca rozwiązanie jako łańcuch nazw ruchów rozdzielonych separatorem. int GetPhase1Length() - Zwraca długość rozwiązania znalezionego w pierwszej fazie.

Metody prywatne: void CheckFormat(const char* sSol)

KociembaMoveTable - Klasa bazowa tablicy przekształceń dla algorytmu Kociemby. Klasa bazowa: CubeMoveTable Agregacje chronione:

KociembaCube pKCube - lokalny obiekt kostki Kociemby uŜywany do przekształceń

Pola chronione:

Page 147: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

141

iCoordNum: int

Metody publiczne: KociembaMoveTable(int coordNum) - Konstruktor. Wywołuje konstruktor klasy bazowej, który alokuje

odpowiednią ilość pamięci na tablicę i ustawia pole pCube na podstawie argumentu Dodatkowo konstruktor przypisuje wskaźnik do kostki Kociemby oraz ustawia, czy tabela dotyczy drugiej fazy algorytmu.

KociembaMoveTable(const KociembaMoveTable& table) - Konstruktor kopiujący. ~KociembaMoveTable() - Destruktor. KociembaMoveTable& operator=(const KociembaMoveTable& table) - Operator przypisania.

Metody chronione: int GetCoord()

void SetCoord(int coord) -

Metody prywatne: int GetCoordSize(int coordNum)

KociembaPhase1MoveTable - Klasa tablicy przekształceń współrzędnych permutacji rogów przez podstawowe obroty grupy G1. Tablica uŜywana w drugiej fazie algorytmu Kociemby.

Klasa bazowa: KociembaMoveTable Metody publiczne:

KociembaPhase1MoveTable(int coordNum) const char* GetName() - Zwraca nazwę pliku, w którym zapisana jest zawartość tabeli. const char* GetDescription() - Zwraca opis danych tabeli.

Metody chronione: void PreGenerate() - Wykonuje operacje przed generowaniem tablicy. void PostGenerate() - Wykonuje operacje po wygenerowaniu tablicy.

KociembaPhase2MoveTable - Klasa tablicy przekształceń współrzędnych permutacji rogów przez podstawowe obroty grupy G1. Tablica uŜywana w drugiej fazie algorytmu Kociemby.

Klasa bazowa: KociembaMoveTable Metody publiczne:

KociembaPhase2MoveTable(int coordNum) const char* GetName() - Zwraca nazwę pliku, w którym zapisana jest zawartość tabeli. const char* GetDescription() - Zwraca opis danych tabeli.

Metody chronione: void PreGenerate() - Wykonuje operacje przed generowaniem tablicy. void PostGenerate() - Wykonuje operacje po wygenerowaniu tablicy. CubeMove::eTurn GetTurn(CubeMove::eMove move) - Zwraca domyślny obrót dla ruchu move.

KociembaPruningTable - Klasa odległości częściowych stanów kostki od rozwiązania. Klasa konstruowana jest na podstawie dwóch tablic przekształceń. Przechowuje odległość od rozwiązania dla kaŜdej kombinacji współrzędnych z obu tabel.

Klasa bazowa: CubePruningTable Agregacje prywatne:

KociembaMoveTable mt1, mt2 – Tabele przekształceń, o które opiera się baza danych wzorców.

Pola chronione: iCoord1Num: int

iCoord2Num: int

iCoord1Size: int

iCoord2Size: int

Metody publiczne: KociembaPruningTable(int coord1Num, int coord2Num) - Konstruktor. Deklaruje bazowe tablice przekształceń i

początkową wartość współrzędnych z nimi związanych. KociembaPruningTable(const KociembaPruningTable& table) - Konstruktor kopiujący. KociembaPruningTable& operator=(const KociembaPruningTable& table) - Konstruktor kopiujący. int Get(int coord1, int coord2) - Udostępnienie wartości z pola o indeksie index.

Metody chronione: int GetCoord(int coordVal, CubeMove::eMove move, CubeMove::eTurn turn) - Ustawia stan lokalnego obiektu

kostki pCube zgodnie ze wspołrzędna coord.

Metody prywatne: void PTCoordToCCoords(int& coordNum, int& coord1Num, int& coord2Num)

void CCoordsToPTCoord(int& coordNum, int& coord1Num, int& coord2Num)

Page 148: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

142

int GetCoordSize(int coordNum)

KociembaPhase1PruningTable - Klasa odległości częściowych stanów kostki od rozwiązania. Klasa konstruowana jest na podstawie dwóch tablic przekształceń. Przechowuje odległość od rozwiązania dla kaŜdej kombinacji współrzędnych z obu tabel.

Klasa bazowa: KociembaPruningTable Metody publiczne:

KociembaPhase1PruningTable(int coord1Num, int coord2Num) const char* GetName() - Zwraca nazwę pliku, w którym zapisana jest zawartość tabeli. const char* GetDescription() - Zwraca opis danych tabeli.

Metody chronione: int GetInitCoord() - Pobiera wspołrzędną z lokalnego obiektu kostki pCube. void PreGenerate() - Wykonuje operacje przed generowaniem tablicy. void PostGenerate() - Wykonuje operacje po wygenerowaniu tablicy.

Metody prywatne: void PTCoordToCCoords(int& coordNum, int& coord1Num, int& coord2Num)

void CCoordsToPTCoord(int& coordNum, int& coord1Num, int& coord2Num)

KociembaPhase2PruningTable - Klasa odległości częściowych stanów kostki od rozwiązania. Klasa konstruowana jest na podstawie dwóch tablic przekształceń. Przechowuje odległość od rozwiązania dla kaŜdej kombinacji współrzędnych z obu tabel.

Klasa bazowa: KociembaPruningTable Metody publiczne:

KociembaPhase2PruningTable(int coord1Num, int coord2Num) const char* GetName() - Zwraca nazwę pliku, w którym zapisana jest zawartość tabeli. const char* GetDescription() - Zwraca opis danych tabeli.

Metody chronione: int GetInitCoord() - Pobiera wspołrzędną z lokalnego obiektu kostki pCube. void PreGenerate() - Wykonuje operacje przed generowaniem tablicy. void PostGenerate() - Wykonuje operacje po wygenerowaniu tablicy. bool IsAllowed(CubeMove::eMove move, CubeMove::eTurn turn) -

Metody prywatne: void PTCoordToCCoords(int& coordNum, int& coord1Num, int& coord2Num)

void CCoordsToPTCoord(int& coordNum, int& coord1Num, int& coord2Num)

KociembaException - Klasa błędu opisu kostki Rubika. Klasa bazowa: Exception Pola publiczne:

TYPE: const char* = "Kociemba" - Stała określająca ciąg znaków reprezentujący typ klasy.

Pola prywatne: ErrorText: char * [] - Wiadomosci błędów.

Metody publiczne: const char* GetType() - Zwraca typ klasy. KociembaException(int error) - Konstruktor. Tworzy obiekt dla określonego błędu. KociembaException(const KociembaException& exp) - Konstruktor kopiujący. ~KociembaException() - Destruktor. Zwalnia zajmowaną pamięć. Exception* Clone() - Kopiuje błąd. Zwraca nowy błąd, dla którego alokuje pamięć.

Metody chronione: const char* GetErrorText()

Klasy zagnieŜdŜone: enum eError - Zwracane kody błędów

KociembaTester - Klasa wyjątków operacji kombinatorycznych. Klasa bazowa: Tester Metody publiczne:

KociembaTester()

~KociembaTester()

bool Test()

Metody prywatne:

Page 149: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

143

bool TestKociemba1Cube()

bool TestKociemba2Cube()

bool TestKociembaSolver()

bool TestKociemba1CubeCreate()

bool TestKociemba1CubeCubie()

bool TestKociemba1CubeMoveTable(KociembaMoveTable* mt)

bool TestKociemba1CubeMove()

bool TestKociemba2CubeCubieException(CubieCube& ccube)

bool TestKociemba2CubeCreate()

bool TestKociemba2CubeCubie()

bool TestKociemba2CubeMoveTable(KociembaMoveTable* mt)

bool TestKociemba2CubeMoveException(CubeMove::eMove move, CubeMove::eTurn turn)

bool TestKociemba2CubeMove()

bool TestKociembaSolverSolvePhase1()

bool TestKociembaSolverSolvePhase1Next(KociembaPhase1Cube& cube, CubeSolution* sol)

bool TestKociembaSolverSolvePhase2Exception(CubieCube& ccube)

bool TestKociembaSolverSolvePhase2()

bool TestKociembaSolverSolve()

bool TestKociembaSolverSolveNext(CubieCube& cube, KociembaSolution* sol)

bool TestKociembaSolverSolveOptimal()

void GetMoves(CubeMove::eMove * moves, CubeMove::eTurn * turns, Cube* ref, int number)

void Move(Cube* cube, CubeMove::eMove * moves, CubeMove::eTurn * turns, int number, bool forward)

void Print(CubeMove::eMove * moves, CubeMove::eTurn * turns, int number)

void Print(const char * desc, Cube* cube)

void Print(const char * desc, CubeSolution* sol)

void Print(const char * desc, KociembaException* exp)

Page 150: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

144

Korf – rozwiązywanie kostki algorytmem Korfa

KorfCube - Klasa opisująca Kostkę Rubika na poziomie współrzędnych. Klasa bazowa: Cube Agregacje prywatne:

KorfMoveTable mtCP

KorfMoveTable mtCO

KorfMoveTable mtE1CP

KorfMoveTable mtE1CO

KorfMoveTable mtE2CP

KorfMoveTable mtE2CO

Pola publiczne:

Page 151: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

145

TYPE: const char* = "KorfCube" - Stała określająca ciąg znaków reprezentujący typ klasy. EDGE_HALF_NUMBER: const int

CORNER_PERMUTATION_NUMBER: const int

CORNER_ORIENTATION_NUMBER: const int

EDGE_HALF_COMBINATION_NUMBER: const int

EDGE_HALF_PERMUTATION_NUMBER: const int

EDGE_HALF_ORIENTATION_NUMBER: const int

CORNER_COORD_NUMBER: const int

EDGE_HALF_COORD_NUMBER: const int

Pola prywatne: cornerCoord: int

edgeFirstHalfCoord: int

edgeSecondHalfCoord: int

bInitialized: bool = false

Metody publiczne: const char* GetType() - Zwraca typ klasy. int CORNER(int perm, int orie)

int EDGE(int comb, int perm, int orie)

int CORNER_PERMUTATION(int corner)

int CORNER_ORIENTATION(int corner)

int EDGE_COMBINATION(int edge)

int EDGE_PERMUTATION(int edge)

int EDGE_ORIENTATION(int edge)

void SInit()

void SClear() KorfCube() - Konstruktor domyślny. Tworzy ułoŜoną kostkę. KorfCube(const KorfCube& cube) - Konstruktor kopiujący. Tworzy nowy stan równy stanowi cube. ~KorfCube() - Destruktor. Cube* Clone() - Kopiuje stan kostki. Zwraca nowy stan, dla które alokuje pamięć. int operator==(const KorfCube& cube) - Operator porównia. Porównuje ze stanem kostki cube. void SetInitState() - Ustawia stan kostki jako ułoŜony. Nie zwraca Ŝadnej wartości. void FromCubieCube(CubieCube& cube) - Pobiera stan kostki z tabeli reprezentującej go. Rzuca wyjątkiem w

przypadku niepowodzenia. void ToCubieCube(CubieCube& cube) - Zapisuje stan kostki do tabeli void FromCoords(int [] coords) - Pobiera stan kostki ze współrzędnych reprezentujących go. Rzuca wyjątkiem w

przypadku niepowodzenia. void ToCoords(int [] coords) - Zapisuje stan kostki do współrzędnych char* ToString() - Zamienia stan kostki na łańcuch znaków reprezentujący go. Zwraca tenŜe łańcuch znaków.

Alokuje pamięć na łańcuch, która trzeba później zwolnić. void Move(CubeMove::eMove move, CubeMove::eTurn turn) - Wykonuje ruch o numerze move na kostce. Nie

zwraca Ŝadnej wartości. int MoveCoord(int coordNum, int coordValue, CubeMove::eMove move)

Metody prywatne: void MoveCoords(CubeMove::eMove move)

KorfMove - Klasa zawierające dane o ruchach na kostce. Pola prywatne:

bInitialized: bool

Metody publiczne: void Init()

void MoveCoords(int [] coords, CubeMove::eMove move)

KorfSolver - Klasa znajdująca rozwiązanie kostki algorytmem Korfa. Klasa bazowa: CubeSolver Agregacje prywatne:

KorfPruningTable ptCorner - Tabela odległości częściowych stanów złoŜonych ze współrzędnych orientacji i permutacji rogów od rozwiązania

KorfPruningTable ptEdgeFirstHalf - Tabela odległości częściowych stanów złoŜonych ze współrzędnych orientacji i kombinacji pierwszej połowy krawędzi od rozwiązania

KorfPruningTable ptEdgeSecondHalf - Tabela odległości częściowych stanów złoŜonych ze współrzędnych orientacji i kombinacji drugiej połowy krawędzi od rozwiązania

Pola prywatne: bInitialized: bool = false - Znacznik inicjalizacji tabel.

Metody publiczne:

Page 152: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

146

KorfSolver() - Konstruktor domyślny. ~KorfSolver() - Destruktor. void SInit() - Inicjalizuje tablice przekształceń i odległości. void SClear()

CubeSolution* FindSolution(Cube* scrambledCube) -

Metody chronione: int Heuristic(Cube* cube) - Funkcja heurystyczna void Init() - Inicjalizuje tablice przekształceń i odległości.

KorfMoveTable - Klasa bazowa tablicy przekształceń dla algorytmu Korfa. Klasa bazowa: CubeMoveTable Agregacje chronione:

KorfCube pKCube - lokalny obiekt kostki Korfa uŜywany do przekształceń

Metody publiczne: KorfMoveTable(int coordSize) - Konstruktor. Wywołuje konstruktor klasy bazowej, który alokuje odpowiednią

ilość pamięci na tablicę i ustawia pole pCube na podstawie argumentu Dodatkowo konstruktor przypisuje wskaźnik do kostki Korfa.

KorfMoveTable(const KorfMoveTable& table) - Konstruktor kopiujący. ~KorfMoveTable() - Destruktor. KorfMoveTable& operator=(const KorfMoveTable& table) - Konstruktor kopiujący.

Metody chronione: void PreGenerate() - Wykonuje operacje przed generowaniem tablicy. void PostGenerate() - Wykonuje operacje po wygenerowaniu tablicy.

KorfMoveTable_CO - Klasa tablicy przekształceń współrzędnych orientacji rogów przez pojedyncze obroty uŜywana w algorytmie Korfa. KorfMoveTable_CP - Klasa tablicy przekształceń współrzędnych permutacji rogów przez pojedyncze obroty uŜywana w algorytmie Korfa. KorfMoveTable_ECO - Klasa tablicy przekształceń współrzędnych orientacji i kombinacji pierwszej połowy krawędzi przez pojedyncze obroty. KorfMoveTable_ECP - Klasa tablicy przekształceń współrzędnych kombinacji połowy krawędzi przez pojedyncze obroty uŜywana w algorytmie Korfa. KorfPruningTable - Klasa odległości częściowych stanów kostki od rozwiązania. Klasa konstruowana jest na podstawie dwóch tablic przekształceń. Przechowuje odległość od rozwiązania dla kaŜdej kombinacji współrzędnych z obu tabel.

Klasa bazowa: CubePruningTable Agregacje prywatne:

KorfMoveTable mt1, mt2 – Tabele przekształceń, o które opiera się baza danych wzorców.

Pola prywatne: iCoordNum: int

Metody publiczne: KorfPruningTable(int coordNum) - Konstruktor. Deklaruje bazowe tablice przekształceń i początkową wartość

współrzędnych z nimi związanych. KorfPruningTable(const KorfPruningTable& table) - Konstruktor kopiujący. KorfPruningTable& operator=(const KorfPruningTable& table) - Operator przypisania. const char* GetName() - Zwraca nazwę pliku, w którym zapisana jest zawartość tabeli. const char* GetDescription() - Zwraca opis danych tabeli.

Metody chronione: int GetInitCoord() - Pobiera wspołrzędną z lokalnego obiektu kostki pCube.

Metody prywatne: int GetCoordSize(int coordNum)

KorfPruningTable_Corner - Klasa odległości częściowych stanów kostki od rozwiązania. Klasa konstruowana jest na podstawie dwóch tablic przekształceń. Przechowuje odległość od rozwiązania dla kaŜdej kombinacji współrzędnych z obu tabel. KorfPruningTable_Edge - Klasa odległości częściowych stanów kostki od rozwiązania. Klasa konstruowana jest na podstawie dwóch tablic przekształceń. Przechowuje odległość od rozwiązania dla kaŜdej kombinacji współrzędnych z obu tabel. KorfException - Klasa błędu opisu kostki Rubika.

Klasa bazowa: Exception

Page 153: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

147

Pola publiczne: TYPE: const char* = "Korf" - Stała określająca ciąg znaków reprezentujący typ klasy.

Pola prywatne: ErrorText: char * [] - Wiadomosci błędów.

Metody publiczne: const char* GetType() - Zwraca typ klasy. KorfException(int error) - Konstruktor. Tworzy obiekt dla określonego błędu. KorfException(const KorfException& exp) - Konstruktor kopiujący. ~KorfException() - Destruktor. Zwalnia zajmowaną pamięć. Exception* Clone() - Kopiuje błąd. Zwraca nowy błąd, dla którego alokuje pamięć.

Metody chronione: const char* GetErrorText()

Klasy zagnieŜdŜone: enum eError - Zwracane kody błędów

KorfTester - Klasa wyjątków operacji kombinatorycznych. Klasa bazowa: Tester Metody publiczne:

KorfTester()

~KorfTester()

bool Test() -

Metody prywatne: bool TestKorfCube()

bool TestKorfSolver()

bool TestKorfCubeCreate()

bool TestKorfCubeCubie()

bool TestKorfCubeMoveTable(KorfMoveTable* mt)

bool TestKorfCubeMove()

bool TestKorfSolverSolve()

void GetMoves(CubeMove::eMove * moves, CubeMove::eTurn * turns, Cube* ref, int number)

void Move(Cube* cube, CubeMove::eMove * moves, CubeMove::eTurn * turns, int number, bool forward)

void Print(CubeMove::eMove * moves, CubeMove::eTurn * turns, int number)

void Print(const char * desc, Cube* cube)

void Print(const char * desc, CubeSolution* sol)

Interfejs – interfejs uŜytkownika

UserInterface

Pola prywatne: ERROR_TEXT: const char * [] - Wiadomości błędów. ALGORITHM_KORF: const int = 1 - Zaimplementowane algorytmy rozwiązywania kostki Rubika. ALGORITHM_KOCIEMBA: const int = 2

ALGORITHM_KOCIEMBA_OPTIMAL: const int = 4 UNIT_COMBINATORIALS: const int = 1 - Testowane komponenty programu. UNIT_CUBE: const int = 2

UNIT_KORF: const int = 4

UNIT_KOCIEMBA: const int = 8

paramProgram: char *

paramMethod: char *

paramAlgorithm: char *

paramCubeState: char *

paramPreviousSolution: char *

paramLog: char *

paramUnit: char *

paramRepetitionNumber: char *

paramMovesNumber: char *

paramError: char *

iMethod: int

iAlgorithm: int

iUnit: int

bLog: bool

iRepetitions: int

iMovesFirst: int

iMovesLast: int

Page 154: PRACA DYPLOMOWA MAGISTERSKA

Dodatek A

148

iMovesStep: int

iError: int

Metody publiczne: UserInterface()

UserInterface(const UserInterface& ui)

UserInterface& operator=(const UserInterface& ui)

~UserInterface()

int Execute(int argc, char * [] argv) -

Metody prywatne: int SolveCube()

int TestUnit()

int TestPerformance()

void WriteUsage()

void WriteError(int error)

int SetParams(int argc, char * [] argv)

int CheckParamsExist()

int CheckParamsCorrect()

void ClearParams()

Page 155: PRACA DYPLOMOWA MAGISTERSKA

Dodatek B

149

Dodatek B – Opis programu FOSP W ramach pracy magisterskiej stworzone zostały dwa programy. Pierwszy z nich tworzony był z załoŜeniem uniwersalności, czyli tak, aby mógł być stosowany do wielu róŜnych problemów. Ponadto ma on wartości edukacyjne, gdyŜ przedstawia działanie róŜnych algorytmów przeszukiwania drzewa. Program ten oparty został o wiedzę zawartą w publikacjach Korfa. Algorytmy w nich przedstawione są bardzo uniwersalne. Pomysł został jednak zarzucony podczas lektury bardziej zaawansowanych, ale przeznaczonych jedynie dla Kostki Rubika, rozwiązań. Dlatego teŜ jego opis stanowi jedynie załącznik do niniejszej pracy. Program FOSP był chronologicznie wcześniej rozwijany. Program nie został w pełni zaimplementowany. Znajduje on rozwiązanie układanki Sliding-Tile Puzzle przy uŜyciu kilku algorytmów przeszukiwania drzewa rozwiązań. Program umoŜliwia wygenerowanie stanu układanki przez zastosowane na ułoŜonym stanie zadanej liczby losowych ruchów oraz umoŜliwia wybór algorytmu rozwiązania. W trakcie rozwiązywania problemu graficznie prezentowane są kolejne rozwijane stany oraz kolejka stanów do rozwinięcia. Ponadto moŜliwe jest krokowe wykonywanie algorytmu.

Wykorzystane narzędzia

Program prezentujący przebieg algorytmu znajdowania rozwiązania puzzli napisany został w języku C++ pod system operacyjny Windows z moŜliwością szybkiej implementacji pod system Linux. Środowiskiem pracy był open-source’owy program Dev-Cpp z kompilatorem MinGW. Do stworzenia kontenerów danych (drzewa i kolejki) wykorzystana została biblioteka STL. Interfejs graficzny stworzony został w bibliotece wxWindows. Logika programu zamodelowana i udokumentowana została w UMLu. Ponadto wykorzystana została idea wzorców projektowych – fabryki, adaptera i obserwatora.

Budowa programu

W celu ułatwienia pracy oraz uniezaleŜnienia klasy zadania od algorytmu rozwiązania oraz umoŜliwienia wizualizacji przebiegu algorytmu problem do rozwiązania podzielony został na kilka odrębnych części.

Solver - wyszukiwanie rozwiązań

Moduł ten dotyczy znajdywania rozwiązań metodą wyszukiwania rozwiązań w drzewie. UmoŜliwia wybór typu algorytmu. Jest on niezaleŜny od klasy problemu i implementacji kontenerów (drzewa i kolejki). Udostępnia klasy algorytmu, problemu i klasy rozwiązującej problem oraz stanu, węzła, drzewa i kolejki. Struktura tego modułu wynika bezpośrednio z opisu algorytmów wyszukiwania rozwiązań w drzewie stanów przedstawionych w rozdziale trzecim. PoniŜej przedstawiona jest krótka charakterystyka klas z modułu: Algorytm – przechowuje wszystkie rodzaje algorytmów oraz zawiera metody określające cechy algorytmu, czyli stwierdzają np. czy algorytm

- jest prosty czy zorientowany, - narzuca dokładanie do kolejki oczekujących do rozwinięcia węzłów na jej początku czy końcu, - narzuca sortowanie elementów w kolejce, - wykorzystuje funkcję szacującą koszt rozwiązania i jeśli tak, to jaką.

Problem – udostępnia operacje na stanach umoŜliwiające znajdywanie rozwiązania w drzewie przez Solver. Wszystkie informacje dotyczące problemu znajdują się w tej klasie. Udostępnia ona w szczególności metody:

- stworzenie stanu, - porównanie dwóch stanów, - znalezienia operacji moŜliwych do wykonania na stanie, - wykonania zadanej operacji na stanie, - oszacowania kosztu rozwiązania w danym stanie.

Ostatnia z tych metod realizowana jest z wykorzystaniem zewnętrznego w stosunku do Problemu źródła danych, który stanowi następna klasa. Dodatkowe informacje o problemie – udostępnia szacunkowy koszt rozwiązania z zadanego stanu Stan – przechowuje informacje o stanie problemu. Węzeł – klasa węzła drzewa. Przechowuje informacje o swoim rodzicu, operacji generującej go, kosztu ścieŜki dotychczasowej oraz przewidywanego kosztu rozwiązania. Węzeł przechowuje równieŜ obiekt stanu problemu. Drzewo –przechowuje rozwinięte węzły w postaci drzewa o korzeniu reprezentującym stan początkowy. UmoŜliwiająca dodanie i usunięcie dzieci swoich węzłów. Kolejka –przechowuje węzły do rozwinięcia w postaci listy. UmoŜliwia dodanie węzła na swoim początku bądź końcu, sortowanie węzłów według zadanego kryterium oraz pobranie pierwszego swojego węzła. Klasa rozwiązująca problem – w oparciu o Problem buduje Drzewo Węzłów zawierających Stany problemu. Strategia budowy drzewa oparta jest na rodzaju algorytmu. Budowa drzewa kończy się wraz ze spełnieniem

Page 156: PRACA DYPLOMOWA MAGISTERSKA

Dodatek B

150

kryteriów zakończenia szukania rozwiązania. Kryterium to moŜe oznaczać znalezienie pierwszego rozwiązania bądź wyczerpanie węzłów moŜliwych do rozwinięcia. Klasy udostępniane w module Solver są w duŜej części klasami abstrakcyjnymi. Klasy pochodne od nich muszą dostarczyć funkcjonalność związaną z problemem do rozwiązania oraz z funkcjonowaniem kontenerów. W ramach modułu Solver zaimplementowane zostały klasy kontenerów (drzewa i kolejki) w oparciu o bibliotekę STL. W celu ich wykorzystania do rozwiązania zadania zaimplementowana została równieŜ klasa Solvera ich uŜywająca. Ponadto oprócz sposobu znajdywania rozwiązania w drzewie Solver umoŜliwia równieŜ stworzenie bazy danych wzorców dla zadanego problemu. Baza danych wzorców tworzona jest w oparciu o ograniczony (uproszczony) problem. Następnie dla takiego problemu wyszukiwane są koszty rozwiązania kaŜdego stanu. Wartości te zapisywane są do tabeli. W celu stworzenia takiej bazy danych konieczne jest rozwinięcie drzewa tak, aby znalazły się w nim wszystkie moŜliwe stany, ale kaŜdy tylko raz. SłuŜy do tego specjalnie zaimplementowana klasa Drzewo zawierająca tylko jeden raz kaŜdy stan. Tworzeniem drzewa zajmuje się klasa Solver działająca w oparciu o algorytm wyszukiwania wszerz oraz warunek stopu czekający na rozwinięcie wszystkich czekających węzłów, czyli opróŜnienie kolejki.

Puzzle – Problem-Układanka

Moduł ten dostarcza klasę problemu-układanki. UmoŜliwia ona znajdywanie rozwiązania przez Solver z poprzedniego modułu. W tym celu zaimplementowane zostały klasy bazowe dla klas puzzli – Puzzle (Problem) i Stan. Dostarczają one interfejs przydatny do przystosowania programu do pracy z róŜnymi rodzajami Puzzli. W ramach niniejszej pracy zaimplementowane zostały klasy stanu i puzzli dla układanki o przesuwnych kafelkach (Sliding-Tile Puzzle). Działanie tych klas wynika z modelu układanki, który został przedstawiony w pierwszym rozdziale. Implementacja klasy Dodatkowe informacje o problemie dostarcza informacji o przewidywanym koszcie rozwiązania układanki znajdującej się w określonym stanie. Szacowanie tego kosztu moŜe się odbywać na podstawie samego stanu (np. liczbie nieuporządkowanych kafelków) bądź na danych wcześniej zgromadzonych. Oprócz powyŜszych klas, bezpośrednio związanych z rozwiązywaniem problemu, w module Puzzle zaimplementowana została klasa tasująca (mieszająca) ułoŜenie układanki. Jest ona niezaleŜna od rodzaju puzzli. Wykorzystuje funkcje zadeklarowane w interfejsie Puzzle.

PuzzleDrawer – Prezentacja obiektów

Moduł ten umoŜliwia wizualizację obiektów uŜywanych do rozwiązywania zadania. Wykorzystany do tego został wzorzec projektowy obserwatora, umoŜliwiający ustawienie obserwatorów do klas obserwowalnych. Obserwatorzy mogą reagować na kaŜdą zmianę obserwowanego obiektu, jeśli ta o tym poinformuje. Obserwowanymi obiektami są w tym przypadku klasy uŜywane przez Solvera. Zostały one przeciąŜone i wzbogacone o wymaganą do prowadzenia obserwacji funkcjonalność. Obiektami obserwującymi są specjalnie przygotowane kontrolki i panele wxWindows, które umoŜliwiają przedstawienie zawartości obserwowanych obiektów. Ich wygląd i funkcjonalność są dokładniej omówione w następnym podrozdziale.

Praca z programem

Przygotowany program jest plikiem wykonywalnym (.EXE) systemu Windows. Przedstawiany poniŜej program jest wersją rozwojową, niestabilną. Niektóre funkcje nie zostały zaimplementowane. RównieŜ wygląd okienek nie został dopracowany.

Page 157: PRACA DYPLOMOWA MAGISTERSKA

Dodatek B

151

Po uruchomieniu programu pojawia się główne okienko programu:

Okienko to składa się z kilku części, które ze sobą współpracują.

Problem do rozwiązania

Obszar okna głównego dotyczący problemu do rozwiązania zaprezentowany jest poniŜej.

W programie moŜliwe jest wybranie rodzaju układanki, której będzie dotyczyło wyszukiwanie rozwiązanie. Odbywa się to przy pomocy pola wyboru „Rodzaj puzzli”. W tym momencie moŜliwy jest wybór jedynie „Sliding-Tile Puzzle”. Po wybraniu rodzaju układanki moŜliwe jest stworzenie problemu do rozwiązania, czyli obiektu określonej klasy i zdefiniowanie w niej stanu początkowego i końcowego. Po stworzeniu układanki moŜliwe są operacje na jej stanie początkowym i końcowym – wyświetlenie ich w okienku stanu (po dwukrotnym kliknięciu lewym klawiszem myszy w wierszu dotyczącym danego stanu), ustawienie go w początkowym stanie (przycisk „Zresetuj”) oraz potasowanie go (nie do końca widoczny przycisk „Potasuj”). Problem do rozwiązania moŜna wyczyścić (przycisk „Wyczyść”) i tym samym zwolnic całą zajmowaną przez niego pamięć.

Baza danych wzorców

Obszar przedstawiony poniŜej jest bezpośrednio związany z problemem do rozwiązania. Do obiektu problemu moŜna dołączyć obiekt informujący o przewidywanym koszcie rozwiązań. Informacje takie wykorzystywane są w algorytmach zorientowanych.

Page 158: PRACA DYPLOMOWA MAGISTERSKA

Dodatek B

152

Program umoŜliwia stworzenie bazy danych wzorców w oparciu o Solver (guzik „Znajdź (pokazując)”). Wybranie tej opcji umoŜliwi śledzenie tworzenia drzewa stanów w okienkach opisanych w dalszej części sprawozdania. Opcja bez śledzenia (guzik „Znajdź (nie pokazując)”) nie została zaimplementowana. Po stworzeniu drzewa moŜliwe jest stworzenie na jego podstawie bazy danych wzorców i zapisanie jej do pliku (guzik „Stwórz PD”). W tej wersji programu baza zapisywana jest do dwóch plików – „PD.pd” – binarnego i „PD.txt” – moŜliwego do prostej analizy. MoŜliwe jest równieŜ odczytanie bazy danych wzorców z pliku (guzik „Załaduj PD z pliku”). Baza danych zostanie odczytana z pliku „PD.pd”. Nie jest sprawdzana poprawność bazy danych ani to, czy jej zawartość przystaje do problemu reprezentowanego przez Puzzle i Fringe. Do wyczyszczenia bazy i zwolnienia zajmowanej przez nią pamięci słuŜy przycisk „Wyczyść”. Przed kaŜdym kolejnym utworzeniem bazy danych wzorców konieczne jest usuniecie poprzedniej jej wersji przetrzymywanej w pamięci. Pole wyboru „Źródło” i pole „Maska stanu” nie mają w tej wersji programu Ŝadnego zastosowania. Docelowo pole „Maska stanu” miało umoŜliwiać wyświetlenie i edycję maski puzzli, czyli stanu granicznego.

Szukanie rozwiązania

Parametry szukania rozwiązania dla problemu wybranego w panelu „Problem do rozwiązania”, ustawiane są przy pomocy poniŜszego panelu:

Pole wyboru „Algorytm” umoŜliwia wybór jednego z 8 algorytmów przeszukiwania drzewa. Proces wyszukiwania rozwiązania uruchamiany jest przyciskiem „Szukaj”. Na początku sprawdzane są warunki początkowe, czyli czy np. został określony problem do rozwiązania. W przypadku niespełnienia któregokolwiek z warunków początkowych wyświetlane jest okienko informujące o tym,

a proces szukania nie zostaje uruchomiony. MoŜliwe jest krokowe wyszukiwanie rozwiązania. W tym celu naleŜy zaznaczyć pole „Krokowo”. Po dodaniu kolejnego węzła do drzewa i zapisaniu jego następców do kolejki algorytm zatrzymuje się i czeka na wciśnięcie guzika „Krok”. Opcję krokowej pracy algorytmu moŜna w kaŜdej chwili włączyć i wyłączyć. Po znalezieniu rozwiązania sekwencja ruchów prowadząca do niego wyświetlana jest w polu „Rozwiązania”. W tej wersji programu moŜliwe jest przeszukiwanie drzewa z warunkiem stopu znalezienia pierwszego rozwiązania. Guzik „Wyczyść” tak jak w poprzednim przypadku zwalnia niszczy obiekty utworzone podczas szukania rozwiązania – stworzone węzły i stany, kontenery zawierające je oraz rozwiązanie. Pola „Drzewo rozwiązań” i „Kolejka stanów” nie mają w tej wersji programu zastosowania.

Drzewo rozwiązań

Zawartość drzewa rozwiązań, tworzonego podczas znajdywania rozwiązania, prezentowana jest w okienku przedstawionym poniŜej. Element „Root” nie prezentuje Ŝadnego elementu z drzewa. Jest jedynie punktem zaczepienia. Elementy drzewa prezentowanie są jako napis „Node %n”. Numery nadane są węzłom w kolejności ich dodawania do drzewa. Dzięki temu łatwo moŜna zaobserwować róŜnice między algorytmami.

Page 159: PRACA DYPLOMOWA MAGISTERSKA

Dodatek B

153

Poddrzewa drzewa rozwija się i zwija przy pomocy pojedynczego kliknięcia na elemencie stanowiącym ich korzeń. Po kliknięciu prawym klawiszem myszki dwukrotnie w obrębie elementu drzewa, jego zawartość czyli węzeł i odpowiadający mu stan zostaną zaprezentowane w odpowiednich okienkach opisanych w dalszej części sprawozdania. Po takim samym kliknięciu poza obrębem drzewa bądź w obrębie elementu „Root” wyświetlone zostanie okienko:

Okienko to prezentuje informację dotyczącą liczby dodanych do drzewa węzłów. Wiadomość ta jest przydatna w celu obliczenia skuteczności algorytmu bądź sprawdzenia czy wszystkie stany podczas tworzenia bazy danych wzorców zostały znalezione.

Kolejka węzłów

Zawartość kolejki węzłów prezentujących dane do rozwinięcia prezentowana jest w postaci listy. Elementami listy są napisy „Node %n”. Tak jak w przypadku drzewa, numery węzłów informują o kolejności dodania

węzłów do kolejki. Numery te nie pokrywają się z numerami węzłów w drzewie. Ponadto w tej wersji programu, węzły są usuwane z kolejki i ponownie do niej dodawane w wyniku posortowania węzłów w kolejce, której zawartość prezentują. Wynikają stąd niespójności. Tak jak w przypadku drzewa, zawartość węzła i stan prezentowane są w odpowiednich kontrolkach po dwukrotnym kliknięciu prawym przyciskiem myszy w obrębie elementu kolejki. Kliknięcie poza tym obrębem powoduje wyświetlenia okienka informującego o liczbie dodanych i usuniętych z kolejki węzłów:

W przypadku algorytmu sortującego zawartość kolejki liczby te są zaburzone.

Węzeł

Pola obiektu klasy Węzła prezentowane są w poniŜszych polach:

Po dwukrotnym kliknięciu w obrębie pola „Stan” bądź „Rodzic”, odpowiedni obiekt prezentowany jest w przeznaczonym do tego obszarze okna programu.

Stan

Stan układanki prezentowany jest w poniŜszej postaci:

Page 160: PRACA DYPLOMOWA MAGISTERSKA

Dodatek B

154

Baza danych wzorców

Baza danych wzorców tworzona jest w oparciu o drzewo rozwiązań. Po stworzeniu drzewa, w którym kaŜdy stan ograniczonego problemu reprezentowany jest dokładnie raz, tworzona i wypełniana jest tabela – baza danych wzorców. Tabela ta jest jednowymiarowa. Jej indeksami są spakowane ograniczone stany. Pakowanie tych stanów odpowiada w przypadku układanki „Sliding-Tile Puzzle” pakowaniu wariacji. Polega ono na wyliczeniu względnej pozycji i przemnoŜeniu jej przez odpowiedni współczynnik kaŜdego rozpatrywanego kafelka i dodaniu tych liczb do siebie. I tak:

- pierwszy kafelek – jego pozycja liczona jest jako kolejna od początku, a następnie mnoŜona jest przez liczbę wariacji pozostałych elementów

- następny kafelek – wartość mu odpowiadająca liczona jest dla zbioru zawierającego wszystkie kafelki oprócz pierwszego, juŜ rozpatrzonego.

Przy uŜyciu programu FOSP stworzone zostały trzy bazy danych wzorców (zapisane w postaci plików binarnych oraz tekstowych).

1. Problem ograniczony rozróŜniający jedynie kafelki 7,8 i pusty. Problem ten posiada

504987)!(

!=⋅⋅=

−=

=

kn

n

k

nV k

n stany. Dla tego problemu stan docelowy po spakowaniu

równy jest 48. W bazie danych wzorców w polu 48 znajduje się liczba 0, oznaczająca, Ŝe stan ten prezentuje rozwiązanie.

2. Problem ograniczony rozróŜniający jedynie kafelki 2,5,8 i pusty. Problem ten posiada 3024 stany, a stan docelowy prezentowany jest jako 65.

3. Problem ograniczony rozróŜniający jedynie kafelki 2,5,6,7,8 i pusty. Problem ten posiada 60480 stanów, a stan docelowy prezentowany jest jako 1275.

Krótka dokumentacja programu FOSP

Puzzle – definicje puzzli

Klasy opisujące puzzle i umoŜliwiają wykonanie na nich operacji

- pzAPuzzle (pzPuzzle) - Klasa układanki (fabryki stanów). Udostępnia operacje na stanach układanki. Zachowuje ograniczenia wynikające z budowy układanki Abstrakcyjna klasa bazowa (adapter) dla klas konkretnych układanek.

- pzRCPuzzle (pzRubikCube) - Klasa przechowyjąca ułoŜenie układanki o przesuwnych klockach - pzSTPPuzzle (pzSlidingPuzzle) - Klasa przechowyjąca ułoŜenie układanki o przesuwnych klockach - pzPuzzleScrambler - Klasa mieszająca ułoŜenie układanki

Dodatkowo do opisu budowy kostki Rubika zaimplementowane zostały następujące klasy:

- Face - ściany kostki (U..B) - eColor - kolory ścian kostki - eCubieFace - ściany kosteczek (U1..B9) - Twist - wszystkie moŜliwe obroty (jednej zewnętrznej ściany) na kostce (Ux1..Bx3)

Page 161: PRACA DYPLOMOWA MAGISTERSKA

Dodatek B

155

- eSymmetry - symetrie kostki (S_URF3, S_F2, S_U4, S_LR2) - eCorner - rogi kostki z rozróŜnieniem rotacji (URF..DRB) - Corner - róg kostki - CornerCubies - CornerCubie = array [URF..DRB] of OrientedCorner - CubieFacelet - Facelet = array [U1..B9] of Face - eEdge - krawędzie kostki z rozróŜnieniem rotacji (UR..BR) - Edge - krawędź kostki - EdgeCubies - EdgeCubie = array [UR..BR] of OrientedEdge

Klasy stanu pełnego i częściowego puzzli

- pzAState (psState) - Klasa stanu układanki - abstrakcyjna klasa bazowa (adapter) dla klas stanów konkretnych układanek

- pzRCState (psRubikCube) - Klasa stanu układanki "Rubic Cube". Dziedziczy po klasie abstrakcyjnej pzAState.

- pzSTPState (psStateSlidingPuzzle) - Klasa stanu układanki "Sliding-Tile Puzzle" o dowolnej wielkości. Dziedziczy po klasie abstrakcyjnej pzAState.

- pzFringeSTPPuzzle (psFringe) - Klasa ograniczonej układanki - pzAPuzzleInfo (pzData) - Klasa informatora o układance. Udostępnia operacje na stanach układanki

określające minimalny koszt rozwiązania prowadzącego z nich Abstrakcyjna klasa bazowa (adapter) dla klas konkretnych układanek.

Dodatkowo do opisu stanu kostki Rubika zaimplementowane zostały następujące klasy:

- mtPermutation – Klasa permutacji. UŜywana do obliczeń stanu kostki Rubika. - mtVariation – Klasa wariacji. UŜywana do obliczeń stanu kostki Rubika.

Page 162: PRACA DYPLOMOWA MAGISTERSKA

Dodatek B

156

Solver – znajdywanie rozwiązania ogólnego problemu

Klasy zaangaŜowane w rozwiązywanie problemu

Klasy znajdujące rozwiązanie problemu

- slAlgorithm - Klasa typów algorytmów znajdywania rozwiązania w oparciu o drzewo rozwiązań - slAProblem - Abstrakcyjna klasa bazowa (adapter) problemu do rozwiązania - slASolver - Abstrakcyjna klasa bazowa (adapter) szukająca rozwiązania w drzewie stanów - slSTLSolver - Klasa szukania rozwiązania wykorzystująca kontenery zrealizowane w oparciu o

bibliotekę STL. Klasa jest pochodną klasy slASolver oraz klas pomocniczych slSTLTreeFriend i slSTLQueueFriend w celu dostępu do prywatnych metod kontenerów.

- slSTLUniqueItemSolver - Klasa szukania rozwiązania wykorzystująca kontenery zrealizowane w oparciu o bibliotekę STL. Klasa jest pochodną klasy slASolver oraz klas pomocniczych slSTLTreeFriend i slSTLQueueFriend w celu dostępu do prywatnych metod kontenerów.

- slAQueue - Abstrakcyjna klasa bazowa (adapter) kolejki węzłów do rozwinięcia podczas szukania rozwiązania

- slSTLQueue - Klasa kolejki węzłów do rozwinięcia podczas szukania rozwiązania. Klasa zaimplementowana w oparciu o bibliotekę STL, pochodna klasy slAQueue.

Page 163: PRACA DYPLOMOWA MAGISTERSKA

Dodatek B

157

Klasy drzewa rozwiązań

- slATree - Abstrakcyja klasa bazowa (adapter) drzewa rozwiązań - slSTLTree - Klasa drzewa rozwiązań, pochodna klasy slATree zrealizowana w oparciu o bibliotekę

STL, realizacja wzorca stTree - slSTLUniqueItemHashTree - Klasa drzewa rozwiązań, pochodna klasy slATree zrealizowana w

oparciu o bibliotekę STL, realizacja wzorca stTree

Klasy węzła w drzewie rozwiązań

- slNode - Klasa węzła drzewa rozwiązań. - slAState - Klasa stanu związanego z liściem drzewa rozwiązań

Dodatkowo zdefiniowane zostały klasy operacji na strukturach danych oraz klasy zbiorów węzełów i operacji:

- slNodeOper - Klasa otaczająca operację na zawartości węzła, dziedziczy po stOper, w celu moŜliwości wywołania w metodzie ExecOnItems drzewa

- slQueueNodeOper - Abstrakcyjna klasa bazowa udostępniająca operację () na parametrze

Page 164: PRACA DYPLOMOWA MAGISTERSKA

Dodatek B

158

- slDeleteNodeOper - Klasa otaczająca operację usuwania zawartości węzła, dziedziczy po stOper, w celu moŜliwości wywołania w metodzie ExecOnItems drzewa

- slNodes - Klasa zbioru węzłów drzewa rozwiązań - slOpers - Klasa zbioru operacji moŜliwych do wykonania na stanie

Utils –podstawy obserwacji pracy

- utIntTable - Interfejs klasy obserwatora - utIObservable - Interfejs klasy obserwowanego obiektu - utIObserver - Interfejs klasy obserwatora - utObservable - Klasa bazowa obserwowanego obiektu, realizuje interfejs utIObservable - utOper - wzorzec klasy udostępniającej operację () na parametrze - utTHashTree - wzorzec klasy drzewa zawierającego liście klasy stTreeItem, o szybkim do nich

dostepnie z wykorzystaniem funckji haszującej - utTTree - wzorzec klasy drzewa zawierającego liście klasy utTTreeItem

PuzzleSolver – znajdywanie rozwiązania puzzli

- pdNode - Klasa prezentowanego węzła - pdNodeClass - Klasa stanu układanki uŜywana do prezentacji przebiegu rozwiązywania danych

Obiekty tej klasy zaraz po utworzeniu prezentowane są przez obserwatora. Dziedziczy po klasie utObservable

- pdStateClass - Klasa stanu układanki uŜywana do prezentacji przebiegu rozwiązywania danych Obiekty tej klasy zaraz po utworzeniu prezentowane są przez obserwatora. Dziedziczy po klasie utObservable

- pdSolver - Klasa wyszukująca rozwiązanie w drzewie. UmoŜliwia ona wykorzystanie obserwowalnych kontenerów Dziedziczy po slSTLSolver i utObservable

- pdUniqueItemSolver - Klasa wyszukująca rozwiązanie w drzewie. UmoŜliwia ona wykorzystanie obserwowalnych kontenerów Dziedziczy po slSTLSolver i utObservable

- pdSolverThread - Klasa wątku znajdywania rozwiązania umoŜliwiająca niezaleŜne od obliczeń przeglądanie danych. Dziedziczy po klasie wxThread

- pdStepSolverThread - Klasa wątku znajdywania rozwiązania umoŜliwiająca zatrzymywanie go po wykonaniu kaŜdej pętli. Dziedziczy po klasie wxThread

- pdQueue - Klasa kolejki węzłów do rozwinięcia w celu znalezienia rozwiązania Po kaŜdej zmianie zawartości kolejnki informowane są obserwatory, które moga wyświetlić jej zawartość Dziedziczy po slSTLQueue i utObservable oraz pdMovedNodesRegister

- pdTree - Klasa drzewa węzłów rozwiniętych w celu znalezienia rozwiązania Po kaŜdej zmianie zawartości drzewa informowane są obserwatory, które moga wyświetlić jej zawartość Dziedziczy po slSTLTree i utObservable oraz MovedNodesRegister

- pdUniqueItemHashTree - Klasa drzewa węzłów rozwiniętych w celu znalezienia rozwiązania Po kaŜdej zmianie zawartości drzewa informowane są obserwatory, które moga wyświetlić jej zawartość Dziedziczy po slSTLTree i utObservable oraz MovedNodesRegister

Page 165: PRACA DYPLOMOWA MAGISTERSKA

Dodatek B

159

Drawer – prezentacja pracy

- pdFrame - Klasa głównego okienka do prezentacji danych o puzzlach i przebiegu rozwiązania zadania. W okienku tym umieszczane są okienka słuŜące do wyświetlania konkretnych elementów. Klasa dziedziczy po wxFrame.

- pdNodeTreeItem - Klasa elementu kontrolki drzewa prezentującej drzewo rozwiązań - pdObserverListCtrl - Klasa kontrolki listy prezentującej kolejkę węzłów do rozwinięcia w celu

wyszukania rozwiązania. Dziedziczy po wxListCtrl - pdObserverNodePanel - Klasa panela, na którym wyświetlany jest węzeł drzewa. Klasa dziedziczy po

wxPanel i utIObserver - pdObserverProblemPanel - Klasa panela, na którym wyświetlane są parametry problemu do

rozwiązania Klasa dziedziczy po wxPanel - pdObserverSolverPanel - Klasa panela, na którym wyświetlany jest węzeł drzewa. Klasa dziedziczy

po wxPanel i utIObserver - pdObserverStatePanel - Klasa panela, na którym wyświetlane jest ustawienie puzzli. Klasa dziedziczy

po wxPanel i utIObserver - pdObserverTreeCtrl - Klasa kontrolki drzewa prezentującego drzewo rozwiązań wykorzystywane do

wyszukiwania rozwiązania. Dziedziczy po wxTreeControl

Page 166: PRACA DYPLOMOWA MAGISTERSKA
Page 167: PRACA DYPLOMOWA MAGISTERSKA

Dodatek C

161

Dodatek C – Krótki opis UML Dokumentacje programów zawarte w niniejszej pracy opisane są przy pomocy diagramów UML. UML (ang. United Modeling Language) jest to Zunifikowany Język Modelowania [[21]]. UŜywany jest on do graficznej prezentacji wyników obiektowej analizy i projektu oprogramowania. Nie dotyczy jednak samego procesu modelowania. UML definiuje kilka róŜnych diagramów. SłuŜą one do opisu róŜnych własności projektowanego systemu. ZłoŜone są równieŜ z róŜnych komponentów, czyli obiektów graficznych. Przykładowo:

- diagram przypadków uŜycia opisuje scenariusze uŜycia systemu z podziałem na cel działań. UŜywa w tym celu aktorów i przypadków uŜycia oraz róŜnych powiązań między przypadkami uŜycia np. relacji uogólnienia, rozszerzenia i zawierania się.

- diagram klas opisuje typy obiektów w systemie i relacje między nimi. UŜywa on w tym celu obiekty (klasy, interfejsy, etc), asocjacji oraz zaleŜności.

- diagramy interakcji (sekwencji i współdziałania) opisują formy współpracy grup obiektów zwykle w ramach jednego przypadku uŜycia. Obejmują one obiekty i komunikaty wymienianie między nimi.

- diagram stanów opisuje zachowanie systemu. Zawiera wszystkie moŜliwe stany obiektu i zdarzenia wpływające na jego zmiany.

- diagram aktywności opisują uszeregowanie czynności. Przedstawiają one czynności oraz sekwencję ich wykonania zawierające proste następstwo, wykonywanie równolegle oraz warunkowe.

Dokumentacja zawarta w niniejszej pracy jest bardzo uproszczona i zawiera jedynie diagramy klas. PoniŜej znajduję się dokładny opis symboli graficznych uŜywanych w dokumentacji.

Klasa: - nazwa klasy ze stereotypem - atrybuty klasy w postaci: atrybut:typ = wartość początkowa - metody klasy w postaci: <<stereotyp>> operacja(lista argumentów):typ wyniku

Relacje: - asocjacja - uogólnienie - zawieranie

Zasięg widoczności: - prywatny (-) - chroniony (#) - publiczny

Page 168: PRACA DYPLOMOWA MAGISTERSKA
Page 169: PRACA DYPLOMOWA MAGISTERSKA

Dodatek D

163

Dodatek D – Diagramy znajdywania rozwiązania Na kilku następnych stronach znajduja się diagramy reprezentujące znajdywanie rozwiązania algorytmem Korfa i Kociemby. Stanowią one ilustrację do rozdziałów 5.1.4 i 5.1.5.

Page 170: PRACA DYPLOMOWA MAGISTERSKA
Page 171: PRACA DYPLOMOWA MAGISTERSKA

Dodatek E

165

Dodatek E – Płyta CD Załącznikiem do niniejszej pracy jest płyta CD. Zawiera ona materiały i rezultaty pracy, m.in.:

- niniejszą pracę magisterską - kod źródłowy systemu MRROC++ po zintegrowaniu programu CubeSolver - kod źródłowy programu CubeSolver - kod źródłowy programu FOSP - publikacje, w oparciu o które była pisana niniejsza praca - materiały wykorzystane w niniejszej pracy – obrazki, tablice i modele.

Page 172: PRACA DYPLOMOWA MAGISTERSKA
Page 173: PRACA DYPLOMOWA MAGISTERSKA

Bibliografia

167

Bibliografia [1] http://www.kociemba.homepage.t-online.de/cube.htm - strona Herberta Kociemby

dotycząca kostki Rubika i programu do układania jej „CubeSolver” [2] http://www.geocities.com/jaapsch/puzzles/ - strona prowadzona przez Jaapa

Scherphuisa dotycząca puzzli, ich matematycznych podstaw oraz algorytmów układania ich.

[3] http://www.randelshofer.ch/rubik/virtualcubes/index.html - strona Wernera i Waltera Randelshofer zawierająca między innymi aplikację „Virtual Cube” umoŜliwiającą oglądanie struktury kostki.

[4] http://cube.misto.cz/ - strona Jozefa Jelinka i Hany Bizek zawierająca dokładny opis metody ręcznego układania kostki Rubika.

[5] Stuart J. Russell, Peter Norvig : „Artificial Intelligence: a modern approach”, Upper Saddle River: Prentice-Hall, 1995, s.92-115

[6] Richard E. Korf: „Sliding-Tile Puzzles and Rubik’s Cube in AI Research”, Computer Science Department, University of California, Los Angeles, raport, sierpień 2000

[7] Richard E. Korf: „Finding Optimal Solutions to Rubik’s Cube Using Pattern Databases”, American Association for Artificial Intelligence, Fourteenth National Conference on Artificial Intelligence (AAAI-97), sprawozdanie, 1997

[8] Richard E. Korf: „Recent Progress In the Design and Analysis of Admissible Heuristic Functions”, American Association for Artificial Intelligence, Seventeenth National Conference on Artificial Intelligence, sprawozdanie 2000

[9] Joseph C. Culberson, Jonathan Schaeffer: „Searching with Pattern Databases”, Canadian Conference on AI, sprawozdanie, 1996

[10] Keith H. Randall: „Solving Rubik’s Cube”, MIT Student Workshop, 1998 [11] T.Trajdos: Matematyka część III, Wydawnictwo naukowo-techniczne, W-wa 1971,

1999 [12] Kenneth A. Ross, Charles R.B. Wright: Matematyka Dyskretna, Wydawnictwo

Naukowe PWN, Warszawa 1996 [13] Wykład z przedmiotu SPRR [14] http://www.citeseer.ist.psu.edu – strona wyszukiwania publikacji naukowych [15] http://gauss.math.ucf.edu/~reid/Rubik/ - strona domowa Michaela Reida dotycząca

kostki Rubika [16] http://wikipedia.org – wolna encyklopedia internetowa [17] A. Cewe, H. Nahorska, I. Pancer: Tablice Matematyczne, Wydawnictwo Podkowa ,

Gdańsk 1998 [18] http://www.math.rwth-aachen.de/~Martin.Schoenert/Cube-

Lovers/Dik_T._Winter__Kociemba's_algorithm_(3).html – minimalne rozwiązanie dla stanu Superflip

[19] http://www.math.rwth-aachen.de/~Martin.Schoenert/Cube-Lovers/michael_reid__superflip_requires_20_face_turns.html - dowód na minimalność rozwiązania stanu Superflip

[20] http://www.math.rwth-aachen.de/~Martin.Schoenert/Cube-Lovers - forum dotyczące kostki Rubika, na którym umieszczane są wyniki badań nad złoŜonością kostką i publikowane kolejne algorytmy jej rozwiązywania i ulepszenia juŜ istniejących

[21] Martin Fowler, Kendall Scott: UML w kropelce, Oficyna Wydawnicza LTP, Warszawa 2002