Skip to content

Instantly share code, notes, and snippets.

@MikuroXina
Created January 28, 2020 16:18
Show Gist options
  • Select an option

  • Save MikuroXina/84b564be382457152b47380362bfd78a to your computer and use it in GitHub Desktop.

Select an option

Save MikuroXina/84b564be382457152b47380362bfd78a to your computer and use it in GitHub Desktop.
Tic tac toe
#include "Board.hpp"
void defaultEndGame(Judge) {}
Board make() {
Board made{};
for (int y = 0; y < 3; ++y) {
for (int x = 0; x < 3; ++x) {
made.cells[x][y] = Cell::Empty; // マスめの なかみは カラッポ!
}
}
made.next = Stone::X; // 先手はバツ
made.endGame = &defaultEndGame; // 上に書いたデフォルト
return made;
}
std::vector<std::vector<Cell>> cells(Board const *b) {
using std::vector;
vector<vector<Cell>> cells(3, vector<Cell>(3));
for (int y = 0; y < 3; ++y) {
for (int x = 0; x < 3; ++x) {
cells[x][y] = b->cells[x][y];
}
}
return cells;
}
Stone next(Board const *b) { return b->next; }
void onEndGame(Board *b, EndGameHandler handler) { b->endGame = handler; }
void judge(Board const *b) {
// 斜め方向
if ((b->cells[1][1] != Cell::Empty && b->cells[0][0] == b->cells[1][1] &&
b->cells[1][1] == b->cells[2][2]) ||
(b->cells[1][1] != Cell::Empty && b->cells[0][2] == b->cells[1][1] &&
b->cells[1][1] == b->cells[2][0])) {
b->endGame(b->cells[1][1] == Cell::X ? Judge::X : Judge::O);
return;
}
// 水平方向を縦に 3 回
for (int y = 0; y < 3; ++y) {
if (b->cells[1][y] != Cell::Empty && b->cells[0][y] == b->cells[1][y] &&
b->cells[1][y] == b->cells[2][y]) {
b->endGame(b->cells[1][y] == Cell::X ? Judge::X : Judge::O);
return;
}
}
// 垂直方向を横に 3 回
for (int x = 0; x < 3; ++x) {
if (b->cells[x][1] != Cell::Empty && b->cells[x][0] == b->cells[x][1] &&
b->cells[x][1] == b->cells[x][2]) {
b->endGame(b->cells[x][1] == Cell::X ? Judge::X : Judge::O);
return;
}
}
for (int y = 0; y < 3; ++y) {
for (int x = 0; x < 3; ++x) {
if (b->cells[x][y] == Cell::Empty) { // 空のマスがあれば
return;
}
}
}
// 空のマスが無いとここに来る
b->endGame(Judge::Draw);
}
void place(Board *b, int x, int y) {
if (!(0 <= x && x < 3 && 0 <= y && y < 3)) { // x や y が範囲外なら
return;
}
if (b->cells[x][y] != Cell::Empty) { // そのマス目が埋まっているなら
return;
}
if (next(b) == Stone::X) {
b->cells[x][y] = Cell::X;
b->next = Stone::O;
} else {
b->cells[x][y] = Cell::O;
b->next = Stone::X;
}
judge(b); // これは上の勝敗判定の関数
}
#ifndef TTT_BOARD_HPP
#define TTT_BOARD_HPP
// 石
enum struct Stone {
O,
X,
};
// マス目
enum struct Cell {
Empty,
O,
X,
};
// 勝敗結果
enum struct Judge {
O,
X,
Draw,
};
#include <functional>
using EndGameHandler = std::function<void(Judge)>;
struct Board {
Cell cells[3][3]; // 3 x 3 のマス目
Stone next; // 次に置く石
EndGameHandler endGame;
};
// make() は新しい Board のオブジェクトを作って返す
Board make();
#include <vector>
// cells(b) は b の盤面の二次元 vector を返す
std::vector<std::vector<Cell>> cells(Board const *b);
// next(b) は b へ次に置ける石を返す
Stone next(Board const *b);
// place(b, x, y) は (x, y) へ石を置く
void place(Board *b, int x, int y);
// onEndGame(b, func) は b にゲーム終了時のイベントハンドラ func を登録する
void onEndGame(Board *b, EndGameHandler handler);
#endif // TTT_BOARD_HPP
#include <iostream>
#include "Board.hpp"
// Show(b) は b の盤面をコンソールに出力する
void Show(Board const *b) {
auto c = cells(b);
for (int y = 0; y < 3; ++y) {
for (int x = 0; x < 3; ++x) {
switch (c[x][y]) {
case Cell::Empty:
std::cout << " ";
break;
case Cell::O:
std::cout << " O ";
break;
case Cell::X:
std::cout << " X ";
break;
}
if (x != 2) {
std::cout << "|";
}
}
if (y != 2) {
std::cout << "\n-----------\n";
}
}
std::cout << std::endl;
}
int main() {
bool endedGame = false;
Board board = make();
Board *b = &board;
onEndGame(b, [&endedGame](Judge j) {
switch (j) {
case Judge::O:
std::cout << "O の勝ち!\n";
break;
case Judge::X:
std::cout << "X の勝ち!\n";
break;
case Judge::Draw:
std::cout << "引き分け!\n";
break;
}
endedGame = true;
});
while (!endedGame) {
switch (next(b)) {
case Stone::O:
std::cout << "O の手番\n";
break;
case Stone::X:
std::cout << "X の手番\n";
break;
}
Show(b);
int x, y;
std::cin >> x >> y;
place(b, x, y);
}
Show(b);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment