/*									tab:8
 *
 * cribbage.c - Cribbage hand counting for fun and profit
 *
 * "Copyright (c) 1995 by Steve Lumetta and The Regents of the University 
 * of California.  All rights reserved."
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Author:	    Steve Lumetta
 * Version:	    1
 * Creation Date:   Mon Nov  6 16:32:50 1995
 * Filename:	    cribbage.c
 * History:
 *	SL	1	Mon Nov  6 16:33:22 1995
 *		First written.
 */


#include <stdio.h>


static void score_hand (int* cards);


int scores[30];


int 
main ()
{
    int i, cards[5];
    
    for (i = 0; i < 30; i++)
	scores[i] = 0;
    
    for (cards[0] = 0; cards[0] < 52; cards[0]++)
	for (cards[1] = cards[0] + 1; cards[1] < 52; cards[1]++)
	    for (cards[2] = cards[1] + 1; cards[2] < 52; cards[2]++)
		for (cards[3] = cards[2] + 1; cards[3] < 52; cards[3]++)
		    for (cards[4] = cards[3] + 1; cards[4] < 52; cards[4]++)
			score_hand (cards);

    for (i = 0; i < 30; i++)
	printf ("%2d %d\n", i, scores[i]);

    return 0;
}


static void
score_hand (int* cards)
{
    static const int pair_value[4] = {0, 2, 6, 12};    
    static const int rank_value[13] = {
	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10
    };
    int i, j, rank[5], suit[5], score = 0, r_cnt[4], nobs, next, dup;
    int cnt, c3, c4, c5, tot;

    /* Find ranks and suits. */
    for (i = 0; i < 5; i++) {
	rank[i] = cards[i] % 13;
	suit[i] = cards[i] / 13;
    }
    
    /* Sort by rank. */
    for (i = 0; i < 5; i++) {
	for (j = i + 1; j < 5; j++) {
	    if (rank[j] < rank[i]) {
		int t;
		
		t = rank[i];
		rank[i] = rank[j];
		rank[j] = t;
		t = suit[i];
		suit[i] = suit[j];
		suit[j] = t;
	    }
	}
    }

    /* Prepare to count flushes. */
    for (i = 0; i < 4; i++)
	r_cnt[i] = 0;
    for (i = 0; i < 5; i++)
	r_cnt[suit[i]]++;

    /* Count pairs. */
    for (i = 0; i < 5; ) {
	for (j = i + 1; j < 5 && rank[j] == rank[i]; j++);
	score += pair_value[j - i - 1];
	i = j;
    }
	    
    /* Count runs. */
    for (i = 0; i < 5;) {
	next = i;
	dup = 1;
	cnt = 0;
	do {
	    j = next;
	    /* Find card duplicity. */
	    for (next = j + 1; next < 5 && rank[next] == rank[j]; next++);
	    dup *= (next - j);
	    cnt++;
	} while (next < 5 && rank[next] == rank[j] + 1);
	if (cnt >= 3) {
	    score += cnt * dup;
	    break;
	}
	i = next;
    }
	
    /* Count his Nobs. */
    for (i = 0, nobs = 0; i < 5; i++) {
	if (rank[i] != 10 /* Jack */)
	    continue;
	for (j = 0; j < 5; j++)
	    if (suit[j] == suit[i] && j != i)
		nobs++;
    }

    /* Count 15's. */
    for (i = 0; i < 5; i++)
	rank[i] = rank_value[rank[i]];
    for (i = 4; i > 0; i--) {
	for (j = i - 1; j >= 0; j--) {
	    cnt = rank[i] + rank[j];
	    if (cnt == 15) {
		score += 2;
		continue;
	    }
	    if (cnt < 15) {
		for (c3 = j - 1; c3 >= 0; c3--) {
		    next = cnt + rank[c3];
		    if (next == 15) {
			score += 2;
			continue;
		    }
		    if (next < 15) {
			for (c4 = c3 - 1; c4 >= 0; c4--) {
			    tot = next + rank[c4];
			    if (tot == 15 ||
				(c4 > 0 && tot + rank[0] == 15))
				score += 2;
			}
		    }
		}
	    }
	}
    }

    /* Count flushes--a four card flush must all be in the hand
       (and hence his Nobs must be the upcard). */
    for (i = 0; i < 4; i++) {
	if (r_cnt[i] == 5) {
	    score += 5;
	    break;
	}
	if (r_cnt[i] == 4) {
	    scores[score] += (4 - nobs);
	    scores[score + 1] += nobs;
	    scores[score + 4] += 1;
	    return;
	}
    }
    scores[score] += (5 - nobs);
    scores[score + 1] += nobs;
}

