Java newbie here. I have multiple while loops. All separated thinking that it would just go down in order until the while condition equals true. What my output suggests is that it does the first while loop it finds that is true then exits, with out looking at the others. Please advise if there is a better way doing this or if you see an obvious error. Sample output from (xCar =3, yCar =3) and Destination = (1,1) is just "West" "West". There should be 2 "South". *Please excuse the print statements, I was trying to debug what it was doing. I should also point out that I can only move the 'car' one spot then need to report back the direction.
if (car.getLocation().equals(car.getDestination())){
System.out.println("inside this if statement");
System.out.println(car.nextMove().NOWHERE);
}
//Seeing if Xcar is greater than Xdest. If so moving west
while (car.getxCar() > xDestination){
System.out.println("2nd if statement");
System.out.println(car.nextMove().WEST);
}
//Seeing if Xcar is less than Xdest. If so moving east
while (car.getxCar() < xDestination){
//System.out.println("3rd");
System.out.println(car.nextMove().EAST);
}
//Seeing if Ycar is greater than Ydest. If so moving south
while (car.getyCar() > yDestination){
System.out.println("4th");
System.out.println(car.nextMove().SOUTH);
}
//Seeing if Ycar is less than Ydest. If so moving north
while (car.getyCar() < yDestination){
System.out.println("5th");
System.out.println(car.nextMove().NORTH);
}
METHOD nextMove() it is calling a enum in class Direction
public Direction nextMove() {
if (xCar < xDestination){
xCar = xCar + car.x+ 1;
}
if (xCar > xDestination){
xCar = xCar + car.x -1;
}
if (yCar < yDestination){
yCar = yCar + car.y +1;
}
if (yCar > yDestination){
yCar = yCar + car.y -1;
}
return null;
Output
Car [id = car17, location = [x=3, y=3], destination = [x=1, y=1]]
2nd if statement
WEST
2nd if statement
WEST
What is happening is this:
In your first while loop you call your nextMove() method. This method is incrementing both x and y in your first loop, hence why you don't get the output of the other while loops. If you changed your input destination to [3,4] you should get output of WEST,WEST,SOUTH
You could fix this so that only one of the dimensions is incremented at a time in your nextMove() method by changing them to else if like this
public Direction nextMove() {
if (xCar < xDestination){
xCar = xCar + car.x+ 1;
}
else if (xCar > xDestination){
xCar = xCar + car.x -1;
}
else if (yCar < yDestination){
yCar = yCar + car.y +1;
}
else if (yCar > yDestination){
yCar = yCar + car.y -1;
}
return null;
I would not make a new class here. You only need a method to do the moving which can be created in the same file as the main function. If you really want a class to move the car then you need to declare it correctly. Remember, a Class requires a public, private and a constructor as well as all of the methods the class can do. It would also be easy to put the moving methods inside the car class since part of the car class should hold the location of the car object. I don't know if you want it to move across a screen or just change the location. If you want to move across the screen the while loops will work. But if all you need is for the location to change, then it would be much easier to change a private variable holding the location of the car; it will be easier to code and to run since evaluating booleans takes a sizable amount of computation time. Good luck. Let me know if you didn't understand anything.
Related
I'm making a 2d platformer in libgdx with box2d. The below is the update method for one of my enemies. It's an extension of the 'Enemy' class, which is what 'super.update' refers to. I want the enemy to run when the player is behind it or far away and to stop and shoot when the player is close to it and in front of it.
I try to achieve this by setting the speed (velocity.x) initially [depending on the enemy's direction], then setting whether or not it's shooting afterwards.
The problem I have at the moment is that the enemy doesn't run when the player is behind it. As you can see, I printed out a lot of strings to console to see when the velocity.x gets changed back to 0. According to the console, it happens in the last if/else pair of statements which are supposed to check how far away the player is and which direction the enemy is running. However, the console strings within those statements, the ones that say 'Shoot Left' or 'Shoot Right', don't get printed out. Despite this, the line that changes velocity.x must get run because the it's value changes according to the string output in the next line. The if statements at the top which check direction must get run as well because the console outputs within those statements get printed, and the output that says the velocity says the correct velocity (either 2 or -2).
What is going on? It seems like the IDE is running only one of the lines in the if statement. That's impossible so what am I missing here?
Thanks for any help.
public void update (float dt, Player player){
super.update(dt, player);
if (b2body.isActive()){
System.out.println(b2body.getPosition().x - player.b2body.getPosition().x);
System.out.println("After Enemy code: " + velocity.x);
if (getRunningRight()) {
System.out.println("Right");
velocity.x = 2;
}
else if (!getRunningRight()) {
System.out.println("Left");
velocity.x = -2;
}
System.out.println("After checking direction: " + velocity.x);
if ((b2body.getPosition().x - player.b2body.getPosition().x <= 2 &&
b2body.getPosition().x - player.b2body.getPosition().x >= 0) && !getRunningRight()){
velocity.x = 0;
System.out.println("Shoot left");
}
else if ((b2body.getPosition().x - player.b2body.getPosition().x >= -2 &&
b2body.getPosition().x - player.b2body.getPosition().x < 0) && getRunningRight()){
System.out.println("Shoot right");
velocity.x = 0;
}
System.out.println("After shooting: " + velocity.x);
}
}
In your first set of ifs, you evaluate getRunningRight() after you have already determined that it will be false (by the initial if failing), so there is no need to evaluate it again.
If you think you are doing the same thing in the second block, you are not; the expression in the inner if is not the opposite of the first one. That is, (A && B) && C is not the opposite of (!A && !B) && !C. Thus, it is possible for both expressions to be false.
I am trying to build an app implementing A*, and I am having trouble working on the logic. The method here takes in 4 ints (startX/Y, goalX/Y) and then using the A* algorithm, it will build an ArrayList and return it, so the main method can take iterate through and display the path A* builds. But what I am getting is a jumpy path that eventually builds a very thick path to the goal node. Can anybody pinpoint where my mistake is.
Note: open and closed are priority queues and Tile implements comparable.
public ArrayList<Tile> findPath(int sX, int sY, int gX, int gY)
{
ArrayList<Tile> path = new ArrayList<Tile>();
open.offer(gameMap[sX][sY]);
Tile currentNode = gameMap[sX][sY];
Tile goalNode = gameMap[gX][gY];
int cX;
int cY;
while(open.size() > 0){
currentNode = open.poll();
closed.offer(currentNode);
path.add(currentNode);
cX = currentNode.getX();
cY = currentNode.getY();
if(currentNode == goalNode){
break;
}
if((cX > 0 && cX < gameMap.length - 1) && (cY > 0 && cY < gameMap.length -1)){
for(int i = -1; i < 2; i++){
for(int j = 1; j > -2; j--){
if(i == 0 && j == 0){}
else{
if((gameMap[cX + i][cX + j].type != 1) && !closed.contains(gameMap[cX + i][cX + j])){
if(!open.contains(gameMap[cX + i][cX + j])){
open.offer(gameMap[cX + i][cX + j]);
gameMap[cX + i][cX + j].parent = currentNode;
}
}
}
}
}
}
}
// while(currentNode != gameMap[sX][sY]){
// path.push(currentNode);
// currentNode = currentNode.parent;
// }
return path;
}
First off, I don't think your closed set needs to be a priority queue. It's just a set of nodes that have been looked at.
You seem to be missing the core part of how A* works, which is why I think this path finder is not working to well for you.
Here's the main idea:
Have a heuristic function that guesses how far away the destination is. Ideally, that function will be admissible, meaning that it will never overestimate the distance.
For tile grids, this can be done using manhattan distance (x difference + y difference) since that is the minimum distance, so it will always be admissible.
Whenever you take a tile out of your open list and add it to the closed set, you need to update the known value of how far away the neighboring tiles are (keeping the lowest known value). Since you have the known value for the tile you are putting in the closed set, you just add 1 to all the neighbors' known values.
By updating these values, the open list may shift order (which is why a priority queue is a good choice here). The heuristic value will probably remain the same, but the known value will get more refined.
Once you reach the destination, you will have a set of closed nodes that all have a known distance. You then backtrack from the destination, looking at each neighbor that is also in the closed set and choosing the one with the lowest known distance.
In terms of how to implement this, you may want to consider having your Tile class be wrapped in another class called SearchTile or something like that. It could look like this:
//You may not want to use public variables, depending on your needs
public class SearchTile implements Comparable<SearchTile> {
public final Tile tile;
//These need to be updated
public int knownDistance = 0;
public int heuristicDistance = 0;
public SearchTile(final Tile tile) {
this.tile = tile;
}
#Override
public int compareTo(final SearchTile other) {
if (knownDistance + heuristicDistance > other.knownDistance + other.heuristicDistance) {
return 1;
} else if (knownDistance + heuristicDistance < other.knownDistance + other.heuristicDistance) {
return -1;
} else {
return 0;
}
}
}
The cool thing about A* is that in the ideal case, it should go straight to the destination. In cases with walls, it will take the best guess and as long as the heuristic is admissible, it will come up with the optimal solution.
I've not completely entered in the details of your implementation, but it comes to my mind that the way in which you are inserting the nodes in OPEN might be a cause of trouble:
if(!open.contains(gameMap[cX + i][cX + j])){
open.offer(gameMap[cX + i][cX + j]);
gameMap[cX + i][cX + j].parent = currentNode;
}
Your goal here is to manage avoiding repeated elementes in your OPEN list, but it might happen that sometimes you have to replace the element because you have encountered a way in which you reach it with a better cost. In this case you need to remove the node already inserted in OPEN and reintroduce it with a lower cost (and thus with highest priority). If you do not allow this, you might be generating suboptimal paths as it seems to be your case.
Additionaly, some logic of the algorithm is missing. You should store the accumulated cost from the start, G, and the estimated cost to goal, H, for each node you create. The OPEN list is ordered according to the value of G+H, which I didn't notice in your code to be done this way. Anyway, I recommend you to take a look of some existing implementation of A* like one of the Hipster4j library to have more details on how this works.
Hope my answer helped!
I have a text based game that I am making. It is a RPG style where the user is given options linked to numbers and they have to choose a number. Now my problem is that when running the program. A certain method, Decision(), only works certain times. The method is in a superClass while it is being called in the subclass. in the subclass, It works the first time, but not necessarily the second. Also, when I copy the decision method from the superclass into the subclass its starts working, but the next time it is called, it stops. Here is what I've tried and the results. I've included the decision method and where it is being called.
Decision Method:
public int decision(String question, int length, String[] choices){
int[] numbers = new int[length];
int iterator = 1;
for(int i = 0; i < length; i++){
numbers[i] = iterator;
iterator++;
}
boolean done = false;
while(!done){
//print("Test");
print("");
print(question);
String options = "";
for(int i = 0; i < numbers.length; i++){
options = (options + numbers[i] + " - " + choices[i] + " ");
}
print(options);
boolean univSet = true;
int entry = 1;
while(univSet){
if(univInt != 0){
univSet = false;
entry = univInt;
univInt = 0;
//print("testing");
}
}
if(entry == 23){
help();
}else{
for(int i = 0; i < numbers.length; i++){
if(entry == numbers[i]){
done = true;
univInt = 0;
return entry;
}
}
print("Invalid Number, Try again");
print("");
univInt = 0;
}
}
return (Integer) null;
}
Chapter1 Class (Where it's being called:
public class Chapter1 extends Story implements Serializable {
Player player;
public Chapter1(Player player){
this.player = player;
}
public void engage() {
// TODO Auto-generated method stub
player.chapter = 1;
save(player.name);
sPrint("Welcome to Chapter 1");
print("You wake up in a lighted room with white walls.\nA fresh breeze is coming through the window yet the air smells rotten.");
print("You jolt up suddenly. You don't remember anything about how you got here. You've even forgotten who you are.");
print("You look down at your white shirt, there is a streak of blood across the top.\nYou are wearing a nametag that says: " + player.name + ".");
print("You're sitting in a chair but there are no restraints. You decide to get up and look around");
cur = decision("What do you do?", 2, new String[]{"Try the door", "Look out the window"});
print(cur + "");
if(cur == 1){
print("You walk over to the door and try and open it, it is unlocked.\nYou walk through and are welcomed by a cold and poorly lit hallway");
}else{
print("You walk to the window and look outside. You see a huge barren field. You can make out a humanoid like structure.\nYou call out yet the figure doesn't move.");
print("You decide to try the door. It's unlocked so you walk through into a cold dimly lit hallway.");
}
print("You see a dull knife on the floor as well as a door on the end of the hallway");
cur = decision("What do you do?", 2, new String[]{"Go to the door", "Take the knife"});
if(cur == 2){
print("You pick up the knife.");
addWeapon("Kitchen Knife", player);
}else{
print("You walk down the hallway to the door when suddenly the door opens and out comes a zombie.\nIt Lunges for your shoulder. You are caught by surprise and it bites into your skin and you are infected");
gameOver();
}
print("You continue to walk down the hall when suddenly a hideous creature lunges out from the door.\nYou jump back and prepare yourself for a battle.");
battle("Zombie", 5, 2, player);
sPrint("I see that you have succeeded in your first encounter with the undead.\nI congratulate you but you have a long way to go. Remember, I am your only way to learning about your past. \nNow, make your way down to the bottom of the tower. I will help you where I see fit along the way.");
print("You look around and see that the lights have brightened up. The zombie has been mutilated by your Kitchen Knife. \nYou don't know where the voice came from but you are scared. Behind the zombie's original hiding spot you see a staircase.\nYou follow it down, onto what seems to be..the 11th floor.");
print("");
print("Please input 'complete' to continue");
pause();
sPrint("Chapter 1 complete");
}
Now in this class, engage() is being called to run this chapter. And decision is being called where you see it, as well as in the battle() method(the battle method loops a couple times and decision() is called every loop.
Originally, both Decision and battle are in the superclass, but not in the sub class. This results in the first decision method in the class to be called, but not the second. In the second, it stops at the loop checking the value of univInt.
When I put the decision method into the sub class, It passes the first two but it fails to get past the first one in the battle method for the same reason.
When I put both the decision and battle method into the sub class, it has the same result as just putting decision.
Finally if I put battle in the sub class but not decision it only passes the first two again.
In the project I have one variable named cur that holds the integer value of whatever decision returns. I reuse it for every decision. I don't know if that has anything to do with it. This really doesn't make sense to me how whether the methods are in the same class, or inherited would matter at all if they are the same method.
I am ready to clarify anything and I hope someone is able to understand what is going wrong.
EDIT:
univInt is being set to another number other than 0 outside of decision. thats why it works some times. It is a swing class and a method in a superclass sets univInt to whatever is in a TextField when a button is pressed so with that while loop I try to constantly check to see univInt has been changed from 0
It seems like your "univInt" is a class member, not a local variable, and you do not reinitialize it when entering the function. Thus it won't be changed back to allow the program to enter the if-statement you mention.
Here is the algorithm (not working) Please let me know where the error is
Thanks
private void checkSouth(Location point, int player) {
//Loop through everything south
boolean isthereAnOppositePlayer=false;
int oppositePlayer=0;
//Set opposite player
if (player==1) {
oppositePlayer=2;
}else{
oppositePlayer=1;
}
for (int i = point.getVertical(); i < 8; i++) {
//Create a location point with the current location being compared
MyLocation locationBeingChecked= new MyLocation();
locationBeingChecked.setHorizontal(point.getHorizontal());
locationBeingChecked.setVertical(i);
int value = board[locationBeingChecked.getVertical()][locationBeingChecked.getHorizontal()];
//If the first checked is the opposite player
if (value==oppositePlayer) {
//Then potential to evaluate more
isthereAnOppositePlayer=true;
}
//If it isn't an opposite player, then break
if(!isthereAnOppositePlayer && value!=0){
break;
}
//If another of the player's piece found or 0, then end
if (isthereAnOppositePlayer && value==player || isthereAnOppositePlayer && value==0) {
break;
//end
}
//Add to number of players to flip
if(isthereAnOppositePlayer && value==oppositePlayer && value!=0){
//add to array
addToPiecesToTurn(locationBeingChecked);
}
}
}
It looks like the locations that got rotated back to the other player are the exact same as those rotated during the first move. I would guess that the array being populated by addToPiecesToTurn is perhaps not being cleared out between each move, so all the previous locations are still in there.
If you are storing the pieces to be turned in an ArrayList, you can use the clear() method to erase the contents of the collection between each turn.
Another possible problem is that you are checking for the opposite player, and then instantly beginning to populate addToPiecesToTurn. However, the pieces in that direction are not necessarily valid to be rotated unless they are "sandwiched" in by a second location containing the current player's piece. I don't think your code is properly checking for that case; when that happens, you'll want to somehow skip flipping those pieces to the other player, such as clearing out the array of piecesToTurn.
Edit: Looking at your current solution where you are implementing every direction separately, you are going to have a lot of duplicated code. If you think about what it means to walk along a certain direction, you can think of it as adjusting the x/y value by a "step" amount. The step amount could be -1 for backwards, 0 for no move, or 1 for forwards. Then you could create a single method that handles all directions without duplicating the logic:
private void checkDirection(Location point, int player, int yStep, int xStep) {
int x = point.getHorizontal() + xStep;
int y = point.getVertical() + yStep;
MyLocation locationBeingChecked = new MyLocation();
locationBeingChecked.setHorizontal(x);
locationBeingChecked.setVertical(y);
while (isValid(locationBeingChecked)) {
// do the logic here
x += xStep;
y += yStep;
locationBeingChecked = new MyLocation();
locationBeingChecked.setHorizontal(x);
locationBeingChecked.setVertical(y);
}
}
You would need to implement isValid to check that the location is valid, i.e., in the board. Then you could call this method for each direction:
// north
checkDirection(curPoint, curPlayer, -1, 0);
// north-east
checkDirection(curPoint, curPlayer, -1, 1);
// east
checkDirection(curPoint, curPlayer, 0, 1);
// etc
This is the sort of problem that is ripe for some unit testing. You could very easily set up a board, play a move, and validate the answer, and the test results would give plenty of insight into where your expectations and reality diverge.
why didn't you use a 2d array ?
each cell would contain an enum : EMPTY, PLAYER_1, PLAYER_2 .
then, in order to go over the cells, you simply use loops for each direction.
for example, upon clicking on a cell , checking to the right would be:
for(int x=pressedLocation.x+1;x<cells[pressedLocation.y].length;++x)
{
Cell cell=cells[pressedLocation.y][x];
if(cell==EMPTY||cell==currentPlayerCell)
break;
cells[pressedLocation.y][x]=currentPlayerCell;
}
checking from top to bottom would be:
for(int y=pressedLocation.y+1;y<cells.length;++y)
{
Cell cell=cells[y][pressedLocation.x];
if(cell==EMPTY||cell==currentPlayerCell)
break;
cells[y][pressedLocation.x]=currentPlayerCell;
}
Im making a text based battleship game and the player plays against the computer. 3 random 3 unit long ships are placed on the board, and I want the computer to be able to guess around where his last guess was if his last guess was a hit. (but I want it to work so that he keeps guessing around the same spot until he got a hit and keep guessing around there until he gets the whole ship, or 3 hits)
It works a bit; the computer will guess near his last guess if it was a hit, but if he misses that guess then he starts guessing randomly again. Can someone help me out a bit?
-getGuess() method is the one with the AI-
/*
* computer class to handle computers guesses/ etc
* most methods are copied from player class, but slightly altered to account for variable names
* Methods that havent been copied have comments
*/
public class Computer{
static int firstCo, secondCo;
static int[] guessedHits={7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
//int array to store last guess
static int[] lastGuess = new int[2];
//int array to store current guess
static int[] guess=new int[2];
public static int[] computerShip1=new int[6];
public static int[] computerShip2=new int[6];
public static int[] computerShip3=new int[6];
/*
* method to choose random guess for computer - but make it guess around last guess if last guess was a hit
* return guess coordinate numbers in an array
*/
public static int[] getGuess(){
int[] guess=new int[2];
int firstCo, secCo;
int ran; //random int between 0 and 1 - will help to make random choices for guesses
if(isHit(lastGuess[0],lastGuess[1])){
ran=(int)(Math.random()*2);
//if ran is 0 and last guesses x coordinate was correct, set next guess to last x, and next y to last y +1
if((ran==0 && lastGuess[0]==Player.playerShip1[0]) || (ran==0 && lastGuess[0]==Player.playerShip1[2]) || (ran==0 && lastGuess[0]==Player.playerShip1[4])){
guess[0]=lastGuess[0];
guess[1]=lastGuess[1]+1;
//if ran is 1 and last guesses x coordinate was correct, set next guess to last x, and next y to last y -1
}else if((ran==1 && lastGuess[0]==Player.playerShip1[0]) || (ran==1 && lastGuess[0]==Player.playerShip1[2]) || (ran==1 && lastGuess[0]==Player.playerShip1[4])){
guess[0]=lastGuess[0];
guess[1]=lastGuess[1]-1;
//if ran is 0 and last guesses y coordinate was correct, set next guess to last y, and next x to last x +1
}else if((ran==0 && lastGuess[1]==Player.playerShip1[1]) || (ran==0 && lastGuess[1]==Player.playerShip1[3]) || (ran==0 && lastGuess[1]==Player.playerShip1[5])){
guess[0]=lastGuess[0]+1;
guess[1]=lastGuess[1];
//if ran is 1 and last guesses y coordinate was correct, set next guess to last y, and next x to last x -1
}else if((ran==1 && lastGuess[1]==Player.playerShip1[1]) || (ran==1 && lastGuess[1]==Player.playerShip1[3]) || (ran==1 && lastGuess[1]==Player.playerShip1[5])){
guess[0]=lastGuess[0]-1;
guess[1]=lastGuess[1];
}
return guess;
}else{
guess[0]=(int)(Math.random()*7);
guess[1]=(int)(Math.random()*7);
return guess;
}
}
public static boolean isHit(int firstC, int secC){
for(int i=0; i<Player.playerShip1.length; i=i+2){
if(firstC==Player.playerShip1[i] && secC==Player.playerShip1[i+1]){
return true;
}
if(i==4){
break;
}
}
for(int i=0; i<Player.playerShip2.length; i=i+2){
if(firstC==Player.playerShip2[i] && secC==Player.playerShip2[i+1]){
return true;
}
if(i==4){
break;
}
}
for(int i=0; i<Player.playerShip3.length; i=i+2){
if(firstC==Player.playerShip3[i] && secC==Player.playerShip3[i+1]){
return true;
}
if(i==4){
break;
}
}
return false;
}
public static void addHits(int firstC, int secC){
int index=-1;
for(int i=0; i<guessedHits.length; i++){
if(guessedHits[i]==7){
index=i;
break;
}
}
guessedHits[index]=firstC;
guessedHits[index+1]=secC;
}
public static void setComputerShips(){
int randX, randY;
int direction; //will be random int 0-1, determines direction ship will extend(up/down, left/right)
randX=(int)(Math.random()*7);
randY=(int)(Math.random()*7);
direction=(int)(Math.random()*2);
computerShip1[0]=randX;
computerShip1[1]=randY;
if(direction==0){//extend upwards or downwards 2 units(y values change, x stays the same)
computerShip1[2]=randX;
computerShip1[4]=randX;
if(randY>3){//if y value is greater than 3, has to extend down or it wont fit
computerShip1[3]=randY-1;
computerShip1[5]=randY-2;
}else if(randY<2){//if y value is less than 2, has to extend up or it wont fit
computerShip1[3]=randY+1;
computerShip1[5]=randY+2;
}else{//if direction doesnt matter, just extend upwards
computerShip1[3]=randY+1;
computerShip1[5]=randY+2;
}
}else if(direction==1){//extends left or right 2 units(y values stay the same, x changes)
computerShip1[3]=randY;
computerShip1[5]=randY;
if(randX>3){//if x is greater than 3, must extend left or it wont fit
computerShip1[2]=randX-1;
computerShip1[4]=randX-2;
}else if(randX<2){//if x is less than 2, must extend right or it wont fit
computerShip1[2]=randX+1;
computerShip1[4]=randX+2;
}else{//if direction doesnt matter, just extend right
computerShip1[2]=randX+1;
computerShip1[4]=randX+2;
}
}
//do same for both other ships
do{
randX=(int)(Math.random()*7);
randY=(int)(Math.random()*7);
}while((randX==computerShip1[0] && randY==computerShip1[1])||(randX==computerShip1[2]&&randY==computerShip1[3])||(randX==computerShip1[4]&&randY==computerShip1[5]));
direction=(int)(Math.random()*2);
computerShip2[0]=randX;
computerShip2[1]=randY;
if(direction==0){
computerShip2[2]=randX;
computerShip2[4]=randX;
if(randY>3){
computerShip2[3]=randY-1;
computerShip2[5]=randY-2;
}else if(randY<2){
computerShip2[3]=randY+1;
computerShip2[5]=randY+2;
}else{
computerShip2[3]=randY+1;
computerShip2[5]=randY+2;
}
}else if(direction==1){
computerShip2[3]=randY;
computerShip2[5]=randY;
if(randX>3){
computerShip2[2]=randX-1;
computerShip2[4]=randX-2;
}else if(randX<2){
computerShip2[2]=randX+1;
computerShip2[4]=randX+2;
}else{
computerShip2[2]=randX+1;
computerShip2[4]=randX+2;
}
}
do{
randX=(int)(Math.random()*7);
randY=(int)(Math.random()*7);
}while((randX==computerShip1[0] && randY==computerShip1[1])||(randX==computerShip1[2]&&randY==computerShip1[3])||(randX==computerShip1[4]&&randY==computerShip1[5])||(randX==computerShip2[0] && randY==computerShip2[1])||(randX==computerShip2[2]&&randY==computerShip2[3])||(randX==computerShip2[4]&&randY==computerShip2[5]));
direction=(int)(Math.random()*2);
computerShip3[0]=randX;
computerShip3[1]=randY;
if(direction==0){
computerShip3[2]=randX;
computerShip3[4]=randX;
if(randY>3){
computerShip3[3]=randY-1;
computerShip3[5]=randY-2;
}else if(randY<2){
computerShip3[3]=randY+1;
computerShip3[5]=randY+2;
}else{
computerShip3[3]=randY+1;
computerShip3[5]=randY+2;
}
}else if(direction==1){
computerShip3[3]=randY;
computerShip3[5]=randY;
if(randX>3){
computerShip3[2]=randX-1;
computerShip3[4]=randX-2;
}else if(randX<2){
computerShip3[2]=randX+1;
computerShip3[4]=randX+2;
}else{
computerShip3[2]=randX+1;
computerShip3[4]=randX+2;
}
}
}
public static boolean hasWon(){
if(guessedHits[17]!=7)
return true;
else
return false;
}
}
Your getGuess() function is the one you're after right?
1) You never account for times when you guess the same spot twice. Make a boolean value that determines whether the coordinates you're attempting to guess haven't already been guessed.
2) Your method of keeping ship coordinates is very awkward where 0,2,4 are X coords while 1,3,5 are Y coords? You're better off creating a Ship class that handles coordinates, and checks like isHit.
public class Ship {
int[] xCoords = new int[3];
int[] yCoords = new int[3];
public boolean isHit(int x, int y) {
return (Arrays.asList(xCoords).contains(x) && Arrays.asList(yCoords).contains(y));
}
}
Then you can:
if (Player.ship1.isHit(guess[0],guess[1])) {
....
}
At the very heart of it you have a little ways to go. You'll get better responses here if you start working at the problem then come back with specific problems you may have. Try to be as concise as possible when giving code snippets because not many people will spend much time going through an entire class to find a line or two giving issues.
Good luck!
---PS---
I wrote a battleship game about 3-4 years ago with some fairly advanced AI. I'll link it here:
https://github.com/GrahamBlanshard/AI-Battleship/blob/master/prograham/battleship/player/AIPlayer.java
First, I apologize for the... lame code (I was a much younger programmer, I swear!). If you want to view it to get hints that is fine. A brief explanation:
At the heart of it you need to create some form of datatype that stores his hits. Once a "hit" is scored you push it to the datatype, I used a Stack. The shots that are successful hits get stored on the stack until the ship is sunk. At that point it removes shots from the stack that belonged to the ship that just sunk. If there are shots still on the stack it knows it has hit a second ship during that process and continues to guess in the area.
To accomplish this, it goes through phases:
1) Shoot randomly until a hit.
2) Shoot around that shot (use a random(4) call to get N/S/E/W direction)
-- Keep doing this until you score a second shot
3) Create a "line" with the two points and fire along it until the ship sinks or...
4) Reverse the line and shoot the other direction.
Does that give you a good start to work with?
That's a lot of code to look at. So for now I will give some general suggestions that come to mind:
When the computer AI gets a "hit", set a "global" flag (more likely a class variable) and "remember" where the hit occured. On the following turns, guess the neighboring squares in some predetermined order (say north, south, east, west) until another hit is found. Then set another flag and on the next turn guess in the same direction as the second hit. The initial flag should only be reset when all three hits are found. This should fix the problem that a subsequent miss causes the computer AI to start guessing randomly again.