#!/usr/bin/perl
######################
#
# moo.pl
#
# A cute little game in which the user
# tries to guess a number that the computer picks.
#
# This game is also called Mastermind;
# see http://cs.marlboro.edu/code/javascript/mastermind/mastermind.html
# for javascript version running in a web.
#
# I used a partial version of this as an assignment for a perl class.
# Here's my complete program.
#
# Counting the bulls and the cows can get tricky.
# But that's why it's an exercise, eh?
# And why I gave another (easier) alternative...
#
# Version history
#
#   * 0.1_jm  partial program outline created                         9/15
#   * 0.2_jm  a working (mostly) complete mool.pl                     9/15
#   * 0.3_jm  more debugging reports, fixed some bugs.                9/22
#
# Jim Mahoney
#
######################
use strict;
my $VERSION = "0.3_jm";
my $DEBUG   = 1;             # 1 => print debugging diagnostics; 0 => don't.

my $number_of_digits = 4;
my $max_digit        = 6;

print "Let's play a game of *** MOO *** (version $VERSION). \n";
print "Each guess should be $number_of_digits digits,";
print " each from 1 to $max_digit.\n\n";

# Computer picks 4 randoms from 1..6 and puts them in this array.
my @answer = ();
push @answer, 1+int($max_digit*rand) for 1 .. $number_of_digits;
print "   DEBUG : answer is @answer \n" if $DEBUG;

### Alternative syntax possibilities for filling in @answer.
#
#   push @answer, int(6*rand) for 1..4;    
#   # ... but remembering what "6", "4", "1" represent may be tricky.
#
# # or with a more typical "for (){}" loop
#
#   for (1..$number_of_digits){
#     push @answer, int($max_digit * rand());
#   }
#
# # or the C'ish
#
#   for (my $index=0;  $index < $number_of_digits ; $index = $index + 1){
#     $answer[$index] = int($number_of_digits*rand);
#   }
#

my @guess;
my $guess_number   = 0;
my $still_guessing = 1;
while ( $still_guessing ){
  $guess_number = $guess_number +1;

  my $have_legal_answer = 0;
  my $line;
  while (not $have_legal_answer){
    # Get user guess (4 digits from 1..6)
    print " $guess_number : ";
    chomp($line = <>);              # Read in a line of input; remove newline.
    @guess = split //, $line;       # Split characters into an array.

    # Debugging:
    print "   DEBUG : guess is @guess \n" if $DEBUG;

    if ($guess[0] eq 'q'){
      print " Are you sure you want to quit? [y] ";
      chomp($line = <>);
      if ( $line eq '' or $line eq 'y'){
        print " Bye...\n";
        exit;
      }
    }

    # Check to make sure the guess is legal.
    $have_legal_answer = 1;    # assume it is unless we find it isn't.
    if ( scalar(@guess) != $number_of_digits ){
      $have_legal_answer=0;  # incorrect number of digits.
      print "  Oops - your guess didn't have the correct number of digits.\n";
    }
    else {
      for my $index (0 .. $number_of_digits-1){
        if ( $guess[$index] < 1 or $guess[$index] > $max_digit ){
          $have_legal_answer=0;  # It isn't.
          print "  Oops - '$guess[$index]' at index $index is out of range.\n";
        }
      }
    }
  }

  my ($bulls, $cows) = (0,0);
  # Count number of 
  #   bulls (a digit in @guess matches one in @numbers in same place), and
  #   cows  (a digit in @guess matches one anywhere in @numbers).
  # You may not count any digit in either @guess or @numbers more than once.
  # How do we keep track of whether we've used a digit from a guess
  # or an answer already?  One way is to use boolean arrays:
  my @guess_used  = (0) x $number_of_digits;    # 1 if we've used that digit.
  my @answer_used = (0) x $number_of_digits;    # ditto.

  # First count the bulls; 
  # one loop over the indeces, remembering when we use a guess or answer.
  for my $index (0 .. $number_of_digits-1){
    if ($DEBUG){
      print "   DEBUG : bull i, guess[i]==answer[i] (gu[i],au[i]) is";
      print " $index, $guess[$index]==$answer[$index]";
      print " ($guess_used[$index],$answer_used[$index])\n";
    }
    if ( $answer[$index] == $guess[$index] ){
      $bulls = $bulls + 1;
      print "   DEBUG : *bull match* ; bulls = $bulls \n" if $DEBUG;
      $guess_used[$index]  = 1;  # remember that we've used this guess digit.
      $answer_used[$index] = 1;  # remember that we've used this answer digit.
    }
  }

  # Then we count the cows.
  # This takes a pair nested loops over both indeces,
  # only looking at the cases when the indeces are different,
  # and only counting a "cow" if those indeces haven't been counted already.
  for my $guess_index (0 .. $number_of_digits-1){
    for my $answer_index (0 .. $number_of_digits-1){
      next if $guess_index == $answer_index;       # skip if indeces are same.
      if ($DEBUG){
        print "   DEBUG : cow i,j, guess[i]==answer[j] (gu[i],au[j]) is";
        print " $guess_index,$answer_index,";
        print " $guess[$guess_index]==$answer[$answer_index]";
        print " ($guess_used[$guess_index],$answer_used[$answer_index])\n";
      }
      if (      $answer[$answer_index] == $guess[$guess_index] 
                and  $guess_used[$guess_index]   == 0
                and  $answer_used[$answer_index] == 0 ){
        $cows = $cows + 1;
        print "   DEBUG : *cow match* ; cows = $cows \n" if $DEBUG;
        $guess_used[$guess_index]   = 1;   # remember that this guess is used.
        $answer_used[$answer_index] = 1;   # remember that this answer is used.
      }
    }
  }

  # Tell the user the result.
  my ($s, $b) = ("s", "s");
  $b = "" if $bulls == 1;    # singular, change "bulls" to "bull".
  $s = "" if $cows  == 1;    # singular, change "cows" to  "cow".
  print "           is worth $bulls bull$b and $cows cow$s.\n";

  # If we have a winner, say so, and stop playing.
  if ($bulls == $number_of_digits){
    print "\n You win! \n";
    $still_guessing = 0;
  }

}
