/* ShogiBoard.java a shogi board 97-feb-26 ped created */ import java.util.* ; public class ShogiBoard implements Enum_ShogiPieces { public void dump( ) { String piece[ ] = { " -", " P", " L", " N", " S", " G", " B", " R", " K", "+P", "+L", "+N", "+S", "??", "+B", "+R", "??", " p", " l", " n", " s", " g", " b", " r", " k", "+p", "+l", "+n", "+s", "??", "+b", "+r", "??" } ; for( int j = 8 ; j >= 0 ; j -- ) { for( int i = 0 ; i < 9 ; i ++ ) System.out.print( piece[ square[ i ][ j ] ] + " " ) ; System.out.println( " : " + ( j + 1 ) ) ; } for( int i = 0 ; i < 2 ; i ++ ) { for( int j = 0 ; j < 7 ; j ++ ) System.out.print( hand[ i ][ j ] ) ; System.out.print( " " ) ; } } private int square[ ][ ] = { { SL, EM, SP, EM, EM, EM, GP, EM, GL }, { SN, SB, SP, EM, EM, EM, GP, GR, GN }, { SS, EM, SP, EM, EM, EM, GP, EM, GS }, { SG, EM, SP, EM, EM, EM, GP, EM, GG }, { SK, EM, SP, EM, EM, EM, GP, EM, GK }, { SG, EM, SP, EM, EM, EM, GP, EM, GG }, { SS, EM, SP, EM, EM, EM, GP, EM, GS }, { SN, SR, SP, EM, EM, EM, GP, GB, GN }, { SL, EM, SP, EM, EM, EM, GP, EM, GL }, } ; private int hand[ ][ ] = { { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 } } ; private boolean senteToMove = true ; static int globalPly = 0 ; // ugly kludge, set by constructor... ShogiBoard( ) { globalPly = 0 ; } ShogiBoard( String str ) { String handicap[ ] = { "Lance", "Right Lance", "Bishop", "Rook", "Rook and Lance", "2 Piece", "3 Piece", "4 Piece", "5 Piece", "6 Piece", "7 Piece", "8 Piece" } ; for( int i = 0 ; i < 12 ; i ++ ) { if( str.equalsIgnoreCase( handicap[ i ] ) ) { senteToMove = false ; globalPly = 1 ; switch( i ) { case 11 : // 8 piece square[ 2 ][ 8 ] = EM ; case 10 : // 7 piece square[ 6 ][ 8 ] = EM ; case 9 : // 6 piece square[ 1 ][ 8 ] = EM ; case 8 : // 5 piece square[ 7 ][ 8 ] = EM ; case 7 : // 4 piece square[ 0 ][ 8 ] = EM ; case 6 : // 3 piece square[ 8 ][ 8 ] = EM ; case 5 : // 2 piece square[ 7 ][ 7 ] = EM ; case 3 : // Rook square[ 1 ][ 7 ] = EM ; return ; case 4 : // Rook and Lance square[ 1 ][ 7 ] = EM ; case 0 : // Lance square[ 8 ][ 8 ] = EM ; return ; case 2 : // Bishop square[ 7 ][ 7 ] = EM ; return ; case 1 : // Right Lance square[ 0 ][ 8 ] = EM ; return ; } } } // process FEN int FENindex = 0 ; hand[ 1 ][ 0 ] = 18 ; hand[ 1 ][ 1 ] = 4 ; hand[ 1 ][ 2 ] = 4 ; hand[ 1 ][ 3 ] = 4 ; hand[ 1 ][ 4 ] = 4 ; hand[ 1 ][ 5 ] = 2 ; hand[ 1 ][ 6 ] = 2 ; for( int rank = 8 ; rank >= 0 ; rank -- ) { // debug System.out.println( str.substring( FENindex ) ) ; for( int file = 0 ; file <= 8 ; file ++ ) { char ch = str.charAt( FENindex ++ ) ; if( Character.isDigit( ch ) ) { int count = ch - '0' ; while( count -- > 0 ) square[ file ++ ][ rank ] = EM ; if( file > 8 ) break ; ch = str.charAt( FENindex ++ ) ; } boolean promoted = false ; if( ch == '+' ) { promoted = true ; ch = str.charAt( FENindex ++ ) ; } switch( Character.toUpperCase( ch ) ) { case 'P' : square[ file ][ rank ] = SP ; hand[ 1 ][ 0 ] -- ; break ; case 'L' : square[ file ][ rank ] = SL ; hand[ 1 ][ 1 ] -- ; break ; case 'N' : square[ file ][ rank ] = SN ; hand[ 1 ][ 2 ] -- ; break ; case 'S' : square[ file ][ rank ] = SS ; hand[ 1 ][ 3 ] -- ; break ; case 'G' : square[ file ][ rank ] = SG ; hand[ 1 ][ 4 ] -- ; break ; case 'B' : square[ file ][ rank ] = SB ; hand[ 1 ][ 5 ] -- ; break ; case 'R' : square[ file ][ rank ] = SR ; hand[ 1 ][ 6 ] -- ; break ; case 'K' : square[ file ][ rank ] = SK ; break ; } if( Character.isLowerCase( ch ) ) square[ file ][ rank ] += 16 ; if( promoted ) square[ file ][ rank ] += 8 ; } FENindex ++ ; // skip slash or space... } // debug System.out.println( str.substring( FENindex ) ) ; for( int index = 0 ; index < 7 ; index ++ ) { int count = str.charAt( FENindex++ ) - '0' ; hand[ 0 ][ index ] = count ; hand[ 1 ][ index ] -= count ; } FENindex ++ ; // skip slash // debug System.out.println( str.substring( FENindex ) ) ; if( Character.toLowerCase( str.charAt( FENindex ) ) == 't' ) FENindex ++ ; else { for( int index = 0 ; index < 7 ; index ++ ) hand[ 1 ][ index ] = str.charAt( FENindex ++ ) - '0' ; } FENindex ++ ; // skip space // debug System.out.println( str.substring( FENindex ) ) ; if( Character.toLowerCase( str.charAt( FENindex ++ ) ) == 'g' ) senteToMove = false ; FENindex ++ ; // skip space String s = str.substring( FENindex ) ; globalPly = Integer.parseInt( s ) * 2 - 1 ; if( senteToMove ) globalPly -- ; // debug dump( ) ; } public int pieceAt( int file, int rank ) { return square[ file ][ rank ] ; } public int inHand( int piece ) { switch( piece ) { case SP : return hand[ 0 ][ 0 ] ; case SL : return hand[ 0 ][ 1 ] ; case SN : return hand[ 0 ][ 2 ] ; case SS : return hand[ 0 ][ 3 ] ; case SG : return hand[ 0 ][ 4 ] ; case SB : return hand[ 0 ][ 5 ] ; case SR : return hand[ 0 ][ 6 ] ; case GP : return hand[ 1 ][ 0 ] ; case GL : return hand[ 1 ][ 1 ] ; case GN : return hand[ 1 ][ 2 ] ; case GS : return hand[ 1 ][ 3 ] ; case GG : return hand[ 1 ][ 4 ] ; case GB : return hand[ 1 ][ 5 ] ; case GR : return hand[ 1 ][ 6 ] ; } // throw exception return 0 ; } public boolean isSenteToMove( ) { return senteToMove ; } public void makeMove( ShogiMove move ) { if( move.fromfile < 0 ) { // drop int piece = - move.fromfile ; switch( piece ) { case SP : if( hand[ 0 ][ 0 ] <= 0 ) throw new RuntimeException( "No piece to drop" ) ; hand[ 0 ][ 0 ] -- ; break ; case SL : if( hand[ 0 ][ 1 ] <= 0 ) throw new RuntimeException( "No piece to drop" ) ; hand[ 0 ][ 1 ] -- ; break ; case SN : if( hand[ 0 ][ 2 ] <= 0 ) throw new RuntimeException( "No piece to drop" ) ; hand[ 0 ][ 2 ] -- ; break ; case SS : if( hand[ 0 ][ 3 ] <= 0 ) throw new RuntimeException( "No piece to drop" ) ; hand[ 0 ][ 3 ] -- ; break ; case SG : if( hand[ 0 ][ 4 ] <= 0 ) throw new RuntimeException( "No piece to drop" ) ; hand[ 0 ][ 4 ] -- ; break ; case SB : if( hand[ 0 ][ 5 ] <= 0 ) throw new RuntimeException( "No piece to drop" ) ; hand[ 0 ][ 5 ] -- ; break ; case SR : if( hand[ 0 ][ 6 ] <= 0 ) throw new RuntimeException( "No piece to drop" ) ; hand[ 0 ][ 6 ] -- ; break ; case GP : if( hand[ 1 ][ 0 ] <= 0 ) throw new RuntimeException( "No piece to drop" ) ; hand[ 1 ][ 0 ] -- ; break ; case GL : if( hand[ 1 ][ 1 ] <= 0 ) throw new RuntimeException( "No piece to drop" ) ; hand[ 1 ][ 1 ] -- ; break ; case GN : if( hand[ 1 ][ 2 ] <= 0 ) throw new RuntimeException( "No piece to drop" ) ; hand[ 1 ][ 2 ] -- ; break ; case GS : if( hand[ 1 ][ 3 ] <= 0 ) throw new RuntimeException( "No piece to drop" ) ; hand[ 1 ][ 3 ] -- ; break ; case GG : if( hand[ 1 ][ 4 ] <= 0 ) throw new RuntimeException( "No piece to drop" ) ; hand[ 1 ][ 4 ] -- ; break ; case GB : if( hand[ 1 ][ 5 ] <= 0 ) throw new RuntimeException( "No piece to drop" ) ; hand[ 1 ][ 5 ] -- ; break ; case GR : if( hand[ 1 ][ 6 ] <= 0 ) throw new RuntimeException( "No piece to drop" ) ; hand[ 1 ][ 6 ] -- ; break ; } square[ move.tofile ][ move.torank ] = piece ; } else { int piece = square[ move.fromfile ][ move.fromrank ] ; int torank = move.torank ; if( torank >= 10 ) { // promotion piece += 8 ; torank -= 10 ; } int captured = square[ move.tofile ][ torank ] ; switch( captured ) { case GP : case GPP : hand[ 0 ][ 0 ] ++ ; break ; case GL : case GPL : hand[ 0 ][ 1 ] ++ ; break ; case GN : case GPN : hand[ 0 ][ 2 ] ++ ; break ; case GS : case GPS : hand[ 0 ][ 3 ] ++ ; break ; case GG : hand[ 0 ][ 4 ] ++ ; break ; case GB : case GPB : hand[ 0 ][ 5 ] ++ ; break ; case GR : case GPR : hand[ 0 ][ 6 ] ++ ; break ; case SP : case SPP : hand[ 1 ][ 0 ] ++ ; break ; case SL : case SPL : hand[ 1 ][ 1 ] ++ ; break ; case SN : case SPN : hand[ 1 ][ 2 ] ++ ; break ; case SS : case SPS : hand[ 1 ][ 3 ] ++ ; break ; case SG : hand[ 1 ][ 4 ] ++ ; break ; case SB : case SPB : hand[ 1 ][ 5 ] ++ ; break ; case SR : case SPR : hand[ 1 ][ 6 ] ++ ; break ; } square[ move.tofile ][ torank ] = piece ; square[ move.fromfile ][ move.fromrank ] = EM ; } senteToMove = ! senteToMove ; } public ShogiBoard copy( ) { ShogiBoard copy = new ShogiBoard( ) ; for( int i = 0 ; i < 9 ; i ++ ) { for( int j = 0 ; j < 9 ; j ++ ) copy.square[ i ][ j ] = square[ i ][ j ] ; } for( int i = 0 ; i < 2 ; i ++ ) { for( int j = 0 ; j < 7 ; j ++ ) copy.hand[ i ][ j ] = hand[ i ][ j ] ; } copy.senteToMove = senteToMove ; return copy ; } public Vector generateLegalMoves( int piece ) { Vector v = new Vector( ) ; for( int fromfile = 0 ; fromfile < 9 ; fromfile ++ ) { for( int fromrank = 0 ; fromrank < 9 ; fromrank ++ ) { if( square[ fromfile ][ fromrank ] == piece ) { switch( piece ) { case SP : if( ! isSente( square[ fromfile ][ fromrank + 1 ] ) ) addMove( v, fromfile, fromrank, fromfile, fromrank + 1 ) ; break ; case SL : for( int torank = fromrank + 1 ; torank < 9 ; torank ++ ) { if( ! isSente( square[ fromfile ][ torank ] ) ) addMove( v, fromfile, fromrank, fromfile, torank ) ; if( square[ fromfile ][ torank ] != EM ) break ; } break ; case SN : for( int i = 0 ; i < 2 ; i ++ ) { int tofile = fromfile + knightMoves[ i ][ 0 ] ; int torank = fromrank + knightMoves[ i ][ 1 ] ; if( isOnBoard( tofile, torank ) && ! isSente( square[ tofile][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; } break ; case SS : for( int i = 0 ; i < 5 ; i ++ ) { int tofile = fromfile + silverMoves[ i ][ 0 ] ; int torank = fromrank + silverMoves[ i ][ 1 ] ; if( isOnBoard( tofile, torank ) && ! isSente( square[ tofile][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; } break ; case SG : case SPP : case SPL : case SPN : case SPS : for( int i = 0 ; i < 6 ; i ++ ) { int tofile = fromfile + goldMoves[ i ][ 0 ] ; int torank = fromrank + goldMoves[ i ][ 1 ] ; if( isOnBoard( tofile, torank ) && ! isSente( square[ tofile][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; } break ; case SPB : for( int i = 0 ; i < 4 ; i ++ ) { int tofile = fromfile + rookMoves[ i ][ 0 ] ; int torank = fromrank + rookMoves[ i ][ 1 ] ; if( isOnBoard( tofile, torank ) && ! isSente( square[ tofile][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; } // fall through case SB : for( int i = 0 ; i < 4 ; i ++ ) { int dir[ ] = bishopMoves[ i ] ; int tofile = fromfile + dir[ 0 ] ; int torank = fromrank + dir[ 1 ] ; while( isOnBoard( tofile, torank ) ) { if( ! isSente( square[ tofile ][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; if( square[ tofile ][ torank ] != EM ) break ; tofile += dir[ 0 ] ; torank += dir[ 1 ] ; } } break ; case SPR : for( int i = 0 ; i < 4 ; i ++ ) { int tofile = fromfile + bishopMoves[ i ][ 0 ] ; int torank = fromrank + bishopMoves[ i ][ 1 ] ; if( isOnBoard( tofile, torank ) && ! isSente( square[ tofile][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; } // fall through case SR : for( int i = 0 ; i < 4 ; i ++ ) { int dir[ ] = rookMoves[ i ] ; int tofile = fromfile + dir[ 0 ] ; int torank = fromrank + dir[ 1 ] ; while( isOnBoard( tofile, torank ) ) { if( ! isSente( square[ tofile ][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; if( square[ tofile ][ torank ] != EM ) break ; tofile += dir[ 0 ] ; torank += dir[ 1 ] ; } } break ; case SK : for( int i = 0 ; i < 8 ; i ++ ) { int tofile = fromfile + kingMoves[ i ][ 0 ] ; int torank = fromrank + kingMoves[ i ][ 1 ] ; if( isOnBoard( tofile, torank ) && ! isSente( square[ tofile][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; } break ; case GP : if( ! isGote( square[ fromfile ][ fromrank - 1 ] ) ) addMove( v, fromfile, fromrank, fromfile, fromrank - 1 ) ; break ; case GL : for( int torank = fromrank - 1 ; torank >= 0 ; torank -- ) { if( ! isGote( square[ fromfile ][ torank ] ) ) addMove( v, fromfile, fromrank, fromfile, torank ) ; if( square[ fromfile ][ torank ] != EM ) break ; } break ; case GN : for( int i = 0 ; i < 2 ; i ++ ) { int tofile = fromfile - knightMoves[ i ][ 0 ] ; int torank = fromrank - knightMoves[ i ][ 1 ] ; if( isOnBoard( tofile, torank ) && ! isGote( square[ tofile][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; } break ; case GS : for( int i = 0 ; i < 5 ; i ++ ) { int tofile = fromfile - silverMoves[ i ][ 0 ] ; int torank = fromrank - silverMoves[ i ][ 1 ] ; if( isOnBoard( tofile, torank ) && ! isGote( square[ tofile][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; } break ; case GG : case GPP : case GPL : case GPN : case GPS : for( int i = 0 ; i < 6 ; i ++ ) { int tofile = fromfile - goldMoves[ i ][ 0 ] ; int torank = fromrank - goldMoves[ i ][ 1 ] ; if( isOnBoard( tofile, torank ) && ! isGote( square[ tofile][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; } break ; case GPB : for( int i = 0 ; i < 4 ; i ++ ) { int tofile = fromfile - rookMoves[ i ][ 0 ] ; int torank = fromrank - rookMoves[ i ][ 1 ] ; if( isOnBoard( tofile, torank ) && ! isGote( square[ tofile][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; } // fall through case GB : for( int i = 0 ; i < 4 ; i ++ ) { int dir[ ] = bishopMoves[ i ] ; int tofile = fromfile + dir[ 0 ] ; int torank = fromrank + dir[ 1 ] ; while( isOnBoard( tofile, torank ) ) { if( ! isGote( square[ tofile ][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; if( square[ tofile ][ torank ] != EM ) break ; tofile += dir[ 0 ] ; torank += dir[ 1 ] ; } } break ; case GPR : for( int i = 0 ; i < 4 ; i ++ ) { int tofile = fromfile - bishopMoves[ i ][ 0 ] ; int torank = fromrank - bishopMoves[ i ][ 1 ] ; if( isOnBoard( tofile, torank ) && ! isGote( square[ tofile][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; } // fall through case GR : for( int i = 0 ; i < 4 ; i ++ ) { int dir[ ] = rookMoves[ i ] ; int tofile = fromfile + dir[ 0 ] ; int torank = fromrank + dir[ 1 ] ; while( isOnBoard( tofile, torank ) ) { if( ! isGote( square[ tofile ][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; if( square[ tofile ][ torank ] != EM ) break ; tofile += dir[ 0 ] ; torank += dir[ 1 ] ; } } break ; case GK : for( int i = 0 ; i < 8 ; i ++ ) { int tofile = fromfile - kingMoves[ i ][ 0 ] ; int torank = fromrank - kingMoves[ i ][ 1 ] ; if( isOnBoard( tofile, torank ) && ! isGote( square[ tofile][ torank ] ) ) addMove( v, fromfile, fromrank, tofile, torank ) ; } break ; } } } } return v ; } private void addMove( Vector v, int fromfile, int fromrank, int tofile, int torank ) { v.addElement( new ShogiMove( fromfile, fromrank, tofile, torank ) ) ; } private static boolean isOnBoard( int file, int rank ) { return file >= 0 && file < 9 && rank >= 0 && rank < 9 ; } private static boolean isSente( int piece ) { return piece >= SP && piece <= SPR ; } private static boolean isGote( int piece ) { return piece >= GP && piece <= GPR ; } // constant move tables private static final int[ ][ ] knightMoves = { { -1, 2 }, { 1, 2 } } ; private static final int[ ][ ] silverMoves = { { -1, 1 }, { 0, 1 }, { 1, 1 }, { -1, -1 }, { 1, -1 } } ; private static final int[ ][ ] goldMoves = { { -1, 1 }, { 0, 1 }, { 1, 1 }, { -1, 0 }, { 1, 0 }, { 0, -1 } } ; private static final int[ ][ ] bishopMoves = { { -1, -1 }, { -1, 1 }, { 1, -1 }, { 1, 1 } } ; private static final int[ ][ ] rookMoves = { { -1, 0 }, { 0, -1 }, { 0, 1 }, { 1, 0 } } ; private static final int[ ][ ] kingMoves = { { -1, -1 }, { -1, 0 }, { -1, 1 }, { 0, -1 }, { 0, 1 }, { 1, -1 }, { 1, 0 }, { 1, 1 } } ; }