KLASICKÁ ÚLOHA

           Pro  vás co  se chcete   přiučit něco  zajímavého tu  mám jeden
     klasický  příklad  z  programování.  Tady  máte  jeho  znění: Najděte
     nejkratší cestu jezdce (šachového koně) z jednoho místa šachovnice na
     druhé.
           Ukážu vám, jak jsem ji  vyřešil já a  popíšu vám většinu  svých
     chyb, které jsem při tom napáchal, protože chybami se člověk učí.

     Obecný algoritmus
           Četli-li jste v minulé Výhni články o umělé inteligenci, měl by
     vás napadnout algoritmus. Jeden vám tu popíšu, asi není nejlepší, ale
     je snadno  srozumitelný. Cestu jezdce si  mohu představit jako nějaký
     takovýhle strom. (jedu např. z bodu a1 do bodu c1)

                              a1
                        +-----+------+
                        b3           c2
                  +--+--+--+--+   +--+--+--+
                  a5 c5 d4 d2 c1  a3 b4 e3 e1
                        .             .
                        .             .

     Každá větev stromu  by se nakonec ke koncovému  bodu dostala, ale mně
     jde   jen  o   nejkratší   cestu   takže  rozvinu   strom  prozkoumám
     nenarazím-li  na  koncový  bod,  a  když  ne  rozvíjím strom dál.

     Komunikace s uživatelem
           Users interface (uživatelský  meziksicht) je důležitou stránkou
     programu  a mnohdy  je jeho nejdelší částí. Snažil  jsem se ho udělat
     co nejkratší  a nejhezčí. Idea:  šachovnice a po  ní budu moci jezdit
     kursorem a vybrat si políčka.
     Nakreslit šachovnici: Dá se to udělat i takhle.

     void prchebo{
     byte c,d;
     for (c=0;c<8;c+=2){
       gotoxy(SX,SY+c);
       printf("%i                        ",8-c);
       gotoxy(SX,SY+c+1);
       printf("%i                        ",7-c);
     }
       gotoxy(SX,SY+c);
       printf("  a  b  c  d  e  f  g  h\n");
     }

     Ale mně se  to líbí jinak. Vím-li, že když  sečteme souřadnice pole a
     dostaneme liché  číslo je políčko  černé, dostaneme-li číslo  sudé je
     políčko  bílé (lichost  určíme  podle  nejnižšího bitu  fcí. iseven).
     Takže radši použiju tyto procedurky.

    //vybarvi jedno policko
     void fara(byte x, byte y){
     const char pat[2][4]={"   \x0","   \x0"};
      gotoxy(x*3+SX+1,y+SY);
      cprintf("%s",pat[iseven(x+y)]);
     }

     //kresli sachovnici
     void prchebo(){
      byte c,d;
      textcolor(TC);
      for (c=0;c<8;c++)
       for (d=0;d<8;d++){
        gotoxy(SX,SY+c);
        printf("%i",8-c);
        fara(c,d);
       }
      gotoxy(SX,SY+c);
      textcolor(LIGHTGRAY);
      cprintf("  a  b  c  d  e  f  g  h\n");
     }
     Neni to  rychlejší ani kratší,  ale mně to  připadá hezčí, a  protože
     programuju pro radost, napsal jsem to takhle.

     A teď  kursor.  Jestli  jste  si  nevšimli, tak proceduru na kreslení
     kursoru  už máme.  Ano uhodli  jste. Zavoláme  fci. fara  se změněnou
     barvou  písma.  Takže  fce.   repric  jen  zkontroluje  údaje,  změní
     souřadnice a zavolá fci. fara. Komunikaci s klávesnicí zajišťuje fce.
     direc, která po stisknutí ENTERu  vrátí nulu a po stisknutí kursorové
     klávesy  změní proměnné  dx, dy.  Avšak s  kursorovými klávesami bývá
     problém,  protože jak  jistě většina   z vás  ví, stisknutí  šipky je
     signalizováno nulou a následným znakem, kterým  může být K, H, M nebo
     P. Takže fce. direc může vypadat nějak takhle.

     //cte klavesy hlida sipky a ENTER
     byte direc(signed char * dx,signed char * dy){
     byte c,n;
      do{
       c=getch();
       if (c==13) return 0;
       else if (c==0) {
         c=getch();
         switch (c) {
            case 'K':*dx=-1;
                   break;
            case 'H':*dy=-1;
                   break;
            case 'M':*dx=1;
                   break;
            case 'P':*dy=1;
                   break;
         }
        if (*dx+*dy!=0) c=1;
       }
      }while (c>1);
     return 1;
     }

     Ale mně se  to zase nelíbilo. Vždyť ty 4  písmena musí mít mezi sebou
     nějaký vztah. A opravdu po probdělé hodině dějepisu jsem ho objevil.
     Odečtete-li od kódu  klávesy 76 tak získáme nějaké  číslo. Je-li to 1
     nebo -1 přiřadí  se dx (1=doprava, -1=doleva), je-li  toto číslo 4 či
     -4 přiřadí se po vydělení 4mi do dy (-4=nahoru, 4=dolu). Touto fintou
     se fce. direc výrazně zjednoduší.

     //cte klavesy hlida sipky a ENTER
     byte direc(signed char * dx,signed char * dy){
     int c;
      c=getch();
      if (c==13) return 0;//je to ENTER?
      else
      if (c==0) {
       c=getch();
       c-=76;
       if (abs(c)==4) *dy=c/4; //je +-4?
       if (abs(c)==1) *dx=c;
      }
     return 1;
     }

     ALGORITMUS byl  popsán už výše,  ale s jeho  praktickým využitím byly
     drobné problémy.Idea: Šachovnici si představím jako dvourozměrné pole
     8*8. Budu do  něj označovat pole, na která už  jsem se dostal, a když
     nenajdu hledaný bod rozšířím hledání dál.
           Postupoval jsem podle tohoto návodu, ale narazil jsem.
     Problém  1.   Jak  poznám  konec  větve   (přeci  nebudu  celý  strom
               prohledávat znovu a znovu)
     Řešení   :K  označení  poslední  části  větve  přičtu konstantu (80),
               a při rozšiřování stromu ji odečtu.
     Problém 2. Jak při nalezení konce najdu cestu zpátky.
     Řešení   :K  označení  prohledaného  políčka  použiju kód políčka, ze
               kterého jsem se  na něj dostal. Např. bod a1  má kód 00, b3
               12 (číselný  kód zmenšený o  11 =>  a1  = 11;11 -  11 = 00)
               První (nulté) pole má kód 78, koncové 79.
     Problém 3.Při  vyhodnocování bere některé právě  rozšířené větve jako
               ty, které má vyhodnocovat => nenajde nejkratší cestu.
     Řešení   :Rozšiřování ukládat do jednoho  pole, vyhodnocovat jiné. Po
               vyhodnocení je ale musíte sjednotit.

     A teď  už  zbývá  vyznačit  nalezenou  cestu.  Protože jsem si chytře
     nechal  uložit kód  políčka, ze  kterého byl  cíl  nalezen  a v tomto
     políčku je uložen kód předešlého, mohu klidně dojí až do nultého bodu.

     Kosmetické úpravy
           Skrytí  originálního kursoru  bylo nutné,  protože svým hloupým
     blikáním  dost znervózňoval.  Kursor byl  odklizen přerušením  10h ve
     fci. hscur.
           Barvy můžete změnit přenastavením maker TC, CC na začátku.

     A nakonec  k  nejčastějším  chybám.  Prohazuju  souřadnice.  x  značí
     sloupec,  y  řádek,  takže  když  čtete  z  pole  musíte  číst  takto
     chebo[y][x].  Další error  byl, když  jsem měl  pole vyplněno nulama.
     Program  sice fungoval,  ale jen  někdy, protože  číslo 0 značí první
     pole vlevo nahoře (dělalo to nádherný věci)


      Poznámky: Omlouvám se, že neumim moc vysvětlovat, ale ono to neni tak
      jednoduchý.  V  jedné  knize  to  přirovnávali  tak,  že  to je jako
      popisovat  symfonickou  báseň  slovy.  Takže  vy, co  nechápete moje
      vysvětlení, se laskavě koukněte do not (zdrojáku) a  musí vám to být
      jasný.
     Nechápete-li princip  zavolejte program(tímle ho vyexportujete)
     s jakýmkoli parametrem a on vám bude ukazovat co dělá (Vypíše obsah pole
     chebow).

                                                                      HIPP

     (Naskytnou-li se problémy nebo budete-li mít dotazy čí poznámky pište
     a ptejte se)


            výheň