Because I have a thread and in my main program I want to create multiple threads of the same thing and I don't want the same name I tried to create unique names for each thread, e.g Player_1, Player_2, etc.
The thing is that it throws Duplicate local variable which I know that is because I use the same variable but I don't know how else I can create multiple names for a thread without me writing them. Here is the code.
Original Question
for (int l=0; l < noPlayers; l++){
String name = P + "" + (l + 1);
System.out.println(name);
Player name = new Player(TURN);
}
*The Player is the thread which extends and TURN is just a variable that will be processed.
Updated Question
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Scanner;
class Referee extends Thread{
}
class Player extends Thread{
private int TURN;
public Player(int TURN) {
this.TURN = TURN;
}
public void run(){
int win = 0;
int lose = 0;
int draw = 0;
boolean k = true;
int j = 0;
for (j=0;j<=TURN;j++){
String [] arr = {"ROCK", "PAPER", "SCISSORS"};
Random Pick = new Random();
// randomly selects an index from the arr
int select = Pick.nextInt(arr.length);
// prints out the value at the randomly selected index
System.out.println("Random String selected: " + arr[select]);
}
}
}
public class MainApp {
public static void main(String[] args) {
int TURN = 0;
int No_Players = 0;
int i=0;
boolean h= true;
int j=0;
boolean k = true;
System.out.println("Welcome to Rock-paper-scissors, this is a tutorial of threads");
Scanner number = new Scanner( System.in );
System.out.println("Insert the number of players that will play");
while (h){
while (!number.hasNextInt()){
System.out.println("You didnt insert a number please try again");
number.next();
}
if(number.hasNextInt()){
j = number.nextInt();
if(j>1){
No_Players = j;
h=false;
}
else {
System.out.println("You need a value bigger than 1");
}
}
}
System.out.println("Please enter how many turns you want each player to play");
while (k){
while (!number.hasNextInt()){
System.out.println("You didnt insert a number please try again");
number.next();
}
if(number.hasNextInt()){
i = number.nextInt();
if(i>0){
TURN = i;
k=false;
}
else {
System.out.println("You need a value bigger than 0");
}
}
}
System.out.println("This game will have " + No_Players +" players and each one will have " + TURN + " turns");
Map<String,Thread> map = new HashMap<>();
for (int l = 0; i < No_Players; ++i) {
String name = "Player_" + i;
Player player = new Player(TURN);
player.setName(name);
map.put(name, player);
player.start();
}
}
}
**Posted the whole code because of some misunderstandings.
Assuming that Player implements Runnable.
Map<String,Thread> map = new HashMap<>();
for (int i = 0; i < numPlayers; ++i) {
String name = "Player_" + i;
Player player = new Player(TURN);
Thread t = new Thread(player):
t.setName(name);
map.put(name, t);
t.start();
}
You can then retrieve the thread by the player name. You can also add a thread group if desired.
Based upon a comment that Player extends Thread (edit: fixed the Map definition to use Player rather than Thread).
Map<String,Player> map = new HashMap<>();
for (int i = 0; i < numPlayers; ++i) {
String name = "Player_" + i;
Player player = new Player(TURN);
player.setName(name);
map.put(name, player);
// thread may need to be started elsewhere depending upon the requirement
player.start();
}
Elsewhere to get the particular Player, just do:
Player p = map.get(playerName);
Based upon a comment, here is working example that show Player, extending Thread, using the Map suggested above, and displaying the players using the .getName() method on a Player object.
public class TestPlayer
{
public TestPlayer()
{
}
public static void main(String[] args)
{
int numPlayers = 5;
Map<String,Player> map = new HashMap<>();
for (int i = 0; i < numPlayers; ++i) {
String name = "Player_" + i;
Player player = new Player(0);
player.setName(name);
map.put(name, player);
// thread may need to be started elsewhere depending upon the requirement
player.start();
}
for (Player p : map.values()) {
System.out.println("Found player : " + p.getName());
}
}
static class Player extends Thread
{
private int turn;
public Player(int turn)
{
this.turn = turn;
}
#Override
public void run()
{
System.out.println("Running player " +
Thread.currentThread().getName() +
" turn " + this.turn);
}
}
}
Output:
Running player Player_1 turn 0
Running player Player_3 turn 0
Running player Player_0 turn 0
Running player Player_2 turn 0
Running player Player_4 turn 0
Found player : Player_3
Found player : Player_2
Found player : Player_4
Found player : Player_1
Found player : Player_0
Related
So I'm writing a basic MasterMind game that is... mostly functional. However, its exhibiting odd behavior and I'm unsure why.
The idea is that what defines a Code and its behavior is one file, the gameplay is another, and the Main just creates a new game and starts playing. When I initialize the game, the computer creates a new random string of 4 (the "secret code"), as expected; but then once I get input for the User guess, it seems to rewrite the secret code into whatever I've input. Further, my methods for evaluating matches don't work at all, but considering that the secret code keeps changing means that it's not being set to begin with, and I'm unsure why.
All three classes below. Why is my class variable in Game not setting properly and accessible to the other methods?
Main.java
class Main {
public static void main(String[] args) {
Game newGame = new Game();
newGame.play();
}
}
Code.java
import java.util.Random;
import java.util.HashMap;
import java.util.Collection;
import java.util.ArrayList;
import java.util.Set;
import java.lang.Math;
import java.lang.StringBuilder;
class Code {
private static HashMap<String,String> PEGS;
private static ArrayList<String> pegStrings;
protected static String secretCodeString;
public static void main(String[] args) {
}
public Code(String input){
this.secretCodeString = input;
}
public Code(){
randomize();
}
//literally just creates the peghash
public static void setPegs(){
PEGS = new HashMap<String,String>();
PEGS.put("C","c");
PEGS.put("Y","y");
PEGS.put("R","r");
PEGS.put("P","p");
PEGS.put("O","o");
PEGS.put("G","g");
}
//turns the pegs ito something randomize can use
public static ArrayList<String> makePegArray(){
setPegs();
pegStrings = new ArrayList<String>();
Collection<String> pegValues = PEGS.values();
Object[] pegObjects = pegValues.toArray();
for (int i = 0; i < pegObjects.length; i++){
pegStrings.add(pegObjects[i].toString());
}
return pegStrings;
}
// sets Class Variable secretCode to a four letter combination
public static Code randomize(){
secretCodeString = new String();
Random rand = new Random();
int randIndex = rand.nextInt(makePegArray().size());
for (int i = 0; i < 4; i++){
randIndex = rand.nextInt(makePegArray().size());
secretCodeString = secretCodeString.concat(makePegArray().get(randIndex));
}
Code secretCode = parse(secretCodeString);
return secretCode;
}
public static Code parse(String input) {
setPegs();
makePegArray();
String[] letters = input.split("");
StringBuilder sb = new StringBuilder();
for (String letter : letters) {
if (pegStrings.contains(letter)) {
sb.append(letter);
} else {
System.out.println(letter);
throw new RuntimeException();
}
}
String pegListString = sb.toString();
Code parsedCode = new Code(pegListString);
//System.out.println(parsedCode);
return parsedCode;
}
public int countExactMatches(Code guess){
String guessString = guess.secretCodeString;
int exactMatches = 0;
String[] guessArray = guessString.split("");
String[] winningCodeArray = (this.secretCodeString).split("");
for(int i = 0; i < 4; i++){
if(guessArray[i] == winningCodeArray[i]){
exactMatches++;
}
}
return exactMatches;
}
public int countNearMatches(Code guess) {
String guessString= guess.secretCodeString;
HashMap<String,Integer> guessCount = new HashMap<String,Integer>();
HashMap<String,Integer> secretCodeCount = new HashMap<String,Integer>();
Set<String> codeKeys = guessCount.keySet();
int matches = 0;
int keys = guessCount.keySet().size();
String[] keyArray = new String[keys];
for(int i = 0; i < guessString.length(); i++) {
//removes character from string
String codeCharacter = String.valueOf(guessString.charAt(i));
String guessShort = guessString.replace(codeCharacter,"");
//counts instances of said character
int count = guessString.length() - guessShort.length();
guessCount.put(codeCharacter, count);
}
for(int i = 0; i < secretCodeString.length(); i++) {
//removes character from string
String winningString = this.secretCodeString;
String winningCodeCharacter = String.valueOf(winningString.charAt(i));
String winningCodeShort = guessString.replace(winningCodeCharacter,"");
//counts instances of said character
int count = winningString.length() - winningCodeShort.length();
secretCodeCount.put(winningCodeCharacter, count);
}
for (int i = 0; i < keys; i++) {
codeKeys.toArray(keyArray);
String keyString = keyArray[i];
if (secretCodeCount.containsKey(keyString)) {
matches += Math.min(secretCodeCount.get(keyString), guessCount.get(keyString));
}
}
int nearMatches = matches - countExactMatches(guess);
return nearMatches;
}
}
Game.java
import java.util.Scanner;
class Game {
protected static Code winningCode;
public static void main(String[] args){
}
public Game(){
winningCode = new Code();
}
protected static Code getGuess() {
Scanner userInput = new Scanner(System.in);
int count = 0;
int maxTries = 5;
while(true){
try {
String codeToParse = userInput.next();
Code guess = Code.parse(codeToParse);
return guess;
} catch(RuntimeException notACode) {
System.out.println("That's not a valid peg. You have " + (maxTries - count) + " tries left.");
if (++count == maxTries) throw notACode;
}
}
}
protected static void displayMatches(Code guess){
int nearMatches = winningCode.countNearMatches(guess);
int exactMatches = winningCode.countExactMatches(guess);
System.out.println("You have " + exactMatches + " exact matches and " + nearMatches + " near matches.");
}
protected static void play(){
int turnCount = 0;
int maxTurns = 10;
System.out.println("Greetings. Pick your code of four from Y,O,G,P,C,R.");
while(true){
Code guess = getGuess();
displayMatches(guess);
if (guess == winningCode) {
System.out.print("You win!!");
break;
} else if (++turnCount == maxTurns) {
System.out.print("You lose!!");
break;
}
}
}
}
On every guess, you call Code.parse, Code.parse creates a new Code (new Code(pegListString);) and that constructor sets the secretCodeString and because that's static, all instances of Code share the same variable. You need to avoid mutable static members.
Another tip is to either have a method return a value, or mutate state (of either its input, or its own instance, this), but avoid doing both.
"Why is my class variable rewriting itself after an unrelated method runs?"
Because, actually, it is not unrelated. The "mess" that you have created by declaring variables and methods as static has lead to unwanted coupling between different parts of your code.
It is difficult to say what the correct solution is here because your code has gotten so confused by the rewrites that it is hard to discern the original "design intent".
My advice would be to start again. You now should have a clearer idea of what functionality is required. What you need to do is to redo the object design so that each class has a clear purpose. (The Main and Game classes make sense, but Code seems to be a mashup of functionality and state that has no coherent purpose.)
I've been trying to search for the bug, but I couldn't find it. Already spent an hour trying to resolve what's wrong. The error begins when the code enters the isPlayerSet method while (!player.isPlayerSet()) {. I already set the used properties to "" but I am still getting this nullpointerexeption error. Please understand that I am fairly new in programming, especially in Java.
Here's the main class
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String playerName = "";
int chosenPokemon = 0;
boolean isANumber = false;;
Player player;
/*
* Initialize Players
*/
Player[] players = new Player[2];
for (int counter = 0; counter < players.length; counter++) {
player = new Player();
}
/*
* Get details of trainers
*/
for (int counter = 0; counter <= players.length-1; counter++) {
player = players[counter];
while (!player.isPlayerSet()) {
/*
* Input player name
*/
if(player.getPlayerName() == "") {
System.out.println("Enter a valid name for Player " + (counter+1) + ":");
player.setPlayerName(playerName);
}
/*
* Choose Pokemon
*/
if(player.getChosenPokemon() == ""){
System.out.println("Choose a starting pokemon for Player " + (counter+1) + ":");
System.out.println("[1] Charmander");
System.out.println("[2] Bulbasaur");
System.out.println("[3] Squirtle");
do {
if(!scanner.hasNextInt())
{
System.out.println("Input must be a valid integer. Try Again.");
scanner.next();
}
else if(!(chosenPokemon >= 1) && !(chosenPokemon <= 3))
{
System.out.println("Input must be a number from 1-3. Try Again.");
scanner.next();
}
else {
chosenPokemon = scanner.nextInt();
isANumber = true;
}
} while(!isANumber);
player.setChosenPokemon(chosenPokemon);
}
} // End of while loop
} // End of for loop
}
}
And here's the player class
public class Player {
Scanner scanner = new Scanner(System.in);
private String playerName = "";
private String chosenPokemon = "";
public String getPlayerName() {
return this.playerName;
}
public void setPlayerName(String playerName) {
do {
playerName = scanner.nextLine();
if(!isAlpha(playerName)) {
System.out.println("Invalid input. Try again");
}
if(playerName.isEmpty()) {
System.out.println("Player name cannot be blank! Try again");
}
} while(!isAlpha(playerName) || playerName.isEmpty());
this.playerName = playerName;
System.out.println("Welcome " + this.playerName);
}
public String getChosenPokemon() {
return chosenPokemon;
}
public void setChosenPokemon(int chosenPokemon) {
if(chosenPokemon == 1) {
this.chosenPokemon = "Charmander";
} else if(chosenPokemon == 2) {
this.chosenPokemon = "Bulbasaur";
} else {
this.chosenPokemon = "Squirtle";
}
}
public boolean isPlayerSet() {
if (this.playerName.isEmpty() && this.chosenPokemon.isEmpty()) {
return false;
}
return true;
}
public static boolean isAlpha(String name) {
char[] chars = name.toCharArray();
for (char c : chars) {
if (!Character.isLetter(c)) {
return false;
}
}
return true;
}
}
I also have another question, is it advisable to replace players[counter] with Player player?
You are creating new Player objects here:
for (int counter = 0; counter < players.length; counter++) {
player = new Player();
}
But: you are not storing those players in the array that you defined above. Thus: the array elements stay at its initial value - meaning that all players in the player array ... are null.
So your loop should say
players[counter] = new Player();
And of course, you really want to read this here.
In the loop
for (int counter = 0; counter < players.length; counter++) {
player = new Player();
}
You initialize the local variable player, so in while (!player.isPlayerSet()) player is null. You need to initialize the instance in the players array
for (int counter = 0; counter < players.length; counter++) {
players[counter] = new Player();
}
You're clobbering the same variable within this loop.
for (int counter = 0; counter < players.length; counter++) {
player = new Player();
}
Option 1:
for (int counter = 0; counter < players.length; counter++) {
players[counter] = new Player();
}
Option 2 (Slightly more concise and elegant):
for (Player p: players) p = new Player();
This
for (int counter = 0; counter < players.length; counter++) {
player = new Player();
}
should be this.
for (int counter = 0; counter < players.length; counter++) {
players[counter] = new Player();
}
I'm making a number guessing game for a school project in Java, which I'm extremely bad at. I've got everything to work with classes and the guessing part, but now I'm going to create a top players list and sort it and I have no idea how.
This is the code I use for guessing and creating objects of the player.
public static void spela() {
int nummer= ((int) (1+Math.random()*100));
Scanner input = new Scanner(System.in);
Scanner s_input = new Scanner(System.in);
boolean ratt = false;
int forsok = 1;
int gissning;
String namn;
while(ratt==false) {
System.out.println("Gissa nummer: ");
gissning = input.nextInt();
if(gissning == nummer) {
System.out.println("Grattis du gissade rätt! Tog: " + forsok + " försök att gissa rätt!");
System.out.println("Skriv in namn: ");
namn = s_input.nextLine();
for(int i=0;i<cr;i++) {
if(namn.equals(allaspelare[i].namn)) {
allaspelare[i].setpoang(forsok);
ratt=true;
menu();
}
}
allaspelare[cr] = new spelare(namn);
allaspelare[cr].setpoang(forsok);
cr++;
ratt=true;
menu();
}
if(gissning > nummer) {
System.out.println("Du gissade: " + gissning + " och det var för mycket!");
}
if(gissning < nummer) {
System.out.println("Du gissade: " + gissning + " och det var för lite!");
}
forsok++;
}
}
this is the "spelare" class:
public class spelare {
int[] poang = new int[100];
int antal;
String namn;
public spelare(String innamn) {
namn = innamn;
}
public void setpoang(int inpoang) {
poang[antal] = inpoang;
antal++;
}
}
as you see one player can have multiple scores so that's the problem I can't get it right in my mind how I'm going to sort it so the output if I wan't to get out the score chart will come like:
testplayer1: 9
testplayer2: 11
testplayer3: 34
So basically I need help to code a method that goes through the class and sort it and output it as above! Any help/sources is extremely appreciated!
And commented code would be extremely appreciated so I can learn!
EDIT:
I've been searching for hours, and the only thing that I found was this:
public static void sortera(int[] lista, int plats) {
int i;
if (lista.length < 2) return;
int temp;
for(int n=1; n<lista.length; n++) {
temp=lista[n];
i = n - 1;
while(i >=0 && lista[i] > temp) {
lista[i+1] = lista[i];
}
lista[i+1] = temp;
}
allaspelare[plats].poang = lista;
}
And this is how I called it:
case 5:
sortera(allaspelare[0].poang, 0);
break;
but this doesn't do anything..
The structure you use is simply bad. Instead you should use pairs of names and scores. This way multiple scorepairs with the same name exist, but you can easily sort them.
public class Score implements Comparable<Score>{
private int score;
private String name;
public Score(String name , int score){
this.score = score;
this.name = name;
}
//getters and setters as required
public int compareTo(Score s){
return score - s.score;
}
}
This aswell allows you to directly compare Scoreobjects to eachother. This way a list of Score objects can easily be sorted via Collections.sort(someList).
I am attempting to sort the values in my program using the Bubble Sort method. I believe that my code in the organisedRoom method is correct. However when I run the code, add some customers and then attempt to sort them, the program crashes. If anyone can please point me in the right direction I would greatly appreciate it.
package test;
import java.io.IOException;
import java.util.Scanner;
public class Test {
private class Customer implements Comparable<Customer>{
private String name;
public Customer(String name) {
this.name = name;
}
//Override to stop the program returning memory address as string
#Override
public String toString() {
return name;
}
#Override
public int compareTo(Customer c) {
return name.compareTo(c.name);
}
}
//Array to store customers
public Customer[] customers;
public Scanner input = new Scanner(System.in);
public Test(int nRooms) throws IOException {
customers = new Test.Customer[nRooms];
System.out.println("Welcome to the Summer Tropic Hotel\n");
chooseOption();
}
final JFileChooser fc = new JFileChooser();
// Call new Hotel with int value to allocate array spaces
public static void main(String[] args) throws IOException {
Test t = new Test(11);
}
// New procedure to return User input and point to next correct method
private String chooseOption() throws IOException {
// Set to null, this will take user input
String choice;
//Menu options
System.out.println("This is the Hotel Menu. Please choose from the following options:\n");
System.out.println("A: " + "This will add a new entry\n");
System.out.println("O: " + "View booked rooms, in order of customers name.\n");
System.out.println("X: " + "Exit the program\n");
// Take user input and assign it to choice
choice = input.next();
// Switch case used to return appropriate method
switch (choice.toUpperCase()) {
case "A" :
System.out.println("");
addCustomer();
return this.chooseOption();
case "O" :
System.out.println("");
organisedRoom();
return this.chooseOption();
case "X":
System.exit(0);
}
return choice;
}
// Add a new customer to the Array
public void addCustomer() throws IOException {
// New variable roomNum
int roomNum = 1;
// Loop
do {
// Take user input as room number matching to array index - 1
System.out.println("Please choose a room from 1 to 10");
roomNum = input.nextInt() - 1;
// If room is already booked print this
if (customers[roomNum] != null) {
System.out.println("Room " + roomNum + 1 + " is not free, choose a different one.\n");
this.addCustomer();
}
// Do until array index does not equal to null
} while (customers[roomNum]!= null);
System.out.println("");
// User input added to array as name replacing null (non case-sensetive)
System.out.println("Now enter a name");
customers[roomNum] = new Customer(input.next().toLowerCase());
// Customer (name) added to room (number)
System.out.println(String.format("Customer %s added to room %d\n", customers[roomNum], roomNum + 1));
}
private void organisedRoom() {
boolean flag = true;
Customer temp;
int j;
while (flag) {
flag = false;
for (j = 0; j < customers.length - 1; j++) {
if (customers[j].compareTo(customers[j+1]) < 0) {
temp = customers[j];
customers[j] = customers[j + 1];
customers[j + 1] = temp;
flag = true;
}
}
}
}
}
I think this is because the initialisation of the array adds null to all the array index places.
The stack trace is as follows:
Exception in thread "main" java.lang.NullPointerException
at test.Test$Customer.compareTo(Test.java:34)
at test.Test.organisedRoom(Test.java:133)
at test.Test.chooseOption(Test.java:83)
at test.Test.chooseOption(Test.java:79)
at test.Test.chooseOption(Test.java:79)
at test.Test.<init>(Test.java:46)
at test.Test.main(Test.java:55)
Java Result: 1
It fails because you create Customer[] which will be initialized with11 null references. If you want to order them all elements in the array will be compared. Which lead into the java.lang.NullPointerException.
Store the Customer in an ArrayList. Then you should be able to prevent this error.
edit
If you really need to stick as close as possible to your current code. The following would fix your sorting. (don't use this solution for a real life project)
private void organisedRoom() {
for (int i = customers.length - 1; i > 0; i--) {
for (int j = 0; j < i; j++) {
if (customers[j + 1] == null) {
continue;
}
if (customers[j] == null ||customers[j + 1].compareTo(customers[j]) < 0) {
Customer temp = customers[j + 1];
customers[j + 1] = customers[j];
customers[j] = temp;
}
}
}
System.out.println("show rooms: " + Arrays.toString(customers));
}
edit 2
To keep most of your current code, you might store the room in the Customer instance (which I personally would not prefer).
// change the constructor of Customer
public Customer(String name, int room) {
this.name = name;
this.room = room;
}
// change the toString() of Customer
public String toString() {
return String.format("customer: %s room: %d", name, room);
}
// store the Customer like
customers[roomNum] = new Customer(input.next().toLowerCase(), roomNum);
Your implementation of Bubble Sort is incorrect. It uses nested for loops.
for(int i = 0; i < customers.length; i++)
{
for(int j = 1; j < (customers.length - i); j++)
{
if (customers[j-1] > customers[j])
{
temp = customers[j-1];
customers[j-1] = customers[j];
customers[j] = temp;
}
}
}
So my array currently assign 5 instances of a dice object. My issue is that I have another class that needs to lock a dice from use.
public class Yahtzee {
OneDice[] dice = new OneDice[5];
public Yahtzee() {
yahtzeeRoll(); //constructor
}
public void yahtzeeRoll() {
for (int i = 0; i != dice.length; i++) {
dice[i] = new OneDice();
}
public void lock(int which) {
dice[which - 1].lockDice();
}
}
however my dice[i] = new OneDice(); creates a whole new set of random numbers each time yahtzeeRoll is called.
here is the method passing the which parameter.
#Override
public void choose() {
int which;
Scanner sc = new Scanner(System.in);
System.out.println(getName() + " Rolling.");
hand.printYahtzee();
System.out.println("Would you like to lock dice 1? 1 for yes");
choice = sc.nextInt();
if (choice == 1) {
which = 1;
hand.lock(which);
}
how can I assign a random value to each dice index without creating a brand new set of rolls that negates the lock. At least that appears to be the issue to me?
It sounds like you need to just skip over entries which are locked:
for (int i = 0; i < dice.length; i++) {
if (dice[i] == null || !dice[i].isLocked()) {
dice[i] = new OneDice();
}
}
Either that, or change your code to initialize dice in the constructor with new instances, but make your yahtzeeRoll method just change the values within the existing unlocked instances, instead of creating new instances. For example:
public Yahtzee() {
for (int i = 0; i < dice.length; i++) {
dice[i] = new OneDice();
}
rollUnlocked();
}
public void rollUnlocked() { // Renamed from yahtzeeRoll for clarity
for (OneDice die : dice) {
die.rollIfUnlocked(); // Or whatever method you want
}
}
(where rollIfUnlocked would reroll the single die, only if it hadn't previously been locked).
Don't reinitialize the entire array each time you roll. In real life when playing yahtzee you don't go grab 5 new dice every time you roll.
create OneDice as follows:
class OneDice {
int value;
boolean locked;
void roll(){
if(!locked)
value = Math.nextInt(6);
}
int getValue(){
return value;
}
void setLock(boolean lock){
locked = lock;
}
boolean isLocked(){
return locked;
}
}