21 game: Difference between revisions

3,817 bytes added ,  3 years ago
→‎{{header|C}}: a better code variant, fullfilled all use cases / assumptions
m (→‎{{header|REXX}}: added an error check return.)
(→‎{{header|C}}: a better code variant, fullfilled all use cases / assumptions)
Line 175:
*/
 
 
#define _CRT_SECURE_NO_WARNINGS /* turn off MS Visual Studio panic warnings */
/*
* Turn off MS Visual Studio panic warnings which disable to use old gold
* library functions like printf, scanf etc. This definition should be harmless
* for non-MS compilers.
*/
#define _CRT_SECURE_NO_WARNINGS
 
#include <stdio.h>
Line 181 ⟶ 187:
#include <time.h>
 
/*
* Define bool, true and false as needed. The stdbool.h is a standard header
* in C99, therefore for older compilers we need DIY booleans. BTW, there is
* no __STDC__VERSION__ predefined macro in MS Visual C, therefore we need
* check also _MSC_VER.
*/
#if __STDC_VERSION__ >= 199901L || _MSC_VER < 1800
#include <stdbool.h>
#else
#define bool int
#define true 1
#define false 0
#endif
 
#define GOAL 21
static char DESCRIPTION[] =
#define BUFFER_SIZE 256
#define MIN(A,B) (A < B) ? (A) : (B)
#define _(STRING) STRING
 
/*
* Spaces are meaningful: on some systems they can be visible.
*/
static char DESCRIPTION[] = _(
"New 21 Game \n"
" \n"
"21 is a two player game, the game is played by choosing a number \n"
"(1, 2, or 3) to be added to the running total. The game is won by\n"
"the player whose chosen number causes the running total to reach \n"
"exactly 21. The running total starts at zero. \n\n");
 
 
Line 199 ⟶ 228:
* 3. If we cannot do any of the above, we choose a random number.
*
* @param nrunningTotal is the existing running running total BEFORE our move/choice
* @return best move/choice, it may be 1 or 2 or 3
*/
int bestChoiceaiMove(int nrunningTotal)
{
int i;
Line 211 ⟶ 240:
*/
for(i = 1; i <= 3; i++)
if(nrunningTotal + i == 21)
return i;
 
for(i = 1; i <= 3; i++)
if ((nrunningTotal + i - 1) % 4 == 0)
return i;
 
/*
return 1 + rand() % 3;
* If runningTotal was be 20 or 19 or 18 then we will not be here.
* Therefore it is safe to use 1 or 2 or 3 as return value.
* A good human player would always win with AI in this case, but there
* is a possibility that human player would use bad strategy and lose.
* In this case it would be advantageous for AI return low values to stall
* the game to fatigue of the opponent.
*
* Therefore we return 1 in 50%, 2 in 25%, 3 in 25% of cases.
*/
if (rand() % 2)
return 1;
else
return 1 + rand() % 3;
 
}
 
/**
 
* An function to read a single int from the standard input. The value must be
int main(int argc, char* argv[])
* no less than lo and no greater than hi, except 0 which is always accepted.
*
* @param value pointer to int variable, filled with readed value on return
* @lo low limit, must be greater than zero
* @hi high limit, must be greater than zero
* @return false if zero is entered
*/
bool getInt(int* value, int lo, int hi)
{
char p[] = "or enter 0 to exit game";
int player; /* 0 is for AI, 1 is for human player */
char* PLAYERS_NAMESs[BUFFER_SIZE] = {"AI", "human"};
intchar runningTotalb[BUFFER_SIZE];
int choice;
 
if (lo == hi) sprintf(s, _("%d"), lo);
srand(time(NULL));
else if (lo + 1 == hi) sprintf(s, _("%d or %d"), lo, hi);
else if (lo + 2 == hi) sprintf(s, _("%d or %d or %d"), lo, lo+1, hi);
else sprintf(s, _("%d or %d or ... or %d"), lo, lo+1, hi);
 
while (1true) {
{
puts(DESCRIPTION);
printf(_("enter %s to play (%s): "), s, p);
player = rand() % 2; /* It randomly chooses a side to start the game. */
runningTotalfgets(b, =BUFFER_SIZE, 0stdin);
whileif (runningTotalsscanf(b, <"%d", 21value) != 1
|| (*value != 0 && (*value < lo || *value > hi)))
{
ifputs(player_("\nYour answer is not valid choice.\n"));
{continue;
}
printf("\n%s", "enter 1 or 2 or 3: ");
else
if(scanf("%d", &choice) != 1 || choice < 1 || choice > 3)
continue;{
}putchar('\n');
elsereturn *value != 0;
}
choice = bestChoice(runningTotal);
}
}
 
/**
printf("\n%8s %2d = %2d + %1d\n",
* An function to read human move as a user choice.
PLAYERS_NAMES[player],
*
runningTotal + choice, runningTotal, choice);
* @param runningTotal the current running total
* @return human move as a number points to take
*/
int humanMove(int runningTotal)
{
int value;
if (getInt(&value, 1, MIN(3, GOAL - runningTotal)))
return value;
else
return 0;
}
 
runningTotal += choice;
 
/**
if (runningTotal == 21)
* Take the running total and update it with move of a player.
printf("\nThe winner is %s.\n\n\n", PLAYERS_NAMES[player]);
*
* @note This procedure can call exit() function thus terminate the program.
*
* @param runningTotal pointer to int variable with running total
* @param name the name (as a string) for the player
* @param getMove function to calculate or otherwise obtain the move
*/
void update(int* runningTotal, char* name, int (*getMove)(int))
{
int move;
if (*runningTotal < GOAL)
{
move = getMove(*runningTotal);
if (move == 0)
exit(EXIT_SUCCESS);
printf("%8s: %d = %d + %d\n\n",
name, *runningTotal + move, *runningTotal, move);
*runningTotal += move;
if (*runningTotal == GOAL)
printf(_("The winner is %s.\n\n"), name);
}
}
 
/**
player = !player;
* Play a single game, i.e. play until running total reach 21.
}
*/
void playGame(void)
{
int runningTotal;
int move;
 
puts(_("\n---- NEW GAME ----\n"));
puts(_("\nThe running total is currently zero.\n"));
 
runningTotal = 0;
if (rand() % 2)
{
/*
* Force first AI move. We assume that it is not possible to reach GOAL
* in this step (i.e. that all move values are less than GOAL).
*/
puts(_("The first move is AI move.\n"));
update(&runningTotal, "AI", aiMove);
}
else
return EXIT_SUCCESS;
puts(_("The first move is human move.\n"));
}</lang>
 
while (runningTotal < GOAL)
{
update(&runningTotal, "human", humanMove);
update(&runningTotal, "AI", aiMove);
}
}
 
 
/**
* The main entry point.
*
* @param argc number of command line parameters
* @param argv table of command parameters as null-terminated strings
*
* @return exit code for diagnostic purposes (zero matters as a normal ending)
*/
int main(int argc, char* argv[])
{
srand(time(NULL));
puts(DESCRIPTION);
while (true)
playGame();
}
</lang>
 
=={{header|C++}}==