Bulls and cows: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|UNIX Shell}}: Added Bash3 example)
(→‎{{header|UNIX Shell}}: Modified to produce better results regarding guesses with repetitive digits)
Line 2,171: Line 2,171:
min=$(( min ^ max )) &&
min=$(( min ^ max )) &&
max=$(( min ^ max )) &&
max=$(( min ^ max )) &&
min=$(( min ^ max ))
min=$(( min ^ max ))


echo -n $(( ( $RANDOM % $max ) + $min ))
echo -n $(( ( $RANDOM % $max ) + $min ))
Line 2,196: Line 2,196:


echo -n "${arr[@]:1:$(( idx - 1 ))} ${arr[@]:$((idx + 1)):$(( ${#arr[@]} - idx - 1))}"
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[*]}"
}
}


Line 2,213: Line 2,227:
choose_idx() {
choose_idx() {
local arr=( $@ )
local arr=( $@ )

echo -n "$( rand 0 $(( ${#arr[@]} - 1 )) )"
echo -n "$( rand 0 $(( ${#arr[@]} - 1 )) )"
}
}


bulls() {
locate_bulls() {
local secret=( $( to_arr "${1}" ) )
local secret=( $( to_arr "${1}" ) )
local guess=( $( to_arr "${2}" ) )
local guess=( $( to_arr "${2}" ) )
local hits=0
local hits=()
local i=0
local i=0


for (( i=0; i<4; i++ ))
for (( i=0; i<4; i++ ))
do
do
[ "${secret[${i}]}" -eq "${guess[${i}]}" ] && (( hits++ ))
[ "${secret[${i}]}" -eq "${guess[${i}]}" ] && hits=( ${hits[*]} ${i} )
done
done


echo -n ${hits}
echo -n "${hits[*]}"
}

bulls() {
local secret="${1}"
local guess="${2}"
local bulls=( $( locate_bulls "${secret}" "${guess}" ) )

echo -n "${#bulls[@]}"
}
}


Line 2,234: Line 2,256:
local secret=( $( to_arr "${1}" ) )
local secret=( $( to_arr "${1}" ) )
local guess=( $( to_arr "${2}" ) )
local guess=( $( to_arr "${2}" ) )
local bulls=$( bulls "${1}" "${2}" )
local bulls=( $( locate_bulls "${1}" "${2}" ) )
local hits=0
local hits=0
local i=''
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[*]}
for i in ${guess[*]}
do
do
in_arr "${i}" ${secret[*]} && (( hits++ ))
in_arr "${i}" ${secret[*]} &&
secret=( $( delete_first "${i}" ${secret[*]} ) ) &&
(( hits++ ))
done
done


echo -n $(( hits - bulls ))
echo -n ${hits}
}
}


Line 2,250: Line 2,281:
local i=''
local i=''


[ ${#guess[@]} -ne 4 ] &&
[ ${#guess[@]} -ne 4 ] &&
return 0
return 0


for i in ${guess[*]}
for i in ${guess[*]}
do
do
if ! in_arr ${i} 1 2 3 4 5 6 7 8 9
if ! in_arr ${i} 1 2 3 4 5 6 7 8 9
then
then
return 0
return 0
Line 2,280: Line 2,311:
[ "${guess}" == "${secret}" ] && echo "You win!" && exit
[ "${guess}" == "${secret}" ] && echo "You win!" && exit
echo "Score: $( bulls "${secret}" "${guess}" ) Bulls, $( cows "${secret}" "${guess}" ) Cows"
echo "Score: $( bulls "${secret}" "${guess}" ) Bulls, $( cows "${secret}" "${guess}" ) Cows"
done
done</lang>

</lang>


=={{header|Vedit macro language}}==
=={{header|Vedit macro language}}==

Revision as of 10:32, 21 July 2010

Task
Bulls and cows
You are encouraged to solve this task according to the task description, using any language you may know.

This is an old game played with pencil and paper that was later implemented on computer.

The task is for the program to create a four digit random number from the digits 1 to 9, without duplication. The program should ask for guesses to this number, reject guesses that are malformed, then print the score for the guess.

The score is computed as:

  1. The player wins if the guess is the same as the randomly chosen number, and the program ends.
  2. A score of one bull is accumulated for each digit in the guess that equals the corresponding digit in the randomly chosen initial number.
  3. 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.

C.f: Bulls and cows/Player

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

Translation of: Python
Works with: ALGOL 68 version Standard - no extensions to language used


Works with: ALGOL 68G version Any - tested with release mk15-0.8b.fc9.i386


Works with: ELLA ALGOL 68 version Any (with appropriate job cards) - tested with release 1.8.8d.fc9.i386

<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;
  1. 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

Works with: QBasic

<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>

C

Library: ncurses

<lang c>#include <stdio.h>

  1. include <stdarg.h>
  2. include <stdlib.h>
  3. include <stdbool.h>
  4. include <curses.h>
  5. include <string.h>
  1. define MAX_NUM_TRIES 72
  2. define LINE_BEGIN 7
  3. define LAST_LINE 18

int yp=LINE_BEGIN, xp=0;

char number[5]; char guess[5];

  1. 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>

  1. include <string>
  2. include <algorithm>
  3. 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>

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

 (:import (java.util Random Scanner)))

(let [generator (Random.)]

 (defn pick [xs]
   "Randomly pick an element of xs."
   (nth xs (.nextInt generator (count xs)))))

(defn pick-n-unique [n xs]

 "Randomly pick n elements of xs. Every xs can only be picked once."
 (loop [picked []]
   (if (= (count picked) n)
     picked
     (recur (conj picked (pick (remove (set picked) xs)))))))

(defn bulls [guess sol]

 (count (filter true? (map = guess sol))))

(defn cows [guess sol]

 (count (filter (set sol) guess)))

(let [scanner (Scanner. *in*)]

 (defn enter-guess []
   "Let the user enter a guess. Verify the input. Repeat until valid."
   (print "Enter your guess: ") (flush)
   (let [guess (.nextLine scanner)]
     (if (or (not= (count guess) 4)
             (not-every? #(Character/isDigit %1) guess)
             (not= (distinct guess) (seq guess)))
       (recur)
       (map #(Character/digit % 10) guess)))))

(defn bulls-and-cows []

 (let [solution (pick-n-unique 4 (range 1 10))]
   (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>

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

Works with: E-on-Java

(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>

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

Works with: GNU 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

Works with: Fortran version 90 and later

<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 ( . "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>


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>

For example:

<lang j> bullcow Guess my number: 7461 0 bulls and 1 cow. Guess my number: 3215 0 bulls and 3 cows. Guess my number: 2357 2 bulls and 0 cows. Guess my number: 1359 3 bulls and 0 cows. Guess my number: 1358 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!

Works with: UCB 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>

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

Translation of: Python
Works with: Rakudo version #22 "Thousand Oaks"

<lang perl6>constant SIZE = 4;

my @secret = pick SIZE, '1' .. '9'; my $guesses = 0;

loop {

   ++$guesses;
   my ($bulls, $cows, @guess) = 0, 0;
   loop {
       print "Guess $guesses: ";
       @guess = split *, $*IN.get;
       @guess == SIZE
           and all(@guess) eq one(@guess) & any('1' .. '9')
           and last;
       say 'Malformed guess; try again.';
   }
   for ^SIZE {
       when @guess[$_] eq @secret[$_] { ++$bulls; }
       when @guess[$_] eq any @secret { ++$cows; }
   }
   $bulls == SIZE and last;
   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>

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))

  1. 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

Works with: R version 2.8.1

<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

Works with: Ruby version 1.8.7+

<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>

Scheme

Works with: any R6RS 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

Works with: GNU 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>

UNIX Shell

Works with: bash version 3

<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)

  1. 90 = Time_Tick // seed for random number generator
  2. 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

}

  1. 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:
  1. 92 = 0x7fffffff / 48271
  2. 93 = 0x7fffffff % 48271
  3. 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>