/* Copyright (C) 2002 J. M. Spivey */ import java.awt.*; import java.awt.event.*; /** Main class for the CountDown applet * * This class presents the GUI for the applet. The only interesting * aspect is the random selection of numbers, where we want to make * all (N choose K) selections equally likely. */ public class CountDown extends DemoFrame { public static final int N = 6; Panel panel0 = new Panel(new FlowLayout()); Panel panel0a = new Panel(new FlowLayout()); Panel panel1 = new Panel(new BorderLayout(5,5)); Panel panel1a = new Panel(new GridLayout(4,1)); Panel panel1b = new Panel(new GridLayout(5,4)); Panel panel1c = new Panel(); Panel panel2 = new Panel(new BorderLayout(5,5)); Panel panel2a = new Panel(); Panel panel2b = new Panel(); Panel panel3 = new Panel(); TextField solution = new TextField(50); Button solveButton; TextField target = new TextField(3); int targval; Checkbox bigCheck[] = new Checkbox[4]; Checkbox smallCheck[] = new Checkbox[20]; int bigNums[] = { 25, 50, 75, 100 }; int nchoices = 0; // Number of numbers chosen Checkbox choices[] = new Checkbox[N]; // The checkboxes for the chosen numbers private Button addButton(String name, Panel p, ActionListener action) { Button b = new Button(name); b.addActionListener(action); p.add(b); return b; } private ItemListener checkListener = new ItemListener() { public void itemStateChanged(ItemEvent e) { click((Checkbox) e.getSource()); } }; private Checkbox addCheckbox(int value, Panel p) { Checkbox chk = new Checkbox(Integer.toString(value)); chk.addItemListener(checkListener); p.add(chk); return chk; } public CountDown() { super("CountDown"); add(panel0, "Center"); panel0.add(panel1); panel1.add(panel1a, "East"); panel1.add(panel1b, "West"); panel1.add(panel1c, "South"); add(panel0a, "East"); panel0a.add(panel2); panel2.add(panel2a, "Center"); panel2.add(panel2b, "South"); add(panel3, "South"); for (int i = 0; i < bigNums.length; i++) bigCheck[i] = addCheckbox(bigNums[i], panel1a); for (int i = 0; i < 5; i++) { smallCheck[2*i] = addCheckbox(i+1, panel1b); smallCheck[2*i+1] = addCheckbox(i+1, panel1b); smallCheck[2*i+10] = addCheckbox(i+6, panel1b); smallCheck[2*i+11] = addCheckbox(i+6, panel1b); } addButton("Clear", panel1c, new ActionListener() { public void actionPerformed(ActionEvent e) { clearChoices(); } }); addButton("Random", panel1c, new ActionListener() { public void actionPerformed(ActionEvent e) { randomChoices(); } }); solveButton = addButton("Solve", panel1c, new ActionListener() { public void actionPerformed(ActionEvent e) { solve(); } }); solveButton.setEnabled(false); addButton("Quit", panel1c, new ActionListener() { public void actionPerformed(ActionEvent e) { die(); } }); Font targetFont = new Font("Sans", Font.PLAIN, 20); target.setFont(targetFont); target.setForeground(Color.green); target.setBackground(Color.black); target.addTextListener(new TextListener() { public void textValueChanged(TextEvent e) { checkState(); } }); target.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (solveButton.isEnabled()) solve(); } }); panel2a.add(target); addButton("Random", panel2b, new ActionListener() { public void actionPerformed(ActionEvent e) { randomTarget(); } }); Font solutionFont = new Font("Monospaced", Font.PLAIN, 12); solution.setFont(solutionFont); solution.setEditable(false); panel3.add(solution); pack(); setResizable(false); } /** Respond to a state change for a checkbox */ private void click(Checkbox chk) { boolean state = chk.getState(); if (state) { // A new choice if (nchoices == N) { // Undo the oldest choice, so there are never more than N nchoices--; choices[0].setState(false); for (int i = 0; i < nchoices; i++) choices[i] = choices[i+1]; } choices[nchoices++] = chk; } else { // Cancelling an old choice nchoices--; int j = 0; while (choices[j] != chk) j++; for (int i = j; i < nchoices; i++) choices[i] = choices[i+1]; } checkState(); } private void clearChoices() { for (int i = 0; i < bigCheck.length; i++) bigCheck[i].setState(false); for (int i = 0; i < smallCheck.length; i++) smallCheck[i].setState(false); nchoices = 0; checkState(); } private void randomChoices() { clearChoices(); int big = (int) (4 * Math.random()); bigCheck[big].setState(true); choices[nchoices++] = bigCheck[big]; for (int i = 0; i < 20; i++) { // Choose checkbox i with the appropriate probability if (Math.random() < (double) (N - nchoices)/(20 - i)) { smallCheck[i].setState(true); choices[nchoices++] = smallCheck[i]; } } checkState(); } /** Choose a random target number */ private void randomTarget() { // All numbers from 101 to 999 are equally likely target.setText(Integer.toString(101 + (int) (899 * Math.random()))); checkState(); } /** Return the chosen numbers as an array */ private int[] draw() { int pick[] = new int[nchoices]; int n = 0; for (int i = 0; i < 20; i++) if (smallCheck[i].getState()) pick[n++] = i/2 + 1; for (int i = 0; i < 4; i++) if (bigCheck[i].getState()) pick[n++] = bigNums[i]; return pick; } /** Enable the Solve button if everything is ready for it */ private void checkState() { // List the choices in the solution box StringBuffer buf = new StringBuffer(); int pick[] = draw(); for (int i = 0; i < pick.length; i++) buf.append(pick[i] + " "); solution.setText(buf.toString()); // Check if we are ready to solve the problem boolean ok; try { targval = Integer.parseInt(target.getText()); ok = (nchoices == N && targval > 0); } catch (NumberFormatException e) { ok = false; } solveButton.setEnabled(ok); } /** Compute the best solution */ private void solve() { solution.setText(Solver.Solve(draw(), targval)); } public static void main(String args[]) { Frame frame = new CountDown(); frame.setVisible(true); } }