/*
 * HandRanks.h - Fast poker hand evaluator (Cactus Kev style)
 * Generated by HandRankGen
 *
 * Ranks: 1 (royal flush) to 7462 (7-5-4-3-2 high card)
 * Card encoding: card = rank*4 + suit (0-51)
 *   rank: 0=2, 1=3, 2=4, ..., 8=T, 9=J, 10=Q, 11=K, 12=A
 *   suit: 0=c, 1=d, 2=h, 3=s
 */

#ifndef HAND_RANKS_H
#define HAND_RANKS_H

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

static const int HR_PRIMES[13] = {2,3,5,7,11,13,17,19,23,29,31,37,41};

typedef struct { int32_t product; int16_t rank; } HR_Product;

typedef struct {
    int16_t *flush;
    int16_t *unique5;
    HR_Product *products;
    int num_products;
} HandRankTables;

static inline HandRankTables* hr_load(const char *path) {
    FILE *f = fopen(path, "rb");
    if (!f) return NULL;
    int32_t hdr[4];
    if (fread(hdr, 4, 4, f) != 4 || hdr[0] != 0x48524E4B || hdr[1] != 3) {
        fclose(f); return NULL;
    }
    HandRankTables *t = malloc(sizeof(HandRankTables));
    t->flush = malloc(hdr[2] * 2);
    t->unique5 = malloc(hdr[2] * 2);
    t->products = malloc(hdr[3] * sizeof(HR_Product));
    t->num_products = hdr[3];
    fread(t->flush, 2, hdr[2], f);
    fread(t->unique5, 2, hdr[2], f);
    fread(t->products, sizeof(HR_Product), hdr[3], f);
    fclose(f);
    return t;
}

static inline void hr_free(HandRankTables *t) {
    if (t) { free(t->flush); free(t->unique5); free(t->products); free(t); }
}

static inline int hr_bsearch(const HandRankTables *t, int32_t prod) {
    int lo = 0, hi = t->num_products - 1;
    while (lo <= hi) {
        int mid = (lo + hi) / 2;
        if (t->products[mid].product == prod) return t->products[mid].rank;
        if (t->products[mid].product < prod) lo = mid + 1;
        else hi = mid - 1;
    }
    return 7462;
}

static inline int hr_eval_5(const HandRankTables *t, int c0, int c1, int c2, int c3, int c4) {
    int r0=c0/4, r1=c1/4, r2=c2/4, r3=c3/4, r4=c4/4;
    int s0=c0%4, s1=c1%4, s2=c2%4, s3=c3%4, s4=c4%4;
    int bits = (1<<r0)|(1<<r1)|(1<<r2)|(1<<r3)|(1<<r4);
    if (s0==s1 && s1==s2 && s2==s3 && s3==s4) return t->flush[bits];
    int n = bits, u = 0; while (n) { u += n & 1; n >>= 1; }
    if (u == 5) return t->unique5[bits];
    int32_t p = (int32_t)HR_PRIMES[r0]*HR_PRIMES[r1]*HR_PRIMES[r2]*HR_PRIMES[r3]*HR_PRIMES[r4];
    return hr_bsearch(t, p);
}

static inline int hr_eval_7(const HandRankTables *t, int c0, int c1, int c2, int c3, int c4, int c5, int c6) {
    int c[7] = {c0,c1,c2,c3,c4,c5,c6};
    int best = 9999;
    for (int i = 0; i < 7; i++) {
        for (int j = i+1; j < 7; j++) {
            int h[5], k = 0;
            for (int x = 0; x < 7; x++) if (x != i && x != j) h[k++] = c[x];
            int r = hr_eval_5(t, h[0], h[1], h[2], h[3], h[4]);
            if (r < best) best = r;
        }
    }
    return best;
}

static inline int hr_category(int rank) {
    if (rank <= 10) return 8;
    if (rank <= 166) return 7;
    if (rank <= 322) return 6;
    if (rank <= 1599) return 5;
    if (rank <= 1609) return 4;
    if (rank <= 2467) return 3;
    if (rank <= 3325) return 2;
    if (rank <= 6185) return 1;
    return 0;
}

static const char *HR_CATEGORY_NAMES[] = {
    "High Card", "Pair", "Two Pair", "Three of a Kind",
    "Straight", "Flush", "Full House", "Four of a Kind", "Straight Flush"
};

#endif
