/* ShogiViewer.java shogi board display applet 97-feb-26 ped created */ import java.applet.* ; import java.awt.* ; import java.io. * ; import java.net.* ; import java.util.* ; public class ShogiViewer extends Applet implements Enum_ShogiPieces { private static final int imageCount = GPR + 1 ; private static final int sqwidth = 29 ; private static final int sqheight = 31 ; private static final int boardOffset = ( sqwidth * 3 ) / 2 ; private static final int infoOffset = sqwidth * 13 ; private static final Rectangle advanceButtonRect = new Rectangle( sqwidth * 6 + 2, sqheight * 9 + 25, 58, 20 ) ; private static final Rectangle backButtonRect = new Rectangle( sqwidth * 6 - 60, sqheight * 9 + 25, 58, 20 ) ; private static final Rectangle ffButtonRect = new Rectangle( sqwidth * 6 + 64, sqheight * 9 + 25, 58, 20 ) ; private static final Rectangle rewButtonRect = new Rectangle( sqwidth * 6 - 122, sqheight * 9 + 25, 58, 20 ) ; private static final int arrowSize = 12 ; private static final Rectangle menuButtonRect = new Rectangle( infoOffset, sqheight * 9 + 25, 58, 20 ) ; private Vector games = new Vector( ) ; private ShogiGame game ; private Image[ ] image = new Image[ imageCount ] ; private Image boardImage ; private boolean menuMode = false ; public void init( ) { setBackground( Color.white ) ; showStatus( "Loading Images... please wait" ) ; boardImage = getImage( getCodeBase( ), "images/board.gif" ) ; image[ EM ] = getImage( getCodeBase( ), "images/em.gif" ) ; image[ SP ] = getImage( getCodeBase( ), "images/sp.gif" ) ; image[ SL ] = getImage( getCodeBase( ), "images/sl.gif" ) ; image[ SN ] = getImage( getCodeBase( ), "images/sn.gif" ) ; image[ SS ] = getImage( getCodeBase( ), "images/ss.gif" ) ; image[ SG ] = getImage( getCodeBase( ), "images/sg.gif" ) ; image[ SB ] = getImage( getCodeBase( ), "images/sb.gif" ) ; image[ SR ] = getImage( getCodeBase( ), "images/sr.gif" ) ; image[ SK ] = getImage( getCodeBase( ), "images/sk.gif" ) ; image[ SPP ] = getImage( getCodeBase( ), "images/spp.gif" ) ; image[ SPL ] = getImage( getCodeBase( ), "images/spl.gif" ) ; image[ SPN ] = getImage( getCodeBase( ), "images/spn.gif" ) ; image[ SPS ] = getImage( getCodeBase( ), "images/sps.gif" ) ; image[ SPB ] = getImage( getCodeBase( ), "images/spb.gif" ) ; image[ SPR ] = getImage( getCodeBase( ), "images/spr.gif" ) ; image[ GP ] = getImage( getCodeBase( ), "images/gp.gif" ) ; image[ GL ] = getImage( getCodeBase( ), "images/gl.gif" ) ; image[ GN ] = getImage( getCodeBase( ), "images/gn.gif" ) ; image[ GS ] = getImage( getCodeBase( ), "images/gs.gif" ) ; image[ GG ] = getImage( getCodeBase( ), "images/gg.gif" ) ; image[ GB ] = getImage( getCodeBase( ), "images/gb.gif" ) ; image[ GR ] = getImage( getCodeBase( ), "images/gr.gif" ) ; image[ GK ] = getImage( getCodeBase( ), "images/gk.gif" ) ; image[ GPP ] = getImage( getCodeBase( ), "images/gpp.gif" ) ; image[ GPL ] = getImage( getCodeBase( ), "images/gpl.gif" ) ; image[ GPN ] = getImage( getCodeBase( ), "images/gpn.gif" ) ; image[ GPS ] = getImage( getCodeBase( ), "images/gps.gif" ) ; image[ GPB ] = getImage( getCodeBase( ), "images/gpb.gif" ) ; image[ GPR ] = getImage( getCodeBase( ), "images/gpr.gif" ) ; // force images to load MediaTracker tracker = new MediaTracker( this ) ; tracker.addImage( boardImage, 0 ) ; for( int i = 0 ; i < imageCount ; i ++ ) { if( image[ i ] != null ) tracker.addImage( image[ i ], 0 ) ; } try { tracker.waitForID( 0 ) ; } catch( InterruptedException e ) { return ; } try { String dataFileName = getParameter( "datafile" ) ; URL dataURL = new URL( getCodeBase( ), dataFileName ) ; URLConnection connection = dataURL.openConnection( ) ; InputStream is = connection.getInputStream( ) ; game = new ShogiGame( is ) ; while( game.getMoveCount( ) > 0 ) { games.addElement( game ) ; game = new ShogiGame( is ) ; } game = ( ShogiGame ) games.firstElement( ) ; } catch( MalformedURLException e ) { System.out.println( "Malformed URL" ) ; } catch( IOException e ) { System.out.println( "IOException" ) ; } } public void paint( Graphics g ) { g.drawImage( boardImage, boardOffset, 0, null ) ; drawBoard( g ) ; // draw advance button { g.setColor( Color.lightGray ) ; Rectangle r = advanceButtonRect ; g.fill3DRect( r.x, r.y, r.width, r.height, true ) ; g.setColor( Color.red ) ; int leftx = r.x + r.width / 2 - arrowSize / 2 ; int rightx = leftx + arrowSize ; int xpoints[ ] = { leftx, leftx, rightx } ; int midy = r.y + r.height / 2 ; int topy = midy - arrowSize / 2 ; int bottomy = midy + arrowSize / 2 ; int ypoints[ ] = { topy, bottomy, midy } ; g.fillPolygon( xpoints, ypoints, 3 ) ; } // draw back button { g.setColor( Color.lightGray ) ; Rectangle r = backButtonRect ; g.fill3DRect( r.x, r.y, r.width, r.height, true ) ; g.setColor( Color.red ) ; int rightx = r.x + r.width / 2 + arrowSize / 2 ; int leftx = rightx - arrowSize ; int xpoints[ ] = { rightx, rightx, leftx } ; int midy = r.y + r.height / 2 ; int topy = midy - arrowSize / 2 ; int bottomy = midy + arrowSize / 2 ; int ypoints[ ] = { topy, bottomy, midy } ; g.fillPolygon( xpoints, ypoints, 3 ) ; } // draw ff button { g.setColor( Color.lightGray ) ; Rectangle r = ffButtonRect ; g.fill3DRect( r.x, r.y, r.width, r.height, true ) ; g.setColor( Color.red ) ; int leftx = r.x + r.width / 2 - arrowSize ; int midx = leftx + arrowSize ; int rightx = midx + arrowSize ; int leftxpoints[ ] = { leftx, leftx, midx } ; int rightxpoints[ ] = { midx, midx, rightx } ; int midy = r.y + r.height / 2 ; int topy = midy - arrowSize / 2 ; int bottomy = midy + arrowSize / 2 ; int ypoints[ ] = { topy, bottomy, midy } ; g.fillPolygon( leftxpoints, ypoints, 3 ) ; g.fillPolygon( rightxpoints, ypoints, 3 ) ; } // draw rewind button { g.setColor( Color.lightGray ) ; Rectangle r = rewButtonRect ; g.fill3DRect( r.x, r.y, r.width, r.height, true ) ; g.setColor( Color.red ) ; int rightx = r.x + r.width / 2 + arrowSize ; int midx = rightx - arrowSize ; int leftx = midx - arrowSize ; int rightxpoints[ ] = { rightx, rightx, midx } ; int leftxpoints[ ] = { midx, midx, leftx } ; int midy = r.y + r.height / 2 ; int topy = midy - arrowSize / 2 ; int bottomy = midy + arrowSize / 2 ; int ypoints[ ] = { topy, bottomy, midy } ; g.fillPolygon( leftxpoints, ypoints, 3 ) ; g.fillPolygon( rightxpoints, ypoints, 3 ) ; } drawRightHalf( ) ; } private void drawRightHalf( ) { if( menuMode ) drawGameMenu( ) ; else { Graphics g = getGraphics( ) ; drawInfoPanel( g ) ; drawCaption( g ) ; if( games.size( ) > 1 ) { // draw menu button g.setColor( Color.lightGray ) ; Rectangle r = menuButtonRect ; g.fill3DRect( r.x, r.y, r.width, r.height, true ) ; g.setColor( Color.red ) ; String menuString = "Menu" ; FontMetrics fm = g.getFontMetrics( ) ; int x = r.x + ( r.width - fm.stringWidth( menuString ) ) / 2 ; int y = r.y + ( r.height + fm.getHeight( ) ) / 2 - fm.getDescent( ) ; g.drawString( menuString, x, y ) ; } } } private void drawInfoPanel( Graphics g ) { Properties info = game.getGameComments( ) ; g.setColor( Color.black ) ; if( drawInfoItem( g, info, "Sente", 30 ) ) drawInfoItem( g, info, "Gote", 44 ) ; else if( drawInfoItem( g, info, "Uwate", 30 ) ) drawInfoItem( g, info, "Shitate", 44 ) ; else drawInfoItem( g, info, "Composer", 30 ) ; drawInfoItem( g, info, "Event", 64 ) ; drawInfoItem( g, info, "Round", 78 ) ; drawInfoItem( g, info, "Site", 92 ) ; drawInfoItem( g, info, "Date", 106 ) ; if( ! drawInfoItem( g, info, "Opening", 126 ) ) drawInfoItem( g, info, "Handicap", 126 ) ; drawInfoItem( g, info, "Result", 140 ) ; } private boolean drawInfoItem( Graphics g, Properties info, String key, int yPos ) { String value = info.getProperty( key.toLowerCase( ) ) ; if( value == null ) return false ; g.drawString( key + ": " + value, infoOffset, yPos ) ; return true ; } public boolean mouseDown( Event evt, int x, int y ) { if( advanceButtonRect.inside( x, y ) ) { ShogiBoard saveboard = game.getBoard( ).copy( ) ; if( game.advance( ) ) drawDiff( saveboard ) ; if( menuMode ) { menuMode = false ; drawRightHalf( ) ; } } else if( backButtonRect.inside( x, y ) ) { ShogiBoard saveboard = game.getBoard( ).copy( ) ; if( game.back( ) ) drawDiff( saveboard ) ; if( menuMode ) { menuMode = false ; drawRightHalf( ) ; } } else if( ffButtonRect.inside( x, y ) ) { ShogiBoard saveboard = game.getBoard( ).copy( ) ; if( game.toEnd( ) ) drawDiff( saveboard ) ; if( menuMode ) { menuMode = false ; drawRightHalf( ) ; } } else if( rewButtonRect.inside( x, y ) ) { ShogiBoard saveboard = game.getBoard( ).copy( ) ; if( game.toStart( ) ) drawDiff( saveboard ) ; if( menuMode ) { menuMode = false ; drawRightHalf( ) ; } } else if( ! menuMode && menuButtonRect.inside( x, y ) && games.size( ) > 1 ) { menuMode = true ; drawGameMenu( ) ; } else if( menuMode ) { int gamecount = games.size( ) ; if( gamecount > 10 ) gamecount = 10 ; for( int i = 0 ; i < gamecount ; i ++ ) { Rectangle mr = menuButtonRect ; Rectangle r = new Rectangle( mr.x, mr.y, mr.width, mr.height ) ; r.y -= 24 * ( gamecount - i - 1 ) ; if( r.inside( x, y ) ) { ShogiBoard saveboard = game.getBoard( ).copy( ) ; game = ( ShogiGame ) games.elementAt( i ) ; drawDiff( saveboard ) ; menuMode = false ; drawRightHalf( ) ; break ; } } } return true ; } public void drawGameMenu( ) { Graphics g = getGraphics( ) ; // clear info, caption area g.clearRect( infoOffset, 0, 500, 500 ) ; int gamecount = games.size( ) ; if( gamecount > 10 ) gamecount = 10 ; for( int i = 0 ; i < gamecount ; i ++ ) { g.setColor( Color.lightGray ) ; Rectangle r = menuButtonRect ; int y = r.y - ( gamecount - i - 1 ) * 24 ; g.fill3DRect( r.x, y, r.width, r.height, true ) ; g.setColor( games.elementAt( i ) == game ? Color.black : Color.red ) ; String caption = "Game " + ( i + 1 ) ; FontMetrics fm = g.getFontMetrics( ) ; int x = r.x + ( r.width - fm.stringWidth( caption ) ) / 2 ; y += ( r.height + fm.getHeight( ) ) / 2 - fm.getDescent( ) ; g.drawString( caption, x, y ) ; } } public boolean keyDown( Event evt, int key ) { if( key == 'd' ) game.getBoard( ).dump( ) ; return true ; } private void drawBoard( Graphics g ) { for( int rank = 8 ; rank >= 0 ; rank -- ) { for( int file = 0 ; file <= 8 ; file ++ ) drawSquare( g, file, rank ) ; } drawHand( g ) ; } private void drawHand( Graphics g ) { drawHandSente( g ) ; drawHandGote( g ) ; } private void drawHandSente( Graphics g ) { g.clearRect( sqwidth * 12 - 15, sqheight * 2 + 15, sqwidth + 12, sqheight * 7 ) ; int pos = 0 ; for( int i = 0 ; i < 7 ; i ++ ) { int count = game.getBoard( ).inHand( senteHandPiece[ i ] ) ; if( count > 0 ) { Point p = new Point( sqwidth * 12 - 15, ( 8 - pos ) * sqheight + 15 ) ; g.drawImage( image[ senteHandPiece[ i ] ], p.x, p.y, null ) ; if( count > 1 ) g.drawString( new Integer( count ).toString( ), p.x + sqwidth, p.y + 17 ) ; pos ++ ; } } } private void drawHandGote( Graphics g ) { g.clearRect( 0, 15, sqwidth + 12, sqheight * 7 ) ; int pos = 0 ; for( int i = 0 ; i < 7 ; i ++ ) { int count = game.getBoard( ).inHand( goteHandPiece[ i ] ) ; if( count > 0 ) { Point p = new Point( 0, sqheight * pos + 15 ) ; g.drawImage( image[ goteHandPiece[ i ] ], p.x, p.y, null ) ; if( count > 1 ) g.drawString( new Integer( count ).toString( ), p.x + sqwidth, p.y + 17 ) ; pos ++ ; } } } private void drawSquare( Graphics g, int file, int rank ) { Point p = gcoords( file, rank ) ; // draw piece int piece = game.getBoard( ).pieceAt( file, rank ) ; if( image[ piece ] != null ) g.drawImage( image[ piece ], p.x, p.y, null ) ; } private void drawDiff( ShogiBoard old ) { ShogiBoard board = game.getBoard( ) ; Graphics g = getGraphics( ) ; for( int rank = 8 ; rank >= 0 ; rank -- ) { for( int file = 0 ; file <= 8 ; file ++ ) { if( board.pieceAt( file, rank ) != old.pieceAt( file, rank ) ) drawSquare( g, file, rank ) ; } } for( int i = 0 ; i < 7 ; i ++ ) { if( board.inHand( senteHandPiece[ i ] ) != old.inHand( senteHandPiece[ i ] ) ) { drawHandSente( g ) ; break ; } } for( int i = 0 ; i < 7 ; i ++ ) { if( board.inHand( goteHandPiece[ i ] ) != old.inHand( goteHandPiece[ i ] ) ) { drawHandGote( g ) ; break ; } } drawCaption( g ) ; } private void drawCaption( Graphics g ) { g.clearRect( infoOffset, 146, 200, sqheight * 9 + 25 - 146 ) ; ShogiMove move = game.getLastMove( ) ; if( move != null ) { int moveCount = game.getCurrentMoveCount( ) ; String str = move.getString( ) ; if( str != null ) { if( ( moveCount % 2 ) == 1 ) str = new Integer( moveCount / 2 + 1 ).toString( ) + ". " + str ; else str = new Integer( moveCount / 2 ).toString( ) + "... " + str ; g.drawString( "After " + str, infoOffset, 180 ) ; } str = move.getComment( ) ; if( str != null ) drawWrappedText( g, str, infoOffset, 200, 200 ) ; } } private void drawWrappedText( Graphics g, String str, int x, int y, int maxwidth ) { // dirty and clumsy ... // this belongs in a separate class... FontMetrics fm = g.getFontMetrics( ) ; newline: while( true ) { str = str.trim( ) ; // debug // System.out.println( '"' + str + '"' ) ; int nextSpace = str.indexOf( ' ' ) ; if( nextSpace == -1 ) { g.drawString( str, x, y ) ; return ; } while( true ) { String line = str.substring( 0, nextSpace ) ; int nextNextSpace = str.indexOf( ' ', nextSpace + 1 ) ; String attempt ; if( nextNextSpace == -1 ) attempt = str.substring( 0 ) ; else attempt = str.substring( 0, nextNextSpace ) ; if( fm.stringWidth( attempt ) > maxwidth ) { g.drawString( line, x, y ) ; y += fm.getHeight( ) ; str = str.substring( nextSpace ) ; continue newline ; } if( nextNextSpace == -1 ) { g.drawString( attempt, x, y ) ; return ; } nextSpace = nextNextSpace ; } } } private Point gcoords( int file, int rank ) { return new Point( file * sqwidth + boardOffset + 2, ( 8 - rank ) * sqheight + 15 ) ; } private static final int senteHandPiece[ ] = { SP, SL, SN, SS, SG, SB, SR } ; private static final int goteHandPiece[ ] = { GP, GL, GN, GS, GG, GB, GR } ; }