2D遊戲之五子棋(3)人工智慧AI,自動落棋
阿新 • • 發佈:2019-02-03
class AI
{
// 15*15共有572種五子連珠的可能性
const int MaxFiveChainCount = 572;
//玩家的可能性
bool[,,] _ptable = new bool[Board.CrossCount, Board.CrossCount, MaxFiveChainCount];
//電腦的可能性
bool[, ,] _ctable = new bool[Board.CrossCount, Board.CrossCount, MaxFiveChainCount];
//記錄2位玩家所有可能的連珠數,-1則為永遠無法5連珠
int[,] _win = new int[2, MaxFiveChainCount];
//記錄每格的分值
int[,] _cgrades = new int[Board.CrossCount, Board.CrossCount];
int[,] _pgrades = new int[Board.CrossCount, Board.CrossCount];
//記錄棋盤
int[,] _board = new int[Board.CrossCount, Board.CrossCount];
int _cgrade, _pgrade;
int _icount, _m, _n;
int _mat, _nat, _mde, _nde;
public AI( )
{
for ( int i = 0;i<Board.CrossCount;i++)
{
for ( int j = 0;j<Board.CrossCount;j++)
{
_pgrades[i, j] = 0;
_cgrades[i, j] = 0;
_board[i, j] = 0 ;
}
}
//遍歷所有的五連子可能情況的權值
//橫
for ( int i = 0;i<Board.CrossCount;i++)
{
for ( int j = 0;j<Board.CrossCount - 4 ;j++)
{
for( int k = 0;k < BoardModel.WinChessCount;k++)
{
_ptable[j + k, i, _icount] = true;
_ctable[j + k, i, _icount] = true;
}
_icount++;
}
}
//橫
for (int i = 0; i < Board.CrossCount; i++)
{
for (int j = 0; j < Board.CrossCount - 4; j++)
{
for (int k = 0; k < BoardModel.WinChessCount; k++)
{
_ptable[i, j + k, _icount] = true;
_ctable[i, j + k, _icount] = true;
}
_icount++;
}
}
// 右斜
for (int i = 0; i < Board.CrossCount - 4; i++)
{
for (int j = 0; j < Board.CrossCount - 4; j++)
{
for (int k = 0; k < BoardModel.WinChessCount; k++)
{
_ptable[j+k, i + k, _icount] = true;
_ctable[j + k, i + k, _icount] = true;
}
_icount++;
}
}
// 左斜
for (int i = 0; i < Board.CrossCount - 4; i++)
{
for (int j = Board.CrossCount - 1; j >= 4; j--)
{
for (int k = 0; k < BoardModel.WinChessCount; k++)
{
_ptable[j - k, i + k, _icount] = true;
_ctable[j - k, i + k, _icount] = true;
}
_icount++;
}
}
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < MaxFiveChainCount; j++)
{
_win[i, j] = 0;
}
}
_icount = 0;
}
void CalcScore( )
{
_cgrade = 0;
_pgrade = 0;
_board[_m, _n] = 1;//電腦下子位置
for (int i = 0; i < MaxFiveChainCount; i++)
{
if (_ctable[_m, _n, i] && _win[0, i] != -1)
{
_win[0, i]++;//給白子的所有五連子可能的載入當前連子數
}
if (_ptable[_m, _n, i])
{
_ptable[_m, _n, i] = false;
_win[1, i] = -1;
}
}
}
void CalcCore( )
{
//遍歷棋盤上的所有座標
for (int i = 0; i < Board.CrossCount; i++)
{
for (int j = 0; j < Board.CrossCount; j++)
{
//該座標的黑子獎勵積分清零
_pgrades[i, j] = 0;
//在還沒下棋子的地方遍歷
if (_board[i, j] == 0)
{
//遍歷該棋盤可落子點上的黑子所有權值的連子情況,並給該落子點加上相應獎勵分
for (int k = 0; k < MaxFiveChainCount; k++)
{
if (_ptable[i, j, k])
{
switch (_win[1, k])
{
case 1://一連子
_pgrades[i, j] += 5;
break;
case 2://兩連子
_pgrades[i, j] += 50;
break;
case 3://三連子
_pgrades[i, j] += 180;
break;
case 4://四連子
_pgrades[i, j] += 400;
break;
}
}
}
_cgrades[i, j] = 0;//該座標的白子的獎勵積分清零
if (_board[i, j] == 0)//在還沒下棋子的地方遍歷
{
//遍歷該棋盤可落子點上的白子所有權值的連子情況,並給該落子點加上相應獎勵分
for (int k = 0; k < MaxFiveChainCount; k++)
{
if (_ctable[i, j, k])
{
switch (_win[0, k])
{
case 1://一連子
_cgrades[i, j] += 5;
break;
case 2: //兩連子
_cgrades[i, j] += 52;
break;
case 3://三連子
_cgrades[i, j] += 130;
break;
case 4: //四連子
_cgrades[i, j] += 10000;
break;
}
}
}
}
}
}
}
}
// AI計算輸出, 需要玩家走過的點
public void ComputerDo(int playerX, int playerY, out int finalX, out int finalY )
{
setPlayerPiece(playerX, playerY);
CalcCore();
for (int i = 0; i < Board.CrossCount; i++)
{
for (int j = 0; j < Board.CrossCount; j++)
{
//找出棋盤上可落子點的黑子白子的各自最大權值,找出各自的最佳落子點
if (_board[i, j] == 0)
{
if (_cgrades[i, j] >= _cgrade)
{
_cgrade = _cgrades[i, j];
_mat = i;
_nat = j;
}
if (_pgrades[i, j] >= _pgrade)
{
_pgrade = _pgrades[i, j];
_mde = i;
_nde = j;
}
}
}
}
//如果白子的最佳落子點的權值比黑子的最佳落子點權值大,則電腦的最佳落子點為白子的最佳落子點,否則相反
if (_cgrade >= _pgrade)
{
_m = _mat;
_n = _nat;
}
else
{
_m = _mde;
_n = _nde;
}
CalcScore();
finalX = _m;
finalY = _n;
}
void setPlayerPiece( int playerX, int playerY )
{
int m = playerX;
int n = playerY;
if ( _board[m, n ] == 0 )
{
_board[m, n] = 2;
for( int i = 0;i<MaxFiveChainCount;i++)
{
if ( _ptable[m, n, i ] && _win[1, i] != -1 )
{
_win[1, i]++;
}
if (_ctable[m,n,i])
{
_ctable[m, n, i] = false;
_win[0, i] = -1;
}
}
}
}
}