Bulls and cows
You are encouraged to solve this task according to the task description, using any language you may know.
This is an old game played with pencil and paper that was later implemented on computer.
The task is for the program to 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, then 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.
Ada
<lang Ada> with Ada.Text_IO; use Ada.Text_IO; with Ada.Numerics.Discrete_Random;
procedure Bulls_And_Cows is
package Random_Natural is new Ada.Numerics.Discrete_Random (Natural); Number : String (1..4);
begin
declare -- Generation of number use Random_Natural; Digit : String := "123456789"; Size : Positive := 9; Dice : Generator; Position : Natural; begin Reset (Dice); for I in Number'Range loop Position := Random (Dice) mod Size + 1; Number (I) := Digit (Position); Digit (Position..Size - 1) := Digit (Position + 1..Size); Size := Size - 1; end loop; end; loop -- Guessing loop Put ("Enter four digits:"); declare Guess : String := Get_Line; Bulls : Natural := 0; Cows : Natural := 0; begin if Guess'Length /= 4 then raise Data_Error; end if; for I in Guess'Range loop for J in Number'Range loop if Guess (I) not in '1'..'9' or else (I < J and then Guess (I) = Guess (J)) then raise Data_Error; end if; if Number (I) = Guess (J) then if I = J then Bulls := Bulls + 1; else Cows := Cows + 1; end if; end if; end loop; end loop; exit when Bulls = 4; Put_Line (Integer'Image (Bulls) & " bulls," & Integer'Image (Cows) & " cows"); exception when Data_Error => Put_Line ("You should enter four different digits 1..9"); end; end loop;
end Bulls_And_Cows; </lang>
ALGOL 68
<lang algol>STRING digits = "123456789";
[4]CHAR chosen; STRING available := digits; FOR i TO UPB chosen DO
INT c = ENTIER(random*UPB available)+1; chosen[i] := available[c]; available := available[:c-1]+available[c+1:]
OD;
COMMENT print((chosen, new line)); # Debug # END COMMENT
OP D = (INT d)STRING: whole(d,0); # for formatting an integer #
print (("I have chosen a number from ",D UPB chosen," unique digits from 1 to 9 arranged in a random order.", new line, "You need to input a ",D UPB chosen," digit, unique digit number as a guess at what I have chosen", new line));
PRIO WITHIN = 5, NOTWITHIN = 5; OP WITHIN = (CHAR c, []CHAR s)BOOL: char in string(c,LOC INT,s); OP NOTWITHIN = (CHAR c, []CHAR s)BOOL: NOT ( c WITHIN s );
INT guesses := 0, bulls, cows; WHILE
STRING guess; guesses +:= 1; WHILE # get a good guess # print((new line,"Next guess [",D guesses,"]: ")); read((guess, new line)); IF UPB guess NE UPB chosen THEN FALSE ELSE BOOL ok; FOR i TO UPB guess WHILE ok := guess[i] WITHIN digits AND guess[i] NOTWITHIN guess[i+1:] DO SKIP OD; NOT ok FI DO print(("Problem, try again. You need to enter ",D UPB chosen," unique digits from 1 to 9", new line)) OD;
- WHILE #
guess NE chosen
DO
bulls := cows := 0; FOR i TO UPB chosen DO IF guess[i] = chosen[i] THEN bulls +:= 1 ELIF guess[i] WITHIN chosen THEN cows +:= 1 FI OD; print((" ",D bulls," Bulls",new line," ",D cows," Cows"));
OD; print((new line, "Congratulations you guessed correctly in ",D guesses," attempts.",new line))</lang>
AutoHotkey
<lang autohotkey>While StrLen(Code) < 4 {
Random, num, 1, 9 If !InStr(Code, num) Code .= num
} Gui, Add, Edit, vGuess, Enter a guess... Gui, Add, Button, wp Default, Submit Gui, Add, ListBox, ym r8 vHistory Gui, Show Return
ButtonSubmit:
Gui, Submit, NoHide If StrLen(Guess) != 4 Return If Guess is not digit Return bulls:=0, cows:=0 Loop, 4 If (SubStr(Guess, A_Index, 1) = SubStr(Code, A_Index, 1)) bulls++ Else If InStr(Code, SubStr(Guess, A_Index, 1)) cows++ GuiControl,, History, % Guess ": " bulls " Bulls " cows " Cows"
Return
GuiClose:
ExitApp
</lang>
BASIC
<lang freebasic> DIM secret AS String DIM guess AS String DIM c AS String DIM AS Integer bulls, cows, guesses, i
RANDOMIZE DO WHILE LEN(secret) < 4
c = CHR$(INT(RND*10) + 48) IF INSTR(secret, c) = 0 THEN secret = secret+c
LOOP
guesses = 0 DO
INPUT "Guess a 4-digit number with no duplicate digits: "; guess IF LEN(guess) = 0 THEN EXIT DO
IF LEN(guess) <> 4 OR VAL(guess) = 0 THEN PRINT "** You should enter 4 numeric digits!"
CONTINUE DO
END IF
bulls=0: cows=0: guesses = guesses+1 FOR i = 1 TO 4 c = MID$(secret, i, 1)
IF MID$(guess, i, 1) = c THEN bulls = bulls+1 ELSEIF INSTR(guess, c) THEN cows = cows+1 END IF
NEXT i PRINT bulls; " bulls, "; cows; " cows"
IF guess = secret THEN PRINT "You won after "; guesses; " guesses!"
EXIT DO
END IF
LOOP </lang>
C
<lang c>#include <stdio.h>
- include <stdarg.h>
- include <stdlib.h>
- include <stdbool.h>
- include <curses.h>
- include <string.h>
- define MAX_NUM_TRIES 72
- define LINE_BEGIN 7
- define LAST_LINE 18
int yp=LINE_BEGIN, xp=0;
char number[5]; char guess[5];
- define MAX_STR 256
void mvaddstrf(int y, int x, const char *fmt, ...) {
va_list args; char buf[MAX_STR]; va_start(args, fmt); vsprintf(buf, fmt, args); move(y, x); clrtoeol(); addstr(buf); va_end(args);
}
void ask_for_a_number() {
int i=0; char symbols[] = "123456789";
move(5,0); clrtoeol(); addstr("Enter four digits: "); while(i<4) { int c = getch(); if ( (c >= '1') && (c <= '9') && (symbols[c-'1']!=0) ) { addch(c); symbols[c-'1'] = 0; guess[i++] = c; } }
}
void choose_the_number() {
int i=0, j; char symbols[] = "123456789";
while(i<4) { j = rand() % 9; if ( symbols[j] != 0 ) { number[i++] = symbols[j]; symbols[j] = 0; } }
}</lang>
The following function contains the code to check how many bulls and cows there are.
<lang c>bool take_it_or_not() {
int i; int cows=0, bulls=0;
for(i=0; i < 4; i++) { if ( number[i] == guess[i] ) { bulls++; } else if ( strchr(number, guess[i]) != NULL ) { cows++; } } move(yp, xp); addstr(guess); addch(' '); if ( bulls == 4 ) { yp++; return true; } if ( (cows==0) && (bulls==0) ) addch('-'); while( cows-- > 0 ) addstr("O"); while( bulls-- > 0 ) addstr("X"); yp++; if ( yp > LAST_LINE ) { yp = LINE_BEGIN; xp += 10; } return false;
}
bool ask_play_again() {
int i;
while(yp-- >= LINE_BEGIN) { move(yp, 0); clrtoeol(); } yp = LINE_BEGIN; xp = 0;
move(21,0); clrtoeol(); addstr("Do you want to play again? [y/n]"); while(true) { int a = getch(); switch(a) { case 'y': case 'Y': return true; case 'n': case 'N': return false; } }
}
int main()
{
bool bingo, again; int tries = 0;
initscr(); cbreak(); noecho(); clear();
number[4] = guess[4] = 0;
mvaddstr(0,0, "I choose a number made of 4 digits (from 1 to 9) without repetitions\n" "You enter a number of 4 digits, and I say you how many of them are\n" "in my secret number but in wrong position (cows or O), and how many\n" "are in the right position (bulls or X)"); do { move(20,0); clrtoeol(); move(21, 0); clrtoeol(); srand(time(NULL)); choose_the_number(); do { ask_for_a_number(); bingo = take_it_or_not(); tries++; } while(!bingo && (tries < MAX_NUM_TRIES)); if ( bingo ) mvaddstrf(20, 0, "You guessed %s correctly in %d attempts!", number, tries); else mvaddstrf(20,0, "Sorry, you had only %d tries...; the number was %s",
MAX_NUM_TRIES, number);
again = ask_play_again(); tries = 0; } while(again); nocbreak(); echo(); endwin(); return EXIT_SUCCESS;
}</lang>
C++
<lang cpp>
- include <iostream>
- include <string>
- include <algorithm>
- include <cstdlib>
bool contains_duplicates(std::string s) {
std::sort(s.begin(), s.end()); return std::adjacent_find(s.begin(), s.end()) != s.end();
}
void game() {
typedef std::string::size_type index;
std::string symbols = "0123456789"; int const selection_length = 4;
std::random_shuffle(symbols.begin(), symbols.end()); std::string selection = symbols.substr(0, selection_length); std::string guess; while (std::cout << "Your guess? ", std::getline(std::cin, guess)) { if (guess.length() != selection_length || guess.find_first_not_of(symbols) != std::string::npos || contains_duplicates(s)) { std::cout << guess << " is not a valid guess!"; continue; }
int bulls = 0; int cows = 0; for (index i = 0; i != selection_length; ++i) { index pos = selection.find(guess[i]); if (pos == i) ++bulls; else if (pos != std::string::npos) ++cows; } std::cout << bulls << " bulls, " << cows << " cows.\n"; if (bulls == selection_length) { std::cout << "Congratulations! You have won!\n"; return: } } std::cerr << "Oops! Something went wrong with input, or you've entered end-of-file!\nExiting ...\n"; std::exit(EXIT_FAILURE);
}
int main() {
std::cout << "Welcome to bulls and cows!\nDo you want to play? "; std::string answer; while (true) { while (true) { if (!std::getline(std::cin, answer)) { std::cout << "I can't get an answer. Exiting.\n"; return EXIT_FAILURE; } if (answer == "yes" || answer == "Yes" || answer == "y" || answer == "Y") break; if (answer == "no" || answer == "No" || answer == "n" || answer == "N") { std::cout << "Ok. Goodbye.\n"; return EXIT_SUCCESS; } std::cout << "Please answer yes or no: "; } game(); std::cout << "Another game? "; }
} </lang>
Common Lisp
<lang lisp>(defun get-number ()
(do ((digits '())) ((>= (length digits) 4) digits) (pushnew (1+ (random 9)) digits)))
(defun compute-score (guess number)
(let ((cows 0) (bulls 0)) (map nil (lambda (guess-digit number-digit) (cond ((= guess-digit number-digit) (incf bulls)) ((member guess-digit number) (incf cows)))) guess number) (values cows bulls)))
(defun number->guess (number)
(when (integerp number) (do ((digits '())) ((zerop number) digits) (multiple-value-bind (quotient remainder) (floor number 10) (push remainder digits) (setf number quotient)))))
(defun valid-guess-p (guess)
(and (= 4 (length guess)) (every (lambda (digit) (<= 1 digit 9)) guess) (equal guess (remove-duplicates guess))))
(defun play-game (&optional (stream *query-io*))
(do ((number (get-number)) (cows 0) (bulls 0)) ((= 4 bulls)) (format stream "~&Guess a 4-digit number: ") (let ((guess (number->guess (read stream)))) (cond ((not (valid-guess-p guess)) (format stream "~&Malformed guess.")) (t (setf (values cows bulls) (compute-score guess number)) (if (= 4 bulls) (format stream "~&Correct, you win!") (format stream "~&Score: ~a cows, ~a bulls." cows bulls)))))))</lang>
E
Note: This example was deliberately written in an abstracted style, separating out the algorithms, game logic, and UI.
<lang e>def Digit := 1..9 def Number := Tuple[Digit,Digit,Digit,Digit]
/** Choose a random number to be guessed. */ def pick4(entropy) {
def digits := [1,2,3,4,5,6,7,8,9].diverge() # Partial Fisher-Yates shuffle for i in 0..!4 { def other := entropy.nextInt(digits.size() - i) + i def t := digits[other] digits[other] := digits[i] digits[i] := t } return digits(0, 4)
}
/** Compute the score of a guess. */ def scoreGuess(actual :Number, guess :Number) {
var bulls := 0 var cows := 0 for i => digit in guess { if (digit == actual[i]) { bulls += 1 } else if (actual.indexOf1(digit) != -1) { cows += 1 } } return [bulls, cows]
}
/** Parse a guess string into a list of digits (Number). */ def parseGuess(guessString, fail) :Number {
if (guessString.size() != 4) { return fail(`I need four digits, not ${guessString.size()} digits.`) } else { var digits := [] for c in guessString { if (('1'..'9')(c)) { digits with= c - '0' } else { return fail(`I need a digit from 1 to 9, not "$c".`) } } return digits }
}
/** The game loop: asking for guesses and reporting scores and win conditions.
The return value is null or a broken reference if there was a problem. */
def bullsAndCows(askUserForGuess, tellUser, entropy) {
def actual := pick4(entropy) def gameTurn() { return when (def guessString := askUserForGuess <- ()) -> { escape tellAndContinue {
def guess := parseGuess(guessString, tellAndContinue) def [bulls, cows] := scoreGuess(actual, guess) if (bulls == 4) { tellUser <- (`You got it! The number is $actual!`) null } else { tellAndContinue(`Your score for $guessString is $bulls bulls and $cows cows.`) } } catch message { # The parser or scorer has something to say, and the game continues afterward when (tellUser <- (message)) -> { gameTurn() } } } catch p { # Unexpected problem of some sort tellUser <- ("Sorry, game crashed.") throw(p) } } return gameTurn()
}</lang>
REPL user interface
def replBullsAndCows() { when ( bullsAndCows(fn { def [guess, env] := e`def guess; guess`.evalToPair(interp.getTopScope().nestOuter()) interp.setTopScope(env) println("Please type “ bind guess := \"your guess here\" ”.") guess }, println, entropy) ) -> {} catch p { println(`$p${p.eStack()}`) } }
Graphical user interface
(Java Swing)
<lang e>def guiBullsAndCows() {
var lastGuess := "" def op := <unsafe:javax.swing.makeJOptionPane> return bullsAndCows(fn { lastGuess := op.showInputDialog(null, "Enter your guess:", lastGuess) if (lastGuess == null) { # canceled, so just fail to return an answer and let the game logic get GCed Ref.promise()[0] } else { lastGuess } }, fn msg { op.showMessageDialog(null, msg) }, entropy)
}</lang>
Fan
<lang Fan>
- Bulls and cows. A game pre-dating, and similar to, Mastermind.
class BullsAndCows {
Void main() { digits := [1,2,3,4,5,6,7,8,9] size := 4 chosen := [,] size.times { chosen.add(digits.removeAt(Int.random(0..<digits.size))) }
echo("I've chosen $size unique digits from 1 to 9 at random. Try to guess my number!") guesses := 0 while (true) // game loop { guesses += 1 guess := Int[,] while (true) // input loop { // get a good guess Sys.out.print("\nNext guess [$guesses]: ") Sys.out.flush inString := Sys.in.readLine?.trim ?: "" inString.each |ch| { if (ch >= '1' && ch <= '9' && !guess.contains(ch)) guess.add(ch-'0') } if (guess.size == 4) break // input loop echo("Oops, try again. You need to enter $size unique digits from 1 to 9") } if (guess.all |v, i->Bool| { return v == chosen[i] }) { echo("\nCongratulations! You guessed correctly in $guesses guesses") break // game loop } bulls := 0 cows := 0 (0 ..< size).each |i| { if (guess[i] == chosen[i]) bulls += 1 else if (chosen.contains(guess[i])) cows += 1 } echo("\n $bulls Bulls\n $cows Cows") } }
} </lang>
Forth
<lang forth> include random.fs
create hidden 4 allot
- ok? ( str -- ? )
dup 4 <> if 2drop false exit then 1 9 lshift 1- -rot bounds do i c@ '1 - dup 0 9 within 0= if 2drop false leave then 1 swap lshift over and dup 0= if nip leave then xor loop 0<> ;
- init
begin hidden 4 bounds do 9 random '1 + i c! loop hidden 4 ok? until ;
- check? ( addr -- solved? )
0 4 0 do over i + c@ 4 0 do dup hidden i + c@ = if swap i j = if 8 else 1 then + swap then loop drop loop nip 8 /mod tuck . ." bulls, " . ." cows" 4 = ;
- guess: ( "1234" -- )
bl parse 2dup ok? 0= if 2drop ." Bad guess! (4 unique digits, 1-9)" exit then drop check? if cr ." You guessed it!" then ;
</lang>
init ok guess: 1234 1 bulls, 0 cows ok guess: 1567 1 bulls, 1 cows ok guess: 1895 2 bulls, 1 cows ok guess: 1879 4 bulls, 0 cows You guessed it! ok
Fortran
<lang fortran>module bac
implicit none
contains
subroutine Gennum(n) integer, intent(out) :: n(4) integer :: i, j real :: r call random_number(r) n(1) = int(r * 9.0) + 1 i = 2
outer: do while (i <= 4)
call random_number(r) n(i) = int(r * 9.0) + 1
inner: do j = i-1 , 1, -1
if (n(j) == n(i)) cycle outer end do inner i = i + 1 end do outer end subroutine Gennum
subroutine Score(n, guess, b, c) character(*), intent(in) :: guess integer, intent(in) :: n(0:3) integer, intent(out) :: b, c integer :: digit, i, j, ind b = 0; c = 0 do i = 1, 4 read(guess(i:i), "(i1)") digit if (digit == n(i-1)) then b = b + 1 else do j = i, i+2 ind = mod(j, 4) if (digit == n(ind)) then c = c + 1 exit end if end do end if end do
end subroutine Score
end module bac
program Bulls_and_Cows
use bac implicit none integer :: n(4) integer :: bulls=0, cows=0, tries=0 character(4) :: guess
call random_seed call Gennum(n) write(*,*) "I have selected a number made up of 4 digits (1-9) without repetitions." write(*,*) "You attempt to guess this number." write(*,*) "Every digit in your guess that is in the correct position scores 1 Bull" write(*,*) "Every digit in your guess that is in an incorrect position scores 1 Cow" write(*,*)
do while (bulls /= 4) write(*,*) "Enter a 4 digit number" read*, guess if (verify(guess, "123456789") /= 0) then write(*,*) "That is an invalid entry. Please try again." cycle end if tries = tries + 1 call Score (n, guess, bulls, cows) write(*, "(a, i1, a, i1, a)") "You scored ", bulls, " bulls and ", cows, " cows" write(*,*) end do
write(*,"(a,i0,a)") "Congratulations! You correctly guessed the correct number in ", tries, " attempts"
end program Bulls_and_Cows</lang>
J
<lang J>require 'misc'
plural=: conjunction define
(":m),' ',n,'s'#~1~:m
)
bullcow=:monad define
number=. 1+4?9 guess=._ while.-.guess-:number do. guess=.0 "."0 prompt 'Guess my number: ' if. (4~:#guess)+.(4~:#~.guess)+.0 e.guess e.1+i.9 do. if.0=#guess do. smoutput 'Giving up.' return. end. smoutput 'Guesses must be four different non-zero digits' continue. end. bulls=. +/guess=number cows=. (+/guess e.number)-bulls smoutput bulls plural 'bull',' and ',cows plural 'cow','.' end. smoutput 'you win'
)</lang>
Java
<lang java5>import java.util.InputMismatchException; import java.util.Random; import java.util.Scanner;
public class BullsAndCows{ public static void main(String[] args){ Random gen= new Random(); int target= 0; while(hasDupes(target= (gen.nextInt(9000) + 1000))); String targetStr = target +""; boolean guessed = false; Scanner input = new Scanner(System.in); int guesses = 0; do{ int bulls = 0; int cows = 0; System.out.print("Guess a 4-digit number with no duplicate digits: "); int guess; try{ guess = input.nextInt(); if(hasDupes(guess) || guess < 1000) continue; }catch(InputMismatchException e){ continue; } guesses++; String guessStr = guess + ""; for(int i= 0;i < 4;i++){ if(guessStr.charAt(i) == targetStr.charAt(i)){ bulls++; }else if(targetStr.contains(guessStr.charAt(i)+"")){ cows++; } } if(bulls == 4){ guessed = true; }else{ System.out.println(cows+" Cows and "+bulls+" Bulls."); } }while(!guessed); System.out.println("You won after "+guesses+" guesses!"); }
public static boolean hasDupes(int num){ boolean[] digs = new boolean[10]; while(num > 0){ if(digs[num%10]) return true; digs[num%10] = true; num/= 10; } return false; } }</lang> Output:
Guess a 4-digit number with no duplicate digits: 5834 2 Cows and 0 Bulls. Guess a 4-digit number with no duplicate digits: 1234 1 Cows and 0 Bulls. Guess a 4-digit number with no duplicate digits: 4321 1 Cows and 0 Bulls. Guess a 4-digit number with no duplicate digits: 3421 0 Cows and 1 Bulls. Guess a 4-digit number with no duplicate digits: 8412 0 Cows and 0 Bulls. Guess a 4-digit number with no duplicate digits: 3560 1 Cows and 1 Bulls. Guess a 4-digit number with no duplicate digits: 3650 0 Cows and 2 Bulls. Guess a 4-digit number with no duplicate digits: 3759 2 Cows and 2 Bulls. Guess a 4-digit number with no duplicate digits: 3975 2 Cows and 2 Bulls. Guess a 4-digit number with no duplicate digits: 3957 You won after 10 guesses!
OCaml
<lang ocaml>let rec input() =
let s = read_line () in try if String.length s <> 4 then raise Exit; String.iter (function | '1'..'9' -> () | _ -> raise Exit ) s; let t = [| s.[0]; s.[1]; s.[2]; s.[3] |] in let _ = Array.fold_left (* reject entry with duplication *) (fun ac b -> if List.mem b ac then raise Exit; (b::ac)) [] t in Array.map (fun c -> int_of_string (String.make 1 c)) t with Exit -> prerr_endline "That is an invalid entry. Please try again."; input()
let print_score g t =
let bull = ref 0 in for i = 0 to 3 do if g.(i) = t.(i) then incr bull done; let cow = ref 0 in for i = 0 to 3 do for j = 0 to 3 do if g.(i) = t.(j) then incr cow done; done; cow := !cow - !bull; Printf.printf "%d bulls, %d cows\n%!" !bull !cow
let () =
Random.self_init(); let rec mkgoal acc = function 4 -> acc | i -> let n = succ(Random.int 9) in if List.mem n acc then mkgoal acc i else mkgoal (n::acc) (succ i) in let g = mkgoal [] 0 in let g = Array.of_list g in let found = ref false in while not !found do let t = input() in if t = g then found := true else print_score g t done; print_endline "Congratulations you guessed correctly";
</lang>
Perl
<lang perl>use strict; use Data::Random qw(rand_set);
my $size = 4; my $chosen = join("", rand_set( set => ["1".."9"], size => $size));
print "I've chosen a number from $size unique digits from 1 to 9; you need to input $size unique digits to guess my number\n";
my $guesses = 0; my $guess; while(1) {
$guesses++; while(1) { print "\nNext guess [$guesses]: "; $guess = <STDIN>; chomp $guess; if ( !checkguess($guess) ) {
print "$size digits, no repetition, no 0... retry\n";
} else { last; } } if ( $guess eq $chosen ) {
print "You did it in $guesses attempts!\n"; last;
} else {
my $bulls=0; my $cows=0; for my $i (0 .. $size-1) { if ( substr($guess, $i, 1) eq substr($chosen, $i, 1) ) { $bulls++; } elsif ( index($chosen, substr($guess, $i, 1)) >= 0 ) { $cows++; } } print "$cows cows, $bulls bulls\n";
}
}
sub checkguess($) {
my $g = shift; my %h = (); for my $k ( split(//, $g) ) {
return 0 if exists $h{$k}; $h{$k} = 1;
} return ( $g =~ /^[1-9]{4}$/ );
}</lang>
Python
<lang python>
Bulls and cows. A game pre-dating, and similar to, Mastermind.
import random
digits = '123456789' size = 4 chosen = .join(random.sample(digits,size))
- print chosen # Debug
print I have chosen a number from %s unique digits from 1 to 9 arranged in a random order. You need to input a %i digit, unique digit number as a guess at what I have chosen % (size, size) guesses = 0 while True:
guesses += 1 while True: # get a good guess guess = raw_input('\nNext guess [%i]: ' % guesses).strip() if len(guess) == size and \ all(char in digits for char in guess) \ and len(set(guess)) == size: break print "Problem, try again. You need to enter %i unique digits from 1 to 9" % size if guess == chosen: print '\nCongratulations you guessed correctly in',guesses,'attempts' break bulls = cows = 0 for i in range(size): if guess[i] == chosen[i]: bulls += 1 elif guess[i] in chosen: cows += 1 print ' %i Bulls\n %i Cows' % (bulls, cows)</lang>
Sample output:
I have chosen a number from 4 unique digits from 1 to 9 arranged in a random order. You need to input a 4 digit, unique digit number as a guess at what I have chosen Next guess [1]: 79 Problem, try again. You need to enter 4 unique digits from 1 to 9 Next guess [1]: 7983 2 Bulls 2 Cows Next guess [2]: 7938 Congratulations you guessed correctly in 2 attempts
R
<lang R> target <- sample(1:9,4) bulls <- 0 cows <- 0 attempts <- 0 while (bulls != 4)
{ input <- readline("Guess a 4-digit number with no duplicate digits or 0s: ") if (nchar(input) == 4) { input <- as.integer(strsplit(input,"")1) if ((sum(is.na(input)+sum(input==0))>=1) | (length(table(input)) != 4)) {print("Malformed input!")} else { bulls <- sum(input == target) cows <- sum(input %in% target)-bulls cat("\n",bulls," Bull(s) and ",cows, " Cow(s)\n") attempts <- attempts + 1 } } else {print("Malformed input!")} }
print(paste("You won in",attempts,"attempt(s)!")) </lang>
Ruby
Inspired by Tcl <lang ruby>def generate_word(len)
([1, 2, 3, 4, 5, 6, 7, 8, 9].shuffle)[0,len].join("")
end
def get_guess(len)
while true print "Enter a guess: " guess = gets.strip err = case when guess.match(/\D/) : "digits only" when guess.length != len : "exactly #{len} digits" when guess.split("").uniq.length != len: "digits must be unique " else nil end break if err.nil? puts "the word must be #{len} unique digits between 1 and 9 (#{err}). Try again." end guess
end
def score(word, guess)
bulls = cows = 0 guess.bytes.each_with_index do |byte, idx| if word[idx] == byte bulls += 1 elsif word.include? byte cows += 1 end end [bulls, cows]
end
srand word_length = 4 puts "I have chosen a number with #{word_length} unique digits from 1 to 9." word = generate_word(word_length) count = 0 while true
guess = get_guess(word_length) count += 1 break if word == guess puts "that guess has %d bulls and %d cows" % score(word, guess)
end puts "you guessed correctly in #{count} tries."</lang>
Smalltalk
<lang smalltalk>Object subclass: BullsCows [
|number| BullsCows class >> new: secretNum [ |i| i := self basicNew. (self isValid: secretNum) ifFalse: [ SystemExceptions.InvalidArgument signalOn: secretNum reason: 'You need 4 unique digits from 1 to 9' ]. i setNumber: secretNum. ^ i ] BullsCows class >> new [ |b| b := Set new. [ b size < 4 ] whileTrue: [ b add: ((Random between: 1 and: 9) displayString first) ]. ^ self new: (b asString) ] BullsCows class >> isValid: num [ ^ (num asSet size = 4) & ((num asSet includes: $0) not) ] setNumber: num [ number := num ] check: guess [ |bc| bc := Bag new. 1 to: 4 do: [ :i | (number at: i) = (guess at: i) ifTrue: [ bc add: 'bulls' ] ifFalse: [ (number includes: (guess at: i)) ifTrue: [ bc add: 'cows' ] ] ]. ^ bc ]
].
'Guess the 4-digits number (digits from 1 to 9, no repetition)' displayNl.
|guessMe d r tries| [
tries := 0. guessMe := BullsCows new. [ [ 'Write 4 digits: ' display. d := stdin nextLine. (BullsCows isValid: d) ] whileFalse: [ 'Insert 4 digits, no repetition, exclude the digit 0' displayNl ]. r := guessMe check: d. tries := tries + 1. (r occurrencesOf: 'bulls') = 4 ] whileFalse: [ ('%1 cows, %2 bulls' % { r occurrencesOf: 'cows'. r occurrencesOf: 'bulls' }) displayNl. ]. ('Good, you guessed it in %1 tries!' % { tries }) displayNl. 'Do you want to play again? [y/n]' display. ( (stdin nextLine) = 'y' )
] whileTrue: [ Character nl displayNl ].</lang>
Tcl
<lang tcl>proc main {} {
fconfigure stdout -buffering none set length 4 puts "I have chosen a number from $length unique digits from 1 to 9 arranged in a random order.
You need to input a $length digit, unique digit number as a guess at what I have chosen
" while true { set word [generateWord $length] set count 1 while {[set guess [getGuess $length]] ne $word} { printScore $length $word $guess incr count } puts "You guessed correctly in $count tries." if {[yn "Play again?"] eq "n"} break }
}
proc generateWord {length} {
set chars 123456789 for {set i 1} {$i <= $length} {incr i} { set idx [expr {int(rand() * [string length $chars])}] append word [string index $chars $idx] set chars [string replace $chars $idx $idx] } return $word
# here's another way to generate word with no duplications set word "" while {[string length $word] < $length} { set char [expr {int(1 + 9*rand())}] if {[string first $char $word] == -1} { append word $char } }
}
proc getGuess {length} {
puts -nonewline "Enter your guess: " while true { gets stdin guess if {[string match [string repeat {[1-9]} $length] $guess]} { return $guess } if {[string tolower [string trim $guess]] eq "quit"} { puts Bye exit } puts "The word must be $length digits between 1 and 9 inclusive. Try again." }
}
proc printScore {length word guess} {
set bulls 0 set cows 0 for {set i 0} {$i < $length} {incr i} { if {[string index $word $i] eq [string index $guess $i]} { incr bulls set word [string replace $word $i $i +] } } puts " $bulls bulls" for {set i 0} {$i < $length} {incr i} { if {[set j [string first [string index $guess $i] $word]] != -1} { incr cows set word [string replace $word $j $j -] } } puts " $cows cows"
}
proc yn {msg} {
while true { puts -nonewline "$msg \[y/n] " gets stdin ans set char [string tolower [string index [string trim $ans] 0]] if {$char eq "y" || $char eq "n"} { return $char } }
}
main</lang>
Vedit macro language
<lang vedit> Buf_Switch(Buf_Free)
- 90 = Time_Tick // seed for random number generator
- 91 = 10 // random numbers in range 0 to 9
while (EOB_pos < 4) { // 4 digits needed
Call("RANDOM") BOF Ins_Char(Return_Value + '0') Replace("(.)(.*)\1", "\1\2", REGEXP+BEGIN+NOERR) // remove any duplicate
}
- 3 = 0
repeat (99) {
Get_Input(10, "Guess a 4-digit number with no duplicate digits: ", NOCR) if (Reg_Size(10) == 0) { Break } // empty string = exit Num_Eval_Reg(10) // check for numeric digits if (Chars_Matched != 4) { M("You should enter 4 numeric digits\n") Continue }
Goto_Pos(4) // count bulls Reg_Ins(10, OVERWRITE) #1 = Search("(.)...\1", REGEXP+BEGIN+ALL+NOERR)
RS(10, "[", INSERT) // count cows RS(10, "]", APPEND) #2 = Search_Block(@10, 0, 4, REGEXP+BEGIN+ALL+NOERR) - #1
#3++ NT(#1, NOCR) M(" bulls,") NT(#2, NOCR) M(" cows\n") if (#1 == 4) { M("You won after") NT(#3, NOCR) M(" guesses!\n") Break }
} Buf_Quit(OK) Return
//-------------------------------------------------------------- // Generate random numbers in range 0 <= Return_Value < #91 // #90 = Seed (0 to 0x7fffffff) // #91 = Scaling (0 to 0x10000)
- RANDOM:
- 92 = 0x7fffffff / 48271
- 93 = 0x7fffffff % 48271
- 90 = (48271 * (#90 % #92) - #93 * (#90 / #92)) & 0x7fffffff
Return ((#90 & 0xffff) * #91 / 0x10000) </lang>