プログラム研究 備忘録

java,C#,Unity等の備忘録です。経済理論も少し。

ITパスポートの試験まで、、

10/25日にITパスポートを申し込んであったのをすっかり忘れていまして、

勉強に追われています。

中々、身が入らずに困っているのですが、、

プログラムの更新ができていないので、、作るというより土管工をしながら

コピーしたのものですが、javaの勉強アプリをとりあえずアップ。

と、思ったのですが、無料ブログで対応していなかったので、ソースで。

とりあえず、、、オセロのAIでも。。

こちらはmin-max法です。

 

 

public class AI {
private static final int SEARCH_LEVEL =7;
private MainPanel panel;//参照
//メインパネルへの参照を保存
public AI(MainPanel panel){//コンストラクタァ
this.panel = panel;
}

//コンピュータの手を決定する
public void compute(){//minMaxで打つ場所を決める
int temp = alphaBeta(true, SEARCH_LEVEL, Integer.MIN_VALUE, Integer.MAX_VALUE);//(bestX,Y,*MASU

int x = temp % MainPanel.MASU;
int y = temp/ MainPanel.MASU;//場所を求める

Undo undo = new Undo(x, y);//記録
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
panel.putDownStone(x,y,false);//石を打つ
panel.reverse(undo,false);//反転undoに保存
if(panel.endGame())
return;
panel.nextTurn();//パス組み込み
if(panel.countCanPut() ==0){
panel.nextTurn();
compute();//再帰
}
}
/*private int minMax(boolean flagForWhite, int level){
int value;//子ノード
int childValue;//伝播評価値
int bestX = 0;
int bestY = 0;//最大の評価値を持つ場所(minMax法で出した

//level0から
//木の末端では盤面評価
//その他のノードはMin Maxで伝播する
if(level == 0){
return valueBoard();//白が多いといいように設定してある
}
if(flagForWhite){
value = Integer.MIN_VALUE;//AIの手番で最大の評価値が欲しい(黒は自分に不利にしてくるはず
}else{
value = Integer.MAX_VALUE;//pの手番では最小にしたい(minMaxに則る
}
if(panel.countCanPut()==0){
return valueBoard();
}
//打てるところを全て試す
for(int y =0; y< MainPanel.MASU;y++){
for(int x=0; x < MainPanel.MASU;x++){
if(panel.canPutDown(x,y)){
Undo undo = new Undo(x,y);
panel.putDownStone(x, y, true);
panel.reverse(undo,true);
panel.nextTurn();
//子ノードの評価値を計算(再帰
childValue = minMax(!flagForWhite,level -1);
//子ノード、ノードの評価値を比較
if(flagForWhite){//AI
if(childValue > value){
value = childValue;
bestX =x;
bestY =y;
}
}else{
if(childValue < value){//pl
value = childValue;
bestX = x;
bestY = y;
}
}
panel.undoBoard(undo);//記録を渡す

}
}
}

if(level == SEARCH_LEVEL){
//ルートノードなら最大評価値を持つ場所を返す
return bestX + bestY*MainPanel.MASU;//一つしか返せないので計算式で返す
}else{
//子ノードならノードの評価値を返す
return value;
}
}
/**
* α-β法。最善手を探索する。打つ場所を探すだけで実際には打たない。
*
* @param flag AIの手番のときtrue、プレイヤーの手番のときfalse。
* @param level 先読みの手数。
* @param alpha α値。このノードの評価値は必ずα値以上となる。
* @param beta β値。このノードの評価値は必ずβ値以下となる。
* @return 子ノードでは盤面の評価値。ルートノードでは最大評価値を持つ場所(bestX + bestY * MAS)。
*/
private int alphaBeta(boolean flag, int level, int alpha, int beta) {
// ノードの評価値
int value;
// 子ノードから伝播してきた評価値
int childValue;
// Min-Max法で求めた最大の評価値を持つ場所
int bestX = 0;
int bestY = 0;

// ゲーム木の末端では盤面評価
// その他のノードはMIN or MAXで伝播する
if (level == 0) {
return valueBoard();
}

if (flag) {
// AIの手番では最大の評価値を見つけたいので最初に最小値をセットしておく
value = Integer.MIN_VALUE;
} else {
// プレイヤーの手番では最小の評価値を見つけたいので最初に最大値をセットしておく
value = Integer.MAX_VALUE;
}

// もしパスの場合はそのまま盤面評価値を返す
if (panel.countCanPut() == 0) {
return valueBoard();
}

// 打てるところはすべて試す(試すだけで実際には打たない)
for (int y = 0; y < MainPanel.MASU; y++) {
for (int x = 0; x < MainPanel.MASU; x++) {
if (panel.canPutDown(x, y)) {
Undo undo = new Undo(x, y);
// 試しに打ってみる(盤面描画はしないのでtrue指定)
panel.putDownStone(x, y, false);
// ひっくり返す(盤面描画はしないのでtrue指定)
panel.reverse(undo, false);
// 手番を変える
panel.nextTurn();
// 子ノードの評価値を計算(再帰
// 今度は相手の番なのでflagが逆転する
childValue = alphaBeta(!flag, level - 1, alpha, beta);
// 子ノードとこのノードの評価値を比較する
if (flag) {
// AIのノードなら子ノードの中で最大の評価値を選ぶ
if (childValue > value) {
value = childValue;
// α値を更新
alpha = value;
bestX = x;
bestY = y;
}
// このノードの現在のvalueが受け継いだβ値より大きかったら
// この枝が選ばれることはないのでこれ以上評価しない
// = forループをぬける
if (value > beta) { // βカット
// System.out.println("βカット");
// 打つ前に戻す
panel.undoBoard(undo);
return value;
}
} else {
// プレイヤーのノードなら子ノードの中で最小の評価値を選ぶ
if (childValue < value) {
value = childValue;
// β値を更新
beta = value;
bestX = x;
bestY = y;
}
// このノードのvalueが親から受け継いだα値より小さかったら
// この枝が選ばれることはないのでこれ以上評価しない
// = forループをぬける
if (value < alpha) { // αカット
// System.out.println("αカット");
// 打つ前に戻す
panel.undoBoard(undo);
return value;
}
}
// 打つ前に戻す
panel.undoBoard(undo);
}
}
}

if (level == SEARCH_LEVEL) {
// ルートノードなら最大評価値を持つ場所を返す
return bestX + bestY * MainPanel.MASU;
} else {
// 子ノードならノードの評価値を返す
return value;
}
}
private int valueBoard(){
//Counter counter = panel.countStone();
//return counter.whiteCount;この二行だと多くひっくり返るだけだった
int value = 0;
for(int y=0; y< MainPanel.MASU;y++){
for(int x=0;x<MainPanel.MASU;x++){
//計算式
value +=panel.getBoard(x,y)*valueOfPlace[y][x];
}
}
return -value;
}

private static final int valueOfPlace = {
{150, -30, 20, 5, 5, 20, -30, 150},
{-40, -50, -5, -5, -5, -5, -50, -40},
{ 20, -5, 15, 3, 3, 15, -5, 20},
{ 5, -5, 3, 3, 3, 3, -5, 5},
{ 5, -5, 3, 3, 3, 3, -5, 5},
{ 20, -5, 15, 3, 3, 15, -5, 20},
{-40, -50, -5, -5, -5, -5, -50, -30},
{150, -30, 20, 5, 5, 20, -30, 150}
};
}