Collections.sort() is not working across all members - java

I am trying to sort a list using Collections.sort() and noticing notice all the members are being sorted:
Here is my input, a print out of the .compareTo() insides, and the output:
5 4 3 2 1 // Original
me = 4: o = 5 // A printout at each entry into .compareTo()
me = 3: o = 4
me = 3: o = 5
me = 2: o = 5
me = 2: o = 3
me = 1: o = 3
me = 1: o = 2
4 5 3 2 1 // Final output (1 should be at the beginning though)
My rules for sorting are:
1<4
3<2
4<5
My implementation is:
List<Task> tasks = new TaskList();
Task.create(tasks); // creates a list 5 4 3 2 1
while (scan.hasNext()) {
String line = scan.next();
Task.rules.add(line); // address the rules such as "1<4"
}
System.out.println(tasks);
Collections.sort(tasks);
And the compareTo() implementation:
#Override
public int compareTo(Object arg0) {
int me = id;
int o = ((Task) arg0).id;
System.out.println("me = " + me + ": o = " + o);
for (String s : rules) { // rules is an array of strings "1<4" etc
int left = Integer.valueOf(s.substring(0, 1));
int right = Integer.valueOf(s.substring(2));
char op = s.charAt(1);
boolean meLeft = left == me;
boolean oLeft = left == o;
boolean meRight = right == me;
boolean oRight = right == o;
if (meLeft && oRight) {
if (op == '<') { // me < other
return -1;
} else
return 1;
} else if (oLeft && meRight) {
if (op == '<') {// other < me
return 1;
} else {
return -1;
}
}
}
return 0;
}
As you can see from the "me = M, o = O" at the top, the Collections.sort() is not iterating through all the members of the list!
I would expect the following to show for each member "me" all the other members "o" to be compared, so I'd expected that list at the top of this question to be much longer! I believe its size should be N^2...

Your compareTo method breaks the contract for that method in two ways.
1) Transitivity says that if x.compareTo(y) > 0 and y.compareTo(z) > 0 then x.compareTo(z) > 0. Your method breaks this because 5 > 4 and 4 > 1, but 5>1 is not one of your rules.
2) compareTo must also meet the condition that if x.compareTo(y) == 0 then sgn(x.compareTo(z)) == sgn(y.compareTo(z)) for all z. Your method breaks this because 5.compareTo(1) == 0, whereas 5.compareTo(4) and 1.compareTo(4) have opposite signs.
If you don't meet the contract for compareTo, the results of sort are unpredictable. However in your case, we can see what's going on. 4, 5, 3, 2, 1 is in order because 4 < 5 = 3 < 2 = 1. (I am using = to mean the compareTo method returns 0). There are no > signs in that chain, so there is no reason to continue sorting.
If you want 1 to come to the front, in addition to making your compareTo method meet the two conditions above, you will have to add at least one rule involving something from [1, 4, 5] and something from [2, 3]. As long as there is no such rule, there is no reason for the 1 at the end to move past the 2 and the 3.

Related

Any comparasion condition returns bad value

I struggle with very strange behaviour while trying to compare two ints but first things first. Here is my method inside the class:
public class CollectionsTutorial {
private Collection<String> collection = null;
public CollectionsTutorial() {
this.collection = new ArrayList<String>();
for(int i=0;i<100000;i++) {
collection.add("item_"+((i+1)%10000));
}
}
public Set<String> getSet(){
HashSet<String> set = new HashSet<String>(10000);
for(String item: this.collection) {
if (!set.contains(item)) {
set.add(item);
}
}
return set;
}
public TreeSet<String> getEvery3ElementAsSortedSet(){
TreeSet<String> tree = new TreeSet<String>();
int counter = 0;
for(String item : this.collection) {
if (counter%2==0) {
tree.add(item);
counter = -1;
}
counter++;
}
return tree;
}
}
The whole class doesn't really matter here - it only holds ArrayList<String>. I need to return every 3rd element in a tree and everything goes well until it's time to compare current counter value. It returns true everytime. I'm sure of it becouse while testing it's adding to the Tree every single element of collection. I've tried using compareTo(), equalsTo(), valueOf() and intValue() but nothing helps.
EDIT.
I've change code to the class view - maybe something else is cousing the error?
Here is test i'm trying to pass
public class CollectionsTutorialTest {
#Test
public void GetEvery3ElementTest() {
CollectionsTutorial testObj = new CollectionsTutorial();
TreeSet<String> tree = new TreeSet<String>();
tree.addAll(testObj.getSet() );
assertEquals(false, tree.contains("item_2"));
}
}
"I need to return every 3rd element in a tree..." this description screams for the modulo % operator.
If you want to enter an if-condition on every 3rd iteration then you can check this with the following condition: counter % 3 == 0. You don't need to subtract anything at all.
How does % work?
Put simply: The modulo operator returns the result of a division.
Example:
5 / 3 = 1 with remain 2
5 % 3 = 2
9 / 3 = 3 with remain 0
9 % 3 = 0
Note:
if (counter % 2 == 0) {
tree.add(item);
counter = -1;
}
counter++;
You use counter % 2 == 0. This will return true for the second element. Afterwards you set counter = -1 because you intend to get every 3rd element. However, this does not work.
Here's the reason why:
System.out.println(0 % 1); // 0 % 1 = 0
System.out.println(0 % 2); // 0 % 2 = 0
System.out.println(0 % 3); // 0 % 3 = 0
System.out.println(0 % 4); // 0 % 4 = 0
As you can see, every time your counter reaches the value 0 the if-condition will result in true regardless of the divisor. That's why you use % 3.
the list is created by:
for(int i=0;i<100_000;i++) {
collection.add("item_"+((i+1)%10_000));
}
resulting in:
collection[0] = item_1
collection[1] = item_2
collection[2] = item_3
collection[3] = item_4
...
collection[9_998] = item_9999
collection[9_999] = item_0 // (9_999+1) % 10_000 is 0
collection[10_000] = item_1 // (10_000+1) % 10_000 is 1
collection[10_001] = item_2
collection[10_002] = item_3
collection[10_003] = item_4
...
collection[19_998] = item_9999 // (19_998+1) % 10_000 is 9_999
collection[19_999] = item_0 // (19_999+1) % 10_000 is 0
collection[20_000] = item_1
collection[20_001] = item_2
collection[20_002] = item_3
collection[20_003] = item_4
...
above is NOT code
now note that 20_001 % 3 is 0 - so the third item_2 will be picked; same true for 50_001 % 3 and 80_001 % 3. So, actually that item is added 3 times to the tree (since it is a Set, only one instance is kept). At the end, one version of each item will be present in the result. Similar to counter%3 == 1 or counter%3 == 2 (basically the first code version posted in question.)
Lesson: checking that item_2 is present or not, does NOT check if the condition "returns true everytime".
Better test:
...
int index = 0; // DEBUG
for(String item : this.collection) {
if (counter%2==0) {
System.out.println(index); // DEBUG
tree.add(item);
counter = -1;
}
index += 1; // DEBUG
...
above is not the full code, just showing idea for testing
Bonus:
a Set does not save duplicates ("A collection that contains no duplicate elements"), in below snippet:
if (!set.contains(item)) {
set.add(item);
}
the if is not necessary - this is already checked by add()

Down to Zero II

This is the question:
You are given Q queries. Each query consists of a single number N . You can perform any of the operations on in each move:
If we take 2 integers a and b where N=a*b (a ,b cannot be equal to 1), then we can change N=max(a,b)
Decrease the value of N by 1 .
Determine the minimum number of moves required to reduce the value of to .
Input Format
The first line contains the integer Q.
The next Q lines each contain an integer,N .
Output Format
Output Q lines. Each line containing the minimum number of moves required > to reduce the value of N to 0.
I have written the following code. This code is giving some wrong answers and also giving time limit exceed error . Can you tell what are the the mistakes present in my code ? where or what I am doing wrong here?
My code:
public static int downToZero(int n) {
// Write your code here
int count1=0;
int prev_i=0;
int prev_j=0;
int next1=0;
int next2=Integer.MAX_VALUE;
if (n==0){
return 0;
}
while(n!=0){
if(n==1){
count1++;
break;
}
next1=n-1;
outerloop:
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if (i*j==n){
if (prev_i ==j && prev_j==i){
break outerloop;
}
if (i !=j){
prev_i=i;
prev_j=j;
}
int max=Math.max(i,j);
if (max<next2){
next2=max;
}
}
}
}
n=Math.min(next1,next2);
count1++;
}
return count1;
}
This is part is coded for us:
public class Solution {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));
int q = Integer.parseInt(bufferedReader.readLine().trim());
for (int qItr = 0; qItr < q; qItr++) {
int n = Integer.parseInt(bufferedReader.readLine().trim());
int result = Result.downToZero(n);
bufferedWriter.write(String.valueOf(result));
bufferedWriter.newLine();
}
bufferedReader.close();
bufferedWriter.close();
}
}
Ex: it is not working for number 7176 ....
To explore all solution tree and find globally optimal solution, we must choose the best result both from all possible divisor pairs and from solution(n-1)
My weird translation to Java (ideone) uses bottom-up dynamic programming to make execution faster.
We calculate solutions for values i from 1 to n, they are written into table[i].
At first we set result into 1 + best result for previous value (table[i-1]).
Then we factor N into all pairs of divisors and check whether using already calculated result for larger divisor table[d] gives better result.
Finally we write result into the table.
Note that we can calculate table once and use it for all Q queries.
class Ideone
{
public static int makezeroDP(int n){
int[] table = new int[n+1];
table[1] = 1; table[2] = 2; table[3] = 3;
int res;
for (int i = 4; i <= n; i++) {
res = 1 + table[i-1];
int a = 2;
while (a * a <= i) {
if (i % a == 0)
res = Math.min(res, 1 + table[i / a]);
a += 1;
}
table[i] = res;
}
return table[n];
}
public static void main (String[] args) throws java.lang.Exception
{
int n = 145;//999999;
System.out.println(makezeroDP(n));
}
}
Old part
Simple implementation (sorry, in Python) gives answer 7 for 7176
def makezero(n):
if n <= 3:
return n
result = 1 + makezero(n - 1)
t = 2
while t * t <= n:
if n % t == 0:
result = min(result, 1 + makezero(n // t))
t += 1
return result
In Python it's needed to set recursion limit or change algorithm. Now use memoization, as I wrote in comments).
t = [-i for i in range(1000001)]
def makezeroMemo(n):
if t[n] > 0:
return t[n]
if t[n-1] < 0:
res = 1 + makezeroMemo(n-1)
else:
res = 1 + t[n-1]
a = 2
while a * a <= n:
if n % a == 0:
res = min(res, 1 + makezeroMemo(n // a))
a += 1
t[n] = res
return res
Bottom-up table dynamic programming. No recursion.
def makezeroDP(n):
table = [0,1,2,3] + [0]*(n-3)
for i in range(4, n+1):
res = 1 + table[i-1]
a = 2
while a * a <= i:
if i % a == 0:
res = min(res, 1 + table[i // a])
a += 1
table[i] = res
return table[n]
We can construct the directed acyclic graph quickly with a sieve and
then compute shortest paths. No trial division needed.
Time and space usage is Θ(N log N).
n_max = 1000000
successors = [[n - 1] for n in range(n_max + 1)]
for a in range(2, n_max + 1):
for b in range(a, n_max // a + 1):
successors[a * b].append(b)
table = [0]
for n in range(1, n_max + 1):
table.append(min(table[s] for s in successors[n]) + 1)
print(table[7176])
Results:
7
EDIT:
The algorithm uses Greedy approach and doesn't return optimal results, it just simplifies OP's approach. For 7176 given as example, below algorithm returns 10, I can see a shorter chain of 7176 -> 104 -> 52 -> 13 -> 12 -> 4 -> 2 -> 1 -> 0 with 8 steps, and expected answer is 7.
Let's review your problem in simple terms.
If we take 2 integers a and b where N=a*b (a ,b cannot be equal to 1), then we can change N=max(a,b)
and
Determine the minimum number of moves required to reduce the value of to .
You're looking for 2 factors of N, a and b and, if you want the minimum number of moves, this means that your maximum at each step should be minimum. We know for a fact that this minimum is reached when factors are closest to N. Let me give you an example:
36 = 1 * 36 = 2 * 18 = 3 * 12 = 4 * 9 = 6 * 6
We know that sqrt(36) = 6 and you can see that the minimum of 2 factors you can get at this step is max(6, 6) = 6. Sure, 36 is 6 squared, let me take a number without special properties, 96, with its square root rounded down to nearest integer 9.
96 = 2 * 48 = 3 * 32 = 4 * 24 = 6 * 16 = 8 * 12
You can see that your minimum value for max(a, b) is max(8, 12) = 12, which is, again, attained when factors are closest to square root.
Now let's look at the code:
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++){
if (i*j==n){
You can do this in one loop, knowing that n / i returns an integer, therefore you need to check if i * (n / i) == n. With the previous observation, we need to start at the square root, and go down, until we get to 1. If we got i and n / i as factors, we know that this pair is also the minimum you can get at this step. If no factors are found and you reach 1, which obviously is a factor of n, you have a prime number and you need to use the second instruction:
Decrease the value of N by 1 .
Note that if you go from sqrt(n) down to 1, looking for factors, if you find one, max(i, n / i) will be n / i.
Additionally, if n = 1, you take 1 step. If n = 2, you take 2 steps (2 -> 1). If n = 3, you take 3 steps (3 -> 2 -> 1). Therefore if n is 1, 2 or 3, you take n steps to go to 0. OK, less talking, more coding:
static int downToZero(int n) {
if (n == 1 || n == 2 || n == 3) return n;
int sqrt = (int) Math.sqrt(n);
for (int i = sqrt; i > 1; i--) {
if (n / i * i == n) {
return 1 + downToZero(n / i);
}
}
return 1 + downToZero(n - 1);
}
Notice that I'm stopping when i equals 2, I know that if I reach 1, it's a prime number and I need to go a step forward and look at n - 1.
However, I have tried to see the steps your algorithm and mine takes, so I've added a print statement each time n changes, and we both have the same succession: 7176, 92, 23, 22, 11, 10, 5, 4, 2, 1, which returns 10. Isn't that correct?
So, I found a solution which is working for all the test cases -
static final int LIMIT = 1_000_000;
static int[] solutions = buildSolutions();
public static int downToZero(int n) {
// Write your code here
return solutions[n];
}
static int[] buildSolutions() {
int[] solutions = new int[LIMIT + 1];
for (int i = 1; i < solutions.length; i++) {
solutions[i] = solutions[i - 1] + 1;
for (int j = 2; j * j <= i; j++) {
if (i % j == 0) {
solutions[i] = Math.min(solutions[i], solutions[i / j] + 1);
}
}
}
return solutions;
}
}

Problem in my solution "Repeated string match"

I have to tell the minimum number of times string A needs to be repeated so that string B becomes a substring of A.
My answer is wrong for some test cases like
A = "abc"
B = "cabcabca"
My output is coming 3..it should be 4.
My code is-
class Solution {
public int repeatedStringMatch(String A, String B) {
int count = 0;
while (A.length() <= 1000) {
if (A.indexOf(B) != -1)
return (count + 1);
else
A = A + A;
count++;
}
return -1;
}
}
The problem is because of A=A+A; as it makes A as abcabc after the first iteration, abcabcabcabc after the second iteration, abcabcabcabcabcabcabcabc after the third iteration and so on i.e. instead of getting appended, the string is getting doubled in each iteration.
It is like you have been given a task to add 2 to itself in each iteration i.e. after the first iteration, it should become 2 + 2 = 4, after the second iteration, it should become 4 + 2 = 6, after the third iteration it should become 6 + 2 = 8 and so on.
Whereas the way you have done, it will become 2 + 2 = 4 after the first iteration, 4 + 4 = 8 after the second iteration, 8 + 8 = 16 after the third iteration and so on.
As a side note, you should avoid using string concatenation in a loop. You should also follow Java naming convention e.g. the variable name A should be a.
Do it as follows:
public class Main {
public static void main(String[] args) {
// Test
System.out.println(repeatedStringMatch("abc", "cabcabca"));
}
static int repeatedStringMatch(String a, String b) {
int count = 1;
StringBuilder sb = new StringBuilder(a);
while (sb.length() <= 1000) {
if (sb.indexOf(b) != -1) {
return count;
} else {
sb.append(a);
count++;
}
}
return -1;
}
}
Output:
4

Minimum steps to one logic fails for some conditions

The puzzle is to obtain the minimum number of steps it takes to make a number 1. Allowed operations are
1. You can subtract 1 from the number
2. You can divide the number by 2 if it is divisible by 2.
3. You can divide the number by 3 if it is divisible by 3.
At the end, you need to make the number 1 by performing the above operations. I am trying to obtain a solution that gives me the minimum number of the above operations required to make the number 1.
My code (in Java) is as follows.
public int minStepsBottomUp(int n) {
int[] memoArray = new int[n+1];
memoArray[0] = 0;
memoArray[1] = 0;
for(int i=2;i<=n;++i){
int r = 1 + memoArray[i-1];
if(n % 2 == 0) {
r = Math.min(r, 1+memoArray[n/2]);
}
if(n % 3 == 0) {
r = Math.min(r, 1+memoArray[n/3]);
}
memoArray[i] = r;
}
return memoArray[n];
}
But I get some ambiguous results.Example - if the number is 5, I get the minimun number of steps required as 4. Actually it should be 3. Can someone please explain where I have gone wrong?
I suggest reversing the problem: starting from 1 we should reach n by using three kinds of operations:
add 1
multiply by 2
multiply by 3
For instance for 5 we'll have 3 operations (multiply by 3, add 1, add 1):
1 -> 3 -> 4 -> 5
So far so good, now we have standard dynamic programming problem; C# implementation:
private static int Best(int value) {
if (value <= 0)
return -1; // or throw ArgumentOutOfRangeException
else if (value == 1)
return 0;
Dictionary<int, int> best = new Dictionary<int, int>() { {1, 0} };
List<int> agenda = new List<int>() { 1 };
for (int step = 1; ; ++step)
for (int i = agenda.Count - 1; i >= 0; --i) {
int item = agenda[i];
agenda.RemoveAt(i);
int[] next = new int[] { item + 1, item * 2, item * 3 };
foreach (int v in next) {
if (v == value)
return step;
if (!best.ContainsKey(v)) {
best.Add(v, step);
agenda.Add(v);
}
}
}
}
Tests:
// 3
Console.WriteLine(Best(5));
// 3
Console.WriteLine(Best(10));
// 7
Console.WriteLine(Best(100));
// 19
Console.WriteLine(Best(1000000));
Inside your loop, you are using n instead of i.
For instance, n % 2 == 0 should be i % 2 == 0
If the number is 5 you can get 1 by doing:
int x = 5 - 1;
x = x - 1;
x= x / 3;

The simplest algorithm for poker hand evaluation

I am thinking about poker hand (5 cards) evaluation in Java. Now I am looking for simplicity and clarity rather than performance and efficiency. I probably can write a "naive" algorithm but it requires a lot of code.
I saw also a few poker evaluation libraries, which use hashing and bitwise operations, but they look rather complex.
What is the "cleanest and simplest" algorithm for poker hand evaluation ?
Here is a very short but complete histogram based 5 card poker scoring function in Python (2.x). It will get considerably longer if converted to Java.
def poker(hands):
scores = [(i, score(hand.split())) for i, hand in enumerate(hands)]
winner = sorted(scores , key=lambda x:x[1])[-1][0]
return hands[winner]
def score(hand):
ranks = '23456789TJQKA'
rcounts = {ranks.find(r): ''.join(hand).count(r) for r, _ in hand}.items()
score, ranks = zip(*sorted((cnt, rank) for rank, cnt in rcounts)[::-1])
if len(score) == 5:
if ranks[0:2] == (12, 3): #adjust if 5 high straight
ranks = (3, 2, 1, 0, -1)
straight = ranks[0] - ranks[4] == 4
flush = len({suit for _, suit in hand}) == 1
'''no pair, straight, flush, or straight flush'''
score = ([1, (3,1,1,1)], [(3,1,1,2), (5,)])[flush][straight]
return score, ranks
>>> poker(['8C TS KC 9H 4S', '7D 2S 5D 3S AC', '8C AD 8D AC 9C', '7C 5H 8D TD KS'])
'8C AD 8D AC 9C'
Lookup tables are the most straightforward and simplest solution to the problem, and also the fastest. The trick is managing the size of the table and keeping the mode of use simple enough to process very quickly (space–time tradeoff). Obviously, in theory you could just encode each hand that could be held and have an array of evaluations, then --poof-- one table lookup and you are done. Unfortunately, such a table would be huge and unmanageable for most machines, and would invariably have you thrashing disks anyway as memory gets swapped out lots.
The so-called two-plus-two solution sports a big 10M table, but literally involves one table lookup for each card in the hand. You are not likely to find a faster and simpler to understand algorithm.
Other solutions involve more compressed tables with more complex indexing, but they are readily comprehensible and pretty fast (although much slower than 2+2). This is where you see language concerning hashing and so forth -- tricks to reduce a table size to more manageable sizes.
In any case, lookup solutions are orders of magnitude faster than the histogram-sort-dance-on-your-head-compare-special-case-and-by-the-way-was-it-a-flush solutions, almost none of which are worthy of a second glance.
You actually don't need any advanced functions, it can be all done bitwise: (source: http://www.codeproject.com/Articles/569271/A-Poker-hand-analyzer-in-JavaScript-using-bit-math)
(This one is actually written in JavaScript, but you can evaluate JavaScript from Java if needed, so it shouldn't be a problem. Also, this is as short as it gets, so if even for illustration of the approach...):
First you split your cards into two arrays: ranks (cs) and suits (ss) and to represent suits, you will use either 1,2,4 or 8 (that is 0b0001, 0b0010,...):
var J=11, Q=12, K=13, A=14, C=1, D=2, H=4, S=8;
Now here's the magic:
function evaluateHand(cs, ss) {
var pokerHands = ["4 of a Kind", "Straight Flush","Straight","Flush","High Card","1 Pair","2 Pair","Royal Flush", "3 of a Kind","Full House"];
var v,i,o,s = 1 << cs[0] | 1 << cs[1] | 1 << cs[2] | 1 << cs[3] | 1 << cs[4];
for (i = -1, v = o = 0; i < 5; i++, o = Math.pow(2, cs[i] * 4)) {v += o * ((v / o & 15) + 1);}
v = v % 15 - ((s / (s & -s) == 31) || (s == 0x403c) ? 3 : 1);
v -= (ss[0] == (ss[1] | ss[2] | ss[3] | ss[4])) * ((s == 0x7c00) ? -5 : 1);
return pokerHands[v];
}
Usage:
evaluateHand([A,10,J,K,Q],[C,C,C,C,C]); // Royal Flush
Now what it does (very briefly) is that it puts 1 into 3rd bit of s when there's a 2, into 4th when there's 3, etc., so for the above example s looks like this:
0b111110000000000
for [A,2,3,4,5] it would look like this
0b100 0000 0011 1100
etc.
v uses four bits to record multiple occurencies of same card, so it's 52bits long and if you have three Aces and two kings, its 8 MSB bits look like:
0111 0011 ...
The last line then checks for a flush or straight flush or royal flush (0x7c00).
import java.util.*; // Arrays, Set
import java.util.Map.Entry;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.*; // counting, groupingBy
public record Hand(Category category, Rank... ranks) implements Comparable<Hand> {
public static Hand evaluate(Set<Card> cards) {
if (cards.size() != 5) { throw new IllegalArgumentException(); }
var flush = cards.stream().map(Card::suit).distinct().count() == 1;
var counts = cards.stream().collect(groupingBy(Card::rank, counting()));
var ranks = counts.entrySet().stream().sorted(
comparing(Entry<Rank, Long>::getValue).thenComparing(Entry::getKey).reversed()
).map(Entry::getKey).toArray(Rank[]::new);
if (ranks.length == 4) {
return new Hand(ONE_PAIR, ranks);
} else if (ranks.length == 3) {
return new Hand(counts.get(ranks[0]) == 2 ? TWO_PAIR : THREE_OF_A_KIND, ranks);
} else if (ranks.length == 2) {
return new Hand(counts.get(ranks[0]) == 3 ? FULL_HOUSE : FOUR_OF_A_KIND, ranks);
} else if (ranks[0].ordinal() - ranks[4].ordinal() == 4) {
return new Hand(flush ? STRAIGHT_FLUSH : STRAIGHT, ranks[0]);
} else if (ranks[0].equals(ACE) && ranks[1].equals(FIVE)) { // A-2-3-4-5
return new Hand(flush ? STRAIGHT_FLUSH : STRAIGHT, FIVE);
} else {
return new Hand(flush ? FLUSH : HIGH_CARD, ranks);
}
}
#Override
public int compareTo(Hand that) { // first compare by category, then compare ranks lexicographically
return comparing(Hand::category).thenComparing(Hand::ranks, Arrays::compare).compare(this, that);
}
}
enum Category {HIGH_CARD, ONE_PAIR, TWO_PAIR, THREE_OF_A_KIND, STRAIGHT, FLUSH, FULL_HOUSE, FOUR_OF_A_KIND, STRAIGHT_FLUSH}
enum Rank {TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE}
enum Suit {DIAMONDS, CLUBS, HEARTS, SPADES}
record Card(Rank rank, Suit suit) {}
Here's a modified version of dansalmo's program which works for holdem hands:
def holdem(board, hands):
scores = [(evaluate((board + ' ' + hand).split()), i) for i, hand in enumerate(hands)]
best = max(scores)[0]
return [x[1] for x in filter(lambda(x): x[0] == best, scores)]
def evaluate(hand):
ranks = '23456789TJQKA'
if len(hand) > 5: return max([evaluate(hand[:i] + hand[i+1:]) for i in range(len(hand))])
score, ranks = zip(*sorted((cnt, rank) for rank, cnt in {ranks.find(r): ''.join(hand).count(r) for r, _ in hand}.items())[::-1])
if len(score) == 5: # if there are 5 different ranks it could be a straight or a flush (or both)
if ranks[0:2] == (12, 3): ranks = (3, 2, 1, 0, -1) # adjust if 5 high straight
score = ([1,(3,1,2)],[(3,1,3),(5,)])[len({suit for _, suit in hand}) == 1][ranks[0] - ranks[4] == 4] # high card, straight, flush, straight flush
return score, ranks
def test():
print holdem('9H TC JC QS KC', [
'JS JD', # 0
'AD 9C', # 1 A-straight
'JD 2C', # 2
'AC 8D', # 3 A-straight
'QH KH', # 4
'TS 9C', # 5
'AH 3H', # 6 A-straight
'3D 2C', # 7
# '8C 2C', # 8 flush
])
test()
holdem() returns a list of indices of the winning hand(s). In the test() example that's [1, 3, 6], since the three hands with aces split the pot, or [8] if the flush hand is uncommented.
Python 3 version
def poker(hands):
scores = [(i, score(hand.split())) for i, hand in enumerate(hands)]
winner = sorted(scores , key=lambda x:x[1])[-1][0]
return hands[winner]
def score(hand):
ranks = '23456789TJQKA'
rcounts = {ranks.find(r): ''.join(hand).count(r) for r, _ in hand}.items()
score, ranks = zip(*sorted((cnt, rank) for rank, cnt in rcounts)[::-1])
if len(score) == 5:
if ranks[0:2] == (12, 3): #adjust if 5 high straight
ranks = (3, 2, 1, 0, -1)
straight = ranks[0] - ranks[4] == 4
flush = len({suit for _, suit in hand}) == 1
'''no pair, straight, flush, or straight flush'''
score = ([(1,), (3,1,1,1)], [(3,1,1,2), (5,)])[flush][straight]
return score, ranks
>>> poker(['8C TS KC 9H 4S', '7D 2S 5D 3S AC', '8C AD 8D AC 9C', '7C 5H 8D TD KS'])
'8C AD 8D AC 9C'
Basically have to replace 1 by (1,) to avoid the int to tuple comparison error.
I have written a poker hand evaluator in both C++ and Javascript. Basically the program would convert a randomly picked set of cards to a 3d array of 1s and 0s. By converting the cards into this format I was then able to write functions that would test for each type of hand starting from the highest.
So in recap, my program would generate random cards, convert them into a 3D array of hearts, diamonds, spades and clubs, where 1 represented one of the cards I had. I would then test the 3D array to see if I had a Royal Flush, Then Straight Flush, Then 4 of a Kind until a match was detected. Once a match was detected say after testing for a flush, then my program wouldn't have to test for straight, 3 of a kind, etc as a flush beats a straight.
Below is outputted data from my program:
My random cards:
Table Cards
{ Value: '9', Suit: 'H' }
{ Value: 'A', Suit: 'H' }
{ Value: '9', Suit: 'D' }
{ Value: '7', Suit: 'S' }
{ Value: '6', Suit: 'S' }
3D array representing my cards:
A 2 3 4 5 6 7 8 9 10 J Q K A
Spades
[ 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0 ]
Diamonds
[ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 ]
Clubs
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
Hearts
[ 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]
Using the values above I can tell that I have a pair 9s with an A, 7, 6 kicker.
You can see the array includes Aces twice. This is because you want to test for a straight flush starting from A. So (A,2,3,4,5).
If you wanted to test for 7 cards instead of 5 you could also use this system. You can include the users 2 cards with the 5 on the table and run it through my system. You can also do the same for other players at the table and compare the results.
I hope this helps a little.
If you are representing a hand as an array of, for example, Card objects, then I would have methods for looping through this array and determining if it has a 2-of-a-kind, flush etc - and if it does, what type it is; so you could have the 3ofaKind() method return 5 if a hand had three 5s. Then I would establish a hierarchy of possibilities (e.g. 3 of a kind is higher than 2 of a kind) and work from there. The methods themselves should be pretty straightforward to write.
If you just want to understand how it works here is simple algorithm:
HandStrength(ourcards,boardcards)
{
ahead = tied = behind = 0
ourrank = Rank(ourcards,boardcards)
/* Consider all two-card combinations
of the remaining cards. */
for each case(oppcards)
{
opprank = Rank(oppcards,boardcards)
if(ourrank>opprank)
ahead += 1
else if(ourrank==opprank)
tied += 1
else /* < */
behind += 1
}
handstrength = (ahead+tied/2) / (ahead+tied+behind)
return(handstrength)
}
It is from "ALGORITHMS AND ASSESSMENT IN COMPUTER POKER" by Darse Billings.
Here's a simple rule-based implementation in Kotlin:
class PokerHand constructor(hand: String) : Comparable<PokerHand> {
companion object {
const val WIN = 1
const val TIE = 0
const val LOSS = -1
}
val cards: List<Card>
val isStraightFlush: Boolean
get() = isStraight && isFlush
val isFourOfAKind: Boolean
get() = cards.groupBy { it.weight }.map { it.value }.any { it.size == 4 }
val isFullHouse: Boolean
get() = cards.groupBy { it.weight }.map { it.value }.size == 2
val isFlush: Boolean
get() = cards.groupBy { it.suit }.map { it.value }.size == 1
val isStraight: Boolean
get() = cards.map { it.weight.ordinal } == (cards[0].weight.ordinal..cards[0].weight.ordinal + 4).toList()
val isThreeOfAKind: Boolean
get() = cards.groupBy { it.weight }.map { it.value }.any { it.size == 3 }
val isTwoPair: Boolean
get() = cards.groupBy { it.weight }.map { it.value }.filter { it.size == 2 }.count() == 2
val isPair: Boolean
get() = cards.groupBy { it.weight }.map { it.value }.any { it.size == 2 }
init {
val cards = ArrayList<Card>()
hand.split(" ").forEach {
when (it.length != 2) {
true -> throw RuntimeException("A card code must be two characters")
else -> cards += Card(Weight.forCode(it[0]), Suit.forCode(it[1]))
}
}
if (cards.size != 5) {
throw RuntimeException("There must be five cards in a hand")
}
this.cards = cards.sortedBy { it.weight.ordinal }
}
override fun compareTo(other: PokerHand): Int = when {
(this.isStraightFlush || other.isStraightFlush) ->
if (this.isStraightFlush) if (other.isStraightFlush) compareByHighCard(other) else WIN else LOSS
(this.isFourOfAKind || other.isFourOfAKind) ->
if (this.isFourOfAKind) if (other.isFourOfAKind) compareByHighCard(other) else WIN else LOSS
(this.isFullHouse || other.isFullHouse) ->
if (this.isFullHouse) if (other.isFullHouse) compareByHighCard(other) else WIN else LOSS
(this.isFlush || other.isFlush) ->
if (this.isFlush) if (other.isFlush) compareByHighCard(other) else WIN else LOSS
(this.isStraight || other.isStraight) ->
if (this.isStraight) if (other.isStraight) compareByHighCard(other) else WIN else LOSS
(this.isThreeOfAKind || other.isThreeOfAKind) ->
if (this.isThreeOfAKind) if (other.isThreeOfAKind) compareByHighCard(other) else WIN else LOSS
(this.isTwoPair || other.isTwoPair) ->
if (this.isTwoPair) if (other.isTwoPair) compareByHighCard(other) else WIN else LOSS
(this.isPair || other.isPair) ->
if (this.isPair) if (other.isPair) compareByHighCard(other) else WIN else LOSS
else -> compareByHighCard(other)
}
private fun compareByHighCard(other: PokerHand, index: Int = 4): Int = when {
(index < 0) -> TIE
cards[index].weight === other.cards[index].weight -> compareByHighCard(other, index - 1)
cards[index].weight.ordinal > other.cards[index].weight.ordinal -> WIN
else -> LOSS
}
}
Implementation details:
Instantiate with a coded hand, eg 2H 3H 4H 5H 6H
Methods to evaluate whether the hand is a 'Straight Flush', 'Four of a Kind', 'Full House' etc. These are easy to express in Kotlin.
Implements Comparable<PokerHand> to evaluate against another hand using a simple rules approach, eg a straight flush beats four of a kind, which beats a full house, and so forth.
The sources are here.
as the question was for Java and the answer was for Python I thought of posting a newer asnwer in Java. My target is the function to be easy to understand.
The Evaluator will score:
Royal flush - 10000
Straight flush - 9000 + highest card
Four of a kind - 8000 + card
Full house - 7000 + card
----- Here we have a smal gap
Flush - 5000 + highest card
Straight - 4000 + highest card
Three of a kind - 3000 + card
Two pair - 2000 + 13*card1 + card2 (card1 > card2)
Pair - 1000 + card
high card is not scored! (If you tie on a high card you need to keep checking for the next card etc...) If you want to encode that in your evaluator you would really need bitcode and the program would be less understandable. Fortunately enough, it is easy to check high card on two sorted hands so you first check score. If score is equal you check high card to break the tie ;-)
With no further due here is the code (works with sorted hands):
public static int scoreHand(int[] hand) {
return scoreSeries(hand) + scoreKinds(hand);
}
public static int scoreStraight(int[] hand) {
for(int i = 1; i < hand.length; i++) {
if ((hand[i] % 100 + 1) != (hand[i - 1] % 100)) return 0;
}
return 4000;
}
public static int scoreFlush(int[] hand) {
for(int i = 1; i < hand.length; i++) {
if ((hand[i] / 100) != (hand[i - 1] / 100)) return 0;
}
return 5000;
}
public static int scoreSeries(int[] hand) {
int score = scoreFlush(hand) + scoreStraight(hand);
if (hand[0] % 100 == 12 && score == 9000)
return 10000;
if (score > 0) return score + hand[0] % 100;
return 0;
}
public static int scoreKinds(int[] hand) {
int[] counts = new int[13], highCards = new int[2];
int max = 1, twoSets = 0;
for(int i = 0; i < hand.length; i++) {
counts[hand[i] % 100]++;
if (max > 1 && counts[hand[i] % 100] == 2) {
twoSets = 1;
highCards[1] = hand[i] % 100;
}
if (max < counts[hand[i] % 100]) {
max = counts[hand[i] % 100];
highCards[0] = hand[i] % 100;
}
}
if (max == 1) return 0;
int score = (max * 2 + twoSets) * 1000;
if (score < 7000) score -= 3000;
if (max == 2 && twoSets == 1) {
if (highCards[1] > highCards[0]) swap(highCards, 0, 1);
score += 13 * highCards[0] + highCards[1];
} else {
if (counts[highCards[1]] > counts[highCards[0]]) swap(highCards, 0, 1);
score += highCards[0];
}
return score;
}
Here is the algorithm translated to R, tested with a 6 card deck, corresponding to 42.504 combinations given by the result of:
combinations of poker hands. Did not tested with 13 card deck due to processing limitations (it would correspond to 2.598.960 combinations).
The algorithm represents the value of a hand by a string, composed by 2 parts:
5 character with ordered card count (ex. "31100" means three of a kind)
The card numbers are valued by letters from 'B' (Deuce) to 'N' (Ace) (ex. 'NILH' means Ace, Queen, Nine and Eight). It starts in letter 'B' because of the A2345 poker hand where the Ace comes before the '2' which (the Ace) will have the value 'A'.
So, for example, "32000NB" will be a Full House of three Aces and two Deuce.
The poker hand value string is convenient for comparative and ordering purposes.
library(tidyverse)
library(gtools)
hand_value <- function(playerhand) {
numbers <- str_split("23456789TJQKA", "")[[1]]
suits <- str_split("DCHS", "")[[1]]
playerhand <- data.frame(card = playerhand) %>% separate(card, c("number", "suit"), sep = 1)
number_values <- data.frame(number = numbers, value = LETTERS[2:14], stringsAsFactors = FALSE)
playerhand_number <- playerhand %>%
group_by(number) %>%
count(number) %>%
inner_join(number_values, by = "number") %>%
arrange(desc(n), desc(value))
playerhand_suit <- playerhand %>%
group_by(suit) %>%
count(suit) %>%
arrange(desc(n))
if (nrow(playerhand_number) == 5)
{
if (playerhand_number[1,1] == 'A' & playerhand_number[2,1] == '5')
playerhand_number <- data.frame(playerhand_number[,1:2], value = str_split("EDCBA", "")[[1]], stringsAsFactors = FALSE)
straight <- asc(playerhand_number[1,3]) - asc(playerhand_number[5,3]) == 4
} else
straight = FALSE
flush <- nrow(playerhand_suit) == 1
if (flush)
{
if (straight)
playerhand_number <- data.frame(playerhand_number[,c(1,3)], n = c(5, 0, 0, 0, 0), stringsAsFactors = FALSE) else
playerhand_number <- data.frame(playerhand_number[,c(1,3)], n = c(3, 1, 1, 2, 0), stringsAsFactors = FALSE)
} else
{
if (straight)
playerhand_number <- data.frame(playerhand_number[,c(1,3)], n = c(3, 1, 1, 1, 0), stringsAsFactors = FALSE)
}
playerhand_value <- append(append(c(playerhand_number$n), rep("0", 5 - nrow(playerhand_number))), c(playerhand_number$value))
playerhand_value <- paste(playerhand_value, collapse = '')
playerhand_value
}
Testing the function with the same hands of above example:
l <- c("8C TS KC 9H 4S", "7D 2S 5D 3S AC", "8C AD 8D AC 9C", '7C 5H 8D TD KS')
t <- as_tibble(l)
t <- t %>% mutate(hand = str_split(value, " ")) %>% select(hand)
t <- t %>% mutate(value = sapply(t[,1]$hand, hand_value)) %>% arrange(desc(value))
paste(t[[1]][[1]], collapse = " ")
Which returns the same result:
[1] "8C AD 8D AC 9C"
Hope it helps.
public class Line
{
private List<Card> _cardsToAnalyse;
public Line()
{
Cards = new List<Card>(5);
}
public List<Card> Cards { get; }
public string PriceName { get; private set; }
public int Result()
{
_cardsToAnalyse = Cards;
var valueComparer = new CardValueComparer();
_cardsToAnalyse.Sort(valueComparer);
if (ContainsStraightFlush(_cardsToAnalyse))
{
PriceName = "Straight Flush";
return PayTable.StraightFlush;
}
if (ContainsFourOfAKind(_cardsToAnalyse))
{
PriceName = "Quadra";
return PayTable.FourOfAKind;
}
if (ContainsStraight(_cardsToAnalyse))
{
PriceName = "Straight";
return PayTable.Straight;
}
if (ContainsFullen(_cardsToAnalyse))
{
PriceName = "Full House";
return PayTable.Fullen;
}
if (ContainsFlush(_cardsToAnalyse))
{
PriceName = "Flush";
return PayTable.Flush;
}
if (ContainsThreeOfAKind(_cardsToAnalyse))
{
PriceName = "Trinca";
return PayTable.ThreeOfAKind;
}
if (ContainsTwoPairs(_cardsToAnalyse))
{
PriceName = "Dois Pares";
return PayTable.TwoPairs;
}
if (ContainsPair(_cardsToAnalyse))
{
PriceName = "Um Par";
return PayTable.Pair;
}
return 0;
}
private bool ContainsFullen(List<Card> _cardsToAnalyse)
{
var valueOfThree = 0;
// Search for 3 of a kind
Card previousCard1 = null;
Card previousCard2 = null;
foreach (var c in Cards)
{
if (previousCard1 != null && previousCard2 != null)
if (c.Value == previousCard1.Value && c.Value == previousCard2.Value)
valueOfThree = c.Value;
previousCard2 = previousCard1;
previousCard1 = c;
}
if (valueOfThree > 0)
{
Card previousCard = null;
foreach (var c in Cards)
{
if (previousCard != null)
if (c.Value == previousCard.Value)
if (c.Value != valueOfThree)
return true;
previousCard = c;
}
return false;
}
return false;
}
private bool ContainsPair(List<Card> Cards)
{
Card previousCard = null;
foreach (var c in Cards)
{
if (previousCard != null)
if (c.Value == previousCard.Value)
return true;
previousCard = c;
}
return false;
}
private bool ContainsTwoPairs(List<Card> Cards)
{
Card previousCard = null;
var countPairs = 0;
foreach (var c in Cards)
{
if (previousCard != null)
if (c.Value == previousCard.Value)
countPairs++;
previousCard = c;
}
if (countPairs == 2)
return true;
return false;
}
private bool ContainsThreeOfAKind(List<Card> Cards)
{
Card previousCard1 = null;
Card previousCard2 = null;
foreach (var c in Cards)
{
if (previousCard1 != null && previousCard2 != null)
if (c.Value == previousCard1.Value && c.Value == previousCard2.Value)
return true;
previousCard2 = previousCard1;
previousCard1 = c;
}
return false;
}
private bool ContainsFlush(List<Card> Cards)
{
return Cards[0].Naipe == Cards[1].Naipe &&
Cards[0].Naipe == Cards[2].Naipe &&
Cards[0].Naipe == Cards[3].Naipe &&
Cards[0].Naipe == Cards[4].Naipe;
}
private bool ContainsStraight(List<Card> Cards)
{
return Cards[0].Value + 1 == Cards[1].Value &&
Cards[1].Value + 1 == Cards[2].Value &&
Cards[2].Value + 1 == Cards[3].Value &&
Cards[3].Value + 1 == Cards[4].Value
||
Cards[1].Value + 1 == Cards[2].Value &&
Cards[2].Value + 1 == Cards[3].Value &&
Cards[3].Value + 1 == Cards[4].Value &&
Cards[4].Value == 13 && Cards[0].Value == 1;
}
private bool ContainsFourOfAKind(List<Card> Cards)
{
Card previousCard1 = null;
Card previousCard2 = null;
Card previousCard3 = null;
foreach (var c in Cards)
{
if (previousCard1 != null && previousCard2 != null && previousCard3 != null)
if (c.Value == previousCard1.Value &&
c.Value == previousCard2.Value &&
c.Value == previousCard3.Value)
return true;
previousCard3 = previousCard2;
previousCard2 = previousCard1;
previousCard1 = c;
}
return false;
}
private bool ContainsStraightFlush(List<Card> Cards)
{
return ContainsFlush(Cards) && ContainsStraight(Cards);
}
}

Categories