Java: Skydiving - java

Sorry for lack of details, I made a few edits.
I've got a problem in my java class that I can't wrap my head around.
I need to make a program that draws random numbers which are formations in a 10 round competition.
In this competition judges score you based on the formations you draw.
You can only have 5 or 6 points per round. You can only have 6 points if you draw 3 - 2 point formations.
The range of formations is 1-38.
Formations 1-16 are worth 1 point.
The rest are worth 2 points.
I tried this.
int formation;
int points;
int round;
boolean isOnePoint;
int maneuvers = 0;
public void main(String args[]){
while(points < 5){
getRandomFormation();
if(points < 5 && isOnePoint){
points++;
}
else if(points == 4 && !isOnePoint && maneuvers < 3){
points +=2;
} maneuvers++;
}
}
public void getRandomFormation(){
formation = rand.nextInt(38);
if(formation < 17){ isOnePoint = true; } else isOnePoint = false;
}
The problem I am facing is with this code that I came up with I am still able to get something like:
// example of output round with points recieved
Round 6: 1, 2, 1, 2
The problem however, is that you cannot get 6 points with anything other than getting three random 2 point combinations...
What am I overlooking / missing in my code to be able to get it right?

Based off what you have posted you seem to only want three numeric values.
Change your while(points<5) to while(maneuver<3) and increment maneuver at the end of the loop.
That would be the quickest way to solve your problem. The logic in your if statements are quite convoluted. You only check to see the number of maneuvers in the second if statement which means that you can still meet the parameters for the first if.
for(int i=0;i<3;i++){
getRandomFormation();
if(isOnePoint)
points++;
else
points +=2;
}

Related

How to pull numbers from an array

I currently have java homework that I would appreciate some help with. We are to calculate a team record scenario.
We are given the following numbers:
Team1 Points
{23,45,65,20}
Opponent Points
{20,30,20,18}
I threw these into an array. I also created a public boolean. Basically, you are to pull these points from the array to the boolean? And let the boolean decide which team won? Obviously team1 has won, but we are supposed to let the computer decide, not the human.
Here is my code:
public class TeamScore {
public static boolean Winner(int team1Points, int opponentPoints) {
if (team1Points > opponentPoints) {
return true;
} else {
return false;
}
}
public static void main(String[] args) {
// Scanner in = new Scanner(System.in);
int[] team1Points = { 23, 45, 65, 20 };
int[] opponentPoints = { 20, 30, 20, 18 };
int team1 = 1;
int opponent = 1;
for (int i = 0; i < 5; i++) {
if (Winner(team1Points[i], opponentPoints[1])) {
team1 += 1;
} else {
opponent += 1;
}
}
for (int i = 0; i < 5; i++) {
if (team1 > 0 && opponent == 0) {
System.out.println("Team 1 has the perfect record!");
} else {
System.out.println("Win" + Arrays.toString(team1Points));
System.out.println("Loss" + Arrays.toString(opponentPoints));
}
}
}
Could anyone possibly help me? I am currently in programming II, but I did not have the best teacher in programming I. Any help would be appreciated!
EDIT:
I do not think this is a duplicate question because I already can fix it by changing the variable i-->1. My problem is that the computer thinks that team1 has already won regardless of the score.
When I run the code I am getting an java.lang.ArrayIndexOutOfBoundsException error. However when I change team1Points[i] to team1Points[1] then it goes okay and tells me that "Team 1 has the perfect record!". However, if I change some of the array values for team1Points to be less than opponentPoints then it still says "Team 1 has the perfect record!".
Not sure why you have a method Winner (also as Kevin said, it should be winner because of naming conventions) which turns ´(a > b)´ into a large if-statement. Similar stuff appear elsewhere in your code.
Your variables ´team1, opponent = 1´ inexplicably start with the value 1, am I to understand this as a way for your code to imply to a reader that both teams initialize at a win? Using 0 would probably make more sense.
Your game ought to crash from an indexoutofboundsexception at ´team1Points[i]´, as you have arrays of length 4, but your loops runs 5 times (the currently used range is [0-4], inclusive). Changing your loops to i=1 won't help, as the issue is that you eventually encounter team1Points[4] due to the i < 5 statement.
I don't know what game you are modelling or how it works, but the comparison ´Winner(team1Points[i],opponentPoints[1])´ looks like a blatant error to me (you always look at the opponents score for their second round).
Why are you printing your results 5 times? If you want to print the first message only when team1 won all rounds and the point for each round otherwise, you would need to use the loops counter as an index to the arrays in second case. First case should break loop so its not written five times, in addition you don't need to check team1>0 && opponent==0 as it's enough to only check if ´opponent==0´ (speaking of this conditional, it only works if you initialize the variables at 0 as I mentioned before). You could have checked if team1 equals size of the array instead, but imo thats more of a hassle than opponent==0.
Lastly, please fix your indenting. use the preview system so you can make double sure before posting.
Edit: Kevin also brings up a good point that you should be using the length of the array in your loops second statement.

Trouble understanding dynamic programming

I came across this problem. Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
This is an example of dynamic programming. But a very difficult or confusing concept for me when i come an exercise. I have watched videos and read tutorials online and it seems pretty easy at first but when i approach a problem then i'm totally lost.
So i found a solution online and that uses a bottom approach:
public init minmumTotal(ArrayList<ArrayList<Integer>> triangle) {
if (triangle.size() == 0 || triangle == null)
return 0;
int[] dp = new int[triangle.size()+1]; // store each index’s total
for (int i = triangle.size()-1; i >=0; i--) {
for (int j = 0; j < triangle.get(i).size(); j++) {
// first round: dp[j], dp[j+1] are both 0
dp[j] = Math.min(dp[j], dp[j+1]) + triangle.get(i).get(j);
}
}
return dp[0];
}
Seems easy after going through the solution. But can this be done using a top down approach? And could someone explain why the bottom approach is better than the top down approach? Also when is it appropriate to use either top down or bottom up? And also since the question mentioned that each "Each step you may move to adjacent numbers on the row below." Does that mean for each row iterate the whole column before i step into the next row?
I'm not sure if this solution counts as dynamic programming, but I think it is very efficient.
You can start at the bottom of the triangle, and then collapse it by moving upwards in the triangle. For each number in the next row, add the lowest number of the two numbers below it. When you get to the top, you will only have one number, which would be your result. So you would get this:
Start:
2
3 4
6 5 7
4 1 8 3
Step 1:
2
3 4
7 6 10
Step 2:
2
9 10
Step 3:
11
A little off topic but the first if-statement in that solution needs to be turned around if you really want to handle NullPointerExceptions the right way.
So I tried myself at a top down approach and there are a couple of problems.
First, like marstran already said, you have more numbers in the end and need to do a minimum search.
Second, the bottom up approach used an additional array field to make sure it wouldn't run into IndexOutOfBound Exceptions. I didn't really find a good way to do that in top down (the bottom up approach has the advantage that you always know you have two numbers to look at (left child and right child) with the top down approach a lot of nodes don't have a right or left parent). So there's a couple of additional if-statements.
public static int minimumTotal(ArrayList<ArrayList<Integer>> triangle) {
if (triangle == null || triangle.isEmpty()) return 0;
int[] results = new int[triangle.size()];
for (int i = 0; i < triangle.size(); i++) {
ArrayList<Integer> line = triangle.get(i);
for (int j = line.size() - 1; j >= 0; j--) {
if (j == 0) results[j] = line.get(j) + results[j];
else if (j >= i) results[j] = line.get(j) + results[j - 1];
else results[j] = line.get(j) + Math.min(results[j], results[j - 1]);
}
}
int minimum = results[0];
for (int i = 1; i < results.length; i++) {
if (results[i] < minimum) {
minimum = results[i];
}
}
return minimum;
}
Anyway this is as close to the given solution as I could get with a top down approach.
Keep in mind though that nobody is forcing you to only use a 1d array for your results. If that concept is too difficult to just come up with, you could simply use a 2d array. It will increase the amount of code you need to write, but maybe be a little easier to come up with.

How to make my room sorter more random?

So I'm working on a program which is supposed to randomly put people in 6 rooms (final input is the list of rooms with who is in each room). So I figured out how to do all that.
//this is the main sorting sequence:
for (int srtM = 0; srtM < Guys.length; srtM++) {
done = false;
People newMove = Guys[srtM]; //Guys is an array of People
while (!done) {
newMove.rndRoom(); //sets random number from 4 to 6
if (newMove.getRoom() == 4 && !room4.isFull()) {
room4.add(newMove); //adds person into the room4 object rList
done = true;
} else if (newMove.getRoom() == 5 && !room5.isFull()) {
room5.add(newMove);
done = true;
} else if (newMove.getRoom() == 6 && !room6.isFull()) {
room6.add(newMove);
done = true;
}
}
The problem now is that the code for reasons I don't completely understand (something with the way I wrote it here) is hardly random. It seems the same people are put into the same rooms almost every time I run the program. For example me, I'm almost always put by this program into room 6 together with another one friend (interestingly, we're both at the end of the Guys array). So how can I make it "truly" random? Or a lot more random than it is now?
Thanks in advance!
Forgot to mention that "rndRoom()" does indeed use the standard Random method (for 4-6) in the background:
public int rndRoom() {
if (this.gender == 'M') {
this.room = (rnd.nextInt((6 - 4) + 1)) + 4;
}
if (this.gender == 'F') {
this.room = (rnd.nextInt(((3 - 1) + 1))) + 1;
}
return this.room;
}
if you want it to be more random try doing something with the Random method, do something like this:
Random random = new Random();
for (int i = 0; i < 6; i++)
{
int roomChoice = random.nextInt(5) + 1;
roomChoice += 1;
}
of course this is not exactly the code you will want to use, this is just an example of how to use the Random method, change it to how you want to use it.
Also, the reason I did random.nextInt(5) + 1; is because if random.nextInt(5) + 1; gets you a random number from 0 to 5, so if you want a number from 1 to 6 you have to add 1, pretty self explanatory.
On another note, to get "truly" random is not as easy as it seems, when you generate a "random" number it will use something called Pseudo random number generation, this, is basically these programs produce endless strings of single-digit numbers, usually in base 10, known as the decimal system. When large samples of pseudo-random numbers are taken, each of the 10 digits in the set {0,1,2,3,4,5,6,7,8,9} occurs with equal frequency, even though they are not evenly distributed in the sequence.
There might be something wrong with code you didn't post.
I've build a working example with what your classes might be, and it is distributing pretty randomly:
http://pastebin.com/u8sZRxi6
OK so I figured out why the results don't seem very random. So the room sorter works based on an alphabetical people list of 18 guys. There are only 3 guy rooms (rooms 4, 5 and 6) So each guy has a 1 in 3 chance to be put in say, room 6. But each person could only possibly be in 2 of the 6 spots in each room (depending on where they are in the list).
The first two people for example, could each only be in either the first or second spot of each room. By "spot" I mean their place in the room list which is printed in the end. Me on the other hand am second last on the list, so at that point I could only be in either the last or second last spot of each room.
Sorry if it's confusing but I figured out this is the reason the generated room lists don't appear very random - it's because only the same few people could be put in each room spot every time. The lists are random though, it's just the order in which people appear in each list which is not random.
So in order to make the lists look more random I had to make people's positions in the room random too. So the way I solved this is by adding a shuffler action which mixes the Person arrays:
public static void shuffle(Person[] arr) {
Random rgen = new Random();
for (int i = 0; i < arr.length; i++) {
int randPos = rgen.nextInt(arr.length);
Person tmp = arr[i];
arr[i] = arr[randPos];
arr[randPos] = tmp;
}
}
TL;DR the generated room lists were random - but since the order of the people that got put into the rooms wasn't random the results didn't look very random. In order to solve this I shuffled the Person arrays.

Simulating Coin Tossing To Obtain 2 Heads Before 3 Tails (Java)

(Note: There are some similar problems, but I could not find an exact duplicate)
Question
Consider flipping a coin an arbitrary number of times. What is the probability that you obtain 2 heads before 3 tails?
Code
To simulate this, I set up 10000000 trials, where 0's are heads, 1's are tails, etc.
ArrayList<Integer> listOfTosses=new ArrayList<Integer>();
int numTrue=0;
int numTrials=0;
while(numTrials<10000000)
{
boolean record=false;
boolean twoHeads=false;
int counter=2;
listOfTosses.add((int) Math.random()*2);
listOfTosses.add((int) Math.random()*2);
if(listOfTosses.get(0)==0 && listOfTosses.get(1)==0)
{
twoHeads=true;
record=true;
}
listOfTosses.add((int) Math.random()*2);
while(record=false)
{
if(listOfTosses.get(counter)==0 && listOfTosses.get(counter-1)==0)
{
twoHeads=true;
record=true;
}
if(listOfTosses.get(counter)==1
&& listOfTosses.get(counter-1)==1
&& listOfTosses.get(counter-2)==1)
{
twoHeads=false;
record=true;
}
listOfTosses.add((int) Math.random()*2);
counter++;
}
if(twoHeads==true)
{
numTrue++;
}
record=false;
twoHeads=false;
listOfTosses.clear();
numTrials++;
}
System.out.print(numTrue/10000000.0);
Issue
The code compiles properly, but always gives me an answer of 1.0 (one can prove mathematically that the exact answer is 0.7).
One typo: change while(record=false) to while(record==false).
On top of that, your while loop that runs while record == false isn't running. This is because listOfTosses.get(0) and listOfTosses.get(1) are both set to 0.
When you do listOfTosses.add((int) Math.random()*2);, it's actually equivalent to listOfTosses.add(((int) Math.random()) * 2);. Since Math.random() < 1, that gets turned into a 0. Do listOfTosses.add((int) (Math.random()*2)); instead.
Alternatively, instead of dealing with converting floats, consider the java.util.Random class. The nextInt(int n) function looks like what you need.

Text based battleship enemy AI not working as wanted - Java

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.

Categories