Bulls and cows
This is an old game played with pencil and paper that was later implemented on computer.
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
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 _ = List.fold_left (* reject entry with duplication *) (fun ac b -> if List.mem b ac then raise Exit; (b::ac)) [] t in List.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 List.iter2 (fun x y -> if x = y then incr bull ) g t; let cow = ref 0 in List.iter (fun x -> if List.mem x t then incr cow ) g; 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 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>
PHP
<lang php><?php
$size = 4; $chosen = implode(array_rand(range('1', '9'), $size));
echo "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";
for ($guesses = 1; ; $guesses++) {
while (true) { echo "\nNext guess [$guesses]: "; $guess = rtrim(fgets(STDIN)); if (!checkguess($guess))
echo "$size digits, no repetition, no 0... retry\n";
else break; } if ($guess == $chosen) { echo "You did it in $guesses attempts!\n"; break; } else { $bulls = 0; $cows = 0; foreach (range(0, $size-1) as $i) { if ($guess[$i] == $chosen[$i]) $bulls++; else if (strpos($chosen, $guess[$i]) !== FALSE) $cows++; } echo "$cows cows, $bulls bulls\n"; }
}
function checkguess($g) {
$h = array(); foreach (str_split($g) as $k) { if (array_key_exists($k, $h)) return false; $h[$k] = 1; } return preg_match('/^[1-9]{4}$/', $g);
} ?></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>