Мой код предназначен для игры в Yahtzee, и все работает нормально, пока я не введу имена игроков, он не выполнит первый бросок и не сообщит мне, что мой бросок недействителен, хотя я еще не выбрал, какие броски кубиков хочу сохранить. . Что для меня странно, так это то, что когда он возвращается к игроку 2, он работает совершенно нормально. Если вы запустите код, вы увидите, что сначала вы получаете две единицы, и в этом-то и заключается проблема.
Вот код
// Include C Libraries
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
// Macros
#define ONE 1
#define TWO 2
#define NAME 20
#define ZERO 0
#define SIX 6
#define ROLLS 3
#define THREE 3
#define FOUR 4
#define FIVE 5
#define DICE 5
#define FALSE 0
#define TRUE 1
// Define enumeration scores
enum scores {one, two, three, four, five, six, three_kind, four_kind, full_house, sm_str, lg_str, yahtzee, chance};
// Function Prototypes
void welcomeScreen();
void playGame();
void displayEmptyCard();
void displayDice();
void displayRandomDice();
int rollDie();
void initDice();
void rollDice();
int selectDice();
void displayRoll();
int isValid();
void trimTrailing();
// Main Function
int main()
{
// Calls welcomeScreen function
welcomeScreen();
//random # generator
srand((unsigned)time(NULL));
// Calls playGame function
playGame();
// Program executed successfully
return 0;
}
// welcomeScreen function displays YAHTZEE logo/rules
void welcomeScreen()
{
// Prints Title
printf("\tY Y A H H TTTTTTTTT ZZZZZZZZ EEEEEEEE EEEEEEEE\n");
printf("\t Y Y A A H H T Z E E \n");
printf("\t Y Y A A H H T Z E E \n");
printf("\t Y Y A A HHHHHHHHH T Z EEEE EEEE \n");
printf("\t Y AAAAAAAAA H H T Z E E \n");
printf("\t Y A A H H T Z E E \n");
printf("\t Y A A H H T ZZZZZZZZ EEEEEEEE EEEEEEEE\n");
printf("\n");
// Prints Game Rules Title
printf("YAHTZEE GAME RULES\n");
printf("\n");
// Prints Game Rules
printf("1. Five six-sided dice are rolled.\n");
printf("2. Players roll all five dice.\n");
printf("3. Players can roll selected dice three times per turn.\n");
printf("4. Players must score one of the 13 categories per turn.\n");
printf("5. Players alternate turns.\n");
printf("6. Game ends when all players score 13 categories.\n");
printf("7. Player with the highest score wins!\n");
printf("\n");
}
// Provides The Actual Game Play
void playGame()
{
// Declaring Characters
char playerOne[NAME];
char playerTwo[NAME];
int currentPlayer = ONE;
int loop = ZERO;
int dice[DICE];
int keep[DICE];
// Player 1 Name Input
printf("Player One, enter your name: ");
scanf("%s", playerOne);
// Player 2 Name Input
printf("Player Two, enter your name: ");
scanf("%s", playerTwo);
printf("\n");
// Lets Play Display
printf("%s and %s, let's play Yahtzee!\n",
playerOne, playerTwo);
printf("\n");
while(loop < 2)
{
if (currentPlayer == ONE)
{
// Tells The Player Whos Turn It Is
printf("%s it's your turn.\n", playerOne);
printf("\n");
// Displays Empty Card/Dice
displayEmptyCard();
printf("\n");
initDice(dice);
initDice(keep);
fflush(stdin);
rollDice(dice, keep);
printf("\n");
currentPlayer = TWO;
}
else if (currentPlayer == TWO)
{
// Tells The Player Whos Turn It Is
printf("%s it's your turn.\n", playerTwo);
printf("\n");
// Displays Empty Card/Dice
displayEmptyCard();
printf("\n");
initDice(dice);
initDice(keep);
fflush(stdin);
rollDice(dice, keep);
}
//Increment loop control variable
loop++;
}
}
// Function to Display The Empty Card
void displayEmptyCard()
{
printf("|---------------------------------------|\n");
printf("| UPPER SECTION | LOWER SECTION |\n");
printf("|---------------------------------------|\n");
printf("|---------------------------------------|\n");
printf("| Aces | | 3 Kind | |\n");
printf("| Twos | | 4 Kind | |\n");
printf("| Threes | | Full Hs | |\n");
printf("| Fours | | Sm Str | |\n");
printf("| Fives | | LG Str | |\n");
printf("| Sixes | | Yahtzee | |\n");
printf("| Total | | Chance | |\n");
printf("| Bonus | | Total | |\n");
printf("|---------------------------------------|\n");
}
//Function to Display Random Dice
void displayRoll(int dice[DICE])
{
printf("\n");
printf("+---------+ +---------+ +---------+ +---------+ +---------+\n");
for (int i = 0; i < 5; ++i){
if (i == 0){
printf("| %d |", dice[i]);
}
else{
printf(" | %d |", dice[i]);
}
}
printf("\n");
printf("+---------+ +---------+ +---------+ +---------+ +---------+\n");
printf(" (1) (2) (3) (4) (5) \n");
printf("\n");
}
//Function for Rolling Dice
int rollDie()
{
int dieValue = rand() % 6 + 1;
return dieValue;
}
//Function to Initialize Dice
void initDice(int dice[DICE]){
for (int i = 0; i < DICE; ++i){
dice[i] = 0;
}
}
//Function to Roll Dice
void rollDice(int dice[DICE], int keep[DICE]){
int roll = 0;
while (roll != 3){
printf("Roll %d", roll + 1);
for (int i = 0; i < DICE; ++i){
if (keep[i] == 0){
dice[i] = rollDie();
}
}
displayRoll(dice);
if (selectDice(dice, keep) == 0){
printf("The dice you have selected are invalid. Please try again.\n");
printf("\n");
}
else{
++roll;
}
}
}
//Function to Select Dice
int selectDice(int dice[DICE], int keep[DICE]){
char input[NAME];
char data[NAME];
char * value;
int valid = 0;
printf("Enter the dice you would like to keep, enter values 1 through 5 with spaces between numbers: \n");
fgets(input, NAME, stdin);
trimTrailing(input);
strcpy(data, input);
valid = isValid(data);
printf("\n");
if (valid == 0){
return 0;
}
initDice(keep);
value = strtok(input, " ");
while (value != NULL){
int number = atoi(value);
if (number >= 1 && number <= 5){
keep[number - 1] = 1;
valid = TRUE;
}
value = strtok(NULL, " ");
}
return valid;
}
//Function to determine if Valid
int isValid(char data[NAME]){
char * value;
int valid = FALSE;
value = strtok(data, " ");
while (value != NULL){
//printf("%d", valid);
int number = atoi(value);
if (number >= 1 && number <= 5){
valid = TRUE;
}
else{
valid = FALSE;
}
break;
}
value = strtok(NULL, " ");
return valid;
}
//Function to Trim Trailing
void trimTrailing(char * str){
// Set default index to invalid number
int index = -1;
// loop control variable
int i = 0;
// Find last index of non-white space character
while(str[i] != '\0'){
if (str[i] != ' ' && str[i] != '\t' && str[i] != '\n'){
index = i;
}
i++;
}
// Mark next character to last non-white space character as NULL
str[index + 1] = '\0';
}
Я пытался отслеживать значения, которые я установил, чтобы определить, когда следует сообщать пользователю о недопустимом вводе, но я просто не могу это определить.
Вы также не обрабатываете EOF, что приводит к тому, что ваша программа переходит в бесконечный цикл. Мой совет: прочитайте строку данных, а затем извлеките из нее все, что сможете, используя sscanf()
или функции более низкого уровня. Если вы не можете ничего извлечь, выбросьте эту строку и возьмите другую. Это более устойчиво к недопустимому вводу, и вы отделяете ввод-вывод, который может привести к сбою или возврату EOF при анализе.
scanf("%s", playerTwo);
оставляет конечную новую строку во входном буфере, который fgets(input, NAME, stdin)
считывает selectDice()
и правильно отклоняет его как недопустимый ввод.
Либо удалите новую строку с помощью getchar()
(или scanf("%c", &(char) {0})
):
scanf("%s", playerTwo);
int ch = getchar();
if (ch == EOF)
exit(0);
Всегда проверяйте возвращаемое значение всех функций ввода-вывода, таких как scanf()
, иначе вы можете работать с неинициализированными данными или попасть в бесконечный цикл EOF.
Или в selectDice()
используйте scanf()
, чтобы прочитать цифры. Простым вариантом было бы использовать:
initDice(keep);
int rv = scanf("%d %d %d %d %d", keep, keep+1, keep+2, keep+3, keep+4);
if (rv == EOF)
exit(0);
Или используйте формат %[^\n]
, чтобы пропускать начальные пробелы и читать все до новой строки. Всегда используйте максимальную ширину поля при чтении строк с scanf()
. Макрос str()
генерирует максимальную ширину поля и обратите внимание, что вам нужно выделить дополнительный байт для ввода:
#define str(s) str2(s)
#define str2(s) #s
// ...
char input[NAME+1];
int rv = scanf(" %" str(NAME) "[^\n]", input);
Более надежный подход — разделить ввод-вывод и анализ и читать построчно (fgets()
или getline()
), а затем использовать sscanf()
или другие функции более низкого уровня для анализа входных данных. Если вы не можете что-то разобрать, выбросьте эту строку и прочитайте другую строку.
Не путайте
scanf()
иfgets()
. См. c-faq.com/stdio/scanfinterlace.html и, возможно, sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html