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

📄 756-759.html

📁 java game programming e-book
💻 HTML
字号:
<HTML>
<HEAD>
<META name=vsisbn content="1571690433"><META name=vstitle content="Black Art of Java Game Programming"><META name=vsauthor content="Joel Fan"><META name=vsimprint content="Sams"><META name=vspublisher content="Macmillan Computer Publishing"><META name=vspubdate content="11/01/96"><META name=vscategory content="Web and Software Development: Programming, Scripting, and Markup Languages: Java"><TITLE>Black Art of Java Game Programming:The Internet MahJong Server</TITLE>
<!-- HEADER --><STYLE type="text/css">  <!-- A:hover  { 	color : Red; } --></STYLE><META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW"><script><!--function displayWindow(url, width, height) {         var Win = window.open(url,"displayWindow",'width=' + width +',height=' + height + ',resizable=1,scrollbars=yes');	if (Win) {		Win.focus();	}}//--></script><SCRIPT><!--function popUp(url) {        var Win = window.open(url,"displayWindow",'width=400,height=300,resizable=1,scrollbars=yes');	if (Win) {		Win.focus();	}}//--></SCRIPT><script language="JavaScript1.2"><!--function checkForQuery(fm) {  /* get the query value */  var i = escape(fm.query.value);  if (i == "") {      alert('Please enter a search word or phrase');      return false;  }                  /* query is blank, dont run the .jsp file */  else return true;  /* execute the .jsp file */}//--></script></HEAD><BODY> 
<TABLE border=0 cellspacing=0 cellpadding=0>
<tr>
<td width=75 valign=top>
<img src="../1571690433.gif" width=60 height=73 alt="Black Art of Java Game Programming" border="1">
</td>
<td align="left">
    <font face="arial, helvetica" size="-1" color="#336633"><b>Black Art of Java Game Programming</b></font>
    <br>
    <font face="arial, helvetica" size="-1"><i>by Joel Fan</i>
    <br>
    Sams,&nbsp;Macmillan Computer Publishing
    <br>
    <b>ISBN:</b>&nbsp;1571690433<b>&nbsp;&nbsp;&nbsp;Pub Date:</b>&nbsp;11/01/96</font>&nbsp;&nbsp;
</td>
</tr>
</table>
<P>

<!--ISBN=1571690433//-->
<!--TITLE=Black Art of Java Game Programming//-->
<!--AUTHOR=Joel Fan//-->
<!--AUTHOR=Eric Ries//-->
<!--AUTHOR=Calin Tenitchi//-->
<!--PUBLISHER=Macmillan Computer Publishing//-->
<!--IMPRINT=Sams//-->
<!--CHAPTER=18//-->
<!--PAGES=756-759//-->
<!--UNASSIGNED1//-->
<!--UNASSIGNED2//-->

<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="752-756.html">Previous</A></TD>
<TD><A HREF="../ewtoc.html">Table of Contents</A></TD>
<TD><A HREF="759-762.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>
<P><BR></P>
<P>This method is declared with a <I>synchronized</I> keyword, because it is potentially called by multiple players&#146; threads. Now, you might recall from previous discussion that all packet handlers, hence play(), must return quickly. Fortunately, for most board and card games this is not a problem&#151;the rules are simple and easy to check.</P>
<P>So what is involved in the play() method? Let&#146;s just take one case, where a Player <I>him</I> makes a discard. First check whether he has that tile:</P>
<!-- CODE //-->
<PRE>
if (action == DISCARD) &#123;                  // he wants to discard
  int s = him.seat;
  pri_hands[s].unselectAll();             // unmark everything
  if (pri_hands[s].search(tile, 1) == 0) &#123;
    him.output(Packet.SPYourPlay(false)); // reject this play
    return;
  &#125;
  him.output(Packet.SPYourPlay(true));    // confirm play
  pri_hands[s].delete();                  // delete from hand
  active = tile;                          // make the discard
  outputTable(Packet.SPDiscard(tile));    // tell everyone
</PRE>
<!-- END CODE //-->
<P>Then, tell everyone about the discarded tile, and what this player&#146;s hand looks like now:
</P>
<!-- CODE //-->
<PRE>
// conceal the concealed tiles to the other players
Hand to_other = new Hand();
to_other.append(pub_hands[s]);
for (int i = 0; i &lt; semi_pubs[s]; i&#43;&#43;) &#123;
  to_other.addTile((byte)0, semi_pubs[s].groupAt(i), false);
&#125;
for (int i = 0; i &lt; pri_hands[s]; i&#43;&#43;) &#123;
  to_other.addTile((byte)0, Hand.SINGLE, false);
&#125;
for (int i = 0; i &lt; 4; i&#43;&#43;) &#123;           // send to others
  if (players[i] != null &#38;&#38; i != s)
    players[i].output(Packet.SPTiles(s, to_other));
&#125;
</PRE>
<!-- END CODE //-->
<P>We also have to determine what the other players can do with the discarded tile, and tell them that:
</P>
<!-- CODE //-->
<PRE>
for (int i = 0; i &lt; 4; i&#43;&#43;) &#123;
  if (i == s) &#123;                         // he can only wait
    actions[s] = PASS;
    action_masks[s] = 0;
    him.output(Packet.SPYourChoices(0));
    continue;
  &#125;
  actions[i] = -1;
  Hand h = pri_hands[i];
  if (i == (s &#43; 1) % 4) &#123;               // immediate right
    action_masks[i] = 1 &lt;&lt; DRAW;        // he can draw
    boolean up1 = h.search(Tile.stepUp(tile), 1) != 0;
    boolean up2 = h.search(Tile.stepUp(Tile.stepUp(tile)), 1) != 0;
    boolean dn1 = h.search(Tile.stepDn(tile), 1) != 0;
    boolean dn2 = h.search(Tile.stepDn(Tile.stepDn(tile)), 1) != 0;
    if (up1 &#38;&#38; up2)
      action_masks[i] |= 1 &lt;&lt; CONN_UP;  // he can chow
    if (up1 &#38;&#38; dn1)
      action_masks[i] |= 1 &lt;&lt; CONN_MD;  // he can chow
    if (dn1 &#38;&#38; dn2)
      action_masks[i] |= 1 &lt;&lt; CONN_DN;  // he can chow
  &#125; else action_masks[i] = 1 &lt;&lt; PASS;   // he can pass (not draw)
  int n_id = h.search(tile, 3);
  if (n_id &gt;= 2) &#123;
    action_masks[i] |= 1 &lt;&lt; TRIP;       // he can pong
    if (n_id == 3)
      action_masks[i] |= 1 &lt;&lt; QUAD;     // he can gong
  &#125;
  h.unselectAll();                      // unmark everything again
  if ((winning[i] = CheckMahJong(s, tile)) != null)
    action_masks[i] |= 1 &lt;&lt; WIN;        // he can win
  if (players[i] != null)               // tell him his choices
    players[i].output(Packet.SPYourChoices(action_masks[i]));
&#125;
</PRE>
<!-- END CODE //-->
<P>The other cases are quite similar to this, just tedious to write down fully. If you are writing your own game, be sure to produce something like Figure 18-5 first. Then it&#146;s just a matter of translating it into code.
</P>
<H4 ALIGN="LEFT"><A NAME="Heading35"></A><FONT COLOR="#000077">Checking for a MahJong Pattern</FONT></H4>
<P>The CheckMahJong() method we call above looks at a player&#146;s hand (revealed tiles together with concealed ones) and determines if he has a MahJong pattern. If so, the method returns a Hand with all the tiles grouped up into four sets and a pair. Otherwise, it returns <I>null</I>. This can be achieved with a simple recursive algorithm.</P>
<P>The recursive function takes as arguments a fixed hand of tiles that are already grouped up, a boolean value indicating whether the fixed hand contains a pair or not, and another hand of tiles to test on. We simply look at the first tile of the test hand, and see if we can make chows, a pong, or a pair (if the fixed hand doesn&#146;t have one already) with it and other tiles in the test hand. If no groups can be formed, we return <I>null</I>. Otherwise, in each possible case, we construct a new set of arguments using the new group we form, call the function itself again, and return the first non-<I>null</I> return value from the recursive calls. In the final situation, we have an empty test hand, which means the fixed hand is a MahJong pattern, which is returned all the way up the calling stack. The implementation is tedious yet straightforward.</P>
<P>Given this recursive function, our CheckMahJong() method simply calls it with the fixed hand being the revealed tiles plus concealed gongs, which also have fixed status, the boolean value being <I>false</I>, and the test hand being the concealed tiles.</P>
<H3><A NAME="Heading36"></A><FONT COLOR="#000077">Adding Finishing Touches</FONT></H3>
<P>After the first release of my software, I kept adding features to it. They are not fancy, but either make the server a more robust environment or increase players&#146; convenience. I will discuss them briefly here.
</P>
<H4 ALIGN="LEFT"><A NAME="Heading37"></A><FONT COLOR="#000077">A Flexible Scoring System</FONT></H4>
<P>No game will attract players unless it calculates score. For MahJong, there are well-defined scoring systems, but alas, too many of them. I have chosen a large common subset of the most popular conventions, and allow some minor variations that are adjustable as table options. Implementing them is relatively straightforward after what we&#146;ve been through. It&#146;s just a matter of adding variables to the Table class, patching up the protocol to transmit the options, and finally, making a new GUI window for the players to view and change them. To prevent chaos, I only allow the creator of a table to change the options, and only when no game is in progress.
</P>
<H4 ALIGN="LEFT"><A NAME="Heading38"></A><FONT COLOR="#000077">A Player Database</FONT></H4>
<P>The database records a player&#146;s name, password, score, and optional data such as e-mail address, home page URL, a &#147;plan,&#148; and his preferred client setup. Since I did not own a database server, I had to write my own. What I came up with is the RecordFile class, based on the library RandomAccessFile. Abstractly, a RecordFile holds an arbitrary number of <I>records</I>, which are simply byte streams whose length can vary. The physical file is chopped into <I>blocks</I> of fixed length, and a record can occupy any number of blocks. As records shrink or grow, some blocks may be freed and reused later. Thus, a RecordFile can be thought of as an extremely simple file system! I associate to each player such a record, and use DataOutput and DataInput calls to store and retrieve player records.</P>
<P>The RecordFile class is in the types package. You may find it useful for your own games.</P><P><BR></P>
<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="752-756.html">Previous</A></TD>
<TD><A HREF="../ewtoc.html">Table of Contents</A></TD>
<TD><A HREF="759-762.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>


</BODY>

⌨️ 快捷键说明

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