home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 14 / IOPROG_14.ISO / soft / sdkjava / dxma.exe / DXMA05.cab / samples / da / java / apps / chess / Parser.java < prev    next >
Encoding:
Java Source  |  1997-11-13  |  12.9 KB  |  547 lines

  1. import Piece;
  2. import Pawn;
  3. import Game;
  4. import Board;
  5. import TokenInputStream;
  6. import java.util.*;
  7. import java.io.*;
  8. import Move;
  9.  
  10.  
  11. // class: Parser
  12. //
  13. // This class parses a PGN chess file into a Games made up of a list of Move classes.
  14. // To parse the game this class makes uses the Board, Piece, Pawn, King, Queen, Bishop,
  15. // Knight, and Rook classes. These classes are only used to parse the file when the 
  16. // file is opened. The parser and these classes are not used while the animation is
  17. // running. 
  18. //
  19.  
  20.  
  21. public class Parser {
  22.     
  23.     public int MAX_LINE_LENGTH = 256;
  24.     public int MIN_GAME_LENGTH = 16;
  25.     
  26.     protected Vector m_games = new Vector();
  27.     
  28.     protected int m_currentGame;
  29.     
  30.     protected static Board m_board;
  31.         
  32.     protected int m_xCapture = -1;
  33.   protected int m_yCapture = -1;
  34.     
  35.     public Parser() {
  36.         m_board = null;
  37.         Pawn.m_parser = this;    
  38.     }
  39.     
  40.   public static Board board() { return m_board;};
  41.     
  42.     void Reset() {
  43.         
  44.         m_board = new Board();
  45.         
  46.     m_xCapture = -1;
  47.     m_yCapture = -1;
  48.   }    
  49.     
  50.     void NotifyOfCapture(int x, int y) {
  51.         m_xCapture = x;
  52.     m_yCapture = y;
  53.     
  54.     }
  55.     
  56.     
  57.     
  58.     ////////////////////////////////////////////////////////////////
  59.     //
  60.     // Function Name: Parsefile
  61.     // Parameters: filename - name of PGN database
  62.     // Returns: number of games parsed. 0 indicates an error occured.
  63.     // Effects: 
  64.     //
  65.     /////////////////////////////////-------------------------------
  66.     
  67.     
  68.     Vector ParseFile(String filename) throws FileNotFoundException{
  69.         
  70.         m_currentGame = 0;
  71.         
  72.         TokenInputStream is = new TokenInputStream(new FileInputStream(filename));
  73.         
  74.         try {
  75.             while(is.peek() > 0) {
  76.                 ParseGame(is);   
  77.             }
  78.         } catch (Exception e) {
  79.             System.out.println("ERROR Parsing Game!!");
  80.             return null;
  81.         }
  82.         if ( m_currentGame > 0)
  83.       return m_games;
  84.     else
  85.       return null;
  86.     }
  87.     
  88.     
  89.     ////////////////////////////////////////////////////////////////
  90.     //
  91.     // Function Name: ParseGame
  92.     // Parameters: is - stream to get the game from
  93.     // Effects: parses the game. throws if there is an error. reads the
  94.     // file until the error or the game has been read.
  95.     //
  96.     /////////////////////////////////-------------------------------
  97.     
  98.     
  99.     void ParseGame(TokenInputStream is) throws IOException, Exception {
  100.         char next;
  101.  
  102.         StringBuffer srcCopy = new StringBuffer();
  103.         
  104.         Reset();
  105.         
  106.         m_games.insertElementAt(new Game(),m_currentGame);
  107.         
  108.         
  109.         char buf[] = new char[MAX_LINE_LENGTH];
  110.         
  111.         //move up to tag pair section
  112.         next = is.peek();
  113.         is.setWhite("\r\n");
  114.         // read in all the tags
  115.         while (next == '['){
  116.             int read = 0;
  117.             read = is.read(buf,0,buf.length);
  118.             
  119.             String tag = new String(buf,0,read);
  120.             
  121.             Game current_game = (Game)m_games.elementAt(m_currentGame);
  122.             current_game.m_tags.insertElementAt(tag, current_game.m_tags.size());
  123.             
  124.             is.eatWhite();
  125.             next = is.peek(); 
  126.         }
  127.         
  128.         is.setWhite("\r\n\t ");
  129.         
  130.         // now we're at the beginning of the movetext
  131.         if (next != -1){ 
  132.             while (is.peek() != 0) {
  133.                 if (ParseMove(is, srcCopy))
  134.                     break;
  135.             }
  136.         }
  137.         if (((Game)m_games.elementAt(m_currentGame)).m_moves.size() == 0) {
  138.             m_games.removeElementAt(m_currentGame);
  139.             
  140.         } else {
  141.             
  142.             ((Game)m_games.elementAt(m_currentGame)).m_src = srcCopy.toString();
  143.             m_currentGame++;
  144.         }
  145.     }
  146.     
  147.     
  148.     ////////////////////////////////////////////////////////////////
  149.     //
  150.     // Function Name: CharToType
  151.     // Parameters: character identifying piece type
  152.     // Returns: corresponding enumeration type
  153.     //
  154.     /////////////////////////////////-------------------------------
  155.     
  156.     int CharToType(char c) throws Exception{
  157.         switch(c) {
  158.         case 'P':
  159.             return Piece.PAWN;
  160.         case 'N':
  161.             return Piece.KNIGHT;
  162.         case 'B':
  163.             return Piece.BISHOP;
  164.         case 'R':
  165.             return Piece.ROOK;
  166.         case 'Q':
  167.             return Piece.QUEEN;
  168.         case 'K':
  169.             return Piece.KING;
  170.         default:
  171.             throw new Exception("Invalid piece code");
  172.         }
  173.     }
  174.  
  175.     public static char TypeToChar(int c) {
  176.     switch(c) {
  177.         case Piece.PAWN:
  178.             return 'P';
  179.         case Piece.KNIGHT:
  180.             return 'N';
  181.         case Piece.BISHOP:
  182.             return 'B';
  183.         case Piece.ROOK:
  184.             return 'R';
  185.         case Piece.QUEEN:
  186.             return 'Q';
  187.         case Piece.KING:
  188.             return 'K';
  189.         default:
  190.             return '!';
  191.         }
  192.     
  193.     }
  194.     
  195.     int FindChar(char buf[], char c, int len) {
  196.         for (int i = 0; i < len; i++) {
  197.             if (buf[i] == c)
  198.                 return i;
  199.         }
  200.         return -1;
  201.     }
  202.     
  203.     ////////////////////////////////////////////////////////////////
  204.     //
  205.     // Function Name: ParseMove
  206.     // Parameters: input stream with cursor positioned at beginning of move to parse
  207.     // Returns: True if the move signifies the end of the game
  208.     // Effects: Adds move to move list (if appropriate) moves stream cursor to next element of movetext.
  209.     //
  210.     /////////////////////////////////-------------------------------
  211.     
  212.     
  213.     boolean ParseMove(TokenInputStream is, StringBuffer srcCopy)throws IOException, Exception {
  214.         
  215.         char buf[] = new char[16];
  216.         int iEnd, i;
  217.         int xTo, yTo;  
  218.         int xFrom = -1, yFrom = -1;
  219.         char promote = 0;
  220.         
  221.     Move Result = new Move();
  222.         
  223.         int srcType = Piece.PAWN;
  224.         
  225.         int len = is.read(buf, 0, buf.length);
  226.  
  227.         // copy this move for src
  228.     srcCopy.append(new String(buf,0,len)).append(" ");
  229.  
  230.         
  231.         // check to see if it's a move number
  232.     if ((i = FindChar(buf,'.', len)) != -1) {
  233.         if (i == (len - 1))
  234.             return false;
  235.         else { // move number and real move together, so toss the move number info
  236.             char temp[] = new char[16];
  237.             i++;
  238.             int j;
  239.             for (j=0; i < len; i++,j++){
  240.                 temp[j] = buf[i];
  241.             }
  242.             temp[i] = 0;
  243.             buf=temp;
  244.             len = j;
  245.         }
  246.     }
  247.         
  248.         // check for kingside or queenside castling
  249.         if ( (new String(buf, 0, 5)).equals("O-O-O")  ||
  250.             (new String(buf, 0, 5)).equals("o-o-o")){
  251.             // Queenside castling
  252.             if (m_board.m_currentPlayer == Piece.WHITE) {
  253.                 
  254.                 m_board.MovePiece(4,0,2,0);
  255.                 m_board.MovePiece(0,0,3,0);
  256.                 Result.xFrom = 4;
  257.         Result.yFrom = 0;
  258.         Result.xTo = 2;
  259.         Result.yTo = 0;
  260.         Result.xFrom2 = 0;
  261.         Result.yFrom2 = 0;
  262.         Result.xTo2 = 3;
  263.         Result.yTo2 = 0;
  264.         Result.player = m_board.m_currentPlayer;
  265.         
  266.             } else {
  267.                 
  268.                 m_board.MovePiece(4,7,2,7);
  269.                 m_board.MovePiece(0,7,3,7);
  270.         Result.xFrom = 4;
  271.         Result.yFrom = 7;
  272.         Result.xTo = 2;
  273.         Result.yTo = 7;
  274.         Result.xFrom2 = 0;
  275.         Result.yFrom2 = 7;
  276.         Result.xTo2 = 3;
  277.         Result.yTo2 = 7;
  278.         Result.player = m_board.m_currentPlayer;
  279.             }
  280.             m_board.m_currentPlayer = Board.OtherPlayer(m_board.m_currentPlayer);
  281.             ((Game)m_games.elementAt(m_currentGame)).m_moves.addElement(Result);
  282.             return false;
  283.         } else if ((new String(buf, 0, 3)).equals("O-O")  ||
  284.             (new String(buf, 0, 3)).equals("o-o")){
  285.             // kingside castling
  286.             if (m_board.m_currentPlayer == Piece.WHITE) {
  287.                 m_board.MovePiece(4,0,6,0);
  288.                 m_board.MovePiece(7,0,5,0);
  289.         Result.xFrom = 4;
  290.         Result.yFrom = 0;
  291.         Result.xTo = 6;
  292.         Result.yTo = 0;
  293.         Result.xFrom2 = 7;
  294.         Result.yFrom2 = 0;
  295.         Result.xTo2 = 5;
  296.         Result.yTo2 = 0;
  297.         Result.player = m_board.m_currentPlayer;
  298.             } else {
  299.                 m_board.MovePiece(4,7,6,7);
  300.                 m_board.MovePiece(7,7,5,7);
  301.         Result.xFrom = 4;
  302.         Result.yFrom = 7;
  303.         Result.xTo = 6;
  304.         Result.yTo = 7;
  305.         Result.xFrom2 = 7;
  306.         Result.yFrom2 = 7;
  307.         Result.xTo2 = 5;
  308.         Result.yTo2 = 7;
  309.         Result.player = m_board.m_currentPlayer;
  310.             }
  311.             m_board.m_currentPlayer = Board.OtherPlayer(m_board.m_currentPlayer);
  312.             ((Game)m_games.elementAt(m_currentGame)).m_moves.addElement(Result);
  313.             return false;
  314.         }
  315.         
  316.         // check for end of game
  317.         if (FindChar(buf,'-', len) != -1 || 
  318.       FindChar(buf,'*', len) != -1 ||
  319.       (new String(buf,0,4)).equals("draw")) {
  320.             
  321.  
  322.       if ((new String(buf,0,1)).equals("*")) {
  323.         Result.result = "Game ended";
  324.       } else if ((new String(buf,0,3)).equals("0-1")) {
  325.         Result.result = "Black Wins";
  326.       } else if ((new String(buf,0,3)).equals("1-0")) {
  327.         Result.result = "White Wins";
  328.       } else if ((new String(buf,0,7)).equals("1/2-1/2") || 
  329.         (new String(buf,0,4)).equals("draw")) {
  330.               Result.result = "Draw Game";
  331.       }
  332.       m_board.m_currentPlayer = Board.OtherPlayer(m_board.m_currentPlayer);
  333.             ((Game)m_games.elementAt(m_currentGame)).m_moves.addElement(Result);
  334.       System.err.print("parsed result: ");
  335.       System.err.println(Result.result);
  336.             return true;
  337.         
  338.     }
  339.         
  340.         // check to see if it's an annotation
  341.         if (FindChar(buf,'$',len) != -1) return false;
  342.         
  343.         
  344.         //!!! check for comments and RAV 
  345.         
  346.         iEnd = len - 1;
  347.         
  348.         // move past extra annotations
  349.         switch(buf[iEnd]) {    
  350.         case '+':
  351.         case '#':
  352.         case '?':
  353.         case '!':
  354.             iEnd--;
  355.         }
  356.         
  357.         iEnd--;
  358.         
  359.         // check for promotion
  360.         if ((buf[iEnd] == '=')) {
  361.             promote = buf[iEnd + 1];
  362.             iEnd = iEnd - 2;
  363.         }
  364.         
  365.         
  366.         // now we're at the start of the dest location
  367.         xTo = Board.StringToX(new String(buf,iEnd,2));
  368.         yTo = Board.StringToY(new String(buf,iEnd,2));    
  369.         iEnd--;
  370.         
  371.         if (iEnd >= 0){
  372.             //move through capture indicator if it's there
  373.             if (buf[iEnd] == 'x')
  374.                 iEnd--;
  375.             
  376.             // iEnd should be at the end of the src piece identification
  377.             i = 0;
  378.             while (i <= iEnd){
  379.                 
  380.                 if ((buf[i] >= 'B') && (buf[i] <= 'R')){
  381.                     
  382.                     srcType = CharToType(buf[i]);
  383.                     
  384.                 } else if ((buf[i] >= 'a') && (buf[i] <= 'h')) {
  385.                     
  386.                     xFrom = buf[i] - 'a';
  387.                 }
  388.                 else if ((buf[i] >= '1') && (buf[i] <= '8')) {
  389.                     
  390.                     yFrom = buf[i] - '1';
  391.                 }        
  392.                 i++;
  393.                 
  394.             }
  395.         }
  396.         // we've got all the information out of the string, now do something with it.
  397.         Result = FindMove(srcType, xTo, yTo, xFrom, yFrom);
  398.       
  399.         if (promote != 0) {
  400.             // and a "=Q" for piece promotion
  401.             Result.promote = CharToType(promote);
  402.             // and change the promoted pawn to whatever type
  403.             m_board.PromotePiece(xTo,yTo,CharToType(promote));
  404.             
  405.         }
  406.         
  407.         // add an ,xA0 if we need to explicitly notify of a capture
  408.         
  409.         if (m_xCapture != -1) {
  410.       Result.xCapture = m_xCapture;
  411.       Result.yCapture = m_yCapture;
  412.  
  413.       m_xCapture = -1;
  414.       m_yCapture = -1;
  415.       
  416.         }
  417.         
  418.         ((Game)m_games.elementAt(m_currentGame)).m_moves.
  419.             addElement(Result);
  420.         
  421.     return false;
  422. }
  423.  
  424.  
  425.  
  426. ////////////////////////////////////////////////////////////////
  427. //
  428. // Function Name: FindMove
  429. // Parameters: pieceType, square the piece is moving to, and
  430. //  whatever knowledge about where it's coming from you have (xFrom & yFrom as -1 signify no knowledge)
  431. // Returns: string descibing move which you must delete
  432. // Effects: 
  433. //
  434. /////////////////////////////////-------------------------------
  435.  
  436.  
  437. Move FindMove( int type,
  438.               int xTo, int yTo, int xFrom, int yFrom) throws Exception{
  439.   
  440.   Vector pieces;
  441.     int i;
  442.   int x,y;
  443.   
  444.   pieces = m_board.GetPiecesOfType(type);
  445.     
  446.   // filter out the other player's pieces
  447.   i = 0;
  448.   while(i < pieces.size()){
  449.     
  450.     if (((Piece)pieces.elementAt(i)).GetColor() != m_board.m_currentPlayer){
  451.       pieces.removeElementAt(i);
  452.             continue;
  453.     }
  454.     i++;
  455.   }
  456.     
  457.     // remove pieces that don't match the rank or
  458.     // file specification (if either is given)
  459.     if (xFrom != -1){
  460.         i = 0;
  461.         while(i < pieces.size()){
  462.             x = ((Piece)pieces.elementAt(i)).GetX();
  463.             y = ((Piece)pieces.elementAt(i)).GetY();
  464.             if (x != xFrom){
  465.                 pieces.removeElementAt(i);
  466.                 continue;
  467.             }
  468.             i++;
  469.         }
  470.     }
  471.     
  472.     if (yFrom != -1){
  473.         i = 0;
  474.         while(i < pieces.size()){
  475.             x = ((Piece)pieces.elementAt(i)).GetX();
  476.             y = ((Piece)pieces.elementAt(i)).GetY();
  477.             
  478.             if (y != yFrom){
  479.                 pieces.removeElementAt(i);
  480.                 continue;
  481.             }    
  482.             i++;
  483.         }
  484.     }
  485.     
  486.     // remove pieces that cannot move to target square
  487.     
  488.     i = 0;
  489.     while(i < pieces.size()){
  490.         
  491.         if (!((Piece)pieces.elementAt(i)).CanMoveTo(xTo,yTo)){
  492.             pieces.removeElementAt(i);
  493.             continue;
  494.         }
  495.         i++;
  496.     }
  497.     
  498.     //  check for putting King in check disambiguation
  499.     if (pieces.size() > 1) {
  500.         i = 0;
  501.         while(i < pieces.size()){
  502.             x = ((Piece)pieces.elementAt(i)).GetX();
  503.             y = ((Piece)pieces.elementAt(i)).GetY();
  504.             
  505.             if (!m_board.IsKingStillSafe(x, y, xTo, yTo, m_board.m_currentPlayer)){
  506.                 pieces.removeElementAt(i);
  507.                 continue;
  508.             }
  509.             i++;
  510.         }
  511.     }
  512.     
  513.     // we should have removed all ambiguity;
  514.     //  assert(pieces->Count() == 1);  
  515.     if (pieces.size() != 1) {
  516.         System.out.println("ERROR!");
  517. //        m_board.PrintBoard();
  518.         throw new Exception("Unresolved ambiguity");
  519.     }
  520.     
  521.     xFrom = ((Piece)pieces.elementAt(0)).GetX();
  522.     yFrom = ((Piece)pieces.elementAt(0)).GetY();
  523.     
  524.   
  525.   Move Result = new Move();
  526.   if (m_board.GetPiece(xTo,yTo) != null) {
  527.     Result.xCapture = xTo;
  528.     Result.yCapture = yTo;
  529.   }
  530.   Result.xFrom = xFrom;
  531.   Result.yFrom = yFrom;
  532.   Result.xTo = xTo;
  533.   Result.yTo = yTo;
  534.   Result.player = m_board.m_currentPlayer;
  535.  
  536.   m_board.MovePiece(xFrom, yFrom, xTo, yTo);
  537.     m_board.m_currentPlayer = Board.OtherPlayer(m_board.m_currentPlayer);
  538.  
  539.   
  540.     return Result;
  541.     
  542.  
  543.  
  544.  
  545.