home *** CD-ROM | disk | FTP | other *** search
- // hanoi.c
- //
- // Eine nette interaktive Variante der Türme von Hanoi.
- //
- // Autor: Jochen Becher
-
- #include <classes/layouter/windows.h>
- #include <classes/layouter/boopsigadgets.h>
- #include <classes/layouter/decorgadgets.h>
- #include <classes/exec/libraries.h>
- #pragma header
-
- #include <pragma/intuition_lib.h>
-
- // *************************************************************
-
- // Die Klasse TurmGeometryC übernimmt die Verwaltung der Geometrien in den
- // Türmen
- class TurmGeometryC : public GeometryGroupC {
- public:
- TurmGeometryC(
- GroupLayoutC &frame,
- ULONG topRelation, GeometryC *topObject, WORD topOffset,
- ULONG bottomRelation, GeometryC *bottomObject, WORD bottomOffset,
- ULONG leftRelation, GeometryC *leftObject, WORD leftOffset,
- ULONG rightRelation, GeometryC *rightObject, WORD rightOffset);
- // Eine Geometrie als oberste auf den Turm legen und das dazugehörige
- // Gadget enablen
- VOID add(GeometryC &);
- // Das oberste Element vom Turm nehemn, und das darunterliegende Gadget
- // enablen
- GeometryC *rem();
- // Das oberste Element zurückgeben
- GeometryC *topElement();
- };
-
- TurmGeometryC::TurmGeometryC(
- GroupLayoutC &frame,
- ULONG topRelation, GeometryC *topObject, WORD topOffset,
- ULONG bottomRelation, GeometryC *bottomObject, WORD bottomOffset,
- ULONG leftRelation, GeometryC *leftObject, WORD leftOffset,
- ULONG rightRelation, GeometryC *rightObject, WORD rightOffset)
- : GeometryGroupC(frame,
- topRelation,topObject,topOffset,
- bottomRelation,bottomObject,bottomOffset,
- leftRelation,leftObject,leftOffset,
- rightRelation,rightObject,rightOffset)
- {
- }
-
- VOID TurmGeometryC::add(GeometryC &g)
- {
- ListCursorC lc(*this);
- lc.last();
- if (lc.isDone())
- {
- // Das erste Element wird unten an die Gruppe geklebt
- g.setBottomRule(LAYOUT_GROUP,NULL,0);
- }
- else {
- // Das oberste Element wird disabled
- ((LGButtonC *) ((GeometryC *) lc.item())->layoutObject())->disable(TRUE);
- // Das neue Element wird auf das oberste geklebt
- g.setBottomRule(LAYOUT_OPPBORDER,(GeometryC *) lc.item(),-2);
- };
- g.setTopRule(LAYOUT_SIZE,NULL,0);
- // Das neue oberste wird enabled
- ((LGButtonC *) g.layoutObject())->disable(FALSE);
- GeometryGroupC::add(g);
- }
-
- GeometryC *TurmGeometryC::rem()
- {
- // Das oberste Element wird entfernt
- GeometryC *g = (GeometryC *) remTail();
- if (g)
- {
- ListCursorC lc(*this);
- lc.last();
- if (!lc.isDone())
- {
- // Das neue oberste wird enabled
- ((LGButtonC *) ((GeometryC *) lc.item())->layoutObject())->disable(FALSE);
- };
- };
- return g;
- }
-
- GeometryC *TurmGeometryC::topElement()
- {
- ListCursorC lc(*this);
- lc.last();
- return (GeometryC *) lc.item();
- };
-
- // *************************************************************
-
- // Jede Scheibe ist ein Button, die mittels dieser Klasse reagiert
- class ScheibenEventC : public GadgetEventC {
- public:
- ScheibenEventC() : GadgetEventC(), meinTurm(NULL) { };
- VOID up(WindowC *, GadgetC *, IntuiMessageC * );
- VOID setTurm(TurmGeometryC *t) { meinTurm = t; };
- private:
- TurmGeometryC *meinTurm;
- };
-
- // *************************************************************
-
- // Diese Klasse erzeugt alle Geometrien und Gadgets für das Spiel
- class ScheibenkisteC : public GadgetListC {
- public:
- ScheibenkisteC(WindowC &, ULONG anzahl);
- ~ScheibenkisteC();
- GeometryC *get(ULONG i);
- ULONG anzahl() { return maxanz; };
- private:
- arraylist<GeometryC *> scheiben;
- ULONG maxanz;
- stringarray beschriftung;
- };
-
- ScheibenkisteC::ScheibenkisteC(WindowC &w, ULONG anzahl)
- : GadgetListC(),
- scheiben(anzahl),
- maxanz(anzahl),
- beschriftung("1","2","3","4","5",NULL)
- {
- // Höchstens 5 Scheiben sind erlaubt
- if (maxanz > 5)
- throw Exception();
- ULONG i;
- for (i = 0; i < maxanz; i++)
- {
- ScheibenEventC *ev = new ScheibenEventC();
- if (!ev)
- throw MemoryX(sizeof(ScheibenEventC));
- LBIButtonC *b = new LBIButtonC (ev,w,LAYOUT_AUTOSIZE,LAYOUT_AUTOSIZE,
- GA_Text, beschriftung[i],
- GA_RelVerify, TRUE,
- TAG_END);
- if (!b)
- throw MemoryX(sizeof(LBIButtonC));
- GadgetListC::add(*b);
- GeometryC *g = new GeometryC (*b,
- LAYOUT_GROUP,NULL,0,LAYOUT_SIZE,NULL,0,
- LAYOUT_PROCENT,NULL,5 + i*10,LAYOUT_PROCENT,NULL,95 - i*10);
- if (!g)
- throw MemoryX(sizeof(GeometryC));
- scheiben.addTail() = g;
- };
- }
-
- ScheibenkisteC::~ScheibenkisteC()
- {
- arraycursor<GeometryC *> ac(scheiben);
- while (!ac.isDone())
- {
- GeometryC *g = ac.item();
- if (g)
- {
- LBIButtonC *b = (LBIButtonC *) g->layoutObject();
- delete g;
- if (b)
- {
- delete b;
- };
- };
- ac.next();
- };
- }
-
- GeometryC *ScheibenkisteC::get(ULONG i)
- {
- if (i >= maxanz)
- return NULL;
- return scheiben[i];
- }
-
- // *************************************************************
-
- class HanoiWindowC : public StandardWindowC {
- public:
- HanoiWindowC(GTIDCMPortC &, ScreenC &);
- ~HanoiWindowC();
- VOID open();
- TurmGeometryC *zumNaechsten(TurmGeometryC *, LayoutC *);
- private:
- LBBevelboxC linksRand,mitteRand,rechtsRand;
- TurmGeometryC links,mitte,rechts;
- TransparentLayoutC minimum;
- GeometryC minimumG;
- ScheibenkisteC scheiben;
- WindowCloseHandlerC wch;
- };
-
- HanoiWindowC::HanoiWindowC(GTIDCMPortC &p, ScreenC &s)
- : StandardWindowC(p,s,NULL,
- WA_IDCMP,IDCMP_GADGETUP,
- WA_Title,"Die Türme von Hanoi",
- TAG_END),
- linksRand(*this,"von",NULL,LAYOUT_AUTOSIZE,LAYOUT_AUTOSIZE,
- TAG_END),
- mitteRand(*this,"über",NULL,LAYOUT_AUTOSIZE,LAYOUT_AUTOSIZE,
- TAG_END),
- rechtsRand(*this,"nach",NULL,LAYOUT_AUTOSIZE,LAYOUT_AUTOSIZE,
- TAG_END),
- links(linksRand,
- LAYOUT_GROUP,NULL,0,LAYOUT_GROUP,NULL,0,
- LAYOUT_GROUP,NULL,0,LAYOUT_PROCENT,NULL,33),
- mitte(mitteRand,
- LAYOUT_GROUP,NULL,0,LAYOUT_GROUP,NULL,0,
- LAYOUT_OPPBORDER,&links,2,LAYOUT_PROCENT,NULL,66),
- rechts(rechtsRand,
- LAYOUT_GROUP,NULL,0,LAYOUT_GROUP,NULL,0,
- LAYOUT_OPPBORDER,&mitte,2,LAYOUT_GROUP,NULL,0),
- minimum(0,0),
- minimumG(minimum,
- LAYOUT_GROUP,NULL,0,LAYOUT_GROUP,NULL,0,
- LAYOUT_GROUP,NULL,0,LAYOUT_GROUP,NULL,0),
- scheiben(*this,3),
- wch(*this)
- {
- // Alle Scheiben werden auf den ersten Turm gelegt
- ULONG i;
- for (i = 0; i < scheiben.anzahl(); i++)
- {
- if (scheiben.get(i))
- {
- ((ScheibenEventC *) ((LBIButtonC *) scheiben.get(i)
- ->layoutObject())->event())->setTurm(&links);
- links.add(*scheiben.get(i));
- };
- };
- titlegadgets.add(linksRand);
- titlegadgets.add(mitteRand);
- titlegadgets.add(rechtsRand);
- gadgets.add(scheiben);
- innerGeo.add(links);
- innerGeo.add(mitte);
- innerGeo.add(rechts);
- innerGeo.add(minimumG);
- }
-
- HanoiWindowC::~HanoiWindowC()
- {
- close();
- }
-
- VOID HanoiWindowC::open()
- {
- StandardWindowC::open();
- // Dieser Trick "speichert" die Breite des ersten Layouts für weitere
- // Layoutberechnungen, d.h. die Breite und Höhe des Elements minimum
- // wird ab jetzt ein Minimum für jede Layoutberechnung sein.
- minimumG.setBottomRule(LAYOUT_SIZE,NULL,0);
- minimumG.setRightRule(LAYOUT_SIZE,NULL,0);
- }
-
- TurmGeometryC *HanoiWindowC::zumNaechsten(TurmGeometryC *turm, LayoutC *lay)
- {
- if (turm && lay)
- {
- // Zuerst ein paar Sicherheitstests, ob das Element das oberste auf
- // dem angegeben Turm ist.
- GeometryC *me = turm->topElement();
- if (!me)
- return NULL;
- if (me->layoutObject() != lay)
- return NULL;
- TurmGeometryC *neuerturm = NULL;
- TurmGeometryC *alterturm = turm;
- while (TRUE)
- {
- // Den neuen Turm suchen
- if (turm == &links)
- neuerturm = &mitte
- else if (turm == &mitte)
- neuerturm = &rechts
- else if (turm == &rechts)
- neuerturm = &links;
- // Kein Turm besetzt (sollte nie passieren) oder einmal im Kreis
- // herum, also kann die Scheibe nicht verschoben werden
- if (!neuerturm || neuerturm == alterturm)
- return NULL;
- GeometryC *top = neuerturm->topElement();
- if (!top)
- {
- // Der neue Turm ist leer - kein Problem
- alterturm->rem();
- neuerturm->add(*me);
- reLayout();
- return neuerturm;
- };
- GeometryBaseC *obj;
- WORD offset1, offset2;
- // Die Breite der Scheiben wird einfach über den Prozentwert der
- // linken Regel überprüft. Ziemlich gehackt, würde ich sagen
- me->leftRule(obj,offset1);
- top->leftRule(obj,offset2);
- if (offset1 > offset2)
- {
- // Die Scheibe des neuen Turms ist breiter als die zu
- // verschiebende, also ok
- alterturm->rem();
- neuerturm->add(*me);
- reLayout();
- return neuerturm;
- };
- // Und naechsten Turm versuchen
- turm = neuerturm;
- };
- };
- return NULL;
- }
-
- // *************************************************************
-
- VOID ScheibenEventC::up(WindowC *w, GadgetC *g, IntuiMessageC * )
- {
- if (meinTurm)
- {
- // Die Scheibe verschieben
- TurmGeometryC *m = ((HanoiWindowC *) w)->zumNaechsten(meinTurm,
- (LBIButtonC *) g);
- if (m)
- {
- // Hat geklappt, also neuer Turm
- meinTurm = m;
- }
- else {
- // Scheibe bleibt auf dem alten Turm
- DisplayBeep(w->window()->WScreen);
- };
- }
- else {
- DisplayBeep(w->window()->WScreen);
- };
- }
-
- // *************************************************************
-
- LibraryBaseErrC GadToolsBase("gadtools.library",37);
- LibraryBaseErrC UtilityBase("utility.library",37);
- LibraryBaseErrC CxBase("commodities.library",37);
- LibraryBaseErrC LayersBase("layers.library",37);
- LibraryBaseErrC WorkbenchBase("workbench.library",37);
-
- void main()
- {
- if (!LibraryBaseC::areAllOpen())
- return;
-
- SignalsC sc;
-
- PublicScreenC screen(NULL);
- screen.open();
-
- GTIDCMPortC port;
- sc.add(port);
-
- HanoiWindowC window(port,screen);
-
- GadgetUpHandlerC uphandler;
- port.add(uphandler);
-
- CtrlCHandlerC ctrlchandler;
- sc.add(ctrlchandler);
-
- window.open();
-
- sc.loop();
- }
-
-