Task

Write a player of the Bulls and Cows game, rather than a scorer. The player should give intermediate answers that respect the scores to previous attempts.

One method is to generate a list of all possible numbers that could be the answer, then to prune the list by keeping only those numbers that would give an equivalent score to how your last guess was scored. Your next guess can be any number from the pruned list.

Either you guess correctly or run out of numbers to guess, which indicates a problem with the scoring.



Related tasks

   Bulls and cows
   Guess the number
   Guess the number/With Feedback (Player)


#!/usr/local/bin/shale
 
maths library
file library
string library
 
lista var
listb var
firstTimeThrough var
guess var
guess0 var
guess1 var
guess2 var
guess3 var
bulls var
cows var
 
init dup var {
  count a:: var
  count b:: var
} =
 
randomDigit dup var {
  random maths::() 18 >> 9 % 1 +
} =
 
makeGuess dup var {
  firstTimeThrough {
    guess0 randomDigit() =
    guess1 randomDigit() =
    { guess1 guess0 == } { guess1 randomDigit() = } while
    guess2 randomDigit() =
    { guess2 guess0 == guess2 guess1 == or } { guess2 randomDigit() = } while
    guess3 randomDigit() =
    { guess3 guess0 == guess3 guess1 == guess3 guess2 == or or } { guess3 randomDigit() = } while
    guess guess3 1000 * guess2 100 * guess1 10 * guess0 + + + =
  } {
    i var
 
    i random maths::() count lista->:: % =
    guess i.value lista->:: value =
    guess0 guess 10 % =
    guess1 guess 10 / 10 % =
    guess2 guess 100 / 10 % =
    guess3 guess 1000 / =
  } if
} =
 
getAnswer dup var {
  stdin file:: fgets file::() {
    atoi string::()
  } {
    0 exit
  } if
} =
 
getScore dup var {
  haveBulls dup var false =
  haveCows dup var false =
  ans var
 
  { haveBulls not } {
    "Bulls: " print
    ans getAnswer() =
    ans 0 < ans 4 > and {
      "Please try again" println
    } {
      bulls ans =
      haveBulls true =
    } if
  } while
 
  { haveCows not } {
    "Cows: " print
    ans getAnswer() =
    ans 0 < ans 4 > and {
      "Please try again" println
    } {
      cows ans =
      haveCows true =
    } if
  } while
} =
 
check dup var {
  d0 dup var swap =   // units
  d1 dup var swap =
  d2 dup var swap =
  d3 dup var swap =   // thousands
  b dup var 0 =
  c dup var 0 =
 
  d0 guess0 == { b++ } { d0 guess1 == { d0 guess2 == { d0 guess3 == } or } or { c++ } ifthen } if
  d1 guess1 == { b++ } { d1 guess0 == { d1 guess2 == { d1 guess3 == } or } or { c++ } ifthen } if
  d2 guess2 == { b++ } { d2 guess0 == { d2 guess1 == { d2 guess3 == } or } or { c++ } ifthen } if
  d3 guess3 == { b++ } { d3 guess0 == { d3 guess1 == { d3 guess2 == } or } or { c++ } ifthen } if
 
  b bulls >= c cows >= and
} =
 
add dup var {
  n dup var swap =
 
  n guess != {    // never put our own guess back in the list.
    i var
 
    i count listb->:: =
    i.value listb->:: defined not {
      i.value listb->:: var
    } ifthen
 
    i.value listb->:: n =
    count listb->::++
  } ifthen
} =
 
filterList dup var {
  firstTimeThrough {
    a var
    b var
    c var
    d var
 
    a 1 =
    { a 10 < } {
      b 1 =
      { b 10 < } {
        b a != {
          c 1 =
          { c 10 < } {
            c a != c b != and {
              d 1 =
              { d 10 < } {
                d a != { d b != d c != and } and {
                  a b c d check() {
                    a 1000 * b 100 * c 10 * d + + + add()
                  } ifthen
                } ifthen
                d++
              } while
            } ifthen
            c++
          } while
        } ifthen
        b++
      } while
      a++
    } while
  } {
    i var
    j var
    n var
 
    count listb->:: 0 =
    i 0 =
    { i count lista->:: < } {
      n i.value lista->:: =
      n 1000 / n 100 / 10 % n 10 / 10 % n 10 % check() {
        n.value add()
      } ifthen
      i++
    } while
  } if
} =
 
solve dup var {
  t var
  f var
  n var
 
  lista a &=
  listb b &=
  firstTimeThrough true =
  count a:: 0 =
  count b:: 0 =
 
  n 1 =
  f 1 =
  { f } {
    makeGuess()
    guess0 guess1 guess2 guess3 n "\nGuess %d: %d %d %d %d\n" printf
    getScore()
    bulls 4 == {
      "WooHoo, I won!" println
      break
    } ifthen
    filterList()
    f count listb->:: =
 
    t lista =
    lista listb =
    listb t =
    firstTimeThrough false =
    n++
  } while
 
  count lista->:: 0 == {
    "I've run out of numbers to choose from." println
  } ifthen
} =
 
init()
{ true } {
  solve()
} while