Osobiste, szkoła etc.

Kółko i krzyżyk - w ciekawy sposób...

25 lipca, 2007 o 17:50:40 Dodaj komentarz Poziom: 0 Permalink

Jakis czas temu chciałem trochę pobawić się grami. Na pierwszy ogień poszła najprostsza gra czyli kółko i krzyżyk. Niestety wpisywanie wszystkiego ręcznie było dość nudne(). Teraz postanowiłem trochę uprościć tą sprawę i napisać program jak najciekawiej (tzn. bez zbędnego powtarzania się i nudnego kodu).

Pierwszy sposób to trzymanie całej planszy w jednym 32 bitowym int (uint32_t). Każdy gracz lub sekwencja kończąca gre byłaby maską. Pole opisane byłoby przez 2 bity (zajęte/nie zajęte + numer gracza lub pierwsze zajęcie przez gracza 0 a drugie zajęcie przez gracza 2). Wszystko by było pieknie gdyby dało się wpisać wartości binarne do kodu C - ale da się tylko w szesnastkowym. Dodatkowo tworzenie tablic nie było ciekawe ;) - ale IMHO to jest najoszczedniejszy sposób jeśli chodzi o pamięć i CPU (mylę się?)

WartośćZnaczenie w sposobie pierwszymZnaczenie w sposobie drugim
WartośćZnaczenie w sposobie pierwszymZnaczenie w sposobie drugim
00PustePuste
01PusteZajęte przez gracza 1
10Zajęte przez gracza 0Zajęte przez gracza 0
11Zajęte przez gracza 1Błąd

Teraz wpadłem na inny pomysł - oddzielenie pól, rzędów i planszy. Oto kod (nie jest do końca przetestowany - mogą być w nim błędy):

#include typedef unsigned int uint; typedef unsigned short ushort; namespace ttt { class field { char player; public: field() : player(-1) {} field(char p) : player(p) {} field(field& f) : player(f.player) {} void clear() { player = false; } bool isOccupied() const { return player >= 0; } char getPlayer() const { return player; } bool setPlayer(char p) { if(player >= 0) return false; player = p; return true; } }; typedef std::vector fieldset; class board { std::vector
goboard; std::map > rboard; fieldset gc; char next_player; char winner; void setRBoard() { for(ushort i = 0; i < 3; i++) { std::map r; for(ushort j = 0; j < 3; j++) r[j] = gc[i * 3 + j]; rboard[i] = r; } } void setGoBoard() { goboard.reserve(8); fieldset l, r; for(ushort i = 0; i < 3; i++) { fieldset r, c; for(ushort j = 0; j < 3; j++) { r.push_back(rboard[i][j]); c.push_back(rboard[j][i]); } l.push_back(rboard[i][i]); r.push_back(rboard[i][2 - i]); goboard.push_back(r); goboard.push_back(c); } goboard.push_back(l); goboard.push_back(r); } public: board() : next_player(0), winner(-1) { gc.reserve(9); for(ushort i = 0; i < 9; i++) gc.push_back(new field()); setRBoard(); setGoBoard(); } board(board& b) : next_player(b.next_player), winner(b.winner) { gc.reserve(9); for(fieldset::iterator i = b.gc.begin(); i != b.gc.end(); i++) gc.push_back(new field((*i)->getPlayer())); setRBoard(); setGoBoard(); } ~board() { for(fieldset::iterator i = gc.begin(); i != gc.end(); i++) delete *i; } char getWinner() { if(winner >= 0) return winner; typedef std::vector
fieldsetset; fieldsetset::iterator i = goboard.begin(); do { fieldset &r = *i; char p = r[0]->getPlayer(); fieldset::iterator j = ++(r.begin()); do { if(p < 0) break; else if(p != (*j)->getPlayer()) { p = -1; break; } } while(++j != r.end()); if(p >= 0) { winner = p; return p; } } while(++i != goboard.end()); return -1; } bool isGameOver() { return getWinner() >= 0; } field *getField(ushort x, ushort y) { return rboard[x][y]; } char getNextPlayer() { return next_player; } bool move(ushort x, ushort y) { if(isGameOver()) return false; bool b = getField(x, y)->setPlayer(next_player); if(b) next_player = !next_player; return b; } }; }; #endif]]>

Czy ktoś zna jakiś ciekawszy sposób? A może krótszy/mniej pamięciożerny?

Komentarze do wpisu

Możesz śledzić odpowiedzi poprzez kanał RSS. Możesz dodać komentarz lub zostawić ślad (trackback) ze swojego bloga.

#

iss

Krzyrzyk? Cóż to za zwierz?

25 lipca 2007, 18:23:08

#

Uzytkownik

Nieortograficzny…

25 lipca 2007, 18:31:47

Dodaj komentarz

Textile Lite włączony ( szczegółowy opis znaczników ):