ええ、最初に断っておきますが(笑)、以下のソースは、たとえ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;
}
}
}
}
ソースコードは以上です。
識者からのご指摘をお待ち致しております。(笑)