Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //3D Tic Tac Toe
- //by Logic
- //Environment: Windows 7, Code::Blocks(settings: all default).
- #include <iostream>
- #include <sstream>
- #include <ctime>
- #include <cmath>
- #include <cstdio>
- #include <cstdlib>
- #include <cstring>
- #ifndef _WIN32
- # include <unistd.h>
- # include <termios.h>
- # include <cassert>
- #else
- # include <windows.h>
- # include <conio.h>
- #endif
- using namespace std;
- #ifndef _WIN32
- # define clrscr() printf("\033[1H\033[2J");
- # define Sleep(_t) usleep(_t)
- #else
- void clrscr(void)
- {
- CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
- HANDLE hConsoleOut;
- COORD Home = {0,0};
- DWORD dummy;
- hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
- GetConsoleScreenBufferInfo(hConsoleOut,&csbiInfo);
- FillConsoleOutputCharacter(hConsoleOut,' ',csbiInfo.dwSize.X * csbiInfo.dwSize.Y,Home,&dummy);
- csbiInfo.dwCursorPosition.X = 0;
- csbiInfo.dwCursorPosition.Y = 0;
- SetConsoleCursorPosition(hConsoleOut,csbiInfo.dwCursorPosition);
- }
- #endif
- #ifndef _WIN32
- //Copied from: http://topic.csdn.net/u/20080417/16/6f0b781c-287a-485c-b370-7c62953c2193.html
- int getch(void)
- {
- int c=0;
- struct termios org_opts, new_opts;
- int res=0;
- //----- store old settings -----------
- res=tcgetattr(STDIN_FILENO, &org_opts);
- assert(res==0);
- //---- set new terminal parms --------
- memcpy(&new_opts, &org_opts, sizeof(new_opts));
- new_opts.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOKE | ICRNL);
- tcsetattr(STDIN_FILENO, TCSANOW, &new_opts);
- c=getchar();
- //------ restore old settings ---------
- res=tcsetattr(STDIN_FILENO, TCSANOW, &org_opts);
- assert(res==0);
- return c;
- }
- int getche(void)
- {
- int result=getch();
- putchar(result);
- return result;
- }
- #endif
- const int CTRLC = 0x03;
- const double PRECISION = 1e-6;
- const int sleepTime = 300;
- const int floorOffset[] = { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
- const int xOffset[] = { 0, 1, 1, 1, 0, 0, 0, 1,-1, 1, 1,-1,-1 };
- const int yOffset[] = { 1, 0, 1,-1, 0, 1,-1, 0, 0, 1,-1, 1,-1 };
- const int mediumDepth = 1;
- const int hardDepth = 2;
- class Recorder
- {
- public:
- enum ChessState { NotFilled = 0, FilledO, FilledX, DisplayStar };
- enum Player { UserO, ComputerX, Neither };
- protected:
- int o, x;
- ChessState chessboard[3][3][3];
- private:
- bool lines[3][3][3]; // only center lines may be recalculated.
- bool exists(int floor, int x, int y)
- {
- if (floor >= 0 && floor < 3
- && x >= 0 && x < 3
- && y >= 0 && y < 3) return true;
- return false;
- }
- bool IsANewLine(int floor, int x, int y, int o1, int o2, int o3, int first, int second)
- {
- int floor1 = floor + o1 * first, x1 = x + o2 * first, y1 = y + o3 * first;
- int floor2 = floor + o1 * second, x2 = x + o2 * second, y2 = y + o3 * second;
- if (floor1 == 1 && x1 == 1 && y1 == 1) swap(floor, floor1), swap(x, x1), swap(y, y1);
- if (floor2 == 1 && x2 == 1 && y2 == 1) swap(floor, floor2), swap(x, x2), swap(y, y2);
- if (GetChess(floor1, x1, y1) == chessboard[floor][x][y]
- && GetChess(floor2, x2, y2) == chessboard[floor][x][y]
- && ((floor == 1 && x == 1 && y == 1)
- ? (!lines[floor1][x1][y1] && (lines[floor1][x1][y1] = true, lines[floor2][x2][y2] = true))
- : true))
- return true;
- return false;
- }
- //This will be called only when there is a new line that is described by the arguments.
- void PerformALine(int floor, int x, int y, int o1, int o2, int o3, int first, int second);
- //This will be called only when chessboard[floor][x][y] != NotFilled
- void CheckNewLines(int floor, int x, int y, bool performOnConsole)
- {
- for (int i = 0; i < (int)(sizeof floorOffset / sizeof(int)); ++i)
- {
- bool flag = false;
- if (IsANewLine(floor, x, y, floorOffset[i], xOffset[i], yOffset[i], 1, 2))
- flag = true, performOnConsole ? PerformALine(floor, x, y, floorOffset[i], xOffset[i], yOffset[i], 1, 2) : (void)0;
- else if (IsANewLine(floor, x, y, floorOffset[i], xOffset[i], yOffset[i], 1, -1))
- flag = true, performOnConsole ? PerformALine(floor, x, y, floorOffset[i], xOffset[i], yOffset[i], 1, -1) : (void)0;
- else if (IsANewLine(floor, x, y, floorOffset[i], xOffset[i], yOffset[i], -1, -2))
- flag = true, performOnConsole ? PerformALine(floor, x, y, floorOffset[i], xOffset[i], yOffset[i], -1, -2) : (void)0;
- if (flag && chessboard[floor][x][y] == FilledO) ++this->o;
- else if (flag) ++this->x;
- }
- }
- public:
- Recorder() : o(0), x(0)
- {
- memset(chessboard, 0, sizeof chessboard);
- memset(lines, 0, sizeof lines);
- }
- virtual bool IsGameDone() = 0;
- Player GetWinner()
- {
- if (o > x) return UserO;
- if (o < x) return ComputerX;
- return Neither;
- }
- int O()
- {
- return o;
- }
- int X()
- {
- return x;
- }
- virtual Recorder *Clone() = 0;
- ChessState GetChess(int floor, int x, int y)
- {
- if (!exists(floor, x, y)) return DisplayStar;
- return chessboard[floor][x][y];
- }
- void SetChess(int floor, int x, int y, ChessState state, bool performOnConsole);
- void SetChess(int floor, int x, int y, ChessState state)
- {
- SetChess(floor, x, y, state, true);
- }
- void ABCDisplay (ostream &out)
- {
- out << "Player: " << o << '\t' << "Computer: " << x << endl;
- char x = 'a';
- for (int i = 0; i < 3; ++i)
- {
- out << " _______" << endl;
- for (int j = 0; j < 3; ++j)
- {
- for (int k = 0; k < 4 - j - j; ++k) out << ' ';
- out<< '/';
- for (int k = 0; k < 3; ++k)
- {
- switch (chessboard[i][j][k])
- {
- case Recorder::NotFilled:
- if (i == 1 && j == 1 && k == 1) out << '.';
- else out << x++;
- break;
- case Recorder::FilledO:
- out << 'O';
- break;
- case Recorder::FilledX:
- out << 'X';
- break;
- default:
- break;
- }
- out << '/';
- }
- out << endl;
- }
- }
- }
- void SimpleDisplay(ostream &out)
- {
- out << "Player: " << O() << '\t' << "Computer: " << x << endl;
- for (int i = 0; i < 3; ++i)
- {
- out << " _______" << endl;
- for (int j = 0; j < 3; ++j)
- {
- for (int k = 0; k < 4 - j - j; ++k) out << ' ';
- out<< '/';
- for (int k = 0; k < 3; ++k)
- {
- switch (chessboard[i][j][k])
- {
- case DisplayStar:
- out << '*';
- break;
- case NotFilled:
- out << ' ';
- break;
- case FilledO:
- out << 'O';
- break;
- case FilledX:
- out << 'X';
- break;
- default:
- break;
- }
- out << '/';
- }
- out << endl;
- }
- }
- }
- };
- void Recorder::SetChess(int floor, int x, int y, Recorder::ChessState state, bool performOnConsole)
- {
- if (performOnConsole)
- {
- clrscr();
- SimpleDisplay(cout);
- }
- chessboard[floor][x][y] = state;
- if (performOnConsole)
- {
- Sleep(sleepTime);
- clrscr();
- SimpleDisplay(cout);
- Sleep(sleepTime);
- }
- CheckNewLines(floor, x, y, performOnConsole);
- }
- void Recorder::PerformALine(int floor, int x, int y, int o1, int o2, int o3, int first, int second)
- {
- stringstream s1, s2;
- SimpleDisplay(s1);
- ChessState state = chessboard[floor][x][y];
- chessboard[floor][x][y] = DisplayStar;
- chessboard[floor + o1 * first][x + o2 * first][y + o3 * first] = DisplayStar;
- chessboard[floor + o1 * second][x + o2 * second][y + o3 * second] = DisplayStar;
- SimpleDisplay(s2);
- chessboard[floor][x][y] = state;
- chessboard[floor + o1 * first][x + o2 * first][y + o3 * first] = state;
- chessboard[floor + o1 * second][x + o2 * second][y + o3 * second] = state;
- for (int i = 0; i < 3; ++i)
- {
- clrscr();
- cout << s1.str();
- Sleep(sleepTime);
- clrscr();
- cout << s2.str();
- Sleep(sleepTime);
- }
- }
- class SuperRecorder : public Recorder
- {
- public:
- bool IsGameDone()
- {
- for (int i = 0; i < 3; ++i)
- for (int j = 0; j < 3; ++j)
- for (int k = 0; k < 3; ++k)
- if (chessboard[i][j][k] == NotFilled) return false;
- return true;
- }
- Recorder *Clone()
- {
- return new SuperRecorder(*this);
- }
- };
- class ClassicRecorder : public Recorder
- {
- public:
- bool IsGameDone()
- {
- if (o == 0 && x == 0)
- for (int i = 0; i < 3; ++i)
- for (int j = 0; j < 3; ++j)
- for (int k = 0; k < 3; ++k)
- if (chessboard[i][j][k] == NotFilled) return false;
- return true;
- }
- Recorder *Clone()
- {
- return new ClassicRecorder(*this);
- }
- };
- typedef void (*ComputerPlay)(Recorder *);
- typedef struct _p
- {
- int floor, x, y;
- _p() : floor(0), x(0), y(0) { }
- } point;
- void EasyPlay(Recorder *rec)
- {
- point usables[27];
- point *p = usables;
- if (rec->GetChess(1, 1, 1) != Recorder::FilledX)
- {
- usables[0].floor = 1;
- usables[0].x = 1;
- usables[0].y = 1;
- ++p;
- }
- for (int i = 0; i < 3; ++i)
- for (int j = 0; j < 3; ++j)
- for (int k = 0; k < 3; ++k)
- if (i == 1 && j == 1 && k == 1) continue;
- else if (rec->GetChess(i, j, k) == Recorder::NotFilled) p->floor = i, p->x = j, p->y = k, ++p;
- p = &usables[rand() % (p - usables)];
- rec->SetChess(p->floor, p->x, p->y, Recorder::FilledX);
- }
- inline Recorder::ChessState GetAnotherTurn(Recorder::ChessState turn)
- {
- return turn == Recorder::FilledO ? Recorder::FilledX : Recorder::FilledO;
- }
- double WayAssesment(Recorder *rec, int depth, Recorder::ChessState turn)
- {
- double answer = 0.0;
- int count = 0;
- if (depth == 0 || rec->IsGameDone())
- {
- return rec->X() - rec->O();
- }
- point usables[27];
- point *p = usables;
- if (rec->GetChess(1, 1, 1) != turn)
- {
- usables[0].floor = 1;
- usables[0].x = 1;
- usables[0].y = 1;
- ++p;
- }
- for (int i = 0; i < 3; ++i)
- for (int j = 0; j < 3; ++j)
- for (int k = 0; k < 3; ++k)
- if (i == 1 && j == 1 && k == 1) continue;
- else if (rec->GetChess(i, j, k) == Recorder::NotFilled) p->floor = i, p->x = j, p->y = k, ++p;
- for (point *it = usables; p - it; ++it, ++count)
- {
- Recorder *r = rec->Clone();
- r->SetChess(it->floor, it->x, it->y, turn, false);
- answer += WayAssesment(r, depth - 1, GetAnotherTurn(turn));
- delete r;
- }
- return answer / count;
- }
- void PlayTheBestWay(Recorder *rec, int depth)
- {
- double maxval = -100.0;
- point best;
- int bestcount = 0;
- point usables[27];
- double assesments[27];
- point *p = usables;
- if (rec->GetChess(1, 1, 1) != Recorder::FilledX)
- {
- usables[0].floor = 1;
- usables[0].x = 1;
- usables[0].y = 1;
- ++p;
- }
- for (int i = 0; i < 3; ++i)
- for (int j = 0; j < 3; ++j)
- for (int k = 0; k < 3; ++k)
- if (i == 1 && j == 1 && k == 1) continue;
- else if (rec->GetChess(i, j, k) == Recorder::NotFilled) p->floor = i, p->x = j, p->y = k, ++p;
- for (point *it = usables; p - it; ++it)
- {
- Recorder *r = rec->Clone();
- r->SetChess(it->floor, it->x, it->y, Recorder::FilledX, false);
- assesments[it - usables] = WayAssesment(r, depth * 2 - 1, Recorder::FilledO);
- delete r;
- if (assesments[it - usables] - maxval > PRECISION) maxval = assesments[it - usables], bestcount = 1;
- else if (fabs(assesments[it - usables] - maxval) <= PRECISION) ++bestcount;
- }
- int chosen = rand() % bestcount;
- for (point *it = usables; p - it; ++it)
- {
- if (fabs(assesments[it - usables] - maxval) <= PRECISION && chosen-- == 0)
- {
- best = *it;
- break;
- }
- }
- rec->SetChess(best.floor, best.x, best.y, Recorder::FilledX);
- }
- void MediumPlay(Recorder *rec)
- {
- clrscr();
- rec->SimpleDisplay(cout);
- cout << "Computer is thinking..." << endl;
- PlayTheBestWay(rec, mediumDepth);
- }
- void HardPlay(Recorder *rec)
- {
- clrscr();
- rec->SimpleDisplay(cout);
- cout << "Computer is thinking..." << endl;
- PlayTheBestWay(rec, hardDepth);
- }
- ComputerPlay ChooseDifficuty()
- {
- choose:
- clrscr();
- cout << "Please choose the difficuty of the game:" << endl;
- cout << "(E)asy" << endl
- << "(M)edium" << endl
- << "(H)ard" << endl;
- cout << "Choose one by inputing the first letter: ";
- char d = getche();
- switch (d)
- {
- case 'E':
- case 'e':
- return EasyPlay;
- case 'M':
- case 'm':
- return MediumPlay;
- case 'H':
- case 'h':
- return HardPlay;
- default:
- break;
- }
- cout << endl << "Input is invalid." << endl
- << "Press any key to input again..." << endl
- << "Press Ctrl+C to end the game." << endl;
- if (getch() == CTRLC) exit(0);
- goto choose;
- }
- Recorder *ChooseGameType()
- {
- choose:
- clrscr();
- cout << "Please choose the type of 3D Tic Tac Toe you want to play:" << endl;
- cout << "(S)uper" << endl
- << "(C)lassic" << endl;
- cout << "Choose one by inputing the first letter: ";
- char t = getche();
- if (t == 'S' || t == 's') return new SuperRecorder();
- if (t == 'C' || t == 'c') return new ClassicRecorder();
- cout << endl << "Input is invalid." << endl
- << "Press any key to input again..." << endl
- << "Press Ctrl+C to end the game." << endl;
- if (getch() == CTRLC) exit(0);
- goto choose;
- }
- bool PlayerPlay(Recorder *rec)
- {
- clrscr();
- rec->ABCDisplay(cout);
- cout << "Please input the letter of the place you want to fill: ";
- char x = getche();
- char y = 'a';
- if (x == '.')
- {
- if (rec->GetChess(1, 1, 1) == Recorder::FilledO) return false;
- rec->SetChess(1, 1, 1, Recorder::FilledO);
- return true;
- }
- if (!(('a' <= x && x <= 'z') || ('A' <= x && x <= 'Z'))) return false;
- if ('A' <= x && x <= 'Z') x = x - 'A' + 'a';
- int i, j, k;
- for (i = 0; i < 3; ++i)
- {
- for (j = 0; j < 3; ++j)
- {
- for (k = 0; k < 3; ++k)
- {
- if (i == 1 && j == 1 && k == 1) continue;
- if (rec->GetChess(i, j, k) == Recorder::NotFilled && y++ == x) goto exitfor;
- }
- }
- }
- exitfor:
- if (i == 3)
- return false;
- rec->SetChess(i, j, k, Recorder::FilledO);
- return true;
- }
- int main()
- {
- Recorder *recorder = ChooseGameType();
- ComputerPlay computerPlay = ChooseDifficuty();
- srand((unsigned)time(NULL));
- bool IsPlayerFirst = rand() % 2;
- clrscr();
- if (IsPlayerFirst)
- cout << "Player first." << endl;
- else cout << "Computer first." << endl;
- cout << "Press any key to continue..." << endl;
- getch();
- clrscr();
- while (!recorder->IsGameDone())
- {
- if (!IsPlayerFirst)
- {
- computerPlay(recorder);
- if (recorder->IsGameDone()) break;
- }
- while (!PlayerPlay(recorder))
- {
- cout << endl << "Input is invalid." << endl
- << "Press any key to input again..." << endl;
- getch();
- }
- if (recorder->IsGameDone()) break;
- if (IsPlayerFirst) computerPlay(recorder);
- }
- clrscr();
- recorder->SimpleDisplay(cout);
- cout << endl;
- switch (recorder->GetWinner())
- {
- case Recorder::Neither:
- cout << ":-| Tie." << endl;
- break;
- case Recorder::UserO:
- cout << ":-) Congratulations! You won!" << endl;
- break;
- case Recorder::ComputerX:
- cout << ":'( Sorry... You lost." << endl;
- break;
- default:
- break;
- }
- delete recorder;
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement