21 game: Difference between revisions
Line 3,444: | Line 3,444: | ||
{{works with|Visual Basic .NET|9.0+}} |
{{works with|Visual Basic .NET|9.0+}} |
||
⚫ | |||
<lang vbnet> |
|||
⚫ | |||
Class MainWindow |
Class MainWindow |
||
Line 3,508: | Line 3,507: | ||
End If |
End If |
||
End Sub |
End Sub |
||
End Class |
End Class</lang> |
||
<lang xaml><Window x:Class="MainWindow" |
|||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
|||
⚫ | |||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
|||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
|||
xmlns:local="clr-namespace:Game21vb" |
|||
mc:Ignorable="d" |
|||
Title="MainWindow" Height="292" Width="409" Loaded="StartGame"> |
|||
<Grid> |
|||
<TextBlock HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="64" Width="376"> |
|||
Game 21 is a two player game, the game is played by choosing a number (1, 2, or 3) to be added to the running total. |
|||
The game is won by the player whose chosen number causes the running total to reach exactly 21. |
|||
The running total starts at zero. |
|||
</TextBlock> |
|||
<Label Content="AI" HorizontalAlignment="Left" Margin="60,121,0,0" VerticalAlignment="Top" Width="49" HorizontalContentAlignment="Right"/> |
|||
<Label Content="Human" HorizontalAlignment="Left" Margin="60,152,0,0" VerticalAlignment="Top" HorizontalContentAlignment="Right"/> |
|||
<Label Content="Total" HorizontalAlignment="Left" Margin="60,183,0,0" VerticalAlignment="Top" Width="49" HorizontalContentAlignment="Right"/> |
|||
<TextBox x:Name="boxAI" HorizontalAlignment="Left" Height="23" Margin="114,125,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" IsReadOnly="True"/> |
|||
<TextBox x:Name="boxHuman" HorizontalAlignment="Left" Height="23" Margin="114,156,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" IsReadOnly="True"/> |
|||
<TextBox x:Name="boxTotal" HorizontalAlignment="Left" Height="23" Margin="114,187,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" IsReadOnly="True"/> |
|||
<Button x:Name="button1" Content="1" HorizontalAlignment="Left" Margin="114,220,0,0" VerticalAlignment="Top" Width="25"/> |
|||
<Button x:Name="button2" Content="2" HorizontalAlignment="Left" Margin="144,220,0,0" VerticalAlignment="Top" Width="25"/> |
|||
<Button x:Name="button3" Content="3" HorizontalAlignment="Left" Margin="174,220,0,0" VerticalAlignment="Top" Width="25"/> |
|||
<Button x:Name="restart" Content="restart" HorizontalAlignment="Left" Margin="215,220,0,0" VerticalAlignment="Top" Width="75"/> |
|||
<Label x:Name="winner" HorizontalAlignment="Left" Margin="245,184,0,0" VerticalAlignment="Top" Width="133"/> |
|||
<Label x:Name="first" HorizontalAlignment="Left" Margin="10,79,0,0" VerticalAlignment="Top"/> |
|||
</Grid> |
|||
⚫ |
Revision as of 11:55, 12 August 2020
You are encouraged to solve this task according to the task description, using any language you may know.
21 is a two player game, the game is played by choosing a number (1, 2, or 3) to be added to the running total.
The game is won by the player whose chosen number causes the running total to reach exactly 21.
The running total starts at zero.
One player will be the computer. Players alternate supplying a number to be added to the running total.
- Task
Write a computer program that will:
- do the prompting (or provide a button menu),
- check for errors and display appropriate error messages,
- do the additions (add a chosen number to the running total),
- display the running total,
- provide a mechanism for the player to quit/exit/halt/stop/close the program,
- issue a notification when there is a winner, and
- determine who goes first (maybe a random or user choice, or can be specified when the game begins).
bash
<lang bash>shopt -s expand_aliases alias bind_variables=' {
local -ri goal_count=21 local -ri player_human=0 local -ri player_computer=1 local -i turn=1 local -i total_count=0 local -i input_number=0 local -i choose_turn=0
} ' whose_turn() {
case $(( ( turn + choose_turn ) % 2 )) in ${player_human}) echo "player";; ${player_computer}) echo "computer";; esac
} next_turn() {
let turn++
} validate_number() {
! test ${input_number} -ge 1 -a ${input_number} -le $( max_guess )
} prompt_number() {
local prompt_str test $( max_guess ) -eq 1 && { prompt_str="enter the number 1 to win" true } || { prompt_str="enter a number between 1 and $( max_guess )" } while [ ! ] do read -p "${prompt_str} (or quit): " input_number=${REPLY} case ${REPLY} in "quit") { false return } ;; esac validate_number || break echo "try again" done
} update_count() {
let total_count+=input_number
} remaining_count() {
echo $(( goal_count - total_count ))
} max_guess() {
local -i remaining_count remaining_count=$( remaining_count ) case $( remaining_count ) in 1|2|3) echo ${remaining_count} ;; *) echo 3 ;; esac
} iter() {
update_count next_turn
} on_game_over() {
test ! ${input_number} -eq $( remaining_count ) || { test ! "$( whose_turn )" = "player" && { echo -ne "\nYou won!\n\n" true } || { echo -ne "\nThe computer won!\nGAME OVER\n\n" } false }
} on_game_start() {
echo 21 Game read -p "Press enter key to start"
} choose_turn() {
let choose_turn=${RANDOM}%2
} choose_number() {
local -i remaining_count remaining_count=$( remaining_count ) case ${remaining_count} in 1|2|3) { input_number=${remaining_count} } ;; 5|6|7) { let input_number=remaining_count-4 } ;; *) { let input_number=${RANDOM}%$(( $( max_guess ) - 1 ))+1 } esac
} game_play() {
choose_turn while [ ! ] do echo "Total now ${total_count} (remaining: $( remaining_count ))" echo -ne "Turn: ${turn} (" test ! "$( whose_turn )" = "player" && { echo -n "Your" true } || { echo -n "Computer" } echo " turn)" test ! "$( whose_turn )" = "player" && { prompt_number || break true } || { choose_number sleep 2 echo "Computer chose ${input_number}" } on_game_over || break sleep 1 iter done
} 21_Game() {
bind_variables on_game_start game_play
} if [ ${#} -eq 0 ] then
true
else
exit 1
fi 21_Game </lang>
C
<lang C>/**
* Game 21 - an example in C language for Rosseta Code. * * A simple game program whose rules are described below * - see DESCRIPTION string. * * This program should be compatible with C89 and up. */
/*
* 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 standard library headers files. */
- include <stdio.h>
- include <stdlib.h>
- 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)
/*
* A very limited support for future l10n and i18n - see GNU gettext. */
- define _(STRING) STRING
/*
* Spaces are meaningful: they can be visible as a background tint. */
static char DESCRIPTION[] = _( "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");
/**
* Choosing the best answer if the current number of points is exactly n. * * The algorithm: * * 1. It is best if it is possible to reach the number 21 at once. * 2. If it is not possible to reach the number 21 just now then * force opponent to take lost position. * 3. If we cannot do any of the above, we choose a random number. * * @param runningTotal is the running total BEFORE our move/choice * @return best move/choice, it may be 1 or 2 or 3 */
int aiMove(int runningTotal) {
int i;
/* * It is possible just to compute i = 21 - n, but the for-if construct * can be "reused" below once again. The efficiency is fairly good anyway. */ for (i = 1; i <= 3; i++) if (runningTotal + i == GOAL) return i;
for (i = 1; i <= 3; i++) if ((runningTotal + i - 1) % 4 == 0) 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 67%, 2 in 16%, 3 in 16% 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. A planned side effect: this function * close program when 0 is entered. * * @lo low limit, must be greater than zero * @hi high limit, must be greater than zero and MUST be not less than lo * @return the readed integer number */
int getInt(int lo, int hi) {
int value; char prompt[BUFFER_SIZE]; char inputBuffer[BUFFER_SIZE];
/* * Although this passage could be written a bit more succinctly, * the current version seems be easier to adopt i18n. */ switch (hi - lo) { case 0: sprintf(prompt, _("enter %d to play (or enter 0 to exit game): "), lo); break; case 1: sprintf(prompt, _("enter %d or %d to play (or enter 0 to exit game): "), lo, hi); break; case 2: sprintf(prompt, _("enter %d or %d or %d to play (or enter 0 to exit game): "), lo, lo + 1, hi); break; default: sprintf(prompt, _("enter %d or %d or ... or %d to play (or enter 0 to exit game): "), lo, lo + 1, hi); }
while (true) { printf(_("%s to play "), prompt); fgets(inputBuffer, BUFFER_SIZE, stdin); if (sscanf(inputBuffer, "%d", &value) != 1) { if (value == 0) exit(0); else if (value >= lo || value <= hi) { putchar('\n'); return value; } else puts(_("\nYour answer is not a valid choice.\n")); } }
}
/**
* 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) {
return getInt(1, MIN(3, GOAL - runningTotal));
}
/**
* 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 (unused) * @param argv table of command parameters (unused) */
int main(int argc, char* argv[]) {
srand(time(NULL)); puts(DESCRIPTION); while (true) playGame();
}</lang>
- Output:
21 Game 21 is a two player game, the game is played by choosing a number (1, 2, or 3) to be added to the running total. The game is won by the player whose chosen number causes the running total to reach exactly 21. The running total starts at zero. ---- NEW GAME ---- The running total is currently zero. The first move is AI move. AI: 1 = 0 + 1 enter 1 or 2 or 3 to play (or enter 0 to exit game): 1 human: 2 = 1 + 1 AI: 5 = 2 + 3 enter 1 or 2 or 3 to play (or enter 0 to exit game): 2 human: 7 = 5 + 2 AI: 9 = 7 + 2 enter 1 or 2 or 3 to play (or enter 0 to exit game): 3 human: 12 = 9 + 3 AI: 13 = 12 + 1 enter 1 or 2 or 3 to play (or enter 0 to exit game): 1 human: 14 = 13 + 1 AI: 17 = 14 + 3 enter 1 or 2 or 3 to play (or enter 0 to exit game): 2 human: 19 = 17 + 2 AI: 21 = 19 + 2 The winner is AI.
C++
<lang cpp>/**
* Game 21 - an example in C++ language for Rosseta Code. * * This version is an example of MVP architecture. The user input, as well as * the AI opponent, is handled by separate passive subclasses of abstract class * named Controller. It can be noticed that the architecture support OCP, * for an example the AI module can be "easily" replaced by another AI etc. * * BTW, it would be better to place each class in its own file. But it would * be less convinient for Rosseta Code, where "one solution" mean "one file". */
- include <cstdlib>
- include <ctime>
- include <iostream>
- include <iomanip>
- include <limits>
using namespace std;
- define _(STR) STR
class Model
{
protected:
int oldTotal; int newTotal; int lastMove;
public:
static const int GOAL = 21; static const int NUMBER_OF_PLAYERS = 2;
Model() { newTotal = 0; oldTotal = 0; lastMove = 0; }
void update(int move) { oldTotal = newTotal; newTotal = oldTotal + move; lastMove = move; }
int getOldTotal() { return oldTotal; }
int getNewTotal() { return newTotal; }
int getLastMove() { return lastMove; }
bool isEndGame() { return newTotal == GOAL; }
};
class View
{
public:
void update(string comment, Model* model) { cout << setw(8) << comment << ": " << model->getNewTotal() << " = " << model->getOldTotal() << " + " << model->getLastMove() << endl << endl; }
void newGame(string player) { cout << _("----NEW GAME----") << endl << endl << _("The running total is currently zero.") << endl << endl << _("The first move is ") << player << _(" move.") << endl << endl; }
void endGame(string name) { cout << endl << _("The winner is ") << name << _(".") << endl << endl << endl; }
};
class Controller
{
public:
virtual string getName() = 0; virtual int getMove(Model* model) = 0;
};
class AI : public Controller
{
public:
string getName() { return _("AI"); }
int getMove(Model* model) { int n = model->getNewTotal(); for (int i = 1; i <= 3; i++) if (n + i == Model::GOAL) return i; for (int i = 1; i <= 3; i++) if ((n + i - 1) % 4 == 0) return i; return 1 + rand() % 3; }
};
class Human : public Controller
{
public:
string getName() { return _("human"); }
int getMove(Model* model) { int n = model->getNewTotal(); int value; while (true) { if (n == Model::GOAL - 1) cout << _("enter 1 to play (or enter 0 to exit game): "); else if (n == Model::GOAL - 2) cout << _("enter 1 or 2 to play (or enter 0 to exit game): "); else cout << _("enter 1 or 2 or 3 to play (or enter 0 to exit game): "); cin >> value; if (!cin.fail()) { if (value == 0) exit(0); else if (value >= 1 && value <= 3 && n + value <= Model::GOAL) { cout << endl; return value; } } cout << _("Your answer is not a valid choice.") << endl; cin.clear(); cin.ignore((streamsize)numeric_limits<int>::max, '\n'); } }
};
class Presenter
{
protected:
Model* model; View* view; Controller** controllers;
public:
Presenter(Model* model, View* view, Controller** controllers) { this->model = model; this->view = view; this->controllers = controllers; }
void run() { int player = rand() % Model::NUMBER_OF_PLAYERS; view->newGame(controllers[player]->getName());
while (true) { Controller* controller = controllers[player]; model->update(controller->getMove(model)); view->update(controller->getName(), model); if (model->isEndGame()) { view->endGame(controllers[player]->getName()); break; } player = (player + 1) % Model::NUMBER_OF_PLAYERS; } }
};
int main(int argc, char* argv)
{
srand(time(NULL));
while (true) { Model* model = new Model(); View* view = new View(); Controller* controllers[Model::NUMBER_OF_PLAYERS]; controllers[0] = new Human(); for (int i = 1; i < Model::NUMBER_OF_PLAYERS; i++) controllers[i] = new AI(); Presenter* presenter = new Presenter(model, view, controllers);
presenter->run();
delete model; delete view; delete controllers[0]; delete controllers[1]; delete presenter; } return EXIT_SUCCESS; // dead code
} </lang>
- Output:
----NEW GAME---- The running total is currently zero. The first move is human move. enter 1 or 2 or 3 to play (or enter 0 to exit game): 1 human: 1 = 0 + 1 AI: 4 = 1 + 3 enter 1 or 2 or 3 to play (or enter 0 to exit game): 2 human: 6 = 4 + 2 AI: 9 = 6 + 3 enter 1 or 2 or 3 to play (or enter 0 to exit game): nope Your answer is not a valid choice. enter 1 or 2 or 3 to play (or enter 0 to exit game): 8 Your answer is not a valid choice. enter 1 or 2 or 3 to play (or enter 0 to exit game): 3 human: 12 = 9 + 3 AI: 13 = 12 + 1 enter 1 or 2 or 3 to play (or enter 0 to exit game): 2 human: 15 = 13 + 2 AI: 17 = 15 + 2 enter 1 or 2 or 3 to play (or enter 0 to exit game): 3 human: 20 = 17 + 3 AI: 21 = 20 + 1 The winner is AI. ----NEW GAME---- The running total is currently zero. The first move is human move. enter 1 or 2 or 3 to play (or enter 0 to exit game): 1 human: 1 = 0 + 1 AI: 4 = 1 + 3 enter 1 or 2 or 3 to play (or enter 0 to exit game): 2 human: 6 = 4 + 2 AI: 9 = 6 + 3 enter 1 or 2 or 3 to play (or enter 0 to exit game): 3 human: 12 = 9 + 3 AI: 13 = 12 + 1 enter 1 or 2 or 3 to play (or enter 0 to exit game): 0
C#
<lang csharp>// 21 Game
using System;
namespace _21Game {
public class Program { private const string computerPlayer = "Computer"; private const string humanPlayer = "Player 1";
public static string SwapPlayer(string currentPlayer) { if (currentPlayer == computerPlayer) { currentPlayer = humanPlayer; } else { currentPlayer = computerPlayer; }
return currentPlayer; }
public static void PlayGame() { bool playAnother = true; int total = 0; int final = 21; int roundChoice = 0; string currentPlayer = RandomPLayerSelect(); int compWins = 0; int humanWins = 0;
while (playAnother) { Console.WriteLine($"Now playing: {currentPlayer}"); try { if (currentPlayer == computerPlayer) { roundChoice = CompMove(total); } else { roundChoice = int.Parse(Console.ReadLine()); }
if (roundChoice != 1 && roundChoice != 2 && roundChoice != 3) { throw new Exception(); }
total += roundChoice; } catch (Exception) { Console.WriteLine("Invalid choice! Choose from numbers: 1, 2, 3."); continue; }
Console.WriteLine(total);
if (total == final) { if (currentPlayer == computerPlayer) { compWins++; } if (currentPlayer == humanPlayer) { humanWins++; } Console.WriteLine($"Winner: {currentPlayer}"); Console.WriteLine($"Comp wins: {compWins}. Human wins: {humanWins}"); Console.WriteLine($"do you wan to play another round? y/n"); var choice = Console.ReadLine(); if (choice == "y") { total = 0; } else if (choice == "n") { break; } else { Console.WriteLine("Invalid choice! Choose from y or n"); continue; } }
else if (total > 21) { Console.WriteLine("Not the right time to play this game :)"); break; }
currentPlayer = SwapPlayer(currentPlayer); } }
public static bool CheckIfCanWin(int total) { bool result = false; if (total == 18) { result = true; } return result; }
public static int CompMove(int total) { int choice = 0;
if (CheckIfCanWin(total)) { choice = 21 - total; } else { choice = new Random().Next(1,4); }
return choice; }
public static string RandomPLayerSelect() { string[] players = new string[] { computerPlayer, humanPlayer }; var random = new Random().Next(0,2); return players[random]; }
public static void Main(string[] args) { // welcome message and rules Console.WriteLine("Welcome to 21 game \n"); Console.WriteLine(@"21 is a two player game.
The game is played by choosing a number. 1, 2, or 3 to be added a total sum. \n The game is won by the player reaches exactly 21. \n" );
Console.WriteLine("Choose your number: (1, 2 or 3)");
PlayGame(); } }
}
</lang>
Factor
A difficulty system has been implemented. The player chooses a difficulty from 1-10. There is a difficulty in 10
chance that the computer opponent gets to move first. There is a difficulty in 10
chance each turn that the computer opponent will make the optimal move (i.e. setting the total to a number of the form 4n+1
) as opposed to a random move. At difficulty level 10, it is impossible for the human player to win the game.
<lang factor>USING: accessors combinators.random continuations formatting io kernel math math.functions math.parser multiline qw random sequences ; IN: rosetta-code.21-game
STRING: welcome 21 is a two-player game. The game is played by choosing a number (1, 2, or 3) to be added to the running total.
The game is won by the player whose chosen number causes the running total to reach 21.
One player will be the computer. Players alternate supplying a number to be added to the running total.
- .welcome ( -- ) welcome print ;
SYMBOLS: +computer+ +human+ ;
TUPLE: game total difficulty who ;
! Instead of saying something dry like 'invalid input,' spice ! it up a little.
- insult ( -- )
{ "No." "Er..." "Learn to read." "I think not." "Come on, is it really this difficult?" } random print ;
- get-input ( options-seq prompt-str -- str )
dup "%s: " printf flush readln dup reach member? [ 2nip ] [ drop insult get-input ] if ;
- get-integer ( options-seq prompt-str -- n )
get-input string>number ;
- get-difficulty ( -- x )
qw{ 1 2 3 4 5 6 7 8 9 10 } "Difficulty (1-10)" get-integer 10 / ;
- human-move ( game -- n )
drop qw{ q 1 2 3 } "Your move (1-3) or q to quit" get-input dup "q" = [ drop return ] when string>number ;
- choose-first-player ( difficulty -- player )
[ +computer+ ] [ +human+ ] ifp ;
- <game> ( -- game )
0 get-difficulty dup choose-first-player game boa ;
- swap-player ( game -- )
[ +human+ = +computer+ +human+ ? ] change-who drop ;
- .total ( game -- ) total>> "Running total: %d\n" printf ;
- random-move ( game -- n ) drop 3 random 1 + ;
- boundary? ( n -- ? ) 1 - 4 divisor? ;
- (optimal-move) ( m -- n ) dup 4 / ceiling 4 * 1 + swap - ;
- optimal-move ( game -- n )
total>> dup boundary? [ random-move ] [ (optimal-move) ] if ;
- computer-move ( game -- n )
dup difficulty>> [ optimal-move ] [ random-move ] ifp dup "Computer chose %d.\n" printf ;
- do-turn ( game -- )
dup dup who>> +human+ = [ human-move ] [ computer-move ] if [ + ] curry change-total dup .total swap-player ;
- do-turns ( game -- )
[ dup total>> 20 > ] [ dup do-turn ] until dup swap-player who>> "%u wins!\n" printf ;
- play-21-game ( -- )
.welcome nl [ <game> do-turns ] with-return ;
MAIN: play-21-game</lang>
- Output:
21 is a two-player game. The game is played by choosing a number (1, 2, or 3) to be added to the running total. The game is won by the player whose chosen number causes the running total to reach 21. One player will be the computer. Players alternate supplying a number to be added to the running total. Difficulty (1-10): 3 Your move (1-3) or q to quit: 3 Running total: 3 Computer chose 2. Running total: 5 Your move (1-3) or q to quit: 2 Running total: 7 Computer chose 2. Running total: 9 Your move (1-3) or q to quit: 1 Running total: 10 Computer chose 3. Running total: 13 Your move (1-3) or q to quit: apple Er... Your move (1-3) or q to quit: 3 Running total: 16 Computer chose 1. Running total: 17 Your move (1-3) or q to quit: 1 Running total: 18 Computer chose 1. Running total: 19 Your move (1-3) or q to quit: 2 Running total: 21 +human+ wins!
Fortran
<lang Fortran>! game 21 - an example in modern fortran language for rosseta code.
subroutine ai
common itotal, igoal if (itotal .lt. igoal) then move = 1 do i = 1, 3 if (mod(itotal + i - 1 , 4) .eq. 0) then move = i end if end do do i = 1, 3 if (itotal + i .eq. igoal) then move = i end if end do print *, " ai ", itotal + move, " = ", itotal, " + ", move itotal = itotal + move if (itotal .eq. igoal) then print *, "" print *, "the winner is ai" print *, "" end if end if
end subroutine ai
subroutine human
common itotal, igoal print *, "" do while (.true.) if (itotal + 1 .eq. igoal) then print *, "enter 1 (or 0 to exit): " else if (itotal + 2 .eq. igoal) then print *, "enter 1 or 2 (or 0 to exit): " else print *, "enter 1 or 2 or 3 (or 0 to exit)" end if read(*,*) move if (move .eq. 0) then stop else if (move .ge. 1 .and. move .le. 3 .and. move + itotal .le. igoal) then print *, " human ", itotal + move, " = ", itotal, " + ", move itotal = itotal + move if (itotal .eq. igoal) then print *, "" print *, "the winner is human" print *, "" end if return else print *, "a bad choice" end if end do
end subroutine human
program main
common itotal, igoal print *,"game 21 - an example in fortran language for rosseta code." print *,"" print *,"21 is a two player game, the game is played by choosing a number" print *,"(1, 2, or 3) to be added to the running total. the game is won" print *,"by the player whose chosen number causes the running total to reach" print *,"exactly 21. the running total starts at zero." print *,"" i = irand(1) igoal = 21 do while(.true.) print *, "---- new game ----" print *, "" print *, "the running total is currently zero." print *, "" itotal = 0 if (mod(irand(0), 2) .eq. 0) then print *, "the first move is ai move." print *, "" call ai else print *, "the first move is human move." print *, "" do while(itotal .lt. igoal) call human call ai end do end if end do
end program main</lang>
- Output:
game 21 - an example in fortran language for rosseta code. 21 is a two player game, the game is played by choosing a number (1, 2, or 3) to be added to the running total. the game is won by the player whose chosen number causes the running total to reach exactly 21. the running total starts at zero. ---- new game ---- the running total is currently zero. the first move is human move. enter 1 or 2 or 3 (or 0 to exit) 1 human 1 = 0 + 1 ai 2 = 1 + 1 enter 1 or 2 or 3 (or 0 to exit) 3 human 5 = 2 + 3 ai 6 = 5 + 1 enter 1 or 2 or 3 (or 0 to exit) 4 a bad choice enter 1 or 2 or 3 (or 0 to exit) 3 human 9 = 6 + 3 ai 10 = 9 + 1 enter 1 or 2 or 3 (or 0 to exit) 2 human 12 = 10 + 2 ai 13 = 12 + 1 enter 1 or 2 or 3 (or 0 to exit) 3 human 16 = 13 + 3 ai 17 = 16 + 1 enter 1 or 2 or 3 (or 0 to exit) 2 human 19 = 17 + 2 ai 21 = 19 + 2 the winner is ai ---- new game ---- the running total is currently zero. the first move is human move. enter 1 or 2 or 3 (or 0 to exit) 0
Go
To give the human player a reasonable chance whoever goes first, the computer always chooses randomly when the running total is below 18 but otherwise chooses the exact number needed to win the game. <lang go>package main
import (
"bufio" "fmt" "log" "math/rand" "os" "strconv" "time"
)
var scanner = bufio.NewScanner(os.Stdin)
var (
total = 0 quit = false
)
func itob(i int) bool {
if i == 0 { return false } return true
}
func getChoice() {
for { fmt.Print("Your choice 1 to 3 : ") scanner.Scan() if scerr := scanner.Err(); scerr != nil { log.Fatalln(scerr, "when choosing number") } text := scanner.Text() if text == "q" || text == "Q" { quit = true return } input, err := strconv.Atoi(text) if err != nil { fmt.Println("Invalid number, try again") continue } newTotal := total + input switch { case input < 1 || input > 3: fmt.Println("Out of range, try again") case newTotal > 21: fmt.Println("Too big, try again") default: total = newTotal fmt.Println("Running total is now", total) return } }
}
func main() {
rand.Seed(time.Now().UnixNano()) computer := itob(rand.Intn(2)) fmt.Println("Enter q to quit at any time\n") if computer { fmt.Println("The computer will choose first") } else { fmt.Println("You will choose first") } fmt.Println("\nRunning total is now 0\n") var choice int for round := 1; ; round++ { fmt.Printf("ROUND %d:\n\n", round) for i := 0; i < 2; i++ { if computer { if total < 18 { choice = 1 + rand.Intn(3) } else { choice = 21 - total } total += choice fmt.Println("The computer chooses", choice) fmt.Println("Running total is now", total) if total == 21 { fmt.Println("\nSo, commiserations, the computer has won!") return } } else { getChoice() if quit { fmt.Println("OK, quitting the game") return } if total == 21 { fmt.Println("\nSo, congratulations, you've won!") return } } fmt.Println() computer = !computer } }
}</lang>
- Output:
A sample game where the human player manages to win even though the computer (chosen randomly) goes first.
Enter q to quit at any time The computer will choose first Running total is now 0 ROUND 1: The computer chooses 1 Running total is now 1 Your choice 1 to 3 : 3 Running total is now 4 ROUND 2: The computer chooses 2 Running total is now 6 Your choice 1 to 3 : 4 Out of range, try again Your choice 1 to 3 : 3 Running total is now 9 ROUND 3: The computer chooses 2 Running total is now 11 Your choice 1 to 3 : 2 Running total is now 13 ROUND 4: The computer chooses 2 Running total is now 15 Your choice 1 to 3 : 2 Running total is now 17 ROUND 5: The computer chooses 1 Running total is now 18 Your choice 1 to 3 : 3 Running total is now 21 So, congratulations, you've won!
A sample game where the human player plays sensibly but still loses when the computer goes first.
Enter q to quit at any time The computer will choose first Running total is now 0 ROUND 1: The computer chooses 3 Running total is now 3 Your choice 1 to 3 : 3 Running total is now 6 ROUND 2: The computer chooses 3 Running total is now 9 Your choice 1 to 3 : 3 Running total is now 12 ROUND 3: The computer chooses 1 Running total is now 13 Your choice 1 to 3 : 3 Running total is now 16 ROUND 4: The computer chooses 1 Running total is now 17 Your choice 1 to 3 : 1 Running total is now 18 ROUND 5: The computer chooses 3 Running total is now 21 So, commiserations, the computer has won!
Haskell
The computer chooses values randomly. <lang haskell>import System.Random import System.IO import System.Exit import Control.Monad import Text.Read import Data.Maybe
promptAgain :: IO Int promptAgain = do
putStrLn "Invalid input - must be a number among 1,2 or 3. Try again." playerMove
playerMove :: IO Int playerMove = do
putStr "Your choice(1 to 3):" number <- getLine when (number == "q") $ do exitWith ExitSuccess let n = readMaybe number :: Maybe Int x <- if isNothing n then promptAgain else let val = read number in if (val > 3 || val < 1) then promptAgain else return val return x
computerMove :: IO Int computerMove = do
x <- randomRIO (1, 3) putStrLn $ "Computer move:" ++ (show x) return x
gameLoop :: (IO Int, IO Int) -> IO Int gameLoop moveorder = loop moveorder 0
where loop moveorder total = do number <- fst moveorder let total1 = number + total putStrLn $ "Running total:" ++ (show total1) if total1 >= 21 then return 0 else do number <- snd moveorder let total2 = number + total1 putStrLn $ "Running total:" ++ (show total2) if total2 >= 21 then return 1 else loop moveorder total2
main :: IO () main = do
hSetBuffering stdout $ BlockBuffering $ Just 1 putStrLn "Enter q to quit at any time" x <- randomRIO (0, 1) :: IO Int let (moveorder, names) = if x == 0 then ((playerMove, computerMove), ("Player", "Computer")) else ((computerMove, playerMove), ("Computer", "Player")) when (x == 1) $ do putStrLn "Computer will start the game" y <- gameLoop moveorder when (y == 0) $ do putStrLn $ (fst names) ++ " has won the game" when (y == 1) $ do putStrLn $ (snd names) ++ " has won the game"</lang>
Java
Options for creating a game:
- Who goes first on the first game. Thereafter, the winner of the current game goes first on the next game.
- The value needed to win the game.
- Valid values allowed to select on each turn.
Sample output provided for options as follows:
- Computer goes first on the first game.
- Value needed to win game is 21.
- Valid values to select is 1, 2, or 3.
The computer strategy is to see if a valid value will win the game. If so, that value is selected. Otherwise, a random value among the valid values is selected.
<lang java> import java.util.Random; import java.util.Scanner;
public class TwentyOneGame {
public static void main(String[] args) { new TwentyOneGame().run(true, 21, new int[] {1, 2, 3}); } public void run(boolean computerPlay, int max, int[] valid) { String comma = ""; for ( int i = 0 ; i < valid.length ; i++ ) { comma += valid[i]; if ( i < valid.length - 2 && valid.length >= 3 ) { comma += ", "; } if ( i == valid.length - 2 ) { comma += " or "; } } System.out.printf("The %d game.%nEach player chooses to add %s to a running total.%n" + "The player whose turn it is when the total reaches %d will win the game.%n" + "Winner of the game starts the next game. Enter q to quit.%n%n", max, comma, max); int cGames = 0; int hGames = 0; boolean anotherGame = true; try (Scanner scanner = new Scanner(System.in);) { while ( anotherGame ) { Random r = new Random(); int round = 0; int total = 0; System.out.printf("Start game %d%n", hGames + cGames + 1); DONE: while ( true ) { round++; System.out.printf("ROUND %d:%n%n", round); for ( int play = 0 ; play < 2 ; play++ ) { if ( computerPlay ) { int guess = 0; // try find one equal for ( int test : valid ) { if ( total + test == max ) { guess = test; break; } } // try find one greater than if ( guess == 0 ) { for ( int test : valid ) { if ( total + test >= max ) { guess = test; break; } } } if ( guess == 0 ) { guess = valid[r.nextInt(valid.length)]; } total += guess; System.out.printf("The computer chooses %d%n", guess); System.out.printf("Running total is now %d%n%n", total); if ( total >= max ) { break DONE; } } else { while ( true ) { System.out.printf("Your choice among %s: ", comma); String line = scanner.nextLine(); if ( line.matches("^[qQ].*") ) { System.out.printf("Computer wins %d game%s, human wins %d game%s. One game incomplete.%nQuitting.%n", cGames, cGames == 1 ? "" : "s", hGames, hGames == 1 ? "" : "s"); return; } try { int input = Integer.parseInt(line); boolean inputOk = false; for ( int test : valid ) { if ( input == test ) { inputOk = true; break; } } if ( inputOk ) { total += input; System.out.printf("Running total is now %d%n%n", total); if ( total >= max ) { break DONE; } break; } else { System.out.printf("Invalid input - must be a number among %s. Try again.%n", comma); } } catch (NumberFormatException e) { System.out.printf("Invalid input - must be a number among %s. Try again.%n", comma); } } } computerPlay = !computerPlay; } } String win; if ( computerPlay ) { win = "Computer wins!!"; cGames++; } else { win = "You win and probably had help from another computer!!"; hGames++; } System.out.printf("%s%n", win); System.out.printf("Computer wins %d game%s, human wins %d game%s%n%n", cGames, cGames == 1 ? "" : "s", hGames, hGames == 1 ? "" : "s"); while ( true ) { System.out.printf("Another game (y/n)? "); String line = scanner.nextLine(); if ( line.matches("^[yY]$") ) { // OK System.out.printf("%n"); break; } else if ( line.matches("^[nN]$") ) { anotherGame = false; System.out.printf("Quitting.%n"); break; } else { System.out.printf("Invalid input - must be a y or n. Try again.%n"); } } } } }
} </lang>
- Output:
A sample of 3 games.
The 21 game. Each player chooses to add 1, 2 or 3 to a running total. The player whose turn it is when the total reaches 21 will win the game. Winner of the game starts the next game. Enter q to quit. Start game 1 ROUND 1: The computer chooses 3 Running total is now 3 Your choice among 1, 2 or 3: 4 Invalid input - must be a number among 1, 2 or 3. Try again. Your choice among 1, 2 or 3: r Invalid input - must be a number among 1, 2 or 3. Try again. Your choice among 1, 2 or 3: 1 Running total is now 4 ROUND 2: The computer chooses 1 Running total is now 5 Your choice among 1, 2 or 3: 3 Running total is now 8 ROUND 3: The computer chooses 1 Running total is now 9 Your choice among 1, 2 or 3: 3 Running total is now 12 ROUND 4: The computer chooses 3 Running total is now 15 Your choice among 1, 2 or 3: 2 Running total is now 17 ROUND 5: The computer chooses 3 Running total is now 20 Your choice among 1, 2 or 3: 1 Running total is now 21 You win and probably had help from another computer!! Computer wins 0 games, human wins 1 game Another game (y/n)? y Start game 2 ROUND 1: Your choice among 1, 2 or 3: 3 Running total is now 3 The computer chooses 1 Running total is now 4 ROUND 2: Your choice among 1, 2 or 3: 3 Running total is now 7 The computer chooses 3 Running total is now 10 ROUND 3: Your choice among 1, 2 or 3: 3 Running total is now 13 The computer chooses 2 Running total is now 15 ROUND 4: Your choice among 1, 2 or 3: 2 Running total is now 17 The computer chooses 1 Running total is now 18 ROUND 5: Your choice among 1, 2 or 3: 3 Running total is now 21 You win and probably had help from another computer!! Computer wins 0 games, human wins 2 games Another game (y/n)? y Start game 3 ROUND 1: Your choice among 1, 2 or 3: 3 Running total is now 3 The computer chooses 3 Running total is now 6 ROUND 2: Your choice among 1, 2 or 3: 3 Running total is now 9 The computer chooses 2 Running total is now 11 ROUND 3: Your choice among 1, 2 or 3: 3 Running total is now 14 The computer chooses 2 Running total is now 16 ROUND 4: Your choice among 1, 2 or 3: 3 Running total is now 19 The computer chooses 2 Running total is now 21 Computer wins!! Computer wins 1 game, human wins 2 games Another game (y/n)? n Quitting.
JavaScript
The solution as a Javascript script inside a page written in HTML5. It should work with all modern browsers. <lang javascript><!DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8"> <meta name="keywords" content="Game 21"> <meta name="description" content=" 21 is a two player game, the game is played by choosing a number (1, 2, or 3) to be added to the running total. The game is won by the player whose chosen number causes the running total to reach exactly 21. The running total starts at zero. "> <meta name="dc.publisher" content="Rosseta Code"> <meta name="dc.date" content="2020-07-23"> <meta name="dc.created" content="2020-07-23"> <meta name="dc.modified" content="2020-07-30"> <title> 21 Game </title> <meta http-equiv="cache-control" content="no-cache">
<style> .ui div { width: 50%; display: inline-flex; justify-content: flex-end; } div.total { margin-bottom: 1ch; } label { padding-right: 1ch; } button + button { margin-left: 1em; } </style>
</head>
<body>
21 Game in ECMA Script (Java Script)
21 is a two player game, the game is played by choosing a number (1, 2, or 3) to be added to the running total. The game is won by the player whose chosen number causes the running total to reach exactly 21. The running total starts at zero.
Use buttons to play.
<label for="human">human last choice:</label> <input type="text" id="human" readonly>
<label for="AI">AI last choice:</label> <input type="text" id="AI" readonly>
<label for="runningTotalText">running total:</label> <input type="text" id="runningTotalText" readonly>
<noscript> No script, no fun. Turn on Javascript on. </noscript>
<script> // I really dislike global variables, but in any (?) WWW browser the global // variables are in the window (separately for each tab) context space. // var runningTotal = 0; const human = document.getElementById('human'); const AI = document.getElementById('AI'); const runningTotalText = document.getElementById('runningTotalText'); const first = document.getElementById('first') const message = document.getElementById('message'); const choiceButtons = new Array(3);
// An function to restart game in any time, should be called as a callback // from the WWW page, see above for an example. // function restart() { runningTotal = 0; runningTotalText.value = runningTotal; human.value = ; AI.value = ; for (let i = 1; i <= 3; i++) { let button = document.getElementById('choice' + i); button.disabled = false; choiceButtons[i] = button; } message.innerText = ; if (Math.random() > 0.5) { update(AI, ai()); first.innerText = 'The first move is AI move.' } else first.innerText = 'The first move is human move.' }
// This function update an (read-only for a user) two text boxes // as well as runningTotal. It should be called only once per a move/turn. // function update(textBox, n) { textBox.value = n; runningTotal = runningTotal + n; runningTotalText.value = runningTotal; for (let i = 1; i <= 3; i++) if (runningTotal + i > 21) choiceButtons[i].disabled = true; }
// An callback function called when the human player click the button. // function choice(n) { update(human, n); if (runningTotal == 21) message.innerText = 'The winner is human.'; else { update(AI, ai()); if (runningTotal == 21) message.innerText = 'The winner is AI.'; } }
// A rather simple function to calculate a computer move for the given total. // function ai() { for (let i = 1; i <= 3; i++) if (runningTotal + i == 21) return i;
for (let i = 1; i <= 3; i++) if ((runningTotal + i - 1) % 4 == 0) return i;
return 1; }
// Run the script - actually this part do only some initialization, because // the game is interactively driven by events from an UI written in HTML. // restart(); </script>
</body> </html></lang>
Julia
The computer or player can always win if they go first and choose a number that brings the total to one of the following: 1, 5, 9, 13, or 17. To make things vary more, there is a choice of computer play level at the start. The computer will randomly respond with level 1 and choose a random response 1/4 of the time at level 2. <lang julia> function trytowin(n)
if 21 - n < 4 println("Computer chooses $(21 - n) and wins. GG!") exit(0) end
end
function choosewisely(n)
trytowin(n) targets = [1, 5, 9, 13, 17, 21] pos = findfirst(x -> x > n, targets) bestmove = targets[pos] - n if bestmove > 3 println("Looks like I could lose. Choosing a 1, total now $(n + 1).") return n + 1 end println("On a roll, choosing a $bestmove, total now $(n + bestmove).") n + bestmove
end
function choosefoolishly(n)
trytowin(n) move = rand([1, 2, 3]) println("Here goes, choosing $move, total now $(n + move).") n + move
end
function choosesemiwisely(n)
trytowin(n) if rand() > 0.75 choosefoolishly(n) else choosewisely(n) end
end
prompt(s) = (println(s, ": => "); return readline())
function playermove(n)
rang = (n > 19) ? "1 is all" : ((n > 18) ? "1 or 2" : "1, 2 or 3") choice = 0 while true nstr = prompt("Your choice ($rang), 0 to exit") if nstr == "0" exit(0) elseif nstr == "1" return n + 1 elseif nstr == "2" && n < 20 return n + 2 elseif nstr == "3" && n < 19 return n + 3 end end
end
function play21game()
n = 0 level = prompt("Level of play (1=dumb, 3=smart)") algo = choosewisely if level == "1" algo = choosefoolishly elseif level == "2" algo = choosesemiwisely elseif level != "3" println("Bad choice syntax--default to smart choice") end whofirst = prompt("Does computer go first? (y or n)") if whofirst[1] == 'y' || whofirst[1] == 'Y' n = algo(n) end while n < 21 n = playermove(n) if n == 21 println("Player wins! Game over, gg!") break end n = algo(n) end
end
play21game() </lang>
Lua
<lang lua> gamewon = false running_total = 0 player = 1 opponent = 2
while not gamewon do
num = 0 if player == 1 then opponent = 2 repeat print("Enter a number between 1 and 3 (0 to quit):") num = io.read("*n") if num == 0 then os.exit() end until (num > 0) and (num <=3) end if player == 2 and not (gamewon) then opponent = 1 if (21 - running_total <= 3) then num = 21 - running_total else num = math.random(1,3) end print("Player 2 picks number "..num) end running_total = running_total + num print("Total: "..running_total) if running_total == 21 then print("Player "..player.." wins!") gamewon = true end if running_total > 21 then print("Player "..player.." lost...") print("Player "..opponent.." wins!") gamewon = true end if player == 1 then player = 2 else player = 1 end
end </lang>
Objeck
<lang objeck>class TwentyOne {
@quit : Bool; @player_total : Int; @computer_total : Int;
function : Main(args : String[]) ~ Nil { TwentyOne->New()->Play(); }
New() { }
method : Play() ~ Nil { player_first := Int->Random(1) = 1;
"Enter 'q' to quit\n==="->PrintLine(); do { if(player_first) { PlayerTurn(); if(<>@quit) { "---"->PrintLine(); ComputerTurn(); }; } else { ComputerTurn(); "---"->PrintLine(); PlayerTurn(); }; "==="->PrintLine(); } while(<>@quit); }
method : ComputerTurn() ~ Nil { input := Int->Random(1, 3); "Computer choose: {$input}"->PrintLine(); @computer_total += input;
if(@computer_total = 21) { "Computer Wins!"->PrintLine(); @quit := true; } else if(@computer_total > 21) { "Computer Loses."->PrintLine(); @quit := true; } else { "Computer total is {$@computer_total}."->PrintLine(); }; }
method : PlayerTurn() ~ Nil { input := GetInput();
if(input = -1) { "Quit"->PrintLine(); @quit := true; } else if(input = 0) { "Invalid Input!"->PrintLine(); } else { @player_total += input; };
if(@player_total = 21) { "Player Wins!"->PrintLine(); @quit := true; } else if(@player_total > 21) { "Player Loses."->PrintLine(); @quit := true; } else { "Player total is {$@player_total}."->PrintLine(); }; }
function : GetInput() ~ Int { "Choosing a number beween 1-3: "->Print();
input := System.IO.Console->ReadString(); if(input->Size() = 1) { if(input->Get(0) = 'q') { return -1; };
return input->ToInt(); };
return 0; }
}</lang>
Pascal
<lang pascal> program Game21;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, System.StrUtils, // for IfThen Winapi.Windows; // for ClearScreen
const
HARD_MODE = True;
var
computerPlayer: string = 'Computer'; humanPlayer: string = 'Player 1';
// for change color ConOut: THandle; BufInfo: TConsoleScreenBufferInfo;
procedure ClearScreen; var
stdout: THandle; csbi: TConsoleScreenBufferInfo; ConsoleSize: DWORD; NumWritten: DWORD; Origin: TCoord;
begin
stdout := GetStdHandle(STD_OUTPUT_HANDLE); Win32Check(stdout <> INVALID_HANDLE_VALUE); Win32Check(GetConsoleScreenBufferInfo(stdout, csbi)); ConsoleSize := csbi.dwSize.X * csbi.dwSize.Y; Origin.X := 0; Origin.Y := 0; Win32Check(FillConsoleOutputCharacter(stdout, ' ', ConsoleSize, Origin, NumWritten)); Win32Check(FillConsoleOutputAttribute(stdout, csbi.wAttributes, ConsoleSize, Origin, NumWritten)); Win32Check(SetConsoleCursorPosition(stdout, Origin));
end;
procedure ResetColor; begin
SetConsoleTextAttribute(ConOut, BufInfo.wAttributes);
end;
procedure ChangeColor(color: Word); begin
ConOut := TTextRec(Output).Handle; GetConsoleScreenBufferInfo(ConOut, BufInfo); SetConsoleTextAttribute(TTextRec(Output).Handle, color);
end;
function SwapPlayer(currentPlayer: string): string; begin
Result := IfThen(currentPlayer = humanPlayer, computerPlayer, humanPlayer);
end;
function RandomPlayerSelect(): string; begin
Result := IfThen(Random() < 0.5, computerPlayer, humanPlayer);
end;
function CheckIfCanWin(total: Integer): Boolean; begin
result := (total >= 18);
end;
function CheckIfCanLose(total: Integer; var choose: Integer; hardMode: Boolean =
False): Boolean;
var
range: Integer;
begin
range := 17 - total; Result := false; if (range > 0) and (range < 4) then begin Result := true; if hardMode then choose := range else choose := Random(range - 1) + 1; end;
end;
function CompMove(total: Integer): Integer; begin
if (CheckIfCanWin(total)) then begin exit(21 - total); end;
if CheckIfCanLose(total, Result, HARD_MODE) then exit;
Result := Random(3) + 1;
end;
function HumanMove: Integer; var
choice: string;
begin
repeat Writeln('Choose from numbers: 1, 2, 3'); Readln(choice); until TryStrToInt(choice, Result) and (Result in [1..3]);
end;
procedure PlayGame(); var
playAnother: Boolean; total, final_, roundChoice, compWins, humanWins: Integer; choice, currentPlayer: string;
begin
playAnother := True; total := 0; final_ := 21; roundChoice := 0; Randomize; currentPlayer := RandomPLayerSelect(); compWins := 0; humanWins := 0;
while (playAnother) do begin ClearScreen; ChangeColor(FOREGROUND_INTENSITY or FOREGROUND_GREEN); Writeln(total); ResetColor; Writeln();
Writeln('Now playing: ' + currentPlayer); if currentPlayer = computerPlayer then roundChoice := CompMove(total) else roundChoice := HumanMove; inc(total, roundChoice);
if (total = final_) then begin if (currentPlayer = computerPlayer) then begin inc(compWins); end else begin inc(humanWins); end;
ClearScreen; Writeln('Winner: ' + currentPlayer); Writeln('Comp wins: ', compWins, '. Human wins: ', humanWins, #10); Writeln('Do you wan to play another round? y/n');
readln(choice);
if choice = 'y' then begin total := 0; ClearScreen; end else if choice = 'n' then playAnother := false else begin Writeln('Invalid choice! Choose from y or n'); Continue; end; end else if total > 21 then begin Writeln('Not the right time to play this game :)'); break; end;
currentPlayer := SwapPlayer(currentPlayer); end;
end;
const
WELLCOME_MSG: array[0..5] of string = ('Welcome to 21 game'#10, '21 is a two player game.', 'The game is played by choosing a number.', '1, 2, or 3 to be added a total sum.'#10, 'The game is won by the player reaches exactly 21.'#10, 'Press ENTER to start!'#10);
var
i: Integer;
begin
try for i := 0 to High(WELLCOME_MSG) do Writeln(WELLCOME_MSG[i]); ResetColor; Readln; // Wait press enter
PlayGame(); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end;
end. </lang>
Perl
<lang perl>print <<'HERE'; The 21 game. Each player chooses to add 1, 2, or 3 to a running total. The player whose turn it is when the total reaches 21 wins. Enter q to quit. HERE
my $total = 0;
while () {
print "Running total is: $total\n"; my ($me,$comp); while () { print 'What number do you play> '; $me = <>; chomp $me; last if $me =~ /^[123]$/; insult($me); } $total += $me; win('Human') if $total >= 21; print "Computer plays: " . ($comp = 1+int(rand(3))) . "\n"; $total += $comp; win('Computer') if $total >= 21;
}
sub win {
my($player) = @_; print "$player wins.\n"; exit;
}
sub insult {
my($g) = @_; exit if $g =~ /q/i; my @insults = ('Yo mama', 'Jeez', 'Ummmm', 'Grow up'); my $i = $insults[1+int rand($#insults)]; print "$i, $g is not an integer between 1 and 3...\n"
}</lang>
- Output:
The 21 game. Each player chooses to add 1, 2, or 3 to a running total. The player whose turn it is when the total reaches 21 wins. Enter q to quit. Running total is: 0 What number do you play> 3 Computer plays: 3 Running total is: 6 What number do you play> 3 Computer plays: 3 Running total is: 12 What number do you play> 3 Computer plays: 2 Running total is: 17 What number do you play> 1 Computer plays: 1 Running total is: 19 What number do you play> 2 Human wins.
Phix
If the computer goes first you cannot win.
Once the computer stops displaying "no clear strategy" you cannot win.
The computer_first flag only applies to the first game. After winning, losing, or conceding, you go first.
<lang Phix>bool computer_first = false
bool show_spoiler = false
integer total = 0
procedure computer_play()
integer move = 0 for i=1 to 3 do if mod(total+i,4)=1 then move = i exit end if end for if move=0 then puts(1,"no clear strategy\n") move = rand(min(3,21-total)) end if printf(1,"Total is %d. I play %d.\n",{total,move}) total += move if total=21 then puts(1,"21! I win!\n") end if
end procedure
puts(1,"\n21 game\n\n") puts(1,"Press escape or q to quit the game, c to concede and start a new game from 0\n\n")
if computer_first then
printf(1,"Total is %d.\n",{total}) computer_play()
elsif show_spoiler then
-- The secret to winning! puts(1,sq_sub("Uif!pomz!xbz!up!xjo!jt!qmbz!2!gjstu-!uifo!5.=dpnqvufs!npwf?!fwfsz!ujnf",1)&"\n\n")
end if
while 1 do
printf(1,"Total is %d. enter 1, 2, or 3: ",{total}) integer ch = wait_key() puts(1,iff(ch=#1B?"esc":ch)&"\n") if ch>='1' and ch<='3' then ch -= '0' if total+ch>21 then puts(1,"Too big\n") else total += ch if total=21 then puts(1,"21! You win!\n") else computer_play() end if end if elsif ch=#1B or lower(ch)='q' then puts(1,"Quitting\n") exit end if if lower(ch)='c' or total=21 then total = 0 end if
end while</lang>
- Output:
21 game Press escape or q to quit the game, c to concede and start a new game from 0 Total is 0. enter 1, 2, or 3: 1 no clear strategy Total is 1. I play 3. Total is 4. enter 1, 2, or 3: 1 no clear strategy Total is 5. I play 1. Total is 6. enter 1, 2, or 3: 3 no clear strategy Total is 9. I play 1. Total is 10. enter 1, 2, or 3: 1 Total is 11. I play 2. Total is 13. enter 1, 2, or 3: 3 Total is 16. I play 1. Total is 17. enter 1, 2, or 3: 2 Total is 19. I play 2. 21! I win! Total is 0. enter 1, 2, or 3: q Quitting
PHP
The solution as a server-side PHP7 script and HTML5. <lang PHP><!DOCTYPE html> <html lang="en">
<head>
<meta charset="UTF-8"> <meta name="keywords" content="Game 21"> <meta name="description" content=" 21 is a two player game, the game is played by choosing a number (1, 2, or 3) to be added to the running total. The game is won by the player whose chosen number causes the running total to reach exactly 21. The running total starts at zero. "> <meta name="dc.publisher" content="Rosseta Code"> <meta name="dc.date" content="2020-07-31"> <meta name="dc.created" content="2020-07-31"> <meta name="dc.modified" content="2020-08-01"> <title> 21 Game </title> <meta http-equiv="cache-control" content="no-cache">
<style> .ui div { width: 50%; display: inline-flex; justify-content: flex-end; } div.total { margin-bottom: 1ch; } label { padding-right: 1ch; } button + button { margin-left: 1em; } </style>
</head>
<body>
21 Game in PHP 7
21 is a two player game, the game is played by choosing a number (1, 2, or 3) to be added to the running total. The game is won by the player whose chosen number causes the running total to reach exactly 21. The running total starts at zero.
<?php
const GOAL = 21; const PLAYERS = array('AI', 'human');
function best_move($n) { for ($i = 1; $i <= 3; $i++) if ($n + $i == GOAL) return $i; for ($i = 1; $i <= 3; $i++) if (($n + $i - 1) % 4 == 0) return $i; return 1; }
if (isset($_GET['reset']) || !isset($_GET['total'])) { $first = PLAYERS[rand(0, 1)]; $total = 0; $human = 0; $ai = 0; $message = ; if ($first == 'AI') { $move = best_move($total); $ai = $move; $total = $total + $move; } } else { $first = $_GET['first']; $total = $_GET['total']; $human = $_GET['human']; $ai = $_GET['ai']; $message = $_GET['message']; }
if (isset($_GET['move'])) { $move = (int)$_GET['move']; $human = $move; $total = $total + $move; if ($total == GOAL) $message = 'The winner is human.'; else { $move = best_move($total); $ai = $move; $total = $total + $move; if ($total == GOAL) $message = 'The winner is AI.'; } }
$state = array(); for ($i = 1; $i <= 3; $i++) $state[$i] = $total + $i > GOAL ? 'disabled' : ;
echo <<< END
The first player is $first. Use buttons to play.
<form class="ui">
<input type='hidden' id='first' name='first' value='$first'> <input type='hidden' name='message' value='$message'>
<label for='human'>human last choice:</label> <input type='text' name='human' readonly value='$human'>
<label for='AI'>AI last choice:</label> <input type='text' name='ai' readonly value='$ai'>
<label for='runningTotalText'>running total:</label> <input type='text' name='total' readonly value='$total'>
</form>
$message
END ?>
</body></lang>
Python
<lang python> from random import randint def start(): game_count=0 print("Enter q to quit at any time.\nThe computer will choose first.\nRunning total is now {}".format(game_count)) roundno=1 while game_count<21: print("\nROUND {}: \n".format(roundno)) t = select_count(game_count) game_count = game_count+t print("Running total is now {}\n".format(game_count)) if game_count>=21: print("So, commiserations, the computer has won!") return 0 t = request_count() if not t: print('OK,quitting the game') return -1 game_count = game_count+t print("Running total is now {}\n".format(game_count)) if game_count>=21: print("So, congratulations, you've won!") return 1 roundno+=1
def select_count(game_count): selects a random number if the game_count is less than 18. otherwise chooses the winning number if game_count<18: t= randint(1,3) else: t = 21-game_count print("The computer chooses {}".format(t)) return t
def request_count(): request user input between 1,2 and 3. It will continue till either quit(q) or one of those numbers is requested. t="" while True: try: t = raw_input('Your choice 1 to 3 :') if int(t) in [1,2,3]: return int(t) else: print("Out of range, try again") except: if t=="q": return None else: print("Invalid Entry, try again")
c=0 m=0 r=True while r: o = start() if o==-1: break else: c+=1 if o==0 else 0 m+=1 if o==1 else 0 print("Computer wins {0} game, human wins {1} games".format(c,m)) t = raw_input("Another game?(press y to continue):") r = (t=="y")</lang>
- Output:
Enter q to quit at any time. The computer will choose first. Running total is now 0 ROUND 1: The computer chooses 1 Running total is now 1 Your choice 1 to 3 :4 Out of range, try again Your choice 1 to 3 :w Invalid Entry, try again Your choice 1 to 3 :3 Running total is now 4 ROUND 2: The computer chooses 1 Running total is now 5 Your choice 1 to 3 :2 Running total is now 7 ROUND 3: The computer chooses 3 Running total is now 10 Your choice 1 to 3 :3 Running total is now 13 ROUND 4: The computer chooses 1 Running total is now 14 Your choice 1 to 3 :2 Running total is now 16 ROUND 5: The computer chooses 1 Running total is now 17 Your choice 1 to 3 :1 Running total is now 18 ROUND 6: The computer chooses 3 Running total is now 21 So, commiserations, the computer has won! Computer wins 1 game, human wins 0 games Another game?(press y to continue):y Enter q to quit at any time. The computer will choose first. Running total is now 0 ROUND 1: The computer chooses 1 Running total is now 1 Your choice 1 to 3 :3 Running total is now 4 ROUND 2: The computer chooses 3 Running total is now 7 Your choice 1 to 3 :3 Running total is now 10 ROUND 3: The computer chooses 3 Running total is now 13 Your choice 1 to 3 :5 Out of range, try again Your choice 1 to 3 :3 Running total is now 16 ROUND 4: The computer chooses 2 Running total is now 18 Your choice 1 to 3 :3 Running total is now 21 So, congratulations, you've won! Computer wins 1 game, human wins 1 games Another game?(press y to continue):y Enter q to quit at any time. The computer will choose first. Running total is now 0 ROUND 1: The computer chooses 3 Running total is now 3 Your choice 1 to 3 :4 Out of range, try again Your choice 1 to 3 :3 Running total is now 6 ROUND 2: The computer chooses 3 Running total is now 9 Your choice 1 to 3 :q OK,quitting the game
Racket
<lang racket>#lang racket
(define limit 21) (define max-resp 3)
(define (get-resp)
(let loop () (match (read-line) [(app (conjoin string? string->number) n) #:when (and (exact-integer? n) (<= 1 n max-resp)) n] ["q" (exit)] [n (printf "~a is not in range 1 and ~a\n" n max-resp) (loop)])))
(define (win human?) (printf "~a wins\n" (if human? "Human" "Computer")))
(printf "The ~a game. Each player chooses to add a number in range 1 and ~a to a running total. The player whose turn it is when the total reaches exactly ~a wins. Enter q to quit.\n\n" limit max-resp limit)
(let loop ([total 0] [human-turn? (= 0 (random 2))])
(define new-total (+ total (cond [human-turn? (printf "Running total is: ~a\n" total) (printf "Your turn:\n") (get-resp)] [else (define resp (random 1 (add1 max-resp))) (printf "Computer plays: ~a\n" resp) resp]))) (cond [(= new-total limit) (win human-turn?)] [(> new-total limit) (win (not human-turn?))] [else (loop new-total (not human-turn?))]))</lang>
- Output:
The 21 game. Each player chooses to add an integer in range 1 and 3 to a running total. The player whose turn it is when the total reaches exactly 21 wins. Enter q to quit. Running total is: 0 Your turn: 1 Computer plays: 3 Running total is: 4 Your turn: foo foo is not an integer in range 1 and 3 Your turn: bar bar is not an integer in range 1 and 3 Your turn: 3 Computer plays: 1 Running total is: 8 Your turn: 1 Computer plays: 1 Running total is: 10 Your turn: 1 Computer plays: 2 Running total is: 13 Your turn: 1 Computer plays: 3 Running total is: 17 Your turn: 1 Computer plays: 2 Running total is: 20 Your turn: 1 Human wins
Raku
(formerly Perl 6)
Since there is no requirement that the computer play sensibly, it always plays a random guess so the player has some chance to win. <lang perl6>say qq :to 'HERE';
The 21 game. Each player chooses to add 1, 2, or 3 to a running total. The player whose turn it is when the total reaches 21 wins. Enter q to quit. HERE
my $total = 0; loop {
say "Running total is: $total"; my ($me,$comp); loop { $me = prompt 'What number do you play> '; last if $me ~~ /^<[123]>$/; insult $me; } $total += $me; win('Human') if $total >= 21; say "Computer plays: { $comp = (1,2,3).roll }\n"; $total += $comp; win('Computer') if $total >= 21;
}
sub win ($player) {
say "$player wins."; exit;
}
sub insult ($g) {
exit if $g eq 'q'; print ('Yo mama,', 'Jeez,', 'Ummmm,', 'Grow up,', 'Did you even READ the instructions?').roll; say " $g is not an integer between 1 & 3..."
}</lang>
- Sample game:
The 21 game. Each player chooses to add 1, 2, or 3 to a running total. The player whose turn it is when the total reaches 21 wins. Enter q to quit. Running total is: 0 What number do you play> 5 Did you even READ the instructions? 5 is not an integer between 1 & 3... What number do you play> g Yo mama, g is not an integer between 1 & 3... What number do you play> 12 Jeez, 12 is not an integer between 1 & 3... What number do you play> 3 Computer plays: 2 Running total is: 5 What number do you play> 3 Computer plays: 3 Running total is: 11 What number do you play> 1 Computer plays: 1 Running total is: 13 What number do you play> 3 Computer plays: 2 Running total is: 18 What number do you play> 3 Human wins.
REXX
Around half of the REXX program deals with incorrect or missing input (of the required integer).
This REXX version allows the user to choose if the computer should go first. <lang rexx>/*REXX program plays the 21 game with a human, each player chooses 1, 2, or 3 which */ /*──────────── is added to the current sum, the first player to reach 21 exactly wins.*/ sep= copies('─', 8); sep2= " "copies('═', 8)" " /*construct an eye─catching msg fences.*/ say sep 'Playing the 21 game.' /*tell what's happening here at the zoo*/ $=0; goal= 21 /*the sum [or running total] (so far).*/
do j=1 while $<goal; call g /*obtain the user's number via a prompt*/ if x\==0 then call tot x, 1 /*Not 0? The user wants to go first. */ if $==goal then leave /*the user won the game with the last #*/ call ?; if y==. then y= random(1, 3) /*get computer's choice or a random #*/ say sep 'The computer chooses ' y " as it's choice." /*inform player.*/ call tot y, 0 /*call subroutine to show the total. */ end /*j*/
say if who then say sep 'Congratulations! You have won the 21 game.'
else say sep 'The computer has won the 21 game.'
exit 0 /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ ?: y=.; do c=1 for 3 until y\==.; if (c+$) // 4 == 1 then y= c; end; return ser: if bad then return; bad=1; say; say; say sep '***error***' arg(1); say; return tot: arg q,who; $=$+q; say sep 'The game total is now' sep2 $ sep2; /*add; show $*/ return /*──────────────────────────────────────────────────────────────────────────────────────*/ g: low = (j \== 1) /*allow user to have computer go first.*/
do until \bad; bad= 0; say /*prompt 'til user gives a good number.*/ say sep 'Please enter a number from ' low " ───► 3 (or Quit):" if j=1 then say sep '[A value of 0 (zero) means you want the computer to go first.]' parse pull x _ . 1 ox; upper x /*obtain user's lowercase response(s). */ if x= then call ser "Nothing entered." if _\== then call ser "Too many arguments entered: " ox if abbrev('QUIT', x, 1) then do; say; say sep "quitting."; exit 1; end if \datatype(x, 'N') then call ser "Argument isn't numeric: " ox if \datatype(x, 'W') then call ser "Number isn't an integer: " ox if x<0 then call ser "Number can't be negative: " x if x=0 & j>1 then call ser "Number can't be zero: " x if x>3 then call ser "Number is too large (>3): " x if bad then iterate /*Had an error? Then get another number*/ x= x/1; if $+x>goal then call ser "Number will cause the sum to exceed " goal': ' x end /*until*/; return</lang>
- output :
──────── Playing the 21 game. ──────── Please enter a number from 0 ───► 3 (or Quit): ──────── [A value of 0 (zero) means you want the computer to go first.] 3 ◄■■■■■■■■■■ user input ──────── The game total is now ════════ 3 ════════ ──────── The computer chooses 2 as it's choice. ──────── The game total is now ════════ 5 ════════ ──────── Please enter a number from 1 ───► 3 (or Quit): 3 ◄■■■■■■■■■■ user input ──────── The game total is now ════════ 8 ════════ ──────── The computer chooses 1 as it's choice. ──────── The game total is now ════════ 9 ════════ ──────── Please enter a number from 1 ───► 3 (or Quit): 3 ◄■■■■■■■■■■ user input ──────── The game total is now ════════ 12 ════════ ──────── The computer chooses 1 as it's choice. ──────── The game total is now ════════ 13 ════════ ──────── Please enter a number from 1 ───► 3 (or Quit): 3 ◄■■■■■■■■■■ user input ──────── The game total is now ════════ 16 ════════ ──────── The computer chooses 1 as it's choice. ──────── The game total is now ════════ 17 ════════ ──────── Please enter a number from 1 ───► 3 (or Quit): 1 ◄■■■■■■■■■■ user input ──────── The game total is now ════════ 18 ════════ ──────── The computer chooses 3 as it's choice. ──────── The game total is now ════════ 21 ════════ ──────── The computer has won the 21 game.
Ring
<lang ring>
- Project : 21 Game
load "guilib.ring"
limit = 21 posold = 0 button = list(limit) mynum = list(3) yournum = list(3)
new qapp
{ win1 = new qwidget() { setwindowtitle("21 Game") setgeometry(100,100,1000,600) label1 = new qlabel(win1) { setgeometry(10,10,1000,600) settext("") }
label2 = new qlabel(win1) { setgeometry(240,50,120,40) setAlignment(Qt_AlignHCenter) setFont(new qFont("Verdana",12,100,0)) settext("my number:") }
label3 = new qlabel(win1) { setgeometry(640,50,120,40) setAlignment(Qt_AlignHCenter) setFont(new qFont("Verdana",12,100,0)) settext("your number:") }
for p = 1 to 3 mynum[p] = new qpushbutton(win1) { setgeometry(200+p*40,100,40,40) setstylesheet("background-color:orange") settext(string(p)) setclickevent("choose(" + string(p) + ",1)") } next
for p = 1 to 3 yournum[p] = new qpushbutton(win1) { setgeometry(600+p*40,100,40,40) setstylesheet("background-color:white") settext(string(p)) setclickevent("choose(" + string(p) + ",2)") } next
for n = 1 to limit button[n] = new qpushbutton(win1) { setgeometry(40+n*40,190,40,40) settext(string(n)) } next show() } exec() }
func choose(ch,ym)
pos = posold + ch if pos > limit msg = "You must choose number from 1 to " + string(limit - posold) msgBox(msg) for n = 1 to 3 mynum[n].setenabled(false) yournum[n].setenabled(false) next return ok for n = posold+1 to pos if ym = 1 button[n] { setstylesheet("background-color:orange") } else button[n] { setstylesheet("background-color:white") } ok next posold = pos if ym = 1 for n = 1 to 3 mynum[n].setenabled(false) yournum[n].setenabled(true) next else for n = 1 to 3 mynum[n].setenabled(true) yournum[n].setenabled(false) next ok if pos = 21 if ym = 1 msgBox("I won!") else msgBox("You won!") ok ok
func msgBox(text) { m = new qMessageBox(win1) { setWindowTitle("21 Game") setText(text) show() }
}
</lang>
Output:
21 Game
rust
<lang rust>use rand::Rng; use std::io;
- [derive(Clone)]
enum PlayerType {
Human, Computer,
}
- [derive(Clone)]
struct Player {
name: String, wins: u32, // holds wins level: u32, // difficulty level of Computer player_type: PlayerType,
}
trait Choose {
fn choose(&self, game: &Game) -> u8;
}
impl Player {
fn new(name: &str, player_type: PlayerType, level: u32) -> Player { Player { name: String::from(name), wins: 0, level, player_type, } } fn get_name(&self) -> &str { &self.name[..] } fn get_level(&self) -> u32 { self.level } fn add_win(&mut self) { self.wins += 1 } fn level_up(&mut self) { self.level += 1 }
}
impl Choose for Player {
fn choose(&self, game: &Game) -> u8 { match self.player_type { PlayerType::Human => loop { let max_choice = game.max_choice(); match max_choice { 1 => println!("Enter a number 1 to win (or quit):"), _ => println!("Enter a number between 1 and {} (or quit):", max_choice) } let mut guess = String::new(); io::stdin() .read_line(&mut guess) .expect("Failed to read line"); if guess.trim() == "quit" { return 0 } let guess: u8 = match guess.trim().parse() { Ok(num) if num >= 1 && num <= max_choice => num, Ok(_) => continue, Err(_) => continue, }; return guess; }, PlayerType::Computer => match self.level { 5 => match game.get_total() { total if total == 20 => 1, total if total == 19 => 2, total if total == 18 => 3, _ => 1, }, 4 => match game.get_total() { total if total == 20 => 1, total if total == 19 => 2, total if total == 18 => 3, _ => rand::thread_rng().gen_range(1, 3), }, 3 => match game.get_total() { total if total == 20 => 1, total if total == 19 => 2, total if total == 18 => 3, _ => rand::thread_rng().gen_range(1, 4), }, 2 => match game.get_total() { total if total == 20 => 1, total if total == 19 => 2, _ => rand::thread_rng().gen_range(1, 3), }, 1 => 1, _ => match game.get_total() { total if total == 20 => 1, total if total == 19 => 2, total if total == 18 => 3, _ => match game.get_remaining() % 4 { 0 => rand::thread_rng().gen_range(1, 4), _ => game.get_remaining() % 4, }, }, }, } }
}
struct Game {
players: Vec<Player>, turn: u8, total: u8, start: u8, // determines which player goes first
}
impl Game {
fn init(players: &Vec<Player>) -> Game { Game { players: players.to_vec(), turn: 1, total: 0, start: rand::thread_rng().gen_range(0, 2), } } fn play(&mut self) -> &Player { loop { println!( "Total now {} (remaining: {})", self.get_total(), self.get_remaining() ); { let player = self.whose_turn(); println!("Turn: {} ({} turn)", self.get_turn(), player.get_name()); let choice = player.choose(&self); if choice == 0 { self.next_turn(); break; // quit } println!("{} choose {}", player.get_name(), choice); self.add_total(choice) } if self.get_total() >= 21 { break; } println!(""); self.next_turn(); } self.whose_turn() } fn add_total(&mut self, choice: u8) { self.total += choice; } fn next_turn(&mut self) { self.turn += 1; } fn whose_turn(&self) -> &Player { let index: usize = ((self.turn + self.start) % 2).into(); &self.players[index] } fn get_total(&self) -> u8 { self.total } fn get_remaining(&self) -> u8 { 21 - self.total } fn max_choice(&self) -> u8 { match self.get_remaining() { 1 => 1, 2 => 2, _ => 3 } } fn get_turn(&self) -> u8 { self.turn }
}
fn main() {
let mut game_count = 0; let mut players = vec![ Player::new("human", PlayerType::Human, 0), Player::new("computer", PlayerType::Computer, 1), ]; println!("21 Game"); println!("Press enter key to start"); { let _ = io::stdin().read_line(&mut String::new()); } loop { game_count += 1; let mut game = Game::init(&players); let winner = game.play(); { let mut index = 0; while index < players.len() { if players[index].get_name() == winner.get_name() { players[index].add_win(); } index += 1 } } println!("\n{} won game {}\n", winner.get_name(), game_count); // limit game count if game_count >= 10000 { break; } // ask player if they want to keep on playing println!("Press enter key to play again (or quit):"); let mut reply = String::new(); io::stdin() .read_line(&mut reply) .expect("Failed to read line"); if reply.trim() == "quit" { break; } // level up computer if winner.get_name() != "computer" { println!("Computer leveling up ..."); players[1].level_up(); println!("Computer now level {}!", players[1].get_level()); println!("Beware!\n"); } } println!("player: {} win: {}", players[0].get_name(), players[0].wins); println!("player: {} win: {}", players[1].get_name(), players[1].wins);
} </lang>
Visual Basic .NET
Platform: .NET
<lang vbnet>' Game 21 in VB.NET - an example for Rosetta Code
Class MainWindow
Private Const GOAL As Integer = 21 Private total As Integer = 0 Private random As New Random
Private Sub Update(box As TextBox, player As String, move As Integer) total = total + move box.Text = move boxTotal.Text = total If total + 1 > GOAL Then button1.IsEnabled = False If total + 2 > GOAL Then button2.IsEnabled = False If total + 3 > GOAL Then button3.IsEnabled = False If total = GOAL Then winner.Content = $"The winner is {player}." End If End Sub
Private Sub Ai() Dim move As Integer = 1 For i = 1 To 3 If (total + i - 1) Mod 4 = 0 Then move = i Next i For i = 1 To 3 If total + i = GOAL Then move = i Next i Update(boxAI, "AI", move) End Sub
Private Sub Choice(sender As Object, e As RoutedEventArgs) _ Handles button1.Click, button2.Click, button3.Click Update(boxHuman, "human", sender.Content) If total < GOAL Then Ai() End Sub
' StartGame method handles both OnLoad (WM_INIT?) event as well as a restart ' of the game after user press the 'restart' button. ' Private Sub StartGame(sender As Object, e As RoutedEventArgs) Handles restart.Click
total = 0
boxAI.Text = "" boxHuman.Text = "" boxTotal.Text = "" 'first.Content = "" ' It is not necessary, see below. winner.Content = ""
button1.IsEnabled = True button2.IsEnabled = True button3.IsEnabled = True
' The random.Next(2) return pseudorandomly either 0 or 1. Generally ' random.Next(n) Return a value from 0 (inclusive) To n - 1 (inclusive). ' If random.Next(2) = 0 Then first.Content = "First player is AI player." Ai() Else first.Content = "First player is human player." End If End Sub
End Class</lang> <lang xaml><Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Game21vb" mc:Ignorable="d" Title="MainWindow" Height="292" Width="409" Loaded="StartGame"> <Grid> <TextBlock HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="64" Width="376"> Game 21 is a two player game, the game is played by choosing a number (1, 2, or 3) to be added to the running total. The game is won by the player whose chosen number causes the running total to reach exactly 21. The running total starts at zero. </TextBlock> <Label Content="AI" HorizontalAlignment="Left" Margin="60,121,0,0" VerticalAlignment="Top" Width="49" HorizontalContentAlignment="Right"/> <Label Content="Human" HorizontalAlignment="Left" Margin="60,152,0,0" VerticalAlignment="Top" HorizontalContentAlignment="Right"/> <Label Content="Total" HorizontalAlignment="Left" Margin="60,183,0,0" VerticalAlignment="Top" Width="49" HorizontalContentAlignment="Right"/> <TextBox x:Name="boxAI" HorizontalAlignment="Left" Height="23" Margin="114,125,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" IsReadOnly="True"/> <TextBox x:Name="boxHuman" HorizontalAlignment="Left" Height="23" Margin="114,156,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" IsReadOnly="True"/> <TextBox x:Name="boxTotal" HorizontalAlignment="Left" Height="23" Margin="114,187,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" IsReadOnly="True"/> <Button x:Name="button1" Content="1" HorizontalAlignment="Left" Margin="114,220,0,0" VerticalAlignment="Top" Width="25"/> <Button x:Name="button2" Content="2" HorizontalAlignment="Left" Margin="144,220,0,0" VerticalAlignment="Top" Width="25"/> <Button x:Name="button3" Content="3" HorizontalAlignment="Left" Margin="174,220,0,0" VerticalAlignment="Top" Width="25"/> <Button x:Name="restart" Content="restart" HorizontalAlignment="Left" Margin="215,220,0,0" VerticalAlignment="Top" Width="75"/> <Label x:Name="winner" HorizontalAlignment="Left" Margin="245,184,0,0" VerticalAlignment="Top" Width="133"/> <Label x:Name="first" HorizontalAlignment="Left" Margin="10,79,0,0" VerticalAlignment="Top"/> </Grid>
</Window></lang>