Bulls and Cows


Task

Create a four digit random number from the digits   1   to   9,   without duplication.

The program should:

   ask for guesses to this number
   reject guesses that are malformed
   print the score for the guess


The score is computed as:

 The player wins if the guess is the same as the randomly chosen number, and the program ends.
 A score of one bull is accumulated for each digit in the guess that equals the corresponding digit in the randomly chosen initial number.
 A score of one cow is accumulated for each digit in the guess that also appears in the randomly chosen number, but in the wrong position.


Related tasks

   Bulls and cows/Player
   Guess the number
   Guess the number/With Feedback
   Mastermind


get "libhdr"
 
static $( randstate = ? $)
 
let randdigit() = valof
$(  let x = ?
    $(  randstate := random(randstate)
        x := (randstate >> 7) & 15
    $) repeatuntil 0 < x <= 9
    resultis x
$)
 
let gensecret(s) be
    for i=0 to 3
        s!i := randdigit() repeatuntil valof
        $(  for j=0 to i-1 if s!i = s!j then resultis false
            resultis true
        $)
 
let bulls(secret, guess) = valof
$(  let x = 0
    for i=0 to 3 if secret!i = guess!i then x := x + 1
    resultis x
$)
 
let cows(secret, guess) = valof
$(  let x = 0
    for i=0 to 3
        for j=0 to 3
            unless i=j
                if secret!i = guess!j then x := x + 1
    resultis x
$)
 
let readguess(guess) be
$(  let g, v = ?, true
    writes("Enter a guess, or 0 to quit: ")
    g := readn()
    if g=0 then finish
    for i=3 to 0 by -1
    $(  guess!i := g rem 10
        g := g / 10
    $)
    for i=0 to 2 for j = i+1 to 3
        v := v & guess!i ~= 0 & guess!j ~= 0 & guess!i ~= guess!j  
    if v then return
    writes("Invalid guess.*N")
$) repeat
 
let play(secret) be
$(  let tries, b, c = 0, ?, ?
    let guess = vec 3
    $(  readguess(guess)
        b := bulls(secret, guess)
        c := cows(secret, guess)
        writef("Bulls: %N, cows: %N*N", b, c);
        tries := tries + 1
    $) repeatuntil b = 4
    writef("You win in %N tries.*N", tries)
$)
 
let start() be
$(  let secret = vec 3
    writes("Bulls and cows*N----- --- ----*N")
    writes("Please enter a random seed: ")
    randstate := readn()
    wrch('*N')
    gensecret(secret)
    play(secret)
$)