/* * EFT.java - Embedded Figures Test * Copyright (C) 2007 Alan G. Carter * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ /* * Changes * 15OCT07 - Alan Carter - Made minimal and experimental mode. * Reseed Random for each run. * 30SEP07 - Steve Dodd - corrected mouseClicked() to mousePressed(). */ import java.awt.*; import java.awt.event.*; import java.applet.Applet; import java.util.Random; @SuppressWarnings("serial") public class EFT extends Applet implements ActionListener, MouseListener, MouseMotionListener { //////////////////////////////////////////////////////////////////////////// // // class Segment // //////////////////////////////////////////////////////////////////////////// private class Segment { private final int ARC = 0; private final int LINE = 1; private int x0, y0, x1, y1, start, subtend; private int type; public Segment(int x0, int y0, int x1, int y1) { this.x0 = x0; this.y0 = y0; this.x1 = x1; this.y1 = y1; type = LINE; } Segment(int x0, int y0, int x1, int y1, int start, int subtend) { this.x0 = x0; this.y0 = y0; this.x1 = x1; this.y1 = y1; this.start = start; this.subtend = subtend; type = ARC; } public void display(Graphics g, int x, int y) { if(type == LINE) { g.drawLine(x + x0, y + y0, x + x1, y + y1); } else if(type == ARC) { g.drawArc(x + x0, y + y0, x1, y1, start, subtend); } } } //////////////////////////////////////////////////////////////////////////// // // class Figure // //////////////////////////////////////////////////////////////////////////// private class Figure { private Segment[] segments; private int segmentCount = 0; public Figure() { segments = new Segment[10]; } public void addSegment(Segment segment) { if(segmentCount < 10) segments[segmentCount++] = segment; } public void display(Graphics g, int x, int y) { for(int i = 0; i < segmentCount; i++) { segments[i].display(g, x, y); } } } //////////////////////////////////////////////////////////////////////////// // // class EFT // //////////////////////////////////////////////////////////////////////////// private final int TOP = 100; private final int LEFT = 5; private final int HEIGHT = 90; private final int WIDTH = 590; private final int TARGET_WIDTH = 90; private final int FIGURE_SIZE = 50; private final int FIGTRISTAB = 0; private final int FIGTRIUNSTAB = 1; private final int FIGCROSS = 2; private final int FIGDIAMOND = 3; private final int FIGLAMBDA = 4; private final int FIGMOONLEFT = 5; private final int FIGMOONRIGHT = 6; private final int FIGCIRCLE = 7; private final int FIGMAX = 8; private final int NOTRUN = 0; private final int RUNNING = 1; private final int HASRUN = 2; private String mode = ""; private int state = NOTRUN; private int wally; private int zoneX; private int zoneY; private long startTime; private long[] scores; private int testsCount; private Label noiseLabel; private TextField noiseWidget; private int noiseValue; private Label testsLabel; private TextField testsWidget; private int testsValue; private Button go; private Button restart; private Figure figTriStab = new Figure(); private Figure figTriUnstab = new Figure(); private Figure figCross = new Figure(); private Figure figDiamond = new Figure(); private Figure figLambda = new Figure(); private Figure figMoonLeft = new Figure(); private Figure figMoonRight = new Figure(); private Figure figCircle = new Figure(); private Random random = new Random(); //////////////////////////////////////////////////////////////////////////// private void populateFigures() { figTriStab.addSegment(new Segment(FIGURE_SIZE / 2, 0, 0, FIGURE_SIZE)); figTriStab.addSegment(new Segment(0, FIGURE_SIZE, FIGURE_SIZE, FIGURE_SIZE)); figTriStab.addSegment(new Segment(FIGURE_SIZE, FIGURE_SIZE, FIGURE_SIZE / 2, 0)); figTriUnstab.addSegment(new Segment(FIGURE_SIZE / 2, FIGURE_SIZE, 0, 0)); figTriUnstab.addSegment(new Segment(0, 0, FIGURE_SIZE, 0)); figTriUnstab.addSegment(new Segment(FIGURE_SIZE, 0, FIGURE_SIZE / 2, FIGURE_SIZE)); figCross.addSegment(new Segment(FIGURE_SIZE / 2, 0, FIGURE_SIZE / 2, FIGURE_SIZE)); figCross.addSegment(new Segment(0, FIGURE_SIZE / 2, FIGURE_SIZE, FIGURE_SIZE / 2)); figDiamond.addSegment(new Segment(FIGURE_SIZE / 2, 0, FIGURE_SIZE, FIGURE_SIZE / 2)); figDiamond.addSegment(new Segment(FIGURE_SIZE, FIGURE_SIZE / 2, FIGURE_SIZE / 2, FIGURE_SIZE)); figDiamond.addSegment(new Segment(FIGURE_SIZE / 2, FIGURE_SIZE, 0, FIGURE_SIZE / 2)); figDiamond.addSegment(new Segment(0, FIGURE_SIZE / 2, FIGURE_SIZE / 2, 0)); figLambda.addSegment(new Segment(0, 0, FIGURE_SIZE, FIGURE_SIZE)); figLambda.addSegment(new Segment(FIGURE_SIZE / 2, FIGURE_SIZE / 2, 0, FIGURE_SIZE)); figMoonLeft.addSegment(new Segment(0, 0, FIGURE_SIZE, FIGURE_SIZE, 90, 180)); figMoonLeft.addSegment(new Segment(FIGURE_SIZE / 2, 0, FIGURE_SIZE / 2, FIGURE_SIZE)); figMoonRight.addSegment(new Segment(0, 0, FIGURE_SIZE, FIGURE_SIZE, 270, 180)); figMoonRight.addSegment(new Segment(FIGURE_SIZE / 2, 0, FIGURE_SIZE / 2, FIGURE_SIZE)); figCircle.addSegment(new Segment(0, 0, FIGURE_SIZE, FIGURE_SIZE, 0, 360)); } //////////////////////////////////////////////////////////////////////////// private void displayFigure(Graphics g, int figCode, int x, int y) { if(figCode == FIGTRISTAB) figTriStab.display(g, x, y); else if(figCode == FIGTRIUNSTAB) figTriUnstab.display(g, x, y); else if(figCode == FIGCROSS) figCross.display(g, x, y); else if(figCode == FIGDIAMOND) figDiamond.display(g, x, y); else if(figCode == FIGLAMBDA) figLambda.display(g, x, y); else if(figCode == FIGMOONLEFT) figMoonLeft.display(g, x, y); else if(figCode == FIGMOONRIGHT) figMoonRight.display(g, x, y); else if(figCode == FIGCIRCLE) figCircle.display(g, x, y); } //////////////////////////////////////////////////////////////////////////// private void placeFigure() { // Re-seed the random number generator for each run. random.setSeed(System.currentTimeMillis()); // Pick the zone. zoneX = random.nextInt(WIDTH - (TARGET_WIDTH + FIGURE_SIZE)) + LEFT + TARGET_WIDTH; zoneY = random.nextInt(HEIGHT - FIGURE_SIZE) + TOP; // Pick the figure to be found. wally = random.nextInt(FIGMAX); // Remember the starting time. startTime = System.currentTimeMillis(); } //////////////////////////////////////////////////////////////////////////// public void init() { populateFigures(); scores = new long[256]; setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10)); // We support a minimal mode for a consistent large population test. mode = new String(getParameter("mode")); if(!mode.equals("minimal")) { noiseLabel = new Label("Noise = "); noiseWidget = new TextField("20", 2); testsLabel = new Label("Tests = "); testsWidget = new TextField("10", 2); add(noiseLabel); add(noiseWidget); add(testsLabel); add(testsWidget); } go = new Button("Go"); restart = new Button("Restart"); add(go); add(restart); go.addActionListener(this); restart.addActionListener(this); addMouseListener(this); go.setEnabled(true); restart.setEnabled(false); state = NOTRUN; } //////////////////////////////////////////////////////////////////////////// public void paint(Graphics g) { g.setColor(Color.black); g.drawLine(LEFT, TOP, LEFT + WIDTH, TOP); g.drawLine(LEFT, TOP + HEIGHT, LEFT + WIDTH, TOP + HEIGHT); g.drawLine(LEFT, TOP, LEFT, TOP + HEIGHT); g.drawLine(LEFT + TARGET_WIDTH, TOP, LEFT + TARGET_WIDTH, TOP + HEIGHT); g.drawLine(LEFT + WIDTH, TOP, LEFT + WIDTH, TOP + HEIGHT); if(state == NOTRUN) { if(!mode.equals("minimal")) g.drawString("Select the amount of noise figures and tests to perform.", 110, 120); g.drawString("The figure to find is shown in the box on the left.", 110, 140); g.drawString("Find and click it in this box.", 110, 160); } else if(state == HASRUN) { long total = 0; for(int i = 0; i < testsValue; i++) total += scores[i]; g.drawString("Average time (ms): " + Long.toString(total / testsValue), 110, 120); } else if(state == RUNNING) { // Draw the boxes. displayFigure(g, wally, LEFT + ((TARGET_WIDTH - FIGURE_SIZE) / 2), TOP + ((HEIGHT - FIGURE_SIZE) / 2)); displayFigure(g, wally, zoneX, zoneY); // Pick and place the correct number of noise figures. int count = 0; while(count < noiseValue) { int figCode; if((figCode = random.nextInt(FIGMAX)) == wally) continue; int x = random.nextInt(WIDTH - (TARGET_WIDTH + FIGURE_SIZE)) + LEFT + TARGET_WIDTH; int y = random.nextInt(HEIGHT - FIGURE_SIZE) + TOP; displayFigure(g, figCode, x, y); count++; } } } //////////////////////////////////////////////////////////////////////////// public void actionPerformed(ActionEvent e) { if(e.getSource() == go) { if(mode.equals("minimal")) { noiseValue = 20; testsValue = 10; } else { noiseValue = Integer.parseInt(noiseWidget.getText()); testsValue = Integer.parseInt(testsWidget.getText()); if(testsValue > 255) testsValue = 255; } go.setEnabled(false); restart.setEnabled(true); testsCount = 0; state = RUNNING; placeFigure(); } else if(e.getSource() == restart) { go.setEnabled(true); restart.setEnabled(false); state = NOTRUN; placeFigure(); } repaint(); } //////////////////////////////////////////////////////////////////////////// public void mousePressed(MouseEvent e) { int x = e.getX(); int y = e.getY(); if(state == RUNNING && x > zoneX && x < zoneX + FIGURE_SIZE && y > zoneY && y < zoneY + FIGURE_SIZE) { scores[testsCount++] = System.currentTimeMillis() - startTime; if(testsCount == testsValue) state = HASRUN; placeFigure(); repaint(); } } //////////////////////////////////////////////////////////////////////////// public void mouseDragged(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mouseMoved(MouseEvent e) {} public void mouseClicked(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} }