/* This program is distributed under GNU General Public License. We hope that the study of the source code may be usefull for somebody. Authors: Petr Olsak + Mirek Olsak. See also: www.olsak.net. October 2003. Compile me by: cc -O2 -o grid grid.c Sorry, the comments are only in Czech language. For user documentation (in English) see the gridoce.tex or gridoce.pdf file. */ /* [uvod] Program resi lustovky typu griddlers, resp. nonograms, viz napr. www.griddlers.net. Uzivatelska dokumentace je v souboru gridoc.tex nebo gridoc.pdf. Predpokladame, ze bezduche pouzivani tohoto programu nebude pro mnoho lidi prilis zabavne. Zabavnejsi je reseni tech lustovek manualne. Za daleko nejzabavnejsi ale povazujeme studium a vymysleni algoritmu, kterymi se lustovky daji resit a implementovat do pocitace. Proto je v tomto zdrojovem kodu dukladny komentar ke vsem pouzitym algoritmum. Algoritmy by mely byt pokud mozno inteligentni, protoze vyuziti brutalni sily (rychlosti pocitace) je mnohdy nemozne nebo velmi neuzitecne. Kdo vymysli algoritmus jeste ucelnejsi, nez ten, ktery je zde implementovan, necht da autorum vedet. Dekujeme. */ #define VERSION "1.2" /* [limity] MAXBLOKU je maximalni pocet bloku v jednom radku resp. sloupci, MAXBAREV je maximalni pocet barev. MAXRADKU je maximalni pocet radku lustovky, MAXSLOUPCU je maximalni pocet sloupcu. MAXBUF je maximalni delka jmena souboru, ktery je nacitan. LIMITPOKUSU je maximalni pocet uspesnych pokusu, jehoz prekroceni vede k bezprostrednimu ukonceni tzv. intenzivniho algoritmu, viz [dusleny]. MAXDELKASLOVA je nejvetsi delka slova pro deklaraci barvy v XPM formatu, viz [savexpm]. Pri nacitani ulohy ze souboru je kontrolovano, zda neni prekrocen nektery limit. Pokud ano, program skonci s chybovou zpravou a vypise jmeno limitu. Uzivatel pak muze zmenit hodnotu tohoto limitu a program prekompilovat znovu. */ #define MAXBLOKU 30 #define MAXBAREV 10 #define MAXRADKU 200 #define MAXSLOUPCU MAXRADKU #define MAXBUF 100 #define LIMITPOKUSU 10000000 #define MAXDELKASLOVA 30 /* [prototypy] Uvedeme prototypy vsech pouzitych funkci, abychom mohli dale psat funkce v poradi, jak to vyhovuje cloveku a nikoli v poradi, jak to vyzaduje prekladac. */ #include #include #include int cisloradku (int r); void cmdparser (int argc, char**argv); void dalsikrok (); void error (char *s); void formaterror (char *s); char genbarva (int kmax); void* getmemory (long int i, char *name); void gridprintpole (int b); int iicd (int k); int iief (int k); void inipole (); void intensive (int b); int jakabarva (int i, int j); int kontrolaradku (); void logradekA (int printlr); void logradekB (); int main (int argc, char**argv); int nactibarvu (int jak); int nacticislo (); void nactipart (FILE *f); void nactiproblem (); int nactiradek (); int najdiprvni (int i, int j); int nastavpravolevy (); FILE* openfile (char *name, char *mode); int posunblok (int j, int i); void pprint (FILE *f, int i, int j, int k); char primoradek (int i, int b); void printbloky (int * p, char *s); void printpole (int podrobne); void printstatistic (); char rpole (int i, int b); char rpolei (int i, int b); void rprint (FILE*f, int k, char c); void savexpm (); void skipblanks (); void skipline (); void spole (int i, int b, char c); int sumabarev (int b); void testkonzistence (int i, int y, int z); int tridmaxll (); void tridprintpole (int b); void tridsavexpm (FILE *f); void tridulozprvek (int k, int b, char c); int tri (int k); int trj (int k); void trset (int r); void ulozbarvu (int i, int b); void ulozdopasku (int i, int ba); void ulozpravolevy (); void ulozprvek (int i, int b, char c); void usage (); void vemzpasku (); void vsechnareseni (); int vyres (); int vyresradek (); void wlog (int level, char *s, long int value); void zakazbarvu (int i, int b); #define MAX(A,B) (((A)>(B))?(A):(B)) /* [defaults] Nasleduji implicitni hodnoty promennych, ktere se daji zmenit pomoci parametru prikazoveho radku: */ int llevel = 2 ; /* -log */ int outlevel = 2 ; /* -out */ long int steps = 0 ; /* -stop */ long int paused = 0 ; /* -p */ int xpmnum = 1 ; /* -xpm */ int totalnum = 30 ; /* -total */ int limitbloku = 7 ; /* -bl */ int jeni = 0 ; /* -i */ FILE * outf ; /* -of */ FILE * logf ; /* -lf */ /* [sumarium] Deklarujeme globalni promenne, ktere pocitaji pocet pruchodu, pocet reseni radku/sloupcu atd. pro potreby sumarni informace tistene po vyreseni lustovky. */ unsigned long int sumkr = 0 ; /* pocet kroku typu r */ unsigned long int sumkc = 0 ; /* pocet kroku typu c */ unsigned long int sumke = 0 ; /* pocet kroku typu e */ unsigned long int sumkR = 0 ; /* pocet kroku typu R */ unsigned long int sumkC = 0 ; /* pocet kroku typu C */ unsigned long int sumkE = 0 ; /* pocet kroku typu E */ unsigned long int sumkt = 0 ; /* pocet kroku typu t */ unsigned long int sumrr = 0 ; /* pocet reseni radku rychlym algoritmem */ unsigned long int sumur = 0 ; /* pocet uspechu rychlym algoritmem */ unsigned long int sumri = 0 ; /* pocet reseni radku intenzivnim algoritmem */ unsigned long int sumui = 0 ; /* pocet uspechu intenzivnim algoritmem */ unsigned long int sumr = 0 ; /* pocet nalezenych reseni */ /* [vtupnidata] Popiseme strukturu vstupnich dat, se kterymi pracuji algoritmy na reseni lustovky. Tato data se inicializuji po precteni vstupniho souboru pomoci funkce nactiproblem(). Jak je implementovano cteni souboru nas bude zajimat az pozdeji, viz [nactiproblem]. V programu nerozlisujeme mezi radky a sloupci. Tim si usetrime psani dvou variant stejnych funkci, jednou pro radky a podruhe pro sloupce. Udaje o radcich jsou tesne nasledovany udaji o sloupcich a pouze podle promennych "pocetradku" a "pocetsloupcu" pozname, jaka je geometrie lustovky. K indexovani prave zkoumaneho radku/sloupce pouzivame globalni promenou "ii". Je-li "ii 0 otaznik, pokud nevime, zda na tomto policku barva b bude nebo ne. pole[b][i][j]==' ' znamena, ze tam barva b urcite nebude a pole[b][i][j]=='*' znaci, ze tam barva b urcite bude. Pro rychlejsi dotazovani do pole udrzuji algoritmy v konzistentnim stavu sumarni informaci v prvcich pole[0][i][j]: '?' .. aspon v jednom pole[b][i][j] je otaznik pro b>0 ' ' .. vsechna pole[b][i][j] pro b>0 maji mezeru, tj. jedna se urcite o barvu pozadi. '*' .. existuje prave jedno b, kde je pole[b][i][j] hvezdicka a pro vsechna ostatni b je pole[b][i][j] mezera. Tj. zname definitivne barvu tohoto policka. Protoze pole alokujeme az za behu programu podle aktualnich hodnot "pocetradku", "pocetsloupcu", "pocetbarev" pomoci malloc(), budeme pracovat jen s linearnim polem, tj. pole[]. Pristup do vrstev a radku resime programove a mame na to pripraveny zkratky: BIJ ... pristup do b-te vrstvy, i-teho radku a j-teho sloupce, IJ ... pristup do nulte vrstvy, i-teho radku a j-teho sloupce. Protoze algoritmy nerozlisuji mezi radky a sloupci lustovky (pracuji se zobecnenymi radky a s globalnim ii, viz [vstupnidata]), je potreba pripravit funkci rpole(), ktera precte policko pole ze zobecneneho radku ii z pozice i a z vrstvy b. Dale potrebujeme funkci spole(), ktera do prvku pole odpovidajici zobecnenemu radku ii a pozici i v barevne vrstve b ulozi novy znak c. Pripadem if(triddlers) se zatim pri prvnim cteni nebudeme zabyvat. Zamerime se na pravouhle lustovky. K triddlerum se podrobne vratime pozdeji. */ #define BIJ b*vrstva + i*pocetsloupcu + j #define IJ i*pocetsloupcu + j char *pole; long int vrstva, /* velikost vrstvy pole, vrstva = pocetradku*pocetsloupcu */ total; /* celkova delka pole */ char rpole (int i, int b) { if (triddlers) return pole [b*vrstva + tri(i)*maxj + trj(i)]; if (ii < pocetradku) return pole [b*vrstva + ii*pocetsloupcu + i]; else return pole [b*vrstva + i*pocetsloupcu + ii-pocetradku]; } void spole (int i, int b, char c) { if (triddlers) pole [b*vrstva + tri(i)*maxj + trj(i)] = c; else { if (ii < pocetradku) pole [b*vrstva + ii*pocetsloupcu + i] = c; else pole [b*vrstva + i*pocetsloupcu + ii-pocetradku] = c; } } /* [cosradkem] O kazdem zobecnenem radku si drzime nasledujici informace: cosradkem[ii] = 2 ... radkem ii se budeme zabyvat vzdy cosradkem[ii] = 1 ... radkem se budeme zabyvat jen v intenzivnim algoritmu cosradkem[ii] = 0 ... nema smysl se radkem ii zabyvat vyreseno[ii] ... pocet vyresenych policek v radku ii. */ char cosradkem[MAXRADKU+MAXSLOUPCU]; int vyreseno[MAXRADKU+MAXSLOUPCU]; /* [inipole] Funkce inipole() je volana z funkce main a inicializuje data pro lustovku pred zahajenim reseni, nebo pred vlozenim dalsich udaju pomoci parametru -ini U cernobile lustovky ma smysl se na zacatku nezabyvat radky, ktere maji stupen volnosti vetsi nez je maximalni delka bloku. O to se prave snazime v zaveru funkce inipole. Promenna "psvradku" (stupen volnosti radku) je definovana takto: Kdyz umistime vsechny bloky v radku co nejvice vlevo, pak stupen volnosti udava, o kolik pozic je mozno posledni blok posunout, nez narazi na konec radku. */ int tr0, tr1; /* konstanty, ktere pocita trset(), viz [triddlers] */ void inipole () { long int i; int j, sumb, maxb, maxll, psvradku; vrstva = pocetradku*pocetsloupcu; maxll = MAX(pocetradku,pocetsloupcu); if (triddlers) { trset(pocetradku-1); maxj = tr1; if (maxj > MAXRADKU) error ("limit MAXRADKU for triddlers exeeded"); vrstva = pocetradku * maxj; maxll = tridmaxll (); if (maxll > MAX(MAXRADKU,MAXSLOUPCU)) error ("limit MAXRADKU,MAXSLOUPCU for triddlers exeeded"); } total = vrstva*pocetbarev; if (pocetbarev==2) total = vrstva; pole = getmemory (total, "pole"); for (i=0; i maxb) maxb = vb[ii][j]; sumb += vb[ii][j]; if (vm[ii][j]>0) sumb += vm[ii][j]; } psvradku = ll - sumb; if (pocetbarev > 2 || pb[ii] == 0 || maxb > psvradku) cosradkem [ii] = 2, vyreseno [ii] = 0; else cosradkem [ii] = 0, vyreseno [ii] = 0; } } /* [ulozprvek] Abychom udrzeli udaje cosradkem[] a vyreseno[] konzistentni se stavem rozlustenosti lustovky, bude lepe pri kazdem novem vyresenem policku zapisovat do pole[] prostrednictvim funkce ulozprvek(). Tato funkce ulozi zmenu c na pozici i do vrstvy b podobne jako spole, ale navic pozmeni odpovidajici vyreseno[] a cosradkem[]. Jde o to, ze pokud jsme zanesli zmenu napr. na j-tou pozici v realnem radku k, pak je potreba otevrit realny sloupec j dalsimu reseni, protoze tam muzeme ziskat diky nove informaci dalsi nove informace. Nastavime tedy tomuto sloupci cosradkem[] = 2, protoze je sance, ze rychly algoritmus v tom sloupci neco najde. Globalni promenna "pocetzmen" pocita zmeny v kazdem kroku programu. Podle ni pak zjistime, zda byl krok uspesny (nejake novinky jsme objevili) nebo neuspesny ("pocetzmen" se nezmenilo). Funkce ulozdopasku() uklada stav policka pred zmenou do pameti track[], viz [ulozdopasku]. Zavolame ji jen tehdy, kdyz jsme ve zkousecim modu ("zkousime==1"). */ int pocetzmen, zkousime; void ulozprvek (int i, int b, char c) { pocetzmen++; if (zkousime) ulozdopasku (i, b); if (triddlers) { tridulozprvek (i, b, c); return; } if (ii < pocetradku) { pole [b*vrstva + ii*pocetsloupcu + i] = c; cosradkem[i+pocetradku] = 2; } else { pole [b*vrstva + i*pocetsloupcu + ii-pocetradku] = c; cosradkem[i] = 2; } if (b > 0) return; vyreseno [ii]++; if (ii < pocetradku) vyreseno[i+pocetradku]++; else vyreseno[i]++; } /* [ulozbarvu,zakazbarvu] Funkce ulozprvek() nehlida konzistenci jednotlivych barevnych vrstev v pripade vicebarevne lustovky. Abychom to meli pod kontrolou, budeme v pripade vicebarevne lustovky volat funkce ulozbarvu() a zakazbarvu(). Funkce ulozbarvu() ulozi barvu "b" na policko "i" radku "ii", tj. zanese do vrstvy "b" a vrstvy "0" znak "cerna" a do ostatnich vrstev znak "bila". Funkce zakazbarvu() ulozi do vrstvy "b" na policko "i" radku "ii" znak "bila". Pokud uz v zadne barevne vrstve nezustal na tomto policku otaznik, pak zanese znak "bila" i do vrstvy "0". Abychom zarucili spravne zaneseni predchozich udaju o policku do pasku, viz funkce ulozdopasku() volana z ulozprvek(), musime volat ulozprvek() drive, nez provedeme doplnkove zmeny a navic jej musime volat pokud mozno pro vrstvu "0". Znaky "cerna" resp. "bila" obsahuji hvezdicku resp. mezeru, ale v pripade pausovaciho modu tam mame "#" resp. "-", abychom znazornili rozdily oproti predchozimu kroku. */ char cerna = '*', bila = ' '; void ulozbarvu (int i, int b) { int k; ulozprvek (i, 0, cerna); spole (i, b, cerna); for (k=1; k limitbloku) { /* zatim tento radek/sloupec preskocime */ pocetpreskocenych++; /* vratime se k nemu pozdeji kvuli */ return OK; /* optimalizaci rychlosti */ } if (dukladne) sumri++ ; else sumrr++ ; if (pb[ii]==0) { /* radek neobsahuje zadny blok */ for (i=0; i=3) logradekA (1); ppzmen = pocetzmen; if (dukladne) { if (cosradkem[ii]==1 && !jeni) { i = 0; /* prozkoumame souvislost otazniku */ while (i=3) logradekB (); if (dukladne) cosradkem[ii] = 0; else cosradkem[ii] = 1; if (ppzmen0 && vml[j-1] < 0) vml[j-1] = 0, bml[j] = 1; } if (dvebarvy) prvekpole = primoradek; else prvekpole = rpolei; lll = ll-1; for (i=0; i0 && vml[j-1] < 0) vml[j-1] = 0, bml[j] = 1; pr[j] = ll - p[npp-j] - vbl[j]; } if (dvebarvy) prvekpole = primoradek; else prvekpole = rpole; for (i=0; i1" je tato kontrola velmi dulezita. Funkce kontrolaradku() se pokusi pomoci najdiprvni() najit (v tomto pripade uz jedine) nekonfliktni rozlozeni bloku. Pokud se to nepodari, vrati KO, jinak vrati OK */ int kontrolaradku () { register int i, j; np = pb[ii]; npp = np-1; if (np==0) return OK; for (j=0; j0 && vml[j-1] < 0) vml[j-1] = 0, bml[j] = 1; } for (i=0; i=p[j]; k--) if (radek[k] == '*') { j = posunblok (j-1, k); goto prev; } } while (1) { /* najdu pozici j-teho bloku */ if (dvebarvy) b = 0; else b = bbl[j]; oopj = i; next: p[j] = i; if ((i = p[j] + vbl[j]) > ll) return KO; if (j==npp) /* kontrola mezery vpravo do konce radku */ for (k=ll-1; k>=i; k--) if (radek[k] == '*') { j = posunblok (j, k); goto prev; } while (--i >= p[j]) if (prvekpole (i, b) == ' ') { for (k=i-dvebarvy; k >= p[j]; k--) if (radek [k] == '*') { j = posunblok (j-1, k); goto prev; } i++; goto next; } opj = p[j]; i = opj + vbl[j]; if (vml[j]) while (i < ll && prvekpole(i++, b) == '*') p[j]++; if (bml[j] && p[j] > oopj) { j = posunblok(j-1, p[j]-1); goto prev; } for (i=p[j]-1; i>=opj; i--) /* kontrola obnazene mezery */ if (radek[i] == '*') { j = posunblok(j-1, i); break; } prev: if (j < 0) return KO; if (j==npp) return OK; i = p[j] + vbl[j] + vml[j]; j++; } } /* [posunblok] Funkce se pokusi posunout j-ty blok na pozici i. Predpoklada pritom, ze j-ty blok uz byl nekam usazen. Funkce nejprve prekontroluje, zda pozadovane usazeni bloku nezakryva nejakou mezeru a pokud ano, pokusi se blok usadit vpravo od mezery. Funkce dale prekontroluje, zda po posunuti se neodkryla nejaka hvezdicka. Pokud ano, zavola funkce posunblok() rekurzivne sebe sama na blok vlevo od posunovaneho bloku tak, aby tento zakryl problemovou hvezdicku. Pokud funkce rekursivne sve pozadavky hromadi az do stavu, kdy se ma posunovat blok vlevo od nulteho bloku (tam ale uz zadny neni), funkce vrati -1. To je priznak celkoveho konfliktu v radku. Jinak funkce vrati cislo bloku, ktery je urcite usazen nekonfliktne. Toto cislo diky rekurzivnimu volani muze byt nakonec mensi, nez puvodni cislo "j". Funkce posunblok() a najdiprvni() jsme se snazili optimalizovat na rychlost. Proto zde vidite konstrukce "goto". Verime, ze jsme tim nikoho moc neurazili. Pravdepodobne se da funkce najdiprvni() implementovat jeste jinak a efektivneji. Mame urcitou predstavu, ale zatim jsme to nezkouseli... */ int posunblok (int j, int i) /* posune j-ty blok, aby zakryl pozici i */ { int opj, oopj, b; if (j < 0) return -1; opj = p[j]; if (dvebarvy) b = 0; else b = bbl[j]; i = i-vbl[j]; oopj = i+1; next: p[j] = i+1; if ((i = p[j] + vbl[j]) > ll) return -1; while (--i >= p[j]) if (prvekpole (i, b) == ' ') goto next; i = p[j] + vbl[j]; if (vml[j]) while (i < ll && prvekpole(i++, b) == '*') p[j]++; if (bml[j] && p[j] > oopj) return posunblok(j-1, p[j]-1); for (i=p[j]-1; i>=opj; i--) /* kontrola obnazene mezery */ if (radek[i] == '*') return posunblok(j-1, i); return j; } /* [intensive] Popiseme intensivni algoritmus. Domnivame se, ze tento algoritmus zatim neni nikde na Internetu publikovan a ze je v tomto zdrojovem kodu zverejnen poprve. Zname zatim jen takove programy, ktere maji intenzivni algoritmus zalozen na prohledani vsech nekonfliktnich poloh bloku. Ovsem takovych poloh je s*(s-1)*(s-2)*...*(s-n), kde n je pocet bloku a s je stupen volnosti radku. Nas algoritmus na rozdil od tohoto dosahuje slozitost zhruba linearne zavislou na poctu policek v radku, tedy zadny faktorial! Rozdil v rychlostech na rozsahlych lustovkach, ktere si nevystaci s pravolevym algoritmem, je nebetycny. Autorem algoritmu i jeho implementace ve funkci intensive() je Mirek Olsak. Jak to pracuje je patrne pri pouziti parametru -log 4 -i. Z pravoleveho rozlozeni bloku se dale budeme zabyvat jen pruniky cernych, ktere mohou dat ve vysledku cernou a pruniky mezer, ktere mohou dat mezeru. Jinymi policky se nezabyvame. Dale zuzime nas vyber jen na policka, u kterych dosud mame otaznik. Pri pruniku cernych zkusime do radku pridat mezeru a testujeme pomoci funkce najdiprvni(), zda to vede ke sporu. Pokud ano, mame jistotu, ze policko je cerne. Pokud neni odhalen spor, pak sice o policku nemuzeme nic prohlasit, ale nekonfliktni rozlozeni bloku z najdiprvni() muzeme proniknout se stavajicim prunikem praveho a leveho rozlozeni a tim zuzit vyber dalsich policek k testovani. Ukazuje se, ze se nevyplati delat kompletni prunik, protoze krome nejblizsiho bloku se ostatni bloky vlevo vetsinou moc nehybaji. Doplnime tedy prunik jen o polohu tohoto nejblizsiho bloku. Totez delame s mezerami. Tj. pokud existuje prunik mezer, zkusime najdiprvni() potrapit doplnenim policka cernou. Vede-li to ke sporu, vime, ze policko obsahuje mezeru. Pri vice barvach se algoritmus musi volat opakovane pro kazdou barvu zvlast. Proto je parametrem funkce cislo barvy, se kterou zrovna pracujeme. Funkce pracuje s pracovnim polem pp[], ktere obsahuje informace o stavu pruniku daneho policka : 1 .. neni prunik, 3 .. prunik mezer (zkousi se barva), 4 .. prunik barvy (zkousi se mezera), jine hodnoty nejsou vyuzity. Funkce nejprve naplni pole pp[] podle rozlozeni p[] a pr[] (leve a prave nekonfliktni rozlozeni bloku). Pri te prilezitosti ulozi do pole kacko[] cislo bloku, se kterym se bude muset pri testu daneho policka pohnout. Je to blok nejblize vlevo od daneho policka (pri levem rozlozeni bloku). Dale funkce intensive() prochazi radek odzadu a zkousi konfliktni navrhy. Funkci najdiprvni() kvuli uspore casu vola s nenulovymi parametry. Nakonec ulozi reseni do pole[] pomoci ulozprvek(), ulozbarvu() a zakazbarvu(). */ int kacko[MAX(MAXRADKU,MAXSLOUPCU)]; char pp[MAX(MAXRADKU,MAXSLOUPCU)]; void intensive (int b) /* pokus o dukladne vyreseni radku */ { /* jinak nez brutalni silou */ int i, j, j0, j1, k, k0, k1, dopadlo, pom[MAXBLOKU], dotoho; char zn=0; for(k=j0=j1=k0=k1=i=0; i=0;i--){ if(pp[i] > 2){ if(kacko[i] > -1){ if(pp[i]==3){ radek[i]='*'; if(dvebarvy==0) spole(i,b,'*'); dopadlo=najdiprvni(i-vb[ii][kacko[i]]+1,kacko[i]); if (llevel >= 4) { fprintf (logf, "add %c: |%*s#%*s|", barva[b?b:1], i, "", lll-i, ""); zn = '-'; } } else{ if(dvebarvy) radek[i]=' '; else spole(i,b,' '); dopadlo=najdiprvni(i+1,kacko[i]); if (llevel >= 4) { fprintf (logf, "add %c: |%*s-%*s|", barva[b?b:1], i, "", lll-i, ""); zn = '#'; } } } else { dopadlo=KO; if (llevel >= 4) fprintf (logf, "add %c: |%*s#%*s|", barva[b?b:1], i, "", lll-i, ""), zn = '-'; } radek[i]='?'; if(dopadlo==OK){ if(dvebarvy==0) spole(i,b,'?'); if (llevel>=4) fprintf (logf, " OK .. no info\n"); if(pp[i]==3){ if(i-vb[ii][kacko[i]]+1 == p[kacko[i]]){ if(kacko[i]==0)dotoho = -1; else dotoho = p[kacko[i]-1]+vbl[kacko[i]-1]; for(j=i-1;j>dotoho;j--){ if(rpole(j,b)!='?') break; if(pp[j]==3) pp[j]=1; } } } else{ if(kacko[i]==0)dotoho = -1; else dotoho = p[kacko[i]-1]+vbl[kacko[i]-1]; for(j=i-1;j>dotoho;j--){ if(pp[j]==4) pp[j]=1; } } } if(dopadlo==KO){ if (llevel>=4) fprintf (logf, " KO => r[%d] = %c, found!\n", i, zn); if (zkousime && !dvebarvy) spole(i,b,'?'); /* do pasku musime dat otaznik */ if(pp[i]==4) { if (dvebarvy) ulozprvek (i, 0, cerna); else ulozbarvu (i, b); } else { if (dvebarvy) ulozprvek (i, 0, bila); else zakazbarvu (i, b); } } for(j=0;j=4) printpole (1); if ((paused && paused<=pruchod) || llevel >=3) for (i=0; i+Enter: pause after steps ==> "); ch = getc (stdin); if (ch >= '0' && ch <= '9') { i = ch - '0'; ch = getc (stdin); while (ch >= '0' && ch <= '9') { i = 10*i + ch - '0'; ch = getc (stdin); } if (i==0) paused = 0, cerna = '*', bila = ' '; if (i>=2) paused = pruchod + i, cerna = '*', bila = ' '; } while (ch != '\n') ch = getc (stdin) ; /* vyprazdnime buffer */ } pocetzmen = 0; pruchod++; if (pruchod == paused || pruchod == steps) cerna = '#', bila = '-'; if (steps && pruchod > steps) { if (!paused && outlevel<4) printpole (1); if (logf != outf && logf==stdout) printf ("\n"); exit (0); } } /* [main] Podivejme se nyni na problem z druhe strany -- z pohledu hlavniho programu. Nejprve pomoci funkce cmdparser() prozkoumame parametry prikazove radky. Do pole buf[] si ulozime jmeno ulohy odvozene ze jmena vstupniho souboru (ale s odpojenou pripadnou priponou). Pomoci funkce nactiproblem() precteme zadani ze vstupniho souboru. Pak inicializujeme pole pomoci inipole(). Je-li zadan soubor pomoci parametru -ini, precteme jej funkci nactipart(). Pak se pustime do vlastniho reseni spustenim funkce vsechnareseni(). Na zaver vypiseme pocet nalezenych reseni a statistiku poctu kroku a poctu vstupu do radkovych algoritmu. */ FILE *cmpfile=NULL, /* soubor zadany pomoci -ini */ *inifile=NULL, /* soubor zadany pomoci -cmp */ *mainfile; /* hlavni soubor ulohy */ char buf [MAXBUF]; /* nazev ulohy */ char iityp = ' '; /* typ radku, zejmena rozlisujeme u triddlers */ int main (int argc, char**argv) { int k, inf; cmdparser (argc, argv); inf = argc-1; for (k=0; argv[inf][k]!=0 && argv[inf][k]!='.'; k++) buf[k] = argv[inf][k]; buf [k] = 0; if (buf[0] == '-' && buf[1] == 0) strcpy (buf, "stdin"); if (paused==1 || steps==1 || llevel >= 3) cerna = '#', bila = '-'; nactiproblem (); inipole (); if (inifile != NULL) nactipart (inifile); prvekpole = rpole; if (dvebarvy) prvekpole = primoradek; pocetzmen = 0; zkousime = 0; wlog (2, "Steps: (bl=%d)", limitbloku); vsechnareseni (); if (sumr==0) { if (llevel==0) return 2; if (outlevel<4) printpole (0); fprintf (logf, "\nKO: %s -- the task have NO solution, sorry. ", buf); if (triddlers) trset(ii); if (ii=A)? 2*(ii-A)+1 : 0) /* korekce pro triddlers */ void vsechnareseni () { int backindex, b, i, j, k; if (vyres () == KO) { /* reseni nenalezeno */ if (llevel==2) wlog (2, " -", 0); if (llevel>=3) { logradekA (0); if (llevel >= 3) { if (ii= totalnum) { if (llevel>0) { fprintf (logf, "\nMaximal number of solutions -total %d reached. I terminate.\n", totalnum); printstatistic (); } exit (1); } if (cmpfile != NULL) exit (0); if (sumr<=xpmnum && cmpfile == NULL) savexpm (); return; } /* mame v reseni stale nejaky otaznik, poustime se do testu */ wlog (2, " ?", 0); for (i=0; i", tracktotal); } zkousime = 1; if (dvebarvy) { if (llevel>=2) fprintf (logf, "\n ' '->[%d,%d]", ii+1, i+1-TR), fflush (logf); ulozprvek (i, 0, bila); cosradkem [ii] = 2; typkroku = 't'; vsechnareseni (); while (trindex>backindex) vemzpasku (); if (llevel>=2) fprintf (logf, "\n '*'->[%d,%d]", ii+1, i+1-TR), fflush (logf); ulozprvek (i, 0, cerna); cosradkem [ii] = 2; typkroku = 't'; vsechnareseni (); while (trindex>backindex) vemzpasku (); } else { trskip = (pocetbarev-1) / SIZEINT + 1; if (llevel>=2) fprintf (logf, "\n ' '->[%d,%d]", ii+1, i+1-TR), fflush (logf); ulozprvek (i, 0, bila); for (b=1; bbackindex) vemzpasku (); for (b=1; b=2) fprintf (logf, "\n '%c'->[%d,%d]", barva[b], ii+1, i+1-TR), fflush (logf); ulozprvek (i, 0, cerna); spole (i, b, cerna); for (k=1; kbackindex) vemzpasku (); } } } /* [ulozdopasku] Abychom obnovili pro potreby [vsechnareseni] stav pole reseni, zaznamenavame si ve funkci ulozprvek() pri hodnote promenne zkousime=1 do jednorozmerneho globalniho pole track[] (tzv. "pasku") souradnice zmeneneho policka. Ve funkci vsechnareseni() drzime v lokalni promenne backindex (kazda instance rekurzivniho volani ma svuj backindex) ukazatel na misto v poli track[], kam se potrebujeme po vyzkouseni moznosti vratit. Pri navratu cteme pozpatku track[] az k mistu backindex a uvadime podle udaju v track[] pole reseni do puvodniho stavu. Globalni ukazatel "trindex" ukazuje vzdy tesne za posledni vlozeny prvek. V cernobile verzi staci ukladat do track[] hodnotu "ii", a "i", tj. souradnice zmeneneho policka. Pri navratu vime urcite, ze na techto souradnicich mame zpetne namalovat otaznik a snizit hodnoty vyreseno[] odpovidajiciho radku a sloupce o jednicku. V barevne verzi musime ulozit do track stav otazniku a mezer daneho policka pro kazdou barvu. Muze se totiz stat, ze nektere barvy urcite do policka nepatri, zatimco jine maji zatim v policku otaznik. Tento stav policka ukladame do track[] v komprimovanem tvaru: bit=0 .. mezera, bit=1 .. otaznik. Do pole track[] je tedy potreba krome souradnic policka ulozit "pocetbarev-1" bitu. Ve skutecnosti ukladame "pocetbarev" bitu, protoze navic jeden bit je rezervovan na informaci, zda je nutne pri obnove pole reseni snizovat udaj vyreseno[]. V barevne verzi se pri ulozprvek() totiz nezvedaji udaje vyreseno[] vzdy, ale jen v pripade zmeny ve vrstve 0. Ve funkci vsechnareseni() je uveden vypocet hodnoty trskip, coz je pocet prvku pole track[], ktere je potreba na vyse popsanou bitovou informaci rezervovat. Ve vzorci se pracuje s konstantou SIZEINT, coz je pocet bitu jednotliveho prvku pole track. Napriklad, pokud mame 32 bitovy prvek pole track (to byva obvykle) a mame 34 barev (nepocitame barvu pozadi) a pricteme jeden bit na informaci o obnove vyreseno[], pak je potreba ukladat pro kazde zmenene policko 35 bitu a je tedy trskip=2. V prvnim prvku je vyuzito vsech 32 bitu a ve druhem prvku jeste vyuzivame dalsi tri bity. Ackoli funkce vsechnareseni() alokovala track dostatecne veliky, muze se stat, ze nebude stacit. K tomu muze dojit jen u barevnych lustovek, kdy se k jednomu policku vracime vicekrat, nez jej definitivne vyresime. Kazda nova navsteva policka ulozi novou informaci v track[]. Proto v pripade potreby zdvojnasobime velikost track[] novym volanim malloc(). */ void ulozdopasku (int i, int ba) { unsigned int k, j, b=0; unsigned int *track1; if (trindex+trskip+2 > tracktotal) { /* delka pasku je nepostacujici */ tracktotal *= 2; track1 = getmemory (tracktotal*sizeof(unsigned int), "track1"); wlog (2, " track<%ld>\n", tracktotal); for (k=0; k=pocetbarev) break; } trindex++; } track [trindex++] = ii; track [trindex++] = i; } /* [vemzpasku] Funkce restauruje vzdy jedno policko pole[] na zaklade udaju z track[], ktere jsme tam vlozili pomoci ulozdopasku(). Soucasne funkce snizi trindex tak, aby znovu ukazoval za posledni jeste neprectenou hodnotu v track[]. */ void vemzpasku () { int i, j, k, b, m; i = track [--trindex]; ii = track [--trindex]; if (!dvebarvy) { b = pocetbarev - 1; m = pocetbarev % SIZEINT; for (k=0; k0) m = SIZEINT; for (j=0; j 0) return; vyreseno [ii]++; vyreseno[x]++; vyreseno[y]++; } /* [tridmaxll] je funkce, ktera zjisti z parametru triddleru maximalni delku zobecneneho radku. */ int tridmaxll () { int v; if (Ev) v = ll; if (B>F) trset (A+B+C+D+E-1); else trset (A+B+C+D+E); if (ll>v) v = ll; return v; } /* [cisloradku] Funkce vrati cislo radku nebo sloupce. V pripade triddlers cisluje podel kazde strany sestiuhelnika zvlast. */ int cisloradku (int r) { if (triddlers) switch (iityp) { case 'A': return r + 1; case 'B': return r - A + 1; case 'C': return r - A-B + 1; case 'D': return r - A-B-C + 1; case 'E': return r - A-B-C-D + 1; case 'F': return r - A-B-C-D-E + 1; } if (r\n"); printf (" where is the input file with the task\n"); printf (" options:\n"); printf (" -help ... this text is printed and program terminates\n"); printf (" -p ... start paused mode after steps\n"); printf (" -stop ... do only steps, don't solve the whole task\n"); printf (" -log ... set the verbosity of the log output (default: 2)\n"); printf (" -out ... the format of solution printing (default: 2)\n"); printf (" -lf ... log output to instead on stdout\n"); printf (" -of ... solution output to instead on stdout\n"); printf (" -i ... run the intensive line-solver only\n"); printf (" -ini ... read partial solution from \n"); printf (" -cmp ... read your partial solution for comparison\n"); printf (" -total ... maximal printed solutions limited by \n"); printf (" -xpm ... number of maximal xpm output files (default: 1)\n"); printf (" -bl ... limit of bloks used in first steps (default: 7)\n"); exit (1); } void cmdparser (int argc, char**argv) { int ac=0; outf = logf = stdout; while (++ac < argc && argv[ac][0] == '-' && argv[ac][1] != 0) switch (argv[ac][1]) { case 'p': if (argv[ac][2] != 0) usage (); if (++ac >= argc) usage (); if (argv[ac][0] < '0' || argv[ac][0] > '9') usage(); paused = atoi (argv[ac]); break; case 'c': if (strcmp (argv[ac], "-cmp") != 0) usage (); if (++ac >= argc) usage (); cmpfile = openfile (argv[ac], "r"); break; case 'i': if (strcmp (argv[ac], "-ini") != 0) { if (argv[ac][2] != 0) usage (); jeni = 1; break; } if (++ac >= argc) usage (); inifile = openfile (argv[ac], "r"); steps = 1; break; case 'l': if (strcmp (argv[ac], "-log") != 0) { if (strcmp (argv[ac], "-lf")) usage (); if (++ac >= argc) usage (); logf = openfile (argv[ac], "w"); break; } if (++ac >= argc) usage (); if (argv[ac][0] < '0' || argv[ac][0] > '9') usage(); llevel = atoi (argv[ac]); break; case 'o': if (strcmp (argv[ac], "-out") != 0) { if (strcmp (argv[ac], "-of")) usage (); if (++ac >= argc) usage (); outf = openfile (argv[ac], "w"); break; } if (++ac >= argc) usage (); if (argv[ac][0] < '0' || argv[ac][0] > '9') usage(); outlevel = atoi (argv[ac]); break; case 's': if (strcmp (argv[ac], "-stop") != 0) usage (); if (++ac >= argc) usage (); if (argv[ac][0] < '0' || argv[ac][0] > '9') usage(); steps = atoi (argv[ac]); break; case 't': if (strcmp (argv[ac], "-total") != 0) usage (); if (++ac >= argc) usage (); if (argv[ac][0] < '0' || argv[ac][0] > '9') usage(); totalnum = atoi (argv[ac]); break; case 'x': if (strcmp (argv[ac], "-xpm") != 0) usage (); if (++ac >= argc) usage (); if (argv[ac][0] < '0' || argv[ac][0] > '9') usage(); xpmnum = atoi (argv[ac]); break; case 'b': if (strcmp (argv[ac], "-bl") != 0) usage (); if (++ac >= argc) usage (); if (argv[ac][0] < '0' || argv[ac][0] > '9') usage(); limitbloku = atoi (argv[ac]); break; case 'I': if (argv[ac][2] != 0) usage (); jeni = 1; break; default: usage (); } if (ac != argc-1) usage(); mainfile = openfile (argv[ac], "r"); } /* [printstatistic] vytiskne zaverecnou statistiku poctu kroku a poctu vstupu do radkovych algoritmu */ void printstatistic () { char plus[2]; plus[0]=0, plus[1]=0; fprintf (logf, " steps %ld (",pruchod-1); if(sumkr) fprintf (logf, "%ldr",sumkr), plus[0]='+'; if(sumkc) fprintf (logf, "%s%ldc", plus, sumkc), plus[0]='+'; if(sumke) fprintf (logf, "%s%lde", plus, sumke), plus[0]='+'; if(sumkR) fprintf (logf, "%s%ldR", plus, sumkR), plus[0]='+'; if(sumkC) fprintf (logf, "%s%ldC", plus, sumkC), plus[0]='+'; if(sumkE) fprintf (logf, "%s%ldE", plus, sumkE), plus[0]='+'; if(sumkt) fprintf (logf, "%s%ldt", plus, sumkt); fprintf (logf, "), lines l-r: %ld/%ld, i: %ld/%ld\n", sumur, sumrr, sumui, sumri); } /* [printpole] Funkce vytiskne reseni. Je-li podrobne==1, pak stav reseni neni ukoncen. Ma tedy smysl pri -out >= 3 tisknout jednotlive vrstvy pole[]. Je-li lustovka cernobila, pak pri podrobne==1 vytiskneme primy obsah vrstvy 0, protoze tam mohou byt novinky vyznaceny znakem '#' nebo '-'. */ char jmenobarvy[MAXBAREV+1][MAXDELKASLOVA]; /* jmena barev pro xpm */ void printpole (int podrobne) { int b; if (outlevel==0) return; if (podrobne && (dvebarvy || outlevel>=3)) { for(b=1;b=2 && !dvebarvy) fprintf (outf, "\nCOLOR %c: %s", barva[b], jmenobarvy[b]); if (triddlers) tridprintpole (b); else gridprintpole (b); } if (dvebarvy) return; } if (triddlers) tridprintpole (0); else gridprintpole (0); } /* [gridprintpole] vytiskne jednu barevnou vrstvu pole[]. Pri b=0 tiskne souhrnou informaci o vsech barvach soucasne. */ void gridprintpole (int b) { int i, j, jak; if (outlevel>=2) { if (pocetsloupcu>=10) fprintf (outf, "\n "); for (j=1; j<=pocetsloupcu/10; j++) fprintf (outf, "%10d", 10*j); fprintf (outf, "\n:::: "); for (j=1; j<=pocetsloupcu; j++) fprintf (outf, "%d", j%10); } fprintf (outf, "\n"); for (i=0; i=2) { if ((i%10)==9) fprintf (outf, "%3d: ", (i+1)); else fprintf (outf, "%3d: ", (i+1)%10); } for (j=0; j=2) { fprintf (outf, ":::: "); for (j=1; j<=pocetsloupcu; j++) fprintf (outf, "%d", j%10); if (pocetsloupcu>=10) fprintf (outf, "\n "); for (j=1; j<= pocetsloupcu/10; j++) fprintf (outf, "%10d", 10*j); fprintf (outf, "\n"); } } /* [tridprintpole] je varianta gridprintpole() pro triddlers */ void tridprintpole (int b) { int i, j, d, e, a, jak; if (outlevel>=2) { fprintf (outf, "\n %*s", A+1, ""); for (j=F; j>0; j--) fprintf (outf, " %d", j%10); fprintf (outf, "\n:::: "); } else fprintf (outf, "\n"); e = E; d = D; a = 1; fprintf (outf, "%*s", A+1, ""); rprint (outf, 2*F+1, '-'); if (outlevel>=2 && e) fprintf (outf, " %2d", e--); fprintf (outf, "\n"); for (i=0; i=2) { if (i==A) a = 1; fprintf (outf, "%3d: ", a++); } if (i=2 && e) fprintf (outf, "%2d", e--); fprintf (outf, "\n"); } else { fprintf (outf, " /"); if (outlevel>=2 && i!=E) fprintf (outf, "%2d", d--); fprintf (outf, "\n"); } } if (outlevel>=2) fprintf (outf, ":::: "); fprintf (outf, "%*s", B+1, ""); rprint (outf, 2*C+1, '-'); if (outlevel>=2) fprintf (outf, " %2d", d); fprintf (outf, "\n"); if (outlevel>=2) { fprintf (outf, " %*s", B+1, ""); for (j=1; j<=C; j++) fprintf (outf, " %d", j%10); fprintf (outf, "\n"); } } /* [rprint] je opakujici se print (repeated print). Znak c se vytiskne k-krat. navic zvedneme o pocet vytistenych znaku promennou rp, coz se bude hodit pri ukladani do XPM */ int rp; void rprint (FILE *f, int k, char c) { register int i; for (i=0; i= level. Pouzivame zde fflush(), protoze na pomalych strojich potrebuje uzivatel videt, ze se neco deje. */ void wlog (int level, char *s, long int value) { if (llevel < level) return; fprintf (logf, s, value); fflush (logf); } /* [printbloky] tiskne rozlozeni bloku pro potreby llevel > 3. Je to velice nazorna logovaci informace, jak pracuji pouzite algoritmy. */ void printbloky (int * p, char *s) { int i, j, b=1, d; int nz; fprintf (logf, "%5s: |", s); j = 0; d = 0; if (j= 4 && printlr) { printbloky (pr, "right"); printbloky (p, "left"); } } /* [logradekB] tiskne stav radku po provedeni radkoveho algoritmu. */ void logradekB () { int i, j, new; char zn; new=0; if (dvebarvy) { fprintf (logf, "out: |"); for (i=0; i= '0' && ch <= '9') { pocetbarev = 2; defbarva = 1; mkformat = 1; ii = 0; goto start; } mkformat = 0; while (1) { while (ch != ':' && ch != '#' && ch != EOF) skipline (); if (ch == EOF) formaterror ("unexpected end of file"); if (ch == ':') { ch = NEXTCHAR; break; } if (ch == '#') { ch = NEXTCHAR; if (ch == 'D' || ch == 'd') { ch = '!' ; break; } if (ch == 'T' || ch == 't') { triddlers = 1; strcpy (jmenobarvy[MAXBAREV], "gray"); } skipline (); } } if (ch == '!') { /* ":!" nebo "#d" ... deklarace barev */ skipline (); ii = 2; defbarva = 0; barva [0] = ' '; barva [1] = '*'; while (1) { if (ch == ':') break; skipblanks (); if (ch == EOF) formaterror ("unexpected end of file"); switch (ch) { case '0': i = 0; break; case '1': i = 1; defbarva = 1; break; case '6': i = MAXBAREV; break; default: i = ii++; if (i >= MAXBAREV) formaterror ("limit MAXBAREV exceeded"); znbarvy [i] = ch; } ch = NEXTCHAR; if (ch != ':') formaterror ("the colon expected"); ch = NEXTCHAR; if (ch == '\n' || ch == EOF) formaterror ("wrong color declaration"); if (i != MAXBAREV) barva [i] = ch; ch = NEXTCHAR; skipblanks (); j = 0; while (ch != ' ' && ch != '\t' && ch != '\n') { if (j>=MAXDELKASLOVA-1) formaterror ("limit MAXDELKASLOVA exceeded"); jmenobarvy [i][j++] = ch; ch = NEXTCHAR; } if (j == 0) formaterror ("the color name for XPM expected"); jmenobarvy [i][j] = 0; if (i == MAXBAREV) { skipline (); continue; } skipblanks (); lep[i] = NORMAL; lepc[i] = NORMAL; if (ch == '<') { trojuhelniky = 1; lep[i] = LEFT; ch = NEXTCHAR; if (ch == '>') lepc[i] = RIGHT; else lepc[i] = LEFT; } else if (ch == '>') { trojuhelniky = 1; lep[i] = RIGHT; ch = NEXTCHAR; if (ch == '<') lepc[i] = LEFT; else lepc[i] = RIGHT; } skipline (); } pocetbarev = ii; /* pocet barev vcetne barvy pozadi */ if (defbarva == 0) { /* defaultni barva neni deklarovana */ for (i=1; i= MAXRADKU+MAXSLOUPCU) formaterror ("limit MAXRADKU+MAXSLOUPCU exceeded"); if (!triddlers && ii >= MAXRADKU) formaterror ("limit MAXRADKU exceeded"); j = nactiradek (); if (j < 0) formaterror ("unexpected end of file"); if (npp > maxsirkaradku) maxsirkaradku = npp, indexradku = ii; pb[ii++] = j; ch = NEXTCHAR; ll++; } pocetradku = ii - i0; if (pocetradku==0 && !triddlers) formaterror ("no rows declared"); if (trojuhelniky) for (i=1; i= MAXRADKU+MAXSLOUPCU) formaterror ("limit MAXRADKU+MAXSLOUPCU exceeded"); if (!triddlers && ii - pocetradku >= MAXRADKU) formaterror ("limit MAXSLOUPCU exceeded"); j = nactiradek (); if (j == -1) break; if (npp > pocetradku && !triddlers) formaterror ("the number of rows is less than the column length"); pb[ii++] = j; ch = NEXTCHAR; ll++; } pocetsloupcu = ii - pocetradku - i0; if (pocetsloupcu==0 && !triddlers) formaterror ("no columns declared"); if (pocetsloupcu < maxsirkaradku && !triddlers) { fprintf (stderr, "Error in the input file: "); fprintf (stderr, "the number of columns is less than the length of row %d\n", indexradku); exit (10); } if (triddlers) { if (A+B==0) { A = pocetradku; B = pocetsloupcu; i0 = A+B; if (A+B==0) formaterror ("wrong hexagonal sides: A+B = 0"); goto start; } if (C+D==0) { C = pocetradku; D = pocetsloupcu; i0 = A+B+C+D; if (C+D==0) formaterror ("wrong hexagonal sides: C+D = 0"); goto start; } E = pocetradku; F = pocetsloupcu; if (E+F==0) formaterror ("wrong hexagonal sides: E+F = 0"); if (E != A+B-D) formaterror ("wrong hexagonal sides: A+B-D != E"); if (F != D+C-A) formaterror ("wrong hexagonal sides: D+C-A != F"); pocetradku = A+B; pocetsloupcu = C+D+E+F; } if (mainfile != stdin) fclose (mainfile); if (triddlers) { testkonzistence (0, A+B, A+B+C+D); testkonzistence (A+B, A+B+C+D, A+B+C+D+E+F); } else testkonzistence (0, pocetradku, pocetradku+pocetsloupcu); dvebarvy = (pocetbarev == 2); } /* [nactiradek] precte radek vstupniho souboru obsahujici deklarace realneho radku nebo realneho sloupce. Uvnitr cyklu "while(1)" cteme postupne jeden udaj, pokud lepici trojuhelniky nejsou deklarovany, nebo cteme trojici udaju, pokud lepici trojuhelniky jsou deklarovany. Trojice: pripadny lepici trojuhelnik vlevo, skutecny blok a pripadny lepici trojuhelnik vpravo. Funkce v takovem pripade zmensuje velikosti skutecnych bloku o pocet lepicich trojuhelniku kolem bloku. V takovem pripade muze blok mit nakonec delku nula. V takovem pripade jej funkce ze seznamu bloku bez milosti odstrani. V prvnim pruchodu si funkce poznaci poznamku o lepeni ve tvaru vm[ii][j]=2 a teprve v druhem pruchodu natavuje skutecne velikosti mezer. Problem je v tom, ze totiz bloky lepicich trojuhelniku na sebe mohou navazovat bez mezery, i kdyz jsou stejne. */ int nactiradek () { int i, j=0, lt=0, rt=0, prevbox, curb; while (1) { skipblanks (); if (ch == '\n' && mkformat && j == 0) return -1; if (ch == '\n' || ch == EOF) break; if (j >= MAXBLOKU) formaterror ("limit MAXBLOKU exceeded"); if (trojuhelniky) { lt = nactibarvu (LEFT); if (lt) { vb[ii][j] = 1; vm[ii][j] = -1; bb[ii][j++] = lt; if (j >= MAXBLOKU) formaterror ("limit MAXBLOKU exceeded"); } } vb[ii][j] = nacticislo (); if (vb[ii][j] == 0) { if (j == 0) { skipblanks(); return 0; } else formaterror ("zero as bock length is not allowed"); } bb[ii][j] = nactibarvu (NORMAL); vm[ii][j] = 0; if (trojuhelniky) rt = nactibarvu (RIGHT); if (lt) vb[ii][j]--; if (rt) vb[ii][j]--; if (vb[ii][j] > 0) { j++; prevbox = 1; } else { prevbox = 0; if (lt) { prevbox = 1; vm[ii][j-1] = 2; } } if (j >= MAXBLOKU) formaterror ("limit MAXBLOKU exceeded"); if (rt) { if (prevbox && bb[ii][j-1] == 0) bb[ii][j-1] = 1; if (prevbox) vm[ii][j-1] = -1; vb[ii][j] = 1; vm[ii][j] = 2; bb[ii][j++] = rt; } } curb = npp = 0; for (i=0; i '9') formaterror ("the number is expected"); v = 0; while (ch >= '0' && ch <= '9') { v = 10*v + ch - '0'; ch = NEXTCHAR; } return v; } int nactibarvu (int jak) /* vrati cislo barvy */ { int v; if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == EOF || ch == ',') { if (defbarva == 0) formaterror ("the default color is undefined"); if (jak==RIGHT) return 0; return 1; } for (v=1+defbarva; v= MAXBAREV) { fprintf (stderr,"limit MAXBAREV exceeded during tiangle preparation\n"); return; } strcpy (jmenobarvy[k], jmenobarvy[i]); barva[k] = genbarva (k); if (barva[k]==0) { fprintf (stderr, "the next character for triangle color not found\n"); return; } troj[i][1] = barva[k]; troj[k][0] = 0; pocetvsechbarev++; } jmenobarvy[i][j] = troj[i][0]; j++; for (k=0; k= MAXBAREV) { fprintf (stderr,"limit MAXBAREV exceeded during triangle preparation\n"); return; } strcpy (jmenobarvy[k], &jmenobarvy[i][j]); barva[k] = genbarva (k); if (barva[k]==0) { fprintf (stderr, "the next character for triangle color not found\n"); return; } troj[i][2] = barva[k]; troj[k][0] = 0; pocetvsechbarev++; } } if (xpmnum==1) sprintf (filename, "%s.xpm", buf); else { k=xpmnum; j = 0; while (1) { j++; k /= 10; if (k==0) break; } sprintf (fmt, "%%s%%0%dld.xpm", j); sprintf (filename, fmt, buf, sumr); } outfile = fopen (filename, "w"); if (outfile==NULL) { fprintf (stderr, "The file %s cannot be open to writting\n", filename); return; } k = strlen (filename) - 4; filename [k] = '_'; fprintf (outfile, "/"); fprintf (outfile, "* XPM *"); fprintf (outfile, "/\nstatic char *%s[] = {\n", filename); if (triddlers) { tridsavexpm (outfile); goto finish; } if (numtroj) fprintf (outfile, "\"%d %d %d 1\",\n", XPMBLOCK*pocetsloupcu, XPMBLOCK*pocetradku, pocetvsechbarev-numtroj); else fprintf (outfile, "\"%d %d %d 1\",\n", pocetsloupcu, pocetradku, pocetvsechbarev-numtroj); for (i=0; i=2) fprintf (logf, "\nThe graphic image of the solution is saved in: %s\n", filename); } /* [genbarva] vygeneruje pismeno pro potreby XPM, ktere jeste neni v seznamu barva[] pouzito. Pokud se to nepodari, vrati nulu. */ char genbarva (int kmax) { char j; int k; for (j='A'; j < 'z'; j++) { for (k=0; k= tr1) rprint (f, k, barvakolem); else rprint (f, k, barva[jakabarva (i,j)]); } /* [system] Nasleduji bezne funkce na ziskani prostredku od systemu. Chceme, aby program zkolaboval ve vlastni rezii. Nechceme, aby byl program odstrelen systemem s nic nerikajicim "segmentation fault". */ void * getmemory (long int i, char *name) { void *v; v = malloc (i); if (v==NULL) { fprintf (stderr, "malloc() failed during %s[%ld] initialisation.\n", name, i); exit (12); } return v; } FILE* openfile (char *name, char *mode) { FILE *v; if (name[0] == '-' && name[1] == 0) { if (mode[0] == 'r') return stdin; else return stdout; } if ((v = fopen (name, mode)) == NULL) { if (mode[0] == 'r') fprintf (stderr, "cannot open the file %s to reading\n", name); else fprintf (stderr, "cannot open the file %s to writting\n", name); exit (11); } return v; }