How to change my code to make it more efficient? - java

in this code is playing Rock Paper Scissors, between the computer and the user. My code is all working great, however, I'm trying to think of a better way to make it ask the user if they would want to play again. If yes, then it would start the program again, if no, then it would stop. My "yes" seems to work but the no will stop and not go through all the way. Any suggestions or tips on how to do this? I will trying to incorporate a different while loop, but wasn't working. Would a do loop be good for this scenario? Thanks!
//import scanner
import java.util.Scanner;
import java.util.*;
//declare variables and main methods
class Rock {
Scanner scan = new Scanner(System.in);
Random generator = new Random();
String response, name;
char choice;
int rounds, computerChoice, userScore, computerScore;
boolean playIntro = true;
boolean playGame = true;
//this method will run the entire progrma
public void playRPS(){
//while loop for beginning of game
while(playIntro){
System.out.println("This is a game of Rock Paper Scissors!");
System.out.println("Please enter your name: ");
name = scan.nextLine();
//while loop for the actual part of the game
while(playGame){
System.out.println("Type R (Rock), P (Paper), or S (Scissors): ");
choice = scan.nextLine().charAt(0);
computerChoice = generator.nextInt(3)+1;
//using switch and case for each choice
switch (choice){
//case for Rock
case 'R':
if(computerChoice==1){
System.out.println("Tie between you and the computer! Go again.");
break;
}
else{
if(computerChoice==2){
System.out.println("The computer beat you this round");
computerScore++;
break;
}
else{
System.out.println("You won this round");
userScore++;
break;
}
}
//case for Paper
case 'P':
if(computerChoice==2){
System.out.println("Tie between you and the computer! Go again.");
break;
}
else{
if(computerChoice==3){
System.out.println("The computer beat you this round");
computerScore++;
break;
}
else{
System.out.println("You won this round");
userScore++;
break;
}
}
//case for Scissors
case 'S':
if(computerChoice==3){
System.out.println("Tie between you and the computer! Go again.");
break;
}
else{
if(computerChoice==1){
System.out.println("The computer beat you this round");
computerScore++;
break;
}
else{
System.out.println("You won this round");
userScore++;
break;
}
}
}
System.out.println("You have "+userScore+" points and the computer has "+computerScore+" points");
if (userScore==5){
System.out.println("\nOut of 5 rounds, You beat the computer!");
playGame = false;
}
else if (computerScore==5){
System.out.println("\nOut of 5 rounds, The computer beat you.");
playGame = false;
}
}
askUser();
}
}
public void askUser(){
System.out.println("\nDo you want to play this Rock Paper Scissors again? Type yes: ");
response = scan.nextLine();
if (response.equalsIgnoreCase("yes")){
playGame = true;
userScore=0;
computerScore=0;
}
else{
playGame = false;
scan.nextLine();
}
}
public static void main() {
Rock prog = new Rock();
prog.playRPS();
}
}

I wouldn't say this is necessarily more efficient or even better but it is a little more concise. It's major elements are.
use Lambdas to decide the winner based on the chosen move.
use a map to call the proper Lambda based on the user's move. The lambda then evaluates the two moves to decide the outcome.
for simplicity, moves are selected by number
Of course, the important thing is that your code works.
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Scanner;
import java.util.Set;
import java.util.function.Function;
public class RockPaperScissors {
final static int PAPER = 1;
final static int ROCK = 2;
final static int SCISSORS = 3;
// the next two declarations allows the previous three to take on any values.
private Set<Integer> allowedMoves = Set.of(PAPER, ROCK, SCISSORS);
private List<String> moves = List.of("PAPER", "ROCK", "SCISSORS");
private String ROCK_WINS_MSG = "Rock crushes scissors";
private String SCISSORS_WINS_MSG = "Scissors cuts paper";
private String PAPER_WINS_MSG = "Paper covers rock";
private String COMPUTER_WINS = ", computer wins!";
private String YOU_WIN = ", you win!";
private Function<Integer, String> CHECK_PAPER =
(c) -> c == PAPER ? "It's a tie!" :
c == ROCK ? PAPER_WINS_MSG + YOU_WIN :
SCISSORS_WINS_MSG + COMPUTER_WINS;
private Function<Integer, String> CHECK_ROCK =
(c) -> c == ROCK ? "It's a tie!" :
c == SCISSORS ? ROCK_WINS_MSG + YOU_WIN :
PAPER_WINS_MSG + COMPUTER_WINS;
private Function<Integer, String> CHECK_SCISSORS =
(c) -> c == SCISSORS ? "It's a tie!" :
c == PAPER ? SCISSORS_WINS_MSG + YOU_WIN :
ROCK_WINS_MSG + COMPUTER_WINS;
private Map<Integer, Function<Integer, String>> evalUser =
Map.of(PAPER, CHECK_PAPER, ROCK, CHECK_ROCK, SCISSORS,
CHECK_SCISSORS);
public static void main(String[] args) {
new RockPaperScissors().play();
}
public void play() {
Random r = new Random();
Scanner scan = new Scanner(System.in);
while (true) {
System.out.printf("%n%d : %s%n%d : %s%n%d : %s%n%s%n",
PAPER, "PAPER", ROCK, "ROCK", SCISSORS,
"SCISSORS", "Any other integer to quit.");
System.out.print("Your move! ");
String str = scan.nextLine();
int move;
try {
move = Integer.parseInt(str);
if (!allowedMoves.contains(move)) {
break;
}
} catch (IllegalArgumentException ie) {
System.out.println("Only integers permitted.");
continue;
}
System.out.println("\nYou chose " + moves.get(move - 1));
int cmove = r.nextInt(3);
System.out.println(
"The computer chooses " + moves.get(cmove));
System.out.println(evalUser.get(move).apply(cmove + 1));
}
System.out.println("\nGame over!");
}
}
Once suggestion for your code would be to look at the switch cases. The code for each case is practically identical. I would look for similarities and make the evaluation a single method (something I didn't really do in my code). Then in each case, call that method with the appropriate arguments. One such argument would be either "computer" or "you" based on the context.

There's nothing that ever sets playIntro false, and therefore the outer loop will never terminate.
When askUser() sets playGame false the inner loop terminates, and you fall into the outer loop, which keeps on looping.
I don't see any reason for the outer loop to exist at all. You only want to print the introduction and ask the player's name once.
This isn't so much a matter of 'efficiency' as of correctness.
Incidentally, it would be better to make askUser() return a true/false value rather than set a member variable. Then you can use it directly in a 'while' expression.
The overall structure of playRPS() then looks like:
public void playRPS() {
... print intro, ask name ...
do {
... play one game ...
} while (askUser());
}

Related

Java: Rock Paper Scissors game loop

I'm trying to get this loop to work, but can't get it figured out, tried a few different kinds and haven't had any luck, gone back through some of my studying and poked around to try to get some insight but haven't been able to successfully get it to work. the base program code is as follow, basically this was a project i did a few weeks ago, and a new project wants us to go back in and have it so the game continuously plays until the user inputs a "3". I can't figure it out, I can't seem to find any examples or help online. I'm not looking for someone to just give an answer, just looking for a nudge in the right direction.
TL;DR: the game should repeat until the user inputs 3
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("scissor (0), rock (1), paper (2): ");
int user = input.nextInt();
int computer = (int) (Math.random() * 3);
System.out.print("The Computer is ");
switch (computer) {
case 0:
System.out.print("scissor. ");
break;
case 1:
System.out.print("rock. ");
break;
case 2:
System.out.print("paper. ");
}
System.out.print(" You are ");
switch (user) {
case 0:
System.out.print("scissor");
break;
case 1:
System.out.print("rock");
break;
case 2:
System.out.print("paper");
}
if (computer == user) {
System.out.println(" too. It is a draw");
} else {
boolean win = (user == 0 && computer == 2)
|| (user == 1 && computer == 0)
|| (user == 2 && computer == 1);
if (win) {
System.out.println(". You won!");
} else {
System.out.println(". You lose!");
}
}
}
}
You can put all your code in your main method into an infinite loop and exit the program when the user inputs 3 like this.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
while(true) { //start of the loop
Scanner input = new Scanner(System.in);
//setting the variable to an incorrect value,
//so the text is printed always at least once
int user = -1;
//while the input is incorrect (lower than 0 or higher than 3)
while(user < 0 || user > 3) {
//ask for the input
System.out.print("scissor (0), rock (1), paper (2), exit (3): ");
//try reading an integer, as the user might input whatever (String, float,..)
try {
user = input.nextInt(); //trying to read an integer
} catch (Exception e) { //in case of an invalid input (not an integer)
//I still want to "read" the tokens,
//because the .nextInt() did not process the input
input.next();
}
if (user == 3) System.exit(0);
}
//rest of your code
} //end of the loop
}
You can see, that I used try and catch to check for other inputs than an integer. I also repeat asking for the input until it is valid. You might not necessarily need that if it is not part of your focus right now and exchange it just for the following.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
while(true) { //start of the loop, loops forever unless the user inputs 3
Scanner input = new Scanner(System.in);
System.out.print("scissor (0), rock (1), paper (2): ");
int user = input.nextInt(); //trying to read an integer
if (user == 3) System.exit(0); //if the input is 3, exit the program
//rest of your code
} //end of the loop
}
Your code has no loops at all, though.
You can use the while construct, or the do/while construct, which is quite similar:
boolean playing = true;
while (playing) {
... all the code you currently have ....
}
would keep looping; until you set playing to false, of course, which you can do when the user enters 3.

Java rock paper scissor printing the statements oddly

So here i am trying to create a program that takes an input as an int and then plays a game of Rock paper scissors. It seems to want to reprint statements that it shouldn't be and is skipping printing statements as well. I would love some assistance if possible. I have tried setting up print statements everywhere but it has just been more confusing.
import java.util.Scanner;
public class RPSS{
//Main method
public static void main(String[ ] argc)
{
System.out.println("Lets play rock paper scissors");
Scanner tnt = new Scanner(System.in);
String computerHand; // string variable for computer choice
String userHand; // string variable for user choice
//
String answer = "";
while (!a
nswer.equals("No") && (!answer.equals("no"))){
userHand = userHand();
computerHand = computerHand();
System.out.println("The User picks " + userHand + " " );
System.out.print("The Computer picks " + computerHand );
String winner = getWinner(computerHand, userHand);
System.out.println(winner);
System.out.println("play again?");
answer = tnt.next();
}
//Condition for the do-while loop
}
public static String userHand(){ //method for users choice in the game
//prints message to user giving them choices
System.out.println(" ");
System.out.println("1. Rock ");
System.out.println("2. Paper ");
System.out.println("3. Scissors ");
int userChoice; // user choice variable in this method
Scanner tnt = new Scanner(System.in); // creates instance of scanner class
userChoice = tnt.nextInt(); //reads user input
return getChoice(userChoice); //returns user choice to userChoice
}
public static String computerHand() //method for computer generated choice
{
int computernum = 1 + (int)(Math.random() * (( 2) +1));
return getChoice(computernum);
}
public static String getChoice(int num) //method recieving both computer hand and user hand
{
// if statements to place the correct choice
String choice = "";
if (num == 1){
choice = "Rock";
}
else if(num == 2){
choice = "Paper";
}
else if(num == 3){
choice = "Scissors";
}
return choice;
}
// Method determing the winner
public static String getWinner(String computerChoice, String userChoice)
{
computerChoice = computerHand(); //places computerChoice variable in computerhand
userChoice = userHand(); //does same for user choice
String winner="";
if (userChoice.equals("Rock") && computerChoice.equals("Paper")){
System.out.println("The computer wins");
return winner;
}
else if (userChoice.equals("Paper") && computerChoice.equals("Scissors")){
System.out.println(" The computer wins");
return winner;
}
else if (userChoice.equals("Scissors") && computerChoice.equals("Rock")){
System.out.println(" The computer wins ");
return winner;
}
else if (userChoice.equals("Rock") && computerChoice.equals("Paper")){
System.out.println(" The computer wins ");
return winner;
}
else if(userChoice.equals(computerChoice))
{
System.out.println(" There is no winner");
return " ";
}
else{
return winner;
}
}
}
The first problem is that userhand() and computerHand() are being called twice per "round", once at the beginning of the while loop inside the main method and once at the beginning of the getWinner() method. Elimination of the calls at the beginning of the getWinner() method should solve the repeats.
The 2nd Problem is that instead of modifying the value of winner inside the getWinner() method before returning it, you are you are simply outputting the message via println(). an example of fixing this would be converting this:
if (userChoice.equals("Rock") && computerChoice.equals("Paper"){
System.out.println("The computer wins");
return winner;
}
to this:
if (userChoice.equals("Rock") && computerChoice.equals("Paper")){
winner = "The computer wins";
return winner;
}
another minor issue is the fact that
userChoice.equals("Rock") && computerChoice.equals("Paper")
is checked twice, id just remove the entire if else block based around the
2nd check of it
Lastly i would treat the final else clause as the player wins one and set winner to something like " The player wins "

Java Do While isn't working properly

Sorry I am new to this site so not sure how this will show up. I am trying to make a simple Rock, Paper, Scissors game. After the while statement, if R, P, S isn't entered, the program just does nothing. I want it to loop back to the question at the beginning so a right choice can be entered. Also, how would I enter a print statement like "Invalid Choice Please Retry"?
package rps.gameapp;
import java.util.Scanner;
public class RPSGameApp
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
String userChoice;
String playAgain;
int randNum = (int) (Math.random() * 3);
do
{
System.out.println("Welcome to Rock, Paper, Scissors Game.");
System.out.println("Pick R, P, or S.");
userChoice = sc.nextLine();
while (!userChoice.equalsIgnoreCase("P")
&& !userChoice.equalsIgnoreCase("R")
&& !userChoice.equalsIgnoreCase("S"));
String compChoice = "";
switch (randNum)
{
case 0:
compChoice = "R";
break;
case 1:
compChoice = "P";
break;
case 2:
compChoice = "S";
break;
}
System.out.println("The computer entered \"" + compChoice + "\".");
if (compChoice.equalsIgnoreCase(userChoice))
{
System.out.println("Draw");
} else if (userChoice.equalsIgnoreCase(userChoice)
&& compChoice.equalsIgnoreCase("S")
|| userChoice.equalsIgnoreCase("P")
&& compChoice.equalsIgnoreCase("R")
|| userChoice.equalsIgnoreCase("S")
&& compChoice.equalsIgnoreCase("P"))
{
System.out.println("User Wins");
} else
{
System.out.println("User Loses");
}
System.out.print(
"Do you want to play again? (Y/N)");
playAgain = sc.nextLine();
} while (playAgain.equalsIgnoreCase("Y"));
System.out.println("Thanks for Playing!");
}
}
It looks like you forgot one do for your inner do while loop.
It should be :
do {
do {
System.out.println("Welcome to Rock, Paper, Scissors Game.");
System.out.println("Pick R, P, or S.");
userChoice = sc.nextLine();
} while (!userChoice.equalsIgnoreCase("P") && !userChoice.equalsIgnoreCase("R") && !userChoice.equalsIgnoreCase("S"));
...
} while (playAgain.equalsIgnoreCase("Y"));
Without that inner do (and the curly braces surrounding that loop's body), the inner loop becomes a while loop with an empty body.
Like Eran said, you need to wrap your do-while loop in another loop, that will keep asking user for correct input. This is fully working code. One thing that could be better is the message after user inputs wrong letter.
Edit: also make sure you draw random number for every iteration.
Edit 2: to change the message depending on user input you can introduce a new variable that will keep the track of number of times you asked user for correct input. If it is 0- it means user is asked the first time and we should print "Welcome" message. It is anything other than 0- you need to ask the user for correct input. After every round we assign zero to the variable again and the cycle repeats. I have implemented this change in the code. Note that this variable can also be a boolean.
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String userChoice;
String playAgain;
int iterationNumber;
while (true) {
iterationNumber = 0;
do {
if (iterationNumber == 0) {
System.out.println("Welcome to Rock, Paper, Scissors Game.");
System.out.println("Pick R, P, or S.");
} else {
System.out.println("Please enter valid letter.");
System.out.println("Pick R, P, or S.");
}
iterationNumber++;
userChoice = sc.nextLine();
} while (!userChoice.equalsIgnoreCase("P")
&& !userChoice.equalsIgnoreCase("R")
&& !userChoice.equalsIgnoreCase("S"));
String compChoice = "";
int randNum = (int) (Math.random() * 3);
switch (randNum) {
case 0:
compChoice = "R";
break;
case 1:
compChoice = "P";
break;
case 2:
compChoice = "S";
break;
}
System.out.println("The computer entered \"" + compChoice + "\".");
if (compChoice.equalsIgnoreCase(userChoice)) {
System.out.println("Draw");
} else if (userChoice.equalsIgnoreCase("R")
&& compChoice.equalsIgnoreCase("S")
|| userChoice.equalsIgnoreCase("P")
&& compChoice.equalsIgnoreCase("R")
|| userChoice.equalsIgnoreCase("S")
&& compChoice.equalsIgnoreCase("P")) {
System.out.println("User Wins");
} else {
System.out.println("User Loses");
}
System.out.print(
"Do you want to play again? (Y/N)");
playAgain = sc.nextLine();
if (playAgain.equalsIgnoreCase("N")) {
break;
}
iterationNumber = 0;
}
System.out.println("Thanks for Playing!");
}

A way to reset program on cmd?

I wrote a simlpe dice game and would like to know a way to reset the program after typing something like "Reset". I use cmd to run my programs. There is no graphics included in any of my programs whatsoever.
import java.util.Scanner;
import java.util.Random;
public class Dice
{
public static void main(String[] args)
{
String personPlay; //User's play
String computerPlay = ""; //Computer's play
int computerInt; //Randomly generated number used to determine computer's play
String response;
Scanner scan = new Scanner(System.in);
Random generator = new Random();
System.out.println("Let's play some dice!");
//Generate computer's play
computerInt = generator.nextInt(6)+1;
//Translate computer's randomly generated play to
//string using if statements
if (computerInt == 1)
computerPlay = "1";
else if (computerInt == 2)
computerPlay = "2";
else if (computerInt == 3)
computerPlay = "3";
else if (computerInt == 4)
computerPlay = "4";
else if (computerInt == 5)
computerPlay = "5";
else if (computerInt == 6)
computerPlay = "6";
//Get player's play from input
System.out.println("Choose a number between 1 and 6.");
personPlay = scan.next();
//Print computer's play
System.out.println("The dice rolled " + computerPlay);
//See if you won.
if (personPlay.equals(computerPlay))
System.out.println("You won!");
else System.out.println("You lost!");
}
}
You should use an infinite loop and get input from user, check if user entered "RESET", if so roll the dice again or do whatever you're doing now.
If he entered a phrase like "EXIT" infinite loop ends or your program ends.
Usually I don't like giving full answers, but there are some improvements I wanted to show and just listing them would be a lot of work as well.
import java.util.Scanner;
import java.util.Random;
public class Dice
{
private static void play(Scanner scan, Random generator)
{
int computersPlay, usersPlay;
System.out.println("Let's play some dice!");
computersPlay = generator.nextInt(6) + 1;
System.out.print("Give a number:");
usersPlay = scan.nextInt();
System.out.printf("The dice rolled %d\n", computerPlay);
if (computersPlay == usersPlay) {
System.out.println("You win !");
}
else {
System.out.println("You lose!");
}
}
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
Random generator = new Random();
do {
play(scan, generator);
System.out.println("If you want to continue type:'Reset'");
} while(scan.next().equals("Reset");
}
}
Changes moving the play to a different method to keep oversight, using the Scanners nextInt method to obtain a number directly and compare that instead, and the do {} while(); statement to let it repeat an arbitrary amount of times (given that you type reset)
By "reset" I assume you meant "repeat"? Use a while loop.
Also, no real need to store String values other than capture what the user entered.
public class DiceGuess {
// Global variables for this class
static Random generator = new Random();
static Scanner scan = new Scanner(System.in);
public static void main(String[] args) {
System.out.println("Let's play some dice!");
// Initialize some variables
int computerInt;
String response;
while (true) { // Play forever
computerInt = generator.nextInt(6) + 1;
System.out.println("Choose a number between 1 and 6. ('quit' to stop playing)");
response = scan.nextLine();
if (response.equalsIgnoreCase("quit")) break; // Stop the game
try {
System.out.println("The dice rolled " + computerInt);
if (Integer.parseInt(response) == computerInt) {
System.out.println("You won!");
} else {
System.out.println("You lost!");
}
} catch (NumberFormatException e) {
System.err.println("That wasn't a number!");
}
}
}
}

RPS game making it say invalid error

I made this Rock Paper scissors game but i cnt figure out how to make it show invalid error when the user enters something other than R,P,S. It would be helpful if any once could tell me how to make it so that it does this. Im a relatively new coder. Thanks in advance for all your help
import java.util.Random;
import java.util.Scanner;
public class RPS {
public static void main(String[] args)
{
String userPlay; //User's play -- "R", "P", or "S"
String computerPlay = ""; //Computer's play -- "R", "P", or "S"
int computerInt;
String response;
Scanner scan = new Scanner(System.in);
Random generator = new Random();
System.out.println("Lets play Rock, Paper, Scissors!\n" +
"Choose your move.\n" + "Rock = R, Paper" +
"= P, and Scissors = S.");
System.out.println();
//Generate computer's play (0,1,2)
computerInt = generator.nextInt(3)+1;
//Translate computer's randomly generated play to
//string using if //statements
if (computerInt == 1)
computerPlay = "R";
else if (computerInt == 2)
computerPlay = "P";
else if (computerInt == 3)
computerPlay = "S";
//Get player's play from input-- note that this is r
System.out.println("Enter your play: ");
userPlay = scan.next();
//Make player's play uppercase
userPlay = userPlay.toUpperCase();
//Print computer's play
System.out.println("Your opponents play is: " + computerPlay);
//See who won.
if (userPlay.equals(computerPlay))
System.out.println("It's a tie!");
else if (userPlay.equals("R"))
if (computerPlay.equals("S"))
System.out.println("Rock breaks scissors. You win!!");
else if (computerPlay.equals("P"))
System.out.println("Paper covers rock. You lose!!");
else if (userPlay.equals("P"))
if (computerPlay.equals("S"))
System.out.println("Scissor cuts paper. You lose!!");
else if (computerPlay.equals("R"))
System.out.println("Paper covers rock. You win!!");
else if (userPlay.equals("S"))
if (computerPlay.equals("P"))
System.out.println("Scissor cuts paper. You win!!");
else if (computerPlay.equals("R"))
System.out.println("Rock breaks scissors. You lose!!");
else
System.out.println("Invalid user input.");
}
}
I think the best way to do it is with loop. You ask to enter player's move, if it is unacceptable you ask again. You continue it until user enters valid string. In code it will look like this
//Get player's play from input
boolean moveOk = false;
while (moveOk == false) {
System.out.println("Enter your play: ");
userPlay = scan.next();
//Make player's play uppercase
userPlay = userPlay.toUpperCase();
// check that the input is ok
if ("R".equals(userPlay) ||
"P".equals(userPlay) ||
"S".equals(userPlay)) {
moveOk = true;
} else {
System.out.println("Bad input, try again!");
}
}
If you want to show error and then stop the program, instead of creating the loop you can use simple if with similar condition and when input is incorrect print error message and use return.
Also you could make your code easier to understand if you divide your conditions in parts, for example by user input. See example below.
//See who won.
String result = "";
if (userPlay.equals(computerPlay)) {
result = "It's a tie!";
}
if (userPlay.equals("R")) {
if (computerPlay.equals("S")) {
result = "Rock breaks scissors. You win!!";
}
if (computerPlay.equals("P")) {
result = "Paper covers rock. You lose!!";
}
}
if (userPlay.equals("P")) {
if (computerPlay.equals("S")) {
result = "Scissor cuts paper. You lose!!";
}
if (computerPlay.equals("R")) {
result = "Paper covers rock. You win!!";
}
}
if (userPlay.equals("S")) {
if (computerPlay.equals("P")) {
result = "Scissor cuts paper. You win!!";
}
if (computerPlay.equals("R")) {
result = "Rock breaks scissors. You lose!!";
}
}
System.out.println(result);
Also you could use switch statement.

Categories