//---------------------------------------------------------------------- // クロスサム(カックロ、足し算クロス) // // Copyright(C) 1996 Hirofumi Fujiwara // 本プログラムは、改造も含め、その商用利用は禁止します。 //---------------------------------------------------------------------- import java.awt.*; import java.applet.*; import java.lang.*; import java.io.*; import java.util.*; import java.net.*; public class CrossSum extends Applet { public String postpage; // 正解の時に表示するページ String probfile; DatabaseAccess db = null; DatabaseIF dbif = null; int unitsize = 0; int fontsize = 0; boolean first = true; Color controlPanelcolor; Panel controlPanel; // 制御パネル Checkbox hintbox; // ヒント Choice dbchoice; // DBアクセス用チョイス PlayPanel playPanel; // 中央ボード Font boldfont = new java.awt.Font( "Helvetica", 0, 18 ); //---------------------------------------- // 構築子 //---------------------------------------- public void init() { dbif = new DatabaseIF( this, getParentFrame() ); postpage = getParameter("post"); probfile = getParameter("problemfile"); db.problemid = getParameter("problemid"); String str = getParameter("unitsize"); if( str != null ) { try { unitsize = (Integer.valueOf(str)).intValue(); } catch( NoSuchElementException e ) {} } str = getParameter("fontsize"); if( str != null ) { try { fontsize = (Integer.valueOf(str)).intValue(); } catch( NoSuchElementException e ) {} } setLayout( new BorderLayout() ); // 上部 controlPanel = new Panel(); controlPanel.setFont( boldfont ); add( "North", controlPanel ); controlPanel.setLayout( new FlowLayout( FlowLayout.CENTER, 30, 2 ) ); controlPanelcolor = controlPanel.getBackground(); hintbox = new Checkbox( "Hint" ); hintbox.setFont( boldfont ); controlPanel.add( hintbox ); controlPanel.add( new ControlButton( this, "Clear" ) ); controlPanel.add( new ControlButton( this, "Check" ) ); // if( db.problemid != null ) { // dbchoice = new Choice(); // dbchoice.setFont(boldfont); // dbchoice.addItem( "Database" ); // dbchoice.addItem( "Register" ); // dbchoice.addItem( "Enter" ); // dbchoice.addItem( "Save" ); // dbchoice.addItem( "Load" ); // dbchoice.addItem( "View" ); // dbchoice.addItem( "Answer" ); // controlPanel.add( dbchoice ); // } // 中央 playPanel = new PlayPanel( this ); add( "Center", playPanel ); // (C)Copyright Label copyright = new Label( "Cross Sums V0.4" + " " + "Copyright(C)1996 Hirofumi Fujiwara.", Label.CENTER ); add( "South", copyright ); if( probfile!=null && first ) { first = false; playPanel.loadData( probfile ); } playPanel.canvas.resizeCanvas(); } //---------------------------------------- // キー押し下げイベント //---------------------------------------- public boolean keyDown( Event evt, int key ) { CrosssumCanvas cc = playPanel.canvas; if( key == Event.UP ) { cc.moveCurXY( 0, -1 ); return true; } if( key == Event.DOWN ) { cc.moveCurXY( 0, +1 ); return true; } if( key == Event.LEFT ) { cc.moveCurXY( -1, 0 ); return true; } if( key == Event.RIGHT ) { cc.moveCurXY( +1, 0 ); return true; } if( key == '\n' ) { hintbox.setState( playPanel.ishint = ! playPanel.ishint ); return true; } if( key == ' ' ) { playPanel.changeValue( 0, true ); return true; } int keynum = key - '0'; if( 0<=keynum && keynum<10 ) { playPanel.changeValue( keynum, true ); return true; } return true; } //---------------------------------------- // 親フレームを見つける //---------------------------------------- Frame getParentFrame() { Component co = this; while(!((co = co.getParent()) instanceof Frame)) {} return (Frame) co; } //---------------------------------------- // アクション //---------------------------------------- public boolean action( Event evt, Object obj ) { if( evt.target == hintbox ) { playPanel.ishint = hintbox.getState(); return true; } return false; } } //================================================================================ // 中央のボード(遊び用パネル) //================================================================================ class PlayPanel extends Panel { CrossSum app; DatabaseAccess db; GridBagLayout gbl; CrosssumCanvas canvas; Cell table[][]; boolean ishint; // ヒント int curX = -1; int curY = -1; int bdwidth = 20; // 盤の幅 int bdheight = 20; // 高さ int bdunit = 32; // ユニットサイズ int fw, fh; // フルキャンバスのサイズ //-------------------------------------- PlayPanel // 構築子 //------------------------------------------------ PlayPanel( CrossSum p ) { app = p; db = app.db; if( app.unitsize > 0 ) bdunit = app.unitsize; newBoard(); canvas = new CrosssumCanvas( this ); add( canvas ); } //-------------------------------------- PlayPanel // セル //------------------------------------------------ Cell cell() { return cell( curX, curY ); } Cell cell( int x, int y ) { if( x < 0 || bdwidth <= x || y < 0 || bdheight <= y ) return null; return table[x][y]; } //-------------------------------------- PlayPanel // テーブルの再生成 //------------------------------------------------ void newBoard() { table = new Cell[bdwidth][bdheight]; for( int x=0; x 0 ) { int array[] = new int[10]; int sum = 0; int len = 0; for( int k=1; k<10; ++k ) { if( y+k >= bdheight ) break; Cell cc = table[x][y+k]; if( cc.mark ) break; ++len; ++array[cc.value]; sum += cc.value; } if( sum != c.vsum ) { c.verror = true; err = true; } for( int k=1; k<10; ++k ) { if( array[k] == 1 ) array[k] = 0; } for( int k=1; k<=len; ++k ) { Cell cc = table[x][y+k]; if( array[cc.value] == 0 ) continue; cc.error = true; c.verror = true; err = true; } } // 水平和のチェック if( c.hsum > 0 ) { int array[] = new int[10]; int sum = 0; int len = 0; for( int k=1; k<10; ++k ) { if( x+k >= bdwidth ) break; Cell cc = table[x+k][y]; if( cc.mark ) break; ++len; ++array[cc.value]; sum += cc.value; } if( sum != c.hsum ) { c.herror = true; err = true; } for( int k=1; k<10; ++k ) { if( array[k] == 1 ) array[k] = 0; } for( int k=1; k<=len; ++k ) { Cell cc = table[x+k][y]; if( array[cc.value] == 0 ) continue; cc.error = true; c.herror = true; err = true; } } } } return err; } //-------------------------------------- PlayPanel // 値の変更 //------------------------------------------------ void changeValue( int v, boolean update ) { if( curX<0 && curY<0 ) return; Cell c = table[curX][curY]; int prevvalue = c.value; boolean prevhint = (c.color != Color.black); c.setValue( v, ishint ); db.history.set( curX, curY, prevhint, prevvalue, ishint, v ); canvas.paintCell( curX, curY, true ); if( update ) canvas.paint( canvas.getGraphics() ); } } //================================================================================ // キャンバス //================================================================================ class CrosssumCanvas extends Canvas { PlayPanel panel; CrossSum app; Image fullCanvas = null; Graphics fg = null; Font sumfont; Font numfont; //---------------------------------------- // 構築子 //---------------------------------------- CrosssumCanvas( PlayPanel p ) { panel = p; app = panel.app; } //---------------------------------------- // フルキャンバスの生成 //---------------------------------------- void resizeCanvas() { panel.fw = panel.bdwidth * panel.bdunit + 1; panel.fh = panel.bdheight * panel.bdunit + 1; fullCanvas = app.createImage( panel.fw, panel.fh ); fg = fullCanvas.getGraphics(); paintFull(); resize( panel.fw, panel.fh ); } //---------------------------------------- // マスがマークされているか //---------------------------------------- boolean isMark( int x, int y ) { if( x<0 || panel.bdwidth<=x || y<0 || panel.bdheight<=y ) { return false; } return panel.table[x][y].mark; } //---------------------------------------- // 1マスの描画 //---------------------------------------- void paintCell( int x, int y, boolean act ) { int unit = panel.bdunit; Cell c = panel.table[x][y]; if( c.mark ) { // マーク部分 fg.setColor( Color.black ); fg.fillRect( unit*x+1, unit*y+1, unit-1, unit-1 ); drawSumNumber( fg, x, y, c ); fg.setColor( Color.white ); // 斜め線 fg.drawLine( unit*x+1, unit*y+1, unit*(x+1), unit*(y+1) ); if( isMark(x-1,y) ) { fg.drawLine( unit*x, unit*y, unit*x, unit*(y+1) ); } if( isMark(x,y-1) ) { fg.drawLine( unit*x, unit*y, unit*(x+1), unit*y ); } } else { // 普通枠部分 fg.setColor( act ? Color.cyan : Color.white ); fg.fillRect( unit*x+1, unit*y+1, unit-1, unit-1 ); drawNumber( fg, x, y, c ); } } //---------------------------------------- // 数字の描画 //---------------------------------------- void drawNumber( Graphics g, int x, int y, Cell c ) { int v = c.value; if( v==0 ) return; int unit = panel.bdunit; if( numfont == (Font)null ) { int fs = (app.fontsize!=0) ? app.fontsize : unit*9/10; numfont = new Font( "Helvetica", 0, fs ); } Color col = c.color; if( c.error ) col = Color.red; g.setColor( col ); g.setFont( numfont ); FontMetrics fm = g.getFontMetrics();; int sHeight = fm.getHeight(); int sAscent = fm. getAscent(); String s = String.valueOf(v); int sWidth = fm.stringWidth(s); int xx = x*unit + (unit - sWidth)/2; int yy = y*unit + sAscent+ (unit - sAscent)/2; g.drawString( s, xx, yy ); } //---------------------------------------- // 数字の描画(和) //---------------------------------------- void drawSumNumber( Graphics g, int x, int y, Cell c ) { int v = c.vsum; int h = c.hsum; if( v==0 && h==0 ) return; int unit = panel.bdunit; if( sumfont == (Font)null ) { sumfont = new Font( "Helvetica", 0, unit/2 ); } g.setFont( sumfont ); FontMetrics fm = g.getFontMetrics(); int sHeight = fm.getHeight(); int sAscent = fm. getAscent(); if( v != 0 ) { if( c.verror ) { Polygon p = new Polygon(); p.addPoint( x*unit+1, y*unit+1 ); p.addPoint( x*unit+1, (y+1)*unit ); p.addPoint( (x+1)*unit, (y+1)*unit ); g.setColor( Color.red ); g.fillPolygon( p ); } g.setColor( Color.white ); String s = String.valueOf(v); int sWidth = fm.stringWidth(s); int xx = x*unit + (unit/2 - sWidth)/2 + 2; int yy = (y+1)*unit - unit/20 - 1; g.drawString( s, xx, yy ); } if( h != 0 ) { if( c.herror ) { Polygon p = new Polygon(); p.addPoint( x*unit+1, y*unit+1 ); p.addPoint( (x+1)*unit, y*unit+1 ); p.addPoint( (x+1)*unit, (y+1)*unit ); g.setColor( Color.red ); g.fillPolygon( p ); } g.setColor( Color.white ); String s = String.valueOf(h); int sWidth = fm.stringWidth(s); int xx = (x+1)*unit - (unit/2 + sWidth)/2 - 2; int yy = y*unit + sAscent + unit/20 ; g.drawString( s, xx, yy ); } } //---------------------------------------- // フルキャンバスに描画する。 //---------------------------------------- void paintFull() { int unit = panel.bdunit; fg.setColor( Color.white ); fg.fillRect( 0, 0, size().width, size().height ); fg.setColor( Color.black ); for( int i=0; i<=panel.bdwidth; ++i ) { fg.drawLine( i*unit, 0, i*unit, panel.fh ); } for( int i=0; i<=panel.bdheight; ++i ) { fg.drawLine( 0, i*unit, panel.fw, i*unit ); } for( int x=0; x=0 && oldY>=0 ) { // アクティブな場所があった。 paintCell( oldX, oldY, false ); } if( panel.curX>=0 && panel.curY>=0 ) { // 新しい場所をアクティブにする。 paintCell( panel.curX, panel.curY, true ); } paint( getGraphics() ); return true; } //---------------------------------------- // カレント位置の移動 //---------------------------------------- void moveCurXY( int dx, int dy ) { int oldX = panel.curX; int oldY = panel.curY; int cx = panel.curX+dx; int cy = panel.curY+dy; if( cx < 1 ) cx = 1; if( cx >= panel.bdwidth ) cx = panel.bdwidth - 1; if( cy < 1 ) cy = 1; if( cy >= panel.bdheight ) cy = panel.bdheight - 1; panel.curX = cx; panel.curY = cy; if( oldX>=0 && oldY>=0 ) { // アクティブな場所があった。 paintCell( oldX, oldY, false ); } if( panel.curX>=0 && panel.curY>=0 ) { // 新しい場所をアクティブにする。 paintCell( panel.curX, panel.curY, true ); } paint( getGraphics() ); } } //-------------------------------------------------------------------------------- // セル情報 //-------------------------------------------------------------------------------- class Cell { boolean mark; byte vsum, hsum; byte value; boolean verror; boolean herror; boolean error; Color color; //---------------------------------------- // 構築子 //---------------------------------------- Cell() { mark = false; vsum = hsum = value = 0; verror = herror = error = false; color = Color.black; } //---------------------------------------- // マークに縦と横の和を設定する //---------------------------------------- void setMark( int v, int h ) { mark = true; vsum = (byte)v; hsum = (byte)h; } //---------------------------------------- // 数値のセット //---------------------------------------- void setValue( int v, boolean ishint ) { value = (byte)v; error = false; color = ishint ? Color.pink : Color.black; } //---------------------------------------- // 人が入力する部分のクリア //---------------------------------------- void clear() { value = 0; verror = herror = error = false; } //---------------------------------------- // 文字列データに直す // 1文字目 't' ヒント 'f' 黒 // 2文字目 '0'〜'9' // マークのマス "mk" //---------------------------------------- String convtoString() { String str = "mk"; if( ! mark ) { str = (color==Color.pink) ? "t" : "f"; str += value; } return str; } void setfromString( String str ) { if( "mk".equals( str ) ) { return; } int v = 0; try { v = (byte)Integer.valueOf(str.substring(1)).intValue(); } catch( NoSuchElementException e ) {} boolean h = "t".equals( str.substring(0,1) ); setValue( v, h ); } } //-------------------------------------------------------------------------------- // 制御ボタンクラス //-------------------------------------------------------------------------------- class ControlButton extends Button { CrossSum app; String name; // 構築子 ControlButton( CrossSum p, String str ) { super(); app = p; name = str; setLabel( str ); setFont( app.boldfont ); } public boolean action( Event evt, Object obj ) { if( name.equals("Clear") ) { app.playPanel.clear(); return true; } if( name.equals("Check") ) { app.playPanel.check(); return true; } return true; } } //================================================================================ // データベース用インターフェイス //-------------------------------------------------------------------------------- // このクラスの中では、CrossSumアプリケーション内を自由に呼び出してよい //================================================================================ class DatabaseIF { Frame parentFrame; CrossSum applet; DatabaseAccess db = null; URL docbase; DatabaseIF( CrossSum app, Frame parent ) { applet = app; parentFrame = parent; docbase = applet.getCodeBase(); applet.db = db= new DatabaseAccess( this, parentFrame ); } //---------------------------------------- // 1手(+、−) //---------------------------------------- private void stepHistory( String step, boolean isforward ) { if( step == null ) return; StringTokenizer tk = new StringTokenizer( step ); int n = tk.countTokens(); if( n < 5 ) return; int x = Integer.parseInt( String.valueOf(tk.nextToken()) ); int y = Integer.parseInt( String.valueOf(tk.nextToken()) ); String ss = tk.nextToken(); String es = tk.nextToken(); int t = Integer.parseInt( String.valueOf(tk.nextToken()) ); String str = isforward ? es : ss; int v = 0; boolean h = false; try { h = str.charAt(0) == 't'; v = Integer.parseInt( String.valueOf( str.substring(1) ) ); } catch( StringIndexOutOfBoundsException e ) {} Cell oc = applet.playPanel.cell(); if( oc != null ) { applet.playPanel.canvas.paintCell( applet.playPanel.curX, applet.playPanel.curY, false ); } applet.playPanel.curX = x; applet.playPanel.curY = y; Cell c = applet.playPanel.table[x][y]; c.setValue( v, h ); applet.playPanel.canvas.paintCell( x, y, true ); applet.playPanel.canvas.paint( applet.playPanel.canvas.getGraphics() ); } //---------------------------------------- // 盤面の表示クリア //---------------------------------------- void clearBoard() { applet.playPanel.curX = -1; applet.playPanel.curY = -1; applet.playPanel.clearview(); } //---------------------------------------- // 1手進める //---------------------------------------- void forwardHistory( String s ) { stepHistory( s, true ); } //---------------------------------------- // 1手戻す //---------------------------------------- void backHistory( String s ) { stepHistory( s, false ); } } //================================================================================ // end of "CrossSum.java", by Hirofumi Fujiwara //================================================================================