RPSLS Code

See it in action here

SmartGuesser.java

import java.util.ArrayList;
import java.util.HashMap;
/**
 * SmartGuess add a little "AI" to guesses of an integer nature
 * It keeps track of the last 4 guess pattern and 
 * stores a history of the moves made for that pattern
 * It then returns a move based on the most popular move 
 * made with that pattern. If there is no history for that
 * pattern, it makes a random choice from 0 to max.
 *  
 * @author Chris Thiel, OFMCap
 * @version Nov 26, 2011
 * @param choices 
 */

public class SmartGuesser 
{
	private HashMap<Integer,String> history;
	private int currentPattern;
	private int guessCount;
	private int maxGuess;
	private ArrayList<GestureButton> choices;
	public SmartGuesser(ArrayList<GestureButton> choices){
		history=new HashMap<Integer,String>();
		currentPattern = 0;
		guessCount=0;
		this.choices=choices;
		this.maxGuess=choices.size()-1;
	}
	public void record(int move){
		if (guessCount>3){
			String value="";
			if (history.containsKey(currentPattern) )
				value=history.get(currentPattern);
			history.put(currentPattern, value+move);
		}
		guessCount++;
		currentPattern=(10*currentPattern+move)%100;

	}
	public int getGuess(){
		if (guessCount>3 && history.containsKey(currentPattern)){
		       int theirChoice=popularChoice(history.get(currentPattern));
		       int guess=0;
		       while(choices.get(guess).beats(choices.get(theirChoice))<1){
		    	   		guess++;
		       }
		    	   return guess;
		}
		return (int)((maxGuess+1)*Math.random());
	}
	public int popularChoice(String h){
		int [] count=new int[maxGuess+1];
		for (int i=0; i<h.length(); i++)
			count[Integer.parseInt(h.substring(i, i+1))]++;
		int max=0;
		for (int i=0; i<count.length; i++)
			if (count[i]>count[max])
				max=i;
		return max;
	}
}

CircleButton.java

import java.awt.*;


public class CircleButton
{
    // instance variables - replace the example below with your own
    private Rectangle bounds;
    private Color color;
    private String name;
    private boolean hilight,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;}
}

PointingCircleButton.java


import java.awt.*;
public class PointingCircleButton extends CircleButton
{
    public PointingCircleButton(int x, int y, int size, String name, Color color){
        super(x,y,size,name,color);
    }
    public void drawArrowTo(Graphics g, CircleButton other){
        g.setColor(getColor() );
        if (isPressed() )
            g.setColor(Color.BLACK);
        int x1=getX()+getSize()/2;
        int y1=getY()+getSize()/2;
        int r=other.getSize()/2;
        int x2=other.getX()+r;
        int y2=other.getY()+r;
        double theta = Math.atan2(y2-y1,x2-x1);
        Polygon arrowShaft=new Polygon();
        int d=20;
        double t=.12;
        arrowShaft.addPoint(x1+(int)(r*Math.cos(theta+t)), y1+(int)(r*Math.sin(theta+t)) );
        arrowShaft.addPoint(x1+(int)(r*Math.cos(theta-t)), y1+(int)(r*Math.sin(theta-t)) );
        arrowShaft.addPoint(x2-(int)(r*Math.cos(theta)), y2-(int)(r*Math.sin(theta)) );
        Polygon arrowHead=new Polygon();
        arrowHead.addPoint(x2-(int)((r+d)*Math.cos(theta+t)), y2-(int)((r+d)*Math.sin(theta+t)) );
        arrowHead.addPoint(x2-(int)((r+d)*Math.cos(theta-t)), y2-(int)((r+d)*Math.sin(theta-t)) );
        arrowHead.addPoint(x2-(int)(r*Math.cos(theta)), y2-(int)(r*Math.sin(theta)) );

        g.fillPolygon(arrowShaft);
        g.fillPolygon(arrowHead);
    }
    public void draw(Graphics g){
        super.draw(g);
    }

}

Gesture.java


interface Gesture 
{
     int beats(Gesture g);
     String action(Gesture g);
}

GestureButton.java


import java.util.ArrayList;
import java.awt.*;
/**
 * GestureButton is a generic Gesture, designed to be a super class of 
 * Rock, Paper, Scissors, etc.
 * 
 * @author Chris Thiel, OFMCap
 * @version Nov 25, 2011
 */
public class GestureButton extends PointingCircleButton implements Gesture
{
    private ArrayList<GestureButton> winsOver, losesTo;
    private ArrayList<String> winAction, loseAction;
    public GestureButton(int x, int y, int size, String name, Color color){
        super(x,y,size,name,color);
        winsOver = new ArrayList<GestureButton>();
        losesTo =new ArrayList<GestureButton>();
        winAction = new ArrayList<String>();
        loseAction = new ArrayList<String>();
    }
    public void winsOver(GestureButton other, String winVerb, String loseVerb){
        this.winsOver.add(other);
        this.winAction.add(winVerb);
        other.losesTo.add(this);
        other.loseAction.add(loseVerb);

    }

    public String toString()
    {
        return getName();
    }
    public int beats(Gesture g) {
       if ( winsOver.indexOf(g) >=0 )
          return 1;
       if ( losesTo.indexOf(g) >=0 )
            return -1;
       return 0;
    }

    public String action(Gesture g) {
        if (this.beats(g)>0){
            return winAction.get(winsOver.indexOf(g));      
        }
        if (this.beats(g)<0){
            return loseAction.get(losesTo.indexOf(g));
        }   
        return " ties with ";
    }
    public void draw(Graphics g)
    {
        for (GestureButton b:winsOver){
            drawArrowTo(g,b);
         }
        super.draw(g);
    }
}

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)));
        translate(left+radius,top+radius);

    }
    public int getX(int i){
    		return this.xpoints[i];
    }
    public int getY(int i){
    		return this.ypoints[i];
    }
}

ResetButton.java


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

public class ResetButton extends CircleButton
{
    private boolean visable;
	public ResetButton(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)
			super.draw(g);
	}

}

RockPaperScissorsLizardSpock.java



import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.applet.*;
import java.util.ArrayList;
//import javax.swing.event.*;
/**
 * Class CircleButtons - write a description of the class here
 * 
 * @author (your name) 
 * @version (a version number)
 */
public class RockPaperScissorsLizardSpock extends Applet implements MouseListener,MouseMotionListener
{
    private ArrayList<GestureButton> btns;
    private String message="";
    private int human, computer,ties;
    private boolean gameOver;
    private ResetButton resetBtn;
    private SmartGuesser ai;
    private Image virtualMem;
	private BufferedImage img;
	private Graphics gBuffer;
    public void init()
    {
       human=0;
       computer=0;
       ties=0;
       gameOver=false;

       resetBtn= new ResetButton(195,220,100,75,"Play Again", Color.MAGENTA);
       resetBtn.setVisable(false);
       Ngon pattern = new Ngon(5, 20, 30, 175, -90); 
       GestureButton rock  = new GestureButton(pattern.getX(0),pattern.getY(0),100,"Rock",Color.CYAN );
       GestureButton paper = new GestureButton(pattern.getX(1),pattern.getY(1),100,"Paper", Color.RED );
       GestureButton scissors = new GestureButton(pattern.getX(2),pattern.getY(2),100, "Scissors", new Color(210,125,255));
       GestureButton lizard = new GestureButton(pattern.getX(3),pattern.getY(3),100,"Lizard", Color.ORANGE );
       GestureButton spock = new GestureButton(pattern.getX(4),pattern.getY(4),100, "Spock", Color.GREEN );

       rock.winsOver(scissors," crushes ", " crushed by ");
       paper.winsOver(rock, " covers ", " covered by ");
       scissors.winsOver(paper, " cuts ", " cut by ");
       lizard.winsOver(paper, " eats ", " eaten by ");
       spock.winsOver(rock, " vaporizes ", " vaporized by ");

       rock.winsOver(lizard," crushes ", " crushed by ");
       paper.winsOver(spock, " disproves ", " disproved by ");
       scissors.winsOver(lizard, " decapitates ", " decapitated by ");
       lizard.winsOver(spock, " poisons ", " poisoned by ");
       spock.winsOver(scissors, " smashes ", " smashed by ");

       btns=new ArrayList<GestureButton>();
       btns.add(rock);
       btns.add(paper);
       btns.add(scissors);
       btns.add(lizard);
       btns.add(spock);
       ai=new SmartGuesser(btns);      
       addMouseListener(this);
       addMouseMotionListener(this);
       virtualMem = createImage(getWidth(),getHeight());
       gBuffer = virtualMem.getGraphics();
    }



    /**
     * Paint method for applet.
     * 
     * @param  g   the Graphics object for this applet
     */
    public void paint(Graphics g)
    {
        // simple text displayed on applet
    		gBuffer.setColor(Color.white);
        gBuffer.fillRect(0, 0, getWidth(), getHeight());
        gBuffer.setColor(Color.black);
        gBuffer.drawString("Rock Paper Scissors Lizard Spock (with basic AI)", 20, 20);
        gBuffer.setColor(Color.blue);
        gBuffer.drawString(message, 150, 470);
        gBuffer.drawString("You: "+human, 58, 60);
        gBuffer.drawString("Computer: "+computer, 20, 80);
        gBuffer.drawString("Ties: "+ties, 55, 100);
        resetBtn.draw(gBuffer);
        for(GestureButton gesture:btns){
            gesture.draw(gBuffer);
        }
        g.drawImage(virtualMem,0,0,this);
    }
    public void mouseClicked(MouseEvent e){}
    public void mousePressed(MouseEvent e){
         int x=e.getX();
          int y=e.getY();
          if(!gameOver)
        	  	for(CircleButton c:btns)
                c.setPressed(c.contains(x,y));
          resetBtn.setPressed(resetBtn.contains(x, y)); 
          repaint();
    }
    public void mouseReleased(MouseEvent e){
        int x=e.getX();
        int y=e.getY();
        if(!gameOver)
        		for(GestureButton c:btns){
              c.setPressed(false);
              if(c.contains(x,y))
                  doButton(c);            
        }else{
        		if(resetBtn.contains(x, y)){
        			gameOver=false;
        			resetBtn.setVisable(false);
        			if (message.length()>2)
        				message=message.substring(message.indexOf(" "))+" last time";
        			for(CircleButton c:btns)
                        c.setPressed(false);
        		}
        }

        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));
                //c.setPressed(false);
            }
          resetBtn.setHilight(resetBtn.contains(x, y));
          repaint();
    }
    public void mouseDragged(MouseEvent e){}
    public void doButton(GestureButton b) {
    		gameOver=true;
        GestureButton rand=btns.get(ai.getGuess());
        ai.record(btns.indexOf(b));
        rand.setHilight(true);
        b.setHilight(true);
        if (rand.beats(b)==0){
        		message="Tie! ";
        		ties++;
        }else if (rand.beats(b)>0){
            rand.setPressed(true);
            b.setPressed(false);
            message="Sorry, ";
            computer++;
        }else if (b.beats(rand)>0){
            b.setPressed(true);
            rand.setPressed(false);
            message="Yes! ";
            human++;
        }

        resetBtn.setVisable(true);       
        message+=b.getName()+b.action(rand)+rand.getName();
        repaint();
    }
    public void update(Graphics g){ paint(g); }
}