(私)
簡単なマルバツゲームをc言語で作成してください。
(chatGPT)
以下はC言語で簡単なマルバツゲームを作成する例です。この例では、2人のプレイヤーが交互に入力し、勝者が決まるまでゲームを続けます。
・・・
(私)
途中できれちゃいましたね、、、冗長なのでしょうビット演算子を使用して書き換えてください。
(chatGPT)
ビット演算子を使用して、条件文をより短く書くことができます。以下は、先ほどのプログラムにビット演算子を使って書き直した例です。
・・・
(私)
また切れちゃいましたね、、、2次元配列のboardは、1次元配列にしましょう。
あと draw_board() の中の枠を出力するところも割愛しましょう。
(chatGPT)
おっしゃる通りです。以下は、2次元配列を1次元配列にし、盤面の描画に不要な枠を削除した、改善版のプログラムです。
#include <stdio.h>
char board[9] = { // 1次元配列で盤面を作成
'1', '2', '3',
'4', '5', '6',
'7', '8', '9'
};
int player = 1; // 最初のプレイヤーは1
int choice;
char mark;
void draw_board() {
// 盤面を表示する関数
printf("\n");
printf(" %c | %c | %c \n", board[0], board[1], board[2]);
printf("---+---+---\n");
printf(" %c | %c | %c \n", board[3], board[4], board[5]);
printf("---+---+---\n");
printf(" %c | %c | %c \n", board[6], board[7], board[8]);
printf("\n");
}
void mark_board(char mark) {
// マスに印を付ける関数
board[choice - 1] = mark;
}
int check_win() {
// 勝者をチェックする関数
int row, col;
char player_mark = (player == 1) ? 'X' : 'O';
// 行をチェック
for (row = 0; row < 3; row++) {
if ((board[row * 3] & board[row * 3 + 1] & board[row * 3 + 2]) == player_mark) {
return 1;
}
}
// 列をチェック
for (col = 0; col < 3; col++) {
if ((board[col] & board[col + 3] & board[col + 6]) == player_mark) {
return 1;
}
}
// 斜めをチェック
if ((board[0] & board[4] & board[8]) == player_mark) {
return 1;
}
if ((board[2] & board[4] & board[6]) == player_mark) {
return 1;
}
return 0;
}
int main() {
int i;
int row, col;
draw_board();
for (i = 1; i <= 9; i++) {
player = (i % 2) ? 1 : 2; // プレイヤーを切り替える
printf("Player %d, enter a number: ", player);
scanf("%d", &choice);
mark = (player == 1) ? 'X' : 'O'; // プレイヤーの印を設定する
mark_board(mark);
draw_board();
if (check_win()) {
printf("Player %d wins!\n", player);
return 0;
}
}
printf("Draw game.\n");
return 0;
}
(私)
いいですね!
つぎは上記プログラムをc++にし、人vsCPUにしてください。
(chatGPT)
以下が、C++で人対CPUのマルバツゲームの例です。
#include <iostream>
#include <vector>
#include <random>
using namespace std;
vector<char> board(9, ' '); // 盤面を1次元のchar型vectorで表現する
const int player = 1;
const int computer = 2;
char player_mark = 'X';
char computer_mark = 'O';
void draw_board() {
// 盤面を表示する関数
cout << "\n " << board[0] << " | " << board[1] << " | " << board[2] << endl;
cout << "---+---+---" << endl;
cout << " " << board[3] << " | " << board[4] << " | " << board[5] << endl;
cout << "---+---+---" << endl;
cout << " " << board[6] << " | " << board[7] << " | " << board[8] << endl << endl;
}
int get_player_choice() {
// プレイヤーにマスの選択を尋ねる関数
int choice;
while (true) {
cout << "Enter a number (1-9): ";
cin >> choice;
if (choice < 1 || choice > 9) {
cout << "Invalid choice. Please try again." << endl;
} else if (board[choice - 1] != ' ') {
cout << "That space is already occupied. Please try again." << endl;
} else {
return choice - 1;
}
}
}
int get_computer_choice() {
// コンピュータがマスを選択する関数
int choice;
vector<int> choices;
for (int i = 0; i < 9; i++) {
if (board[i] == ' ') {
choices.push_back(i);
}
}
if (choices.size() > 0) {
default_random_engine engine(random_device{}());
uniform_int_distribution<int> distribution(0, choices.size() - 1);
choice = choices[distribution(engine)];
return choice;
} else {
return -1;
}
}
int check_win(int player) {
// 勝者をチェックする関数
char mark = (player == 1) ? player_mark : computer_mark;
for (int i = 0; i < 3; i++) {
if (board[i * 3] == mark && board[i * 3 + 1] == mark && board[i * 3 + 2] == mark) {
return player;
} else if (board[i] == mark && board[i + 3] == mark && board[i + 6] == mark) {
return player;
}
}
if (board[0] == mark && board[4] == mark && board[8] == mark) {
return player;
} else if (board[2] == mark && board[4] == mark && board[6] == mark) {
return player;
}
return 0;
}
int main() {
int turn = 1;
int winner = 0;
int choice;
cout << "Welcome to Tic-Tac-Toe!" << endl << endl;
cout << "Player 1 is X." << endl;
while (turn)
{
if (turn % 2 == 1) {
// プレイヤーのターン
draw_board();
cout << "Player 1, your turn." << endl;
choice = get_player_choice();
board[choice] = player_mark;
winner = check_win(player);
} else {
// コンピュータのターン
draw_board();
cout << "Computer's turn." << endl;
choice = get_computer_choice();
if (choice >= 0) {
board[choice] = computer_mark;
}
winner = check_win(computer);
}
turn++;
if (winner != 0) {
draw_board();
if (winner == player) {
cout << "Congratulations, you win!" << endl;
} else {
cout << "The computer wins." << endl;
}
break;
} else if (turn > 9) {
draw_board();
cout << "It's a tie." << endl;
break;
}
}
return 0;
}
このプログラムでは、vector を使用して1次元の盤面を表現しています。get_player_choice() 関数では、プレイヤーに1から9までの数字を入力させ、その数字が選択可能かどうかをチェックして、選択可能な場合にはインデックスに変換して返します。get_computer_choice() 関数では、空きマスを検索して、ランダムに選択します。check_win() 関数では、行、列、斜めのいずれかに同じマークが揃っているかどうかをチェックして、勝者がいる場合にはそのプレイヤーの番号を返します。
また、このプログラムでは、マークの種類やプレイヤーの番号など、いくつかの定数を使用しています。これにより、プログラム全体で同じ定数を使用することができ、プログラムをより読みやすく、保守性が高くなります。
(私)
いいですね!次は上記プログラムをベースに、デザインパターン:ストラテジーを組んでCPUの思考方法を将来的に変更できるように改造してください。
(chatGPT)
了解しました。以下が、ストラテジーパターンを使用してCPUの思考方法を柔軟に変更できるようにしたプログラムです。
#include <iostream>
#include <vector>
#include <random>
using namespace std;
// 盤面を表すベクター
vector<char> board(9, ' ');
// プレイヤーのマークとコンピュータのマーク
const char player_mark = 'X';
const char computer_mark = 'O';
// ヒューマンプレイヤーを表すクラス
class HumanPlayer {
public:
// 人間が次の手を選ぶためのメソッド
int get_choice() {
int choice;
while (true) {
cout << "Enter a number (1-9): ";
cin >> choice;
if (choice < 1 || choice > 9 || board[choice - 1] != ' ') {
cout << "Invalid choice. Please try again." << endl;
} else {
return choice - 1;
}
}
}
};
// コンピュータの戦略を表す抽象クラス
class Strategy {
public:
// 次の手を選ぶためのメソッド
virtual int get_choice(const vector<char>& board, char mark) = 0;
};
// ランダムな戦略を表すクラス
class RandomStrategy : public Strategy {
public:
// 次の手をランダムに選ぶメソッド
int get_choice(const vector<char>& board, char mark) {
vector<int> choices;
for (int i = 0; i < 9; i++) {
if (board[i] == ' ') {
choices.push_back(i);
}
}
if (choices.size() > 0) {
uniform_int_distribution<int> distribution(0, choices.size() - 1);
return choices[distribution(random_engine)];
} else {
return -1;
}
}
private:
// 乱数を生成するためのエンジン
default_random_engine random_engine{random_device{}()};
};
// スマートな戦略を表すクラス
class SmartStrategy : public RandomStrategy {
public:
// スマートなアルゴリズムを用いて次の手を選ぶメソッド
int get_choice(const vector<char>& board, char mark) {
// 自分が勝てる手があるかどうかをチェック
for (int i = 0; i < 9; i++) {
if (board[i] == ' ') {
vector<char> new_board(board);
new_board[i] = mark;
if (check_win(new_board, mark)) {
return i;
}
}
}
// 相手が勝てる手を防ぐための手があるかどうかをチェック
for (int i = 0; i < 9; i++) {
if (board[i] == ' ') {
vector<char> new_board(board);
new_board[i] = (mark == 'X') ? 'O' : 'X';
if (check_win(new_board, (mark == 'X') ? 'O' : 'X')) {
return i;
}
}
}
// 上記のいずれの手もない場合は、ランダムな手を選ぶ
return RandomStrategy::get_choice(board, mark);
}
private:
// 自分が勝つ手があるかどうかをチェックするためのメソッド
bool check_win(const vector<char>& board, char mark) {
for (int i = 0; i < 3; i++) {
if (board[i * 3] == mark && board[i * 3 + 1] == mark && board[i * 3 + 2] == mark) {
return true;
} else if (board[i] == mark && board[i + 3] == mark && board[i + 6] == mark) {
return true;
}
}
if (board[0] == mark && board[4] == mark && board[8] == mark) {
return true;
} else if (board[2] == mark && board[4] == mark && board[6] == mark) {
return true;
}
return false;
}
};
// コンピュータを表すクラス
class Computer {
public:
// コンピュータが次の手を選ぶためのメソッド
Computer(Strategy& strategy) : strategy(strategy) {}
int get_choice(const vector<char>& board, char mark) {
return strategy.get_choice(board, mark);
}
private:
Strategy& strategy;
};
// 盤面を表示する関数
void draw_board() {
cout << "\n " << board[0] << " | " << board[1] << " | " << board[2] << endl;
cout << "---+---+---" << endl;
cout << " " << board[3] << " | " << board[4] << " | " << board[5] << endl;
cout << "---+---+---" << endl;
cout << " " << board[6] << " | " << board[7] << " | " << board[8] << endl << endl;
}
// 勝敗をチェックする関数
int check_win(const vector<char>& board, char mark) {
for (int i = 0; i < 3; i++) {
if (board[i * 3] == mark && board[i * 3 + 1] == mark && board[i * 3 + 2] == mark) {
return 1;
} else if (board[i] == mark && board[i + 3] == mark && board[i + 6] == mark) {
return 1;
}
}
if (board[0] == mark && board[4] == mark && board[8] == mark) {
return 1;
} else if (board[2] == mark && board[4] == mark && board[6] == mark) {
return 1;
}
return 0;
}
// メイン関数
int main() {
// ヒューマンプレイヤーとコンピュータを作成
HumanPlayer human_player;
Computer computer_player(SmartStrategy());
// ゲームの初期設定
int turn = 1
int winner = 0;
int choice;
cout << "Welcome to Tic-Tac-Toe!" << endl << endl;
cout << "Player 1 is X." << endl;
// ゲームを開始
while (true) {
// プレイヤーが交互に手を選ぶ
if (turn % 2 == 1) {
draw_board();
cout << "Player 1, your turn." << endl;
choice = human_player.get_choice();
board[choice] = player_mark;
winner = check_win(board, player_mark);
} else {
draw_board();
cout << "Computer's turn." << endl;
choice = computer_player.get_choice(board, computer_mark);
board[choice] = computer_mark;
winner = check_win(board, computer_mark);
}
// 勝敗がついた場合、終了
turn++;
if (winner) {
draw_board();
if (winner == 1) {
cout << "Congratulations, you win!" << endl;
} else {
cout << "The computer wins." << endl;
}
break;
} else if (turn > 9) {
draw_board();
cout << "It's a tie." << endl;
break;
}
}
return 0;
}
このプログラムでは、まず盤面を表す board ベクターを定義しました。HumanPlayer クラスと Strategy クラスを定義し、RandomStrategy クラスと SmartStrategy クラスを作成しました。Computer クラスは、Strategy クラスを使用して、次の手を選びます。draw_board() 関数は、盤面を表示するために使用されます。check_win() 関数は、勝敗をチェックするために使用されます。
メイン関数では、HumanPlayer クラスと Computer クラスを作成し、ゲームを開始します。交互に手を選び、勝敗がつくか、引き分けになるまで繰り返します。SmartStrategy クラスでは、より複雑なアルゴリズムを使用することで、CPUの強さを向上させています。また、プログラムは、ストラテジーパターンを使用しているため、将来的に異なる戦略を簡単に実装することができます。