I'm trying to create a hand evaluator that it will allow me to compare if one hand is better than another. I know there many other post on SO about this topic however many of them are old now and the links no longer link to anything useful. The only way I can think of doing this at the moment is to manually check for every different combination. Eg check for ace of any suit, if this doesn't exist then move to the next combination eg straight flush then 4 of a kind and so on. However, then how would you compare a pair of 2s to a pair of 3s unless you gave an integer to every combination of cards that made something interesting. However, that would very hard to do manually. Is there a better way?
Why hard?
class Card{
String suite;
int value;
....
}
// ...if two combinations are equal, Do for both combinations
int power = 0;
for (Card card: combination){
power += card.getValue()
}
// and compare!
I don't know if this is the best approach, but this could be possible and this is all manually.
Let's say you already have the code to determine which hand the player has in this format:
22s, KKs, 98o, 11o
Now you have an array with three values e.g.:
["K", "K", "s"]
...and another array:
[9, 8, "o"]
You first have to class those hands (like flush, straight etc.) to make sure which one will win (royal flush always win). And after those checks, you have to do some checks in the array. Check if it's suited or offsuit, if "K" is higher than 9 etc.
You can give them values like this:
...
8=8
9=9
10=10
J=11
Q=12
K=13
A=14 (or 1)
And then compare with that. This is a hard algorithm to do it properly without doing so many things manually. I hope someone who has experience with this takes my answer over and recover my mistakes or wrong steps/thoughts.
I would separate the problem for each type of combinations, and assign an integer for a specific occurence of a combination called ie. strength (so a Straight Flush of 5-4-3-2-A is the weakest and K-Q-J-10-9 is the strongest).
Individual combinations can be handled pretty well i think. For a royal flush, you sort your 7 cards by their number descending, and check if the first 5 cards are (A-K-Q-J-10) and if they are of the same suit. A royal flush's strength is indefinite.
For flush you can sort your cards by suit, and check if you can move 4 times in your list of card without witnessing a suit change. A Flush's strength is determined by the highest valued card of it.
A very brief template for the idea:
// main logic of who wins, note it doesn't handle when two players have the same
// combo with same strength
class HandComparator {
public Player compare(Player player1, Player player2) {
HandEvaluator handEvaluator = new HandEvaluator();
Combination player1Combo = handEvaluator.evaluate(player1.hand);
Combination player2Combo = handEvaluator.evaluate(player2.hand);
if (player1Combo.type.equals(player2Combo.type)) {
// note, strength is only taken into account if the two players have
// the same combo (ie both has full house)
if (player1Combo.strength < player2Combo.strength) {
return player2;
} else {
return player1;
}
} else if (player1Combo.type.compareTo(player2Combo.type) < 0) {
return player2;
} else {
return player1;
}
}
}
class Card {
int suit;
int number;
}
class Player {
List<Card> hand;
}
// this is built by CombinationRecognisers. Note, that the member 'strength' is
// related to a specific combination, not all possible hands
class Combination {
enum Type {
ROYAL_FLUSH,
STRAIGHT_FLUSH;
// etc.
}
Type type;
int strength;
}
// implement this for all combinations (ROYAL_FLUSH,STRAIGHT_FLUSH, etc)
interface CombinationRecogniser {
public Combination evaluate(List<Card> hand);
}
/*
* this class holds all CombinationRecognisers and iterates throught them. It
* will stop the moment a combo has been found.
*/
class HandEvaluator {
static List<CombinationRecogniser> recognizers = new ArrayList<CombinationRecogniser>();
static {
recognizers.add(new RoyalFlushRecogniser());
recognizers.add(new StraightFlushRecogniser());
}
public Combination evaluate(List<Card> hand) {
for (CombinationRecogniser recogniser : recognizers) {
Combination combination = recogniser.evaluate(hand);
if (combination != null) {
return combination;
}
}
return null;
}
}
class RoyalFlushRecogniser implements CombinationRecogniser {
#Override
public Combination evaluate(List<Card> hand) {
// code goes here that decides if the given hand is a valid royal flush
return null; // of new Combination() if the given hand is a valid royal flush
}
}
class StraightFlushRecogniser implements CombinationRecogniser {
#Override
public Combination evaluate(List<Card> hand) {
// code goes here that decides if the given hand is a valid straight flush
return null; // of new Combination() if the given hand is a valid royal flush
}
}
This code actually works if you implement the CombinationRecogniser interface for all special combinations. An example:
Related
I have the following objects:
enum Slot
{
HANDS, LEGS, CHEST, HEAD, FEET;
}
class Clothing
{
// The slot this piece of clothing is worn on.
Slot s;
// The color of the clothing, used for `gradeOutfit`
Color c;
}
class Person
{
Map<Slot, Clothing> body;
// look through his outfit and give a score
// for how well he looks
int gradeOutfit()
{
return ...
}
}
I have one Person object and a collection of Clothing. This collection has many Clothing objects of each Slot. For example, it might look like this:
MyCloset = { GREEN_HAT, RED_VEST, BLACK_VEST,
BLUE_JEANS, BROWN_PANTS, RED_SHOES, BLACK_HAT, BLUE_GLOVES, PURPLE_VEST }
In the reality of my program, there are a lot more items than just these but this is just a simplified example.
Problem:
I need to find a combination of these clothes that lead to the highest gradeOutfit score. That means my Person will have to make sure he tries on every Clothing item with every other Clothing item (within limits, ex. it's impossible for two hats to be worn because both are for HEAD Slot). A Person cannot have their gradeOutfit called until they are wearing a Clothing item for every Slot.
I was thinking recursion is the best way to do this but then I think I'd get a stack overflow very fast if I had a decent amount of items. I tried doing it iteratively but I cannot seem to find a good easy way to loop through everything. My program basically looks like
Person p = new Person();
for (Clothing i : MyCloset)
{
for (Clothing h : MyCloset)
{
if (i == h) continue;
if (!p.isWearing(h.slot())
{
p.wear(h);
}
}
int score = p.gradeOutfit();
}
But I know this is just a terrible approach. In order to ensure that every clothing item has been paired up with every other Clothing item, I would need so much more looping logic than just this. No matter what I try, it turns into spaghetti code. I also need to avoid looping over the same outfit twice and make sure that no outfit combination is forgotten about.
What is the best way to approach something like this?
This is an example of a mathematical optimization problem. You seem to already have the objective function (the function that calculates the gradeOutfit score - taking as an input five clothings, one per slot) and you need some constraints (e.g. each clothing in a combination of 5 belongs to a different slot). You need a Java solver library to do this. If your objective function is linear, a linear solver will do. As I have only experience with commercial solvers, I cannot recommend an open-source one, a list of options can be found here.
A simpler (but not extremely elegant) way, without a solver:
Create 5 sets of Clothing objects, one per slot (you can use Java
HashSet for this).
Iterate over all combinations, each time taking one item from each of the 5 sets. You need n1 x n2 x n3 x n4 x n5 combinations, where ni is the number of clothing instances per slot.
It also seems to me that the gradeOutfit function should not be part of the Person class - as it is actually the property of an outfit, not a person (i.e. two persons with the same outfit have exactly the same scores). I 'd prefer to have an Outfit class and put it there.
You have very poorly created the data structure.
enum Slot
{
HANDS, LEGS, CHEST, HEAD, FEET;
numbers = new int[values.length()]
}
enum COLOR
{
RED,BLUE,...;
}
enum Clothing {
GREEN_HAT(HEAD,GREEN), ...;
Slot slot;
Color color;
public static Clothing (Slot slot, Color color){...}
}
class Outfit extends Map <Slot, Clothing> {
countScore(){};
public static Outfit(){
//foreach slot this.put(slot, Clothing.values().get(0));
}
}
...
int n=slot.values.length()-1;
Outfit currentOutfit = new Outfit();
Outfit bestOutfit = new Outfit();
int currentActiveSlot = 0;
// make a cycle for combination of all Outfits
for an enum , you have to use the method "values()" to loop on it:
For (clothe c: clothes.values())
First, I have searched. And all of the answers I have found have been about NOT having the same reference to the same object in two different array lists. so maybe that should tell me I'm doing this wrong in itself? But I'm not sure of how else to manage this.
I am trying to learn Java. And part of that is Swing.
My app I am working on is a simple tournament/bracket app (think march madness. or any simple bracket tree).
Simplified code with just the issue at hand:
class Bracket extends JPanel {
ArrayList<Round> rounds = new ArrayList<Round>();
public void declareWinner(Team team, Game game, Round round) {
// code that gets current round, game, team numbers to calculate the next round, game, team numbers.
int currentRoundNum = rounds.indexOf(round);
int currentGameNum = rounds.get(currentRoundNum).games.indexOf(game);
int currentTeamNum = rounds.get(currentRoundNum).games.get(currentGameNum).teams.indexOf(team);
int nextRoundNum = currentRoundNum + 1;
int nextGameNum = (int) (Math.floor(gameNumber / 2));; // to position the team in the appropriate game slot in the next round
int nextTeamNum = ((gameNumber % 2) == 0) ? 0 : 1; // even game numbers will be the top team in the next round, odd team numbers will be the bottom team in the next round
// here is where things are getting wonky. Trying to set the next round slot to the team that is being declared the winner
rounds.get(nextRoundNum).games.get(nextGameNum).teams.set(nextTeamNum, team);
}
public Bracket(int numRounds) {
// code that creates the bracket structure. # of rounds. the correct # of games depending on the round. etc. Creates empty shell of "placeholder" teams with no name/info.
for(int i = 0; i < numRounds; i++) {
int numGames // set to (number of games of the last round added) * 2
rounds.add(0, new Round(numGames)
}
}
}
class Round extends JPanel {
ArrayList<Game> games = new ArrayList<Game>();
public Round(int numGames) {
for(int i = 0; i < numGames; i++) {
games.add(new Game());
}
}
// more code...
}
class Game extends JPanel {
ArrayList<Team> teams = new ArrayList<Team>();
// more code... creates two teams per each game in constructor
}
class Team extends JPanel {
String teamName;
public Team(String name) {
teamName = name;
add(new JLabel(name));
}
// simple team info, just going for functionality. not much else is here yet.
}
So, lets say in the first round (index 0 of rounds), in the first game (index 0 of rounds.get(0).games), Team 1 (index 0 of rounds.get(0).games.get(0).teams) wins. It's calculating all the stuff correctly. The team is placed in the correct slot. BUT, it completely removes the team from the current position in the round. So now I'm left with only 1 team in the first game of the first round.
It won't let me have the same Team object referenced in both ArrayLists in Rounds[0].Games[0].Teams and Rounds[1].Games[0].Teams. They are nested array lists in each, so 2 different Array Lists. Am I failing because it's bad to extend the JComponents on the classes themselves, and I should completely refactor this?
I can't see exactly what is going on in your example code, as it is not self-contained. However from your description it looks like you are falling foul of the property that Swing components can only be added to one container at a time. If you add the same component to a second container it is automatically removed from the first one.
This doesn't affect the contents of your ArrayLists in the slightest - you can have the same object in as many different ArrayLists as you like.
It also looks like you are muddying the waters by storing this sort of data inside objects which extend Swing components. I suggest you consider separating out a data structure (the Model) from the display components (the View) to make things clearer. Just get the data structure working first, then build the view from it once you have verified it is correct.
On an unrelated note, it looks like you could simplify the start of your code, where before you had:
public void declareWinner(Team team, Game game, Round round) {
// code that gets current round, game, team numbers to calculate the next round, game, team numbers.
int currentRoundNum = rounds.indexOf(round);
int currentGameNum = rounds.get(currentRoundNum).games.indexOf(game);
int currentTeamNum = rounds.get(currentRoundNum).games.get(currentGameNum).teams.indexOf(team);
...
you could replace these lines with
public void declareWinner(Team team, Game game, Round round) {
// code that gets current round, game, team numbers to calculate the next round, game, team numbers.
int currentRoundNum = rounds.indexOf(round);
int currentGameNum = round.games.indexOf(game);
int currentTeamNum = game.teams.indexOf(team);
...
since you already have references to those objects passed in as arguments.
So I'm writing a Rush Hour solver in Java, which is meant to be able to solve the configurations here. However, even the simplest puzzle from that page results in the solver running infinitely and eventually running out of memory. I'm using a breadth first search to work my way through all possible moves arising from each board state (using a HashSet to ensure I'm not repeating myself), and mapping each state to the move that got it there so I can backtrack through them later.
The thing is, I've tried it with more trivial puzzles that I've come up with myself, and it's able to solve them (albeit slowly).
Is there anything blatantly wrong with how I'm approaching this problem? I can put up some code from the relevant classes as well if I need to, but I've tested them pretty thoroughly and I'm pretty sure the problem lies somewhere in the code below. My gut says it's something to do with the HashSet and making sure I'm not repeating myself (since the Queue's size regularly reaches the hundred thousands).
Any suggestions?
// Start at the original configuration
queue.add(originalBoard);
// We add this to our map, but getting here did not require a move, so we use
// a dummy move as a placeholder move
previous.put(originalBoard, new Move(-1, -1, "up"));
// Breadth first search through all possible configurations
while(!queue.isEmpty()) {
// Dequeue next board and make sure it is unique
Board currentBoard = queue.poll();
if (currentBoard == null) continue;
if (seen.contains(currentBoard)) continue;
seen.add(currentBoard);
// Check if we've won
if (currentBoard.hasWon()) {
System.out.println("We won!");
currentBoard.renderBoard();
return solved(currentBoard);
}
// Get a list of all possible moves for the current board state
ArrayList<Move> possibleMoves = currentBoard.allPossibleMoves();
// Check if one of these moves is the winning move
for (Move move : possibleMoves) {
Board newBoard = move.execute(currentBoard);
// We don't need to enqueue boards we've already seen
if (seen.contains(newBoard)) continue;
queue.add(newBoard);
// Map this board to the move that got it there
previous.put(newBoard, move);
}
}
As requested, here are my initialisations of the HashSet (they're class level variables):
private static HashSet<Board> seen = new HashSet<>();
And my Board.equals() method:
#Override
public boolean equals (Object b) {
Board otherBoard = (Board) b;
boolean equal = false;
if (this.M == otherBoard.getM() && this.N == otherBoard.getN()) {
equal = true;
// Each board has an ArrayList of Car objects, and boards are only
// considered equal if they contain the exact same cars
for (Car car : this.cars) {
if (otherBoard.getCar(car.getPosition()) == null) {
equal = false;
}
}
}
System.out.println(equal);
return equal;
}
You must implement Board.hashCode() to override the default Object-based version, in such a way that, per its contract, any two equal Board objects have the same hash code. If you do not, then your seen set does not in fact accomplish anything at all for you.
On another issue, I suspect that the way you're checking the boards' cars is not fully correct. If it works the way I think it does, it would consider these two boards to be equal:
. = empty space
* = part of a car
......
.**.*.
....*.
.*....
.*.**.
......
......
.*..**
.*....
......
.**.*.
....*.
I would like some help coding these methods. Each method should check to see if a group of 5 cards, stored as an array, is certain hand in poker, like one pair, two pair, Full House, etc. This is what I have so far. Also, sort(), sort the cards from smallest to largest and in the order of Clubs, Diamonds, Hearts and then Spades. Lastly I apologize for any formatting issues with the brackets. Thank you.
private boolean isOnePair(){//checks if one pair exists---Done
sort();
for(int i=0;i<cards.length-2;i++){
if(cards[i].compareTo(cards[i+1])==0){
return true;
}
else{
return false;
}
}
}
In theory this one checks to see if there One pair exists in the hand. I believe it is done and makes sense, but if it aint, please tell me why.
private boolean isTwoPair(){//check if two pair exists---
sort();
for(int i=0;i<cards.length-2;i++){
if(cards[i].compareTo(cards[i+1])==0){
return true;
}
}else{
return false;
}
}
This is where I would like help. It needs to check if there are two different pairs. I'm assuming I need something to check like I did in isOnePair. Also, Since Four of a Kind is technically(in real life, not card terms) considered Two pairs, would this be an issue?
private boolean isThreeOfAKind(){//check if three of a kind---Done
sort();
for(int i=0;i<cards.length-3;i++){
if((cards[i].compareTo(cards[i+1])==0)
&&(cards[i+1].compareTo(cards[i+2])==0)){
return true;
}else{
return false;
}
}
}
This checks to see if there are three kinds of one card. This I believe is good
private boolean isStraight(){//check if all in a row---Done
sort();
for(int i=0;i<cards.length-1;i++){
if(cards[i]<cards[i+1]&&()cards[i+1]-cards[i])==1)){
return true;
}else{
return false;
}
}
}
This checks to see if the cards are a Straight. So they are in numerical order since the difference between each card will have to be 1.
private boolean isFlush(){//check if all have same suit---
sort();
for(int i=0;i<cards.length-1;i++){
}
}
This is also where I would like to most help. My trouble is just the thought behind how to check the suits. I know you guys dont have the actual code that tells you the suit value, but if someone could help me with the thought process of it.
private boolean isFourKind(){//check if four of a kind---Done
sort();
for(int i=0;i<cards.length-4;i++){
if((cards[i].compareTo(cards[i+1])==0)
&&(cards[i+1].compareTo(cards[i+2])==0)
&&(cards[i+2].compareTo(cards[i+3])==0)){
return true;
}else{
return false;
}
}
}
Check Four of a Kind. Should be all good.
private boolean isRoyalFlush(){//check if from 10-Ace and All of same suit---
sort();
for(int i=0;i<cards.length-1;i++){
}
}
This should be a combo of Straight and Flush. But the last condition is that the card in slot card[0]==10.
To check whether you have two pairs, simply create a counter that increments every time you find a pair - instead of instantly returning true. If your counter ever reaches two, you return true.
Also, your worries about two pairs and four of a kind being similar should all be handled outside these methods. As in, check to see if you have the most restrictive (or highest point) hand first, and only if you don't have it do you check the next restrictive hands.
Finally, you cannot program this without your Card class having a visible suit variable (or a getter function that returns the suit). Once you have that, then you can very easily check for flushes, flushes+straights, etc. After you implement this, it should look something like the following
int suit = cards[0].getSuit();
for (int i = 1; i < cards.length; ++i) {
if (suit != cards[i].getSuit()) // checks to see if you have a card of a different suit
return false;
}
return true; // suits of all cards are the same
PS: Don't really know the rules for Poker. Can a straight be composed of cards of different suits?
I recently gave an interview and was asked the following question.
A maze is a group of linked Places. Each Place has a North, South, East, and West Place adjacent to it. There are two special pre-defined Place's: Place Wall represents a wall - the mouse can't go there. Place Cheese is ... cheese! The connections between Places are symmetrical - if you start from any Place and go North and then South, you return to where you were.
To simplify things, the maze has no closed loops - that is, if you start in any Place and follow any path, you eventually either hit a wall or find cheese - you never come back to the Place you started unless you actually retrace your steps.
A mouse starts off in some Place and searches around for Cheese. When it finds Cheese, it returns a set of directions - a string of the letters NSEW that lead from where it started to the Cheese.
The following framework defines the classes and functions. Some other code not included here generates a maze by creating a bunch of Place's and linking them. It then calls mouse(), passing some starting Place from the maze:
interface Place {
// Return the adjacent Place in the given direction
public Place goNorth();
public Place goSouth();
public Place goEast();
public Place goWest();
// Returns true only for the special "Wall" place
public bool isWall();
// Returns true only for the special "Cheese" place
public bool isCheese();
};
class Mouse {
public Mouse() {}
// Return a string of the letters NSEW which, if used to traverse the
// the maze from startingPoint, will reach a Place where isCheese() is
// true. Return null if you can't find such a path.
public String findCheese(Place startingPoint) {
... fill this in ...
}
}
Implement findCheese(). You can add any fields or helper methods you need to Mouse.
Extra credit: Eliminate the "no closed loops" restriction. That is, change your code so that it works correctly even if there might be a path like SSNEEW that leads the mouse back to the Place it started from.
This is what I tried. I understand this won't be the best or optimized solution, and wanted feedback as to what I else I could try. I have not considered the extra credit part
public String findCheese(place startingPoint)
{
//Call helper function in all 4 directions;
return findCheeseHelper(startingPoint,new StringBuilder("N")).append(
findCheeseHelper(startingPoint,new StringBuilder("S"))).append(
findCheeseHelper(startingPoint,new StringBuilder("E"))).append(
findCheeseHelper(startingPoint,new StringBuilder("W"))).toString();
}
public StringBuilder findCheeseHelper(place startingPoint, StringBuilder direction)
{
StringBuilder nDir=new StringBuilder("");
StringBuilder sDir=new StringBuilder("");
StringBuilder eDir=new StringBuilder("");
StringBuilder wDir=new StringBuilder("");
//Rerturn which direction this step came from if cheese found
if(startingPoint.isCheese())
{
return direction;
}
//Specify this is not a correct direction by returning an empty String
else if(startingPoint.isWall())
{
return "";
}
//Explore all other 3 directions (except the one this step came from)
if(direction=="N")
{
sDir=findCheeseHelper(startPoint.goSouth(), new StringBuilder("N"));
eDir=findCheeseHelper(startPoint.goEast(), new StringBuilder("E"));
wDir=findCheeseHelper(startPoint.goWest(), new StringBuilder("W"));
}
else if(direction=="E")
{
nDir=findCheeseHelper(startPoint.goNorth(), new StringBuilder("N"));
sDir=findCheeseHelper(startPoint.goSouth(), new StringBuilder("S"));
wDir=findCheeseHelper(startPoint.goWest(), new StringBuilder("E"));
}
else if(direction=="W")
{
nDir=findCheeseHelper(startPoint.goNorth(), new StringBuilder("N"));
sDir=findCheeseHelper(startPoint.goSouth(), new StringBuilder("S"));
eDir=findCheeseHelper(startPoint.goEast(), new StringBuilder("W"));
}
else if(direction=="S")
{
nDir=findCheeseHelper(startPoint.goNorth(), new StringBuilder("S"));
eDir=findCheeseHelper(startPoint.goEast(), new StringBuilder("E"));
wDir=findCheeseHelper(startPoint.goWest(), new StringBuilder("W"));
}
//If I hit wall in every direction, I will get empty string and so specify to calling
//function that this is not a correct direction
if(nDir.equals("") && sDir.equals("") && eDir.equals("") && wDir.equals(""))
return new StringBuilder("");
//If Cheese was found in even 1 direction, return direction to come to this step, appended with the path
// forward to the calling function
return direction.append(nDir).append(sDir).append(eDir).append(wDir);
}