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)


 
clear screen
 
guesses = 0
 
void = ran()
 
while(len(secret$) < 4)    //    zero not allowed
    n$ = chr$(int(ran(1) * 9) + 49)
    if not(instr(secret$, n$)) secret$ = secret$ + n$
wend
 
print " Secretly, my opponent just chose a number. But she didn't tell anyone!\n\t\t\t\t", secret$, "."
print "     I can however be given a score for my guesses."
 
for i = 1234 to 9876
    if check(str$(i)) = 0 then
    	available$ = available$ + " " + str$(i)
    	k = k +1
    end if
next i
 
available$ = trim$(available$)  //   remove the surplus, leading space
 
while(true)
    print
    print "Currently holding ", k, " possible numbers. "
 
    guess$ =word$(available$, 1 + int(k * ran(1)), " ")
    print "Computer guessed ", guess$, " & got ";
 
    bulls = 0
    cows = 0
    guesses = guesses + 1
 
    r$ = score$(guess$, secret$)
 
    bulls = val(word$(r$, 1, ","))
    cows  = val(word$(r$, 2, ","))
 
    print bulls, " bull(s), and ", cows, " cow(s)."
 
    if guess$ = secret$ then
        print "\nComputer won after ", guesses, " guesses!";
        print " That took ", right$(time$, 1), " seconds. ENDED!"
        break
    end if
    kk = 0
    new$ = ""
 
    for j = 1 to k
        bullsT = 0
        cowsT = 0
 
        possible$ = word$(available$, j, " ")
 
        r$ = score$(guess$, possible$)
 
        bullsT = val(word$(r$, 1, ","))
        cowsT = val(word$(r$, 2, ","))
 
        if (bullsT = bulls) and ( cowsT = cows)  then
            new$ = new$ + " " + possible$    //    keep those with same score
            kk = kk + 1
        end if
    next j
 
    available$ = trim$(new$)
    k = kk
 
wend
 
sub score$(a$, b$)    //   return as a csv string the number of bulls & cows.
    local i, c$, bulls, cows
 
    bulls = 0 : cows = 0
    for i = 1 to 4
        c$ = mid$(a$, i, 1)
        if mid$(b$, i, 1) = c$ then
            bulls = bulls + 1
        else
            if (instr(b$, c$) <> 0) and (instr(b$, c$) <> i) cows = cows + 1
        end if
    next i
    return str$(bulls) + "," + str$(cows)
end sub
 
sub check(i$)
    local t, i, j
 
    t = 0    //    zero flags available: 1 means not available
    for i = 1 to 3
        for j = i + 1 to 4
            if mid$(i$, i, 1) = mid$(i$, j, 1) t = 1
        next j
    next i
    if instr(i$, "0") t = 1
    return t
end sub
 
sub word$(l$, i, d$)
    local c$(1), n
 
    n = token(l$, c$(), d$)
    return c$(i)
end sub