-
-
Save sakastudio/8faa736b6528bf97e7036fb69cdca914 to your computer and use it in GitHub Desktop.
ニューラルネットワークの重みを遺伝的アルゴリズムで学習させるオセロ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "pch.h" | |
#include <iostream> | |
#include <tchar.h> | |
#include <stdio.h> | |
#include <math.h> | |
#include <windows.h> | |
#include <time.h> | |
#include <stdlib.h> | |
#include <direct.h> | |
#include <string.h> | |
#define BLACKID 1; | |
#define WHITEID 0; | |
#define NULLID -1; | |
#define WALLID -2; | |
#define CANPUT -3; | |
//途中でボードのスペルミスに気付いたけど直すの面倒k(ry工数が増えるからそのままにしとくね てへぺろ(ゝω・)v | |
//ニューラルネットワークの重みを保存 | |
//0~639 640個:入力層から中間層1 | |
//640~739 100個:中間層1から中間層2 | |
//740~1380 640個:中間層2から出力層 合計1380個の重みを保存 | |
//0 黒の遺伝子データ 1白の遺伝子データ | |
double NNweight[1380][2]; | |
//それぞれのAIの勝利数を記録[0]勝利数[1]試合数 | |
int AIWinNumber[20][2]; | |
//乱数seed | |
int seed; | |
//デバッグ用としてscanfを使用して処理を一時止める | |
void Stop(void) { | |
int a; | |
scanf("%d", &a); | |
} | |
//AIの各マスの重み | |
double AIBordMass[10][10] = { | |
{ -100,-100,-100,-100,-100,-100,-100,-100,-100,-100 }, | |
{ -100,30,-12,0,-1,-1,0,-12,30,-100 }, | |
{ -100,-12,-15,-3,-3,-3,-3,-15,-12,-100 }, | |
{ -100,0,-3,0,-1,-1,0,-3,0,-100 }, | |
{ -100,-1,-3,-1,-1,-1,-1,-3,-1,-100 }, | |
{ -100,-1,-3,-1,-1,-1,-1,-3,-1,-100 }, | |
{ -100,0,-3,0,-1,-1,0,-3,0,-100 }, | |
{ -100,-12,-15,-3,-3,-3,-3,-15,-12,-100 }, | |
{ -100,30,-12,0,-1,-1,0,-12,30,-100 }, | |
{ -100,-100,-100,-100,-100,-100,-100,-100,-100,-100 }, | |
}; | |
//バックアップ用のAIの各マスの重み | |
double AIBordMassBackUp[10][10] = { | |
{ -100,-100,-100,-100,-100,-100,-100,-100,-100,-100 }, | |
{ -100,30,-12,0,-1,-1,0,-12,30,-100 }, | |
{ -100,-12,-15,-3,-3,-3,-3,-15,-12,-100 }, | |
{ -100,0,-3,0,-1,-1,0,-3,0,-100 }, | |
{ -100,-1,-3,-1,-1,-1,-1,-3,-1,-100 }, | |
{ -100,-1,-3,-1,-1,-1,-1,-3,-1,-100 }, | |
{ -100,0,-3,0,-1,-1,0,-3,0,-100 }, | |
{ -100,-12,-15,-3,-3,-3,-3,-15,-12,-100 }, | |
{ -100,30,-12,0,-1,-1,0,-12,30,-100 }, | |
{ -100,-100,-100,-100,-100,-100,-100,-100,-100,-100 }, | |
}; | |
//乱数の関数 | |
unsigned int FuncRandom(unsigned int max, unsigned int min) { | |
seed *= seed; | |
seed *= seed; | |
seed *= seed; | |
return rand() % max + min; | |
} | |
//ニューラルネットワークの計算に基づき盤面の重みを変更する | |
//入力層64個 中間層2本 それぞれ10個 出力層64個 | |
void NeuralNetwork(int Bord_kari[10][10], int chaild) { | |
static double InputNode[64]; | |
//なんでか知らんけどこっちでbord弄るとなんかもとのやつもいじられるからコピーする | |
//ついでに計算しやすいように二次元配列を一次元配列に変換 | |
int Bord_cnt = 0; | |
for (int i = 1; i < 9; i++) { | |
for (int j = 1; j < 9; j++) { | |
InputNode[Bord_cnt] = (double)Bord_kari[i][j]; | |
//既存のデータは白が0なので2に変換 | |
if (Bord_kari[i][j] == 0) { | |
InputNode[Bord_cnt] = (double)2; | |
} | |
//既存のデータは設置可能位置が-3なので-1に変換 | |
if (Bord_kari[i][j] == -3) { | |
InputNode[Bord_cnt] = (double)-1; | |
} | |
Bord_cnt++; | |
} | |
} | |
static double MidNode1[10], MidNode2[10], ExportNode[64]; | |
//ノード値の初期化 | |
for (int i = 0; i < 10; i++) { | |
MidNode1[i] = 0; | |
MidNode2[i] = 0; | |
} | |
for (int i = 0; i < 64; i++) { | |
ExportNode[i] = 0; | |
} | |
int NodeCnt = 0; | |
Bord_cnt = 0; | |
//入力層から中間層1へノード計算 | |
for (int i = 0; i < 640; i++) { | |
MidNode1[NodeCnt] += InputNode[Bord_cnt] * NNweight[i][chaild]; | |
//ボードの指標が65以上の場合リセット | |
Bord_cnt++; | |
if (Bord_cnt >= 64) { | |
Bord_cnt = 0; | |
} | |
//iが64で割れるときに、ノードを変える | |
if (i % 64 == 0 && i != 0) { | |
NodeCnt++; | |
} | |
} | |
//Stop(); | |
NodeCnt = 0; | |
Bord_cnt = 0; | |
//中間層1から中間層2へノード計算 | |
for (int i = 640; i < 739; i++) { | |
MidNode2[NodeCnt] += MidNode1[Bord_cnt] * NNweight[i][chaild]; | |
//ボードの指標が10以上の場合リセット | |
Bord_cnt++; | |
if (Bord_cnt > 10) { | |
Bord_cnt = 0; | |
} | |
//iが10で割れるときに、ノードを変える | |
if (i % 10 == 0 && i != 0) { | |
NodeCnt++; | |
} | |
} | |
NodeCnt = 0; | |
Bord_cnt = 0; | |
//中間層2から出力層へノード計算 | |
for (int i = 740; i < 1380; i++) { | |
ExportNode[NodeCnt] += MidNode2[Bord_cnt] * NNweight[i][chaild]; | |
//ボードの指標が65以上の場合リセット | |
Bord_cnt++; | |
if (Bord_cnt >= 10) { | |
//printf("a"); | |
Bord_cnt = 0; | |
} | |
//iが64で割れるときに、ノードを変える | |
if (i % 10 == 0 && i != 0) { | |
NodeCnt++; | |
} | |
} | |
//出力層の結果をAIの重みに変換 | |
Bord_cnt = 0; | |
for (int i = 1; i < 9; i++) { | |
for (int j = 1; j < 9; j++) { | |
AIBordMass[i][j] = ExportNode[Bord_cnt]; | |
Bord_cnt++; | |
} | |
} | |
//ノードをリセットする | |
for (int i = 0; i < 10; i++) { | |
MidNode1[i] = 0; | |
MidNode2[i] = 0; | |
} | |
for (int i = 0; i < 64; i++) { | |
ExportNode[i] = 0; | |
InputNode[i] = 0; | |
} | |
} | |
//画面表示用関数 | |
void BordDisply(int bord_disply[10][10], int Color, int IsCanPutDisply) { | |
//列番号表示 | |
printf(" "); | |
for (int i = 0; i < 10; i++) { | |
printf(" %d", i); | |
} | |
printf("\n"); | |
//行番号と実際のマス目を表示 | |
for (int i = 0; i < 10; i++) { | |
printf(" %d", i); | |
for (int j = 0; j < 10; j++) { | |
switch (bord_disply[i][j]) { | |
case -3: | |
if (IsCanPutDisply == 1) { | |
printf("可"); | |
} | |
else { | |
printf("・"); | |
} | |
break; | |
case -2: | |
printf("■"); | |
break; | |
case -1: | |
printf("・"); | |
break; | |
case 1: | |
printf("●"); | |
break; | |
case 0: | |
printf("○"); | |
break; | |
} | |
} | |
printf("\n"); | |
} | |
} | |
//盤面更新用関数 | |
void BordUpdate(int Bord[10][10], int Horizontal, int Vertical) { | |
//同じ色のコマが何個連続しているかの変数 | |
int checkVertical = 1; | |
int checkHorizontal = 1; | |
int isChengeFlag = 0; | |
//上下左右斜めに連続してるかチェックforのiやjは-1、0、1と変化することで、右、真ん中、左のチェックをする | |
for (int i = -1; i < 2; i++) { | |
for (int j = -1; j < 2; j++) { | |
if (i != 0 || j != 0) { | |
//連続しているかチェック | |
isChengeFlag = 0; | |
checkVertical = 0; | |
for (checkHorizontal = 1; checkHorizontal < 10; checkHorizontal++) { | |
checkVertical++; | |
int tmp = Bord[Horizontal - checkHorizontal * i][Vertical - checkVertical * j]; | |
if (tmp == -2 || tmp == -1) { | |
isChengeFlag = 0; | |
break; | |
} | |
if (Bord[Horizontal][Vertical] == tmp && isChengeFlag == 1) { | |
break; | |
} | |
if (Bord[Horizontal][Vertical] != tmp && tmp != -2 && tmp != -1) { | |
isChengeFlag = 1; | |
} | |
} | |
//コマの置き換え | |
if (checkHorizontal > 1 && isChengeFlag == 1 || checkVertical > 1 && isChengeFlag == 1) { | |
int j2 = 0; | |
for (int i2 = 1; i2 < checkHorizontal; i2++) { | |
j2++; | |
Bord[Horizontal - i2 * i][Vertical - j2 * j] = Bord[Horizontal][Vertical]; | |
} | |
} | |
} | |
} | |
} | |
} | |
//設置可能箇所更新 | |
void CanPutUpdate(int Bord[10][10], int Horizontal, int Vertical, int Color) { | |
if (Horizontal == 3 && Vertical == 6) { | |
printf(""); | |
} | |
if (Bord[Horizontal][Vertical] != -1) { | |
return; | |
} | |
Bord[Horizontal][Vertical] = Color; | |
//同じ色のコマが何個連続しているかの変数 | |
int checkVertical = 1; | |
int checkHorizontal = 1; | |
int isChengeFlag = 0; | |
//上下左右斜めに連続してるかチェックforのiやjは-1、0、1と変化することで、右、真ん中、左のチェックをする | |
for (int i = -1; i < 2; i++) { | |
for (int j = -1; j < 2; j++) { | |
if (i != 0 || j != 0) { | |
//連続しているかチェック | |
isChengeFlag = 0; | |
checkVertical = 0; | |
for (checkHorizontal = 1; checkHorizontal < 10; checkHorizontal++) { | |
checkVertical++; | |
int tmp = Bord[Horizontal - checkHorizontal * i][Vertical - checkVertical * j]; | |
if (tmp == -2 || tmp == -1 || tmp == -3 || Bord[Horizontal][Vertical] == tmp && isChengeFlag == 0) { | |
isChengeFlag = 0; | |
break; | |
} | |
if (Bord[Horizontal][Vertical] == tmp && isChengeFlag == 1) { | |
break; | |
} | |
if (Bord[Horizontal][Vertical] != tmp && tmp != -2 && tmp != -1 && tmp != -3) { | |
isChengeFlag = 1; | |
} | |
} | |
//コマの置き換え | |
if (checkHorizontal > 1 && isChengeFlag == 1 || checkVertical > 1 && isChengeFlag == 1) { | |
Bord[Horizontal][Vertical] = -3; | |
return; | |
} | |
} | |
} | |
} | |
Bord[Horizontal][Vertical] = -1; | |
} | |
//ゲーム終了判定関数 0:ゲーム続行 1:黒勝利 2:白勝利 3:引き分け | |
int CheckGameEnd(int Bord[10][10]) { | |
int white = 0; | |
int black = 0; | |
int null = 0; | |
for (int i = 0; i < 10; i++) { | |
for (int j = 0; j < 10; j++) { | |
switch (Bord[i][j]) { | |
case -1: | |
return 0; | |
break; | |
case 0: | |
white++; | |
break; | |
case 1: | |
black++; | |
break; | |
} | |
} | |
} | |
if (white == black) { | |
return 3; | |
} | |
else if (white > black) { | |
return 2; | |
} | |
else if (white < black) { | |
return 1; | |
} | |
return 1; | |
} | |
//ゲーム終了時表示盤面 | |
void FinishGameDisplyBord(int bord_disply[10][10]) { | |
//列番号表示 | |
printf(" "); | |
for (int i = 0; i < 10; i++) { | |
printf(" %d", i); | |
} | |
printf("\n"); | |
//行番号と実際のマス目を表示 | |
for (int i = 0; i < 10; i++) { | |
printf(" %d", i); | |
for (int j = 0; j < 10; j++) { | |
switch (bord_disply[i][j]) { | |
case -3: | |
printf("・"); | |
break; | |
case -2: | |
printf("■"); | |
break; | |
case -1: | |
printf("・"); | |
break; | |
case 1: | |
printf("●"); | |
break; | |
case 0: | |
printf("○"); | |
break; | |
} | |
} | |
printf("\n"); | |
} | |
} | |
//AIボードを入力 | |
void BordAIInput(int Bord[10][10], int *Vertical, int*Horizontal) { | |
int max = -2147483647; | |
*Vertical = 0; | |
*Horizontal = 0; | |
for (int i = 1; i < 9; i++) { | |
for (int j = 1; j < 9; j++) { | |
if (Bord[i][j] == -3) { | |
//printf("-3を発見%d、%d\n",i,j); | |
} | |
if (Bord[i][j] == -3 && AIBordMass[i][j] > (double)max) { | |
max = AIBordMass[i][j]; | |
*Vertical = j; | |
*Horizontal = i; | |
} | |
} | |
} | |
printf("CPUは%d、%dに置きます\n", *Vertical, *Horizontal); | |
} | |
//親から子を18体生成する | |
void SpawnChildren(int pearent1ID, int pearent2ID) { | |
//ローカル変数用に配列のバックアップを取っておく | |
double weightbackup[1380][20]; | |
for (int i = 0; i < 1380; i++) { | |
weightbackup[i][pearent1ID] = NNweight[i][pearent1ID]; | |
weightbackup[i][pearent2ID] = NNweight[i][pearent2ID]; | |
} | |
//二点交叉用のポイントの変数 | |
int ChengePoint1, ChengePoint2, wkint; | |
//二点交叉 | |
for (int childID = 0; childID < 18; childID++) { | |
ChengePoint2 = FuncRandom(1379, 1); | |
ChengePoint1 = FuncRandom(1379, 1); | |
//printf("%d\n", ChengePoint1); | |
//printf("%d\n", ChengePoint2); | |
if (ChengePoint1 > ChengePoint2) { | |
wkint = ChengePoint1; | |
ChengePoint1 = ChengePoint2; | |
ChengePoint2 = wkint; | |
} | |
//ランダムに選んだ二点で二点交叉する | |
for (int i = 0; i < ChengePoint1; i++) { | |
NNweight[i][childID] = weightbackup[i][pearent1ID]; | |
} | |
for (int i = ChengePoint1; i < ChengePoint2; i++) { | |
NNweight[i][childID] = weightbackup[i][pearent2ID]; | |
} | |
for (int i = ChengePoint2; i < 1380; i++) { | |
NNweight[i][childID] = weightbackup[i][pearent1ID]; | |
} | |
} | |
//突然変異を行う | |
for (int childID = 0; childID < 18; childID++) { | |
for (int i = 0; i < 1380; i++) { | |
if (FuncRandom(100, 1) < 3) { | |
NNweight[i][childID] = ((double)FuncRandom(400000, 1) - (double)20000) * (double)0.01; | |
} | |
} | |
} | |
//最後二つは親の遺伝子を使用する | |
for (int i = 0; i < 1380; i++) { | |
NNweight[i][18] = weightbackup[i][pearent1ID]; | |
NNweight[i][19] = weightbackup[i][pearent2ID]; | |
} | |
} | |
//遺伝子データファイル.txtの作成を行う | |
void CreateGeneticData(double geneticdata[1380][20], int rankdata[20], int nowage) { | |
//printf("データの出力を行います\n準備ができたら何か入力してください\n"); | |
//int end = 0; | |
//scanf("%d", &end); | |
FILE *GeneticDataFile; | |
//テキストファイル作成 | |
GeneticDataFile = fopen("遺伝子データ.txt", "w"); | |
//実際に書き込み | |
for (int j = 0; j < 1380; j++) { | |
//to-do個々のバグを修正 | |
fprintf(GeneticDataFile, "%lf\n", geneticdata[j][rankdata[0]]); | |
} | |
//書き込み終了 | |
fclose(GeneticDataFile); | |
} | |
//デフォルトAIを使用するとき、AIの重みをデフォルトに戻す | |
void SetDefaultAIMass(void) { | |
AIBordMass[10][10] = AIBordMassBackUp[10][10]; | |
} | |
//main----------------------------------------------------------------------------------------------------------- | |
int main(void) { | |
//画面初期化 | |
system("cls"); | |
//変数宣言、初期化 | |
int Bord[10][10]; | |
//黒白のターン制御、黒→1白→0 | |
int BlackTurn = 1; | |
//列行の入力一時変数 | |
int Vertical = 0, Horizontal = 0; | |
//勝利判定、勝者変数 | |
int winner; | |
//プレイヤーが黒や白がAIか人間かの管理 0:人間 1:AI | |
int BlackPlayer = 0, WhitePlayer = 0; | |
//設置可能個所を表示するかどうか 1表示 0非表示 | |
int IsCanPutDisply = 1; | |
//CPUのときNNを使用するか、デフォルトのAIを使用するか選択する | |
int IsBlackCpuUseNN = 0, IsWhiteCpuUseNN = 0; | |
//スキップした数を記録する | |
int Skipcnt = 0; | |
//AIの重みを表示する | |
int DisplyAImass = 0; | |
//ムービーを見るか | |
printf("このゲームはオセロです。\n"); | |
printf("人間vs人間、人間vsAI、AIvsAIがプレイできます。\n"); | |
printf("●は黒の石、○は白の石です。\n"); | |
printf("可は石を置ける位置です。コマンドプロンプトの特性上見づらい場合は非表示設定にすることをお勧めします。\n\n"); | |
while (1) { | |
printf("石の設置可能位置(可の表示)を表示しますか?\n"); | |
printf("表示しない 0 表示する 1\n"); | |
scanf("%d", &IsCanPutDisply); | |
if (IsCanPutDisply == 0 || IsCanPutDisply == 1) { | |
break; | |
} | |
else { | |
printf("入力エラー 0か1を入力してください。\n"); | |
} | |
} | |
//プレイヤーに関する各種設定--------------------------------------------------------------------------------------------------- | |
//遺伝子データを読み込み | |
//ファイル名 | |
char BlackNNFileName[50], WhiteNNFileName[50]; | |
//ファイル | |
FILE *BlackNNFile, *WhiteNNFile; | |
//黒と白のプレイヤーを人間かAIか決める | |
//黒セット | |
while (1) | |
{ | |
printf("黒のプレイヤーを設定してください。\n"); | |
printf("人間は0、CPUは1を設定してください。\n"); | |
scanf("%d", &BlackPlayer); | |
if (BlackPlayer == 0) { | |
printf("黒のプレイヤーは人間です。\n"); | |
break; | |
} | |
else if (BlackPlayer == 1) { | |
printf("黒のプレイヤーはCPUです。\n"); | |
break; | |
} | |
else | |
{ | |
printf("入力エラー 0か1を入力してください。\n"); | |
} | |
} | |
//黒のプレイヤーがCPUのときNNを使用するか聞く | |
if (BlackPlayer == 1) { | |
while (1) { | |
printf("CPUはニューラルネットワークの遺伝子データを使用しますか?\n"); | |
printf("デフォルトのAIを使用 0 遺伝子データを使用 1\n"); | |
scanf("%d", &IsBlackCpuUseNN); | |
if (IsBlackCpuUseNN == 0 || IsBlackCpuUseNN == 1) { | |
break; | |
} | |
else | |
{ | |
printf("入力エラー 0か1を入力してください。\n"); | |
} | |
} | |
} | |
//親データのファイル名入力 | |
//黒のプレイヤーがNNを使用するとき、その設定をする | |
if (IsBlackCpuUseNN == 1) { | |
while (1) { | |
printf("黒の遺伝子データのファイル名を入力してください(.txtを含む)\n"); | |
scanf("%s", BlackNNFileName); | |
BlackNNFile = fopen(BlackNNFileName, "r"); | |
if (BlackNNFile == NULL) { | |
printf("ファイルの読み込みに失敗しました。\n\n"); | |
} | |
else { | |
printf("ファイルの読み込みに成功しました。\n"); | |
break; | |
} | |
} | |
//遺伝子データからNNの重みを設定する | |
for (int i = 0; i < 1380; i++) { | |
fscanf(BlackNNFile, "%lf", &NNweight[i][0]); | |
} | |
} | |
//白セット | |
while (1) | |
{ | |
printf("\n白のプレイヤーを設定してください。\n"); | |
printf("人間は0、CPUは1を設定してください。\n"); | |
scanf("%d", &WhitePlayer); | |
if (WhitePlayer == 0) { | |
printf("白のプレイヤーは人間です。\n"); | |
break; | |
} | |
else if (WhitePlayer == 1) { | |
printf("白のプレイヤーはCPUです。\n"); | |
break; | |
} | |
else | |
{ | |
printf("入力エラー 0か1を入力してください。\n"); | |
} | |
} | |
//白のプレイヤーがCPUのときNNを使用するか聞く | |
if (WhitePlayer == 1) { | |
while (1) { | |
printf("CPUはニューラルネットワークの遺伝子データを使用しますか?\n"); | |
printf("デフォルトのAIを使用 0 遺伝子データを使用 1\n"); | |
scanf("%d", &IsWhiteCpuUseNN); | |
if (IsWhiteCpuUseNN == 0 || IsWhiteCpuUseNN == 1) { | |
break; | |
} | |
else | |
{ | |
printf("入力エラー 0か1を入力してください\n"); | |
} | |
} | |
} | |
//白のプレイヤーがNNを使用するとき、その設定をする | |
if (IsWhiteCpuUseNN == 1) { | |
while (1) { | |
printf("白の遺伝子データのファイル名を入力してください(.txtを含む)\n"); | |
scanf("%s", WhiteNNFileName); | |
WhiteNNFile = fopen(WhiteNNFileName, "r"); | |
if (WhiteNNFile == NULL) { | |
printf("ファイルの読み込みに失敗しました。\n\n"); | |
} | |
else { | |
printf("ファイルの読み込みに成功しました。\n"); | |
break; | |
} | |
} | |
//遺伝子データからNNの重みを設定する | |
for (int i = 0; i < 1380; i++) { | |
fscanf(WhiteNNFile, "%lf", &NNweight[i][1]); | |
} | |
} | |
//AIがNNを使用するときは重みを表示するかどうか判定する | |
if (IsBlackCpuUseNN == 1 || IsWhiteCpuUseNN == 1) { | |
while (1) { | |
printf("各マスの重みを表示しますか?\nこの設定を使うときは、コマンドプロンプトのウィンドウサイズを大きくすることをお勧めします。\n"); | |
printf("表示しない 0 表示する 1\n"); | |
scanf("%d", &DisplyAImass); | |
if (DisplyAImass == 0 || DisplyAImass == 1) { | |
break; | |
} | |
else | |
{ | |
printf("入力エラー 0か1を入力してください\n"); | |
} | |
} | |
} | |
//プレイヤーに関する各種設定おわり--------------------------------------------------------------------------------------------------- | |
//NNテスト用 | |
for (int i = 0; i < 1380; i++) { | |
//NNweight[i][0] = 1; | |
//NNweight[i][1] = 1; | |
} | |
//盤面初期化 | |
for (int i = 0; i < 10; i++) { | |
for (int j = 0; j < 10; j++) { | |
if (i == 0 || i == 9 || j == 0 || j == 9) { | |
Bord[i][j] = WALLID; | |
} | |
else { | |
Bord[i][j] = NULLID; | |
} | |
} | |
} | |
//初期コマ配置 | |
Bord[4][4] = WHITEID; | |
Bord[5][5] = WHITEID; | |
Bord[4][5] = BLACKID; | |
Bord[5][4] = BLACKID; | |
//ループ開始---------------------------------------------------------------------- | |
while (1) { | |
//設置可能場所を特定する | |
for (int i = 0; i < 10; i++) { | |
for (int j = 0; j < 10; j++) { | |
CanPutUpdate(Bord, i, j, BlackTurn); | |
} | |
} | |
//スキップ判定 | |
int SkipFlag = 1; | |
for (int i = 0; i < 10; i++) { | |
for (int j = 0; j < 10; j++) { | |
if (Bord[i][j] == -3) { | |
SkipFlag = 0; | |
Skipcnt = 0; | |
} | |
} | |
} | |
if (SkipFlag == 1) { | |
if (BlackTurn == 1) { | |
printf("黒スキップ\n"); | |
Skipcnt++; | |
BlackTurn = 0; | |
} | |
else { | |
printf("白スキップ\n"); | |
Skipcnt++; | |
BlackTurn = 1; | |
} | |
} | |
//二回連続スキップしたときループを抜ける | |
if (Skipcnt == 2) { | |
break; | |
} | |
//画面表示 | |
BordDisply(Bord, BlackTurn, IsCanPutDisply); | |
//入力始まりーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー | |
//AI、人間の入力 | |
//人間が黒入力 | |
if (BlackPlayer == 0 && BlackTurn == 1) { | |
//ターンに基づき行番号、列番号を入力 | |
while (1) { | |
if (BlackTurn == 1) { | |
printf("黒のターンです\n"); | |
} | |
else { | |
printf("白のターンです\n"); | |
} | |
printf("列番号を入力してください\n"); | |
scanf("%d", &Vertical); | |
printf("行番号を入力してください\n"); | |
scanf("%d", &Horizontal); | |
//入力終わり | |
if (Bord[Horizontal][Vertical] != -3) { | |
printf("入力エラー %d,%dにコマを置けません\n", Vertical, Horizontal); | |
} | |
else { | |
break; | |
} | |
//デバッグ用終了コマンド | |
if (Vertical == -100 || Horizontal == -100) { | |
return 0; | |
} | |
} | |
} | |
//AIが黒入力 | |
else if (BlackPlayer == 1 && BlackTurn == 1) | |
{ | |
//NNを使うかどうかを判断する | |
if (IsBlackCpuUseNN == 1) { | |
NeuralNetwork(Bord, 0); | |
} | |
else | |
{ | |
SetDefaultAIMass(); | |
} | |
//AIの重みの表示をする | |
if (DisplyAImass) { | |
for (int i = 1; i < 9; i++) { | |
for (int j = 1; j < 9; j++) { | |
printf("%10.2lf", AIBordMass[i][j]); | |
} | |
printf("\n"); | |
} | |
printf("\n"); | |
} | |
BordAIInput(Bord, &Vertical, &Horizontal); | |
} | |
//人間が白入力 | |
if (WhitePlayer == 0 && BlackTurn == 0) { | |
//ターンに基づき行番号、列番号を入力 | |
while (1) { | |
if (BlackTurn == 1) { | |
printf("黒のターンです\n"); | |
} | |
else { | |
printf("白のターンです\n"); | |
} | |
printf("列番号を入力してください\n"); | |
scanf("%d", &Vertical); | |
printf("行番号を入力してください\n"); | |
scanf("%d", &Horizontal); | |
//入力終わり | |
if (Bord[Horizontal][Vertical] != -3) { | |
printf("入力エラー %d,%dにコマを置けません\n", Vertical, Horizontal); | |
} | |
else { | |
break; | |
} | |
//デバッグ用終了コマンド | |
if (Vertical == -100 || Horizontal == -100) { | |
return 0; | |
} | |
} | |
} | |
//AIが白入力 | |
else if (WhitePlayer == 1 && BlackTurn == 0) | |
{ | |
//NNを使うかどうかを判断する | |
if (IsWhiteCpuUseNN == 1) { | |
NeuralNetwork(Bord, 1); | |
} | |
else | |
{ | |
SetDefaultAIMass(); | |
} | |
//AIの重みの表示をする | |
if (DisplyAImass) { | |
for (int i = 1; i < 9; i++) { | |
for (int j = 1; j < 9; j++) { | |
printf("%10.2lf", AIBordMass[i][j]); | |
} | |
printf("\n"); | |
} | |
printf("\n"); | |
} | |
BordAIInput(Bord, &Vertical, &Horizontal); | |
} | |
if (Vertical == 0 || Horizontal == 0) { | |
break; | |
} | |
//入力終わりーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー | |
//表示用に変更した-3を-1に戻す | |
for (int i = 0; i < 10; i++) { | |
for (int j = 0; j < 10; j++) { | |
if (Bord[i][j] == -3) { | |
Bord[i][j] = -1; | |
} | |
} | |
} | |
//ボード内容の更新 | |
if (BlackTurn == 1) { | |
Bord[Horizontal][Vertical] = BLACKID; | |
} | |
else { | |
Bord[Horizontal][Vertical] = WHITEID; | |
} | |
//ターン制御フラグの更新 | |
if (BlackTurn == 1) { | |
BlackTurn = 0; | |
} | |
else { | |
BlackTurn = 1; | |
} | |
//盤面の更新 | |
BordUpdate(Bord, Horizontal, Vertical); | |
//通常の勝利判定 | |
winner = CheckGameEnd(Bord); | |
if (winner != 0) { | |
break; | |
} | |
//完封勝利判定 | |
int black = 0, white = 0; | |
for (int i = 0; i < 10; i++) { | |
for (int j = 0; j < 10; j++) { | |
if (Bord[i][j] == 1) { | |
white++; | |
} | |
else if (Bord[i][j] == 0) { | |
black++; | |
} | |
} | |
} | |
if (white == 0) { | |
winner = 1; | |
break; | |
} | |
else if (black == 0) { | |
winner = 2; | |
break; | |
} | |
} | |
printf("\n\n\n\n\n\n"); | |
printf("ゲーム終了です\n"); | |
int black = 0, white = 0; | |
for (int i = 0; i < 10; i++) { | |
for (int j = 0; j < 10; j++) { | |
if (Bord[i][j] == 0) { | |
white++; | |
} | |
else if (Bord[i][j] == 1) { | |
black++; | |
} | |
} | |
} | |
if (white == black) { | |
winner = 3; | |
} | |
else if (white > black) { | |
winner = 2; | |
} | |
else if (white < black) { | |
winner = 1; | |
} | |
printf("黒:%d\n", black); | |
printf("白:%d\n", white); | |
switch (winner) { | |
case 1: | |
printf("黒の勝利です\n"); | |
break; | |
case 2: | |
printf("白の勝利です\n"); | |
break; | |
case 3: | |
printf("引き分けです\n"); | |
break; | |
} | |
FinishGameDisplyBord(Bord); | |
printf("終了するに何か入力し、エンターキーを押してください\n"); | |
int end = 0; | |
scanf("%d", &end); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment