This is a modified example from the book, Head First Java. It's a kind of Battleship game where a 3 element array is being used as the battleship. The user has to guess these 3 locations. Currently, I've hard-coded the values of the ship location to 2,3,4. When the user guesses the correct location "Hit" is printed. If not then "Miss" is printed. If a user guesses all 3 locations then "Kill" is printed. But I have a problem. Currently if the user enters the same location multiple times, it still gives a hit. I tried to fix this by changing the value of a variable that has already been hit (int cell) to "-1". But for some reason this didn't fix it too. Please tell me what I am doing wrong.
public class Game {
public static void main(String[] args) {
// TODO Auto-generated method stub
int [] location = {2,3,4};
SimpleDotCom firstGame = new SimpleDotCom();
firstGame.setLocation(location);
firstGame.checkYourself("2");
firstGame.checkYourself("2");
//firstGame.checkYourself("2");
}
}
public class SimpleDotCom {
int [] loc = null;
int numOfHits = 0;
void setLocation (int [] cellLocation){
loc = cellLocation;
}
void checkYourself(String userGuess){
int guess = Integer.parseInt(userGuess);
String result = "Miss";
for(int cell:loc){
if (guess == cell){
result = "Hit";
numOfHits++;
cell = -1;
break;
}
if (numOfHits==loc.length){
result = "Kill";
}
}
System.out.print("Result: " + result);
System.out.println(" ** Num of Hits: " + numOfHits);
}
}
When you loop over loc, you get an int cell for each location. The problem is that that variable doesn't have any connection to the array, it's only a copy. If you change it, nothing's going to happen to the original array. I suggest looping over loc with a traditional for(;;) and using the current array index within the loop's logic to set the right "cells" to -1.
because you are assigning -1 to local variable. not updating in array actually
for(int cell:loc){ // cell is local copy of element in array is you have array of primitive int
if (guess == cell){
result = "Hit";
numOfHits++;
cell = -1;
break;
}
if (numOfHits==loc.length){
result = "Kill";
}
}
You can use traditional for loop for this or use List which has methods for adding removing elements.
You need to update the array at the correct index, not simply change the value of the cell variable, which only references the array element at the current iteration state.
You should probably use a traditionnal for loop for that, since you cannot get the index for free from an enhanced for loop.
for (int i = 0; i < loc.length; i++) {
//code...
loc[i] = -1; //instead of cell = -1;
}
Related
Hoping for some help - I've been asked to write a hotel room system using methods for uni. All has been going well until I try to order the array alphabetically.
I have managed to get it to order within the method but it updated the main array (hotel). I want it to keep it within the order method, if that makes sense?
I've included a cut down version below without all the functions.
Currently it will reorder the array hotel so if you view the rooms the array will print like 'e,e,e,etc, George, Peter, Robert' instead of keeping its original form 'e, Robert, Peter, e,e,etc, George'
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String roomName;
int roomNum = 0;
String[] hotelRef = new String[12];
String[] hotel = new String[12];
initialise(hotel); //initialise
while (roomNum < 13) {
System.out.println("Please select from the menu:");
System.out.println("V : View rooms");
System.out.println("O : Order Guests alphabetically");
String selection = input.next();
switch (selection) {
//There are more switch cases on the original version
case "O":
order(hotel);
break;
default:
System.out.println("");
}
}
}
private static void order(String[] hotelRef) {
int j;
boolean flag = true; //will determine when the sort is finished
String temp;
String[] order = new String[12];
order = hotelRef;
while (flag) {
flag = false;
for (j = 0; j < order.length - 1; j++) {
if (order[j].compareToIgnoreCase(order[j + 1]) > 0) {
//ascending sort
temp = order[j];
order[j] = order[j + 1]; // swapping
order[j + 1] = temp;
flag = true;
}
}
}
for (int y = 0; y < order.length; y++) {
if (!order[y].equals("e")) {
System.out.println("Room " + y + " is occupied by " + order[y]);
}
}
System.out.println("Ordering completed");
}
You should clone the hotelRef instead of assigning the reference like this order = hotelRef;
You could do the following while creating the order array :
String[] order = new String[hotelRef.length]; // to make sure that order has the right size.
and instead of order = hotelRef;
for (int i=0;i<order.length;i++)
order[i]=hotelRef[i]; // thereby cloning
or use System.arraycopy() or any other method to accomplish cloning the array.
You can make copy of hotel array in your order method:
String[] hotelCopy = new String[hotelRef.length];
System.arraycopy(hotelRef, 0, hotelCopy, 0, hotelRef.length);
And then just use hotelCopy inside your order method.
The problem lies with the following line
order = hotelRef;
Change it to
order = hotelRef.clone();
Though you are creating a new object, you have assigned the reference to outer object only. So whatever changes you make in the inner object it will be reflected to the outer object.
public static void main(String[] args){
........................
for(int i = 0; i<play.size(); i=i+1){
System.out.println("the Winner is; " +Winners(play).get(i).name);
}
}
This is the main method. i didnt write down Everything here, because its unnecesary. basically what i am doing, is that i am Calling Winners method that takes ArrayList<Game> as argument. play is of type ArrayList<Game>. on that i want to get the elements stored inside and get their name. so that the winners name is shown on screen. i for loop it because there can be several winners. depends on how many shares the same score.
private static ArrayList<Game> Winners(ArrayList<Game> gamers){
ArrayList<Game> winner = new ArrayList<Game>();
for(int i = 1; i==gamers.size(); i=i+1){
if(gamers.get(i).getPoints()>gamers.get(i-1).getPoints()){ winner.clear();
winner.add(gamers.get(i));
}
else if(gamers.get(i).getPoints()<gamers.get(i-1).getPoints()){ winner.clear();
winner.add(gamers.get(i-1));
}
else if(gamers.get(i).getPoints()==gamers.get(i-1).getPoints()){ winner.clear();
winner.add(gamers.get(i));
winner.add(gamers.get(i-1));
}
}
return winner;
}
the Winners method returns an Arraylist<Game>, which is where the gamer or gamers with top score are stored.
i loop through each on of the gamers and compare their points to each other. the one who has the most score gets stored in the Winner arraylist.
i clear the winner arraylist all the time some elements goes inside, because i only want the top Points stored there.
My issue is, i dont know if i am doing it correct. because i am getting error on
on the System.out.println("the Winner is; " +Winners(play).get(i).name);.
it says index 0 size 0 (indexoutofboundsexception)
for(int i = 1; i==gamers.size(); i=i+1)
It means the loop will terminate when i==gamers.size() is false. At the first time when i=1, but gamers.size() is greater than 1. It never enters the loop. And returns empty list. When you trying to get one element from an empty list, you are getting the exception.
But I think you want to check i < gamers.size(). It might be:
for(int i = 1; i < gamers.size(); i++)
Again, you don't need winner.clear() in each if block. Rather you could:
private static ArrayList<Game> Winners(ArrayList<Game> gamers) {
ArrayList<Game> winner = new ArrayList<Game>();
for (int i = 1; i < gamers.size(); i++) {
winner.clear();
if (gamers.get(i).getPoints() > gamers.get(i - 1).getPoints()) {
winner.add(gamers.get(i));
} else if (gamers.get(i).getPoints() < gamers.get(i - 1).getPoints()) {
winner.add(gamers.get(i - 1));
} else { // last check when points are equal
winner.add(gamers.get(i));
winner.add(gamers.get(i - 1));
}
}
return winner;
}
N.B: There is an issue in the approach of your Winners() method. You are iterating over gamers and adding a winner to the list. But every time you are clearing the list. That means you will get only the winner from last two players. Previous winners will be cleared. I think you need to recheck it.
As you are clearing the list, the size of winner list won't be same as the size of play. As a result, you will also get exception in this code.
for(int i = 0; i < play.size(); i=i+1) {
System.out.println("the Winner is; " + Winners(play).get(i).name);
}
One fix could be:
ArrayList<Game> winnersList = Winners(play);
for(int i = 0; i < winnersList.size(); i++) {
System.out.println("the Winner is; " + winnersList.get(i).name);
}
I am processing elements of an ArrayList in random order, generally by printing them out. I would like to detect when the randomly selected index is 0 or 1 so as to perform special handling for those cases, where the handling for index 0 is partially dependent on whether index 1 has previously been processed. Specifically, nothing is immediately printed when index 1 is processed, but if it is processed then when index 0 is subsequently processed, both the index 1 and the index 0 values are printed. In any event, the loop is exited after ten iterations or after processing index 0, whichever comes first.
I tried to implement this using if statements, but there where obvious flaws with that one. I have searched everywhere for any examples but found none. I have begun to consider using sorting algorithms or threads to hold the first value found then continue looping until it sees the second the print it out. I would appreciate any help possible.
Here is my code:
public static void random_sortType(){
types = new ArrayList<String>();
types.add("Start");
types.add("Starting");
types.add("Load");
types.add("Loading");
types.add("End");
ran = new Random();
int listSize = types.size();
String tempEventType;//the temp variable intended to hold temporary values
for(int i = 0; i < 10; i++){ //the loop goes round the ArrayList 10 times
int index = ran.nextInt(listSize);//this produces the random selection of the elements within the list
if(index == 0){
out.println(types.get(index));
out.println();
break;
}
if(index == 1){
tempEventType = types.get(index);
if(index == 0){
tempEventType = types.get(0) + " " + types.get(1);
out.println(tempEventType);
break;
}
}/*if(index == 0){
tempEventType = types.get(0) + " " + types.get(1);
out.println(tempEventType);
break;
}*/
//out.print("Index is " + index + ": ");
//out.println(types.get(index));
}
}
You need to store the random generated index into a global variable and update it everytime a random number is generated. It should be something like this.
public static void random_sortType(){
types = new ArrayList<String>();
types.add("Start");
types.add("Starting");
types.add("Load");
types.add("Loading");
types.add("End");
` int previousIndex;
ran = new Random();
int listSize = types.size();
String tempEventType;//the temp variable intended to hold temporary values
for(int i = 0; i < 10; i++){ //the loop goes round the ArrayList 10 times
int index = ran.nextInt(listSize);//this produces the random selection of the elements within the list
previous_index =index;
if(index == 0){
out.println(types.get(index));
out.println();
break;
}
if(index == 1){
tempEventType = types.get(index);
if(previousIndex == 0){
temp EventType = types.get(0) + " " + types.get(1);
out.println(tempEventType);
break;
}
According to your description, these are the basic requirements for your application:
Process ArrayList in random order
Processing = printing value at randomly selected index
Make 10 attempts to process items in the list.
Detect when random index is 1 or 0.
if 1
don't process, but flag it was selected.
if 0 && 1 is flagged
process 0 and 1
exit
If these requirements are correct, here is the implementation I came up with:
import java.util.ArrayList;
import java.util.Random;
import static java.lang.System.*;
public class RandomSort {
private static final int MAX_ATTEMPTS = 10;
private static boolean wasOneSelected = false;
public static void main(String[] args) {
ArrayList<String> types = new ArrayList<>(5);
types.add("Start");
types.add("Starting");
types.add("Load");
types.add("Loading");
types.add("End");
random_sortType(types);
}
public static void random_sortType(ArrayList<String> types) {
Random ran = new Random();
int lastIndex = types.size() - 1; // index range is from 0 to 4
for (int i = 0; i < MAX_ATTEMPTS; i++) {
int index = ran.nextInt(lastIndex);
if ( (index == 0) && wasOneSelected) {
process(types.get(index) + " " + types.get(index + 1));
break;
} else if (index == 1) {
wasOneSelected = true;
} else {
process(types.get(index));
}
}
}
public static void process(String str) {
out.println("Processing: " + str);
}
}
The key here is the inclusion of the boolean wasOneSelected initialized to false. Once it is set to true, it will never be false again for the duration of the application. The if-else block handles all branching within the loop, and I favored wrapping the println call into a method called "process" for readability purposes to align it more closely with your description.
Feedback appreciated :)
Here is the program that I am trying to run:
/**
* Write a description of class mainGame here.
*
* #author Anthony Parsch
* #version 0.1.1
*/
//Import what I need to.
import java.io.*;
public class mainGame
{
/**
* Constructor for objects of class mainGame
*/
public static void main(String[] args)
{
// initialise instance variables
int xCoord = 10; //The map's max x coordinate +1
int yCoord = 10; //The map's max y coordinate +1
int playerX = 0; //The player's current x coordinate
int playerY = 0; //The player's current y coordinate
//Declare the arrays
String[][] map; //[x][y]The map
String[][] direc; //[x][y]Which directions that you can go
String[][] items; //[x][y]Where items are at
String[] inv; // Holds your inventory.
int[][] helpInt; //[x][y] All the other stuff in the
//Initalize the arrays
//---The player arrays
inv = new String[10]; //The player's inventory
inv[0] = "0";
inv = addItem(inv, "Blarg");//GET RID OF THIS LATER
//---The map arrays
map = new String[xCoord][yCoord]; //Descriptions
direc = new String[xCoord][yCoord]; //north y++,west x--,south y--,east x++
items = new String[xCoord][yCoord]; //The items within the world
//Declare the values of map
map[0][0] = "You wake up with the feel of cold metal on your back. The only other thing in this room is the door.";
map[0][1] = "You are now in a hallway with a door behind you and one either side. Forward is a continuation of the hallway.com";
//Declare the values of direc
direc[0][0] = "north";
direc[0][1] = "north, south, east, west";
print(inv[0]); //Check that the functions work
print(findDirec(direc, 0, 0));
}
/**
* Finds and displays the avaliable exits for a coordinate.
*
* #param map[][] The map array from which this method pulls the directions from.
* #param x The x value of the map
* #param y The y value of the map
* #return The string value of which way you can go
*/
static String findDirec(String[][] map, int x, int y){
//Pulls the directions
String match = map[x][y];
//Checks Directions
boolean nor = match.matches("(.*)north(.*)");
boolean sou = match.matches("(.*)south(.*)");
boolean wes = match.matches("(.*)west(.*)");
boolean eas = match.matches("(.*)east(.*)");
//Displays directions
String placeHolder = "You can go ";
if (nor == true){
placeHolder = placeHolder + "north, ";
} else if(sou == true) {
placeHolder = placeHolder + "south, ";
} else if(wes == true) {
placeHolder = placeHolder + "west, ";
} else if(eas == true) {
placeHolder = placeHolder + "east";
}
//---Checks if east is in the string, if not it removes the space and comma
if (eas == false){
StringBuffer soo = new StringBuffer(placeHolder);
soo.delete((placeHolder.length()-3), (placeHolder.length()-1));
placeHolder = soo.toString();
}
//Adds the ending period
placeHolder = placeHolder + ".";
//Returns the string
return placeHolder;
}
//Adds an item to an inventory
static String[] addItem(String inv[], String item){
int i; //Counter for the for loop, and where to add the item at.
boolean stop = false;
for(i=0; stop = true; i++)
{
if(inv[i].equals("0"))
{
stop = true;
}
}
inv[i] = item;
return inv;
}
static void print(String entry){
System.out.print(entry);
}
}
And when I try and run it through the Command Prompt, I get this error:
Exception in thread "main" java.lang.NullPointerExcpetion
at mainGame.addItem(mainGame.java:113)
at mainGame.main(mainGame.java:38)
When I paste this in to a text editor, line 113 is simply a closing brace }.
However, one line before that is a logic flaw which I presume is really line 113 for you.
for(i=0; stop = true; i++)
{
if(inv[i].equals("0"))
{
stop = true;
}
}
Each iteration of the loop assigns true to stop and then tests if true equals true, which it does. Your condition to exit the loop is when true equals false, which is never the case, therefore your loop goes forever until an error occurs. Also, don't you want to iterate while stop is false? I think you have it backwards.
The next problem is your if statement, which is probably where your NullPointerException is coming from:
if(inv[i].equals("0"))
{
stop = true;
}
You assume that inv[i] refers to an object. You need a null check.
Three recommendations:
Never use = for a comparison. Use ==. Since this is a boolean, you can even simplify this to stop.
Check the length in your for loop.
Compare "0" to inv[i] instead of the other way around to avoid null pointer dereferencing.
Try this:
boolean stop = false;
for (int i = 0; i < inv.length && !stop; i++)
{
if("0".equals(inv[i])
{
stop = true;
}
}
Another option, and this is a matter of form, is to remove the looping variable and just break out of the loop explicitly.
for (int i = 0; i < inv.length; i++)
{
if("0".equals(inv[i])
{
break;
}
}
inv = new String[10]; //The player's inventory
inv[0] = "0";
inv = addItem(inv, "Blarg");//GET RID OF THIS LATER
So you only initialize one index of your array but here:
for(i=0; stop = true; i++)
{
if(inv[i].equals("0"))
{
stop = true;
}
}
.. you loop through all of them. just kidding, didn't read the full problem. You should still read the rest of my answer, but the reason why you get the NPE is because your loop condition is broken. (by the way your for loop condition is broken, it should test for equivalence using the == operator, not the assignment = operator.)
So what you actually are doing with that code is this :
inv = new String[10];
At this point you have a new String array of capacity 10, with no values inside, something like this:
[null][null][null][null][null][null][null][null][null][null]
inv[0] = "0";
Now you set [0] to "0", so:
["0"][null][null][null][null][null][null][null][null][null]
Then your loop attempts to access all of those null references, that'll probably be why you have a null reference exception.
To fix it, simply every index position in your array to anything that is not-null:
Arrays.fill(inv, "");
I use Arrays.fill() because it's shorter.
In your for loop condition, which one do you prefer?
stop = true or stop == true
for(i=0; i<inv.length && !stop; i++)
{
if(inv[i]!=null && inv[i].equals("0"))
{
stop = true;
}
}
Can someone could be kind and help me out here. Thanks in advance...
My code below outputs the string as duplicates. I don't want to use Sets or ArrayList. I am using java.util.Random. I am trying to write a code that checks if string has already been randomly outputted and if it does, then it won't display. Where I am going wrong and how do I fix this.
public class Worldcountries
{
private static Random nums = new Random();
private static String[] countries =
{
"America", "Candada", "Chile", "Argentina"
};
public static int Dice()
{
return (generator.nums.nextInt(6) + 1);
}
public String randomCounties()
{
String aTemp = " ";
int numOfTimes = Dice();
int dup = 0;
for(int i=0 ; i<numOfTimes; i++)
{
// I think it's in the if statement where I am going wrong.
if (!countries[i].equals(countries[i]))
{
i = i + 1;
}
else
{
dup--;
}
// and maybe here
aTemp = aTemp + countries[nums.nextInt(countries.length)];
aTemp = aTemp + ",";
}
return aTemp;
}
}
So the output I am getting (randomly) is, "America, America, Chile" when it should be "America, Chile".
When do you expect this to be false?
countries[i].equals(countries[i])
Edit:
Here's a skeleton solution. I'll leave filling in the helper methods to you.
public String[] countries;
public boolean contains(String[] arr, String value) {
//return true if value is already in arr, false otherwise
}
public String chooseRandomCountry() {
//chooses a random country from countries
}
//...
int diceRoll = rollDice();
String[] selection = new String[diceRoll];
for ( int i = 0; i < selection.length; i++ ) {
while (true) {
String randomCountry = chooseRandomCountry();
if ( !contains(selection, randomCountry ) {
selection[i] = randomCountry;
break;
}
}
}
//...then build the string here
This doesn't check important things like the number of unique countries.
You need a data structure which allows you to answer the question "does it already contain item X?"
Try the collection API, for example. In your case, a good candidate is either HashSet() or LinkedHashSet() (the latter preserves the insert order).
You'd probably be better of using another structure where you save the strings you have printed. Since you don't want to use a set you could use an array instead. Something like
/*
...
*/
bool[] printed = new bool[countries.length];
for(int i=0 ; i<numOfTimes ; /*noop*/ )
{
int r = nums.nextInt(countries.length);
if (printed[r] == false)
{
i = i + 1;
printed[r] = true;
aTemp = aTemp + countries[r];
aTemp = aTemp + ",";
}
}
return aTemp;
Consider what you're comparing it to:
if (!countries[i].equals(countries[i]))
are you comparing c[i] to c[i]? or c[i] to c[i-1]? Or do you need to check the whole array for a particular string? Perhaps you need a list of countries that get output.
make list uniqueCountries
for each string called country in countries
if country is not in uniqueCountries
add country to uniqueCountries
print each country in uniqueCountries
When you do this, watch out for index out of bounds, and adjust accordingly
Much faster way to do it then using HashSets and other creepy stuff. Takes less code too:
public String randomCounties() {
List<String> results = Arrays.asList(countries);
Collections.shuffle(results);
int numOfTimes = Dice();
String result = " ";
for(int i=0 ; i<numOfTimes; i++) {
result = result + countries[i] + ", ";
}
return result;
}
If you want to avoid outputting duplicate values, you need to record what values have already been listed or remove values from the pool of possibilities when they get selected.
You mention that you do not want to use Sets or ArrayList (I assume you mean Lists in general), I assume that is a requirement of the assignment. If so, you can accomplish this by building arrays and copying data between them the same way that an ArrayList would.
one note, your current implementation chooses between 1 and 6 entries from and array of 4 entries. If you force the selections to be unique you need to decide how to handle the case when you have no more unique selections.