In pratica l'esercizio chiede di modificare un programma (inserito di seguito), che prende in input 5 carte (i valori sono 2 3 4 5 6 7 8 9 t j q k a mentre i semi sono c d h s) e calcola il valore in base ai punti del poker.
La modifica da effettuare è rimuovere i vettori num_in_rank, num_in_suit e card_exists dal programma originale e salvare le carte in un vettore 5x2 (ogni riga contiene il valore nella colonna 0 e il seme nella colonna 1). Il programma originale è questo:
/*********************************************************
* From C PROGRAMMING: A MODERN APPROACH, Second Edition *
* By K. N. King *
* Copyright (c) 2008, 1996 W. W. Norton & Company, Inc. *
* All rights reserved. *
* This program may be freely distributed for class use, *
* provided that this copyright notice is retained. *
*********************************************************/
/* poker.c (Capitolo 10, pag. 244) */
/* Classifica una mano di poker */
#include <stdbool.h> /* solo C99 */
#include <stdio.h>
#include <stdlib.h>
#define NUM_RANKS 13
#define NUM_SUITS 4
#define NUM_CARDS 5
/* external variables */
int num_in_rank[NUM_RANKS];
int num_in_suit[NUM_SUITS];
bool straight, flush, four, three;
int pairs; /* can be 0, 1, or 2 */
/* prototypes */
void read_cards(void);
void analyze_hand(void);
void print_result(void);
/**********************************************************
* main: Chiama ripetutamente read_cards, analyze_hand *
* e print_result *
**********************************************************/
int main(void)
{
for (;;) {
read_cards();
analyze_hand();
print_result();
}
}
/***********************************************************
* read_cards: Salva le carte lette nelle varibili esterne *
* num_in_rank e num_in_suit. Esegue il *
* controllo per le carte errate *
* e per quelle duplicate. *
***********************************************************/
void read_cards(void)
{
bool card_exists[NUM_RANKS][NUM_SUITS];
char ch, rank_ch, suit_ch;
int rank, suit;
bool bad_card;
int cards_read = 0;
for (rank = 0; rank < NUM_RANKS; rank++) {
num_in_rank[rank] = 0;
for (suit = 0; suit < NUM_SUITS; suit++)
card_exists[rank][suit] = false;
}
for (suit = 0; suit < NUM_SUITS; suit++)
num_in_suit[suit] = 0;
while (cards_read < NUM_CARDS) {
bad_card = false;
printf("Enter a card: ");
rank_ch = getchar();
switch (rank_ch) {
case '0': exit(EXIT_SUCCESS);
case '2': rank = 0; break;
case '3': rank = 1; break;
case '4': rank = 2; break;
case '5': rank = 3; break;
case '6': rank = 4; break;
case '7': rank = 5; break;
case '8': rank = 6; break;
case '9': rank = 7; break;
case 't': case 'T': rank = 8; break;
case 'j': case 'J': rank = 9; break;
case 'q': case 'Q': rank = 10; break;
case 'k': case 'K': rank = 11; break;
case 'a': case 'A': rank = 12; break;
default: bad_card = true;
}
suit_ch = getchar();
switch (suit_ch) {
case 'c': case 'C': suit = 0; break;
case 'd': case 'D': suit = 1; break;
case 'h': case 'H': suit = 2; break;
case 's': case 'S': suit = 3; break;
default: bad_card = true;
}
while ((ch = getchar()) != '\n')
if (ch != ' ') bad_card = true;
if (bad_card)
printf("Bad card; ignored.\n");
else if (card_exists[rank][suit])
printf("Duplicate card; ignored.\n");
else {
num_in_rank[rank]++;
num_in_suit[suit]++;
card_exists[rank][suit] = true;
cards_read++;
}
}
}
/**************************************************************
* analyze_hand: Determina se la mano contiene una scala, *
* un colore, un poker e/o un tris; determina *
* il numero delle coppie e salva il risultato *
* all'interno nelle variabili esterne straight *
* flush, four, three e pairs. *
**************************************************************/
void analyze_hand(void)
{
int num_consec = 0;
int rank, suit;
straight = false;
flush = false;
four = false;
three = false;
pairs = 0;
/* check for flush */
for (suit = 0; suit < NUM_SUITS; suit++)
if (num_in_suit[suit] == NUM_CARDS)
flush = true;
/* check for straight */
rank = 0;
while (num_in_rank[rank] == 0) rank++;
for (; rank < NUM_RANKS && num_in_rank[rank] > 0; rank++)
num_consec++;
if (num_consec == NUM_CARDS) {
straight = true;
return;
}
/* check for 4-of-a-kind, 3-of-a-kind, and pairs */
for (rank = 0; rank < NUM_RANKS; rank++) {
if (num_in_rank[rank] == 4) four = true;
if (num_in_rank[rank] == 3) three = true;
if (num_in_rank[rank] == 2) pairs++;
}
}
/**********************************************************
* print_result: Stampa la classificazione della mano *
* basandosi sui valori delle variabili *
* esterne straight, flush, four, three, *
* e pairs. *
**********************************************************/
void print_result(void)
{
if (straight && flush) printf("Straight flush");
else if (four) printf("Four of a kind");
else if (three &&
pairs == 1) printf("Full house");
else if (flush) printf("Flush");
else if (straight) printf("Straight");
else if (three) printf("Three of a kind");
else if (pairs == 2) printf("Two pairs");
else if (pairs == 1) printf("Pair");
else printf("High card");
printf("\n\n");
}
La mia modifica mi dà i risultati corretti...per la verità ho provato solo alcuni valori in quanto mi compare un bug (che non intacca il funzionamento del resto del programma).
Il bug credo appartenga alla funzione read_cards(). Quando inserisco le carte, a partire dalla seconda, mi compare la scritta "Duplicate card; ignored." che dovrebbe comparire solo se viene inserita una carta già inserita in precedenza. La cosa strana è che la chiamata a quella printf è seguita dall'istruzione break che esclude che la carta duplicata venga salvata, quindi la condizione che permette la chiamata alla printf (stampando il messaggio di carta duplicata) dovrebbe chiamare anche l'istruzione di break interrompendo il salvataggio della carta... ma ciò non avviene! In pratica se la carta non è un doppione, mi compare il messaggio (che non dovrebbe comparire) ma effettivamente non salva la carta (e qui fa la cosa corretta permettendo al programma di proseguire); nel caso in cui si inserisce un doppione fa quello che dovrebbe fare.
Il codice del mio programma è questo:
/*********************************************************
* From C PROGRAMMING: A MODERN APPROACH, Second Edition *
* By K. N. King *
* Copyright (c) 2008, 1996 W. W. Norton & Company, Inc. *
* All rights reserved. *
*********************************************************/
/* Progetto di programmazione 3 */
/* Classifica una mano di poker */
#include <stdbool.h> /* solo C99 */
#include <stdio.h>
#include <stdlib.h>
#define NUM_RANKS 13
#define NUM_SUITS 4
#define NUM_CARDS 5
#define NUM_INFO 2
/* external variables */
int card[NUM_CARDS][NUM_INFO];
bool straight, flush, four, three;
int pairs; /* can be 0, 1, or 2 */
/* prototypes */
void read_cards(void);
void analyze_hand(void);
void print_result(void);
/**********************************************************
* main: Chiama ripetutamente read_cards, analyze_hand *
* e print_result *
**********************************************************/
int main(void)
{
for (;;) {
read_cards();
analyze_hand();
print_result();
}
}
/***********************************************************
* read_cards: Salva le carte lette nelle varibili esterne *
* num_in_rank e num_in_suit. Esegue il *
* controllo per le carte errate *
* e per quelle duplicate. *
***********************************************************/
void read_cards(void)
{
char ch, rank_ch, suit_ch;
int rank, suit, card_num, card_type;
bool bad_card;
int cards_read = 0;
for (card_num = 0; card_num < NUM_CARDS; card_num++) {
for (card_type = 0; card_type < NUM_INFO; card_type++)
card[card_num][card_type] = 0;
}
while (cards_read < NUM_CARDS) {
bad_card = false;
printf("Enter a card: ");
rank_ch = getchar();
switch (rank_ch) {
case '0': exit(EXIT_SUCCESS);
case '2': rank = 0; break;
case '3': rank = 1; break;
case '4': rank = 2; break;
case '5': rank = 3; break;
case '6': rank = 4; break;
case '7': rank = 5; break;
case '8': rank = 6; break;
case '9': rank = 7; break;
case 't': case 'T': rank = 8; break;
case 'j': case 'J': rank = 9; break;
case 'q': case 'Q': rank = 10; break;
case 'k': case 'K': rank = 11; break;
case 'a': case 'A': rank = 12; break;
default: bad_card = true;
}
suit_ch = getchar();
switch (suit_ch) {
case 'c': case 'C': suit = 0; break;
case 'd': case 'D': suit = 1; break;
case 'h': case 'H': suit = 2; break;
case 's': case 'S': suit = 3; break;
default: bad_card = true;
}
while ((ch = getchar()) != '\n')
if (ch != ' ') bad_card = true;
if (bad_card) {
printf("Bad card; ignored.\n");
} else if (cards_read == 0) {
card[cards_read][0] = rank;
card[cards_read][1] = suit;
cards_read++;
} else {
for (int i = 0; i < cards_read; i++) {
if ( (card[i][0]) == rank && (card[i][1]) == suit ) {
printf("Duplicate card;ignored\n");
break;
} else if (i == (cards_read - 1)) {
card[cards_read][0] = rank;
card[cards_read][1] = suit;
cards_read++;
}
}
}
}
}
/**************************************************************
* analyze_hand: Determina se la mano contiene una scala, *
* un colore, un poker e/o un tris; determina *
* il numero delle coppie e salva il risultato *
* all'interno nelle variabili esterne straight *
* flush, four, three e pairs. *
**************************************************************/
void analyze_hand(void)
{
straight = true;
flush = true;
four = false;
three = false;
pairs = 0;
/* check for flush */
for (int i = 0; i < NUM_CARDS; i++) {
if (card[i][1] != card[0][1]) {
flush = false;
break;
}
}
/* ordina le carte dalla più piccola alla più grande */
int r = NUM_CARDS;
while (r > 0) {
for (int i = 0; i < (r - 1); i++) {
if (card[i][0] > card[i+1][0]) {
int temp;
temp = card[i][0];
card[i][0] = card[i+1][0];
card[i+1][0] = temp;
temp = card[i][1];
card[i][1] = card[i+1][1];
card[i+1][1] = temp;
}
}
r -= 1;
}
/* controlla coppie, tris e poker */
int cont = 0;
for (int i = 1; i < NUM_CARDS; i++) {
if (card[i-1][0] == card[i][0]) {
cont += 1;
pairs += 1;
} else {
cont = 0;
}
if (cont == 2) {
three = true;
pairs -= 2;
} else if (cont == 3) {
pairs -= 1;
three = false;
four = true;
}
}
/* controlla se c'è una scala */
for (int i = 1; i < NUM_CARDS; i++) {
if ((card[i][0] - card[i-1][0]) != 1) {
straight = false;
return;
}
}
}
/**********************************************************
* print_result: Stampa la classificazione della mano *
* basandosi sui valori delle variabili *
* esterne straight, flush, four, three, *
* e pairs. *
**********************************************************/
void print_result(void)
{
if (straight && flush) printf("Straight flush");
else if (four) printf("Four of a kind");
else if (three &&
pairs == 1) printf("Full house");
else if (flush) printf("Flush");
else if (straight) printf("Straight");
else if (three) printf("Three of a kind");
else if (pairs == 2) printf("Two pairs");
else if (pairs == 1) printf("Pair");
else printf("High card");
printf("\n\n");
}
Quindi il risultato è corretto ma mi stampa quei messaggi che non capisco da dove escono.
Il pezzo di codice che contiene l'istruzione di stampa è:
for (int i = 0; i < cards_read; i++) {
if ( (card[i][0]) == rank && (card[i][1]) == suit ) {
printf("Duplicate card; ignored.\n");
break;
} else if (i == (cards_read - 1)) {
card[cards_read][0] = rank;
card[cards_read][1] = suit;
cards_read++;
}
}
A me sembra che dovrebbe accedere alla printf all'istruzione break contemporaneamente, senza possibilità che acceda al break senza passare per la printf o viceversa.
Edit: aggiungo che mi sono reso conto che c'è un bug anche nel conteggio di coppie, tris, e poker, al quale devo dare un'occhiata