Anonymous user
21 game: Difference between revisions
→{{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:
*/
/*
* 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
#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
* @return best move/choice, it may be 1 or 2 or 3
*/
int
{
int i;
Line 211 ⟶ 240:
*/
for(i = 1; i <= 3; i++)
if(
return i;
for(i = 1; i <= 3; i++)
if ((
return i;
/*
* 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
* 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";
char
if (lo == hi) sprintf(s, _("%d"), lo);
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 (
{
printf(_("enter %s to play (%s): "), s, p);
|| (*value != 0 && (*value < lo || *value > hi)))
{
}
else
}
}
}
/**
* An function to read human move as a user 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;
}
/**
* Take the running total and update it with move of a 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);
}
}
/**
* 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
puts(_("The first move is human move.\n"));
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++}}==
|