So is there a way to simplify this to make is smaller in anyway?
else if(selectedCards.size() == 3
&& cardAt(selectedCards.get(0)).pointValue() + cardAt(selectedCards.get(1)).pointValue() + cardAt(selectedCards.get(2)).pointValue() == 0
&& !cardAt(selectedCards.get(0)).rank().equals(cardAt(selectedCards.get(1)).rank())
&& !cardAt(selectedCards.get(0)).rank().equals(cardAt(selectedCards.get(2)).rank())
&& !cardAt(selectedCards.get(1)).rank().equals(cardAt(selectedCards.get(2)).rank()))
From what I can see you're trying to test if the 3 cards have different ranks. An easier way to test this is to put them into a Set and see if the set size is same as selected set. This scales to any number of selected cards...
public boolean differentRanks(List<Integer> selectedCards) {
Set<Integer> ranks = new HashSet<Integer>();
for (int card : selectedCards) {
ranks.add(cardAt(card).rank());
}
return ranks.size() == selectedCards.size();
}
I'd also create a method to total the points for the selected cards...
public int sum(List<Integer> selectedCards) {
int total;
for (int card : selectedCards) {
total += cardAt(card).pointValue();
}
return total;
}
So the condition would end up
} else if (selectedCards.size() == 3 && sum(selectedCards) == 0 &&
differentRanks(selectedCards) {
This would be one option:
else if(selectedCards.size() == 3
&& cardAt(selectedCards.get(0)).pointValue() + cardAt(selectedCards.get(1)).pointValue() + cardAt(selectedCards.get(2)).pointValue() == 0
&& !(cardAt(selectedCards.get(0)).rank().equals(cardAt(selectedCards.get(1)).rank())).equals(cardAt(selectedCards.get(2)).rank()) )
To make more readable this condition you could do something like this:
//here you extract the values you need only once and use them in your condition block below
int cardsSize = selectedCards.size();
int pointValue0 = cardsSize == 3 ? cardAt(selectedCards.get(0)).pointValue() : 0;
int pointValue1 = cardsSize == 3 ? cardAt(selectedCards.get(1)).pointValue() : 0;
int pointValue2 = cardsSize == 3 ? cardAt(selectedCards.get(2)).pointValue() : 0;
bool rankEquals = CompareRanks(cardAt(selectedCards.get(0)),cardAt(selectedCards.get(1)),cardAt(selectedCards.get(2));
if (<condition>) {
//block of sentences
} else if (cardsSize == 3 && (pointValue0 + pointValue1 + pointValue2) == 0 && !rankEquals )
I'm suggesting the creation of a function called "CompareRanks" where you receive 3 different objects (result of "cardAt") and you get the rank in there and compare if the values are the same or not.
This option leads you to more lines of code but is cleaner and more readable for any person besides you.
In my opinion most readable:
else if(selectedCards.size() == 3 && checkRanks(selectedCards))
{
//...
}
//...
private boolean checkRanks(List<Card> cards)
{
Card zeroCard = cardAt(selectedCards.get(0));
Card firstCard = cardAt(selectedCards.get(1));
Card secondCard = cardAt(selectedCards.get(2));
boolean isZero = zeroCard.pointValue() + firstCard.pointValue() + secondCard.pointValue() == 0;
boolean zeroCardRankNotEqualFirst = !zeroCard.rank().equals(firstCard.rank())
boolean zeroCardRankNotEqualSecond = !zeroCard.rank().equals(secondCard.rank())
boolean firstCardRankNotEqualsSecond = !firstCard.rank().equals(secondCard.rank());
return isZero && zeroCardRankNotEqualFirst && zeroCardRankNotEqualSecond && firstCardRankNotEqualsSecond;
}
Related
I have a project for my computer science class that involves making a card game. Here's a basic look at the Card.
public Card(int value, int suit) {
if (value < 1 || value > 9) {
throw new RuntimeException("Illegal card value attempted. The " +
"acceptible range is 1 to 9. You tried " + value);
}
if (suit < 0 || suit > 4) {
throw new RuntimeException("Illegal suit attempted. The " +
"acceptible range is 0 to 4. You tried " + suit);
}
this.suit = suit;
this.value = value;
}
public int getValue() {
return value;
}
My issue is that my straight method doesn't seem to be working. What I tried to do was organize the cards in my hand from least to greatest and then do some if statements.
public static boolean hasStraight(Card [] cards) {
boolean exist = false;
Card[] other = new Card[cards.length];
for (int i = 0; i<cards.length; i++){
for (int j = 0; j<cards.length; j++){
if (cards[i].getValue()>cards[j].getValue()){
other[i]=cards[j];
other[j]=cards[i];
}
}
}
if (other[0].getValue()==1 && other[1].getValue()==2 && other[2].getValue()==3 && other[3].getValue()==4 && other[4].getValue()==5){
exist = true;
}
else if (other[0].getValue()==2 && other[1].getValue()==3 && other[2].getValue()==4 && other[3].getValue()==5 && other[4].getValue()==6){
exist = true;
}
else if (other[0].getValue()==3 && other[1].getValue()==4 && other[2].getValue()==5 && other[3].getValue()==6 && other[4].getValue()==7){
exist = true;
}
else if (other[0].getValue()==4 && other[1].getValue()==5 && other[2].getValue()==6 && other[3].getValue()==7 && other[4].getValue()==8){
exist = true;
}
else if (other[0].getValue()==5 && other[1].getValue()==6 && other[2].getValue()==7 && other[3].getValue()==8 && other[4].getValue()==9){
exist = true;
}
else if (other[0].getValue()==6 && other[1].getValue()==7 && other[2].getValue()==8 && other[3].getValue()==9 && other[4].getValue()==1){
exist = true;
}
return exist;
}
The length of Card[] is always 5. Every time I call the method, it returns true even if there isn't a straight. A straight is a condition where the values of the cards are consecutive without looping.
I seems to me that the sorting in the loops does not work. You can use Arrays.sort instead, but you have to write a Comparator for it or make Card implement Comparable. The code after the loops can be simplified to check if the difference of the last and first card is 4.
I was given this project by a friend who is coding in school, but I am trying to find a better way to code it. It is calling different Boolean methods, checking if true and adding to a count for latter use.
public static void testHand(PokerHand d) {
if (d.isRoyalFlush()) {
royalFlush++;
} else if (d.isStraightFlush()) {
straightFlush++;
} else if (d.is4OfAKind()) {
fourtOfAKind++;
} else if (d.isFullHouse()) {
fullHouse++;
} else if (d.isFlush()) {
flush++;
} else if (d.isStraight()) {
straight++;
} else if (d.is3OfAKind()) {
threeOfAKind++;
} else if (d.is2Pair()) {
twoPair++;
} else if (d.isPair()) {
pair++;
} else if(d.isHighCard()){
highCard++;
}
}
The code for PokerHand is as follows:
public class PokerHand {
private Card[] hand; // the hand of 5 cards
// the default constructor
public PokerHand() {
hand = new Card[5];
}
// A constructor to help with testing
public PokerHand(Card c0, Card c1, Card c2, Card c3, Card c4) {
hand = new Card[5];
hand[0] = c0;
hand[1] = c1;
hand[2] = c2;
hand[3] = c3;
hand[4] = c4;
}
/* This methods fills the hand with cards from the deck.
It uses an insertion sort so that the cards are ordered by rank.*/
public void fillHand(Deck deck) {
for (int i = 0; i < 5; i++) {
int j = i - 1;
Card temp = deck.dealCard();
while (j >= 0 && hand[j].getRank() > temp.getRank()) {
hand[j + 1] = hand[j];
j--;
}
hand[j + 1] = temp;
}
}
//PLACE ADDITIONAL METHODS AFTER THIS COMMENT
/*Checking for Royal flush by first checking if straight flush
and then if highest card is an Ace.*/
public boolean isRoyalFlush() {
return (isStraightFlush() && hand[4].getRank() == 14);
}
//Check for Straight Flush by seeing if it is both a straight and a flush
public boolean isStraightFlush() {
return (isFlush() && isStraight());
}
/*Checking if hand is a Four-of-a-kind. Done by looking at first card and
checking if it equals next 3 cards. If not, then checking second card and
checking if it equals next three cards.*/
public boolean is4OfAKind() {
boolean isFour = false;
for (int i = 0; i < hand.length - 3; i++) {
int card = hand[i].getRank();
if (card == hand[i + 1].getRank()
&& card == hand[i + 2].getRank()
&& card == hand[i + 3].getRank()) {
isFour = true;
}
}
return isFour;
}
//Checking if hand holds a Full House By:
public boolean isFullHouse() {
//Setting two boolean values
boolean a1, a2;
//First checking if it is a pair followed by a 3-of-a-kind.
a1 = hand[0].getRank() == hand[1].getRank() &&
hand[2].getRank() ==hand[3].getRank() && hand[3].getRank() == hand[4].getRank();
//Second, checking if it is 3-of-a-cind followed by a pair
a2 = hand[0].getRank() == hand[1].getRank() && hand[1].getRank() == hand[2].getRank() &&
hand[3].getRank() == hand[4].getRank();
//Returns true if it is either.
return (a1 || a2);
}
/*Checking if hand is a Flush by first getting the first card's suit
and checking if it is the same for all cards.*/
public boolean isFlush() {
String suit = hand[0].getSuit();
return hand[1].getSuit().equals(suit)
&& hand[2].getSuit().equals(suit)
&& hand[3].getSuit().equals(suit)
&& hand[4].getSuit().equals(suit);
}
/*Checking id hand is a Straight by first getting the rank of the first
card, then checking if the following cards are incremented by 1*/
public boolean isStraight() {
int card = hand[0].getRank();
return (hand[1].getRank() == (card + 1) &&
hand[2].getRank() == (card + 2) &&
hand[3].getRank() == (card + 3) &&
hand[4].getRank() == (card + 4));
}
/*Checking if hand is a Three-of-a-kind. Done by looking at first card and
checking if it equals next 2 cards. If not, then checking next card and
checking if it equals next 2 cards. This is done three times in total.*/
public boolean is3OfAKind() {
boolean threeKind = false;
for (int i = 0; i < hand.length - 2; i++) {
int card = hand[i].getRank();
if (card == hand[i + 1].getRank() &&
card == hand[i + 2].getRank()) {
threeKind = true;
}
}
return threeKind;
}
//Checking hand for 2 pairs by:
public boolean is2Pair() {
int count = 0; // Number of pairs.
int firstPair = 0; //If pair found, store rank.
//Go through hand
for (int i = 0; i < hand.length - 1; i++) {
int card = hand[i].getRank();
//Finding pairs. Cannot be same rank pairs.
if (card == hand[i + 1].getRank() && card != firstPair) {
firstPair = card;
count++;
}
}
return count == 2;
}
/*Checking if hand is a Pair. Done by looking at first card and
checking if it equals the next card. If not, then it checks the next card and
sees if it equals the next card. This is done four times in total.*/
public boolean isPair() {
boolean isPair = false;
for (int i = 0; i < hand.length - 1; i++) {
int card = hand[i].getRank();
if (card == hand[i + 1].getRank()) {
isPair = true;
}
}
return isPair;
}
//If hand is not equal to anything above, it must be High Card.
public boolean isHighCard() {
return !(isRoyalFlush() || isStraightFlush() || is4OfAKind()
|| isFullHouse() || isFlush() || isStraight()
|| is3OfAKind() || is2Pair() || isPair());
}
}
You could use the ternary operator ? : to shorten the code. Like
public static void testHand(PokerHand d) {
royalFlush += d.isRoyalFlush() ? 1 : 0;
straightFlush += d.isStraightFlush() ? 1 : 0;
fourtOfAKind += d.is4OfAKind() ? 1 : 0; // <-- this appears to be a typo.
fullHouse += d.isFullHouse() ? 1 : 0;
flush += d.isFlush() ? 1 : 0;
straight += d.isStraight() ? 1 : 0;
threeOfAKind += d.is3OfAKind() ? 1 : 0;
twoPair += d.is2Pair() ? 1 : 0;
pair += d.isPair() ? 1 : 0;
highCard += d.isHighCard() ? 1 : 0;
}
Alternatively, you could encode the hand types with an enum. Give the PokerHand a HandType (or create a factory method). Something like,
enum HandType {
ROYALFLUSH, STRAIGHTFLUSH, FOUROFAKIND, FULLHOUSE, FLUSH,
STRAIGHT, THREEOFAKIND, TWOPAIR, PAIR, HIGHCARD;
static HandType fromHand(PokerHand d) {
if (d.isRoyalFlush()) {
return ROYALFLUSH;
} else if (d.isStraightFlush()) {
return STRAIGHTFLUSH;
} else if (d.is4OfAKind()) {
return FOUROFAKIND;
} else if (d.isFullHouse()) {
return FULLHOUSE;
} else if (d.isFlush()) {
return FLUSH;
} else if (d.isStraight()) {
return STRAIGHT;
} else if (d.is3OfAKind()) {
return THREEOFAKIND;
} else if (d.is2Pair()) {
return TWOPAIR;
} else if (d.isPair()) {
return PAIR;
} else {
return HIGHCARD;
}
}
}
Then you can create an array of counts for testHand like
private static int[] handCounts = new int[HandType.values().length];
public static void testHand(PokerHand d) {
handCounts[HandType.fromHand(d)]++;
}
I would suggest you model the potential hands as an enum. They are a good use case because they have a fixed set of members.
Something like the following:
enum Rank {
ROYAL_FLUSH(Hand::isRoyalFlush),
FOUR_OF_A_KIND(Hand::isFourOfAKind),
...
public static Rank getRank(Hand hand) {
for (Rank rank: values()) {
if (rank.test.test(hand))
return rank;
}
throw new IllegalStateException("No rank for hand " + hand.toString());
}
private final Predicate<Hand> test;
Rank(Predicate<Hand> test) {
this.test = test;
}
}
Then all your if statements can be replaced by Rank.getRank(hand).
Maybe the switch statement will suit your needs :
switch (d) {
case d.isRoyalFlush() : royalFlush++; break;
case d.isStraightFlush(): straightFlush++; break;
... ... ...
default : do-something();
}
Can this code to be simplifed using for?
if ((col[0] == null) && (col[1] == null) && (col[2] == null) && (col[3] == null) && (col[4] == null)){
//statement
}
You can use a Java 8 feature with Stream API:
boolean allNull = Arrays.stream(col).allMatch(Objects::isNull);
Use a boolean flag:
boolean areAllNull = true;
for (int i = 0; i < col.length; i ++) {
if (col[i] != null) {
areAllNull = false;
break;
}
}
if (areAllNull) {
//statement
}
If you want to limit only to certain positions in the array change col.length by a variable or constant marking the limit:
int numberOfPositions = 5;
for (int i = 0; i < numberOfPositions ; i ++)`
To check if X elements in an array are null, you cannot reduce the number of checks (X) unless you can short-circuit them. However, you can have a cleaner "if" statement if you package it in a method:
if (isAllNull(col, 0, 4)){
// do stuff
}
public boolean isAllNull(Object[] col, int start, int end){
for (int index=start;index<=end;index++){
if (col[index] !=null){
return false;
}
}
return true;
}
This will return false immediately when it finds one of the values not null.
I am trying to make a cee-lo program in simple, simple java. I'm just learning. However when I get to my instant w. (i have simplified it for the test) it just always returns false. I can't seem to figure out why. It even displays the correct data but when it compares it it fails.
public class ceeLo
{
public static void main (String [] args)
{
Scanner scan= new Scanner (System.in);
int [] die = new int [3];
int answer;
boolean roll = true;
boolean qualifed;
boolean instantW;
boolean instantL;
do
{
System.out.println("Roll the dice?");
answer = scan.nextInt ();
if (answer == 0)
roll= false;
else
{
int i;
for (i = 0; i < die.length; i++)
{
die[i]= rollin();
System.out.println(diceTxt(die[i]));
}
qualifed = (qualify (die));
System.out.println("Qualified = " + qualifed);
instantW = (easyW (die));
System.out.println("Instant win = " + instantW);
}
}
while (roll);
}
// Generate random numbers for the roll
public static int rollin ()
{
Random rand = new Random();
int die= rand.nextInt(6);
return die;
}
//Check if dice qualify with pair
public static boolean qualify (int [] die)
{
boolean qualify;
//Pair Qualifying roll
if (die[0] == die[1] || die[0] == die[2] || die[1] == die[2])
qualify = true;
else
qualify = false;
return qualify;
}
//Check if instant win
public static boolean easyW (int [] die)
{
boolean instantW;
// show contents of die [x] for testing
System.out.println (die[0] + "" + die[1] + "" + die[2]);
if (die[0] > 2 && die [1] > 2 && die[2] > 2)
instantW = true;
else;
instantW = false;
return instantW;
}
}
Remove semi-colon after else; it should be just else
I guess the reason is,
instantW = false; is being treated as separate statement not part of else block. Which is why instantW is always being assigned to false and returning false.
It is always better to use {} to define block even though they are single liners. It is my preference.
As Greg Hewgill suggested, using single statement instantW = die[0] > 2 && die [1] > 2 && die[2] > 2; would do good than if/else.
A better way to write boolean methods is really to do something like
boolean easyW(int[] die)
{
return (die[0] > 2 && die[1] > 2 && die[2] > 2);
}
Or even better (more general)
boolean easyW(int[] die)
{
for(int roll : die)
{
if(roll < 2)
{
return false;
}
}
return true;
}
But in your case, you have a ; after your else. Fixed version:
public static boolean easyW (int [] die)
{
boolean instantW;
// show contents of die [x] for testing
System.out.println (die[0] + "" + die[1] + "" + die[2]);
if (die[0] > 2 && die [1] > 2 && die[2] > 2)
instantW = true;
else
instantW = false;
return instantW;
}
To explain what I'm doing, I'm basically taking a string of X's and O's as an input String, converting it to an array, so XXXOXOXOO as the input would be the same array. Then I'm checking each possible scenario where one could win, coordinate wise, and if it matches it through if statements it returns the number corresponding to who won.
But it's not quite working, haha. It seems to only output O as the winner, in clear cases where X should win.
Could anyone lend a hand? Much appreciated in advance, thanks.
import java.util.Scanner;
public class TicTacToe {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
System.out.println("Type in a board for analysis");
String b = keyboard.nextLine();
drawBoard(b);
int result = decide(b);
if (result == 1) {
System.out.println("Win for X");
}
else if (result == 0) {
System.out.println("Win for O");
}
else if (result == 3) {
System.out.println("Draw");
}
else {
System.out.println("Game Unfinished");
}
}
public static int decide(String scheme) {
int decision = 0;
String boardScheme[] = new String[9];
for (int i = 0; i < 9; i++) {
boardScheme[i] = scheme.substring(i,i+1);
}
if ((boardScheme[0] == boardScheme[1] && boardScheme[0] == boardScheme[2]) || (boardScheme[0] == boardScheme[3] && boardScheme[0] == boardScheme[6]) || (boardScheme[0] == boardScheme[4] && boardScheme[0] == boardScheme[8])) {
if (boardScheme[0] == "X") {
decision = 1;
}
else {
decision = 0;
}
}
else if (boardScheme[3] == boardScheme[4] && boardScheme[3] == boardScheme[5]) {
if (boardScheme[3] == "X") {
decision = 1;
}
else {
decision = 0;
}
}
else if (boardScheme[6] == boardScheme[7] && boardScheme[6] == boardScheme[8]) {
if (boardScheme[6] == "X") {
decision = 1;
}
else {
decision = 0;
}
}
else if (boardScheme[1] == boardScheme[4] && boardScheme[1] == boardScheme[7]) {
if (boardScheme[1] == "X") {
decision = 1;
}
else {
decision = 0;
}
}
else if ((boardScheme[2] == boardScheme[5] && boardScheme[2] == boardScheme[8]) || (boardScheme[2] == boardScheme[4] && boardScheme[2] == boardScheme[6])) {
if (boardScheme[2] == "X") {
decision = 1;
}
else {
decision = 0;
}
}
return decision;
}
public static void drawBoard(String scheme) {
if (scheme.length() == 9) {
String board[] = new String[9];
for (int i = 0; i < 9; i++) {
board[i] = scheme.substring(i,i+1);
}
System.out.println(board[0] + " | " + board[1] + " | " + board[2]);
System.out.println(board[3] + " | " + board[4] + " | " + board[5]);
System.out.println(board[6] + " | " + board[7] + " | " + board[8]);
}
else {
System.out.println("Please input 9 characters, no more, no less.");
}
}
}
You are not covering all the possible cases. What would happen if you had missed a case? sorry, I went through them and indeed you do cover each case correctly. However, as noted by Hovercraft Full Of Eels in the comment to the question, you are comparing strings incorrectly. Still I would suggest the below.
You are setting decision = 0, so whenever a case occur which you are not covering, then you will end up returning 0. Which will output 'O' wins.
So, what you need to do is to figure out each possible case that can happen and then check for it. I would also suggest that you use codereview.stackexchange.com and ask for advice on how to restructure your code a bit, it will make it easier for you in the end.
For example what if you had a function horizontalWin(int column) and verticalWin(int row) and diagonalWin().
Good luck!