import java.awt.*; import java.applet.*; //-------------------------------------------------- // ゲームクラス //-------------------------------------------------- class Game{ //-------------------------------------------------- // 定数 //-------------------------------------------------- // 固定小数の1の値(16=1) final static byte ONE = 0x10; // 固定小数シフト数 final static byte SHIFT = 4; // 横幅 int WIDTH = 3; // 高さ int HEIGHT = 4; // 一辺のサイズ(ピクセル) final byte G_SIZE = 16; // 空白フラグ final int eSPACE = 0; // 訪問フラグ final int eVISIT = 1; // キャラ移動速度 final int CHARA_SPEED = 0x40; // 履歴最大数 int HISTORY_MAX; //-------------------------------------------------- // メンバ変数 //-------------------------------------------------- // 盤 int m_map[][]; // クリアフラグ boolean m_clear_flag; // 訪問開始フラグ boolean m_visit_start_flag; // 自分のイメージ Image m_my_image; // 自分の位置 Point m_my = new Point(); // 自分の位置(固定小数) Point m_my_one = new Point(); // 目標地点 Point m_next_point = new Point(); // 目標地点(固定小数) Point m_next_point_one = new Point(); // 移動速度(x,y) int m_vx, m_vy; // 履歴 Point m_history[]; // 履歴ポイント int m_history_p; // 履歴ポイント(自動訪問用) int m_history_p_auto; // 履歴リスト List m_history_list = new List(); // 思考中 boolean think_flag; // ゴールフラグ boolean goal_flag; // 経路カウント long road_count; // 前回の方角 int prev_dir; // クリアしたか boolean IsClear(){ return m_clear_flag; } //-------------------------------------------------- // コンストラクタ //-------------------------------------------------- Game( int width, int height ){ // 横幅 WIDTH = width; // 高さ HEIGHT = height; m_map = new int[ WIDTH ][ HEIGHT ]; HISTORY_MAX = WIDTH * HEIGHT + 1; m_history = new Point[ HISTORY_MAX ]; Initialize(); } //-------------------------------------------------- // 初期化 //-------------------------------------------------- void Initialize(){ int x,y; int i; // 盤 for( x = 0; x < WIDTH; x++ ){ for( y = 0; y < HEIGHT; y++ ){ m_map[ x ][ y ] = eSPACE; } } // 自分 m_my.x = 0; m_my.y = 0; m_my_one.x = 0; m_my_one.y = 0; // 最初の場所は訪問済み DoneVisit( m_my ); // フラグ m_clear_flag = false; m_visit_start_flag = false; think_flag = false; goal_flag = false; // 履歴 for( i = 0; i < HISTORY_MAX; i++ ){ m_history[ i ] = new Point(); } m_history_p = 0; m_history_p_auto = 0; road_count = 0; prev_dir = 1; } //-------------------------------------------------- // 画像関係 //-------------------------------------------------- // 画像ロード void LoadImage( Applet applet, String file ){ m_my_image = applet.getImage( applet.getDocumentBase(), file ); } // イメージを返す Image GetImage(){ return m_my_image; } // 描画 void DrawImage( Graphics g, Applet applet ){ g.drawImage( m_my_image, m_my_one.x >> SHIFT, m_my_one.y >> SHIFT, applet ); // 履歴表示 //g.setColor( Color.black ); //for( int i=0; i < HISTORY_MAX; i++ ){ //g.drawString( "" + m_history[ i ].x + ", " + m_history[ i ].y , 20, (i+1)*10 ); //} // クリアしていたら文字表示 g.setColor( Color.black ); if( m_clear_flag ){ g.drawString( "クリア", 5, 20 ); } if( think_flag ){ g.drawString( "思考中", 5, 20 ); } } //-------------------------------------------------- // 盤を描画 //-------------------------------------------------- void DspMap( Graphics g ){ int x, y; Point next = new Point(); // 中身 for( x = 0; x < WIDTH; x++ ){ for( y = 0; y < HEIGHT; y++ ){ // 訪問済み if( m_map[ x ][ y ] == eVISIT ){ g.setColor( Color.yellow ); }else{ g.setColor( Color.white ); } g.fillRect( x * G_SIZE, y * G_SIZE, G_SIZE, G_SIZE ); } } // 枠線 g.setColor( Color.orange ); // 縦線 for( x = 0; x <= WIDTH; x++ ){ g.drawLine( x * G_SIZE, 0 ,x * G_SIZE , HEIGHT * G_SIZE ); } // 横線 for( y = 0; y <= HEIGHT; y++ ){ g.drawLine( 0, y * G_SIZE ,WIDTH * G_SIZE , y * G_SIZE ); } // ケイマの地点を太枠で囲む g.setColor( Color.blue ); // 現在地点からケイマへ(8箇所) next = AddPoint( m_my.x + 2, m_my.y + 1 ); IsSpaceDrawRect( g, next ); next = AddPoint( m_my.x - 2, m_my.y + 1 ); IsSpaceDrawRect( g, next ); next = AddPoint( m_my.x + 2, m_my.y - 1 ); IsSpaceDrawRect( g, next ); next = AddPoint( m_my.x - 2, m_my.y - 1 ); IsSpaceDrawRect( g, next ); next = AddPoint( m_my.x + 1, m_my.y + 2 ); IsSpaceDrawRect( g, next ); next = AddPoint( m_my.x - 1, m_my.y + 2 ); IsSpaceDrawRect( g, next ); next = AddPoint( m_my.x + 1, m_my.y - 2 ); IsSpaceDrawRect( g, next ); next = AddPoint( m_my.x - 1, m_my.y - 2 ); IsSpaceDrawRect( g, next ); } // 空白だったら描画 void IsSpaceDrawRect( Graphics g, Point next ){ if( IsSpace( next ) ) g.drawRect( next.x * G_SIZE, next.y * G_SIZE, G_SIZE, G_SIZE ); } //-------------------------------------------------- // ポイント加算 //-------------------------------------------------- Point AddPoint( int x, int y ){ Point point = new Point(); point.x = x; point.y = y; return point; } //-------------------------------------------------- // その場所は開いてるかチェック //-------------------------------------------------- boolean IsSpace( Point point ){ // 範囲は正しいか? if( point.x >= 0 && point.x < WIDTH && point.y >= 0 && point.y < HEIGHT ){ // 訪問できる場所か? // まずはその場所がスペース場所か? // 訪問可能 if( m_map[ point.x ][ point.y ] == eSPACE ){ return true; } // 訪問不可 else{ return false; } } return false; } //-------------------------------------------------- // 訪問可能か? //-------------------------------------------------- boolean IsVisit( Point point ){ Point next = new Point(); // まずはその場所がスペース場所か? // 訪問可能 if( m_map[ point.x ][ point.y ] == eSPACE ){ ; } // 訪問不可 else{ return false; } // 次に自分の位置からケイマの場所を調べる // 現在地点からケイマへ(8箇所) next = AddPoint( m_my.x + 2, m_my.y + 1 ); // その場所と等しい? if( next.equals( point ) )return true; next = AddPoint( m_my.x - 2, m_my.y + 1 ); if( next.equals( point ) )return true; next = AddPoint( m_my.x + 2, m_my.y - 1 ); if( next.equals( point ) )return true; next = AddPoint( m_my.x - 2, m_my.y - 1 ); if( next.equals( point ) )return true; next = AddPoint( m_my.x + 1, m_my.y + 2 ); if( next.equals( point ) )return true; next = AddPoint( m_my.x - 1, m_my.y + 2 ); if( next.equals( point ) )return true; next = AddPoint( m_my.x + 1, m_my.y - 2 ); if( next.equals( point ) )return true; next = AddPoint( m_my.x - 1, m_my.y - 2 ); if( next.equals( point ) )return true; // 全部無理 return false; } //-------------------------------------------------- // 訪問する //-------------------------------------------------- void DoneVisit( Point point ){ boolean flag; int x, y; // 座標チェック m_map[ point.x ][ point.y ] = eVISIT; // 自分の座標更新 m_my = point; m_my_one.x = ( m_my.x * G_SIZE ) << SHIFT; m_my_one.y = ( m_my.y * G_SIZE ) << SHIFT; // 全部塗りつぶせていたらクリア flag = true; for( x = 0; x < WIDTH; x++ ){ for( y = 0; y < HEIGHT; y++ ){ if( m_map[ x ][ y ] == eSPACE ){ flag = false; break; } } } m_clear_flag = flag; } //-------------------------------------------------- // クリックした場所を訪問する //-------------------------------------------------- void Clicked( Point click ){ Point point = new Point(); // 移動中ならスキップ if( m_visit_start_flag ) return; // 座標に変換 point.x = click.x / G_SIZE; point.y = click.y / G_SIZE; // 範囲は正しいか? if( point.x >= 0 && point.x < WIDTH && point.y >= 0 && point.y < HEIGHT ){ // 訪問できる場所か? if( IsVisit( point ) ){ // 訪問開始フラグ m_visit_start_flag = true; // 目標地点セット m_next_point = point; } } } //-------------------------------------------------- // 目標に向かって移動 //-------------------------------------------------- void ToMove(){ if( !m_visit_start_flag ) return; // 目標地点を固定小数に変換 m_next_point_one.x = (m_next_point.x * G_SIZE) << SHIFT; m_next_point_one.y = (m_next_point.y * G_SIZE) << SHIFT; // 移動量 double length = Math.sqrt( (m_next_point_one.x - m_my_one.x) * (m_next_point_one.x - m_my_one.x) + (m_next_point_one.y - m_my_one.y) * (m_next_point_one.y - m_my_one.y) ); if( length != 0.0 ){ m_vx = (int)( CHARA_SPEED * (m_next_point_one.x - m_my_one.x) / length ); m_vy = (int)( CHARA_SPEED * (m_next_point_one.y - m_my_one.y) / length ); } // 移動 m_my_one.x += m_vx; m_my_one.y += m_vy; // 目標との距離が縮まったら目標にピッタリ到着させてフラグオフ if( length <= CHARA_SPEED ){ m_visit_start_flag = false; // 訪問 DoneVisit( m_next_point ); } } //-------------------------------------------------- // 自動解答 //-------------------------------------------------- boolean Solve( Point start ){ int x, y; boolean flag; Point next = new Point(); // 現在地点を訪問 m_map[ start.x ][ start.y ] = eVISIT; // 履歴に追加 m_history[ m_history_p++ ] = start; if( goal_flag ){ return goal_flag; } //System.out.println("m_history_p="+m_history_p); // ゴール? flag = true; for( x = 0; x < WIDTH; x++ ){ for( y = 0; y < HEIGHT; y++ ){ if( m_map[ x ][ y ] == eSPACE ){ flag = false; break; } } } // ゴールしていたらtrueを if( flag ){ System.out.println("ゴールしたよ m_history_p="+m_history_p); System.out.println("["+road_count+"]通り調べました。"); for( int i = 0; i < HISTORY_MAX; i++ ){ System.out.println("("+m_history[i].x+", "+m_history[i].y+")" ); } goal_flag = true; return true; } // 現在地点からケイマへ(8箇所) // 南南西、南南東、東南東、東北東、北北東、北北西、西北西、西南西の順 // 前回の方角によって優先度を付ける。時計周りになるように。 if( prev_dir == 1 ){ next = AddPoint( start.x - 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 1; Solve( next ); } next = AddPoint( start.x + 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 2; Solve( next ); } next = AddPoint( start.x + 2, start.y + 1 ); // その場所が通行可能なら進む if( !goal_flag && IsSpace( next ) ){ prev_dir = 3; Solve( next ); } next = AddPoint( start.x + 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 4; Solve( next ); } next = AddPoint( start.x + 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 5; Solve( next ); } next = AddPoint( start.x - 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 6; Solve( next ); } next = AddPoint( start.x - 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 7; Solve( next ); } next = AddPoint( start.x - 2, start.y + 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 8; Solve( next ); } } // 前回の方角によって優先度を付ける。時計周りになるように。 else if( prev_dir == 2 ){ next = AddPoint( start.x - 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 1; Solve( next ); } next = AddPoint( start.x + 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 2; Solve( next ); } next = AddPoint( start.x + 2, start.y + 1 ); // その場所が通行可能なら進む if( !goal_flag && IsSpace( next ) ){ prev_dir = 3; Solve( next ); } next = AddPoint( start.x + 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 4; Solve( next ); } next = AddPoint( start.x + 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 5; Solve( next ); } next = AddPoint( start.x - 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 6; Solve( next ); } next = AddPoint( start.x - 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 7; Solve( next ); } next = AddPoint( start.x - 2, start.y + 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 8; Solve( next ); } } // 前回の方角によって優先度を付ける。時計周りになるように。 else if( prev_dir == 3 ){ next = AddPoint( start.x + 2, start.y + 1 ); // その場所が通行可能なら進む if( !goal_flag && IsSpace( next ) ){ prev_dir = 3; Solve( next ); } next = AddPoint( start.x + 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 4; Solve( next ); } next = AddPoint( start.x + 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 5; Solve( next ); } next = AddPoint( start.x - 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 6; Solve( next ); } next = AddPoint( start.x - 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 7; Solve( next ); } next = AddPoint( start.x - 2, start.y + 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 8; Solve( next ); } next = AddPoint( start.x - 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 1; Solve( next ); } next = AddPoint( start.x + 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 2; Solve( next ); } } // 前回の方角によって優先度を付ける。時計周りになるように。 else if( prev_dir == 4 ){ next = AddPoint( start.x + 2, start.y + 1 ); // その場所が通行可能なら進む if( !goal_flag && IsSpace( next ) ){ prev_dir = 3; Solve( next ); } next = AddPoint( start.x + 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 4; Solve( next ); } next = AddPoint( start.x + 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 5; Solve( next ); } next = AddPoint( start.x - 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 6; Solve( next ); } next = AddPoint( start.x - 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 7; Solve( next ); } next = AddPoint( start.x - 2, start.y + 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 8; Solve( next ); } next = AddPoint( start.x - 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 1; Solve( next ); } next = AddPoint( start.x + 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 2; Solve( next ); } } // 前回の方角によって優先度を付ける。時計周りになるように。 else if( prev_dir == 5 ){ next = AddPoint( start.x + 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 5; Solve( next ); } next = AddPoint( start.x - 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 6; Solve( next ); } next = AddPoint( start.x - 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 7; Solve( next ); } next = AddPoint( start.x - 2, start.y + 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 8; Solve( next ); } next = AddPoint( start.x - 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 1; Solve( next ); } next = AddPoint( start.x + 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 2; Solve( next ); } next = AddPoint( start.x + 2, start.y + 1 ); // その場所が通行可能なら進む if( !goal_flag && IsSpace( next ) ){ prev_dir = 3; Solve( next ); } next = AddPoint( start.x + 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 4; Solve( next ); } } // 前回の方角によって優先度を付ける。時計周りになるように。 else if( prev_dir == 6 ){ next = AddPoint( start.x + 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 5; Solve( next ); } next = AddPoint( start.x - 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 6; Solve( next ); } next = AddPoint( start.x - 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 7; Solve( next ); } next = AddPoint( start.x - 2, start.y + 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 8; Solve( next ); } next = AddPoint( start.x - 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 1; Solve( next ); } next = AddPoint( start.x + 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 2; Solve( next ); } next = AddPoint( start.x + 2, start.y + 1 ); // その場所が通行可能なら進む if( !goal_flag && IsSpace( next ) ){ prev_dir = 3; Solve( next ); } next = AddPoint( start.x + 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 4; Solve( next ); } } // 前回の方角によって優先度を付ける。時計周りになるように。 else if( prev_dir == 7 ){ next = AddPoint( start.x - 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 7; Solve( next ); } next = AddPoint( start.x - 2, start.y + 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 8; Solve( next ); } next = AddPoint( start.x - 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 1; Solve( next ); } next = AddPoint( start.x + 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 2; Solve( next ); } next = AddPoint( start.x + 2, start.y + 1 ); // その場所が通行可能なら進む if( !goal_flag && IsSpace( next ) ){ prev_dir = 3; Solve( next ); } next = AddPoint( start.x + 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 4; Solve( next ); } next = AddPoint( start.x + 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 5; Solve( next ); } next = AddPoint( start.x - 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 6; Solve( next ); } } // 前回の方角によって優先度を付ける。時計周りになるように。 else if( prev_dir == 8 ){ next = AddPoint( start.x - 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 7; Solve( next ); } next = AddPoint( start.x - 2, start.y + 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 8; Solve( next ); } next = AddPoint( start.x - 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 1; Solve( next ); } next = AddPoint( start.x + 1, start.y + 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 2; Solve( next ); } next = AddPoint( start.x + 2, start.y + 1 ); // その場所が通行可能なら進む if( !goal_flag && IsSpace( next ) ){ prev_dir = 3; Solve( next ); } next = AddPoint( start.x + 2, start.y - 1 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 4; Solve( next ); } next = AddPoint( start.x + 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 5; Solve( next ); } next = AddPoint( start.x - 1, start.y - 2 ); if( !goal_flag && IsSpace( next ) ){ prev_dir = 6; Solve( next ); } } // 全部無理なら一つ前に戻る if( !goal_flag ){ m_map[ start.x ][ start.y ] = eSPACE; //System.out.println("["+m_history_p+"] map["+start.x+", "+start.y+"]は無理ぽ"); m_history_p--; } // カウント road_count++; if( road_count % 1000000 == 0 ){ System.out.println("["+road_count+"]通り調べました。"); } return goal_flag; } //-------------------------------------------------- // 履歴通り進行 //-------------------------------------------------- void AutoMoveByHistory(){ if( goal_flag && m_history_p > 0 && m_history_p >= m_history_p_auto ){ HistoryMove( m_history[ m_history_p_auto ] ); } } //-------------------------------------------------- // 盤のクリア //-------------------------------------------------- void ClearMap(){ int x, y; // 盤 for( x = 0; x < WIDTH; x++ ){ for( y = 0; y < HEIGHT; y++ ){ m_map[ x ][ y ] = eSPACE; } } // 最初の場所は訪問済み DoneVisit( m_my ); m_history_p_auto = 0; } //-------------------------------------------------- // そのポイントを訪問する //-------------------------------------------------- void HistoryMove( Point point ){ // 移動中ならスキップ if( m_visit_start_flag ) return; // 範囲は正しいか? if( point.x >= 0 && point.x < WIDTH && point.y >= 0 && point.y < HEIGHT ){ // 訪問できる場所か? if( IsVisit( point ) ){ // 訪問開始フラグ m_visit_start_flag = true; // 目標地点セット m_next_point = point; } } m_history_p_auto++; } }