Valhalla Legends Forums Archive | Java Programming | [JAVA] Rock Paper Scissors!

AuthorMessageTime
JoeTheOdd
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.

[code]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;
  }

}
[/code]
November 4, 2005, 1:18 AM
LW-Falcon
[quote author=Joe link=topic=13143.msg132793#msg132793 date=1131067122]
  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
  }
[/quote]
You could also use the nextInt() method in the java.util.Random class.
November 4, 2005, 2:54 AM
rabbit
[quote author=Joe link=topic=13143.msg132793#msg132793 date=1131067122]
[code]  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
  }[/code]
[/quote][tt](int) (Math.random() * num) + 1[/tt] works very well, where [tt]num[/tt] is the max you want (here, it would be 3).
November 5, 2005, 4:56 PM
JoeTheOdd
I think I did it like that at school.

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

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

PS: You didn't close your tt tags.
November 5, 2005, 11:47 PM
JoeTheOdd
Updated to use rabbit's suggestion, and fix a bug related to not using ()'s after Math.random.

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

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.
November 6, 2005, 12:50 AM
Myndfyr
[code]
  public static String getName(int i) {
    switch(i) {
      case 1:  return "rock";
      case 2:  return "paper";
      case 3:  return "scissors";
      default: return "error";
    }
  }
[/code]
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):

[code]
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;
  }
}
[/code]

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:

[code]
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));
  }
}
[/code]

Enjoy :)
November 6, 2005, 3:29 PM
zorm
Wow you wrote many extra lines of code that could possibly contain bugs just to avoid a switch statement.
November 7, 2005, 1:23 AM
Myndfyr
[quote author=Zorm link=topic=13143.msg133055#msg133055 date=1131326623]
Wow you wrote many extra lines of code that could possibly contain bugs just to avoid a switch statement.
[/quote]

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.
November 7, 2005, 4:39 PM
FrOzeN
Erm, it's not a dice. You don't exactly 'roll' scissors or paper, though I guess you can with rocks.
November 18, 2005, 3:38 AM
JoeTheOdd
Don't be so literal Fr0zeN!
November 18, 2005, 5:09 PM
FrOzeN
[quote author=Joe link=topic=13143.msg134521#msg134521 date=1132333792]
Don't be so literal Fr0zeN!
[/quote]
But then I have no reason to be in this forum. :(

Why not "Player # picked #item#", that way it at least sounds half decent.
November 19, 2005, 5:35 AM
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:

[code]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!");

}[/code]

[quote author=FrOzeN link=topic=13143.msg134453#msg134453 date=1132285082]
Erm, it's not a dice. You don't exactly 'roll' scissors or paper, though I guess you can with rocks.
[/quote]
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. 
November 20, 2005, 6:54 PM
Kp
[quote author=iago link=topic=13143.msg134811#msg134811 date=1132512880]Also, I thought you couldn't compare Java strings with "==" operator, or was I wrong about that?[/quote]

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

[code]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));
}
}
[/code]

[pre]kp@vl> gcj --main=tst tst.java
kp@vl> ./a.out
false true true
kp@vl>[/pre]
November 20, 2005, 7:49 PM
iago
[quote author=Kp link=topic=13143.msg134825#msg134825 date=1132516182]
[quote author=iago link=topic=13143.msg134811#msg134811 date=1132512880]Also, I thought you couldn't compare Java strings with "==" operator, or was I wrong about that?[/quote]

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

[code]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));
}
}
[/code]

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

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. 
November 20, 2005, 8:31 PM
LW-Falcon
[quote author=iago link=topic=13143.msg134811#msg134811 date=1132512880]
Also, I thought you couldn't compare Java strings with "==" operator, or was I wrong about that? 
[/quote]
You're right, although it wouldn't give you a compile error, it won't work when you run the program.
November 20, 2005, 9:33 PM
iago
[quote author=Falcon[anti-yL] link=topic=13143.msg134836#msg134836 date=1132522416]
[quote author=iago link=topic=13143.msg134811#msg134811 date=1132512880]
Also, I thought you couldn't compare Java strings with "==" operator, or was I wrong about that? 
[/quote]
You're right, although it wouldn't give you a compile error, it won't work when you run the program.
[/quote]
According to what Kp posted, it works fine.  *shrug*

Maybe it's a newer feature in like 1.5-style compilers?  I learned on 1.4 compilers, so..
November 20, 2005, 9:41 PM
kamakazie
[quote author=Falcon[anti-yL] link=topic=13143.msg134836#msg134836 date=1132522416]
You're right, although it wouldn't give you a compile error, it won't work when you run the program.
[/quote]

Yep. Kp's example is misleading.

[code]
[dxoigmn@tahoe:~]# cat Test.java
public class Test {
    public static void main(String[] args) {
        String a = "abc";
        String b = "a";

        b += "b";
        b += "c";

        System.out.println(a + " == " + b + " => " + (a == b));
    }
}
[dxoigmn@tahoe:~]# gcj --main=Test Test.java
[dxoigmn@tahoe:~]# ./a.out
abc == abc => false
[/code]
November 20, 2005, 9:47 PM
LW-Falcon
[quote author=iago link=topic=13143.msg134838#msg134838 date=1132522899]
[quote author=Falcon[anti-yL] link=topic=13143.msg134836#msg134836 date=1132522416]
[quote author=iago link=topic=13143.msg134811#msg134811 date=1132512880]
Also, I thought you couldn't compare Java strings with "==" operator, or was I wrong about that? 
[/quote]
You're right, although it wouldn't give you a compile error, it won't work when you run the program.
[/quote]
According to what Kp posted, it works fine.  *shrug*

Maybe it's a newer feature in like 1.5-style compilers?  I learned on 1.4 compilers, so..
[/quote]
We use 1.5 at our school and I was working on a program when I figured it out. I had to use equals() to make it work.
November 20, 2005, 10:56 PM
FrOzeN
[quote author=iago link=topic=13143.msg134811#msg134811 date=1132512880][quote author=FrOzeN link=topic=13143.msg134453#msg134453 date=1132285082]
Erm, it's not a dice. You don't exactly 'roll' scissors or paper, though I guess you can with rocks.
[/quote]
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. 
[/quote]
Point taken, though Joe know's I'm just joking around. :P
November 21, 2005, 1:51 AM
The-FooL
== compares references.  If the objects that the strings point to are the same, then it will return true.  More likely is that both strings contain the same data, but are different objects in memory, so the comparison will return false.
November 21, 2005, 4:01 AM
iago
[quote author=The-FooL link=topic=13143.msg134877#msg134877 date=1132545670]
== compares references.  If the objects that the strings point to are the same, then it will return true.  More likely is that both strings contain the same data, but are different objects in memory, so the comparison will return false.
[/quote]
That's what I thought, but Kp's example seemed to show otherwise..
November 21, 2005, 1:48 PM
K
[quote author=iago link=topic=13143.msg134897#msg134897 date=1132580902]
[quote author=The-FooL link=topic=13143.msg134877#msg134877 date=1132545670]
== compares references. If the objects that the strings point to are the same, then it will return true. More likely is that both strings contain the same data, but are different objects in memory, so the comparison will return false.
[/quote]
That's what I thought, but Kp's example seemed to show otherwise..
[/quote]

Take a look at dx's example.  I think Kp's is showing the same behavior as this C snippet:

[code]
const char* a = "abc";
const char* b = "abc";

if (a == b)
{
  // ...
}
[/code]

which will return true as the compiler will assign both pointers to point to the same memory.  In java this probably happens also because strings are immutable; if you change a, it won't change  b, but rather b will point to a new string.

dx's example shows that two strings with the same contents but that point to different objects should return false.
November 21, 2005, 7:22 PM
iago
But Kp's strings clearly aren't the same, since he constructs them in different ways.  Does Java really search for strings that are the same and combine them?  That seems really bad, and it seems like it could lead to a lot of confusion... :-/
November 21, 2005, 11:14 PM
Myndfyr
[quote author=iago link=topic=13143.msg134947#msg134947 date=1132614895]
But Kp's strings clearly aren't the same, since he constructs them in different ways.  Does Java really search for strings that are the same and combine them?  That seems really bad, and it seems like it could lead to a lot of confusion... :-/
[/quote]

Kp's strings really aren't constructed differently.  Look at the code:
[code]
String a = "abc";
String b = "def";
String c = "abc";
String d = "a" + "b" + "c";
[/code]
The Java compiler recognizes that "a" + "b" + "c" is a constant expression and concatenates them at compile time to reduce memory use and runtime operations.  I believe Java also uses string interning (like .NET) to reduce the number of times a specific string exists in memory.  Thus, if "abc" is loaded three times at compile time, since Java strings are immutable, the variables a, c, and d can all safely point to the same string in memory.

However, doing this:
[code]
String a = "a";
a = a + "b";
a = a + "c";
// or
a = "a";
a = a.concat("b");
a = a.concat("c");
[/code]
will both result in a being a different string reference than the String abc = "abc" declaration would.
November 22, 2005, 1:04 AM
iago
Ah, I get it. 

I still think that's evil, though.  If it's going to work like that, it should just error out if you compare strings with ==..
November 22, 2005, 4:51 PM
Myndfyr
[quote author=iago link=topic=13143.msg135016#msg135016 date=1132678282]
Ah, I get it. 

I still think that's evil, though.  If it's going to work like that, it should just error out if you compare strings with ==..
[/quote]
It's in the Java API that you're not supposed to compare strings with ==.  It's the same with every object comparison in Java -- you compare object references.  You don't do this:
[code]
public class Blarg
{
  private int i;
  Blarg a = new Blarg();
  Blarg b = new Blarg();
  a = 1;
  b = 1;
  System.out.println(a==b);
}
[/code]
Strings are just another Object-derived class; why would you expect it to work with String and not Blarg?
November 22, 2005, 8:46 PM
iago
[quote author=MyndFyre link=topic=13143.msg135036#msg135036 date=1132692372]
[quote author=iago link=topic=13143.msg135016#msg135016 date=1132678282]
Ah, I get it. 

I still think that's evil, though.  If it's going to work like that, it should just error out if you compare strings with ==..
[/quote]
It's in the Java API that you're not supposed to compare strings with ==.  It's the same with every object comparison in Java -- you compare object references.  You don't do this:
[code]
public class Blarg
{
  private int i;
  Blarg a = new Blarg();
  Blarg b = new Blarg();
  a = 1;
  b = 1;
  System.out.println(a==b);
}
[/code]
Strings are just another Object-derived class; why would you expect it to work with String and not Blarg?
[/quote]

I wouldn't expect it to worth with string, of course.  I also wouldn't expect the following strings:

String a = "abc";
String b = "a" + "b" + "c";

to be equal, for the same reason I wouldn't expect your Blargs to be equal. 

I totally agree that you shouldn't compare objects with '==', but the way String's are handled seems to make it look like you can. 
November 23, 2005, 4:00 AM
Myndfyr
[quote author=iago link=topic=13143.msg135092#msg135092 date=1132718434]
I totally agree that you shouldn't compare objects with '==', but the way String's are handled seems to make it look like you can. 
[/quote]
That's only because of the hack of overloading the + operator.  If Java supports overloaded operators in one class, then it should support them in all classes (of course, then it'd be C#).

Like I said before, the fact that "abc" == "a" + "b" + "c" is a compile-time optimization.  If you did something like:
[code]
String abc = "abc";
String def = "a";
def = def.concat("b");
def = def.concat("c");
System.out.println(abc==def);
[/code]

The compiler most likely won't optimize this out (although in theory it could since it's really only operating on constants... but you'd have to have a really smart compiler).

I still think that the way strings are native to Java should make them either an intrinsic data type or at least also overload == to call .equals().  But that's just me.  I'm not sure if there's an equivalent to .ReferenceEquals in Java, and if not, it would be impossible to do the current implementation of ==.
November 23, 2005, 4:42 AM
iago
[quote author=MyndFyre link=topic=13143.msg135098#msg135098 date=1132720977]
[quote author=iago link=topic=13143.msg135092#msg135092 date=1132718434]
I totally agree that you shouldn't compare objects with '==', but the way String's are handled seems to make it look like you can. 
[/quote]
That's only because of the hack of overloading the + operator.  If Java supports overloaded operators in one class, then it should support them in all classes (of course, then it'd be C#).

Like I said before, the fact that "abc" == "a" + "b" + "c" is a compile-time optimization.  If you did something like:
[code]
String abc = "abc";
String def = "a";
def = def.concat("b");
def = def.concat("c");
System.out.println(abc==def);
[/code]

The compiler most likely won't optimize this out (although in theory it could since it's really only operating on constants... but you'd have to have a really smart compiler).

I still think that the way strings are native to Java should make them either an intrinsic data type or at least also overload == to call .equals().  But that's just me.  I'm not sure if there's an equivalent to .ReferenceEquals in Java, and if not, it would be impossible to do the current implementation of ==.
[/quote]

You're completely right.  But optimizations should be 100% invisible from the point of view of the programer.  This isn't really invisible, though, it does affect ==.  So it shouldn't be optimized like that, in my opinion. 
November 23, 2005, 5:14 AM
Kp
Alternately, they could've avoided this whole mess if they'd had a, c, d share the underlying data, but be three distinct String objects (each with a distinct address).  This would add another layer of indirection (and inefficiency), but Java advocates have a long history of accepting inefficiency and poor performance to uphold their language of choice.

Thus, == would only return true if you were truly comparing a reference to itself, not just comparing one String reference to another String reference (which by chance happened to have the same internal text and the optimizer proved this at compile time).  equals() is for deep comparisons.  == shouldn't be affected by the presence of a string-folding optimizer.
November 23, 2005, 6:21 AM

Search