⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch16.htm

📁 对于程序员来说可以利用JAVA来开发网络游戏!
💻 HTM
📖 第 1 页 / 共 5 页
字号:
is simply a 7<FONT FACE="Symbol">&#165;</FONT>6 two-dimensional
array of integers that represents the state of the game. Each
integer entry can be set to either <TT><FONT FACE="Courier">0</FONT></TT>
or <TT><FONT FACE="Courier">1</FONT></TT> (for a player occupying
that position on the board) or <TT><FONT FACE="Courier">Empty</FONT></TT>.
<P>
The <TT><FONT FACE="Courier">score</FONT></TT> member variable
contains a two-dimensional array of integers representing the
&quot;score&quot; for the players. The main array in <TT><FONT FACE="Courier">score</FONT></TT>
contains a subarray for each player that is <TT><FONT FACE="Courier">winPlaces</FONT></TT>
in length. These subarrays contain information describing how
close the player is to completing a winning series. It works like
this: Each subarray entry corresponds to a potential winning series
and contains a count of how many of the player's pieces occupy
the series. If a series is no longer a winning possibility for
the player, its entry in the array is set to 0. Otherwise, the
entry is set to <TT><FONT FACE="Courier">2</FONT></TT><FONT SIZE=1 FACE="MCPdigital">p</FONT>,
where <TT><FONT FACE="Courier">p</FONT></TT> is the number of
the player's pieces occupying the series. So if one of these entries
is set to <TT><FONT FACE="Courier">16</FONT></TT> (<TT><FONT FACE="Courier">2</FONT></TT><FONT SIZE=1 FACE="MCPdigital">4</FONT>),
that player has won.
<P>
Rounding out the member variables for <TT><FONT FACE="Courier">Connect4State</FONT></TT>
is <TT><FONT FACE="Courier">numPieces</FONT></TT>, which is just
a count of how many pieces have been played in the game. <TT><FONT FACE="Courier">numPieces</FONT></TT>
is really used only in determining whether the game is a tie;
in the event of a tie, <TT><FONT FACE="Courier">numPieces</FONT></TT>
is equal to <TT><FONT FACE="Courier">maxPieces</FONT></TT>.
<P>
That covers the member variables for the <TT><FONT FACE="Courier">Connect4State</FONT></TT>
class. You might have realized by now that by understanding the
member variables and what they model, you already understand a
great deal about how the AI works in the game. Let's move on to
the methods in <TT><FONT FACE="Courier">Connect4State</FONT></TT>,
because that's where the fun really begins.
<P>
The default constructor for <TT><FONT FACE="Courier">Connect4State</FONT></TT>
takes on the role of initializing the <TT><FONT FACE="Courier">map</FONT></TT>,
<TT><FONT FACE="Courier">board</FONT></TT>, and <TT><FONT FACE="Courier">score</FONT></TT>
arrays. This constructor is shown in Listing 16.2.
<HR>
<BLOCKQUOTE>
<B>Listing 16.2. The </B><TT><B><FONT FACE="Courier">Connect4State</FONT></B></TT><B>
class's default constructor.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public Connect4State() {<BR>
&nbsp;&nbsp;// Initialize the map<BR>
&nbsp;&nbsp;int i, j, k, count = 0;<BR>
&nbsp;&nbsp;if (map == null) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;map = new boolean[7][6][winPlaces];<BR>
&nbsp;&nbsp;&nbsp;&nbsp;for (i = 0; i &lt; 7; i++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (j = 0; j &lt; 6; j++)
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (k = 0; k
&lt; winPlaces; k++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map[i][j][k]
= false;<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// Set the horizontal win positions<BR>
&nbsp;&nbsp;&nbsp;&nbsp;for (i = 0; i &lt; 6; i++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (j = 0; j &lt; 4; j++)
{<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (k = 0; k
&lt; 4; k++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map[j
+ k][i][count] = true;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count++;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
&nbsp;&nbsp;&nbsp;&nbsp;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// Set the vertical win positions<BR>
&nbsp;&nbsp;&nbsp;&nbsp;for (i = 0; i &lt; 7; i++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (j = 0; j &lt; 3; j++)
{<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (k = 0; k
&lt; 4; k++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map[i][j
+ k][count] = true;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count++;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// Set the forward diagonal win positions
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;for (i = 0; i &lt; 3; i++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (j = 0; j &lt; 4; j++)
{<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (k = 0; k
&lt; 4; k++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map[j
+ k][i + k][count] = true;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count++;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// Set the backward diagonal win positions
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;for (i = 0; i &lt; 3; i++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (j = 6; j &gt;= 3; j--)
{<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (k = 0; k
&lt; 4; k++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map[j
- k][i + k][count] = true;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count++;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
&nbsp;&nbsp;}<BR>
<BR>
&nbsp;&nbsp;// Initialize the board<BR>
&nbsp;&nbsp;for (i = 0; i &lt; 7; i++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;for (j = 0; j &lt; 6; j++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;board[i][j] = Empty;<BR>
<BR>
&nbsp;&nbsp;// Initialize the scores<BR>
&nbsp;&nbsp;for (i = 0; i &lt; 2; i++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;for (j = 0; j &lt; winPlaces; j++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;score[i][j] = 1;<BR>
<BR>
&nbsp;&nbsp;numPieces = 0;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
The default constructor also sets the number of pieces to zero.
There is also a copy constructor for <TT><FONT FACE="Courier">Connect4State</FONT></TT>,
whose source code follows:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public Connect4State(Connect4State state)
{<BR>
&nbsp;&nbsp;// Copy the board<BR>
&nbsp;&nbsp;for (int i = 0; i &lt; 7; i++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;for (int j = 0; j &lt; 6; j++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;board[i][j] = state.board[i][j];
<BR>
<BR>
&nbsp;&nbsp;// Copy the scores<BR>
&nbsp;&nbsp;for (int i = 0; i &lt; 2; i++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;for (int j = 0; j &lt; winPlaces; j++)
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;score[i][j] = state.score[i][j];
<BR>
<BR>
&nbsp;&nbsp;numPieces = state.numPieces;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
If you aren't familiar with copy constructors, they enable you
to create new objects that are copies of existing objects. It
is necessary to have a copy constructor for <TT><FONT FACE="Courier">Connect4State</FONT></TT>
because the AI algorithms use temporary state objects a great
deal, as you'll see in a moment. The copy constructor for <TT><FONT FACE="Courier">Connect4State</FONT></TT>
just copies the contents of each member variable.
<P>
The <TT><FONT FACE="Courier">isWinner</FONT></TT> method in <TT><FONT FACE="Courier">Connect4State</FONT></TT>
checks to see whether either player has won the game:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public boolean isWinner(int player) {
<BR>
&nbsp;&nbsp;for (int i = 0; i &lt; winPlaces; i++)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;if (score[player][i] == 16)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<BR>
&nbsp;&nbsp;return false;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
The <TT><FONT FACE="Courier">isWinner</FONT></TT> method looks
for a winner by checking to see whether any member in the <TT><FONT FACE="Courier">score</FONT></TT>
array is equal to <TT><FONT FACE="Courier">16</FONT></TT> (<TT><FONT FACE="Courier">2</FONT></TT><FONT SIZE=1 FACE="MCPdigital">4</FONT>).
This indicates victory because it means that four pieces occupy
the series.
<P>
The <TT><FONT FACE="Courier">isTie</FONT></TT> method checks for
a tie by simply seeing whether <TT><FONT FACE="Courier">numPieces</FONT></TT>
equals <TT><FONT FACE="Courier">maxPieces</FONT></TT>, which indicates
that the board is full. The source code for <TT><FONT FACE="Courier">isTie</FONT></TT>
follows:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public boolean isTie() {<BR>
&nbsp;&nbsp;return (numPieces == maxPieces);<BR>
}<BR>
The dropPiece method handles dropping a new piece onto the board:
<BR>
public int dropPiece(int player, int xPos) {<BR>
&nbsp;&nbsp;int yPos = 0;<BR>
&nbsp;&nbsp;while ((board[xPos][yPos] != Empty) &amp;&amp; (++yPos
&lt; 6))<BR>
&nbsp;&nbsp;&nbsp;&nbsp;;<BR>
<BR>
&nbsp;&nbsp;// The column is full<BR>
&nbsp;&nbsp;if (yPos == 6)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;return -1;<BR>
<BR>
&nbsp;&nbsp;// The move is OK<BR>
&nbsp;&nbsp;board[xPos][yPos] = player;<BR>
&nbsp;&nbsp;numPieces++;<BR>
&nbsp;&nbsp;updateScore(player, xPos, yPos);<BR>
<BR>
&nbsp;&nbsp;return yPos;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
The <TT><FONT FACE="Courier">dropPiece</FONT></TT> method takes
a player and an X position (column) as its only parameters. It
first checks to make sure there is room in the specified column
to drop a new piece. Incidentally, you might have noticed from
this code that the board is stored upside down in the <TT><FONT FACE="Courier">board</FONT></TT>
member variable. Having the board inverted simplifies the process
of adding a new piece a little. If the move is valid, the entry
in the <TT><FONT FACE="Courier">board</FONT></TT> array is set
to <TT><FONT FACE="Courier">player</FONT></TT>, and <TT><FONT FACE="Courier">numPieces</FONT></TT>
is incremented. Then the score is updated to reflect the move
with a call to <TT><FONT FACE="Courier">updateScore</FONT></TT>.
You'll learn about <TT><FONT FACE="Courier">updateScore</FONT></TT>
in a moment.
<P>
The <TT><FONT FACE="Courier">evaluate</FONT></TT> method is where
the low-level AI in the game takes place. The source code for
the <TT><FONT FACE="Courier">evaluate</FONT></TT> method is shown
in Listing 16.3.
<HR>
<BLOCKQUOTE>
<B>Listing 16.3. The </B><TT><B><FONT FACE="Courier">Connect4State</FONT></B></TT><B>
class's </B><TT><B><FONT FACE="Courier">evaluate</FONT></B></TT><B>
method.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier">public int evaluate(int player, int level,
int depth, int alpha,<BR>
&nbsp;&nbsp;int beta) {<BR>
&nbsp;&nbsp;int goodness, best, maxab = alpha;<BR>
<BR>
&nbsp;&nbsp;if (level != depth) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;best = -30000;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;for(int i = 0; i &lt; 7; i++) {<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Connect4State tempState =
new Connect4State(this);<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (tempState.dropPiece(getOtherPlayer(player),
i) &lt; 0)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (tempState.isWinner(getOtherPlayer(player)))
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goodness = 25000
- depth;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goodness = tempState.evaluate(getOtherPlayer(player),
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;level,
depth + 1, -beta, -maxab);<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (goodness &gt; best) {
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;best = goodness;
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (best &gt;
maxab)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxab
= best;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (best &gt; beta)<BR>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<BR>
&nbsp;&nbsp;&nbsp;&nbsp;}<BR>
<BR>
&nbsp;&nbsp;&nbsp;&nbsp;// What's good for the other player is
bad for this one<BR>
&nbsp;&nbsp;&nbsp;&nbsp;return -best;<BR>
&nbsp;&nbsp;}<BR>
<BR>
&nbsp;&nbsp;return (calcScore(player) - calcScore(getOtherPlayer(player)));
<BR>
}</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
It is the <TT><FONT FACE="Courier">evaluate</FONT></TT> method's
job to come up with the best move for the computer player given

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -