Page 1 of 1

Rock paper scissors with classes and methods Rate Topic: -----

#1 CasiOo  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1391
  • View blog
  • Posts: 3,078
  • Joined: 05-April 11

Posted 26 June 2012 - 10:51 AM

This tutorial will teach you
  • How to create a Rock, Paper, Scissors game using classes and methods
  • How to make readable code using classes and methods


This tutorial will NOT teach you
  • How to make a class
  • How to make/call a method


I hope my tutorial will help you see the beauty in classes and method, and will be an inspiration for you to start using them. My tutorial gives a good example of a basic OO design, and java newcomers can hopefully learn a thing or two :)/>

I have created a basic Rock, Paper, Scissors game (like you haven't found out already!), and I will go through the code with you. I will do my best to try and explain what is going on in the code, but feel free to ask if you have any questions.

Lets get started!
Input & output
We want to start off with a console application, so all of out input and output will go through the console.
The class "IO" will be handling everything that has to do with input and output. It is important that the IO class ONLY will have one responsibility, which will be IO handling.

import java.util.Scanner;


public class IO {
	private Scanner scanner = new Scanner(System.in);
	
	/**
	 * Receive input from the user, and check the input against all of the allowed inputs.
	 * 
	 * @param message The message to show the user before taking input.
	 * @param possibleInputs All of the allowed inputs.
	 * @return Returns the first allowed input made by the user.
	 */
	public String getInput(String message, String... possibleInputs) {
		//Show the message
		printLine(message);
		
		//Loop as long as the user haven't entered an allowed input
		String input;
		while (true) {
			//Read input from our scanner
			input = scanner.nextLine();
			
			//If the input is allowed then break out of the while loop
			if (isAllowedInput(input, possibleInputs))
				break;
			else
				printLine("Invalid input!\n" + message);
		}
		
		return input;
	}
	
	/**
	 * Checks if 'input' is equal to one of the allowed inputs.
	 * 
	 * @param input Input made by the user.
	 * @param possibleInputs All allowed inputs.
	 * @return Returns true if the input is allowed.
	 */
	private boolean isAllowedInput(String input, String[] possibleInputs) {
		for (int i=0; i<possibleInputs.length; i++)
			if (input.equals(possibleInputs[i]))
				return true;
		return false;
	}
	
	/**
	 * Shows a message to the user through the console.
	 * 
	 * @param line The message to show.
	 */
	public void printLine(String line) {
		System.out.println(line);
	}
}



First of all we have the printLine method. The printLine method is simply a way to show a message to the user, and because we are making a console application, all we have to do is make a System.out.println :)/>

The next method isAllowedInput is also straight forward. We loop through the array and check if we have a match. If there is a match, then we return true to tell the input is allowed. After we have looped through our array, we are sure there is no match, therefore we return false to tell the input is not allowed.

The last method, getInput, is a little tricky! You might see something new here, and if you don't then why are you reading this tutorial anyway (you already know it all)?!
Lets start with the parameter
String... possibleInputs



Many experienced programmers haven't seen this before, and will say it is an error. Well it is not!
String... tells you that possibleInputs is an array, and should be treated that way. What makes String... special is that java will make your parameters (when you call the method) into an array by itself.
It requires an example:
//Input1, Input2, and Input3 will be made into an array!
io.getInput("Our message to show the user", "Input1", "Input2", "Input3");

//Here we call the method using a normal array instead
String[] array = { "Input1", "Input2", "Input3" };
io.getInput("Our message to show the user", array);



So lets move on with our code.
We see that we let the user make an input, then we check the input from the user. If the input is allowed, then we break out of the loop and returns the input, else we just continue looping asking for a new input.

Weapons!!!
Weapons yaaaaaaaay! :D/>

We know we will be needing three weapons: Rock, Paper, and Scissors.
The player would need one of these weapons, so we will be having a super class Weapon that all weapons should extend.


/**
 * The super class of all weapons.
 * All weapons should be able to be compared to another weapon to check which is strongest.
 */
public abstract class Weapon implements Comparable<Weapon> {
	
}



We would like to be able to compare the weapons against each other (to see who wins), and that is why the Comparable interface is implemented. We could as well had made a method ourselves named something like: beat(Weapon other)
The interface only has one method: compareTo(T other), where other is the object we want to compare ourself against.
The method should return 1 IF we are stronger than the other, we return -1 if we are weaker, and we return 0 if we are equally strong.
If there are new weapons added to the game, then you would have to edit the compareTo method of all weapons.

How it is implemented:
public class Paper extends Weapon {

	@Override
	public int compareTo(Weapon o) {
		if (o instanceof Paper)
			return 0;
		else if (o instanceof Rock)
			return 1;
		return -1;
	}
}



The players
The player classes are pretty straight forward. We want a player to be able to pick a weapon, and we want to know what weapon the player is wearing and the name of the player


public class Player {
	private IO io;
	private Weapon weapon;
	private String name;
	
	/**
	 * Initialize the player
	 * 
	 * @param io Class to use for all IO.
	 * @param name Name of this player.
	 */
	public Player(IO io, String name) {
		this.io = io;
		this.name = name;
	}
	
	/**
	 * It is our time to pick a weapon.
	 * After a call to this method, it is guaranteed that a weapon has been picked.
	 */
	public void pickWeapon() {
		//Get input from the player. Possible inputs are: Rock, Paper, or Scissors
		String input = io.getInput(name + " pick your weapon - Rock, Paper, or Scissors", "Rock", "Paper", "Scissors");
		
		switch (input) {
			case "Rock":
				weapon = new Rock();
				break;
			case "Paper":
				weapon = new Paper();
				break;
			default:
				weapon = new Scissors();
				break;
		}
	}
	
	/**
	 * @return Returns the weapon picked or null if yet to pick a weapon.
	 */
	public Weapon getWeapon() {
		return weapon;
	}
	
	/**
	 * @return Returns the name of this player.
	 */
	public String getName() {
		return name;
	}
}



The game class
This is where everything happens!
Our game is progressed from this class, and we also have some basic logic (since the game is small)


/**
 * The game class is responsible for any progress made in the game.
 * You should edit this class to change the flow of the game.
 * 
 * @author CasiOo
 *
 */
public class Game {
	private IO io;
	private Player player1, player2;
	
	public Game() {
		io = new IO();
	}
	
	/**
	 * This method starts the game and is responsible for any progress made in the game.
	 * 
	 * @param player1Start True if player1 will start the game, false if player2.
	 */
	public void startRound(boolean player1Start) {
		io.printLine("New round!");
		
		//Initialize the players, giving them a name and access to the IO class
		player1 = new Player(io, "Player 1");
		player2 = new Player(io, "Player 2");
		
		//Swap the players if player2 should start the round
		if (!player1Start)
			swapPlayers();
		
		//Let the players pick their weapon
		player1.pickWeapon();
		player2.pickWeapon();
		
		//Find the winner of the round
		findWinner();
		
		//Find out if we should play again
		if (playAgain())
			//Negate the boolean value to swap starting player
			startRound(!player1Start);
	}
	
	/**
	 * Find the winner of the round and congratulate them.
	 */
	private void findWinner() {
		//Compare the two weapons against each other to find out which is strongest
		int winner = player1.getWeapon().compareTo(player2.getWeapon());
		
		switch (winner) {
			case 1: //Player1's weapon beats player2's
				io.printLine(player1.getName() + " wins!");
				break;
			case -1: //Player2's weapon beats player1's
				io.printLine(player2.getName() + " wins!");
				break;
			case 0: //Draw
				io.printLine("Draw!");
				break;
		}
	}
	
	/**
	 * Will swap the two player references.
	 */
	private void swapPlayers() {
		Player temp = player1;
		player1 = player2;
		player2 = temp;
	}
	
	/**
	 * Checks if the two players want to play another round.
	 * 
	 * @return Returns true if we should play again.
	 */
	private boolean playAgain() {
		String input = io.getInput("Play again? - Y/N", "Y", "N");
		return input.equals("Y");
	}
}




We initialize the players and IO, but then we actually just use the classes and methods we have already made. The code is easy to maintain, and is highly readable (at least I think!).

Hopefully my javadoc and comments can explain most of what is going on.
I want to explain what is going on here:

int winner = player1.getWeapon().compareTo(player2.getWeapon());



Remember our Comparable interface? This is where we use it.
We get both of the weapons and compare one of them against the other, We do not need to call compareTo on both of them!



All of the code

public class Main {

	public static void main(String[] args) {
		new Game().startRound(true);
	}
}





/**
 * The game class is responsible for any progress made in the game.
 * You should edit this class to change the flow of the game.
 * 
 * @author CasiOo
 *
 */
public class Game {
	private IO io;
	private Player player1, player2;
	
	public Game() {
		io = new IO();
	}
	
	/**
	 * This method starts the game and is responsible for any progress made in the game.
	 * 
	 * @param player1Start True if player1 will start the game, false if player2.
	 */
	public void startRound(boolean player1Start) {
		io.printLine("New round!");
		
		//Initialize the players, giving them a name and access to the IO class
		player1 = new Player(io, "Player 1");
		player2 = new Player(io, "Player 2");
		
		//Swap the players if player2 should start the round
		if (!player1Start)
			swapPlayers();
		
		//Let the players pick their weapon
		player1.pickWeapon();
		player2.pickWeapon();
		
		//Find the winner of the round
		findWinner();
		
		//Find out if we should play again
		if (playAgain())
			//Negate the boolean value to swap starting player
			startRound(!player1Start);
	}
	
	/**
	 * Find the winner of the round and congratulate them.
	 */
	private void findWinner() {
		//Compare the two weapons against each other to find out which is strongest
		int winner = player1.getWeapon().compareTo(player2.getWeapon());
		
		switch (winner) {
			case 1: //Player1's weapon beats player2's
				io.printLine(player1.getName() + " wins!");
				break;
			case -1: //Player2's weapon beats player1's
				io.printLine(player2.getName() + " wins!");
				break;
			case 0: //Draw
				io.printLine("Draw!");
				break;
		}
	}
	
	/**
	 * Will swap the two player references.
	 */
	private void swapPlayers() {
		Player temp = player1;
		player1 = player2;
		player2 = temp;
	}
	
	/**
	 * Checks if the two players want to play another round.
	 * 
	 * @return Returns true if we should play again.
	 */
	private boolean playAgain() {
		String input = io.getInput("Play again? - Y/N", "Y", "N");
		return input.equals("Y");
	}
}




import java.util.Scanner;


public class IO {
	private Scanner scanner = new Scanner(System.in);
	
	/**
	 * Receive input from the user, and check the input against all of the allowed inputs.
	 * 
	 * @param message The message to show the user before taking input.
	 * @param possibleInputs All of the allowed inputs.
	 * @return Returns the first allowed input made by the user.
	 */
	public String getInput(String message, String... possibleInputs) {
		//Show the message
		printLine(message);
		
		//Loop as long as the user haven't entered an allowed input
		String input;
		while (true) {
			//Read input from our scanner
			input = scanner.nextLine();
			
			//If the input is allowed then break out of the while loop
			if (isAllowedInput(input, possibleInputs))
				break;
			else
				printLine("Invalid input!\n" + message);
		}
		
		return input;
	}
	
	/**
	 * Checks if 'input' is equal to one of the allowed inputs.
	 * 
	 * @param input Input made by the user.
	 * @param possibleInputs All allowed inputs.
	 * @return Returns true if the input is allowed.
	 */
	private boolean isAllowedInput(String input, String[] possibleInputs) {
		for (int i=0; i<possibleInputs.length; i++)
			if (input.equals(possibleInputs[i]))
				return true;
		return false;
	}
	
	/**
	 * Shows a message to the user through the console.
	 * 
	 * @param line The message to show.
	 */
	public void printLine(String line) {
		System.out.println(line);
	}
}





public class Player {
	private IO io;
	private Weapon weapon;
	private String name;
	
	/**
	 * Initialize the player
	 * 
	 * @param io Class to use for all IO.
	 * @param name Name of this player.
	 */
	public Player(IO io, String name) {
		this.io = io;
		this.name = name;
	}
	
	/**
	 * It is our time to pick a weapon.
	 * After a call to this method, it is guaranteed that a weapon has been picked.
	 */
	public void pickWeapon() {
		//Get input from the player. Possible inputs are: Rock, Paper, or Scissors
		String input = io.getInput(name + " pick your weapon - Rock, Paper, or Scissors", "Rock", "Paper", "Scissors");
		
		switch (input) {
			case "Rock":
				weapon = new Rock();
				break;
			case "Paper":
				weapon = new Paper();
				break;
			default:
				weapon = new Scissors();
				break;
		}
	}
	
	/**
	 * @return Returns the weapon picked or null if yet to pick a weapon.
	 */
	public Weapon getWeapon() {
		return weapon;
	}
	
	/**
	 * @return Returns the name of this player.
	 */
	public String getName() {
		return name;
	}
}





/**
 * The super class of all weapons.
 * All weapons should be able to be compared to another weapon to check which is strongest.
 */
public abstract class Weapon implements Comparable<Weapon> {
	
}





public class Paper extends Weapon {

	@Override
	public int compareTo(Weapon o) {
		if (o instanceof Paper)
			return 0;
		else if (o instanceof Rock)
			return 1;
		return -1;
	}
}





public class Rock extends Weapon {

	@Override
	public int compareTo(Weapon o) {
		if (o instanceof Rock)
			return 0;
		else if (o instanceof Scissors)
			return 1;
		return -1;
	}
}





public class Scissors extends Weapon {

	@Override
	public int compareTo(Weapon o) {
		if (o instanceof Scissors)
			return 0;
		else if (o instanceof Paper)
			return 1;
		return -1;
	}
}




Is This A Good Question/Topic? 0
  • +

Replies To: Rock paper scissors with classes and methods

#2 CasiOo  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1391
  • View blog
  • Posts: 3,078
  • Joined: 05-April 11

Posted 28 June 2012 - 03:35 PM

I have no idea why I implemented the swap player part, seems pretty unnecessary for this game :D

I should also mention that JDK 7 is required to run the code. The switch statements on Strings should be the only part not working in version 6 :)

This post has been edited by CasiOo: 28 June 2012 - 06:57 PM

Was This Post Helpful? 0
  • +
  • -

#3 hscribe  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 16
  • Joined: 22-July 12

Posted 25 July 2012 - 06:26 PM

I have run into a problem. The project requires Compiler Compliance of 5.0 or 6.0 (1.5 or 1.6), where the code itself requires 1.7 because of the "switch(input)" Any ideas? It's pretty aggrevating. Thanks for any help!!
Was This Post Helpful? 0
  • +
  • -

#4 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10477
  • View blog
  • Posts: 38,840
  • Joined: 27-December 08

Posted 25 July 2012 - 06:34 PM

I think CasiOo already answered this question. You need Java 7 to run this project.
Was This Post Helpful? 0
  • +
  • -

#5 hscribe  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 16
  • Joined: 22-July 12

Posted 28 July 2012 - 09:55 AM

Ok, now I'm getting more errors within the Main Class. First: The method main cannot be declared static; static methods can only be declared in a static or top
level type

shows up when public static void main(String[] args) is under it. When I add static to Public Class Main, I get

No enclosing instance of type Rock_Paper_Scissors is accessible. Must qualify the allocation with an
enclosing instance of type Rock_Paper_Scissors (e.g. x.new A() where x is an instance of
Rock_Paper_Scissors).

on the line with new Game().startRound(true);

I have no idea what the second one means, or how to fix it. I'm also not sure if I actually fixed the first problem or just appeased Eclipse. Any ideas? Here is my code.



import java.util.Scanner;


public class Rock_Paper_Scissors{
	
    public static class Main {
    	public static void main(String[] args){
    		new Game().startRound(true);
    	}
    }
	
	
	String message;
	
	private Scanner scanner = new Scanner(System.in);
	
	public String getInput(String ... possibleInputs){
	printLine(message);
	String input;
	
	while (true){
		input = scanner.nextLine();
		
		if(isAllowedInput(input, possibleInputs))
			break;
			else;
				printLine("Invalid Input! \n" + message);
	}
	return input;
	}
	
	
	private boolean isAllowedInput(String input, String[] possibleInputs){
	
		for(int i = 0; i<possibleInputs.length; i ++)
			if (input.equals(possibleInputs[i]))
				return true;
			return false;
	}
	
	
	public void printLine(String line){
		System.out.println(line);
	}

    //@Override
   /* public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_io);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_io, menu);
        return true;
    }
    */

    public abstract class Weapon implements Comparable<Weapon>{
    	
    }
    
    public class Paper extends Weapon{
    	public int compareTo(Weapon o){
    	if (o instanceof Paper)
    		return 0;
    	else if (o instanceof Rock)
    		return 1;
    	return -1;
    }
 }
    
    public class Rock extends Weapon{
    	public int compareTo(Weapon o){
    		if (o instanceof Rock)
    			return 0;
    		else if (o instanceof Scissors)
    			return 1;
    		return -1;
    	}
    }
    
    public class Scissors extends Weapon{
    	public int compareTo(Weapon o){
    		if (o instanceof Scissors)
    			return 0;
    		else if (o instanceof Paper)
    			return 1;
    		return -1;
    	}
    }
    public class Player{
    	private Rock_Paper_Scissors io;
    	private Weapon weapon;
    	private String name;
    	
    public Player (Rock_Paper_Scissors io, String name){
    	this.io = io;
    	this.name = name;
    }
    
    public void pickWeapon(){
    	String input = io.getInput(name + "Pick your weapon!  Rock, Paper, or Scissors!  Rock, Paper, Scissors!");
    	
    	if (input == "Rock"){
    		weapon = new Rock();
    	}
    	
    	if (input == "Paper"){
    		weapon = new Paper();
    	}
    	
    	if (input == "Scissors"){
    		weapon = new Scissors();
    	}
    	
    	
    	/*switch(input){
    	case "Rock":
    		weapon = new Rock();
    		break;
    	case "Paper":
    		weapon = new Paper();
    		break;
    	case "Scissors":
    		weapon = new Scissors();
    		break;
    	}
    	*/
    }
    public Weapon getWeapon(){
    	return weapon;
    }
    
    public String getName(){
    	return name;
    }
    
    }
    
    public class Game{
    	private Rock_Paper_Scissors io;
    	private Player player1, player2;
    	
    public Game(){
    	io = new Rock_Paper_Scissors();
    }
    
    public void startRound(boolean player1Start){
    	io.printLine("New Round");
    	
    	player1 = new Player(io, "Player 1");
    	player2 = new Player(io, "Player 2");
    	
    	if(!player1Start)
    		swapPlayers();
    	
    	player1.pickWeapon();
    	player2.pickWeapon();
    	
    	findWinner();
    	
    	if(playAgain())
    		startRound(!player1Start);
    }
    
    private void findWinner(){
    	int winner = player1.getWeapon().compareTo(player2.getWeapon());
    	
    	switch (winner){
    	case 1:
    		io.printLine(player1.getName() + " wins!");
    		break;
    	case 2:
    		io.printLine(player2.getName() + " wins!");
    		break;
    	case 0:
    		io.printLine("Draw!");
    		break;
    	}
    }
    
    private void swapPlayers(){
    	Player temp = player1;
    	player1 = player2;
    	player2 = temp;
    }
    
    private boolean playAgain(){
    	String input = io.getInput("Play Again? - Y/N", "Y", "N");
    	return input.equals("Y");
    		
    	}
    }
    
    }
    
    
    


Was This Post Helpful? 0
  • +
  • -

#6 kazisami  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 11
  • Joined: 24-July 12

Posted 28 July 2012 - 10:50 AM

Why did you put static in the main class, i really didn't understood. try removing static and see what happens
Was This Post Helpful? 0
  • +
  • -

#7 kazisami  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 11
  • Joined: 24-July 12

Posted 28 July 2012 - 11:27 AM

Try separating your main class and don't put static before it. It will be better to make every class separate, but if you want to make the other classes nested except main, then remove public(any access specifier) before them, then it should compile. but make sure you put them in the same directory.
Was This Post Helpful? 0
  • +
  • -

#8 hscribe  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 16
  • Joined: 22-July 12

Posted 28 July 2012 - 04:26 PM

I'm not sure I'm following. When I put my main class outside the Rock_Paper_Scissors class, it tells me it must be defined in its own file.
Was This Post Helpful? 0
  • +
  • -

#9 kazisami  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 11
  • Joined: 24-July 12

Posted 28 July 2012 - 06:10 PM

Yes, make Main a separate class, cut all the code of main and paste them in a new file. Name that file Main.java and make sure Main.java and your other classes are on the same folder/directory.
Was This Post Helpful? 0
  • +
  • -

#10 hscribe  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 16
  • Joined: 22-July 12

Posted 28 July 2012 - 06:32 PM

Ok, I did that. Now I get Game can't be resolved as a Type error.
Was This Post Helpful? 0
  • +
  • -

#11 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10477
  • View blog
  • Posts: 38,840
  • Joined: 27-December 08

Posted 28 July 2012 - 06:49 PM

Each class goes in its own .java File. Compile each class. You shouldn't get any errors. I set this project up fine when reviewing this tutorial, with no problems. If you can't figure out how to copy/paste each class in its own file and compile them, you might want to start with something more basic like Hello, World.
Was This Post Helpful? 0
  • +
  • -

#12 hscribe  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 16
  • Joined: 22-July 12

Posted 29 July 2012 - 12:04 PM

I started over, and I copy and pasted all the classes into their own file, verbatum what is in the tutorial. It runs until after the Player 2 chooses a weapon, and I get this error:
Exception in thread "main" java.lang.NullPointerException
at Game.findWinner(Game.java:52)
at Game.startRound(Game.java:37)
at Main.main(Main.java:4)

I googled it and found that it means there's a variable on those lines with a null value. One line is just "findWinner();" and the other is new Game().startRound(true); I don't see any obvious variables that are null.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1