/* Copyright (C) 2002 J. M. Spivey */ import java.awt.*; import java.awt.event.*; /** GUI class for the Lights Out board. * * The board responds to mouse clicks by making moves in the game. */ public class LightsBoard extends Canvas { private int mode = PLAY; public static final int PLAY = 1, SETUP = 2; private Label messageLabel; private int count[][] = new int[5][5]; private int hint[][] = new int[5][5]; private boolean sflag = false; private int i0, j0; public LightsBoard(Label messageLabel) { this.messageLabel = messageLabel; setBackground(Color.lightGray); this.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { click(e.getX(), e.getY(), true); } public void mouseReleased(MouseEvent e) { click(e.getX(), e.getY(), false); } }); setRandom(5); } /** Respond to a mouse click */ private void click(int x, int y, boolean down) { message(""); // Compute which square the click is in int i = x / u, j = y / u; // Return if we are not actually inside the square if (! (x >= i*u+d && x < (i+1)*u-d && y >= j*u+d && y < (j+1)*u-d)) return; if (down) { // Record where the mouse button goes down i0 = i; j0 = j; } else { // Perform action if the button comes up in the same square if (i == i0 && j == j0) { if (mode == PLAY) toggle(i, j, -1); else { sflag = false; increment(i, j, 1); } repaint(); } i0 = j0 = -1; } } /** Display a message in the message area */ private void message(String text) { if (messageLabel != null) messageLabel.setText(text); } /** Set the mode to PLAY or SETUP */ public void setMode(int mode) { this.mode = mode; } /** Increment a specified square */ private void increment(int i, int j, int inc) { if (i < 0 || i >= 5 || j < 0 || j >= 5) return; count[i][j] = (count[i][j] + inc + 3) % 3; } /** Carry out a move in a specified square */ private void toggle(int i, int j, int inc) { increment(i, j, inc); increment(i+1, j, inc); increment(i, j+1, inc); increment(i-1, j, inc); increment(i, j-1, inc); // Update the hint if the solution is being shown if (sflag) hint[i][j] = (hint[i][j] - 1 + 3) % 3; } /** Choose a random integer from 1 to n-1 */ private static int randChoice(int n) { return (int) (n * Math.random()); } /** Set up n random moves */ public void setRandom(int n) { setBlank(); for (int k = 0; k < n; k++) toggle(randChoice(5), randChoice(5), 1); } /** Blank out the board */ public void setBlank() { for (int i = 0; i < 5; i++) for (int j = 0; j < 5; j++) count[i][j] = 0; message(""); sflag = false; repaint(); } /** Compute and display the solution */ public void showSolution() { int y[] = new int[25]; for (int i = 0; i < 5; i++) for (int j = 0; j < 5; j++) y[5*i+j] = count[i][j]; int x[] = LightsSolver.solve(y); if (x == null) { sflag = false; message("Impossible"); return; } for (int i = 0; i < 5; i++) for (int j = 0; j < 5; j++) hint[i][j] = x[5*i+j]; sflag = true; repaint(); } final int u = 60, d = 2, r = 20; final Color[] colours = new Color[] { Color.white, Color.green, Color.red }; public void paint(Graphics g) { for (int i = 0; i < 5; i++) for (int j = 0; j < 5; j++) { g.setColor(colours[count[i][j]]); g.fillRoundRect(i*u+d, j*u+d, u-2*d, u-2*d, r, r); g.setColor(Color.black); g.drawRoundRect(i*u+d, j*u+d, u-2*d, u-2*d, r, r); if (sflag && hint[i][j] > 0) g.drawString(Integer.toString(hint[i][j]), i*u+d+r/2, (j+1)*u-d-r/2); } } public void update(Graphics g) { paint(g); } public Dimension getPreferredSize() { return new Dimension(5*u+1, 5*u+1); } }