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); }
}
