• Welcome to Valhalla Legends Archive.
 

[JAVA] Rock Paper Scissors!

Started by Joe[x86], November 03, 2005, 07:18 PM

Previous topic - Next topic

Joe[x86]

This code is untested, because I don't have GCJ installed. I should fix that. =).

Anyhow, I wrote this in school (it worked), came home, and wrote it from scratch.

Output, something like:
Player one has rolled paper.
Player two has rolled rock.
Player one wins.

Hope this can help someone.

public class RPS {

  public static void main(String args[]) {
    int player1, player2, winner;
    player1 = makeRoll();
    player2 = makeRoll();
    System.out.println("Player one has rolled " + getName(player1) + ".");
    System.out.println("Player two has rolled " + getName(player2) + ".");
    switch(getWinner(player1, player2)) {
      case 1: System.out.println("Player one wins."); break;
      case 2: System.out.println("Player two wins."); break;
      case 0: System.out.println("It's a tie."); break;
      case -1: /* This should never happen, but just in case.. */ System.out.println("An error has occured."); break;
    }
    System.exit(0);
  }

  public static int makeRoll() {
    double ret = Math.random() * 3;
    return (int)ret + 1;
    // Math.random returns a double, so we have to typecast it back to int
  }

  public static String getName(int i) {
    switch(i) {
      case 1:  return "rock";
      case 2:  return "paper";
      case 3:  return "scissors";
      default: return "error";
    }
  }

  public static int getWinner(int player1, int player2) {
    // About to get ugly here son.
    int winner = -1; // Asume an error, until proven otherwise
    switch(player1) {
      case 1: {
        switch(player2) { // Player one rolls rock
          case 1: winner=0; break; // Rock ties rock
          case 2: winner=2; break; // Paper covers rock
          case 3: winner=1; break; // Rock breaks scissors
        }
        break;
      }
      case 2: {
        switch(player2) { // Player one rolls paper
          case 1: winner=1; break; // Paper covers rock
          case 2: winner=0; break; // Paper ties paper
          case 3: winner=2; break; // Scissors cut paper
        }
        break;
      }
      case 3: {
        switch(player2) { // Player one rolls scissors
          case 1: winner=2; break; // Rock breaks scissors
          case 2: winner=1; break; // Scissors cut paper
          case 3: winner=0; break; // Scissors ties sissors
        }
        break;
      }
    }
    return winner;
  }

}
Quote from: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.

Falcon[anti-yL]

#1
Quote from: Joe on November 03, 2005, 07:18 PM
  public static int makeRoll() {
    return (int)Math.random + Math.random + Math.random + 1;
    // Math.random returns a double, so we have to typecast it back to int
  }
You could also use the nextInt() method in the java.util.Random class.

rabbit

#2
Quote from: Joe on November 03, 2005, 07:18 PM
  public static int makeRoll() {
    return (int)Math.random + Math.random + Math.random + 1;
    // Math.random returns a double, so we have to typecast it back to int
  }

(int) (Math.random() * num) + 1 works very well, where num is the max you want (here, it would be 3).
Grif: Yeah, and the people in the red states are mad because the people in the blue states are mean to them and want them to pay money for roads and schools instead of cool things like NASCAR and shotguns.  Also, there's something about ketchup in there.

Joe[x86]

I think I did it like that at school.

VB:
Public Function makeRoll() As Integer
  Randomize 'Stupid VB
  makeRoll = (Rnd * 3) + 1
End Function


Java:
public static int makeRoll() {
  return (int)(Math.random() * 3) + 1;
}


PS: You didn't close your tt tags.
Quote from: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.

Joe[x86]

#4
Updated to use rabbit's suggestion, and fix a bug related to not using ()'s after Math.random.

[cave:~] joe% javac RPS.java && java RPS
Player one has rolled scissors.
Player two has rolled scissors.
Its a tie.


EDIT -
For fear of being smoten for a tripple-post, I'll edit.

I installed javac on JoeMomma now. Per MyndFyre's excellent suggestion, in getWinner I declare a winner variable, and ret it once.

Also, I had some screwed up winner returns (where the incorrect player would win), so I fixed them.

This *should* work right, inside and out, now.
Quote from: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.

MyndFyre


  public static String getName(int i) {
    switch(i) {
      case 1:  return "rock";
      case 2:  return "paper";
      case 3:  return "scissors";
      default: return "error";
    }
  }

To avoid requiring switch statements for this, and to make it somewhat more object-oriented, in cases like this, we were encouraged in my first-semester Java class to use final classes (it also prevented "error" from popping up):


public final class Hand : Comparable
{
  private String m_name;
  private int m_id;

  private static Hashtable s_ht = new Hashtable();
  private static Hand[] s_hands = new Hand[3];

  public static final Hand ROCK = new Hand("Rock", 0);
  public static final Hand PAPER = new Hand("Paper", 1);
  public static final Hand SCISSORS = new Hand("Scissors", 2);

  private Hand(String name, int id)
  {
    m_id = id;
    m_name = name;
    s_ht.put(name, this);
    s_hands[id] = this;
  }

  public String getName()
  {
    return m_name;
  }

  public static Hand getById(int id) throws IllegalArgumentException
  {
    if (id > 2 || id < 0) throw new IllegalArgumentException("Valid ids are between 0 and 2, inclusive.");

    return s_hands[id];
  }

  public static Hand getByName(String name)
  {
    Hand hand = null;
    // this method could be updated to be case-insensitive if you chose to make the
    // add operation change the key to upper- or lower-case before adding the object
    // to the collection, and then checking with .containsKey() with the same case
    // right here.
    if (s_ht.containsKey(name))
    {
      hand = (Hand)s_ht.get(name);
    }

    return hand;
  }

  public int compareTo(Object o)
  {
    return toString().compareTo(o.toString());
  }

  public int compareTo(Hand h)
  {
    int result = 0;
    if (this == ROCK)
    {
      if (h == PAPER) result = -1; else if (h == SCISSORS) result = 1;
    }
    else if (this == PAPER)
    {
      if (h == SCISSORS) result = -1; else if (h == ROCK) result = 1;
    }
    else
    {
      if (h == ROCK) result = -1; else if (h == PAPER) result = 1;
    }
    return result;
  }
}


This might seem a bit extraneous for something so simple.  However, there are a few things you might want to consider.
1.) All of your code relating to the Hand is in this class.  You can change your strings to anything and all of your functions except getByName() will work exactly the same.  If you use string constants instead of string literals you'll be even better off.
2.) You could update Hand to implement Comparable, and then Comparable.compareTo() would tell you who won (rather than having a bunch of switch blocks).
3.) You already have a conditional getName() function.  For medium- to large-sized collections of strings, a Hashtable will be MUCH faster for repeated access.

Wow, I really like the idea of adding Comparable support.  It should be in the class now.  :)

My overall implementation of this, including the Hand class above:


public class Game
{
  public static void main(String[] args)
  {
    Random rnd = new Random();
    Hand pl1 = roll(rnd);
    Hand pl2 = roll(rnd);
    System.out.println("Player one has rolled " + pl1.getName() + ".");
    System.out.println("Player two has rolled " + pl2.getName() + ".");
    int comp = pl1.compareTo(pl2);
    if (comp > 0) System.out.println("Player one wins.");
    else if (comp == 0) System.out.println("It's a tie.");
    else System.out.println("Player two wins.");
  }

  private static Hand roll(Random generator)
  {
    return Hand.getById(generator.nextInt(3));
  }
}


Enjoy :)
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Zorm

Wow you wrote many extra lines of code that could possibly contain bugs just to avoid a switch statement.
"Now, gentlemen, let us do something today which the world make talk of hereafter."
- Admiral Lord Collingwood

MyndFyre

Quote from: Zorm on November 06, 2005, 07:23 PM
Wow you wrote many extra lines of code that could possibly contain bugs just to avoid a switch statement.

13?  Wow, it's a shame I spent so much extra effort to make it object-oriented....  you know, like Java is meant to be.

I mean, damn, 13 extra lines really put a cramp in my hand.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

FrOzeN

Erm, it's not a dice. You don't exactly 'roll' scissors or paper, though I guess you can with rocks.
~ FrOzeN

Joe[x86]

Quote from: brew on April 25, 2007, 07:33 PM
that made me feel like a total idiot. this entire thing was useless.

FrOzeN

Quote from: Joe on November 18, 2005, 11:09 AM
Don't be so literal Fr0zeN!
But then I have no reason to be in this forum. :(

Why not "Player # picked #item#", that way it at least sounds half decent.
~ FrOzeN

iago

Mynd, you call toString() but you don't implement toString().  Wouldn't that be required to get a meaningful response?

Also, I thought you couldn't compare Java strings with "==" operator, or was I wrong about that?

I think that the best way to play this game would be this program:

public static void main(...)
{
double result = Math.random();
  if(result < 0.333333333333333)
    System.out.println("Player 1 won");
  else if(result > 0.66666666666667
    System.out.println("Player 2 won");
  else
    System.out.println("tie!");

}


Quote from: FrOzeN on November 17, 2005, 09:38 PM
Erm, it's not a dice. You don't exactly 'roll' scissors or paper, though I guess you can with rocks.
I noticed that, but I realized that if I posted something petty like that, people might stop caring about things I say. so I'd better not. 
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Kp

Quote from: iago on November 20, 2005, 12:54 PMAlso, I thought you couldn't compare Java strings with "==" operator, or was I wrong about that?

I just ran a quick test with gcj and it looks like you can compare them.

public class tst {
public static void main(String[] args)
{
String a = "abc";
String b = "def";
String c = "abc";
String d = "a" + "b" + "c";
System.out.println((a == b) + " " + (a == c) + " " + (a == d));
}
}


kp@vl> gcj --main=tst tst.java
kp@vl> ./a.out
false true true
kp@vl>
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

iago

Quote from: Kp on November 20, 2005, 01:49 PM
Quote from: iago on November 20, 2005, 12:54 PMAlso, I thought you couldn't compare Java strings with "==" operator, or was I wrong about that?

I just ran a quick test with gcj and it looks like you can compare them.

public class tst {
public static void main(String[] args)
{
String a = "abc";
String b = "def";
String c = "abc";
String d = "a" + "b" + "c";
System.out.println((a == b) + " " + (a == c) + " " + (a == d));
}
}


kp@vl> gcj --main=tst tst.java
kp@vl> ./a.out
false true true
kp@vl>


Well, there you go.  I didn't know you could even do that. 

In this project, it would still be a better idea to use integer constants, I think.  There's no real reason to use strings for this stuff. 
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Falcon[anti-yL]

Quote from: iago on November 20, 2005, 12:54 PM
Also, I thought you couldn't compare Java strings with "==" operator, or was I wrong about that? 
You're right, although it wouldn't give you a compile error, it won't work when you run the program.