So I'm having an issue simulating a game of craps. Everything runs properly except for the while loop within the while loop. When debugging, the sum variable is retaining it's value, the newSum variable is changing in every iteration, and often hitting 7 and the sum variable's value. If I comment out the nested while loop, and just have it as wins++;, then the code executes properly, to an expected value. So I'm quite certain the issue is within the nested loop.
Thanks for all your input!!
import java.util.Random;
import java.text.DecimalFormat;
public class Ch3Ex2
{
public static void main (String[] args)
{
Random rng = new Random();
int counter = 0;
int sum = 0;
int wins = 0;
int losses = 0;
int newSum = 0;
int reroll1 = 0;
int reroll2 = 0;
while (counter < 10000)
{
int die1 = rng.nextInt(6) + 1;
int die2 = rng.nextInt(6) + 1;
sum = die1 + die2;
if ((sum == 7) || (sum == 11))
wins++;
else if ((sum == 2) || (sum == 3) || (sum == 12))
losses++;
else
{
while((newSum != sum) || (newSum != 7))
{
reroll1 = rng.nextInt(6) + 1;
reroll2 = rng.nextInt(6) + 1;
newSum = reroll1 + reroll2;
}
if (newSum == sum)
{
wins++;
}
else
{
losses++;
}
}
counter++;
}
DecimalFormat percent = new DecimalFormat("0.00%");
double winDenom = wins + losses;
double winRate = wins/winDenom;
System.out.print("Your chance of winning a game of craps is : ");
System.out.println(percent.format(winRate));
}
}
The infinite loop is in this blook:
while((newSum != sum) || (newSum != 7))
{
reroll1 = rng.nextInt(6) + 1;
reroll2 = rng.nextInt(6) + 1;
newSum = reroll1 + reroll2;
}
because if you got a not 7 value in the first start, it will always be true and not stop.
i think you should replace the || with &&
so it could look like this:
while((newSum != sum) && (newSum != 7))
{
reroll1 = rng.nextInt(6) + 1;
reroll2 = rng.nextInt(6) + 1;
newSum = reroll1 + reroll2;
}
while((newSum != sum) || (newSum != 7))
This logic is incorrect. At the moment it will only ever exit if sum is equal to 7.
You need to use && not ||.
At your algorithm (newSum == sum) or (newSum == 7) conditions win so you will use the opposite of this action. After the logical negation
¬(x or y) = ¬x and ¬y
you will have this solution. That means you need to change your while condition as (newSum != sum) && (newSum != 7).
Your program will still be wrong as you never update newSum in nested while loop.
Once you enter the nested while loop, your newSum set to 7. Then it won't change anymore. Then this would cause your win chance to about 20%.
So you need update the newSum to 0 after a nested while loop terminate. Then the win change would be about 50%. You should
else
{
while((newSum != sum) || (newSum != 7))
{
reroll1 = rng.nextInt(6) + 1;
reroll2 = rng.nextInt(6) + 1;
newSum = reroll1 + reroll2;
}
if (newSum == sum)
{
wins++;
}
else
{
losses++;
}
newSum = 0;
}
Related
I added these 3 variable to make operation of finding the winner in O(1) time.
private final int[] rowSum, colSum;
private int diagSum;
private int revDiagSum;
rowSum array contains sum of each row in n * n board, similary colSum contains column sums and diagSum and revDiagSum contains sum in diagonal and reverse diagonal.
Min-Max logic :
// returns an array containing { x, y, score }
// n is board.size here.
private int[] minMax(int player, final int n) {
// At max level --> human's turn | At min level --> Computer's turn
// MIN == -1 | MAX == +1
int best[] = null;
if(player == MIN) {
best = new int[] {-1, -1, Integer.MAX_VALUE};
}
else if(player == MAX) {
best = new int[] {-1, -1, Integer.MIN_VALUE};
}
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if(board.get(i, j) == 0) {
int win = tryMove(i, j, player);
int []score = null;
if((win != 0) || board.filled()) {
// if this is the last move we can play in game, score is calculated.
score = new int[] {i, j, win};
}
else {
score = minMax(-1 * player, n);
}
undoMove(i, j, player);
if(player == MIN) {
if(score[2] < best[2]) {
best[0] = i;
best[1] = j;
best[2] = score[2];
}
}
else if(player == MAX) {
if(score[2] > best[2]) {
best[0] = i;
best[1] = j;
best[2] = score[2];
}
}
}
}
}
// return the optimal move(with score) player(=computer/human) can play by making a move.
return best;
}
private int tryMove(int i, int j, int player) {
int n = board.getSize();
board.set(i, j, player);
rowSum[i] += player;
colSum[j] += player;
if(i == j)
diagSum += player;
if(i + j == n - 1)
revDiagSum += player;
// if any of the sum == (+n / -n) means player won.
if(rowSum[i] == Math.abs(n) || colSum[j] == Math.abs(n) || diagSum == Math.abs(n) || revDiagSum == Math.abs(n)) {
return player;
}
return 0;
}
private int undoMove(int i, int j, int player) {
int n = board.getSize();
board.set(i, j, 0);
rowSum[i] -= player ;
colSum[j] -= player;
if(i == j)
diagSum -= player;
if(i + j == n - 1)
revDiagSum -= player;
return 0;
}
I call the above Min-Max func() always like this :
int[] move = minMax(-1, n); // always consider computer as the min-player and human as max player.
Now the issue I am facing is, whenever I am running this Game, I
("Human") am able to beat the computer which should not happen in the
ideal case as PC plays optimal moves everytime against us.
Tried debugging, but couldn't figure what's the issue here.
As per the logic, I am not able to suspect the issue in code.
Complete Code: https://github.com/tusharRawat821/Tic-Tac-Toe
Bug Fixed:
Below piece of code should be updated:
if(rowSum[i] == Math.abs(n) || colSum[j] == Math.abs(n) || diagSum == Math.abs(n) || revDiagSum == Math.abs(n)) {
....}
Corrected if condition :
if(Math.abs(rowSum[i]) == n || Math.abs(colSum[j]) == n || Math.abs(diagSum) == n || Math.abs(revDiagSum) == n) {
....}
The riddle I'm hoping to solve can be found in this video.
In case you're unable to watch the whole video, here is an outline of the riddle:
In short, I need to find the smallest number of points where there is guaranteed to be at least one single-color triangle from any arrangement of red and blue lines connecting every single pair of points.
Below is a Java program I wrote to solve it.
public class RedBlueTimeTravelProblem {
public static void main(String[] args) {
int max = 3;
boolean alltri = false;
long start, end;
double time;
while (!alltri) {
start = System.nanoTime();
int edgecount = max * (max - 1) / 2;
int combos = (int) Math.pow(2, edgecount);
alltri = false;
for (int i=1; i<=combos; i++) {
int a = i-1;
int[][] edge = new int[edgecount][3];
for (int j=0; j<edgecount; j++) {
edge[j][2] = a % 2;
a = (a - a % 2) / 2;
}
int c2 = 0;
for (int j=1; j<=max; j++) {
for (int k=j+1; k<=max; k++) {
edge[c2][0] = j;
edge[c2][1] = k;
c2++;
}
}
boolean tri = false;
for (int j=0; j<edgecount-2; j++) {
for (int k=j+1; k<edgecount-1; k++) {
for (int m=k+1; m<edgecount; m++) {
if ((edge[j][0] == edge[k][0] && ((edge[j][1] == edge[m][0] && edge[k][1] == edge[m][1]) || (edge[j][1] == edge[m][1] && edge[k][1] == edge[m][0]))) ||
(edge[j][0] == edge[k][1] && ((edge[j][1] == edge[m][0] && edge[k][0] == edge[m][1]) || (edge[j][1] == edge[m][1] && edge[k][0] == edge[m][0]))) ||
(edge[j][0] == edge[m][0] && ((edge[j][1] == edge[k][0] && edge[k][1] == edge[m][1]) || (edge[j][1] == edge[k][1] && edge[k][0] == edge[m][1]))) ||
(edge[j][0] == edge[m][1] && ((edge[j][1] == edge[k][0] && edge[k][1] == edge[m][0]) || (edge[j][1] == edge[k][1] && edge[k][0] == edge[m][0])))) {
tri = tri || (edge[j][2] == edge[k][2] && edge[k][2] == edge[m][2]);
}
}
}
}
alltri = alltri && tri;
}
end = System.nanoTime();
time = (end - start) / 1000000000.0;
System.out.println(max + ": " + time + " seconds");
max++;
}
System.out.println("DONE");
}
}
It seems to work so far in checking whether 3, then 4, 5, etc. points will guarantee a single color triangle, but its time complexity is ridiculous. For example, here are the times for 3-8 points:
3: 1.8475E-5 seconds
4: 2.59876E-4 seconds
5: 0.009313668 seconds
6: 0.192455789 seconds
7: 19.226652708 seconds
Based on the trend, 8 points will take 30 min to 1 hr, 9 points will take roughly a few days, 10 will take over 6 months, and well... nobody wants to wait that long.
Any suggestions on how to make my program more time efficient?
Edit: Apparently the answer was 6. Not only was my code inefficient, it was just plain wrong. Also thanks for the suggestions everyone.
I'm writing a Java program that will play a game.
Basically you choose the no. of players and rounds, then the program shows you what every player should say, in order, considering the following rules:
-assuming the players are standing in a circle, they start counting one-by-one clockwise until someone reaches a number (larger than 10) made of only the same digit. For example 11, 22, 33, .. , 444 etc, then they start counting counter clockwise
E.g.: P9: 9; P10: 10; P11: 11; P12: 13; P11: 14 etc (P10 = Player 10)
-when the get to a number that is multiple of 7, contains 7 or the sum of the digits is 7, they say "Boltz"
E.g.: P1: 13; P2: Boltz (instead of 14); P3: 15; P4 Boltz (16); P5: Boltz (17); P6:18 etc
I have the code in Java, but i can't seem to get the switching from clockwise turns to counterclockwise at numbers made up from only one digit
Can you please help me on SameDigits function? Thank you!
import java.util.Scanner;
public class Boltz {
private static Scanner keyboard;
public static void main(String[] args) {
keyboard = new Scanner(System.in);
int nPlayers = 0;
int nRounds = 0;
int currentPlayer = 0;
int sum = 0;
int x = 0;
boolean isSameDigit = true;
System.out.print("Cati jucatori sunt? ");
nPlayers = keyboard.nextInt();
System.out.print("Cate runde sunt? ");
nRounds = keyboard.nextInt();
System.out.print("Jucatori: " + nPlayers + "; Runde: " + nRounds + "\n");
for (x = 1; x <= nPlayers * nRounds; x++) {
isSameDigit = SameDigits(currentPlayer);
if (currentPlayer < nPlayers && isSameDigit == false) {
currentPlayer++;
} else {
currentPlayer = 1;
}
if (currentPlayer > 1 && isSameDigit == true) {
currentPlayer--;
} else {
currentPlayer = nPlayers;
}
sum = digitSum(x);
if (x % 7 == 0 || String.valueOf(x).contains("7") || sum == 7) {
System.out.println("P:" + currentPlayer + " Boltz");
} else {
System.out.println("P:" + currentPlayer + " " + x);
}
}
}
public static int digitSum(int num) {
int suma = 0;
while (num > 0) {
suma = suma + num % 10;
num = num / 10;
}
return suma;
}
public static boolean SameDigits(int num) {
int add = 0, add2 = 0;
while (num > 0) {
add = add + num % 10;
add2 = add2 + add % 10;
num = num / 10;
}
if (add == add2) {
return true;
} else {
return false;
}
}
}
If I understand you correctly, you want SameDigits to return true if the number is all the same digits and false otherwise. Single-digit numbers should also return true. This should do it:
public static boolean SameDigits(int num) {
if (num < 0) return false; // or something else?
int onesDigit = num % 10;
num /= 10;
while (num > 0) {
if (onesDigit != num % 10) return false; // fail if digits differ
num /= 10;
}
return true;
}
P.S. You should conform to Java naming conventions and name your methods starting with a lower-case letter (sameDigits instead of SameDigits).
That would be something like:
public static boolean sameDigits(int number) {
//speical case
if (number < 10)
return false;
String string = String.valueOf(number);
for (int i = 1; i <= 9; i++) {
if (string.replaceAll(String.valueOf(i), "").length() == 0)
return true;
}
return false;
}
I'd use a regular expression. This one checks whether a String consists of a single digit, followed by one or more repetitions of the same digit.
public static boolean sameDigits(int arg) {
return Integer.toString(arg).matches("(\\d)\\1+");
}
I don't get what does "unreachable code" means ?
Here in the last line of my code double probabilityOfWin = wins / (wins + loses); it says unreachable code.
import java.util.Random;
public class CrapsGame {
public static final int GAMES = 9999;
public static void main(String[] args) {
Random randomGenerator1 = new Random();
Random randomGenerator2 = new Random();
Random randomGenerator3 = new Random();
Random randomGenerator4 = new Random();
int dice1 = randomGenerator1.nextInt(6) + 1;
int dice2 = randomGenerator2.nextInt(6) + 1;
int comeoutSum = dice1 + dice2;
int point = 0;
// The comeout roll
if (comeoutSum == 7 || comeoutSum == 12)
System.out.println("wins");
else if ( comeoutSum == 2 || comeoutSum == 3 || comeoutSum == 12)
System.out.println("loses");
else
point = comeoutSum;
int wins = 0;
int loses = 0;
while(GAMES <= 9999)
{
dice1 = randomGenerator3.nextInt(6) + 1;
dice2 = randomGenerator4.nextInt(6) + 1;
int sum = dice1 + dice2;
if (sum == point)
wins++;
else if (sum == 7)
loses++;
}
double probabilityOfWin = wins / (wins + loses);
}
}
This loop here:
while(GAMES <= 9999)
{
...
}
resolves to while (true) because the value of GAMES is never modified. So any code that comes after (in your case, double probabilityOfWin = wins / (wins + loses);) is deemed unreachable.
You did not make any change to the constant GAME. So while loop will never terminate. Last line of code is unreachable.
Unreachable means the code never gets executed. For example,
return 15;
int a = 12;
Then the last line of code will not get executed because the function has already returned.
when i run the program the output is just continuous and doesnt end. The goal here is to try and get the + all the way to the left or the right, then print which side won and how many turns it took.
the code is executing now, but it only moves left and right one space from the middle, which makes me think its now with the for loops
package test;
import java.util.Scanner;
import java.lang.Math;
public class Test {
public static int MAX_LENGTH = 21;
public static int MIN_LENGTH = 5;
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
System.out.print("Enter the length of the rope: ");
int ropeLength = keyboard.nextInt();
while (ropeLength < MIN_LENGTH || ropeLength > MAX_LENGTH || ropeLength % 2 != 1) {
System.out.println("Thats not a valid length (odd number between 5 and 21)");
System.out.print("Enter the length of the rope: ");
ropeLength = keyboard.nextInt();
}
char a;
String flag = " ";
for (int i = 0; i < ropeLength / 2; i += 1) {
flag += "-";
}
flag += "+";
for (int i = 0; i < ropeLength / 2; i += 1) {
flag += "-";
}
System.out.println("");
do {
flag = "";
double rand = Math.random();
int i;
if (rand > 0.5) {
for (i = 0; i < (ropeLength / 2) - 1; i++) {
flag += "-";
}
flag += "+";
for (i = 0; i < (ropeLength / 2) + 1; i++) {
flag += "-";
}
System.out.println( flag );
}
if (rand < 0.5) {
for (i = 0; i < (ropeLength / 2) + 1; i++) {
flag += "-";
}
flag += "+";
for (i = 0; i < (ropeLength / 2) - 1; i++) {
flag += "-";
}
System.out.println( flag );
}
} while (flag.charAt(1) != '+' || flag.charAt(ropeLength) != '+');
if (flag.charAt(0) == '+') {
System.out.println("\nLeft side wins!");
}
else {
System.out.println("\nRight side wins!");
}
System.out.println("It took steps");
}
}
You need to pay attention to the position of the flag. Currently you only put the flag one position to the left or right of the center. You might want to pull your flag printing method into a helper method to ease readability and make it clearer what you need to keep track of.
Once you replace your three printing methods with calls to this method, it should become clearer what you need to keep track of and pass as parameters in order to get everything working.
Something like this should get you started:
public static void printFlag(int ropeLength, int flagPosition) {
for (int i = 0; i < flagPosition; i += 1) {
System.out.print("-");
}
System.out.print("+");
for (int i = flagPosition + 1; i < ropeLength; i += 1) {
System.out.print("-");
}
System.out.println();
}
Note: Using a StringBuilder instead of a bunch of print() calls is probably a good idea, but I'll leave that as an exercise to the reader.
There are multiple problems with the logic in your code.
1) In your do-while loop you always just keep appending to flag. This means that for every iteration your flag just gets bigger, it doesn't actually move the + that you have in there. You can have a temporary variable called 'nextState' to generate the next state and then set flag equal to it at the end.
Code:
String nextState = "";
if (rand > 0.5) {
for (i = 0; i < (ropeLength / 2) - 1; i++) {
nextState += "-";
}
nextState += "+";
for (i = 0; i < (ropeLength / 2) + 1; i++) {
nextState += "-";
}
flag = nextState;
System.out.println(flag);
}
2) You are checking if flag.charAt(1)=='+' and flag.charAt(ropeLength)=='+'. Since arrays have a 0 based index this is incorrect, you actually need 0 and ropeLength-1 respectively. (I do note that you did it correctly below the do-while loop).
3) The problem with your do-while loop is that if you correct errors 1 and 2, you will definitely move the + to the left and to the right, however you will NEVER be able to move it to position 0 (all the way left) or position ropeLength-1 (all the way right) with your current logic. Something like this can be done and you can similarly do it for the other if.
if (rand > 0.5) {
i = 0;
while (i + 1 < flag.length() && flag.charAt(i + 1) != '+') {
nextState += "-";
i++;
}
nextState += "+";
i++;
while (i < flag.length()) {
nextState += "-";
i++;
}
flag = nextState;
}
4) You initialize flag = " "; but you just want flag = ""; (an empty string) as flag only contains -'s and a +.
5) while (flag.charAt(0) != '+' || flag.charAt(ropeLength - 1) != '+'); is incorrect. It shold be && because your original statement will ALWAYS be true and the loop will never end. Your original statement will only be false if there is a + in the begining and in the end which is impossible.
6) Not really an issue but with your if (rand > 0.5) you could have used an if-else instead of two if's. If rand is exactly equal to 0.5 your code does nothing. Since you have to count steps you need to change one of them to rand <= 0.5 or rand >= 0.5 or just use an if-else.
Once you fix these problems. You are good to go. Great effort!
You never reset your flag at the start of each iteration
and you need the && operator as knoight says
you need something like:
do {
flag = "";
... your existing code
} while ( (flag.charAt(1) != '+') && (flag.charAt(ropeLength) != '+') );
it seems like your flag is going to randomly jump around with the fixes i've proposed above. perhaps you want to simply move the flag left or right one spot on each iteration?
you can do that like this:
int flagpos = (ropeLength / 2)+1;
do {
flag = "";
double rand = Math.random();
int i;
if (rand > 0.5) {
flagpos++;
else
flagpos--;
for (i = 0; i < flagpos - 1; i++)
flag += "-";
flag += "+";
for (i = flagpos + 1; i < ropeLength ; i++)
flag += "-";
System.out.println( flag );
} while (flag.charAt(1) != '+' || flag.charAt(ropeLength) != '+');
You need to change the last line, from:
while (flag.charAt(1) != '+' || flag.charAt(ropeLength) != '+');
to
while (flag.charAt(0) != '+' && flag.charAt(ropeLength) != '+');
Using || means that only ONE of those conditions has to be true, and since you are using a while loop, you're saying that if the first position is not equal to + OR the last position is not equal to + then you want the loop to continue.
As stated earlier the follow will work.
do {
flag = "";
//do stuff
} while (flag.charAt(1) != '+' && flag.charAt(ropeLength-1) != '+');
Problem is your flipping a coin to move the rope and the larger the rope length the smaller the chance you will ever reach the end.