Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: PL/I: Towers of Hanoi

jalski [27.04.2011 16:30:57]

#

Towers of Hanoi puzzle:n ei rekursiivinen ratkaisu PL/I - ohjelmointikielellä käyttäen apuna binääriesitystä.

Wikipediasta löytyy lisätietoa aiheesta ja tarkempi kuvaus binääriratkaisusta.

Lyhyt kuvaus:

On kolme sauvaa: 1, 2 ja 3. Lisäksi on kasa eri kokoisia levyjä, jotka on aloitustilanteessa pinottu ensimmäiseen sauvaan kokojärjestykseen siten, että suurin levy on alimmaisena ja pienin päällimmäisenä. Levyt on numeroitu siten, että aloitustilanteessa päällimmäisin levy on ykkönen, sitä seuraava kakkonen, jne. Tarkoituksena on saada koko levypino siirrettyä johonkin toiseen sauvaan. Levyt siirretään yksi kerrallaan ja pienemmän levyn päälle ei saa laittaa suurempaa levyä.

*PROCESS MARGINS(1,160) pp(macro);
%replace NUMBER_OF_DISKS by 5;

 hanoi: proc options (main);
   dcl (i, from, to) fixed bin(31);

   dcl (iand, ior, trim, bit, length, mod) builtin;

   do i = 1 to 2**NUMBER_OF_DISKS - 1; /* All the possible moves */
     from = iand(i, i - 1);
     from = mod(from, 3) + 1;

     to = ior(i, i - 1) + 1;
     to = mod(to, 3) + 1;

     put skip list ('move disk' || trim(disk_nro(bit(i))), 'from peg' ||
                     trim(from), 'to peg' || trim(to));
   end;


   /* Returns number of the disk based on how many trailing */
   /* zeroes are at the end of the bit string.              */
   disk_nro: proc (m) returns (fixed bin(31));
     dcl m bit (*);    /* move as bit string */
     dcl i fixed bin;

     do i = length(m) to 1 by -1;
       if substr(m, i, 1) then
         return(length(m) - i + 1);
     end;

     return(i + 1);
   end disk_nro;


 end hanoi;

Ajettaessa ohjelma saadaan levyjen siirrot seuraavanlaisena listauksena:

move disk1              from peg1               to peg3
move disk2              from peg1               to peg2
move disk1              from peg3               to peg2
move disk3              from peg1               to peg3
move disk1              from peg2               to peg1
move disk2              from peg2               to peg3
move disk1              from peg1               to peg3
move disk4              from peg1               to peg2
move disk1              from peg3               to peg2
move disk2              from peg3               to peg1
move disk1              from peg2               to peg1
move disk3              from peg3               to peg2
move disk1              from peg1               to peg3
move disk2              from peg1               to peg2
move disk1              from peg3               to peg2
move disk5              from peg1               to peg3
move disk1              from peg2               to peg1
move disk2              from peg2               to peg3
move disk1              from peg1               to peg3
move disk3              from peg2               to peg1
move disk1              from peg3               to peg2
move disk2              from peg3               to peg1
move disk1              from peg2               to peg1
move disk4              from peg2               to peg3
move disk1              from peg1               to peg3
move disk2              from peg1               to peg2
move disk1              from peg3               to peg2
move disk3              from peg1               to peg3
move disk1              from peg2               to peg1
move disk2              from peg2               to peg3
move disk1              from peg1               to peg3

Kirjoitetaanpa vastaava koodinpätkä Iron Spring PL/I:llä. Kyseessä on beta-asteella oleva kääntäjä, josta vielä puuttuu ominaisuuksia sekä sisäänrakennettuja funktioita kuten: TRIM, IAND ja IOR.

%replace NUMBER_OF_DISKS by 5;


 hanoi: proc options (main);
  dcl (i, from, to) fixed bin (31);
  dcl disks_on_pegs bit (31);


  do i = 1 to 2**NUMBER_OF_DISKS - 1;
    disks_on_pegs = bit(i);

    from = disks_on_pegs & disks_on_pegs - '1'b;
    from = mod(from, 3) + 1;

    to = (disks_on_pegs | (disks_on_pegs - '1'b)) +  1;
    to = mod(to, 3) + 1;

    put skip list ('move disk' || ltrim(disk_nro(disks_on_pegs)), 'from peg' ||
      ltrim(from), 'to peg' || ltrim(to));
  end;


  disk_nro: proc (m) returns (fixed bin (31));
    dcl m bit (*);
    dcl i fixed bin;

    do i = length(m) to 1 by -1;
      if substr(m, i, 1) then
        return (length(m) - i + 1);
    end;

    return (i + 1);
  end disk_nro;


  ltrim: proc (buf) returns (char (32767) varying);
    dcl buf char (*);

    buf = substr(buf, verify(buf, ' '), length(buf) - verify(buf, ' ') + 1);

    return (buf);
  end ltrim;


 end hanoi;

OS/2 käyttäjät voivat kokeilla alla olevaa graafisesti siirrot näyttävää PM-ohjelmaa. Kysessä on Iron Spring kääntäjän mukana tuleva esimerkkiohjelma, jonka muokkasin käyttämään binääriratkaisua rekursiivisen ratkaisun sijaan. Korjasin myös hiukan levyjen piirron kohdistusta.

/* PMHanoi: Towers of Hanoi                              */
/*                                                       */
/* This one is Iron Spring PL/I sample program           */
/* modified to use binary solution instead of recursive. */


 pmhanoi: package;

   %replace NUMBER_OF_DISKS by 5;

   %replace NULLHANDLE     by 0;

   /*--------------------------------*/
   /* Package Static data            */
   /*--------------------------------*/
   dcl   hab                 fixed bin(31)  static;
   dcl   hmq                 fixed bin(31)  static;
   dcl   hwndFrame           fixed bin(31)  static;
   dcl   qmsg                like qmsg_type static;

   dcl 1 scrn_resolution     static,
         2 horz_resolution   fixed bin(31),
         2 vert_resolution   fixed bin(31);

   dcl   WindowText          char(32)       static    varying
             init( 'Iron Spring Software, 2010' );
   dcl   WindowTextbox  (0:3)like pointl_type static;
   %replace TXTBOX_TOPLEFT      by 0;
   %replace TXTBOX_BOTTOMLEFT   by 1;
   %replace TXTBOX_TOPRIGHT     by 2;
   %replace TXTBOX_BOTTOMRIGHT  by 3;
   %replace TXTBOX_CONCAT       by 4;

   /*--------------------------------*/
   /* Standard Window handles        */
   /*--------------------------------*/
   %replace HWND_DESKTOP        by 1;
   %replace HWND_OBJECT         by 2;
   %replace HWND_TOP            by 3;
   %replace HWND_BOTTOM         by 4;
   %replace HWND_THREADCAPTURE  by 5;

   /*--------------------------------*/
   /* Window Messages                */
   /*--------------------------------*/
   %replace WM_NULL             by  0;
   %replace WM_CREATE           by  1;
   %replace WM_DESTROY          by  2;
   %replace WM_ENABLE           by  4;
   %replace WM_SHOW             by  5;
   %replace WM_MOVE             by  6;
   %replace WM_SIZE             by  7;
   %replace WM_SYSCOMMAND       by 33;
   %replace WM_PAINT            by 35;
   %replace WM_TIMER            by 36;
   %replace WM_CLOSE            by 41;
   %replace WM_QUIT             by 42;
   %replace WM_ERASEBACKGROUND  by 79;

   /*--------------------------------*/
   /* Frame Creation Flags           */
   /*--------------------------------*/
   %replace FCF_HORZSCROLL           by '80000000'bx;
   %replace FCF_VERTSCROLL           by '40000000'bx;
   %replace FCF_MINMAX               by '30000000'bx;
   %replace FCF_MAXBUTTON            by '20000000'bx;
   %replace FCF_MINBUTTON            by '10000000'bx;
   %replace FCF_SIZEBORDER           by '08000000'bx;
   %replace FCF_MENU                 by '04000000'bx;
   %replace FCF_SYSMENU              by '02000000'bx;
   %replace FCF_TITLEBAR             by '01000000'bx;
   %replace FCF_ACCELTABLE           by '00800000'bx;
   %replace FCF_ICON                 by '00400000'bx;
   %replace FCF_NOMOVEWITHOWNER      by '00200000'bx;
   %replace FCF_NOBYTEALIGN          by '00100000'bx;
   %replace FCF_TASKLIST             by '00080000'bx;
   %replace FCF_SHELLPOSITION        by '00040000'bx;
   %replace FCF_BORDER               by '00020000'bx;
   %replace FCF_DLGBORDER            by '00010000'bx;
   %replace FCF_PALLETTE_POPUPEVEN   by '00004000'bx;
   %replace FCF_PALLETTE_POPUPODD    by '00002000'bx;
   %replace FCF_PALLETTE_HELP        by '00001000'bx;
   %replace FCF_PALLETTE_NORMAL      by '00000800'bx;
   %replace FCF_PALLETTE_MOUSEALIGN  by '00000400'bx;
   %replace FCF_PALLETTE_SCREENALIGN by '00000200'bx;
   %replace FCF_SYSMODAL             by '00000100'bx;
   %replace FCF_DBE_APPSTAT          by '00000080'bx;
   %replace FCF_AUTOICON             by '00000040'bx;
   %replace FCF_HIDEBUTTON           by '00000001'bx;
   %replace FCF_HIDEMAX              by '20000001'bx;
   %replace FCF_STANDARD             by '3FCC0000'bx;

   /*--------------------------------*/
   /* Window Styles                  */
   /*--------------------------------*/
   %replace WS_VISIBLE        by '00000080'bx;
   %replace WS_DISABLED       by '00000040'bx;
   %replace WS_CLIPCHILDREN   by '00000020'bx;
   %replace WS_CLIPSIBLINGS   by '00000010'bx;
   %replace WS_PARENTCLIP     by '00000008'bx;
   %replace WS_SAVEBITS       by '00000004'bx;
   %replace WS_SYNCPAINT      by '00000002'bx;
   %replace WS_MINIMIZED      by '00000001'bx;
   %replace WS_MAXIMIZED      by '00008000'bx;
   %replace WS_ANIMATE        by '00004000'bx;
   %replace WS_GROUP          by '00010000'bx;
   %replace WS_TABSTOP        by '00020000'bx;
   %replace WS_MULTISELECT    by '00040000'bx;

   /*--------------------------------*/
   /* Colors                         */
   /*--------------------------------*/
   %replace CLR_ERROR           by -255;
   %replace CLR_NOINDEX         by -254;
   %replace CLR_FALSE           by   -5;
   %replace CLR_TRUE            by   -4;
   %replace CLR_DEFAULT         by   -3;
   %replace CLR_WHITE           by   -2;
   %replace CLR_BLACK           by   -1;
   %replace CLR_BACKGROUND      by    0;
   %replace CLR_BLUE            by    1;
   %replace CLR_RED             by    2;
   %replace CLR_PINK            by    3;
   %replace CLR_GREEN           by    4;
   %replace CLR_CYAN            by    5;
   %replace CLR_YELLOW          by    6;
   %replace CLR_NEUTRAL         by    7;
   %replace CLR_DARKGRAY        by    8;
   %replace CLR_DARKBLUE        by    9;
   %replace CLR_DARKRED         by   10;
   %replace CLR_DARKPINK        by   11;
   %replace CLR_DARKGREEN       by   12;
   %replace CLR_DARKCYAN        by   13;
   %replace CLR_BROWN           by   14;
   %replace CLR_PALEGRAY        by   15;

   /*--------------------------------*/
   /* Prototypes                     */
   /*--------------------------------*/
   dcl   VarStr              char(0)   varying   based;

   dcl 1 qmsg_type           unaligned based,
         2 hwnd              fixed bin(31),
         2 msg               fixed bin(15),
         2 mp1               ptr,
         2 mp2               ptr,
         2 time              fixed bin(31),
         2 ptl,
           3 x               fixed bin(31),
           3 y               fixed bin(31),
         2 reserved          fixed bin(31);

   dcl 1 rectl_type          unaligned based,
         2 xLeft             fixed bin(31),
         2 yBottom           fixed bin(31),
         2 xRight            fixed bin(31),
         2 yTop              fixed bin(31);

   dcl 1 pointl_type         unaligned based,
         2 x                 fixed bin(31),
         2 y                 fixed bin(31);


   /*--------------------------------*/
   /* GPI Functions                  */
   /*--------------------------------*/
   dcl GpiCharStringAt       entry( fixed bin(31), ptr,
                                    fixed bin(31), ptr )
                             ext( 'GpiCharStringAt' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );
   dcl GpiQueryTextBox       entry( fixed bin(31), fixed bin(31), ptr,
                                    fixed bin(31), ptr )
                             ext( 'GpiQueryTextBox' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );

   /*--------------------------------*/
   /* Device Functions               */
   /*--------------------------------*/
   dcl DevQueryCaps          entry( fixed bin(31), fixed bin(31),
                                    fixed bin(31), ptr )
                             ext( 'DevQueryCaps' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );

   /*--------------------------------*/
   /* PM Functions                   */
   /*--------------------------------*/
   dcl WinBeginPaint         entry( fixed bin(31), ptr, ptr )
                             ext( 'WinBeginPaint' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );
   dcl WinCalcFrameRect      entry( fixed bin(31), ptr, fixed bin(31) )
                             ext( 'WinCalcFrameRect' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );
   dcl WinCreateMsgQueue     entry( fixed bin(31), fixed bin(31) )
                             returns( fixed bin(31) )
                             ext( 'WinCreateMsgQueue' )
                             options( asm byvalue linkage(system) );
   dcl WinCreateStdWindow    entry( fixed bin(31),/* hwndParent      */
                                    bit(32),      /* flStyle         */
                                    ptr,          /* pflCreateFlags  */
                                    ptr,          /* pszClassClient  */
                                    ptr,          /* pszTitle        */
                                    bit(32),      /* flStyleClient   */
                                    fixed bin(31),/* Resource        */
                                    fixed bin(31),/* ulId            */
                                    ptr )         /* phwndClient     */
                             returns( fixed bin(31) )
                             ext( 'WinCreateStdWindow' )
                             options( asm byvalue linkage(system) );
   dcl WinDefWindowProc      entry( fixed bin(31),/* HWND            */
                                    fixed bin(31),/* MSG             */
                                    ptr,          /* MP1             */
                                    ptr )         /* MP2             */
                             returns( ptr )
                             ext( 'WinDefWindowProc' )
                             options( asm byvalue linkage(system) );
   dcl WinDestroyMsgQueue    entry( fixed bin(31) )
                             returns( fixed bin(31) )
                             ext( 'WinDestroyMsgQueue' )
                             options( asm byvalue linkage(system) );
   dcl WinDestroyWindow      entry( fixed bin(31) )
                             returns( fixed bin(31) )
                             ext( 'WinDestroyWindow' )
                             options( asm byvalue linkage(system) );
   dcl WinDispatchMsg        entry( fixed bin(31),/* HAB             */
                                    ptr )         /* &qmsg           */
                             returns( fixed bin(31) )
                             ext( 'WinDispatchMsg' )
                             options( asm byvalue linkage(system) );
   dcl WinDrawText           entry( fixed bin(31), fixed bin(31), ptr, ptr,
                                    fixed bin(31), fixed bin(31), bit(32) )
                             ext( 'WinDrawText' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );
   dcl WinEndPaint           entry( fixed bin(31) )
                             ext( 'WinEndPaint' )
                             options( asm byvalue linkage(system) );
   dcl WinFillRect           entry( fixed bin(31), ptr, fixed bin(31) )
                             ext( 'WinFillRect' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );
   dcl WinGetLastError       entry( fixed bin(31) )
                             returns( fixed bin(31) )
                             ext( 'WinGetLastError' )
                             options( asm byvalue linkage(system) );
   dcl WinGetMsg             entry( fixed bin(31),/* HAB             */
                                    ptr,          /* &qmsg           */
                                    fixed bin(31),/* HWND            */
                                    fixed bin(31),/* ulFirst         */
                                    fixed bin(31) )/* ulLast         */
                             returns( fixed bin(31) )
                             ext( 'WinGetMsg' )
                             options( asm byvalue linkage(system) );
   dcl WinGetScreenPS        entry( fixed bin(31) )
                             returns( fixed bin(31) )
                             ext( 'WinGetScreenPS' )
                             options( asm byvalue linkage(system) );
   dcl WinInitialize         entry( fixed bin(31) )
                             returns( fixed bin(31) )
                             ext( 'WinInitialize' )
                             options( asm byvalue linkage(system) );
   dcl WinInvalidateRegion   entry( fixed bin(31), fixed bin(31),
                                    fixed bin(31) )
                             returns( fixed bin(31) )
                             ext( 'WinInvalidateRegion' )
                             options( asm byvalue linkage(system) );
   dcl WinMapWindowPoints    entry( fixed bin(31), fixed bin(31), ptr,
                                    fixed bin(31) )
                             ext( 'WinMapWindowPoints' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );
   dcl WinOpenWindowDC       entry( fixed bin(31) )
                             ext( 'WinOpenWindowDC' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );
   dcl WinQueryWindowDC      entry( fixed bin(31) )
                             ext( 'WinQueryWindowDC' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );
   dcl WinPostMsg            entry( fixed bin(31), fixed bin(31),
                                    fixed bin(31),
                                    fixed bin(31) )
                             ext( 'WinPostMsg' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );
   dcl WinQueryClassInfo     entry( fixed bin(31), /* HAB */
                                    ptr,           /* pszClassName */
                                    ptr )          /* pClsiClassInfo */
                             returns( fixed bin(31) )
                             ext( 'WinqueryClassInfo' )
                             options( asm byvalue linkage(system) );
   dcl WinQueryWindowRect    entry( fixed bin(31), ptr )
                             ext( 'WinQueryWindowRect' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );
   dcl WinRegisterClass      entry( fixed bin(31),/* HAB             */
                                    ptr,          /* pszClassName    */
                                    entry,        /* pfnWindowProc   */
                                    bit(32),      /* flStyle         */
                                    fixed bin(31) )/* cbWindowData   */
                             returns( fixed bin(31) )
                             ext( 'WinRegisterClass' )
                             options( asm byvalue linkage(system) );
   dcl WinSetWindowPos       entry( fixed bin(31), fixed bin(31),
                                    fixed bin(31), fixed bin(31),
                                    fixed bin(31), fixed bin(31),
                                    bit(32) )
                             ext( 'WinSetWindowPos' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );
   dcl WinShowWindow         entry( fixed bin(31), fixed bin(31) )
                             ext( 'WinShowWindow' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );
   dcl WinStartTimer         entry( fixed bin(31), fixed bin(31),
                                    fixed bin(31), fixed bin(31)  )
                             ext( 'WinStartTimer' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );
   dcl WinStopTimer          entry( fixed bin(31), fixed bin(31),
                                    fixed bin(31)  )
                             ext( 'WinStopTimer' )
                             returns( fixed bin(31) )
                             options( asm byvalue linkage(system) );
   dcl WinTerminate          entry( fixed bin(31) )
                             returns( fixed bin(31) )
                             ext( 'WinTerminate' )
                             options( asm byvalue linkage(system) );
   dcl WinWindowFromID       entry( fixed bin(31), fixed bin(31) )
                             returns( fixed bin(31) )
                             ext( 'WinWindowFromID' )
                             options( asm byvalue linkage(system) );

   dcl  ( addr,
          allocate,
          ceil,
          heximage,
          length,
          null,
          stg,
          sysnull
        )                    builtin;

 /********************************************************************/
 /* Main Procedure                                                   */
 /********************************************************************/

 main: proc options(main);

   /*--------------------------------*/
   /* Automatic Data                 */
   /*--------------------------------*/
   dcl   RC                  fixed bin(31);
   dcl   hwndClient          fixed bin(31);
   dcl  (tbl_cur,tbl_size)   fixed bin(31);
   dcl   rectlClient         like rectl_type;
   dcl   rectlFrame          like rectl_type;
   dcl   window_title        char(64);
   dcl   window_class        char(64);

   dcl   flFrameFlags        bit(32) init(
             FCF_MINBUTTON     | FCF_SYSMENU   |
             FCF_TITLEBAR      | FCF_TASKLIST  |
             FCF_SHELLPOSITION | FCF_BORDER );

   dcl   wsWindowStyle       bit(32)  init( '00000000'bx );


   /*---------------------------------*/
   /* Initialize PM control blocks    */
   /*---------------------------------*/
   hab = Wininitialize(0);
   hmq = WinCreateMsgQueue(hab,0);
   scrn_resolution=0;
   call get_screen_resolution;

   RC = GpiQueryTextBox( WinGetScreenPS(HWND_DESKTOP),
                         length(WindowText),
                         addr(WindowText)+stg(null()->VarStr),
                         4,
                         addr(WindowTextbox) );
   if RC=0 then do;
     RC = WinGetLastError(hab);
     display( 'GpiQueryTextBox returned ' || heximage(addr(RC),2) );
     return;
     end;

   window_title = 'Towers of Hanoi' || '00'x;
   window_class = 'HANOICLASS' || '00'x;

   RC = WinRegisterClass( hab, addr(window_class),
                          client,
                          '00000000'bx, 0 );

   if RC=0 then do;
     RC = WinGetLastError(hab);
     display( 'WinRegisterClass returned ' || heximage(addr(RC),2) );
     return;
     end;

   hwndFrame = WinCreateStdWindow( HWND_DESKTOP,       /* hwndParent     */
                                   wsWindowStyle,      /* flStyle        */
                                   addr(flFrameFlags), /* pflCreateFlags */
                                   addr(window_class), /* pszClassClient */
                                   addr(window_title), /* pszTitle       */
                                   '00000000'bx,       /* flStyleClient  */
                                   0,                  /* Resource       */
                                   0,                  /* ulId           */
                                   addr(hwndClient) ); /* phwndClient    */

  if hwndFrame=0 then do;
    RC = WinGetLastError(hab);
    display( 'WinCreateStdWindow returned ' || heximage(addr(RC),2) );
    return;
    end;

  /*-----------------*/
  /* Size the window */
  /*-----------------*/
  rectlClient.xleft   = 0;
  rectlClient.ybottom = 0;
  rectlClient.xright  = 22*horz_resolution;
  rectlClient.ytop    = ceil( NUMBER_OF_DISKS*vert_resolution ) +
                        4*vert_resolution;
  rectlClient.ytop    = rectlClient.ytop + WindowTextbox(2).y -
                        WindowTextbox(1).y;
  rectlFrame = rectlClient;
  RC = WinMapWindowPoints( hwndClient, HWND_DESKTOP, addr(rectlFrame), 2 );
  if RC=0
  then display( 'WinMapWindowPoints RC=' || heximage(addr(RC),4) );
  RC = WinCalcFrameRect( hwndFrame, addr(rectlFrame), 0 );
  if RC=0
  then display( 'WinCalcFrameRect RC=' || heximage(addr(RC),4) );
  /* Window Positioning Options */
  %replace SWP_SIZE   by '01000000'bx;
  %replace SWP_MOVE   by '02000000'bx;
  %replace SWP_ZORDER by '04000000'bx;
  %replace SWP_SHOW   by '08000000'bx;
  RC = WinSetWindowPos( hwndFrame, 0, 0, 0,
                        rectlFrame.xright, rectlFrame.ytop,
                        SWP_SIZE|SWP_SHOW );
  if RC=0
  then display( 'WinSetWindowPos RC=' || heximage(addr(RC),4) );
  RC = WinShowWindow( hwndFrame, 1 );

  /*------------------------*/
  /* Message Loop           */
  /*------------------------*/
  do while( '1'b );
     RC = WinGetMsg(hab,addr(qmsg),0,0,0);
     if rc=0 then leave;
     RC = WinDispatchMsg(hab,addr(qmsg));
     end; /* do while */

   RC = WinDestroyWindow(hwndFrame);
   RC = WinDestroyMsgQueue(hmq);
   RC = Winterminate(hab);
   return;

   end main;

 /*------------------------------------------------------------------*/
 /* Client window procedure                                          */
 /*------------------------------------------------------------------*/
 client: proc(hwnd,msg,mp1,mp2)
         returns( ptr )
         options(fromalien linkage(system) );

   dcl   hwnd                fixed bin(31);
   dcl   msg                 fixed bin(15);
   dcl  (mp1,mp2)            ptr;

   dcl   RC                  fixed bin(31);
   dcl   hps                 fixed bin(31);
   dcl   text_height         fixed bin(31);
   dcl 1 rectlPaint          like rectl_type;

   dcl 1 disks       (NUMBER_OF_DISKS)           static,
         2 size              fixed bin(31),
         2 color             fixed bin(31);
   dcl 1 peg              (3)                    static,
         2 pos               like pointl_type,
         2 n                 fixed bin(31),
         2 disk           (5)fixed bin(31);

   dcl   idTimer             fixed bin (31)      static;
   dcl   move                fixed bin (31)      static;
   dcl   (from, to)          fixed bin (7);
   dcl   disks_on_pegs       bit (31);


   select ( msg );

    when( WM_CREATE ) do;
      text_height = WindowTextbox(2).y - WindowTextbox(1).y;
      disks(1).color = CLR_RED;
      disks(2).color = CLR_YELLOW;
      disks(3).color = CLR_GREEN;
      disks(4).color = CLR_BLUE;
      disks(5).color = CLR_PINK;
      disks(1).size  = 2;
      disks(2).size  = 3;
      disks(3).size  = 4;
      disks(4).size  = 5;
      disks(5).size  = 6;
      /* disk(n) is on top */
      peg(1).n       = 5;
      peg(1).disk(1) = 5;
      peg(1).disk(2) = 4;
      peg(1).disk(3) = 3;
      peg(1).disk(4) = 2;
      peg(1).disk(5) = 1;
      peg(2).n       = 0;
      peg(3).n       = 0;
      peg(1).x       = 4*horz_resolution;
      peg(1).y       = vert_resolution + text_height-1;
      peg(2).x       = 11*horz_resolution;
      peg(2).y       = peg(1).y;
      peg(3).x       = 18*horz_resolution;
      peg(3).y       = peg(1).y;
      move = 1;
      return( sysnull() );
      end; /* WM_CREATE */

    when( WM_PAINT ) do;
      text_height = WindowTextbox(2).y - WindowTextbox(1).y;
      hps = WinBeginPaint( hwnd, sysnull(), sysnull() );
       /* Background fill    */
      call WinQueryWindowRect( hwnd, addr(rectlPaint) );
      call WinFillRect( hps, addr(rectlPaint), CLR_WHITE );
      /* Draw baseline       */
      rectlPaint.xleft   = horz_resolution;
      rectlPaint.ybottom = ceil(vert_resolution/2) + text_height;
      rectlPaint.xright  = 21*horz_resolution;
      rectlPaint.ytop    = peg(1).y;
      call WinFillRect( hps, addr(rectlPaint), CLR_BLACK );
      /* Draw pegs           */
      rectlPaint.xleft   = 4*horz_resolution-ceil(horz_resolution/2);
      rectlPaint.ybottom = peg(1).y;
      rectlPaint.xright  = rectlPaint.xleft+horz_resolution;
      rectlPaint.ytop    = rectlPaint.ytop +
                           (NUMBER_OF_DISKS+1)*vert_resolution;
      call WinFillRect( hps, addr(rectlPaint), CLR_BLACK );
      rectlPaint.xleft   = 11*horz_resolution-ceil(horz_resolution/2);
      rectlPaint.xright  = rectlPaint.xleft+horz_resolution;
      call WinFillRect( hps, addr(rectlPaint), CLR_BLACK );
      rectlPaint.xleft   = 18*horz_resolution-ceil(horz_resolution/2);
      rectlPaint.xright  = rectlPaint.xleft+horz_resolution;
      call WinFillRect( hps, addr(rectlPaint), CLR_BLACK );
      call display_disks;
      /* Display the text - note that the textbox may not start at   */
      /* (0,0) because textbox allows for descenders.                */
      rectlPaint.xleft   = horz_resolution;
      rectlPaint.ybottom = -WindowTextbox(1).y;
      RC = GpiCharStringAt( hps,
                            addr(rectlPaint),
                            length(WindowText),
                            addr(WindowText)+stg(null()->VarStr) );
      call WinEndPaint( hps );
      /* Set timer for two-second delay */
      idTimer = WinStartTimer( hab, hwnd, 1, 2000 );
      return( sysnull() );
      end; /* WM_PAINT */

    when( WM_TIMER ) do;
      if move < 2**NUMBER_OF_DISKS then do;
        disks_on_pegs = bit(move);
        from = disks_on_pegs & disks_on_pegs - '1'b;
        from = mod(from, 3) + 1;
        to = (disks_on_pegs | (disks_on_pegs - '1'b)) +  1;
        to = mod(to, 3) + 1;
        /* Move one disk */
        call move_disk(from, to);
        move = move + 1;
        /* Don't restart the timer after last move */
        if move < 2**NUMBER_OF_DISKS then do;
          idTimer = WinStartTimer( hab, hwnd, 1, 2000 );
          end;
        /* Repaint the window */
        RC = WinInvalidateRegion( hwnd, NULLHANDLE, 0 );
        end;
      return( sysnull() );
      end; /* WM_TIMER */
    when( WM_CLOSE ) do;
      call WinPostMsg( hwnd, WM_QUIT, 0, 0 );
      return( sysnull() );
      end; /* WM_CLOSE */

    otherwise do;
      return( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
      end;

    end; /* select */

  /* Display the disks */
   display_disks: proc;
     dcl (i,j,k)              fixed bin(31);
     dcl  rectlDisk           like rectl_type;
     do i=1 to 3;
       do j=1 to peg(i).n;
         k = peg(i).disk(j);
         rectlDisk.xleft = peg(i).x -
                          ceil( (disks(k).size*horz_resolution)/2 );
         rectlDisk.ybottom = peg(i).y + (j-1)*vert_resolution;
         rectlDisk.xright = rectlDisk.xleft +
                           disks(k).size*horz_resolution;
         rectlDisk.ytop   = rectlDisk.ybottom + horz_resolution - (NUMBER_OF_DISKS - 1);
         call WinFillRect( hps, addr(rectlDisk), disks(k).color );
         end; /* do j */
       end; /* do i */
   end display_disks;

   /* Move one disk */
   move_disk: proc(f,t);
     dcl (f,t)                fixed bin(7);
     dcl  d                   fixed bin(31);
     dcl  i                   fixed bin(31);
     d = peg(f).disk(peg(f).n);         /* Get top disk on 'from' peg */
     peg(f).n = peg(f).n-1;             /* One less disk there        */
     peg(t).n = peg(t).n+1;             /* One more on 'to' peg       */
     peg(t).disk(peg(t).n) = d;         /* Move to 'to'               */
   end move_disk;

  end client;


  /* Get the screen resolution in pels per 200mm */
  /* This is the drawing unit used throughout.   */
  get_screen_resolution: proc;
    dcl  screen_dc           fixed bin(31);
    dcl  RC                  fixed bin(31);

    screen_dc = WinOpenWindowDC(HWND_DESKTOP);
    %replace CAPS_HORIZONTAL_RESOLUTION by 8;
    RC = DevQueryCaps( screen_dc, CAPS_HORIZONTAL_RESOLUTION,
                       2, addr(scrn_resolution) );
    horz_resolution = horz_resolution / 200;
    vert_resolution = vert_resolution / 200;
  end get_screen_resolution;

  end pmhanoi;

Metabolix [19.02.2012 17:42:29]

#

Saisit kuvailla tehtävän lisäksi myös sitä ratkaisua vähän, vaikka kuinka löytyisi Wikipediasta. Linkkikin olisi kiva.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta