Trig Drill

<< Birds | OtherProjectsTrailIndex | Guassian Elimination >>

Click here to see it running

Ngon.java

import java.awt.Polygon;
public class Ngon extends Polygon
{

    public Ngon(int sides, int left, int top, int radius){
        this(sides, left, top, radius, 0);       
    }
    public Ngon(int sides, int left, int top, int radius, double degrees){
    	    double start=degrees*Math.PI/180.0;  	    
        for(double theta=start; theta<2*Math.PI+start; theta+=2*Math.PI/sides)
           addPoint((int)(radius*Math.cos(theta)), (int)(radius*Math.sin(theta+Math.PI)));
        translate(left+radius,top+radius);

    }
    public int getX(int i){
    		return this.xpoints[i];
    }
    public int getY(int i){
    		return this.ypoints[i];
    }
    public int getCenterX(){return getBounds().x + getBounds().width/2;}
    public int getCenterY(){return getBounds().y + getBounds().height/2;}
}

CircleButton.java


import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;


public class CircleButton
{
    // instance variables - replace the example below with your own
    private Rectangle bounds;
    protected Color color;
    private String name;
    protected boolean hilight;
	protected boolean pressed;
    private Font font=new Font("SansSerif",Font.BOLD, 14);
    /**
     * Constructor for objects of class CircleButton
     */
    public CircleButton(int x, int y, int size, String name, Color color)
    {
        this(x,y,size,size,name,color);

    }
    public CircleButton(int x, int y, int width, int height, String name, Color color)
    {

        bounds = new Rectangle(x,y,width,height);
        this.color = color;
        this.name = name;
        this.hilight=false;
        this.pressed=false;
    }

    public void draw(Graphics g)
    {
        if (hilight){ 
            g.setColor(Color.BLACK);
            g.fillOval(bounds.x-4, bounds.y-4, bounds.width+8, bounds.height+8);
        } 
        if (pressed)
            g.setColor(Color.BLACK);
        else
            g.setColor(color);
        g.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);
        g.setFont(font);
        if (pressed)
            g.setColor(Color.WHITE);
        else
            g.setColor(Color.BLACK);
        int x=bounds.x+(bounds.width-name.length()*7)/2;
        int y=bounds.y+(bounds.height/2+4);
        g.drawString(name, x, y);

    }
    public void setHilight(boolean b){ hilight=b;}
    public boolean isHilighted() {return hilight;}
    public void setPressed(boolean b){ pressed=b;}
    public boolean isPressed() { return pressed; }
    public boolean contains(int x, int y){
        return bounds.contains(x,y);
    }
    public String getName() {return name;}
    public void setName(String s){name=s;}
    public Color getColor(){return color;}
    public void setColor(Color c){color=c;}
    public void setBounds(Rectangle r){bounds=r;}
    public Rectangle getBounds(){return bounds;}
    public int getX(){return bounds.x;}
    public int getY(){return bounds.y;}
    public int getSize(){return bounds.width;}
    public void setFont(Font f){font=f;}
    public Font getFont(){return font;}
    public int getCenterX(){return bounds.x + bounds.width/2;}
    public int getCenterY(){return bounds.y + bounds.height/2;}

}

QuestionButton.java

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;

public class QuestionButton extends CircleButton
{
    private boolean visable;
    private String question,answer;
	public QuestionButton(int x, int y, int width, int height, String name, Color color) {
		super(x, y, width, height, name, color);
		visable=true;
	}
	public boolean isVisable(){return visable;}
	public void setVisable(boolean b){ visable=b;}
	public void draw(Graphics g){
		if (!visable)
			return;
		setFont(new Font("serif", Font.ITALIC + Font.BOLD, 36));

		if (hilight){ 
			g.setColor(Color.BLACK);
			g.fillOval(getBounds().x-4, getBounds().y-4, getBounds().width+8, getBounds().height+8);
		} 
		if (pressed)
			g.setColor(Color.BLACK);
		else
			g.setColor(color);
		g.fillOval(getBounds().x, getBounds().y, getBounds().width, getBounds().height);

		if (pressed)
			g.setColor(Color.WHITE);
		else
			g.setColor(Color.BLACK);
		int x=getBounds().x+(getBounds().width-getName().length()*18)/2;
		int y=getBounds().y+(getBounds().height/2+10);
		g.setFont(getFont());
		g.drawString(getName(), x, y);


	}
	public void setQuestion(String q, String a){
		question=q;
		answer=a;
	}
	public void showQuestion(){
		this.setName(question);
	}
	public void showAnswer(){
		this.setName(question+answer);
	}
	public String getAnswer() {
		return answer;
	}

}

AnswerButton.java

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;

public class AnswerButton extends CircleButton
{
    private boolean visable;
	public AnswerButton(int x, int y, int width, int height, String name, Color color) {
		super(x, y, width, height, name, color);
		visable=true;
	}
	public boolean isVisable(){return visable;}
	public void setVisable(boolean b){ visable=b;}
	public void draw(Graphics g){
		if (visable){
			//g.setFont(new Font("sansserif",Font.BOLD,14));
			super.draw(g);
		}
	}

}

Stats.java


import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;


public class Stats 
{
	private ArrayList<Double> d;
	private double sum, sumSq;
	DecimalFormat df;
	public Stats(){
		d=new ArrayList<Double>();
		sum=0;
		sumSq=0;
		df=new DecimalFormat("#.##");
	}
	public void add(double x){
		d.add(x);
		sum+=x;
		sumSq+=x*x;
	}
	public double getMean(){
		if (d.size()>0)
		  return sum/d.size();
		return 0;
	}
	public String getMeanString(){
		if(d.size()<1)
			return "";
		return df.format(getMean());
	}
	public double getSD(){
		if (d.size()<2)
			return 0;
		return Math.sqrt((sumSq-(sum*sum/d.size()))/(d.size()-1));
	}
	public String getSDString(){
		if(d.size()<2)
			return "";
		return df.format(getSD());
	}
	public double getQuartile(int q){
		int n=d.size();
		if(n<4)
			if(n>0)
				return d.get(0);
			else
				return 0;
		Collections.sort(d);

		int index=q*n/4;
		boolean even=n%q==0;
		if (q==3){

			even=n%4==0;
		}
		if (even)
				return 0.5*(  d.get(index)+ d.get(index-1));
		return d.get(index);		
	}
	public String getIQRString(){
		if (d.size()<4)
			return "";
		return "between "+df.format(getQuartile(1))+" and "+df.format(getQuartile(3));
	}
	public String getQuartileString(int q){
		return df.format(getQuartile(q));
	}
	public int n(){ return d.size();}
}

TrigDrill3.java

import java.applet.Applet;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;

public class TrigDrill3 extends Applet implements MouseListener,MouseMotionListener
{
	private HashMap<String,String> sin, cos, tan,csc,sec,cot;
	private Image virtualMem;
	private BufferedImage img;
	private Graphics gBuffer;
	private ArrayList<AnswerButton> btns;
	private QuestionButton qBtn;
	private Rectangle easyBtn,resetBtn;
	private Stats stats;
	private Font big,small;
	private boolean easyMode, started;
	private String message;
	public static final String pi="\u03c0";
	public static final String root="\u221A";
	public static final String[] angles={"-"+pi+"/2", "-"+pi+"/3", "-"+pi+"/4", "-"+pi+"/6",
											"0", pi+"/6", pi+"/4", pi+"/3",
											pi+"/2", "2"+pi+"/3", "3"+pi+"/4", "5"+pi+"/6",
		                                     pi, "7"+pi+"/6", "5"+pi+"/4", "4"+pi+"/3",
		                                     "3"+pi+"/2", "5"+pi+"/3", "7"+pi+"/4", "11"+pi+"/6"};
	public static final String[] functions={"arcsin", "arccos", "arctan", "arccsc", "arcsec","arccot"};
	public static final String[] ratios = {"0", "1/2",root+"3/3",root+"2/2",root+"3/2","1","2"+root+"3/3",
										  "undefined", "-1/2","-"+root+"3/3","-"+root+"2/2","-"+root+"3/2","-1","-"+root+"2",
										  "-"+root+"3","-2"+root+"3/3"};

	private Color btnColor, bgColor;
	private int centerX, centerY, count, correct;
	private DecimalFormat df;
	long startTime;
	public void initAnswers(){
		sin = new HashMap<String,String>();
		cos = new HashMap<String,String>();
		tan = new HashMap<String,String>();
		csc = new HashMap<String,String>();
		sec = new HashMap<String,String>();
		cot = new HashMap<String,String>();

		sec.put(pi, "-1");
		sec.put("5"+pi+"/6", "-2"+root+"3/3");
		sec.put("3"+pi+"/4","-"+root+"2");
		sec.put("2"+pi+"/3", "-2");
		sec.put(pi+"/2", "undefined");
		sec.put(pi+"/3", "2");
		sec.put(pi+"/4",root+"2");
		sec.put(pi+"/6", "2"+root+"3/3");
		sec.put("0", "1");

		cos.put(pi, "-1");
		cos.put("5"+pi+"/6", "-"+root+"3/2");
		cos.put("3"+pi+"/4","-"+root+"2/2");
		cos.put("2"+pi+"/3", "-1/2");
		cos.put(pi+"/2", "0");
		cos.put(pi+"/3", "1/2");
		cos.put(pi+"/4",root+"2/2");
		cos.put(pi+"/6", root+"3/2");
		cos.put("0", "1");

		sin.put(angles[0], "-1");
		sin.put(angles[1], "-"+root+"3/2");
		sin.put(angles[2], "-"+root+"2/2");
		sin.put(angles[3], "-1/2");
		sin.put(angles[4], "0");
		sin.put(angles[5], "1/2");
		sin.put(angles[6], root+"2/2");
		sin.put(angles[7], root+"3/2");
		sin.put(angles[8], "1");

		csc.put(angles[0], "-1");
		csc.put(angles[1], "-2"+root+"3/3");
		csc.put(angles[2], "-"+root+"2");
		csc.put(angles[3], "-2");
		csc.put(angles[4], "undefined");
		csc.put(angles[5], "2");
		csc.put(angles[6], root+"2");
		csc.put(angles[7], "2"+root+"3/3");
		csc.put(angles[8], "1");

		tan.put(angles[0], "undefined");
		tan.put(angles[1], "-"+root+"3");
		tan.put(angles[2], "-1");
		tan.put(angles[3], "-"+root+"3/3");
		tan.put(angles[4], "0");
		tan.put(angles[5], root+"3/3");
		tan.put(angles[6], "1");
		tan.put(angles[7], root+"3");
		tan.put(angles[8], "undefined");

		cot.put(angles[0], "0");
		cot.put(angles[1], "-"+root+"3/3");
		cot.put(angles[2], "-1");
		cot.put(angles[3], "-"+root+"3");
		cot.put(angles[4], "undefined");
		cot.put(angles[5], root+"3");
		cot.put(angles[6], "1");
		cot.put(angles[7], root+"3/3");
		cot.put(angles[8], "0");



	}
	public void makeQuestion(){
		int max=6;
		if (easyMode)
		    max=3;
		int f = (int)(max*Math.random());
		//for sin,csc,tan,cot, angles 0 through 8

		int a = (int)(9*Math.random());
		if (f==1 || f==4){//for cos,sec angle 4 through 12
			a+=4;
		}
		//repair so undefined is ok
		if ((f==3 || f==2) && a==0)//csc or tan undefined
			a=8;
		if ((f==5 ||f==4) && a==12)//sec or cot undefined
			a=4;
		String answer=angles[a];
		String question="";
		if (f==0)
			question=sin.get(answer);
		else if (f==1)
			question=cos.get(answer);
		else if (f==2)
			question=tan.get(answer);
		else if (f==3)
			question=csc.get(answer);
		else if (f==4)
			question=sec.get(answer);
		else if (f==5)
			question=cot.get(answer);
		question=functions[f]+"("+question+")=";
		qBtn.setQuestion(question, answer);
	}
	public void init(){
		easyMode=true;
		started=false;
		count=0;
		correct=0;
		df=new DecimalFormat("##.#");
		virtualMem = createImage(getWidth(),getHeight());
		gBuffer = virtualMem.getGraphics();
		message="          Press Start to begin";
		big = new Font("serif", Font.ITALIC + Font.BOLD, 36);
		small = new Font("Ariel",Font.BOLD,14);
		//bgColor = new Color(255, 204,167);
		bgColor = new Color(226, 182,138);
		btnColor = new Color(255, 230,211);
		initAnswers();
		Ngon shape = new Ngon(16, 30, 110, 180,-90);

		btns = new ArrayList<AnswerButton>();
		for (int i=0; i<16; i++)
			btns.add(new AnswerButton(shape.getX(i),shape.getY(i),65,25 ,angles[i], btnColor) );
		centerX=btns.get(0).getCenterX();
		centerY=btns.get(4).getCenterY();
		qBtn=new QuestionButton(105,20, 300,55,"Start", Color.YELLOW);
		easyBtn=new Rectangle(375,525,125,25);
		resetBtn=new Rectangle(0,0,95,25);
		stats = new Stats();
		addMouseListener(this);
	    addMouseMotionListener(this);
	}

	public void paint(Graphics g){
		gBuffer.setColor(bgColor);
		gBuffer.fillRect(0, 0, getWidth(), getHeight());
		gBuffer.setColor(Color.BLACK);
		gBuffer.drawLine(centerX, 110, centerX, 480);
		gBuffer.drawLine(32, centerY, 400, centerY);
		gBuffer.setColor(btnColor);
		//gBuffer.fillRect(easyBtn.x, easyBtn.y, easyBtn.width, easyBtn.height);
		//gBuffer.fillRect(resetBtn.x, resetBtn.y, resetBtn.width, resetBtn.height);
		for (int i=0; i<btns.size(); i++){
			AnswerButton b=btns.get(i);
			if (b.isHilighted()){
				gBuffer.drawLine(centerX, centerY, b.getCenterX(), b.getCenterY());
				gBuffer.drawLine(b.getCenterX(), centerY, b.getCenterX(), b.getCenterY());
			}
			b.draw(gBuffer);
		}
		qBtn.draw(gBuffer);

		gBuffer.setFont(small);
		gBuffer.drawString(message, 120,100);
		gBuffer.drawString(correct+" out of "+count+" correct", 20,20);
		if (count>0)
			gBuffer.drawString(df.format(100*(double)correct/count)+"%", 20,40);
		if (easyMode)
			gBuffer.drawString("Easy Mode On", 380, 545);
		else
			gBuffer.drawString("Easy Mode Off", 380, 545);
		if (stats.n()>3){
			gBuffer.drawString("Mean time: "+stats.getMeanString(), 10, 515);
			gBuffer.drawString("Half your correct times are ", 10, 530);
			gBuffer.drawString(stats.getIQRString()+" secs", 10, 545);
		}
		g.drawImage(virtualMem,0,0,this);
	}

	public void mouseClicked(MouseEvent e){}
    public void mousePressed(MouseEvent e){
         int x=e.getX();
          int y=e.getY();

        	  	for(CircleButton c:btns)
                c.setPressed(c.contains(x,y));
        	  qBtn.setPressed(qBtn.contains(x,y));
          repaint();
    }
    public void mouseReleased(MouseEvent e){
        int x=e.getX();
        int y=e.getY();

        	for(AnswerButton c:btns){
              c.setPressed(false);
              if(c.contains(x,y))
                  doButton(c);            
        }
        if (qBtn.contains(x,y)){
        		qBtn.setPressed(false);
        		if (!started){
        			started=true;
        			message="";
        			this.makeQuestion();
        			startTime= new Date().getTime();
        			qBtn.setColor(Color.YELLOW);
        			qBtn.showQuestion();
        		}

        }
        if (resetBtn.contains(x,y)){
        		count=0; correct=0; stats=new Stats();
        }
        if (easyBtn.contains(x,y)){
        		easyMode=!easyMode;
        }
        repaint();
    }
    public void mouseEntered(MouseEvent e){}
    public void mouseExited(MouseEvent e){}
    public void mouseMoved(MouseEvent e){
          int x=e.getX();
          int y=e.getY();
          //if(!gameOver)
        	  	for(CircleButton c:btns){
                c.setHilight(c.contains(x,y));

            }
        	  qBtn.setHilight(qBtn.contains(x,y));
          repaint();
    }
    public void mouseDragged(MouseEvent e){}

    public void doButton(AnswerButton b) {
    		if(!started)
    			return;
    		double time=(new Date().getTime()-startTime)/1000.0;
    		started=false;
    		qBtn.showAnswer();
    		message="Time:"+time;
    		count++;
    		if (b.getName().equals(qBtn.getAnswer() )){
    			message="Correct! You got that in "+time+" secs.";
    			stats.add(time);
    			correct++;
    			qBtn.setColor(Color.GREEN);
    		}else{
    			message="No, not "+b.getName();
    			qBtn.setColor(Color.RED);
    		}
        repaint();
    }
    public void update(Graphics g){ paint(g); }
}