Feladványkészítés
Az első Sudoku
feladványkészítő programomba 2011 tavaszán kezdtem bele. Akkor még nem tudtam,
hogy ez mennyire bonyolult, nehezen megoldható problémát jelent számomra.
Közben erősen lekötötte programozási időmet a TFOR órarendkészítő program is, melyet 2012 novemberére sikerült befejeznem
– vagyis sokkal könnyebb volt, mint a Sudoku
feladványkészítés. Ettől kezdve intenzívebben foglalkozhattam a Sudokuval. Az első, magasabb elemszámú (21-39) feladványok már
aránylag hamar létrejöttek. De az első 20 elemű feladványt csak 2013 december elején, az első 19-est 2013 december végén,
míg az első 17-est 2014 áprilisában sikerült létrehoznom. Ettől kezdve szinte
mindig az motivált, hogy minél több, minél kisebb
elemszámú (természetesen 17-nél nem kisebb) feladványt generáljak, mert ez
jelentette számomra az igazi kihívást. Ez látszik a jelenlegi
feladványkészletemen is, amely 4,5 millió feladványt
tartalmaz és ebből 1 millió 18-as, 500 ezer pedig 17-es elemszámú – körülbelül.
A gépi feladványkészítésnek két alapvetően különböző
módszerét különböztetném meg. Az első esetben az alaptáblából (egy helyesen
kitöltött teljes táblából) indul a keresés. Mindig egy újabb elemet törlünk a
táblából, megnézzük hogy helyes feladványt kaptunk-e, ha igen akkor újra
törlünk és vizsgálunk, ha nem helyes, akkor visszatérünk az előző, még jó
feladványhoz, mint eredményhez. A helyes (vagy jó) feladvány itt azt jelenti,
hogy a használt metódusokkal megoldható-e. A második esetben egy üres
feladványtáblából indulunk. Ahány elemű feladványt szeretnénk készíteni, annyi
elemet véletlenül elhelyezünk a táblán, majd addig hajtunk végre
változtatásokat az elemeken, ameddig helyes feladványt nem kapunk. Az első
készítési típust direkt a másodikat indirekt feladványkészítő módszernek
nevezem.
Most nézzük meg egy kicsit jobban a direkt módszert. A
generálás közben hamar kiderült, hogy a legtöbb ilyen módszerrel előállítható
feladvány 24-25 elemszámú. Ha ennél kisebb elemszámút szeretnénk csak
előállítani, akkor ezt korlátozni kell. Ennek az lett
az eredménye, hogy a szükségesnél nagyobb elemszámúakat a program eldobta, nem
rögzítette. Látszólag a generálási idő megnőtt. Lássuk, hogy néz ez ki a
programomban (a látvány szerintem egyértelmű, részletesen nem elemezném a
képernyőt):
A generálást a program 7486 darab feladványnál kezdte,
így 1220 másodperc alatt 1214 darab feladványt állított elő (gyakorlatilag)
másodpercenként 1-et. Látható továbbá, hogy ezzel a módszerrel 20 vagy ez
alatti elemszám esetén nagyon megnő a generálási idő. Körülbelül 2,4 órát kellene várni arra, hogy 20-as feladvány
létrejöjjön. Az előállított feladványok között – a számos alkalmazott
algoritmus miatt – magasabb nehézségi fokút is találhatunk. Nézzük mi a
helyzet, ha csökkentjük a metódusok számát. Használjunk például csak HS-t:
Most az 1000 db elkészítéséhez 128 másodpercre volt
szükség, ami 7,8-szeres sebességet jelent az előzőhöz
képest. Próbálkozzunk meg csak BS
használatával. Ezt kaptuk:
Ekkor a következők figyelhetők meg: a generálási idő
növekedett, azaz a HS nagyon hasznos
a generálás szempontjából még akkor is, ha több lépést kell végrehajtani egy
ciklusban, de a hatékonysága mindezt kompenzálja. A másik, amit észrevehetünk
az, hogy az a generált feladványok elemszáma a nagyobb értékek felé eltolódott
(például létrejött egy 30-as elemszámú is).
Térjünk át az indirekt módszerre. Állítsuk be úgy a
kezdeti feltételeket, hogy a program 18-21 elemű feladványokat keressen
(korábban már használtam 40-es elemszámúra, 583 db-ot állítottam vele elő). Most
is megfigyelhető, hogy a megengedett lehetőségek közül a nagyobb elemszámúakat
gyakrabban tudja előállítani.
A képernyőről leolvasható, hogy a mostani futtatás
alatt egy feladvány átlagosan 34193 ciklus alatt jött létre, 21 generálási
próbálkozásból 16 eredményes volt, közben 8-szor kellett teljesen újra kezdeni
a generálást (51 feladvány már korábban készült). A teljes 72 előállított
feladványból 7db 18-as, 14 db 19-es, 28 db 20-as és 23 db 21-es. A generálási
idő viszont még mindig elég nagy (21 db/112 sec). Ilyen tempóban milliós
nagyságrendű feladványt előállítani képtelenség. Tehát még van mit javítani az
algoritmuson, újabb ötletek szükségesek.
A direkt és indirekt módszert összehasonlítva úgy
tűnik, hogy a direkt gyorsabb, viszont az indirekt módszerrel lehet egyáltalán
alacsony elemszámú feladványokat generálni. Mindkét módszer még önmagában
javítható. Az eljárások viselkedéséért az algoritmusok magjában található
ütközésmentesítő eljárás a felelős. Mint genetikus algoritmus az aktuális egyed,
magában hordozza azt a tulajdonságát – mely számunkra eléggé rejtve marad –
amivel a megoldás felé sodródik az egyed. Ezt az átalakulást – úgy látszik – az
ismert alaphoz való ragaszkodás gátolja. Igaz, hogy a direkt módszernél az
egyed minden állapotban egy helyesen kitöltött tábla része, csak a kiválasztási
lehetőség is olyan nagy, hogy ebből a jó út nehezen található. Amikor ez a
kötöttség nincs, akkor a köztes egyedek nem feltétlen egy helyes tábla részei.
Viszont nemcsak a jó, hanem a rossz egyedekből is tud részmegoldásokat
meríteni, (a hibákból is tanul) és így a kisebb elemszámú feladványoknál is
eredményes (eredményesebb) tud lenni.