ええ、最初に断っておきますが(笑)、以下のソースは、たとえJavaが初めてだったとしても、 他のプログラミング言語をやっていた人間からすれば、ちょっと汚いソースになっています。^^; 数値はそのまんま使ってるし…。 とりあえず、さっさと形にしたかったので、そういうところあたりまで気を配りませんでした。 この点を最初に言い訳しときます。(笑)
あと、今回はJava解説書にあるアプレットの作り方を、そのまんままねている箇所が結構あります。 具体的には、実際のプログラムの中身と関係ない箇所ですが。 Javaを既に使っている方々から見ると、「なんでここにこんな無駄な記述が?」と思われる点が多くあると思います。 それは本をそのまま写したからなんですが(笑)。 もしそういう箇所があったら、ぜひ教えて下さい(^^;)。 私の知りたいのはそこです(^^;)。
ちなみに、ゲームそのもののアルゴリズムは、100%私が考えて書いたものです。 そこは、本を写したわけじゃないです(^^;)。 そりゃそーだよな。^^;
では、ソースコードです。
package applettest; import java.awt.*; import java.awt.event.*; import java.applet.*; import javax.swing.*; public class Applet1 extends JApplet implements Runnable { boolean isStandalone = false; String csign; // 画像配列 Image blocks[] = new Image[19]; // (画像読み込み用) Image panels[] = new Image[16]; // (画面描画用) // ブロック値記憶用配列 int panelnums[] = new int[16]; // 描画位置変数 int dx=0, dy=0, dh=50, dw=50; int MouseOnX=0,MouseOnY=0; int EmptyPointX,EmptyPointY; int margin=10; // ステップ数記憶用 int clicktime=0; // 新しい色の作成 Color darkYellow = new Color(204,204,0); Color lightYellow = new Color(255,255,204); Color darkBlue = new Color(0,0,204); Color lightGray = new Color(204,204,204); // ゲーム状態フラグ boolean gameclear = false; // 描画用コンポーネント JComponent jcWnd; // 並行処理用スレッド Thread thread; // スレッド動作を許可するかどうか boolean isRunnable = true; // ランダムに並べる(16個のブロックを4×4の配列にランダムに配置する) void distblocks() { // 各ブロックの状態記憶用配列(重複不可だから要る) boolean randwork[] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false}; // 16個 int getonenum; int loopr=0; while( loopr<16 ) { // 0〜15までの値を0番〜15番までのブロックにランダムに配置(重複不可) getonenum = (int)(Math.random()*100 % 16.0); // 0〜15の間の整数をランダムに抽出 if( randwork[getonenum] == false ) { // その番号がまだ使われていなければ使用 panelnums[loopr] = getonenum; // 内部用配列に数値を代入 randwork[getonenum] = true; // その番号が使用済みであるフラグを立てる // その番号が15だった場合(※15=空枠) if( getonenum == 15 ) { // EmptyPoint(空枠の場所)の設定 EmptyPointX = loopr % 4; EmptyPointY = loopr / 4; } // 代入回数を記録 loopr++; } } // ランダムに並べた結果を描画用Imageに代入 for( int i=0 ; i<16 ; i++ ) { panels[i] = blocks[panelnums[i]]; } } //引数値の取得 public String getParameter(String key, String def) { return isStandalone ? System.getProperty(key, def) : (getParameter(key) != null ? getParameter(key) : def); } //アプレットの構築 public Applet1() { } //アプレットの初期化 public void init() { try { jbInit(); } catch(Exception e) { e.printStackTrace(); } } //コンポーネントの初期化 private void jbInit() throws Exception { this.setSize(new Dimension(405,240)); this.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(MouseEvent e) { this_mouseClicked(e); } }); this.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() { public void mouseMoved(MouseEvent e) { this_mouseMoved(e); } }); // 画像の読み込み blocks[0] = getImage(getCodeBase(),"15blocks-01.gif"); blocks[1] = getImage(getCodeBase(),"15blocks-02.gif"); blocks[2] = getImage(getCodeBase(),"15blocks-03.gif"); blocks[3] = getImage(getCodeBase(),"15blocks-04.gif"); blocks[4] = getImage(getCodeBase(),"15blocks-05.gif"); blocks[5] = getImage(getCodeBase(),"15blocks-06.gif"); blocks[6] = getImage(getCodeBase(),"15blocks-07.gif"); blocks[7] = getImage(getCodeBase(),"15blocks-08.gif"); blocks[8] = getImage(getCodeBase(),"15blocks-09.gif"); blocks[9] = getImage(getCodeBase(),"15blocks-10.gif"); blocks[10]= getImage(getCodeBase(),"15blocks-11.gif"); blocks[11]= getImage(getCodeBase(),"15blocks-12.gif"); blocks[12]= getImage(getCodeBase(),"15blocks-13.gif"); blocks[13]= getImage(getCodeBase(),"15blocks-14.gif"); blocks[14]= getImage(getCodeBase(),"15blocks-15.gif"); blocks[15]= getImage(getCodeBase(),"15blocks-Empty.gif"); blocks[16]= getImage(getCodeBase(),"15blocks-Excellent.gif"); blocks[17]= getImage(getCodeBase(),"15blocks-Good.gif"); blocks[18]= getImage(getCodeBase(),"15blocks-Loose.gif"); // ランダムに並べる distblocks(); // 描画用コンポーネントの追加 getContentPane().add(jcWnd = new JComponent() { public void paint(Graphics gra) { // 画像の読み込みがまだなら描画しない if( blocks[15] == null ) return; // ブロックを描画 int loop; for( loop=0 ; loop<16 ; loop++ ) { gra.drawImage(panels[loop],dx+margin,dy+margin,this); dx+=50; if( dx>=200 ) { dx-=200; dy+=50; } } // コントロールボタンの表示 // Draw Buttons // "GIVE UP" Button gra.setColor(lightGray); gra.fillRect(231,101,98,25); gra.setColor(Color.white); gra.drawLine(230,100,330,100); gra.drawLine(230,100,230,127); gra.setColor(Color.gray); gra.drawLine(230,127,330,127); gra.drawLine(330,100,330,127); // "OTHER GAME" Button gra.setColor(lightGray); gra.fillRect(231,151,148,25); gra.setColor(Color.white); gra.drawLine(230,150,330,150); gra.drawLine(230,150,230,177); gra.setColor(Color.gray); gra.drawLine(230,177,330,177); gra.drawLine(330,150,330,177); // Write Captions gra.setColor(Color.black); Font font = new Font("Arial",Font.PLAIN,16); gra.setFont(font); gra.drawString("GIVE UP",250,120); gra.drawString("SHUFFLE",245,170); // マウス追跡枠と移動方向指示矢印を描画 if( MouseOnY < 4 && MouseOnX < 4 ) { // マウスがゲーム枠外でないなら if( MouseOnX != EmptyPointX || MouseOnY != EmptyPointY ) { // そのポイントが空でもなく if( MouseOnX == EmptyPointX || MouseOnY == EmptyPointY ) { // 空枠と同じ行または列にあれば、移動可能色を設定して gra.setColor(Color.yellow); } else { // 空枠とは異なる行または列にあれば、移動不可能色を設定して gra.setColor(darkYellow); } // マウス追跡枠を描画 gra.drawRect(margin+MouseOnX*50,margin+MouseOnY*50,50,50); gra.drawRect(margin+MouseOnX*50+1,margin+MouseOnY*50+1,48,48); gra.drawRect(margin+MouseOnX*50-1,margin+MouseOnY*50-1,52,52); // 移動可能矢印の描画処理 if( MouseOnX == EmptyPointX || MouseOnY == EmptyPointY ) { // 三角形描画のための差分値指定用配列を確保 int rectdiffX[] = new int[3]; int rectdiffY[] = new int[3]; // X座標が一致(=縦方向に移動可能)なら if( MouseOnX == EmptyPointX ) { if( MouseOnY < EmptyPointY ) { // 空枠より上にあるなら、下方向への移動可能指示を描画するよう指定して rectdiffX[0] = 15; rectdiffX[1] = 25; rectdiffX[2] = 35; rectdiffY[0] = 55; rectdiffY[1] = 65; rectdiffY[2] = 55; } else if( MouseOnY > EmptyPointY ) { // 空枠より下にあるなら、上方向への移動可能指示を描画するよう指定して rectdiffX[0] = 15; rectdiffX[1] = 25; rectdiffX[2] = 35; rectdiffY[0] = -5; rectdiffY[1] = -15; rectdiffY[2] = -5; } } // Y座標が一致(=横方向に移動可能)なら if( MouseOnY == EmptyPointY ) { // 移動可能矢印の描画 if( MouseOnX < EmptyPointX ) { // 空枠より左にあるなら、右方向への移動可能指示を描画するよう指定して rectdiffX[0] = 55; rectdiffX[1] = 65; rectdiffX[2] = 55; rectdiffY[0] = 15; rectdiffY[1] = 25; rectdiffY[2] = 35; } else if( MouseOnX > EmptyPointX ) { // 空枠より右にあるなら、左方向への移動可能指示を描画するよう指定して rectdiffX[0] = -5; rectdiffX[1] = -15; rectdiffX[2] = -5; rectdiffY[0] = 15; rectdiffY[1] = 25; rectdiffY[2] = 35; } } // 移動可能矢印を描画 int rectX[] = { margin+MouseOnX*50+rectdiffX[0] , margin+MouseOnX*50+rectdiffX[1] , margin+MouseOnX*50+rectdiffX[2] }; int rectY[] = { margin+MouseOnY*50+rectdiffY[0] , margin+MouseOnY*50+rectdiffY[1] , margin+MouseOnY*50+rectdiffY[2] }; gra.fillPolygon(rectX,rectY,3); } } } else if( ( MouseOnY == 14 || MouseOnY == 16 ) && MouseOnX == 12 ) { // コントロールボタンエリア内なら // ボタンのマウス追跡枠を描画 gra.setColor(Color.yellow); gra.drawRect((MouseOnX-10)*100+30,(MouseOnY-10)*25,100,26); gra.drawRect((MouseOnX-10)*100+30+1,(MouseOnY-10)*25+1,98,24); gra.drawRect((MouseOnX-10)*100+30-1,(MouseOnY-10)*25-1,102,28); } // ステップレポートの表示 // Background gra.setColor(darkBlue); gra.fillRoundRect(233,18,150,50,10,10); gra.setColor(lightYellow); gra.fillRoundRect(230,15,150,50,10,10); gra.setColor(Color.blue); gra.drawRoundRect(230,15,150,50,10,10); // Foreground(Fixed Strings and Lines) gra.setColor(darkBlue); font = new Font("Arial",Font.PLAIN,12); gra.setFont(font); gra.drawString("STEPS",240,30); gra.drawLine(238,32,372,32); // Foreground(STEP INFO) gra.setColor(Color.black); font = new Font("Arial",Font.PLAIN,20); gra.setFont(font); String StepReport = clicktime + " steps."; gra.drawString(StepReport,270,60); } } ); } // アプレットの動作開始 public void start() { // 停止中なら if( thread == null ) { // スレッドを生成する thread = new Thread(this); // 実行を許可する isRunnable = true; // 動作を開始する thread.start(); } } // アプレットの動作停止 public void stop() { // 動作中なら if( thread != null ) { // 実行を禁止する isRunnable = false; } } // スレッドの処理 public void run() { // 実行が許可されている間繰り返す while(isRunnable) { int loop=0; dx+= 0; dy=0; // 再描画 jcWnd.repaint(0,0,400,margin*2+200); // 時間待ち try { Thread.sleep(50); } catch(InterruptedException ie) { // 中断されたら繰り返しから抜ける break; } loop++; if( loop >= 10 ) { break; } } // スレッドを破棄する thread = null; } //アプレットの情報取得 public String getAppletInfo() { return "Applet Information"; } //引数情報の取得 public String[][] getParameterInfo() { String[][] pinfo = { {"ClearSign", "String", ""}, }; return pinfo; } //ルック&フィールの設定 static { try { //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); //UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); } catch(Exception e) { } } // マウスの動きを監視 void this_mouseMoved(MouseEvent e) { if( (e.getX()<=200+margin) && (e.getY()<=200+margin) ) { // もしゲームフィールド内なら(※X,Yにブロックの位置を格納/1ブロック50×50だから) MouseOnX = (e.getX()-margin)/50; MouseOnY = (e.getY()-margin)/50; } else { // それ以外の領域なら(※10加えているのは単に判定用数値を2桁にしたかったから/BOX単位100×25) MouseOnX = 10 + (e.getX()-30)/100; MouseOnY = 10 + e.getY()/25; } } // マウスのクリックを監視 void this_mouseClicked(MouseEvent e) { // 移動可能であるかを判定 if( MouseOnY < 4 && MouseOnX < 4 ) { // マウスがゲーム枠外でないなら if( MouseOnX != EmptyPointX || MouseOnY != EmptyPointY ) { // そのポイントが空でもなく if( MouseOnX == EmptyPointX || MouseOnY == EmptyPointY ) { // 空枠と同じ行または列にあれば、移動可能である。 // 移動回数を記録 clicktime++; // クリックされた位置の番号を計算 int clickpoint = MouseOnX + MouseOnY*4; // 空枠の位置の番号を計算 int emptypoint = EmptyPointX + EmptyPointY*4; if( MouseOnX == EmptyPointX ) { // X座標が一致(=縦方向に移動可能)なら if( MouseOnY < EmptyPointY ) { // 空枠より上にあるなら下方向へ移動 if( EmptyPointY - MouseOnY >= 1 ) { panels[emptypoint] = panels[emptypoint-4]; panelnums[emptypoint] = panelnums[emptypoint-4];} if( EmptyPointY - MouseOnY >= 2 ) { panels[emptypoint-4] = panels[emptypoint-8]; panelnums[emptypoint-4] = panelnums[emptypoint-8];} if( EmptyPointY - MouseOnY >= 3 ) { panels[emptypoint-8] = panels[emptypoint-12]; panelnums[emptypoint-8] = panelnums[emptypoint-12];} panels[clickpoint] = blocks[15]; panelnums[clickpoint] = 15; } else if( MouseOnY > EmptyPointY ) { // 空枠より下にあるなら上方向へ移動 if( MouseOnY - EmptyPointY >= 1 ) { panels[emptypoint] = panels[emptypoint+4]; panelnums[emptypoint] = panelnums[emptypoint+4];} if( MouseOnY - EmptyPointY >= 2 ) { panels[emptypoint+4] = panels[emptypoint+8]; panelnums[emptypoint+4] = panelnums[emptypoint+8];} if( MouseOnY - EmptyPointY >= 3 ) { panels[emptypoint+8] = panels[emptypoint+12]; panelnums[emptypoint+8] = panelnums[emptypoint+12];} panels[clickpoint] = blocks[15]; panelnums[clickpoint] = 15; } } if( MouseOnY == EmptyPointY ) { // Y座標が一致(=横方向に移動可能)なら if( MouseOnX < EmptyPointX ) { // 空枠より左にあるなら右方向へ移動 if( EmptyPointX - MouseOnX >= 1 ) { panels[emptypoint] = panels[emptypoint-1]; panelnums[emptypoint] = panelnums[emptypoint-1];} if( EmptyPointX - MouseOnX >= 2 ) { panels[emptypoint-1] = panels[emptypoint-2]; panelnums[emptypoint-1] = panelnums[emptypoint-2];} if( EmptyPointX - MouseOnX >= 3 ) { panels[emptypoint-2] = panels[emptypoint-3]; panelnums[emptypoint-2] = panelnums[emptypoint-3];} panels[clickpoint] = blocks[15]; panelnums[clickpoint] = 15; } else if( MouseOnX > EmptyPointX ) { // 空枠より右にあるなら左方向へ移動 if( MouseOnX - EmptyPointX >= 1 ) { panels[emptypoint] = panels[emptypoint+1]; panelnums[emptypoint] = panelnums[emptypoint+1];} if( MouseOnX - EmptyPointX >= 2 ) { panels[emptypoint+1] = panels[emptypoint+2]; panelnums[emptypoint+1] = panelnums[emptypoint+2];} if( MouseOnX - EmptyPointX >= 3 ) { panels[emptypoint+2] = panels[emptypoint+3]; panelnums[emptypoint+2] = panelnums[emptypoint+3];} panels[clickpoint] = blocks[15]; panelnums[clickpoint] = 15; } } // EMPTY POINT の座標を再設定 EmptyPointX = MouseOnX; EmptyPointY = MouseOnY; // 再描画(STEP REPORT部分だけを再描画) jcWnd.repaint(230,15,150,50); } } } else if( MouseOnY == 16 && MouseOnX == 12 ) { // シャッフルボタン distblocks(); clicktime=0; gameclear = false; } else if( MouseOnY == 14 && MouseOnX == 12 ) { // GIVEUPボタン // EmptyPointにLoose顔アイコンを挿入 panels[EmptyPointX + EmptyPointY*4] = blocks[18]; } // 終了判定 // 空枠が端でなければ終了ではないので判定処理を行わない if( panelnums[0]==15 || panelnums[3]==15 || panelnums[12]==15 || panelnums[15]==15 ) { // 空枠が端なら判定を行う int ra = panelnums[0] + panelnums[1] + panelnums[2] + panelnums[3]; int rb = panelnums[4] + panelnums[5] + panelnums[6] + panelnums[7]; int rc = panelnums[8] + panelnums[9] + panelnums[10] + panelnums[11]; int rd = panelnums[12] + panelnums[13] + panelnums[14] + panelnums[15]; int re = panelnums[0] + panelnums[4] + panelnums[8] + panelnums[12]; int rf = panelnums[1] + panelnums[5] + panelnums[9] + panelnums[13]; int rg = panelnums[2] + panelnums[6] + panelnums[10] + panelnums[14]; int rh = panelnums[3] + panelnums[7] + panelnums[11] + panelnums[15]; // 判定 int A=6, B=22, C=38, D=54, E=24, F=28, G=32, H=36; if( ra==A && rb==B && rc==C && rd==D && re==E && rf==F && rg==G && rh==H ) { gameclear=true; } if( ra==E && rb==F && rc==G && rd==H && re==D && rf==C && rg==B && rh==A ) { gameclear=true; } if( ra==D && rb==C && rc==B && rd==A && re==H && rf==G && rg==F && rh==E ) { gameclear=true; } if( ra==H && rb==G && rc==F && rd==E && re==A && rf==B && rg==C && rh==D ) { gameclear=true; } if( ra==E && rb==F && rc==G && rd==H && re==A && rf==B && rg==C && rh==D ) { gameclear=true; } if( ra==A && rb==B && rc==C && rd==D && re==H && rf==G && rg==F && rh==E ) { gameclear=true; } if( ra==H && rb==G && rc==F && rd==E && re==D && rf==C && rg==B && rh==A ) { gameclear=true; } if( ra==D && rb==C && rc==B && rd==A && re==E && rf==F && rg==G && rh==H ) { gameclear=true; } // 終了なら顔マークを付加 if( gameclear == true ) { // EmptyPoubtに顔マークを挿入 panels[EmptyPointX + EmptyPointY*4] = blocks[16]; // その後の移動(操作)のことを考えて、フラグはすぐに下げる gameclear = false; } } } }
ソースコードは以上です。
識者からのご指摘をお待ち致しております。(笑)