/****************/ /* tictacw.cpp */ /****************/ // Esimerkki pelistä jossa piirretään nappuloita. // Projektiin tictacw.cpp, tictac.rc // Vesa Lappalainen 6.11.1996 // Muutoksia: 7.11.1996 ix<->iy taulukoissa // TWindow-ikkunasta perittyä luokkaa käyttävä versio // // Tehtäviä: (vrt. myös BC5\EXAMPLES\OWL\GAMES\TTT\*.cpp) // 1) Lisää peliin voittajan tarkistus ja mieti tarkkaan minkä luokan // tulee huolehtia mistäkin asiasta. // 2) Kirjoita nappulaan metodi Resize ja lisää ohjelmaan ominaisuus, // jolla nappuloiden kokoa voidaan muuttaa (kaikkia kerralla) // 3) Vaihda #define CHANGE_TYPE 1 ja peri TNappulasta luokat // TTyhja, TRuksi ja TPallo ja mutta Hit-metodia siten, että // kun vanha voistetaan, luodaan uusi Ruksi tai Pallo tilalle // Ainoastaan TTyhja -luokkaa olevaa oliota voi klikata! // Voiko nappulan tyyppi -attribuutin hävitää kokonaan? // 4) Mieti mitä hyvää/huonoa on kummassakin ratkaisussa (CHANGE_TYPE 1/0) // 5) Siirrä napin tyyppi TId -luokkaan ja käytä moniperintää // (joudut ehkä lisäämään 1-2 metodia TId-luokkaan) // 6) Mieti mitä ongelmia seuraisi, jos nappula ei olisikaan peritty // TWindow-luokasta, vaan nappula sisältäisi ikkunan. // 7) Vielä eräs tapa toteuttaa peli olisi se, etteivät nappulat olisikaan // mitään ikkunoita, vaan isäikkunan "hiiri alhaalla" -viestin // koordinaateista päätettäisiin mihin nappulaan on painettu. // Toteuta tällainen versio. // #include #include "tictac.rh" #define CHANGE_TYPE 0 // Määritä tällä, muutetanko tyyppiä (1), vai // vaihdetaanko nappula (0) const int MAX_NX = 9; const int MAX_NY = 9; const int MAX_PELAAJIA = 2; //------------------------------------------------------------------------------ class TNapSize { // Nappulan kokoa ja alkupaikkaa kuvaava luokka TPoint origo; TSize koko; public: TNapSize(TPoint &p,TSize &k) : origo(p), koko(k) {} const TPoint &Origo() const { return origo; } const TSize &Koko() const { return koko; } }; // TNapSize //------------------------------------------------------------------------------ class TId { // Luokka, joka osaa muttua ID <-> x,y ja ix,iy int ix,iy; // index x,y (0-2) const TNapSize &ns; public: TId(int aix,int aiy, const TNapSize &s) : ns(s), ix(aix), iy(aiy) { } int x() const { return ns.Origo().x + ix*ns.Koko().cx; } int y() const { return ns.Origo().y + iy*ns.Koko().cy; } int w() const { return ns.Koko().cx; } int h() const { return ns.Koko().cy; } int inx() const { return ix; } int iny() const { return iy; } operator TRect() const { return TRect(TPoint(x(),y()),TSize(w(),h())); } }; // TId //------------------------------------------------------------------------------ class TLauta; // Eteenpäin viittaus, koska nyt Lauta ja Nappi "keskustelevat" //------------------------------------------------------------------------------ class TNappi : public TWindow { // Varsinainen pelinappula TLauta &lauta; // Tietää mihin lautaan kuuluu int type; // ja mitä tyyppiä itse on TId id; // sekä oman paikkansa indekseinä public: TNappi(TWindow* parent, int aix, int aiy, const TNapSize &ns, TLauta <, int t=0, TModule* module = 0) : id(aix,aiy,ns), lauta(lt), type(t), TWindow(parent) { Attr.Style |= WS_CHILD | WS_VISIBLE; MoveWindow(TRect(id)); } const TBitmap &b(); void Draw(TDC &dc) { TMemoryDC memDC(dc); memDC.SelectObject(b()); dc.StretchBlt(0,0,id.w(),id.h(),memDC, 0,0,b().Size().cx,b().Size().cy,SRCCOPY); } #if CHANGE_TYPE void SetType(int t) { type = t; Invalidate(); } int Type() { return type; } #endif void Paint(TDC &dc,bool,TRect &) { Draw(dc); } void EvLButtonDown(uint modKeys, TPoint& point); DECLARE_RESPONSE_TABLE(TNappi); }; // TNappi DEFINE_RESPONSE_TABLE1(TNappi, TWindow) EV_WM_PAINT, EV_WM_LBUTTONDOWN, END_RESPONSE_TABLE; //------------------------------------------------------------------------------ class TLauta { int nx,ny; TNapSize ns; TNappi *lauta[MAX_NX][MAX_NY]; TBitmap *bmps[MAX_PELAAJIA+1]; TWindow *Wnd; int pelaaja; protected: void CreateButtons(); void DeleteButtons(); public: TLauta(TWindow *awnd,int anx=3,int any=3); ~TLauta(); void uusi(int unx=0,int uny=0) { Wnd->Show(SW_HIDE); DeleteButtons(); if ( unx != 0 && uny != 0 ) { nx = unx; ny = uny; } CreateButtons(); Wnd->Show(SW_SHOW); } #if CHANGE_TYPE int Hit(TNappi &nap) { nap.SetType(pelaaja+1); #else int Hit(int ix, int iy) { // Tämän toimimisen edellytyksenä on ettei nappi delete lauta[iy][ix]; // koske itseensä enää Hit-kutsun jälkeen lauta[iy][ix] = new TNappi(Wnd,ix,iy,ns,*this,pelaaja+1); lauta[iy][ix]->Create(); // #endif pelaaja++; if ( pelaaja >= MAX_PELAAJIA ) pelaaja = 0; return 0; } // Hit const TBitmap &BitMap(int i) { return *bmps[i]; } }; // TLauta TLauta::TLauta(TWindow *awnd,int anx,int any) : nx(anx), ny(any), ns(TPoint(20,20),TSize(40,40)), Wnd(awnd) { pelaaja = 0; const TModule &module(*Wnd->GetModule()); for (int i=0; i= MAX_NX ) nx = MAX_NX-1; if ( ny >= MAX_NY ) ny = MAX_NY-1; for (int iy=0; iyCreateChildren(); // Jos tämä on täällä, ei saa kutsua konstruktorissa } // jollei ole, PITÄÄ kutsua!!! void TLauta::DeleteButtons() { for (int iy=0; iyuusi(); } void CmNxN(WPARAM id) { lauta->uusi(id%100,id%100); } DECLARE_RESPONSE_TABLE(TTicTacDialog); }; // TTicTacDialog DEFINE_RESPONSE_TABLE1(TTicTacDialog, TDialog) EV_COMMAND(CM_GAMEEXIT ,CmExit), EV_COMMAND(CM_GAMENEW ,CmNew), EV_COMMAND_AND_ID(CM_GAME_3x3 ,CmNxN), EV_COMMAND_AND_ID(CM_GAME_4x4 ,CmNxN), END_RESPONSE_TABLE; //------------------------------------------------------------------------------ class TTicTacApp : public TApplication { public: TTicTacApp(const char *title) : TApplication(title) {} void InitMainWindow() { TDecoratedFrame *fw = new TDecoratedFrame(0, Name, new TTicTacDialog(0, IDD_TICTAC) ); fw->SetFlag(wfShrinkToClient); fw->AssignMenu(IDM_PAAMENU); fw->SetIcon(this, IDI_IKONI); fw->SetIconSm(this, IDI_IKONI); fw->Attr.AccelTable = IDM_PAAMENU; SetMainWindow(fw); } }; // TTicTacApp /********************* Pääohjelma *********************************************/ int OwlMain(int ,char far * []) { return TTicTacApp("TicTacToe").Run(); }