home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Programming / C / OTL-MC5.DMS / in.adf / EO-Demos.lha / EasyObjects-Demos / Hanoi / hanoi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-31  |  9.2 KB  |  375 lines

  1. // hanoi.c
  2. //
  3. // Eine nette interaktive Variante der Türme von Hanoi.
  4. //
  5. // Autor: Jochen Becher
  6.  
  7. #include <classes/layouter/windows.h>
  8. #include <classes/layouter/boopsigadgets.h>
  9. #include <classes/layouter/decorgadgets.h>
  10. #include <classes/exec/libraries.h>
  11. #pragma header
  12.  
  13. #include <pragma/intuition_lib.h>
  14.  
  15. // *************************************************************
  16.  
  17. // Die Klasse TurmGeometryC übernimmt die Verwaltung der Geometrien in den
  18. // Türmen
  19. class TurmGeometryC : public GeometryGroupC {
  20. public:
  21.     TurmGeometryC(
  22.         GroupLayoutC &frame,
  23.         ULONG topRelation, GeometryC *topObject, WORD topOffset,
  24.         ULONG bottomRelation, GeometryC *bottomObject, WORD bottomOffset,
  25.         ULONG leftRelation, GeometryC *leftObject, WORD leftOffset,
  26.         ULONG rightRelation, GeometryC *rightObject, WORD rightOffset);
  27.     // Eine Geometrie als oberste auf den Turm legen und das dazugehörige
  28.     // Gadget enablen
  29.     VOID add(GeometryC &);
  30.     // Das oberste Element vom Turm nehemn, und das darunterliegende Gadget
  31.     // enablen
  32.     GeometryC *rem();
  33.     // Das oberste Element zurückgeben
  34.     GeometryC *topElement();
  35. };
  36.  
  37. TurmGeometryC::TurmGeometryC(
  38.         GroupLayoutC &frame,
  39.         ULONG topRelation, GeometryC *topObject, WORD topOffset,
  40.         ULONG bottomRelation, GeometryC *bottomObject, WORD bottomOffset,
  41.         ULONG leftRelation, GeometryC *leftObject, WORD leftOffset,
  42.         ULONG rightRelation, GeometryC *rightObject, WORD rightOffset)
  43.     : GeometryGroupC(frame,
  44.        topRelation,topObject,topOffset,
  45.        bottomRelation,bottomObject,bottomOffset,
  46.        leftRelation,leftObject,leftOffset,
  47.        rightRelation,rightObject,rightOffset)
  48. {
  49. }
  50.  
  51. VOID TurmGeometryC::add(GeometryC &g)
  52. {
  53.     ListCursorC lc(*this);
  54.     lc.last();
  55.     if (lc.isDone())
  56.     {
  57.         // Das erste Element wird unten an die Gruppe geklebt
  58.         g.setBottomRule(LAYOUT_GROUP,NULL,0);
  59.     }
  60.     else {
  61.         // Das oberste Element wird disabled
  62.         ((LGButtonC *) ((GeometryC *) lc.item())->layoutObject())->disable(TRUE);
  63.         // Das neue Element wird auf das oberste geklebt
  64.         g.setBottomRule(LAYOUT_OPPBORDER,(GeometryC *) lc.item(),-2);
  65.     };
  66.     g.setTopRule(LAYOUT_SIZE,NULL,0);
  67.     // Das neue oberste wird enabled
  68.     ((LGButtonC *) g.layoutObject())->disable(FALSE);
  69.     GeometryGroupC::add(g);
  70. }
  71.  
  72. GeometryC *TurmGeometryC::rem()
  73. {
  74.     // Das oberste Element wird entfernt
  75.     GeometryC *g = (GeometryC *) remTail();
  76.     if (g)
  77.     {
  78.         ListCursorC lc(*this);
  79.         lc.last();
  80.         if (!lc.isDone())
  81.         {
  82.             // Das neue oberste wird enabled
  83.             ((LGButtonC *) ((GeometryC *) lc.item())->layoutObject())->disable(FALSE);
  84.         };
  85.     };
  86.     return g;
  87. }
  88.  
  89. GeometryC *TurmGeometryC::topElement()
  90. {
  91.     ListCursorC lc(*this);
  92.     lc.last();
  93.     return (GeometryC *) lc.item();
  94. };
  95.  
  96. // *************************************************************
  97.  
  98. // Jede Scheibe ist ein Button, die mittels dieser Klasse reagiert
  99. class ScheibenEventC : public GadgetEventC {
  100. public:
  101.     ScheibenEventC() : GadgetEventC(), meinTurm(NULL) { };
  102.     VOID up(WindowC *, GadgetC *, IntuiMessageC * );
  103.     VOID setTurm(TurmGeometryC *t) { meinTurm = t; };
  104. private:
  105.     TurmGeometryC *meinTurm;
  106. };
  107.  
  108. // *************************************************************
  109.  
  110. // Diese Klasse erzeugt alle Geometrien und Gadgets für das Spiel
  111. class ScheibenkisteC : public GadgetListC {
  112. public:
  113.     ScheibenkisteC(WindowC &, ULONG anzahl);
  114.     ~ScheibenkisteC();
  115.     GeometryC *get(ULONG i);
  116.     ULONG anzahl() { return maxanz; };
  117. private:
  118.     arraylist<GeometryC *> scheiben;
  119.     ULONG maxanz;
  120.     stringarray beschriftung;
  121. };
  122.  
  123. ScheibenkisteC::ScheibenkisteC(WindowC &w, ULONG anzahl)
  124.     : GadgetListC(),
  125.       scheiben(anzahl),
  126.       maxanz(anzahl),
  127.       beschriftung("1","2","3","4","5",NULL)
  128. {
  129.     // Höchstens 5 Scheiben sind erlaubt
  130.     if (maxanz > 5)
  131.         throw Exception();
  132.     ULONG i;
  133.     for (i = 0; i < maxanz; i++)
  134.     {
  135.         ScheibenEventC *ev = new ScheibenEventC();
  136.         if (!ev)
  137.             throw MemoryX(sizeof(ScheibenEventC));
  138.         LBIButtonC *b = new LBIButtonC (ev,w,LAYOUT_AUTOSIZE,LAYOUT_AUTOSIZE,
  139.             GA_Text, beschriftung[i],
  140.             GA_RelVerify, TRUE,
  141.             TAG_END);
  142.         if (!b)
  143.             throw MemoryX(sizeof(LBIButtonC));
  144.         GadgetListC::add(*b);
  145.         GeometryC *g = new GeometryC (*b,
  146.             LAYOUT_GROUP,NULL,0,LAYOUT_SIZE,NULL,0,
  147.             LAYOUT_PROCENT,NULL,5 + i*10,LAYOUT_PROCENT,NULL,95 - i*10);
  148.         if (!g)
  149.             throw MemoryX(sizeof(GeometryC));
  150.         scheiben.addTail() = g;
  151.     };
  152. }
  153.  
  154. ScheibenkisteC::~ScheibenkisteC()
  155. {
  156.     arraycursor<GeometryC *> ac(scheiben);
  157.     while (!ac.isDone())
  158.     {
  159.         GeometryC *g = ac.item();
  160.         if (g)
  161.         {
  162.             LBIButtonC *b = (LBIButtonC *) g->layoutObject();
  163.             delete g;
  164.             if (b)
  165.             {
  166.                 delete b;
  167.             };
  168.         };
  169.         ac.next();
  170.     };
  171. }
  172.  
  173. GeometryC *ScheibenkisteC::get(ULONG i)
  174. {
  175.     if (i >= maxanz)
  176.         return NULL;
  177.     return scheiben[i];
  178. }
  179.  
  180. // *************************************************************
  181.  
  182. class HanoiWindowC : public StandardWindowC {
  183. public:
  184.     HanoiWindowC(GTIDCMPortC &, ScreenC &);
  185.     ~HanoiWindowC();
  186.     VOID open();
  187.     TurmGeometryC *zumNaechsten(TurmGeometryC *, LayoutC *);
  188. private:
  189.     LBBevelboxC linksRand,mitteRand,rechtsRand;
  190.     TurmGeometryC links,mitte,rechts;
  191.     TransparentLayoutC minimum;
  192.     GeometryC minimumG;
  193.     ScheibenkisteC scheiben;
  194.     WindowCloseHandlerC wch;
  195. };
  196.  
  197. HanoiWindowC::HanoiWindowC(GTIDCMPortC &p, ScreenC &s)
  198.     : StandardWindowC(p,s,NULL,
  199.       WA_IDCMP,IDCMP_GADGETUP,
  200.       WA_Title,"Die Türme von Hanoi",
  201.       TAG_END),
  202.       linksRand(*this,"von",NULL,LAYOUT_AUTOSIZE,LAYOUT_AUTOSIZE,
  203.         TAG_END),
  204.       mitteRand(*this,"über",NULL,LAYOUT_AUTOSIZE,LAYOUT_AUTOSIZE,
  205.         TAG_END),
  206.       rechtsRand(*this,"nach",NULL,LAYOUT_AUTOSIZE,LAYOUT_AUTOSIZE,
  207.         TAG_END),
  208.       links(linksRand,
  209.        LAYOUT_GROUP,NULL,0,LAYOUT_GROUP,NULL,0,
  210.        LAYOUT_GROUP,NULL,0,LAYOUT_PROCENT,NULL,33),
  211.       mitte(mitteRand,
  212.        LAYOUT_GROUP,NULL,0,LAYOUT_GROUP,NULL,0,
  213.        LAYOUT_OPPBORDER,&links,2,LAYOUT_PROCENT,NULL,66),
  214.       rechts(rechtsRand,
  215.        LAYOUT_GROUP,NULL,0,LAYOUT_GROUP,NULL,0,
  216.        LAYOUT_OPPBORDER,&mitte,2,LAYOUT_GROUP,NULL,0),
  217.       minimum(0,0),
  218.       minimumG(minimum,
  219.        LAYOUT_GROUP,NULL,0,LAYOUT_GROUP,NULL,0,
  220.        LAYOUT_GROUP,NULL,0,LAYOUT_GROUP,NULL,0),
  221.       scheiben(*this,3),
  222.       wch(*this)
  223. {
  224.     // Alle Scheiben werden auf den ersten Turm gelegt
  225.     ULONG i;
  226.     for (i = 0; i < scheiben.anzahl(); i++)
  227.     {
  228.         if (scheiben.get(i))
  229.         {
  230.             ((ScheibenEventC *) ((LBIButtonC *) scheiben.get(i)
  231.                 ->layoutObject())->event())->setTurm(&links);
  232.             links.add(*scheiben.get(i));
  233.         };
  234.     };
  235.     titlegadgets.add(linksRand);
  236.     titlegadgets.add(mitteRand);
  237.     titlegadgets.add(rechtsRand);
  238.     gadgets.add(scheiben);
  239.     innerGeo.add(links);
  240.     innerGeo.add(mitte);
  241.     innerGeo.add(rechts);
  242.     innerGeo.add(minimumG);
  243. }
  244.  
  245. HanoiWindowC::~HanoiWindowC()
  246. {
  247.     close();
  248. }
  249.  
  250. VOID HanoiWindowC::open()
  251. {
  252.     StandardWindowC::open();
  253.     // Dieser Trick "speichert" die Breite des ersten Layouts für weitere
  254.     // Layoutberechnungen, d.h. die Breite und Höhe des Elements minimum
  255.     // wird ab jetzt ein Minimum für jede Layoutberechnung sein.
  256.     minimumG.setBottomRule(LAYOUT_SIZE,NULL,0);
  257.     minimumG.setRightRule(LAYOUT_SIZE,NULL,0);
  258. }
  259.  
  260. TurmGeometryC *HanoiWindowC::zumNaechsten(TurmGeometryC *turm, LayoutC *lay)
  261. {
  262.     if (turm && lay)
  263.     {
  264.         // Zuerst ein paar Sicherheitstests, ob das Element das oberste auf
  265.         // dem angegeben Turm ist.
  266.         GeometryC *me = turm->topElement();
  267.         if (!me)
  268.             return NULL;
  269.         if (me->layoutObject() != lay)
  270.             return NULL;
  271.         TurmGeometryC *neuerturm = NULL;
  272.         TurmGeometryC *alterturm = turm;
  273.         while (TRUE)
  274.         {
  275.             // Den neuen Turm suchen
  276.             if (turm == &links)
  277.                 neuerturm = &mitte
  278.             else if (turm == &mitte)
  279.                 neuerturm = &rechts
  280.             else if (turm == &rechts)
  281.                 neuerturm = &links;
  282.             // Kein Turm besetzt (sollte nie passieren) oder einmal im Kreis
  283.             // herum, also kann die Scheibe nicht verschoben werden
  284.             if (!neuerturm || neuerturm == alterturm)
  285.                 return NULL;
  286.             GeometryC *top = neuerturm->topElement();
  287.             if (!top)
  288.             {
  289.                 // Der neue Turm ist leer - kein Problem
  290.                 alterturm->rem();
  291.                 neuerturm->add(*me);
  292.                 reLayout();
  293.                 return neuerturm;
  294.             };
  295.             GeometryBaseC *obj;
  296.             WORD offset1, offset2;
  297.             // Die Breite der Scheiben wird einfach über den Prozentwert der
  298.             // linken Regel überprüft. Ziemlich gehackt, würde ich sagen
  299.             me->leftRule(obj,offset1);
  300.             top->leftRule(obj,offset2);
  301.             if (offset1 > offset2)
  302.             {
  303.                 // Die Scheibe des neuen Turms ist breiter als die zu
  304.                 // verschiebende, also ok
  305.                 alterturm->rem();
  306.                 neuerturm->add(*me);
  307.                 reLayout();
  308.                 return neuerturm;
  309.             };
  310.             // Und naechsten Turm versuchen
  311.             turm = neuerturm;
  312.         };
  313.     };
  314.     return NULL;
  315. }
  316.  
  317. // *************************************************************
  318.  
  319. VOID ScheibenEventC::up(WindowC *w, GadgetC *g, IntuiMessageC * )
  320. {
  321.     if (meinTurm)
  322.     {
  323.         // Die Scheibe verschieben
  324.         TurmGeometryC *m = ((HanoiWindowC *) w)->zumNaechsten(meinTurm,
  325.             (LBIButtonC *) g);
  326.         if (m)
  327.         {
  328.             // Hat geklappt, also neuer Turm
  329.             meinTurm = m;
  330.         }
  331.         else {
  332.             // Scheibe bleibt auf dem alten Turm
  333.             DisplayBeep(w->window()->WScreen);
  334.         };
  335.     }
  336.     else {
  337.         DisplayBeep(w->window()->WScreen);
  338.     };
  339. }
  340.  
  341. // *************************************************************
  342.  
  343. LibraryBaseErrC GadToolsBase("gadtools.library",37);
  344. LibraryBaseErrC UtilityBase("utility.library",37);
  345. LibraryBaseErrC CxBase("commodities.library",37);
  346. LibraryBaseErrC LayersBase("layers.library",37);
  347. LibraryBaseErrC WorkbenchBase("workbench.library",37);
  348.  
  349. void main()
  350. {
  351.     if (!LibraryBaseC::areAllOpen())
  352.         return;
  353.  
  354.     SignalsC sc;
  355.  
  356.     PublicScreenC screen(NULL);
  357.     screen.open();
  358.  
  359.     GTIDCMPortC port;
  360.     sc.add(port);
  361.  
  362.     HanoiWindowC window(port,screen);
  363.  
  364.     GadgetUpHandlerC uphandler;
  365.     port.add(uphandler);
  366.  
  367.     CtrlCHandlerC ctrlchandler;
  368.     sc.add(ctrlchandler);
  369.  
  370.     window.open();
  371.  
  372.     sc.loop();
  373. }
  374.  
  375.