// // // import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.lang.Math; import java.util.Date; public class Fifteen extends Applet implements Runnable { Thread mixThread = null; Thread timerThread = null; Date startTime; Date finishTime; byte field[][] = new byte[4][4]; Button buttons[] = new Button[15]; Button mixButton; Label numMoves; Button initButton; Label time; Label congratulations; int nMoves = 0; int holeX = 3; int holeY = 3; final int DX = 50; final int DY = 50; final int topSkip = 70; final int topMargin = 5; final int leftMargin = 5; final int MIX_DEPTH = 1000; final int MIX_DELAY = 333; boolean mixing = false; boolean solved = false; /*... public static void main(String args[]) { Frame f = new Frame("15"); Fifteen fifteen = new Fifteen(); class MyWindowAdapter extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } }; f.addWindowListener(new MyWindowAdapter()); f.add("Center", fifteen); fifteen.init(); fifteen.start(); f.pack(); f.setVisible(true); } ...*/ public void init() { int x, y; System.out.println("init()."); resize(210, 330); setLayout(null); setFont(new Font("Helvetica", Font.PLAIN, 14)); setBackground(Color.lightGray); mixButton = new Button("Mix"); Label l = new Label("Moves: "); numMoves = new Label("0"); initButton = new Button("Initialize"); Label t = new Label("Time: "); time = new Label("Time: "); congratulations = new Label(""); nMoves = 0; add(mixButton); add(initButton); add(l); add(numMoves); add(t); add(time); add(congratulations); // Make shape of buttons mixButton.reshape(leftMargin, topMargin, 2*DX - 5, 30); initButton.reshape(leftMargin + 2*DX, topMargin, 2*DX, 30); l.reshape(leftMargin, topMargin + 35, DX, 30); numMoves.reshape(leftMargin + DX + 5, topMargin + 35, DX - 5, 30); t.reshape(leftMargin + 2*DX, topMargin + 35, DX - 5, 30); time.reshape(leftMargin + 3*DX, topMargin + 35, DX, 30); congratulations.reshape( leftMargin, topMargin + topSkip + 5 + 4 * DY, 260, 30 ); congratulations.setForeground(Color.blue); Font buttonFont = new Font("Helvetica", Font.BOLD, 24); for (y = 0; y < 4; y++) { for (x = 0; x < 4; x++) { int k = y*4 + x; if (k >= 15) break; field[x][y] = (byte)k; buttons[k] = new Button("" + (k+1)); add(buttons[k]); buttons[k].reshape( x*DX + leftMargin, y*DY + topSkip, DX, DY ); buttons[k].setFont(buttonFont); buttons[k].setForeground(Color.red); } } holeX = 3; holeY = 3; field[holeX][holeY] = (byte)(-1); } public boolean action(Event e, Object arg) { Object target = e.target; if (target == mixButton) { mix(); } else if (target == initButton) { initialize(); } else { Loop: for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { int b = field[x][y]; if (b >= 0 && buttons[b] == target) { makeMove(x, y); buttons[b].requestFocus(); break Loop; } } } } return false; } public synchronized void makeMove(int x, int y) { // System.out.println("makeMove: " + x + ", " + y); int k = field[x][y]; if (k < 0) return; Button b = buttons[k]; int xnew = (-1), ynew = y; if (x-1 >= 0 && field[x-1][y] == (-1)) { xnew = x-1; ynew = y; } if (x+1 < 4 && field[x+1][y] == (-1)) { xnew = x+1; ynew = y; } if (y-1 >= 0 && field[x][y-1] == (-1)) { xnew = x; ynew = y-1; } if (y+1 < 4 && field[x][y+1] == (-1)) { xnew = x; ynew = y+1; } if (xnew >= 0) { b.move( xnew*DX + leftMargin, ynew*DY + topSkip ); field[x][y] = (byte)(-1); field[xnew][ynew] = (byte)k; holeX = x; holeY = y; } if (!mixing) { boolean finished = check(); if (xnew >= 0 && !solved) { nMoves++; numMoves.setText("" + nMoves); } if (!solved && finished) { solved = true; congratulations.setForeground(Color.red); congratulations.setText("Solved, congratulations!!!"); } else if (solved && !finished) { congratulations.setForeground(Color.blue); congratulations.setText("Press \"Mix\", please..."); } else if (!solved) { congratulations.setForeground(Color.blue); congratulations.setText("Can you solve the riddle?"); } } } public synchronized void mix() { if (mixing) { System.out.println("Stop button is pressed."); mixing = false; try { wait(); // Wait until the end of mixing thread } catch (InterruptedException e) { System.out.println(e.toString()); } solved = false; startTime = new Date(); if (timerThread == null) { System.out.println("Creating timer thread."); timerThread = new Thread(this, "Timer thread"); timerThread.start(); } } else if (mixThread == null) { System.out.println("Mix button is pressed."); System.out.println("Creating mixing thread."); mixing = true; mixButton.setLabel("Stop"); mixThread = new Thread(this, "Mixing"); mixThread.start(); } } public synchronized void initialize() { int x, y; System.out.println("Initialize button is pressed."); if (mixing) { mixing = false; try { wait(); // Wait until the end of mixing thread } catch (InterruptedException e) { System.out.println(e.toString()); } } for (y = 0; y < 4; y++) { for (x = 0; x < 4; x++) { int k = y*4 + x; if (k >= 15) break; field[x][y] = (byte)k; buttons[k].move( x*DX + leftMargin, y*DY + topSkip ); } } holeX = 3; holeY = 3; field[holeX][holeY] = (byte)(-1); nMoves = 0; numMoves.setText("" + nMoves); // mixButton.requestFocus(); congratulations.setForeground(Color.blue); congratulations.setText("Press \"Mix\", please..."); } public void run() { Thread current = Thread.currentThread(); if (current == mixThread) { mixRun(); } else if (current == timerThread) { startTime = new Date(); timerRun(); } } public void mixRun() { // Mixing thread System.out.println("Starting mixing thread."); nMoves = 0; numMoves.setText("" + nMoves); congratulations.setForeground(Color.blue); congratulations.setText("Mixing... \"Stop\" to terminate"); time.setText("0"); int prevDir = (-1); for (int i = 0; mixing && i < MIX_DEPTH; i++) { int newx = holeX; int newy = holeY; // Direction of move: 0 - right, 1 - up, 2 - left, 3 - down int dir = (int)(Math.random() * 4. - 0.001); if (dir == (prevDir + 2) % 4) dir = (dir + 1) % 4; if (dir == 0) { // right if (holeX < 3) { newx = holeX + 1; } else { dir++; } } if (dir == 1) { // Up if (holeY > 0) { newy = holeY - 1; } else { dir++; } } if (dir == 2) { // Left if (holeX > 0) { newx = holeX - 1; } else { dir++; } } if (dir == 3) { // Down if (holeY < 3) { newy = holeY + 1; } else if (holeX < 3) { // Right newx = holeX + 1; dir = 0; } } if (newx != holeX || newy != holeY) { makeMove(newx, newy); prevDir = dir; } // Delay try { mixThread.sleep(MIX_DELAY); } catch(InterruptedException e) { System.out.println(e.toString()); } } synchronized (this) { mixing = false; mixButton.setLabel("Mix"); congratulations.setForeground(Color.blue); congratulations.setText("Try to solve the it!"); notify(); } mixThread = null; System.out.println("Mixing thread finished."); } public void timerRun() { System.out.println("Starting timer thread."); while (!mixing && !solved && timerThread != null) { try { timerThread.sleep(1000); } catch (InterruptedException e) { System.out.println(e.toString()); } finishTime = new Date(); long t = (finishTime.getTime() - startTime.getTime()) / 1000; time.setText("" + t); } timerThread = null; System.out.println("Timer thread finished."); } public void start() { System.out.println("start()."); initialize(); mix(); } public void stop() { System.out.println("stop()."); mixing = false; timerThread = null; mixButton.setLabel("Mix"); } public boolean check() { // Check whether the riddle is solved boolean res = true; for (int x = 0; res && x < 4; x++) { for (int y = 0; res && y < 4; y++) { if (x == 3 && y == 3) { res = (res && (int) field[3][3] == (-1)); } else { int k = y*4 + x; res = (res && (int) field[x][y] == k); } } } return res; } }