// Osero Base Project
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections;
using System.Diagnostics;
public class MyForm : Form
{ // 黒番の局面に設定すること
int[,] m_tt = new int[8, 8]
{{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 1, -1, 0, 0, 0 },
{ 0, 0, 0, -1, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 }};
int[,] m_vt = new int[8, 8] // 1-1, 2-2 は別途
{{ 0, -6, 4, 2, 2, 4, -6, 0 },
{ -6, 0, -2, -1, -1, -2, 0, -6 },
{ 4, -2, 0, 0, 0, 0, -2, 4 },
{ 2, -1, 0, 0, 0, 0, -1, 2 },
{ 2, -1, 0, 0, 0, 0, -1, 2 },
{ 4, -2, 0, 0, 0, 0, -2, 4 },
{ -6, 0, -2, -1, -1, -2, 0, -6 },
{ 0, -6, 4, 2, 2, 4, -6, 0 }};
int[,] m_t = new int[8, 8]; // オセロ盤
int[,] t00 = new int[4, 2] //0-0 座標テーブル(Y,X)
{{ 0,0 }, { 0,7 }, { 7,7 }, { 7,0 }};
int[,] t11 = new int[4, 2] //1-1 座標テーブル(Y,X)
{{ 1,1 }, { 1,6 }, { 6,6 }, { 6,1 }};
int[,] dt = new int[4, 2] //上辺→,右辺↓,下辺←,左辺↑
{{ 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 }};
int[,] dt5 = new int[4, 2] //左上,右上,右下,左下
{{ 1, 1 }, { 1, -1 }, { -1, -1 }, { -1, 1 }};
int[] m_dat = new int[70]; // 棋譜の記録(Y*10+X)
int m_num; // m_dat の Index
int m_my, m_you; // マシンの駒, プレイヤーの駒
int m_teban= 0; // 手番(9:終局)
int m_pos; // Final 関数の座標値
int x,y;
Random rand = new Random();
// Constructor
public MyForm()
{
BackColor = SystemColors.AppWorkspace;
Width = 560;
Height = 600;
Paint += new PaintEventHandler(MyHandler);
MouseDown += new MouseEventHandler(OnMyMouseDown);
m_t = (int[,])m_tt.Clone();
}
// オセロ盤の描画
private void MyHandler(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawImage(new Bitmap("c:\\data\\test\\ban.gif"), new PointF(10F, 10F));
for (y = 0; y < 8; y++)
{ for (x = 0; x < 8; x++)
{ if (m_t[y, x] == 1) g.DrawImage(new Bitmap("c:\\data\\test\\koma_b.gif"), new PointF(x * 61 + 28, y * 61 + 24));
if (m_t[y, x] == -1) g.DrawImage(new Bitmap("c:\\data\\test\\koma_w.gif"), new PointF(x * 61 + 28, y * 61 + 24));
}
}
m_teban= Pass(m_teban);
}
// マウスのクリック
private void OnMyMouseDown(object sender, MouseEventArgs e)
{
int x,y;
if (e.Button == MouseButtons.Right)
{
m_t = (int[,])m_tt.Clone();
if (m_num > 0) m_num--; // 一手戻す
if (m_dat[m_num] == 99) m_num--;
for (int i = 0; i < m_num; i++)
{
if (i % 2 == 0) Reverse(1, m_dat[i], m_t);
else Reverse(-1, m_dat[i], m_t);
}
m_teban = Set_Teban(m_num);
Invalidate();
return;
}
if (m_teban==9)
{ Pass(9);
return;
}
x = (e.X - 28) / 61;
y = (e.Y - 24) / 61;
if (m_teban==-1)
{ Think(0, m_teban, m_t);
y= m_pos/10;
x= m_pos%10;
}
if (Reverse(m_teban, x, y, m_t)==false)
{ string str = "Play Error C:" + m_teban + "[" + y + "," + x + "]";
MessageBox.Show(str);
return;
}
m_dat[m_num] = y*10+x;
m_num++;
m_teban = Set_Teban(m_num);
Invalidate();
}
// m_num を参照して手番を設定
int Set_Teban(int num)
{
if (m_num % 2 == 0)
{
m_my = 1; // コンピュータ
m_you = -1; // プレイヤー
return 1;
}
m_my = -1;
m_you = 1;
return -1;
}
// パス, 終局を調べる
int Pass(int c)
{
int nc;
ArrayList array;
if (c == 0)
{
m_num = 0;
m_my = 1;
m_you = -1;
return 1; // 黒番で Start
}
if (c!=9) // パスを調べる
{ array = Search(c, m_t);
if (array.Count>0) return c;
}
nc= 0-c; // 反手番で調べる
array = Search(nc, m_t);
if (array.Count>0)
{ if (c==1)
{ MessageBox.Show("黒はパスです"); }
else
{ MessageBox.Show("白はパスです"); }
m_dat[m_num] = 99;
m_num++;
m_my = 0 - m_my; // 手番を反転
m_you = 0 - m_you;
return nc;
}
string str= "★Game Over 黒:" + Count(1, m_t) + " 白:" + Count(-1, m_t);
MessageBox.Show(str);
return 9; // 終局
}
// t[yp,xp] に打てるか調べる
bool Check(int c, int xp, int yp, int[,] t)
{
int i,j,x,y;
int nc = 0-c;
if (yp>7 || xp>7 || yp<0 || xp<0 || c==0 || t[yp,xp]!=0) return false;
for(i=-1; i<2; i++)
for(j=-1; j<2; j++)
{ y = yp + i; // 上下左右を調べる
x = xp + j;
if (y<8 && x<8 && y>=0 && x>=0 && t[y,x]==nc)
{ for(; y<8 && x<8 && y>=0 && x>=0 && t[y,x]==nc; y+=i,x+=j);
if (y<8 && x<8 && y>=0 && x>=0 && t[y,x]==c) return true;
}
}
return false; //置くことができない
}
bool Check(int c, int pos, int[,] t)
{
int x,y;
y= pos/10;
x= pos%10;
return Check(c,x,y,t);
}
// t[y,x] に駒を置いて、挟んだ駒を裏返す
bool Reverse(int c, int xp, int yp, int[,] t)
{
int i, j, x, y;
bool sw = false;
int nc = 0-c;
if (yp > 7 || xp > 7 || yp < 0 || xp < 0 || c == 0 || t[yp, xp] != 0) return false;
for (i = -1; i < 2; i++)
for (j = -1; j < 2; j++)
{
y = yp + i;
x = xp + j;
if (y < 8 && x < 8 && y >= 0 && x >= 0 && t[y, x] == nc)
{
for (; y < 8 && x < 8 && y >= 0 && x >= 0 && t[y, x] == nc; y += i, x += j) ;
if (y < 8 && x < 8 && y >= 0 && x >= 0 && t[y, x] == c)
{
for (; y != yp || x != xp; y -= i, x -= j) t[y, x] = c;
sw = true;
}
}
}
if (sw == false) return false;
t[yp, xp] = c;
return true;
}
bool Reverse(int c, int pos, int[,] t)
{
int x,y;
y= pos/10;
x= pos%10;
return Reverse(c,x,y,t);
}
// 打てる手をサーチ
ArrayList Search(int c, int[,] t)
{
int x,y,pos;
ArrayList array= new ArrayList();
for(y=0; y<8; y++)
for(x=0; x<8; x++)
{ if (Check(c,x,y,t))
{ pos= y*10 + x;
array.Add(pos);
}
}
return array;
}
// 駒のカウント
int Count(int c, int[,] t)
{
int cnt;
cnt = 0;
for (int y = 0; y < 8; y++)
{
for (int x = 0; x < 8; x++)
if (t[y, x] == c) cnt++;
}
return cnt;
}
// t[8][8] から辺を一列取り出す
ArrayList GetLine(int no, int[,] t)
{
ArrayList array= new ArrayList();
int xp,yp,k;
yp= t00[no,0];
xp= t00[no,1];
for(k=0; k<8; k++)
{ array.Add(t[yp,xp]);
yp+= dt[no,0];
xp+= dt[no,1];
}
return array;
}
// コーナ(黒or白)から展開する駒をカウント
int Corner(int no, int[,] t)
{ int xp, yp, cnt;
int koma;
yp = t00[no, 0];
xp = t00[no, 1];
if (t[yp, xp] == 0) return 0;
koma = t[yp, xp];
//コーナ(no)のt[8,8]をt55にコピー
int[,] t55 = new int[5, 5];
for(y=0, yp=t00[no, 0]; y<5; y++, yp+=dt5[no, 0])
{ for(x=0, xp=t00[no, 1]; x<5; x++, xp+=dt5[no, 1])
{ t55[y,x] = t[yp,xp]; }
}
//コーナの確定した石数を求める
cnt = 0;
xp = 4;
for(y=0; y<4 && t55[y,0]==koma; y++)
{ for(x=0; x<xp; x++)
{ if ((t55[y,x]!=koma) ||
(y>0 && x>0 && t55[y-1, x+1]!=koma && t55[y+1, x-1]!=koma))
{ xp=x; break; }
cnt++;
}
}
return cnt;
}
// 端の駒(黒or白)の立場で続く駒を評価
int EvEdge(ArrayList s, int bcnt, int wcnt, int scnt)
{
if (scnt<3) return 0;
if ((int)s[0]==1 && (int)s[1]==-1 && (int)s[2]==0 ) return wcnt*20; // [●○△・・・]
if ((int)s[0]==-1 && (int)s[1]==1 && (int)s[2]==0 ) return bcnt*20; // [○●△・・・]
return 0;
}
// 1-2 に駒(黒or白)があるとき、C の手番(立場)でパターンを調べる
int EvPattern(ArrayList s, int c, int sc)
{
int you = 0-c;
if (sc == 4)
{ // [△○●・・・・] 黒(c)の手番で隅を取れる
if ((int)s[1]==you && (int)s[2]==c) return 50;
return 20; // 辺が全て黒になる[△●○・・・]
}
if ((int)s[1]==c) // 1-2 に黒 [△●・・・]
{
if ((int)s[2]==you && (int)s[3]==c) return -60; // [△●○●・・・]
if ((int)s[2]==you && (int)s[3]==0 && (int)s[4]==you) return -40; // [△●○ ○・・・]
return 0;
}
// 1-2 に白[△○・・・]
if ((int)s[2]==c && (int)s[3]==you) return 60; // [△○●○・・・]
if ((int)s[2]==0 && (int)s[3]==you) return 20; // [△○※○・・・]
if ((int)s[2]==0 && (int)s[3]==0 && (int)s[4]==c) return 30; //[△○※・●・・・]
if ((int)s[2]==0 && (int)s[3]==c && (int)s[4]==you) return 30; //[△○※●○・・・]
return 0;
}
// C の手番(立場)で取り出した1列の辺を評価
int EvLine(ArrayList s, int c)
{
ArrayList ws= new ArrayList();
int mcnt, ycnt, scnt, rt, val, wk;
int you= 0-c;
// 黒石, 白石, 列の数をカウント
mcnt = ycnt = 0;
scnt = 1;
wk = (int)s[0];
foreach(int DAT in s)
{
if (DAT==c) mcnt++;
if (DAT==you) ycnt++;
if (DAT != wk)
{
scnt++;
wk = DAT;
}
}
if (mcnt+ycnt==8) return (mcnt-ycnt)*20;
if (scnt<3) return 0;
//連続する(○,●)を一つに詰める
wk = 9;
foreach(int DAT in s)
{
if (DAT==0 || DAT!=wk)
{
ws.Add(DAT);
wk = DAT;
}
}
rt= ws.Count-1;
// 端に黒(白)が置かれている
if ((int)ws[0] != 0)
{
val = EvEdge(ws, mcnt, ycnt, scnt);
if ((int)ws[0]==c) return val;
else return(0-val);
}
if ((int)ws[rt]!=0)
{
ws.Reverse();
val = EvEdge(ws, mcnt, ycnt, scnt);
if ((int)ws[0]==c) return val;
else return(0-val);
}
// [△・・・△]
if (scnt==3) return (mcnt-ycnt)*10;
val= 0;
// 1-2 に駒 [△*・・・△]
if ((int)ws[1]!=0 || (int)ws[rt-1]!=0)
{
if ((int)ws[1]!=0)
{
if ((int)ws[1]==c) val-= EvPattern(ws,c,scnt);
else val+= EvPattern(ws,c,scnt);
}
if ((int)ws[rt-1]!=0)
{
ws.Reverse();
if ((int)ws[1]==c) val-= EvPattern(ws,c,scnt);
else val+= EvPattern(ws,c,scnt);
}
}
// 両端は[△△・・・△△]
if (scnt==3) return (mcnt-ycnt)*10; //[△○△][△●△]
if (scnt==4) return (mcnt+ycnt)*10; //[△○●△]
return val;
}
// 現在の局面を C で評価
int Eval(int c, int[,] wt)
{ ArrayList line;
int x,y,val;
int nc= 0-c;
bool flg;
val= 0;
for(int i=0; i<4; i++)
{ y= t00[i,0];
x= t00[i,1];
if (wt[y,x]!=0) // Corner() 関数の評価
{ if (wt[y,x]==c) val+= Corner(i,wt)*20+30;
else val-= Corner(i,wt)*20+30;
}
else
{
flg = false;
if (Check(c,x,y,wt)) // 隅を取れる
{ val += 60;
flg = true;
}
if (flg==false)
{ y = t11[i, 0];
x = t11[i, 1];
if (wt[y,x]==nc) val += 20;
if (wt[y,x]==c) val -= 20;
}
line = GetLine(i, wt);
int wk= EvLine(line,c);
val += wk;
}
}
for(int i=0; i<8; i++)
{ for(int j=0; j<8; j++)
{ if (wt[i,j]==c) val+= m_vt[i,j];
if (wt[i,j]==nc) val-= m_vt[i,j];
}
}
return val;
}
//★ t[8,8] の局面を c の手番で再帰コールする
// 終盤12手は読み切り(それ以外は3手先の白番で評価)
int Think(int lev, int c, int[,] t)
{
ArrayList array;
int[,] w_t;
int best, pos, ans;
int nc;
if (lev > 24)
{
MessageBox.Show("Think Call Over Level");
return (Count(m_my, t) - Count(m_you, t));
}
nc = 0 - c;
array = Search(c, t);
if (array.Count == 0)
{
array = Search(nc, t);
if (array.Count == 0) //☆終局(両方がパス)
{ return (Count(m_my, t) - Count(m_you, t)); }
return (Think(lev+1, nc, t)); //☆反転して再起コール
}
// 白番・3手先で評価
if (m_num<48 && lev>2 && c==m_my) return Eval(c,t);
pos = 99;
best = 60000;
if (c==m_my) best= -60000;
foreach (int DAT in array)
{
w_t = (int[,])t.Clone();
Reverse(c, DAT, w_t);
ans= Think(lev+1,nc,w_t);
if (best<ans && c==m_my)
{
best = ans;
pos = DAT;
}
if (best>ans && c==m_you)
{
best = ans;
pos = DAT;
}
if (best==ans && rand.Next(2)==0)
{
best = ans;
pos = DAT;
}
}
array.Clear();
if (lev == 0) m_pos = pos; // lev=0 のとき座標を設定
return best;
}
//☆ Debug 関数
void T_Log(int sz, int[,] t)
{
string str = "";
for (int y = 0; y < sz; y++)
{
for (int x = 0; x < sz; x++)
{
if (t[y, x] == 0) str = str + ".";
if (t[y, x] == 1) str = str + "X";
if (t[y, x] == -1) str = str + "O";
}
str = str + "\n";
}
Debug.Write(str);
}
void Ary_Log(ArrayList ary)
{
string str= "ArrayList:[";
foreach (int DAT in ary)
{ str += DAT + " "; }
str += "]\n";
Debug.Write(str);
}
}
class osero
{
public static void Main()
{
MyForm mf = new MyForm();
Application.Run(mf);
}
}
|