i am trying to detect a jokerStraightFlush when analysing a poker hand.
I need to add a feature where this hand works 8S JK 6S JK 4S. The JK are jokers. I am using the exact same code logic as https://www.codeproject.com/Articles/38821/Make-a-poker-hand-evalutator-in-Java.
cardsTable represents the distribution of the Card ranks present in the hand. Each element of this array represents the amount of card of that rank(from 1 to 13, 1 being ace) present in the hand. So for 8S JK 6S JK 4S, the distribution would be
0 0 0 0 1 0 1 0 1 0 0 0 0 0
note that the position 1 is for ace (because it's simpler)
I need to find a way to detect if cardsTable[i] == 1 failed and decrement the amount of jokers used (numberOfJokers) to detect a jokerStraightFlush because in this incomplete piece of code, numberOfJokers dont decrement and i dont know how to write it in a nice way. What i do here is i check if the card at this rank exists cardsTable[i] == 1 or if its a joker... but i dont know how to check for a joker in the others consecutive rankings
I dont know if i'm clear, it's a twisted situation.. if i'm not let me know.
straight = false; // assume no straight
int numberOfJokers = 2; //(the maximum number of jokers in a hand is 2)
for (int i = 1; i <= 9; i++) { // can't have straight with lowest value of more than 10
numberOfJokers = 2 //reset the number of jokers available after each loop
if ((cardsTable[i] == 1 || numberOfJokers > 0) &&
(cardsTable[i + 1] == 1 || numberOfJokers > 0) &&
(cardsTable[i + 2] == 1 || numberOfJokers > 0) &&
(cardsTable[i + 3] == 1 || numberOfJokers > 0) &&
(cardsTable[i + 4] == 1 || numberOfJokers > 0)) {
straight = true;
break;
}
}
I also have this code but i don't know how to detect if the first condition failed so i can decrement the number of jokers remaining.
for (int i = 1; i <= 9; i++) {
numberOfJokers = 2
if (cardsTable[i] == 1 || numberOfJokers>0) {
if (cardsTable[i + 1] == 1 || numberOfJokers>0) {
if (cardsTable[i + 2] == 1 || numberOfJokers > 0) {
if (cardsTable[i + 3] == 1 || numberOfJokers > 0) {
if (cardsTable[i + 4] == 1 || numberOfJokers > 0) {
straight = true;
break;
}
}
}
}
}
}
Due to "short-circuiting" behaviour, you don't need to detect the left operand of a || resulted in true: the right operand gets evaluated if the left one was false, only.
(cardsTable[i + c] == 1 || numberOfJokers-- > 0) would work; note that
(numberOfJokers-- > 0 || cardsTable[i + c] == 1) would not.
Whether or not such code is maintainable or readable is an independent consideration, as is the quality of the overall approach to problem and solution.
Conceptually, you just need 3 of the 5 slots to be equal to 1, and the other 2 equal to 0. You could do something like this:
for (int i = 1; i <= 9; i++) {
boolean straight = true;
int numberOfJokers = 2;
for (int j = i; j <= i + 5; j++) { // I used a for loop instead of writing the statement 5 times
if (cardsTable[j] > 1) { // Can't have straight if more than one of a kind
straight = false;
}
if (cardsTable[j] == 0) {
numberOfJokers--;
}
}
if (numberOfJokers >= 0 && straight == true) {
break;
}
}
Alternatively, maybe a simpler way would be to add a position in the cardsTable array indicating the number of jokers.
nvm i used a function inside my conditions.. i don't know if it's the right way but it's logic to me x)
straight = false; // assume no straight
for (int i = 1; i <= 9; i++) // can't have straight with lowest value of more than 10
{
remainingJokers=jokers;
System.out.println("resetjokers : "+jokers);
if (cardsTable[i] == 1 || useJoker()) {
if (cardsTable[i + 1] == 1 || useJoker()) {
if (cardsTable[i + 2] == 1 || useJoker()) {
if (cardsTable[i + 3] == 1 || useJoker()) {
if (cardsTable[i + 4] == 1 || useJoker()) {
System.out.println("straight");
straight = true;
topStraightValue = i + 4; // 4 above bottom value
break;
}
}
}
}
}
}
}
private boolean useJoker() {
int remaining = remainingJokers;//remainingJokers is a global variable
remainingJokers--;
return remaining>0;
}
Related
I may just be tired and not thinking properly anymore, but why is "13" only printed once here? (intelliJ tells me that "i == 11 | i == 13" is always true but I don't see how that makes sense)
for (int i = 0; i < 14; i++) {
System.out.println(i);
String line = clientReader.readLine();
int length = line.length();
if (i == 0 || i == 5 || i == 6) {
line = line.substring(7, length - 6);
} else if (i == 1 || i == 2 || i == 3 || i == 4 || i == 8 || i == 9 || i == 10 || i == 12) {
line = line.substring(8, length - 7);
} else if (i == 7) {
line = line.substring(9, length - 8);
} else if (i == 11 || i == 13) {
line = line.substring(10, length - 9);
}
data[i] = line;
System.out.println(i);
}
p.s. The line.substring does not give an error, if I add System.out.println(line) at the end of the last else if it prints the correct thing.
The last else if is always true because your loop control variable runs from 0 until 13 and the only two numbers you haven't checked before the last else if is 11 and 13 therefore if none of the above conditions are true then i will either be 11 or 13 hence why IntelliJ is smart enough to know it's always true and hence control will always be bound inside the last else if block when the above conditions are not met.
If you increase the loop condition to something like i < 15 or above then IntelliJ wouldn't state else if (i == 11 || i == 13) is always true as i could be 14.
I am trying to solve this : Given an integer, return 1 if the number is between -5 and 5 exclusive and/or if it is an odd integer. If neither properties apply, return 0.
Here is what I have tried:
int rangeOrOdd(int val) {
if (val < 5)
return 1;
else if (val > 5)
return 1;
else if ((val%2)!=0)
return 0;
else
return 0;
}
The problem is that you are checking the different conditions individually. For instance, as soon as your number is smaller than 5, you return 1, which is wrong, because you would then return 1 for numbers like -1000.
Also, you are returning 0 for an odd number. You were supposed to return 1 in that case.
You have to combine your conditions using ANDs (&&) and ORs (||).
Here is a one liner that combines the different conditions correctly:
return ((val < 5 && val > -5) || val % 2 == 1) ? 1 : 0;
And if you don't like it in one line, you can always split it like this (but it's the same thing):
if ((val < 5 && val > -5) || val % 2 == 1) {
return 1;
} else {
return 0;
}
I made a Connect4 game recently and my Connect4 doesn't win the game when it's connected diagonally towards the right. And it only works for some combinations when it's connected diagonally to the left. Coordinates:- Top left: (0,0), Bottom left: (5,0), Top right: (0,6), Bottom right: (5,6). The Connect4 board is 6 by 7.
Problem: Connecting diagonally towards left works fine for only some combinations. But, none of the connections connected diagonally towards right work.
/** A method of winning diagonally towards the left side when playing connect 4 two player*/
/** Giving the new method with all the possible possibilities for a user to win diagonally-left */
public static void diagWinningLeft() {
for (int x = 5; x > 2; x--) { // Checks to see if same colored pegs are lining diagonally to the left
for (int y = 6; y > 3; y--) {
if (board[x][y] == 1 && board[x - 1][y - 1] == 1 && board[x - 2][y - 2] == 1 && board[x - 3][y - 3] == 1) {
JOptionPane.showMessageDialog(null, playerNames[0]+" has connected four diagonally-left in a row in " +(countForRed)+ " turns!");
b.drawLine(x,y,x-3,y-3);
}
if (board[x - 1][y - 1] == 1 && board[x - 2][y - 2] == 1 && board[x - 3][y - 3] == 1 && board[x - 4][y - 4] == 1) {
JOptionPane.showMessageDialog(null, playerNames[0]+" has connected four diagonally-left in a row in " +(countForRed)+ " turns!");
b.drawLine(x,y,x-3,y-3);
}
if (board[x][y] == 2 && board[x - 1][y - 1] == 2 && board[x - 2][y - 2] == 2 && board[x - 3][y - 3] == 2) {
JOptionPane.showMessageDialog(null, playerNames[1]+ " has connected four diagonally-left in a row in " +(countForYellow)+ " turns!");
b.drawLine(x,y,x-3,y-3);
}
}
}
}
/** Another method of winning diagonally towards the right side when playing connect 4 two player*/
/** Giving the new method with all the possible possibilities for a user to win diagonally-right*/
public static void diagWinningRight() {
for (int x = 0; x < 2; x++) { // Check to see if same colored pegs are lining diagonally to the right
for (int y = 0; y < 3; y++) {
if (board[x][y] == 1 && board[x + 1][y + 1] == 1 && board[x + 2][y + 2] == 1 && board[x + 3][y + 3] == 1) {
JOptionPane.showMessageDialog(null, playerNames[0]+" has connected four diagonally-right in a row in " +(countForRed)+ " turns!");
}
if (board[x][y] == 2 && board[x + 1][y + 1] == 2 && board[x + 2][y + 2] == 2 && board[x + 3][y + 3] == 2) {
JOptionPane.showMessageDialog(null, playerNames[1]+" has connected four diagonally-right in a row in " +(countForYellow)+ " turns!");
}
}
}
}
Forgive me for not directly answering the question, but this is stuff that will help you fix it and end up with better code and a better ability to write code in future.
Extracting the logic of your "if" condition into a separate method makes it easier to think about that logic on its own, and lets you test it independently of the rest of the program.
So instead of:
if (board[x][y] == 1 && board[x - 1][y - 1] == 1 && board[x - 2][y - 2] == 1 && board[x - 3][y - 3] == 1) {
JOptionPane.showMessageDialog(...)
}
... use:
if(isDiagonalLeft(x,y,1) { ... }
... and ...
boolean isDiagonalLeft(int x, int y, int player) {
return board[x][y] == player &&
board[x - 1][y - 1] == player &&
board[x - 2][y - 2] == player &&
board[x - 3][y - 3] == player
}
Now you can run unit tests on isDiagonalLeft() to make sure it works. That is, a small program that sets up a board and just runs isDiagonalLeft() to make sure it gives the right answer in various circumstances. This feels like extra work, but most people who try it learn that it saves effort by catching bugs early.
What you've done is to somewhat separate the game logic from the presentation code (JOptionPane), so that the presentation code is not in the way when you just want to exercise the game logic. Later on in your programming studies you'll encounter ways to separate these even more, like the Model-View-Controller model.
Pulling the logic out like this also helps if you need to ask questions on Stack Overflow -- by separating the game logic from Swing, you open up the question to potential answerers who don't know anything about Swing.
And, you can re-use this method, once for each player, rather than copying the logic into two places as you have.
If it doesn't work, use the debugger in your IDE to step through it.
Now that you've done this, you can smarten up the method so that the computer does the decrementing instead of the programmer...
boolean isDiagonalLeft(int x, int y, int player) {
for(int i = 0; i<4; i++) {
if(board[x-i][y-i] != player) {
return false;
}
}
return true;
}
...and you can generalise it so that it covers both directions of diagonal:
boolean isDiagonal(int x, int y, int player, boolean direction) {
int dirUnit = direction ? -1 : 1;
for(int i = 0; i<4; i++) {
if(board[x-i][y + dirUnit] != player) {
return false;
}
}
return true;
}
... so now you can re-use the method in 4 places; for each player and for each direction.
When you come across a situation where it doesn't work in your GUI, make a unit tests that sets up the board the way it is in the GUI, and runs isDiagonal() on it. If the test passes, you know the problem is somewhere else. If the test fails, you can work with a debugger and the method's code, to make it pass.
Following code should work:
//Winning diagonally towards left
public static void diagWinningLeft() {
for (int x = 5; x > 2; x--) { // Checks to see if same colored pegs are lining diagonally to the left
for (int y = 6; y > 2; y--) {
if (board[x][y] == 1 && board[x - 1][y - 1] == 1 && board[x - 2][y - 2] == 1 && board[x - 3][y - 3] == 1) {
JOptionPane.showMessageDialog(null, playerNames[0]+" has connected four diagonally-left in a row in " +(countForRed)+ " turns!");
b.drawLine(x,y,x-3,y-3);
}
if (board[x][y] == 2 && board[x - 1][y - 1] == 2 && board[x - 2][y - 2] == 2 && board[x - 3][y - 3] == 2) {
JOptionPane.showMessageDialog(null, playerNames[1]+ " has connected four diagonally-left in a row in " +(countForYellow)+ " turns!");
b.drawLine(x,y,x-3,y-3);
}
}
}
}
//Winning diagonally towards right
public static void diagWinningRight() {
for (int x = 5; x > 2; x--) { // Check to see if same colored pegs are lining diagonally to the right
for (int y = 0; y < 4; y++) {
if (board[x][y] == 1 && board[x - 1][y + 1] == 1 && board[x - 2][y + 2] == 1 && board[x - 3][y + 3] == 1) {
JOptionPane.showMessageDialog(null, playerNames[0]+" has connected four diagonally-right in a row in " +(countForRed)+ " turns!");
}
if (board[x][y] == 2 && board[x - 1][y + 1] == 2 && board[x - 2][y + 2] == 2 && board[x - 3][y + 3] == 2) {
JOptionPane.showMessageDialog(null, playerNames[1]+" has connected four diagonally-right in a row in " +(countForYellow)+ " turns!");
}
}
}
}
The problem with your code was that while checking towards right your coordinates(indices) continued to check for left direction(as there are 4 diagonals from a[x][y] viz. a[x-1][y-1], a[x+1][y+1] constituting diagonal in NW-SE direction(or left diagonal) and a[x-1][y+1], a[x+1][y-1] constituting diagonal in NE-SW direction(or right diagonal)).
Moreover your inner for loop didn't run to the limits.Hence, diagWinningLeft() didn't work at times..
I'm having an issue with my very first program in Java. I'm trying to reproduce a game you play with matches, but the program never stops when it's supposed to...
When I enter numbers like 6, 3, 2, 1 or 7, 3, 2, 1 the loop should stop there but it just continues to the next turn as if nothing happened, even though the variables have the right value and should match the end conditions.
I'm pretty sure the problem lies in the while part of the main loop (at the very end) but I can't see it! It's probably something obvious, but well...
Here is the full source code (the rules of the game are below it):
import java.util.Scanner;
public class JeuDeNim {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//Starting the game
int totalMatches;
do {
System.out.println("How many matches do you want to play with? "
+ "(from 6 to 60)");
totalMatches = sc.nextInt();
}
while(totalMatches < 6 || totalMatches > 60);
int matchesPlayer1 = 0;//to keep track of
int matchesPlayer2 = 0;//the previous round
int i = 1;//to know whose turn it is
do{
//player 1
if(!(i % 2 == 0)) {//if odd number, player 1
//round 1
if(i == 1) {
do {
System.out.println("Player 1: How many matches do you "
+ "want to pick? (1, 2 or 3)");
matchesPlayer1 = sc.nextInt();
}
while(matchesPlayer1 < 1 || matchesPlayer1 > 3);
totalMatches = totalMatches - matchesPlayer1;
i++;
}
//odd round x
else {
do {
System.out.println("Player 1: How many matches do you "
+ "want to pick this turn?");
matchesPlayer1 = sc.nextInt();
if(totalMatches - matchesPlayer1 < 0) {
System.out.println("Pick a smaller number");
//totalMatches cannot be negative
} else if(matchesPlayer1 == matchesPlayer2) {
System.out.println("You cannot pick the same number "
+ "of matches as Player 2");
}
}
while(matchesPlayer1 < 1 || matchesPlayer1 > 3
|| (totalMatches - matchesPlayer1 < 0)
|| (matchesPlayer1 == matchesPlayer2));
totalMatches = totalMatches - matchesPlayer1;
if(totalMatches == 0
|| (totalMatches == 1 && matchesPlayer1 == 1)) {
System.out.println("Player 1 Wins!");
}
i++;
}
}
//player 2
else {
//round 2
if(i == 2) {
do {
System.out.println("Player 2: How many matches do you "
+ "want to pick? (1, 2 or 3)");
matchesPlayer2 = sc.nextInt();
if(matchesPlayer2 == matchesPlayer1) {
System.out.println("You cannot pick the same "
+ "number of matches as Player 2");
}
}
while(matchesPlayer2 < 1 || matchesPlayer2 > 3
|| matchesPlayer2 == matchesPlayer1);
totalMatches = totalMatches - matchesPlayer2;
i++;
}
//even round x
else {
do {
System.out.println("Player 2: How many matches do you "
+ "want to pick this turn?");
matchesPlayer2 = sc.nextInt();
if (totalMatches - matchesPlayer2 < 0) {
System.out.println("Pick a smaller number");
//totalMatches cannot be negative
} else if(matchesPlayer2 == matchesPlayer1) {
System.out.println("You cannot pick the same number "
+ "of matches as Player 1");
}
}
while(matchesPlayer2 < 1 || matchesPlayer2 > 3
|| (totalMatches - matchesPlayer2 < 0)
|| (matchesPlayer2 == matchesPlayer1));
totalMatches = totalMatches - matchesPlayer2;
if(totalMatches == 0
|| (totalMatches == 1 && matchesPlayer2 == 1)) {
System.out.println("Player 2 Wins!");
}
i++;
}
}
System.out.println("totalMatches: " + totalMatches + " "
+ "matchesPlayer1: " + matchesPlayer1 + " " + "matchesPlayer2: "
+ matchesPlayer2);//to check that everything is working. It is not...
}
while(totalMatches > 0
|| !(!(i % 2 == 0) && totalMatches == 1 && matchesPlayer1 == 1)
|| !((i % 2 == 0) && totalMatches == 1 && matchesPlayer2 == 1));
}
}
Here are the rules of the game: it's a two-player game, where the players take turns picking matches (1, 2 or 3) and cannot pick the same number of matches as the other player: if player one picks 2 matches, player two will have to pick either 1 or 3 matches. The player who cannot pick anymore matches loses the game, which means there are two end scenarios : when there are no more matches, or there is 1 but the other player picked 1 during the previous round.
Look at the conditions in your final while loop
totalMatches > 0 ||
!(!(i % 2 == 0) && totalMatches == 1 && matchesPlayer1 == 1) ||
!((i % 2 == 0) && totalMatches == 1 && matchesPlayer2 == 1));
This means the loop will repeat as long as there are any matches left, or it isn't player 1's turn with 1 match left and a pick of 1 match, or it isn't player 2's turn with 1 match left and a pick of 1 match.
This can never happen because (among other reasons), it requires i%2==0 and i%2 != 0. Switch the || to &&, and it should fix the problem. As was pointed out in the comments, you also need to reverse the player turn check, because the turn counter has already been incremented by this point.
The reason you want to use && here instead of ||, like in the other spots in your code is that your checking for a different concept. Every other time, you check the reasons why the loop should be repeated. This time, you check the reasons why the loop should end, and negate them. When in doubt, actually plug in values for the comparison, and see if it evaluates to what you think it should.
The game ends when there is no more matches left. So while(totalMatches > 0); is just enough.
Remove the unnecessary lines:
|| !(!(i % 2 == 0) && totalMatches == 1 && matchesPlayer1 == 1)
|| !((i % 2 == 0) && totalMatches == 1 && matchesPlayer2 == 1));
I am having trouble finishing the straight method for a poker hand. I don't understand why my code doesn't work.
public static boolean containsStraight(int [] hand)
{
boolean straight = false;
for(int i = 0; i < 5; i++)
{
if (hand[i] == 2 && hand[i] == 3 && hand[i] == 4 && hand[i] == 5 && hand[i] == 6)
{
straight = true;
}
if (hand[i] == 3 && hand[i] == 4 && hand[i] == 5 && hand[i] == 6 && hand[i] == 7)
{
straight = true;
}
if (hand[i] == 4 && hand[i] == 5 && hand[i] == 6 && hand[i] == 7 && hand[i] == 8)
{
straight = true;
}
if (hand[i] == 5 && hand[i] == 6 && hand[i] == 7 && hand[i] == 8 && hand[i] == 9)
{
straight = true;
}
}
return straight;
}
As pL4Gu33 has already stated in his answer, your comparison is faulty. Essentially, each step through the for-loop leaves hand[i] at a constant value (say, 4). That means that your if-statements are checking:
if(4 == 4 && 4 == 5 && 4 == 6 && 4 == 7 && 4 == 8) {
...
}
This will never evaluate to true. If you knew for certain that you had five elements in the hand and that the hand was already sorted, you could do
if (hand[0] == 2 && hand[1] == 3 && hand[2] == 4 && hand[3] == 5 && hand[4] == 6) {
...
}
However, I'm going to show you a better answer.
The first thing you should do is to sort your hand. Once you do that, it's easy to step through the hand and check to see if the next card in the hand is exactly one greater than the previous card. If you get to the end and this holds true, then it's a straight.
/*
* You will need to import java.util.Arrays
*/
public boolean isStraight(int[] hand) {
if(hand == null || hand.length != 5) {
return false;
}
else {
// Automatically sort the hand
Arrays.sort(hand);
// Set the "previous" variable to a theoretically impossible value
int prev = -1;
// Iterate through the hand and see if the next card is exactly one more than
// the previous one.
for(int i = 0; i < hand.length; i++) {
// If prev is -1, then this is the first time through the for-loop
// If the card that we're on has a value of the previous card + 1,
// we still have the possibility of a straight.
if(prev == -1 || (prev + 1) == hand[i]) {
prev = hand[i];
}
else {
return false;
}
}
return true;
}
}
You say in every iteration hand[i] must be 2 AND 3 AND 4 AND 5. That is impossible. There is only one number in hand[i].
The problem is, that you are using the cycle incorrectly, because you are always checking the value of the same card in hand[i]. My suggestion would be either to do a sort first, or if you want to be more efficient, you can use a second field of booleans, that would indicate, whether a card of given value is present in your hand. This way you can easily check, if you have any number of cards in succesion.
public static boolean containsStraight(int[] cards) {
int count = 0;
boolean[] valueInHand = new boolean[10];
for (int card : cards) {
valueInHand[card] = true;
}
for (boolean value : valueInHand) {
if (value == true) {
count++;
} else {
count = 0;
}
// works for any number of cards
if (count == cards.length) {
return true;
}
}
return false;
}