質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

4164閲覧

C++でのオセロゲームについて

退会済みユーザー

退会済みユーザー

総合スコア0

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2016/09/08 13:18

色々手を尽くしましたが、自力で解決できないため教えていただければと思い質問いたします。
学習のためhttps://gist.github.com/mia-0032/5325961に掲載されているオセロプログラムをC++に移植しようとしています。
ほぼ作成は完成したものの最初の1手を打った後は全てAIが白黒の両方を打ってゲームが終了してしまいます。プレイヤーチェンジ部分のコード等を何度も確認しましたが、原因が分かりませんでした。
なお、リファクタリングもまだしていないためコードはハードコーディングもあり汚いですが、よろしくお願いいたします。

#include "Board.h"

//初期化処理(ゲームオーバー後の再開があるためコンストラクタに含められない)
void Board::Init()
{
//配列を初期化
for (int y = 0; y < MATRIX_NUM; y++) {
for (int x = 0; x < MATRIX_NUM; x++) {
board.get()[x][y] = 0;
}
}

//最初に置いてある石 board.get()[MATRIX_NUM / 2 - 1][MATRIX_NUM / 2 - 1] = WHITE; board.get()[MATRIX_NUM / 2 - 1][MATRIX_NUM / 2] = BLACK; board.get()[MATRIX_NUM / 2][MATRIX_NUM / 2 - 1] = BLACK; board.get()[MATRIX_NUM / 2][MATRIX_NUM / 2] = WHITE; //先手は黒 player = BLACK; rival = WHITE; //メッセージ初期化 for (auto& a : message) { a = TEXT('\0'); } //現在の石数をカウント CountStones();

}

//石数のカウント
void Board::CountStones()
{
black_count = 0;
white_count = 0;

for (int y = 0; y < MATRIX_NUM; y++) { for (int x = 0; x < MATRIX_NUM; x++) { if (board.get()[x][y] == BLACK) { black_count++; } else if (board.get()[x][y] == WHITE) { white_count++; } } }

}

//石描画メソッド
void Board::DrawStone(const HDC& mhdc, int player, int x, int y)
{
if (player == BLACK) {
HPEN oldPen = (HPEN)SelectObject(mhdc, GetStockObject(NULL_PEN));
HBRUSH brush = CreateSolidBrush(RGB(0x00,0x00,0x00));
HBRUSH oldBrush = (HBRUSH)SelectObject(mhdc, brush);
Ellipse(mhdc, x, y, x + 28, y + 28);
SelectObject(mhdc, oldPen);
SelectObject(mhdc, oldBrush);
DeleteObject(brush);
}
else if (player == WHITE) {
HPEN oldPen = (HPEN)SelectObject(mhdc, GetStockObject(NULL_PEN));
HBRUSH brush = CreateSolidBrush(RGB(0xFF, 0xFF, 0xFF));
HBRUSH oldBrush = (HBRUSH)SelectObject(mhdc, brush);
Ellipse(mhdc, x, y, x + 28, y + 28);
SelectObject(mhdc, oldPen);
SelectObject(mhdc, oldBrush);
DeleteObject(brush);
}
}

void Board::UserStatusDraw(const HDC& mhdc)
{
HPEN pen = CreatePen(PS_SOLID, 1, RGB(0x00, 0x00, 0x00));
HPEN oldPen = (HPEN)SelectObject(mhdc, pen);
HBRUSH oldBrush = (HBRUSH)SelectObject(mhdc, GetStockObject(NULL_BRUSH));

//画面下のプレイヤー部分 Rectangle(mhdc, 260, 220, 290, 250); DrawStone(mhdc, player, 261, 221); wchar_t* turn = TEXT("Turn"); RECT rect; rect.left = 263; rect.top = 235; StringDraw(mhdc, rect, turn, this->player); SelectObject(mhdc, oldPen); SelectObject(mhdc, oldBrush); DeleteObject(pen); //画面上のプレイヤー部分 DrawStone(mhdc, BLACK, 261, 11); wchar_t blackCount[3] = { TEXT('\0') }; wsprintf(blackCount, TEXT("%d"), black_count); rect.left = 269; rect.top = 18; StringDraw(mhdc, rect, blackCount,BLACK); DrawStone(mhdc, WHITE, 261, 71); wchar_t whiteCount[3] = { TEXT('\0') }; wsprintf(whiteCount, TEXT("%d"), white_count); rect.left = 269; rect.top = 78; StringDraw(mhdc, rect, whiteCount, WHITE); if (wcslen(message) > 0) { rect.left = 20; rect.top = 120; rect.right = 240; rect.bottom = 40; HPEN pen = CreatePen(PS_SOLID, 1, RGB(0xFF, 0x00, 0x00)); HPEN oldPen = (HPEN)SelectObject(mhdc, pen); HBRUSH oldBrush = (HBRUSH)SelectObject(mhdc, GetStockObject(WHITE_BRUSH)); Rectangle(mhdc, rect.left, rect.top, rect.right, rect.bottom); SelectObject(mhdc, oldBrush); SelectObject(mhdc, oldPen); DeleteObject(pen); rect.left = 100; rect.top = 75; StringDraw(mhdc, rect, message, 99); }

}

void Board::StringDraw(const HDC& mhdc, RECT& rect, wchar_t* str, int player)
{
if (mhdc == NULL || str == NULL) {
return;
}

HFONT font = CreateFont(12, 0, 0, 0, FW_EXTRALIGHT, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH | FF_ROMAN, NULL); SetBkMode(mhdc, TRANSPARENT); if (player == BLACK) { SetTextColor(mhdc, RGB(0xFF, 0xFF, 0xFF)); } else if (player == WHITE) { SetTextColor(mhdc, RGB(0x00, 0x00, 0x00)); } else { SetTextColor(mhdc, RGB(0x00, 0x00, 0x00)); } SelectObject(mhdc, font); TextOut(mhdc, rect.left, rect.top, str, lstrlen(str)); DeleteObject(font);

}

//指定したマスにそのプレイヤーの石が置かれているか判定
bool Board::Check(int x, int y, int player)
{
//xとyともにMATRIX_NUMの範囲内かつ指定された配列の場所に引数のプレイヤーが格納されている場合
if (x >= 0 && x < MATRIX_NUM && y >= 0 && y < MATRIX_NUM && (board.get()[x][y] == player)) {
return true;
}
else {
return false;
}
}

//今のプレイヤーが打った時に一方向に裏返すことができる石の数
int Board::CountStone(int x, int y, int dx, int dy)
{
int x1 = x + dx;
int y1 = y + dy;
int stone = 0;

while (Check(x1, y1, rival)) { x1 += dx; y1 += dy; stone++; } if (Check(x1, y1, player)) { return stone; } else { return 0; }

}

//今のプレイヤーが打った時に全方向に対して裏返すことができる石の数
int Board::CountStone(int x, int y)
{
int stone = 0;
if (Check(x, y, 0)) {
stone += CountStone(x, y, 1, 0); //右
stone += CountStone(x, y, -1, 0); //左
stone += CountStone(x, y, 0, 1); //下
stone += CountStone(x, y, 0, -1); //上
stone += CountStone(x, y, 1, 1); //右下
stone += CountStone(x, y, 1, -1); //右上
stone += CountStone(x, y, -1, 1); //左下
stone += CountStone(x, y, -1, -1); //左上
}

return stone;

}

bool Board::CanPut()
{
for (int y = 0; y < MATRIX_NUM; y++) {
for (int x = 0; x < MATRIX_NUM; x++) {
if (CountStone(x, y) > 0) {
return true;
}
}
}

return false;

}

//石を置くメソッド(一方向のみ裏返す)
int Board::PutStone(int x, int y, int dx, int dy)
{
int stone = CountStone(x, y, dx, dy);
for (int i = 1; i <= stone; i++) {
board.get()[x + dx * i][y + dy * i] = player;
}
return stone;
}

//石を置くメソッド(全方向について裏返す)
int Board::PutStone(int x, int y)
{
int stone = 0;
if (Check(x, y, 0)) {
stone += PutStone(x, y, 1, 0); // 右
stone += PutStone(x, y, -1, 0); // 左
stone += PutStone(x, y, 0, 1); // 下
stone += PutStone(x, y, 0, -1); // 上
stone += PutStone(x, y, 1, 1); // 右下
stone += PutStone(x, y, 1, -1); // 右上
stone += PutStone(x, y, -1, 1); // 左下
stone += PutStone(x, y, -1, -1); // 左上

if (stone > 0) { board.get()[x][y] = player; stone++; CountStones(); } } return stone;

}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

1回で書き込みできなかったので残りのコードです。

int Board::Change()
{
int p = this->player;
this->player = this->rival;
this->rival = p;

if (CanPut()) { //交代 return 1; } this->rival = this->player; this->player = p; if (CanPut()) { //次の人はパス return 2; } //ここからは両方とも置けない時 if (black_count > white_count) { wchar_t* tmp = TEXT("Black Wins!"); wsprintf(message, TEXT("%s"), tmp); } else if (black_count < white_count) { wchar_t* tmp = TEXT("White Wins!"); wsprintf(message, TEXT("%s"), tmp); } else { wchar_t* tmp = TEXT("Draw!"); wsprintf(message, TEXT("%s"), tmp); } return 3;

}

void Board::RandomThink()
{
std::random_device rnd;
std::mt19937 mt(rnd());
std::uniform_int_distribution<int> num(0, MATRIX_NUM - 1);
int x;
int y;

do { x = num(mt); y = num(mt); } while (PutStone(x, y) == 0);

}

void Board::MonteCarloMethodThink()
{
std::random_device rnd;
std::mt19937 mt(rnd());
std::uniform_int_distribution<int> num(0, MATRIX_NUM - 1);

int p = this->player; int r = this->rival; std::unique_ptr<int[][MATRIX_NUM]> win(new int[MATRIX_NUM][MATRIX_NUM]); std::unique_ptr<int[][MATRIX_NUM]> bak(new int[MATRIX_NUM][MATRIX_NUM]); if (win.get() == nullptr || bak.get() == nullptr) { return; } for (int y = 0; y < MATRIX_NUM; y++) { for (int x = 0; x < MATRIX_NUM; x++) { bak.get()[x][y] = board.get()[x][y]; } } int max = 0; int tx = 0; int ty = 0; for (int i = 1; i <= 1000; i++) { int x1 = -1; int y1 = -1; for (;;) { int x2 = num(mt); int y2 = num(mt); if (PutStone(x2, y2) > 0) { if (x1 < 0) { x1 = x2; y1 = y2; } if (Change() == 3) { return; } } } if ((p == 1 && black_count > white_count) || (p == 2 && black_count < white_count)) { win.get()[x1][y1]++; if (max < win.get()[x1][y1]) { max = win.get()[x1][y1]; tx = x1; ty = y1; } } for (int y = 0; y < MATRIX_NUM; y++) { for (int x = 0; x < MATRIX_NUM; x++) { bak.get()[x][y] = board.get()[x][y]; } } this->player = p; this->rival = r; } for (auto& a : message) { a = TEXT('\0'); } CountStones(); if (max > 0) { PutStone(tx, ty); } else { RandomThink(); }

}

//コンストラクタ
Board::Board()
{
board.reset(new int[MATRIX_NUM][MATRIX_NUM]);
white_count = 0;
black_count = 0;

for (auto& a : message) { a = TEXT('\0'); } //初期化処理 Init();

}

//描画メソッド
void Board::Draw(HWND& hWnd, HBITMAP& hbitmap, PAINTSTRUCT& ps, RECT& rect)
{
HDC hdc = BeginPaint(hWnd, &ps);
HDC mhdc = CreateCompatibleDC(hdc);
hbitmap = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
SelectObject(mhdc, hbitmap);

//盤面背景描画 HBRUSH brush = CreateSolidBrush(RGB(0x00, 0xAA, 0xAA)); HBRUSH oldbrush = (HBRUSH)SelectObject(mhdc, brush); HPEN oldpen = (HPEN)SelectObject(mhdc, GetStockObject(NULL_PEN)); Rectangle(mhdc, 0, 0, rect.right, rect.bottom); SelectObject(mhdc, oldbrush); DeleteObject(brush); SelectObject(mhdc, oldpen); //盤面の線を描画 HPEN linePen = CreatePen(PS_SOLID, 1, RGB(0x00, 0x00, 0x00)); oldpen = (HPEN)SelectObject(mhdc, linePen); for (int i = 0; i <= MATRIX_NUM; i++) { //縦線の始点に移動 MoveToEx(mhdc, i * 30 + 10, 10, NULL); //線を引く終点を指定 LineTo(mhdc, i * 30 + 10, 250); //横線の始点に移動 MoveToEx(mhdc, 10, i * 30 + 10, NULL); //線を引く終点を指定 LineTo(mhdc, 250, i * 30 + 10); } SelectObject(mhdc, oldpen); DeleteObject(linePen); //石を描画 for (int y = 0; y < MATRIX_NUM; y++) { for (int x = 0; x < MATRIX_NUM; x++) { DrawStone(mhdc, board.get()[x][y], x * 30 + 11, y * 30 + 11); } } //ユーザー情報を描画 UserStatusDraw(mhdc); //ビットマップ転送 BitBlt(hdc, 0, 0, rect.right, rect.bottom, mhdc, 0, 0, SRCCOPY); //各種事後処理 DeleteObject(hbitmap); DeleteObject(mhdc); EndPaint(hWnd, &ps);

}

//石を置くメソッド
void Board::OnMouseDown(HWND& hWnd, POINT& MousePostion)
{
int x = (MousePostion.x - 10) / 30;
int y = (MousePostion.y - 10) / 30;

if (PutStone(x, y) > 0) { if (Change() == 1) { do { InvalidateRect(hWnd, NULL, FALSE); MonteCarloMethodThink(); } while (Change() == 2); } InvalidateRect(hWnd, NULL, FALSE); }

}

//ゲームオーバー状態判定メソッド
bool Board::IsGameOver()
{
if (wcslen(message) <= 0) {
return false;
}
else {
return true;
}
}

投稿2016/09/08 13:21

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問