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.
- Cf,
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 algol68>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> 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]:
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 qbasic>DEFINT A-Z
DIM secret AS STRING DIM guess AS STRING DIM c AS STRING DIM bulls, cows, guesses, i
RANDOMIZE TIMER 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 guess = LTRIM$(RTRIM$(guess)) IF LEN(guess) = 0 THEN EXIT DO
IF LEN(guess) <> 4 OR VAL(guess) = 0 THEN PRINT "** You should enter 4 numeric digits!" GOTO looper 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
looper: LOOP</lang>
BBC BASIC
<lang bbcbasic> secret$ = ""
REPEAT c$ = CHR$(&30 + RND(9)) IF INSTR(secret$, c$) = 0 secret$ += c$ UNTIL LEN(secret$) = 4 PRINT "Guess a four-digit number with no digit used twice."' guesses% = 0 REPEAT REPEAT INPUT "Enter your guess: " guess$ IF LEN(guess$) <> 4 PRINT "Must be a four-digit number" UNTIL LEN(guess$) = 4 guesses% += 1 IF guess$ = secret$ PRINT "You won after "; guesses% " guesses!" : END bulls% = 0 cows% = 0 FOR i% = 1 TO 4 c$ = MID$(secret$, i%, 1) IF MID$(guess$, i%, 1) = c$ THEN bulls% += 1 ELSE IF INSTR(guess$, c$) THEN cows% += 1 ENDIF ENDIF NEXT i% PRINT "You got " ;bulls% " bull(s) and " ;cows% " cow(s)." UNTIL FALSE
</lang>
Brat
<lang brat>secret_length = 4
secret = [1 2 3 4 5 6 7 8 9].shuffle.pop secret_length
score = { guess |
cows = 0 bulls = 0
guess.each_with_index { digit, index | true? digit == secret[index] { bulls = bulls + 1 } { true? secret.include?(digit) { cows = cows + 1 } } }
[cows: cows, bulls: bulls]
}
won = false guesses = 1
p "I have chosen a number with four unique digits from 1 through 9. Can you guess it?"
while { not won }
{ print "Guess #{guesses}: " guess = g.strip.dice.map { d | d.to_i }
when { guess == secret } { p "You won in #{guesses} guesses!"; won = true } { guess.include?(0) || guess.include?(null) } { p "Your guess should only include digits 1 through 9." } { guess.length != secret.length } { p "Your guess was not the correct length. The number has exactly #{secret.length} digits." } { guess.unique.length != secret.length } { p "Each digit should only appear once in your guess." } { true } { result = score guess p "Score: #{result[:bulls]} bulls, #{result[:cows]} cows." guesses = guesses + 1 } }</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"; unsigned 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(guess)) { std::cout << guess << " is not a valid guess!"; continue; }
unsigned int bulls = 0; unsigned 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>
C#
<lang csharp>using System;
namespace BullsnCows {
class Program { static void Main(string[] args) { int[] nums = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; KnuthShuffle<int>(ref nums); int[] chosenNum = new int[4]; Array.Copy(nums, chosenNum, 4);
Console.WriteLine("Your Guess ?"); while (!game(Console.ReadLine(), chosenNum)) { Console.WriteLine("Your next Guess ?"); } Console.ReadKey(); }
public static void KnuthShuffle<T>(ref T[] array) { System.Random random = new System.Random(); for (int i = 0; i < array.Length; i++) { int j = random.Next(array.Length); T temp = array[i]; array[i] = array[j]; array[j] = temp; } }
public static bool game(string guess, int[] num) { char[] guessed = guess.ToCharArray(); int bullsCount = 0, cowsCount = 0;
if (guessed.Length != 4) { Console.WriteLine("Not a valid guess."); return false; }
for (int i = 0; i < 4; i++) { int curguess = (int) char.GetNumericValue(guessed[i]); if (curguess < 1 || curguess > 9) { Console.WriteLine("Digit must be ge greater 0 and lower 10."); return false; } if (curguess == num[i]) { bullsCount++; } else { for (int j = 0; j < 4; j++) { if (curguess == num[j]) cowsCount++; } } }
if (bullsCount == 4) { Console.WriteLine("Congratulations! You have won!"); return true; } else { Console.WriteLine("Your Score is {0} bulls and {1} cows", bullsCount, cowsCount); return false; } } }
} </lang>
Clojure
<lang clojure> (ns bulls-and-cows)
(defn bulls [guess solution]
(count (filter true? (map = guess solution))))
(defn cows [guess solution]
(- (count (filter (set solution) guess)) (bulls guess solution)))
(defn valid-input?
"checks whether the string is a 4 digit number with unique digits" [user-input] (if (re-seq #"^(?!.*(\d).*\1)\d{4}$" user-input) true false))
(defn enter-guess []
"Let the user enter a guess. Verify the input. Repeat until valid.
returns a list of digits enters by the user (# # # #)"
(println "Enter your guess: ") (let [guess (read-line)] (if (valid-input? guess) (map #(Character/digit % 10) guess) (recur))))
(defn bulls-and-cows []
"generate a random 4 digit number from the list of (1 ... 9): no repeating digits
player tries to guess the number with bull and cows rules gameplay"
(let [solution ( take 4 (shuffle (range 1 10)))] (println "lets play some bulls and cows!") (loop [guess (enter-guess)] (println (bulls guess solution) " bulls and " (cows guess solution) " cows.") (if (not= guess solution) (recur (enter-guess)) (println "You have won!")))))
(bulls-and-cows) </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>
D
<lang d>import std.stdio, std.random, std.string, std.algorithm,
std.range, std.conv;
void main() {
enum size = 4; dchar[] ddigits = "123456789"d.dup; //immutable chosen = array(randomCover(ddigits))[0 .. size]; const chosen = array(randomCover(ddigits, rndGen))[0 .. size]; writeln("Guess a number composed of ", size, " unique digits from 1 to 9 in random order.");
int nGuesses; while (true) { nGuesses++; dstring guess; while (true) { writef("\nNext guess (%d): ", nGuesses); guess = to!dstring(readln().strip()); if (guess.countchars(ddigits) == size && walkLength(uniq(guess.dup.sort())) == size) break; writefln("I need %d unique digits from 1 to 9, no spaces", size); }
if (guess == chosen) { writefln("\nYou guessed correctly in %d attempts.", nGuesses); break; }
immutable bulls = count!q{ a[0] == a[1] }(zip(guess, chosen)); immutable cows = count!(i => guess[i] != chosen[i] && chosen.canFind(guess[i])) (iota(size)); writefln(" %d Bulls\n %d Cows", bulls, cows); }
}</lang> Output:
Guess a number composed of 4 unique digits from 1 to 9 in random order. Next guess (1): 123 I need 4 unique digits from 1 to 9, no spaces Next guess (1): 1234 1 Bulls 1 Cows Next guess (2): 5296 2 Bulls 0 Cows Next guess (3): 5217 You guessed correctly in 3 attempts.
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>
Elena
<lang elena>#define std'dictionary'*.
- define std'basic'*.
- define std'collections'*.
- define std'patterns'*.
- define std'routines'*.
- define ext'utils'*.
- define ext'convertors'*.
- define arrays'* = std'routines'arrays'*.
- symbol Digits : aLiteral
= Summing::(List~EListArray~{ += anItem [ $next += (anItem~EInt32Convertor numeric). ]}) start:Scan::aLiteral.
- class GameMaster
{
#field theNumbers. #method new [ // generate secret number #var aRandomNumbers := (1,2,3,4,5,6,7,8,9)~ERandomizer shuffle:9. theNumbers := aRandomNumbers~arrays'eops arrays'subarray &from:0 &to:3. ] #method proceed : aGuess [ #if (aGuess count != 4)? [ 'program'output << "Not a valid guess.%n". ^ $self. ].
#var aCows := Integer::0. #var aBulls := Integer::0. #if It::aGuess run: aNumber => [ // check range Control if:(aNumber > 0) if:(aNumber < 10). // check duplicates Control if:(NilValue == ((aGuess@(1 + aNumber index))~Forevery seek:Matching::aNumber)). #if Control if:(aNumber == theNumbers@aNumber index) [ aBulls += 1. ] | if:(NilValue != Scan::theNumbers find:aNumber) [ aCows += 1. ]. ] | [ 'program'output << "Not a valid guess.%n". ^ $self. ]. #if(aBulls == 4)? [ 'program'output << "%nCongratulations! You have won!". $self fail. ] | [ 'program'output << "%nYour Score is " << aBulls << " bulls and " << aCows << " cows%n". ]. ]
}
- symbol Program =>
[
#var aGameMaster := GameMaster.
#loop aGameMaster proceed:Digits::(ext'io'console << "Your Guess ?" >> String).
]. </lang>
Erlang
Module: <lang erlang>-module(bulls_and_cows). -export([generate_secret/0, score_guess/2, play/0]).
% generate the secret code generate_secret() -> generate_secret([], 4, lists:seq(1,9)). generate_secret(Secret, 0, _) -> Secret; generate_secret(Secret, N, Digits) ->
Next = lists:nth(random:uniform(length(Digits)), Digits), generate_secret(Secret ++ [Next], N - 1, Digits -- [Next]).
% evaluate a guess score_guess(Secret, Guess)
when length(Secret) =/= length(Guess) -> throw(badguess);
score_guess(Secret, Guess) ->
Bulls = count_bulls(Secret,Guess), Cows = count_cows(Secret, Guess, Bulls), [Bulls, Cows].
% count bulls (exact matches) count_bulls(Secret, Guess) ->
length(lists:filter(fun(I) -> lists:nth(I,Secret) == lists:nth(I,Guess) end, lists:seq(1, length(Secret)))).
% count cows (digits present but out of place) count_cows(Secret, Guess, Bulls) ->
length(lists:filter(fun(I) -> lists:member(I, Guess) end, Secret)) - Bulls.
% play a game play() -> play_round(generate_secret()).
play_round(Secret) -> play_round(Secret, read_guess()).
play_round(Secret, Guess) ->
play_round(Secret, Guess, score_guess(Secret,Guess)).
play_round(_, _, [4,0]) ->
io:put_chars("Correct!\n");
play_round(Secret, _, Score) ->
io:put_chars("\tbulls:"), io:write(hd(Score)), io:put_chars(", cows:"), io:write(hd(tl(Score))), io:put_chars("\n"), play_round(Secret).
read_guess() ->
lists:map(fun(D)->D-48 end, lists:sublist(io:get_line("Enter your 4-digit guess: "), 4)).</lang>
Script: <lang erlang>#!/usr/bin/escript % Play Bulls and Cows main(_) -> random:seed(now()), bulls_and_cows:play().</lang>
Sample play:
Enter your 4-digit guess: 8376 bulls:1, cows:0 Enter your 4-digit guess: 8941 bulls:1, cows:1 Enter your 4-digit guess: 8529 bulls:1, cows:1 Enter your 4-digit guess: 4926 bulls:1, cows:1 Enter your 4-digit guess: 9321 Correct!
Euphoria
<lang euphoria>include std\text.e include std\os.e include std\sequence.e include std\console.e
sequence bcData = {0,0} --bull,cow score for the player sequence goalNum = { {0,0,0,0}, {0,0,0,0}, 0} --computer's secret number digits (element 1), marked as bull/cow --indexes in element 2, integer value of it in element 3 sequence currentGuess = { {0,0,0,0}, {0,0,0,0}, 0} --player's guess, same format as goalNum sequence removeChars = 0 & " 0\r\t\n" --characters to trim (remove) from user's input. \r, \t are single escaped characters, --0 is ascii 0x0 and number zero is ascii 48, or 0x30. The rest are wysiwyg integer tries = 0 --track number of tries to guess the number sequence bcStrings ={"bull", "cow"} --stores singular and/or plural strings depending on score in bcData
goalNum[1] = rand( {9,9,9,9} ) --rand function works on objects. here it outputs into each sequence element. goalNum[3] = goalNum[1][1] * 1000 + goalNum[1][2] * 100 + goalNum[1][3] * 10 + goalNum[1][4] --convert digits to an integer --and store it
procedure getInputAndProcess(integer stage = 1) --object = 1 sets default value for the parameter if it isn't specified
goalNum[2][1..4] = 0 --{0,0,0,0} --set these to unscaned (0) since the scanning will start over. currentGuess[1][1..4] = 0 --{0,0,0,0} --these too, or they will contain old marks currentGuess[2][1..4] = 0 tries += 1 --equivalent to tries = tries + 1, but faster and shorter to write bcData[1..2] = 0 -- {0,0}
if stage <= 1 then --if this process was run for the first time or with no parameters, then.. puts(1,"The program has thought of a four digit number using only digits 1 to 9.\nType your guess and press enter.\n") end if while 1 label "guesscheck" do --labels can be used to specify a jump point from exit or retry, and help readability currentGuess[1] = trim(gets(0), removeChars) --get user input, trim unwanted characters from it, store it in currentGuess[1] currentGuess[1] = mapping( currentGuess[1], {49,50,51,52,53,54,55,56,57}, {1,2,3,4,5,6,7,8,9} ) --convert ascii codes to -- integer digits they represent integer tempF = find('0',currentGuess[1]) if length(currentGuess[1]) != 4 or tempF != 0 then --if the input string is now more than 4 characters/integers, --the input won't be used. puts(1,"You probably typed too many digits or a 0. Try typing a new 4 digit number with only numbers 1 through 9.\n") retry "guesscheck" else exit "guesscheck" end if end while --convert separate digits to the one integer they represent and store it, like with goalNum[3] currentGuess[3] = currentGuess[1][1] * 1000 + currentGuess[1][2] * 100 + currentGuess[1][3] * 10 + currentGuess[1][4]
--convert digits to the integer they represent, to print to a string later
--check for bulls for i = 1 to 4 do if goalNum[1][i] = currentGuess[1][i] then goalNum[2][i] = 1 currentGuess[2][i] = 1 bcData[1] += 1 end if end for
--check for cows, but not slots marked as bulls or cows already. for i = 1 to 4 label "iGuessElem"do --loop through each guessed digit for j = 1 to 4 label "jGoalElem" do --but first go through each goal digit, comparing the first guessed digit, --and then the other guessed digits 2 through 4 if currentGuess[2][i] = 1 then --if the guessed digit we're comparing right now has been marked as bull or cow already continue "iGuessElem" --skip to the next guess digit without comparing this guess digit to the other goal digits end if if goalNum[2][j] = 1 then --if the goal digit we're comparing to right now has been marked as a bull or cow already continue "jGoalElem" --skip to the next goal digit end if if currentGuess[1][i] = goalNum[1][j] then --if the guessed digit is the same as the goal one, --it won't be a bull, so it's a cow bcData[2] += 1 --score one more cow goalNum[2][j] = 1 --mark this digit as a found cow in the subsequence that stores 0's or 1's as flags continue "iGuessElem" --skip to the next guess digit, so that this digit won't try to check for --matches(cow) with other goal digits end if end for --this guess digit was compared to one goal digit , try comparing this guess digit with the next goal digit end for --this guess digit was compared with all goal digits, compare the next guess digit to all the goal digits
if bcData[1] = 1 then --uses singular noun when there is score of 1, else plural bcStrings[1] = "bull" else bcStrings[1] = "bulls" end if
if bcData[2] = 1 then --the same kind of thing as above block bcStrings[2] = "cow" else bcStrings[2] = "cows" end if
if bcData[1] < 4 then --if less than 4 bulls were found, the player hasn't won, else they have... printf(1, "Guess #%d : You guessed %d . You found %d %s, %d %s. Type new guess.\n", {tries, currentGuess[3], bcData[1], bcStrings[1], bcData[2], bcStrings[2]} ) getInputAndProcess(2) else --else they have won and the procedure ends printf(1, "The number was %d. You guessed %d in %d tries.\n", {goalNum[3], currentGuess[3], tries} ) any_key()--wait for keypress before closing console window. end if
end procedure --run the procedure getInputAndProcess(1)
</lang>
Output :
The program has thought of a four digit number using only digits 1 to 9. Type your guess and press enter. 7456 Guess #1 : You guessed 7456 . You found 1 bull, 1 cow. Type new guess. 7116 Guess #2 : You guessed 7116 . You found 1 bull, 0 cows. Type new guess. 7862 Guess #3 : You guessed 7862 . You found 0 bulls, 2 cows. Type new guess. 1826 [...etc] 6586 Guess #10 : You guessed 6586 . You found 3 bulls, 0 cows. Type new guess. 5586 Guess #11 : You guessed 5586 . You found 3 bulls, 0 cows. Type new guess. 2586 Guess #12 : You guessed 2586 . You found 3 bulls, 0 cows. Type new guess. 9586 The number was 9586. You guessed 9586 in 13 tries. Press Any Key to continue...
Factor
<lang Factor>USING: accessors assocs combinators fry grouping hashtables kernel
locals math math.parser math.ranges random sequences strings io ascii ;
IN: bullsncows
TUPLE: score bulls cows ;
- <score> ( -- score ) 0 0 score boa ;
TUPLE: cow ;
- <cow> ( -- cow ) cow new ;
TUPLE: bull ;
- <bull> ( -- bull ) bull new ;
- inc-bulls ( score -- score ) dup bulls>> 1 + >>bulls ;
- inc-cows ( score -- score ) dup cows>> 1 + >>cows ;
- random-nums ( -- seq ) 9 [1,b] 4 sample ;
- add-digits ( seq -- n ) 0 [ swap 10 * + ] reduce number>string ;
- new-number ( -- n narr ) random-nums dup add-digits ;
- narr>nhash ( narr -- nhash ) { 1 2 3 4 } swap zip ;
- num>hash ( n -- hash )
[ 1string string>number ] { } map-as narr>nhash ;
- cow-or-bull ( n g -- arr )
{ { [ n first g at n second = ] [ <bull> ] } { [ n second g value? ] [ <cow> ] } [ f ] } cond ;
- add-to-score ( arr -- score )
<score> [ bull? [ inc-bulls ] [ inc-cows ] if ] reduce ;
- check-win ( score -- ? ) bulls>> 4 = ;
- sum-score ( n g -- score ? )
'[ _ cow-or-bull ] map sift add-to-score dup check-win ;
- print-sum ( score -- str )
dup bulls>> number>string "Bulls: " swap append swap cows>> number>string " Cows: " swap 3append "\n" append ;
- (validate-readln) ( str -- ? ) dup length 4 = not swap [ letter? ] all? or ;
- validate-readln ( -- str )
readln dup (validate-readln) [ "Invalid input.\nPlease enter a valid 4 digit number: " write flush drop validate-readln ] when ;
- win ( -- ) "\nYou've won! Good job. You're so smart." print flush ;
- main-loop ( x -- )
"Enter a 4 digit number: " write flush validate-readln num>hash swap [ sum-score swap print-sum print flush ] keep swap not [ main-loop ] [ drop win ] if ;
- main ( -- ) new-number drop narr>nhash main-loop ;</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>
Go
<lang go>package main
import (
"bufio" "bytes" "fmt" "math/rand" "os" "strings" "time"
)
func main() {
fmt.Println(`Cows and Bulls
Guess four digit number of unique digits in the range 1 to 9. A correct digit but not in the correct place is a cow. A correct digit in the correct place is a bull.`)
// generate pattern pat := make([]byte, 4) rand.Seed(time.Now().Unix()) r := rand.Perm(9) for i := range pat { pat[i] = '1' + byte(r[i]) }
// accept and score guesses valid := []byte("123456789")
guess:
for in := bufio.NewReader(os.Stdin); ; { fmt.Print("Guess: ") guess, err := in.ReadString('\n') if err != nil { fmt.Println("\nSo, bye.") return } guess = strings.TrimSpace(guess) if len(guess) != 4 { // malformed: not four characters fmt.Println("Please guess a four digit number.") continue } var cows, bulls int for ig, cg := range guess { if strings.IndexRune(guess[:ig], cg) >= 0 { // malformed: repeated digit fmt.Printf("Repeated digit: %c\n", cg) continue guess } switch bytes.IndexByte(pat, byte(cg)) { case -1: if bytes.IndexByte(valid, byte(cg)) == -1 { // malformed: not a digit fmt.Printf("Invalid digit: %c\n", cg) continue guess } default: // I just think cows should go first cows++ case ig: bulls++ } } fmt.Printf("Cows: %d, bulls: %d\n", cows, bulls) if bulls == 4 { fmt.Println("You got it.") return } }
}</lang> Alternate Solution <lang go>package main
import ( . "fmt" "rand" "time" "os" "bufio" "strconv" "strings" )
func generateTarget() int { rand.Seed(time.Nanoseconds()) // loop until we find a number that doesn't have dupes for { target := rand.Intn(9000) + 1000 if !hasDupes(target) { return target } } panic("Crap.") }
func hasDupes(num int) bool { digs := make([]bool, 10) for num > 0 { if digs[num%10] { return true } digs[num%10] = true num /= 10 } return false }
func askForNumber() (int, os.Error) { in := bufio.NewReader(os.Stdin)
for { Print("Give me a number: ") line, err := in.ReadString('\n')
if err != nil { return -1, err }
// Strip off the \n line = line[0 : len(line)-1] number, err := strconv.Atoi(line)
switch { case err != nil: Println("Give me a number fule!") case number < 1000: Println("Number not long enough") case number > 9999: Println("Number is to big") case hasDupes(number): Println("I said no dupes!") default: return number, nil } // Keep Asking } panic("Crap.") }
func bullsAndCows(number int, guess int) (bulls int, cows int) { bulls, cows = 0, 0 numberstr := strconv.Itoa(number) guessstr := strconv.Itoa(guess)
for i := range guessstr { s := string(guessstr[i]) switch { case guessstr[i] == numberstr[i]: bulls++ case strings.Index(numberstr, s) >= 0: cows++ } } return; }
func main() { attempts := 0
Print("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)\n\n")
target := generateTarget()
for { guess, err := askForNumber() attempts++
// Handle err if err != nil && err != os.EOF { Print(err) } else if err == os.EOF { return }
// Check if target matches guess if guess == target { Printf("Congratulations you guessed correctly in %d attempts\n", attempts) return }
bulls, cows := bullsAndCows(target, guess) Printf("%d Bulls, %d Cows\n", bulls, cows) }
}</lang>
Haskell
<lang haskell>import Data.List (partition, intersect, nub) import Control.Monad import System.Random (StdGen, getStdRandom, randomR) import Text.Printf
numberOfDigits = 4 :: Int
main = bullsAndCows
bullsAndCows :: IO () bullsAndCows = do
digits <- getStdRandom $ pick numberOfDigits ['1' .. '9'] putStrLn "Guess away!" loop digits
where loop digits = do input <- getLine if okay input then let (bulls, cows) = score digits input in if bulls == numberOfDigits then putStrLn "You win!" else do printf "%d bulls, %d cows.\n" bulls cows loop digits else do putStrLn "Malformed guess; try again." loop digits
okay :: String -> Bool okay input = length input == numberOfDigits && input == nub input && all legalchar input where legalchar c = '1' <= c && c <= '9'
score :: String -> String -> (Int, Int) score secret guess = (length bulls, cows) where (bulls, nonbulls) = partition (uncurry (==)) $ zip secret guess cows = length $ uncurry intersect $ unzip nonbulls
pick :: Int -> [a] -> StdGen -> ([a], StdGen) {- Randomly selects items from a list without replacement. -} pick n l g = f n l g (length l - 1) []
where f 0 _ g _ ps = (ps, g) f n l g max ps = f (n - 1) (left ++ right) g' (max - 1) (picked : ps) where (i, g') = randomR (0, max) g (left, picked : right) = splitAt i l</lang>
Icon and Unicon
The following works in both Icon and Unicon.
<lang Unicon>procedure main()
digits := "123456789" every !digits :=: ?digits num := digits[1+:4] repeat if score(num, getGuess(num)) then break write("Good job.")
end
procedure getGuess(num)
repeat { writes("Enter a guess: ") guess := read() | stop("Quitter!") if *(guess ** '123456789') == *num then return guess write("Malformed guess: ",guess,". Try again.") }
end
procedure score(num, guess)
bulls := 0 cows := *(num ** guess) every (num[i := 1 to *num] == guess[i], bulls +:= 1, cows -:= 1) write("\t",bulls," bulls and ",cows," cows") return (bulls = *num)
end</lang>
J
<lang j>require 'misc'
plural=: conjunction define
(":m),' ',n,'s'#~1~:m
)
bullcow=:monad define
number=. 1+4?9 whilst. -.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>
For example:
<lang j> bullcow Guess my number: 1234 0 bulls and 1 cow. Guess my number: 5678 3 bulls and 0 cows. Guess my number: 2349 0 bulls and 0 cows. Guess my number: 1567 0 bulls and 3 cows. Guess my number: 6178 3 bulls and 0 cows. Guess my number: 6157 1 bull and 2 cows. Guess my number: 5178 4 bulls and 0 cows. 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!
Liberty BASIC
<lang lb>
do while len( secret$) <4 c$ =chr$( int( rnd( 1) *9) +49) if not( instr( secret$, c$)) then secret$ =secret$ +c$ loop
print " Secret number has been guessed.... "; secret$
guesses = 0
[loop]
print " Your guess "; input " "; guess$
guesses = guesses +1
r$ =score$( guess$, secret$)
bulls =val( word$( r$, 1, ",")) cows =val( word$( r$, 2, ","))
print " Result: "; bulls; " bulls, and "; cows; " cows" print
if guess$ =secret$ then print " You won after "; guesses; " guesses!" print " You guessed it in "; guesses print " Thanks for playing!" wait end if
goto [loop]
end ' _____________________________________________________________
function check( i$) ' check =0 if no digit repeats, else =1
check =0 for i =1 to 3 for j =i +1 to 4 if mid$( i$, i, 1) =mid$( i$, j, 1) then check =1 next j next i
end function
function score$( a$, b$) ' return as a csv string the number of 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 then cows = cows + 1 end if end if next i score$ =str$( bulls); ","; str$( cows)
end function
[quit] close #w end </lang>
Logo
<lang logo>to ok? :n
output (and [number? :n] [4 = count :n] [4 = count remdup :n] [not member? 0 :n])
end
to init
do.until [make "hidden random 10000] [ok? :hidden]
end
to guess :n
if not ok? :n [print [Bad guess! (4 unique digits, 1-9)] stop] localmake "bulls 0 localmake "cows 0 foreach :n [cond [ [[? = item # :hidden] make "bulls 1 + :bulls] [[member? ? :hidden] make "cows 1 + :cows ] ]] (print :bulls "bulls, :cows "cows) if :bulls = 4 [print [You guessed it!]]
end</lang>
Lua
<lang Lua>function ShuffleArray(array)
for i=1,#array-1 do local t = math.random(i, #array) array[i], array[t] = array[t], array[i] end
end
function GenerateNumber()
local digits = {1,2,3,4,5,6,7,8,9}
ShuffleArray(digits)
return digits[1] * 1000 + digits[2] * 100 + digits[3] * 10 + digits[4]
end
function IsMalformed(input)
local malformed = false
if #input == 4 then local already_used = {} for i=1,4 do local digit = input:byte(i) - string.byte('0') if digit < 1 or digit > 9 or already_used[digit] then malformed = true break end already_used[digit] = true end else malformed = true end
return malformed
end
math.randomseed(os.time()) math.randomseed(math.random(2^31-1)) -- since os.time() only returns seconds
print("\nWelcome to Bulls and Cows!") print("") print("The object of this game is to guess the random 4-digit number that the") print("computer has chosen. The number is generated using only the digits 1-9,") print("with no repeated digits. Each time you enter a guess, you will score one") print("\"bull\" for each digit in your guess that matches the corresponding digit") print("in the computer-generated number, and you will score one \"cow\" for each") print("digit in your guess that appears in the computer-generated number, but is") print("in the wrong position. Use this information to refine your guesses. When") print("you guess the correct number, you win."); print("")
quit = false
repeat
magic_number = GenerateNumber() magic_string = tostring(magic_number) -- Easier to do scoring with a string repeat io.write("\nEnter your guess (or 'Q' to quit): ") user_input = io.read() if user_input == 'Q' or user_input == 'q' then quit = true break end
if not IsMalformed(user_input) then if user_input == magic_string then print("YOU WIN!!!") else local bulls, cows = 0, 0 for i=1,#user_input do local find_result = magic_string:find(user_input:sub(i,i))
if find_result and find_result == i then bulls = bulls + 1 elseif find_result then cows = cows + 1 end end print(string.format("You scored %d bulls, %d cows", bulls, cows)) end else print("Malformed input. You must enter a 4-digit number with") print("no repeated digits, using only the digits 1-9.") end
until user_input == magic_string
if not quit then io.write("\nPress <Enter> to play again or 'Q' to quit: ") user_input = io.read() if user_input == 'Q' or user_input == 'q' then quit = true end end
if quit then print("\nGoodbye!") end
until quit</lang>
MUMPS
<lang MUMPS>BullCow New bull,cow,guess,guessed,ii,number,pos,x Set number="",x=1234567890 For ii=1:1:4 Do . Set pos=$Random($Length(x))+1 . Set number=number_$Extract(x,pos) . Set $Extract(x,pos)="" . Quit Write !,"The computer has selected a number that consists" Write !,"of four different digits." Write !!,"As you are guessing the number, ""bulls"" and ""cows""" Write !,"will be awarded: a ""bull"" for each digit that is" Write !,"placed in the correct position, and a ""cow"" for each" Write !,"digit that occurs in the number, but in a different place.",! Write !,"For a guess, enter 4 digits." Write !,"Any other input is interpreted as ""I give up"".",! Set guessed=0 For Do Quit:guessed . Write !,"Your guess: " Read guess If guess'?4n Set guessed=-1 Quit . Set (bull,cow)=0,x=guess . For ii=4:-1:1 If $Extract(x,ii)=$Extract(number,ii) Do . . Set bull=bull+1,$Extract(x,ii)="" . . Quit . For ii=1:1:$Length(x) Set:number[$Extract(x,ii) cow=cow+1 . Write !,"You guessed ",guess,". That earns you " . If 'bull,'cow Write "neither bulls nor cows..." Quit . If bull Write bull," bull" Write:bull>1 "s" . If cow Write:bull " and " Write cow," cow" Write:cow>1 "s" . Write "." . If bull=4 Set guessed=1 Write !,"That's a perfect score." . Quit If guessed<0 Write !!,"The number was ",number,".",! Quit Do BullCow
The computer has selected a number that consists of four different digits.
As you are guessing the number, "bulls" and "cows" will be awarded: a "bull" for each digit that is placed in the correct position, and a "cow" for each digit that occurs in the number, but in a different place.
For a guess, enter 4 digits. Any other input is interpreted as "I give up".
Your guess: 1234 You guessed 1234. That earns you 1 cow. Your guess: 5678 You guessed 5678. That earns you 1 cow. Your guess: 9815 You guessed 9815. That earns you 1 cow. Your guess: 9824 You guessed 9824. That earns you 2 cows. Your guess: 9037 You guessed 9037. That earns you 1 bull and 2 cows. Your guess: 9048 You guessed 2789. That earns you 1 bull and 2 cows. Your guess: 2079 You guessed 2079. That earns you 1 bull and 3 cows. Your guess: 2709 You guessed 2709. That earns you 2 bulls and 2 cows. Your guess: 0729 You guessed 0729. That earns you 4 cows. Your guess: 2907 You guessed 2907. That earns you 4 bulls. That's a perfect score.</lang>
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>
Oz
<lang oz>declare
proc {Main} Solution = {PickNUnique 4 {List.number 1 9 1}}
proc {Loop} Guess = {EnterGuess} in {System.showInfo {Bulls Guess Solution}#" bulls and "# {Cows Guess Solution}#" cows"} if Guess \= Solution then {Loop} end end in {Loop} {System.showInfo "You have won!"} end
fun {Bulls Xs Sol} {Length {Filter {List.zip Xs Sol Value.'=='} Id}} end
fun {Cows Xs Sol} {Length {Intersection Xs Sol}} end
local class TextFile from Open.file Open.text end StdIn = {New TextFile init(name:stdin)} in fun {EnterGuess} try {System.printInfo "Enter your guess (e.g. \"1234\"): "} S = {StdIn getS($)} in %% verify {Length S} = 4 {All S Char.isDigit} = true {FD.distinct S} %% assert there is no duplicate digit %% convert from digits to numbers {Map S fun {$ D} D-&0 end} catch _ then {EnterGuess} end end end
fun {PickNUnique N Xs} {FoldL {MakeList N} fun {$ Z _} {Pick {Diff Xs Z}}|Z end nil} end
fun {Pick Xs} {Nth Xs {OS.rand} mod {Length Xs} + 1} end
fun {Diff Xs Ys} {FoldL Ys List.subtract Xs} end
fun {Intersection Xs Ys} {Filter Xs fun {$ X} {Member X Ys} end} end fun {Id X} X end
in
{Main}</lang>
PARI/GP
This simple implementation expects guesses in the form [a,b,c,d]. <lang parigp>bc()={
my(u,v,bulls,cows); while(#vecsort(v=vector(4,i,random(9)+1),,8)<4,); while(bulls<4, u=input(); if(type(u)!="t_VEC"|#u!=4,next); bulls=sum(i=1,4,u[i]==v[i]); cows=sum(i=1,4,sum(j=1,4,i!=j&v[i]==u[j])); print("You have "bulls" bulls and "cows" cows") )
};</lang>
Perl
<lang perl>use Data::Random qw(rand_set); use List::MoreUtils qw(uniq);
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";
for ( my $guesses = 1; ; $guesses++ ) {
my $guess; while (1) { print "\nNext guess [$guesses]: "; $guess = <STDIN>; chomp $guess; checkguess($guess) and last; print "$size digits, no repetition, no 0... retry\n"; } if ( $guess eq $chosen ) { print "You did it in $guesses attempts!\n"; last; } 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; return uniq(split //, $g) == $size && $g =~ /^[1-9]{$size}$/;
}</lang>
Perl 6
<lang perl6>my $size = 4; my @secret = pick $size, '1' .. '9';
for 1..* -> $guesses {
my @guess; loop { @guess = (prompt("Guess $guesses: ") // exit).comb; last if @guess == $size and all(@guess) eq one(@guess) & any('1' .. '9'); say 'Malformed guess; try again.'; } my ($bulls, $cows) = 0, 0; for ^$size { when @guess[$_] eq @secret[$_] { ++$bulls; } when @guess[$_] eq any @secret { ++$cows; } } last if $bulls == $size; say "$bulls bulls, $cows cows.";
}
say 'A winner is you!';</lang>
PHP
<lang php><?php $size = 4;
$chosen = implode(array_rand(array_flip(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) {
global $size; return count(array_unique(str_split($g))) == $size && preg_match("/^[1-9]Template:$size$/", $g);
} ?></lang>
PicoLisp
<lang lisp>(de ok? (N)
(let D (mapcar 'format (chop N)) (and (num? N) (not (member 0 D)) (= 4 (length D)) (= D (uniq D)) D )) )
(de init-cows ()
(until (setq *Hidden (ok? (rand 1234 9876)))) )
(de guess (N)
(let D (ok? N) (if D (let Bulls (cnt '= D *Hidden) (if (= 4 Bulls) " You guessed it!" (let Cows (- (cnt '((N) (member N *Hidden)) D) Bulls) (pack Bulls " bulls, " Cows " cows") ) ) ) " Bad guess! (4 unique digits, 1-9)" ) ) )
</lang>
Prolog
Works with SWI-Prolog 6.1.8 (for predicate foldl), module lambda, written by Ulrich Neumerkel found there http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl and module clpfd written by Markus Triska. <lang Prolog>:- use_module(library(lambda)).
- - use_module(library(clpfd)).
% Parameters of the server
% length of the guess proposition(4).
% Numbers of digits % 0 -> 8 digits(8).
bulls_and_cows_server :-
proposition(LenGuess),
length(Solution, LenGuess),
choose(Solution),
repeat,
write('Your guess : '),
read(Guess),
( study(Solution, Guess, Bulls, Cows)
-> format('Bulls : ~w Cows : ~w~n', [Bulls, Cows]),
Bulls = LenGuess
; digits(Digits), Max is Digits + 1,
format('Guess must be of ~w digits between 1 and ~w~n',
[LenGuess, Max]),
fail).
choose(Solution) :- digits(Digits), Max is Digits + 1, repeat, maplist(\X^(X is random(Max) + 1), Solution), all_distinct(Solution), !.
study(Solution, Guess, Bulls, Cows) :- proposition(LenGuess), digits(Digits),
% compute the transformation 1234 => [1,2,3,4] atom_chars(Guess, Chars), maplist(\X^Y^(atom_number(X, Y)), Chars, Ms),
% check that the guess is well formed length(Ms, LenGuess), maplist(\X^(X > 0, X =< Digits+1), Ms),
% compute the digit in good place foldl(\X^Y^V0^V1^((X = Y->V1 is V0+1; V1 = V0)),Solution, Ms, 0, Bulls),
% compute the digits in bad place foldl(\Y1^V2^V3^(foldl(\X2^Z2^Z3^(X2 = Y1 -> Z3 is Z2+1; Z3 = Z2), Ms, 0, TT1), V3 is V2+ TT1), Solution, 0, TT), Cows is TT - Bulls. </lang>
PureBasic
<lang PureBasic>Define.s secret, guess, c Define.i bulls, cows, guesses, i
If OpenConsole()
While Len(secret) < 4 c = Chr(Random(8) + 49) If FindString(secret, c, 1) = 0 secret + c EndIf Wend
Repeat Print("Guess a 4-digit number with no duplicate digits: ") guess = Input() If Len(guess) = 0 Break ;break from loop EndIf isMalformedGuess = #False If Len(guess) <> 4 ;guess is too short isMalformedGuess = #True Else For i = 1 To 4 c = Mid(guess, i, 1) If Not FindString("123456789", c, 1) Or CountString(guess, c) <> 1 ;guess contains either non-digits or duplicate digits isMalformedGuess = #True Break ;break from For/Next loop EndIf Next EndIf If isMalformedGuess PrintN("** You should enter 4 different numeric digits that are each from 1 to 9!") Continue ;continue loop EndIf bulls = 0: cows = 0: guesses = guesses + 1 For i = 1 To 4 c = Mid(secret, i, 1) If Mid(guess, i, 1) = c bulls + 1 ElseIf FindString(guess, c, 1) cows + 1 EndIf Next Print( Str(bulls) + " bull") If bulls <> 1 Print( "s") EndIf Print( ", " + Str(cows) + " cow") If cows <> 1 PrintN( "s") Else PrintN("") EndIf If guess = secret PrintN("You won after " + Str(guesses) + " guesses!") Break ;break from loop EndIf ForEver
Print(#CRLF$ + #CRLF$ + "Press ENTER to exit") Input() CloseConsole()
EndIf</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>
REXX
Version 1
This REXX version doesn't allow repeated digits. <lang rexx>/*REXX program to play the game of "Bulls & Cows". */ ?=getRand()
do forever if getN()==? then leave call scorer call sy "You got" bulls 'bull's(bulls) "and" cows 'cow's(cows)"." end /*forever*/
say say " ┌─────────────────────────────────────────┐" say " │ │" say " │ Congratulations, you've guessed it !! │" say " │ │" say " └─────────────────────────────────────────┘" say exit /*─────────────────────────────────────GETN subroutine──────────────────*/ getN: bulls='[Bulls & Cows game] ' /*get a guess from the guesser. */
do forever call sy bulls 'Please enter a four-digit guess (or QUIT):' parse pull n _ .; nu=n; upper nu if nu=='QUIT' then exit
if n== then do call ser 'no argument specified.' iterate end
if _\== then do call ser 'too many arguments specified.' iterate end
if verify(0,n)==0 then do call ser 'illegal digit: 0' iterate end
_=verify(n,987654321) if _\==0 then do call ser 'illegal character:' substr(n,_,1) iterate end
if length(n)<4 then do call ser 'not enough digits' iterate end
if length(n)>4 then do call ser 'too many digits' iterate end return n end
/*─────────────────────────────────────GETRAND subroutine───────────────*/ getRand: ?=
do until length(?)==4 r=random(1,9) if pos(r,?)\==0 then iterate /*don't allow repeated dig*/ ?=? || r end /*until*/
return ? /*─────────────────────────────────────S subroutine─────────────────────*/ s: if arg(1)==1 then return ; return 's' /*─────────────────────────────────────SCORER subroutine────────────────*/ scorer: g=? bulls=0
do j=1 for 4 x=substr(n,j,1) _=x==substr(g,j,1) if _==0 then iterate bulls=bulls+1 g=overlay(' ',g,j) end /*j*/
cows=0
do k=1 for 4 cows=cows+(pos(substr(n,k,1),g)\==0) end /*k*/
return /*─────────────────────────────────────SER subroutine───────────────────*/ ser: call sy '*** error! ***'; call sy arg(1); return /*─────────────────────────────────────SY subroutine────────────────────*/ sy: say; say arg(1); say; return</lang>
Version 2
<lang rexx> /*REXX program to play the game of "Bulls & Cows". *******************
- Changes from Version 1:
- ?= -> qq= (? not everywhere a valid symbol, righthandside mandatory
- change getRand to avoid invalid digit rejection
- check user's input for multiple digits
- remove the s routine for plural (doesn't work for all plurals anyway)
- add feature MM to ease guessing (MM=Mastermind - a similar game)
- add feature ? to see the solution (for the impatient player)
- program runs as is on ooRexx and on TSO (after changing | to !)
- Made source and output more compact
- formatted source 'my way' 2 July 2012 Walter Pachl
- /
ask='<Bulls & Cows game> Please enter a four-digit guess (or QUIT):'
b.='bulls'; b.1='bull' c.='cows'; c.1='cow' g.='geese'; g.1='goose' /* a plural without the s */ qq=getRand() mm=0 Do Forever
If get_guess()==qq Then leave Call scorer Say "You got" bulls b.bulls "and" cows c.cows"." If mm Then Say mms End /*forever*/
Say " *******************************************" Say " * *" Say " * Congratulations, you've guessed it !! *" Say " * *" Say " *******************************************" Exit
get_guess: /*get a guess from the guesser. */
do forever
Say ask Parse Pull guessi guess=translate(guessi) bc=verify(guess,987654321) Select When guess='?' Then Say qq 'is the correct sequence' When guess='QUIT' Then Exit When guess='MM' Then Do Say 'Mastermind output enabled' mm=1 End When guess= Then Call ser 'no argument specified.' When words(guess)>1 Then Call ser 'too many arguments specified.' When verify(0,guess)=0 Then Call ser 'illegal digit: 0' When bc>0 Then Call ser 'illegal character:' substr(guessi,bc,1) When length(guess)<4 Then Call ser 'not enough digits' When length(guess)>4 Then Call ser 'too many digits' When dups(guess) Then Call ser '4 DIFFERENT digits, please' Otherwise Do /********** Say guess ************/ Return guess End End End
getRand: digits='123456789' qq= Do i=1 To 4
d=random(1,length(digits)) d=substr(digits,d,1) qq=qq||d digits=space(translate(digits,' ',d),0) /************ Say qq digits ************/ End
Return qq
scorer: g=qq mms='----' bulls=0 Do j=1 for 4
If substr(guess,j,1)=substr(qq,j,1) Then Do bulls=bulls+1 guess=overlay(' ',guess,j) mms=overlay('+',mms,j) End End
cows=0 Do j=1 To 4
If pos(substr(guess,j,1),qq)>0 Then Do cows=cows+1 mms=overlay('.',mms,j) End End
Return
dups: Procedure Parse Arg s Do i=1 To 3
If pos(substr(s,i,1),substr(s,i+1))>0 Then Return 1 End
Return 0
ser: Say '*** error ***' arg(1); Return </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>
Scala
<lang scala>import scala.util.Random
object BullCow {
def main(args: Array[String]): Unit = { val number=chooseNumber var guessed=false var guesses=0
while(!guessed){ Console.print("Guess a 4-digit number with no duplicate digits: ") val input=Console.readInt val digits=input.toString.map(_.asDigit).toList if(input>=1111 && input<=9999 && !hasDups(digits)){ guesses+=1 var bulls, cows=0 for(i <- 0 to 3) if(number(i)==digits(i)) bulls+=1 else if(number.contains(digits(i))) cows+=1
if(bulls==4) guessed=true else println("%d Cows and %d Bulls.".format(cows, bulls)) } } println("You won after "+guesses+" guesses!"); }
def chooseNumber={ var digits=List[Int]() while(digits.size<4){ val d=Random.nextInt(9)+1 if (!digits.contains(d)) digits=digits:+d } digits }
def hasDups(input:List[Int])=input.size!=input.distinct.size
}</lang>
Scheme
<lang scheme>
- generate a random non-repeating list of 4 digits, 1-9 inclusive
(define (get-num)
(define (gen lst) (if (= (length lst) 4) lst (let ((digit (+ (random 9) 1))) (if (member digit lst) ;make sure the new digit isn't in the ;list (gen lst) (gen (cons digit lst)))))) (string->list (apply string-append (map number->string (gen '())))))
- is g a valid guess (that is, non-repeating, four digits 1-9
- inclusive?)
(define (valid-guess? g)
(let ((g-num (string->number (apply string g)))) ;does the same digit appear twice in lst? (define (repeats? lst) (cond ((null? lst) #f) ((member (car lst) (cdr lst)) #t) (else (repeats? (cdr lst))))) (and g-num (> g-num 1233) (< g-num 9877) (not (repeats? g)))))
- return '(cows bulls) for the given guess
(define (score answer guess)
;total cows + bulls (define (cows&bulls a g) (cond ((null? a) 0) ((member (car a) g) (+ 1 (cows&bulls (cdr a) g))) (else (cows&bulls (cdr a) g)))) ;bulls only (define (bulls a g) (cond ((null? a) 0) ((equal? (car a) (car g)) (+ 1 (bulls (cdr a) (cdr g)))) (else (bulls (cdr a) (cdr g))))) (list (- (cows&bulls answer guess) (bulls answer guess)) (bulls answer guess)))
- play the game
(define (bull-cow answer)
;get the user's guess as a list (define (get-guess) (let ((e (read))) (if (number? e) (string->list (number->string e)) (string->list (symbol->string e))))) (display "Enter a guess: ") (let ((guess (get-guess))) (if (valid-guess? guess) (let ((bulls (cadr (score answer guess))) (cows (car (score answer guess)))) (if (= bulls 4) (display "You win!\n") (begin (display bulls) (display " bulls, ") (display cows) (display " cows.\n") (bull-cow answer)))) (begin (display "Invalid guess.\n") (bull-cow answer)))))
(bull-cow (get-num)) </lang>
Sample game play
Enter a guess: 1234 0 bulls, 1 cows. Enter a guess: 2345 1 bulls, 0 cows. Enter a guess: 2346 1 bulls, 1 cows. Enter a guess: 2367 0 bulls, 1 cows. Enter a guess: 2647 1 bulls, 1 cows. Enter a guess: 2648 2 bulls, 1 cows. Enter a guess: 2468 1 bulls, 2 cows. Enter a guess: 1468 1 bulls, 2 cows. Enter a guess: 2684 0 bulls, 3 cows. Enter a guess: 6248 3 bulls, 0 cows. Enter a guess: 6948 You win!
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>
TUSCRIPT
<lang tuscript> $$ MODE tuscript SET nr1=RANDOM_NUMBERS (1,9,1) LOOP
SET nr2=RANDOM_NUMBERS (1,9,1) IF (nr2!=nr1) EXIT
ENDLOOP LOOP
SET nr3=RANDOM_NUMBERS (1,9,1) IF (nr3!=nr1,nr2) EXIT
ENDLOOP LOOP
SET nr4=RANDOM_NUMBERS (1,9,1) IF (nr4!=nr1,nr2,nr3) EXIT
ENDLOOP SET nr=JOIN(nr1,"'",nr2,nr3,nr4), limit=10 LOOP r=1,limit SET bulls=cows=0 ASK "round {r} insert a number":guessnr="" SET length=LENGTH(guessnr), checknr=STRINGS (guessnr,":>/:")
LOOP n=nr,y=checknr IF (length!=4) THEN PRINT "4-letter digit required" EXIT ELSEIF (n==y) THEN SET bulls=bulls+1 ELSEIF (nr.ct.":{y}:") THEN SET cows=cows+1 ENDIF ENDLOOP
PRINT "bulls=",bulls," cows=",cows
IF (bulls==4) THEN PRINT "BINGO" EXIT ELSEIF (r==limit) THEN PRINT "BETTER NEXT TIME" EXIT ENDIF
ENDLOOP </lang> Output:
round 1 insert a number >1234 bulls=1 cows=1 round 2 insert a number >5678 bulls=1 cows=1 round 3 insert a number >1298 bulls=2 cows=0 round 4 insert a number >2379 bulls=0 cows=0 round 5 insert a number >1468 bulls=4 cows=0 BINGO
UNIX Shell
<lang bash>#!/bin/bash
rand() {
local min=${1:-0} local max=${2:-32767}
[ ${min} -gt ${max} ] && min=$(( min ^ max )) && max=$(( min ^ max )) && min=$(( min ^ max ))
echo -n $(( ( $RANDOM % $max ) + $min ))
}
in_arr() {
local quandry="${1}" shift local arr=( $@ ) local i=
for i in ${arr[*]} do [ "${quandry}" == "${i}" ] && return 0 && break done
return 1
}
delete_at() {
local idx="$(( $1 + 1 ))" shift local arr=( "sentinel" $@ )
echo -n "${arr[@]:1:$(( idx - 1 ))} ${arr[@]:$((idx + 1)):$(( ${#arr[@]} - idx - 1))}"
}
delete_first() {
local meanie="${1}" shift local arr=( $@ ) local i=0
for (( i = 0; i < ${#arr[@]} ; i++ )) do [ "${arr[${i}]}" == "${meanie}" ] && arr=( $( delete_at ${i} ${arr[*]} ) ) done
echo -n "${arr[*]}"
}
to_arr() {
local string="${1}" local arr=()
while [ "${#string}" -gt 0 ] do arr=( ${arr[*]} ${string:0:1} ) string="${string:1}" done
echo -n "${arr[*]}"
}
choose_idx() {
local arr=( $@ ) echo -n "$( rand 0 $(( ${#arr[@]} - 1 )) )"
}
locate_bulls() {
local secret=( $( to_arr "${1}" ) ) local guess=( $( to_arr "${2}" ) ) local hits=() local i=0
for (( i=0; i<4; i++ )) do [ "${secret[${i}]}" -eq "${guess[${i}]}" ] && hits=( ${hits[*]} ${i} ) done
echo -n "${hits[*]}"
}
bulls() {
local secret="${1}" local guess="${2}" local bulls=( $( locate_bulls "${secret}" "${guess}" ) )
echo -n "${#bulls[@]}"
}
cows() {
local secret=( $( to_arr "${1}" ) ) local guess=( $( to_arr "${2}" ) ) local bulls=( $( locate_bulls "${1}" "${2}" ) ) local hits=0 local i=
# Avoid double-counting bulls for i in ${bulls[*]} do secret=( $( delete_at ${i} ${secret[*]} ) ) done # Process the guess against what's left of the secret for i in ${guess[*]} do in_arr "${i}" ${secret[*]} && secret=( $( delete_first "${i}" ${secret[*]} ) ) && (( hits++ )) done
echo -n ${hits}
}
malformed() {
local guess=( $( to_arr "${1}" ) ) local i=
[ ${#guess[@]} -ne 4 ] && return 0
for i in ${guess[*]} do if ! in_arr ${i} 1 2 3 4 5 6 7 8 9 then return 0 break fi done
return 1
}
candidates=( 1 2 3 4 5 6 7 8 9 ) secret=
while [ "${#secret}" -lt 4 ] do
cidx=$( choose_idx ${candidates[*]} ) secret="${secret}${candidates[${cidx}]}" candidates=( $(delete_at ${cidx} ${candidates[*]} ) )
done
while read -p "Enter a four-digit guess: " guess do
malformed "${guess}" && echo "Malformed guess" && continue [ "${guess}" == "${secret}" ] && echo "You win!" && exit echo "Score: $( bulls "${secret}" "${guess}" ) Bulls, $( cows "${secret}" "${guess}" ) Cows"
done</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>
Visual Basic .NET
<lang vbnet>Imports System Imports System.Text.RegularExpressions
Module Bulls_and_Cows
Function CreateNumber() As String Dim random As New Random() Dim sequence As Char() = {"1"c, "2"c, "3"c, "4"c, "5"c, "6"c, "7"c, "8"c, "9"c}
For i As Integer = 0 To sequence.Length - 1 Dim j As Integer = random.Next(sequence.Length) Dim temp As Char = sequence(i) : sequence(i) = sequence(j) : sequence(j) = temp Next
Return New String(sequence, 0, 4) End Function
Function IsFourDigitNumber(ByVal number As String) As Boolean Return Regex.IsMatch(number, "^[1-9]{4}$") End Function
Sub Main() Dim chosenNumber As String = CreateNumber() Dim attempt As Integer = 0 Console.WriteLine("Number is chosen") Dim gameOver As Boolean = False Do attempt += 1 Console.WriteLine("Attempt #{0}. Enter four digit number: ", attempt) Dim number As String = Console.ReadLine() Do While Not IsFourDigitNumber(number) Console.WriteLine("Invalid number: type four characters. Every character must digit be between '1' and '9'.") number = Console.ReadLine() Loop
Dim bulls As Integer = 0 Dim cows As Integer = 0
For i As Integer = 0 To number.Length - 1 Dim j As Integer = chosenNumber.IndexOf(number(i)) If i = j Then bulls += 1 ElseIf j >= 0 Then cows += 1 End If Next
If bulls < chosenNumber.Length Then Console.WriteLine("The number '{0}' has {1} bulls and {2} cows", _ number, bulls, cows) Else gameOver = True End If Loop Until gameOver Console.WriteLine("The number was guessed in {0} attempts. Congratulations!", attempt) End Sub
End Module</lang>