5 # Copyright (C) 2013 Jason Self <j@jxself.org>
7 # This software's license gives you freedom; you can modify, propagate,
8 # and/or convey it under the terms of the GNU Affero General Public
9 # License as published by the Free Software Foundation (FSF); either
10 # version 3 of the License, or (at your option) any later version
11 # published by the FSF.
13 # This program is distributed in the hope that it will be useful, but WITHOUT
14 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
18 # You should have received a copy of the GNU Affero General Public License
19 # along with this program in a file called 'AGPLv3.txt'. If not, see
20 # http://www.gnu.org/licenses/agpl-3.0-standalone.html or write to the: Free
21 # Software Foundation, Inc., 51 Franklin St, Fifth Floor Boston, MA
44 # Checks that the guess is a number and has the same number of digits as
45 # specified by $DIGITS.
46 sub is_correct_format {
49 return ($guess =~ m/^\d{$DIGITS}$/);
52 # Checks that the guess is made up of distinct digits if $DISTINCT is 1.
54 my $array_ref = shift;
55 my @guess_digits = @{$array_ref};
57 for (my $i = 0; $i < $DIGITS; $i++) {
58 for (my $j = $i+1; $j < $DIGITS; $j++) {
59 if ($guess_digits[$i] eq $guess_digits[$j]) {
60 return $FALSE || !$DISTINCT;
69 # 1) checks that the digits entered are valid
70 # 2) checks the guess against the number to be guessed and prints hints.
75 if (!defined($guess)) {
78 elsif ($guess eq 'q' || $guess eq 'quit') {
81 elsif (!is_correct_format($guess)) {
82 print "Type $DIGITS digits please.\n";
86 my @guess_digits = ();
89 for (my $i = 0; $i < $DIGITS; $i++) {
90 $digit = chop($guess);
91 unshift(@guess_digits, $digit);
94 if (!is_distinct(\@guess_digits)) {
95 print "Type $DIGITS different digits please.\n";
100 for (my $i = 0; $i < $DIGITS; $i++) {
101 if ($guess_digits[$i] eq $digits[$i]) {
106 my $no_match = $TRUE;
108 for (my $j = 0; $j < $DIGITS; $j++) {
109 if ($guess_digits[$i] eq $digits[$j]) {
123 print "For your guess of @guess_digits, I hint $hint.\n";
129 # Reads a line of user input.
138 # Required for a graceful exit when user hits ^C.
146 # Contains various representations of 'Yes' used to parse user input.
153 elsif ($input eq 'Y') {
156 elsif ($input eq 'yes') {
159 elsif ($input eq 'Yes') {
162 elsif ($input eq 'YES') {
170 # Contains various representations of 'No' used to parse user input.
177 elsif ($input eq 'N') {
180 elsif ($input eq 'no') {
183 elsif ($input eq 'No') {
186 elsif ($input eq 'NO') {
194 # Asks player if they would like to play again.
197 my $recursion = shift;
200 print "\nDo you want to play again? Please type a Y for yes or a N for No?\n";
203 print "\nDo you want to play again?\n";
206 $input = read_input();
208 if (affirmative($input)) {
211 elsif (negative($input)) {
219 # Clears screen and prints game title.
224 print "\t\t\t" . '*** DIGITS 1.0.2 ***' . "\n";
225 print "Homepage: http://jxself.org/digits.shtml\n\n";
226 print "Copyright (C) 2013 Jason Self <j\@jxself.org>\n\n";
227 print "Licensed under the GNU AGPL v3 or any later version.\n\n";
229 print "I will think of a number. The object of the game is to guess the number\n";
230 print "in as few tries as possible. Each time you guess I will provide a hint:\n\n";
232 print "For each digit in the correct position I will print an X\n";
233 print "For a correct digit with an incorrect position I will print an O\n";
234 print "For a totally incorrect digit I will print an -\n\n";
236 print "Let's begin. Here are some questions.\nYou can press return to accept the default setting.\n";
240 # Sets the following game state variables by reading command line arguments or
241 # by prompting the player where required:
242 # 1) Length of combination, stored in $DIGITS
243 # 2) Whether of not the digits in the combination are distinct, stored in $DISTINCT
244 # 3) Number of guesses, stored in $MAX_GUESSES
245 # If the player accepts the defaults then the initial assignment of the above
246 # game state variable are used.
253 'digits=i' => \$digits,
254 'distinct=s' => \$distinct,
255 'guesses=i' => \$guesses
258 if (!defined($digits)) {
261 elsif (is_number($digits)) {
268 if (!defined($distinct)) {
271 elsif (affirmative($distinct)) {
274 elsif (negative($distinct)) {
281 if (!defined($guesses)) {
284 elsif (is_number($guesses)) {
285 $MAX_GUESSES = $guesses;
294 # Checks if the input is a number.
298 return ($input =~ m/^\d+$/);
301 # Prompts the player to get number of digits or accept default of 3.
303 print "\nHow long should the combination be? [Default 3, Maximum 8]\n";
304 my $input = read_input();
307 if (is_number($input)) {
308 if ($input > $MAX_DIGITS) {
309 print "Please enter a number less than 8.\n";
318 print "Please enter a number.\n";
325 # Prompts the player about using distinct digits or not. Default is to use
328 print "\nShould each digit in the combination be different from the others? [Default Yes]\n";
329 my $input = read_input();
332 if (affirmative($input)) {
335 elsif (negative($input)) {
339 print "Please enter a Y for yes or a N for No.\n";
346 # Prompts the player to get number of guesses or accept default of unlimited.
347 sub get_max_guesses {
348 print "\nMaximum number of guesses? [Default unlimited]\n";
349 my $input = read_input();
352 if (is_number($input)) {
353 $MAX_GUESSES = $input;
356 print "Please enter a number.\n";
363 # Sets game state for a new game. Setting new game state includes
364 # 1) Setting whether or not the number has been guessed to $FALSE
365 # 2) Setting number of guesses/tries to 0
366 # 3) Setting the number to be guessed
374 while ($i < $DIGITS) {
375 $digit = int(rand(9));
378 my $no_match = $TRUE;
380 for (my $j = 0; $j < $#digits + 1; $j++) {
381 if ($digits[$j] == $digit) {
388 push(@digits, $digit);
393 push(@digits, $digit);
398 print "\nOkay, I've got a number...\n";
401 # The main/starting program for the game.
409 print "\nWhat is your guess? Type 'q' or 'quit' to exit.\n";
410 $guess = read_input();
411 $guessed = check_digits($guess);
414 if ($tries == $MAX_GUESSES) {
416 print "\nYou have not guessed my number in 1 guess.\n";
419 print "\nYou have not guessed my number in $MAX_GUESSES guesses.\n";
426 if ($guessed == $QUIT) {
427 print "\nThe number I had was @digits. Bye!\n";
432 print "Excellent! You guessed it in only 1 try!\n";
434 elsif ($tries < ($DIGITS * 2)) {
435 print "Excellent! You guessed it in only $tries tries!\n";
438 print "You guessed it in $tries tries!\n";