Data commit

This commit is contained in:
Ingy döt Net 2023-07-01 11:58:00 -04:00
parent 7387c8f97b
commit cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions

View file

@ -0,0 +1,3 @@
---
from: http://rosettacode.org/wiki/Bulls_and_cows/Player
note: Games

View file

@ -0,0 +1,12 @@
;Task:
Write a ''player'' of the [[Bulls and cows|Bulls and Cows game]], rather than a scorer. The player should give intermediate answers that respect the scores to previous attempts.
One method is to generate a list of all possible numbers that could be the answer, then to prune the list by keeping only those numbers that would give an equivalent score to how your last guess was scored. Your next guess can be any number from the pruned list.<br>
Either you guess correctly or run out of numbers to guess, which indicates a problem with the scoring.
;Related tasks:
* &nbsp; [[Bulls and cows]]
* &nbsp; [[Guess the number]]
* &nbsp; [[Guess the number/With Feedback (Player)]]
<br><br>

View file

@ -0,0 +1,210 @@
with Ada.Text_IO;
with Ada.Containers.Vectors;
with Ada.Numerics.Discrete_Random;
procedure Bulls_Player is
-- package for In-/Output of natural numbers
package Nat_IO is new Ada.Text_IO.Integer_IO (Natural);
-- for comparing length of the vectors
use type Ada.Containers.Count_Type;
-- number of digits
Guessing_Length : constant := 4;
-- digit has to be from 1 to 9
type Digit is range 1 .. 9;
-- a sequence has specified length of digits
type Sequence is array (1 .. Guessing_Length) of Digit;
-- data structure to store the possible answers
package Sequence_Vectors is new Ada.Containers.Vectors
(Element_Type => Sequence,
Index_Type => Positive);
-- check if sequence contains each digit only once
function Is_Valid (S : Sequence) return Boolean is
Appeared : array (Digit) of Boolean := (others => False);
begin
for I in S'Range loop
if Appeared (S (I)) then
return False;
end if;
Appeared (S (I)) := True;
end loop;
return True;
end Is_Valid;
-- calculate all possible sequences and store them in the vector
procedure Fill_Pool (Pool : in out Sequence_Vectors.Vector) is
Finished : exception;
-- count the sequence up by one
function Next (S : Sequence) return Sequence is
Result : Sequence := S;
Index : Positive := S'Last;
begin
loop
-- overflow at a position causes next position to increase
if Result (Index) = Digit'Last then
Result (Index) := Digit'First;
-- overflow at maximum position
-- we have processed all possible values
if Index = Result'First then
raise Finished;
end if;
Index := Index - 1;
else
Result (Index) := Result (Index) + 1;
return Result;
end if;
end loop;
end Next;
X : Sequence := (others => 1);
begin
loop
-- append all valid values
if Is_Valid (X) then
Pool.Append (X);
end if;
X := Next (X);
end loop;
exception
when Finished =>
-- the exception tells us that we have added all possible values
-- simply return and do nothing.
null;
end Fill_Pool;
-- generate a random index from the pool
function Random_Index (Pool : Sequence_Vectors.Vector) return Positive is
subtype Possible_Indexes is Positive range
Pool.First_Index .. Pool.Last_Index;
package Index_Random is new Ada.Numerics.Discrete_Random
(Possible_Indexes);
Index_Gen : Index_Random.Generator;
begin
Index_Random.Reset (Index_Gen);
return Index_Random.Random (Index_Gen);
end Random_Index;
-- get the answer from the player, simple validity tests
procedure Get_Answer (S : Sequence; Bulls, Cows : out Natural) is
Valid : Boolean := False;
begin
Bulls := 0;
Cows := 0;
while not Valid loop
-- output the sequence
Ada.Text_IO.Put ("How is the score for:");
for I in S'Range loop
Ada.Text_IO.Put (Digit'Image (S (I)));
end loop;
Ada.Text_IO.New_Line;
begin
Ada.Text_IO.Put ("Bulls:");
Nat_IO.Get (Bulls);
Ada.Text_IO.Put ("Cows:");
Nat_IO.Get (Cows);
if Bulls + Cows <= Guessing_Length then
Valid := True;
else
Ada.Text_IO.Put_Line ("Invalid answer, try again.");
end if;
exception
when others =>
null;
end;
end loop;
end Get_Answer;
-- remove all sequences that wouldn't give an equivalent score
procedure Strip
(V : in out Sequence_Vectors.Vector;
S : Sequence;
Bulls, Cows : Natural)
is
function Has_To_Be_Removed (Position : Positive) return Boolean is
Testant : constant Sequence := V.Element (Position);
Bull_Score : Natural := 0;
Cows_Score : Natural := 0;
begin
for I in Testant'Range loop
for J in S'Range loop
if Testant (I) = S (J) then
-- same digit at same position: Bull!
if I = J then
Bull_Score := Bull_Score + 1;
else
Cow_Score := Cow_Score + 1;
end if;
end if;
end loop;
end loop;
return Cow_Score /= Cows or else Bull_Score /= Bulls;
end Has_To_Be_Removed;
begin
for Index in reverse V.First_Index .. V.Last_Index loop
if Has_To_Be_Removed (Index) then
V.Delete (Index);
end if;
end loop;
end Strip;
-- main routine
procedure Solve is
All_Sequences : Sequence_Vectors.Vector;
Test_Index : Positive;
Test_Sequence : Sequence;
Bulls, Cows : Natural;
begin
-- generate all possible sequences
Fill_Pool (All_Sequences);
loop
-- pick at random
Test_Index := Random_Index (All_Sequences);
Test_Sequence := All_Sequences.Element (Test_Index);
-- ask player
Get_Answer (Test_Sequence, Bulls, Cows);
-- hooray, we have it!
exit when Bulls = 4;
All_Sequences.Delete (Test_Index);
Strip (All_Sequences, Test_Sequence, Bulls, Cows);
exit when All_Sequences.Length <= 1;
end loop;
if All_Sequences.Length = 0 then
-- oops, shouldn't happen
Ada.Text_IO.Put_Line
("I give up, there has to be a bug in" &
"your scoring or in my algorithm.");
else
if All_Sequences.Length = 1 then
Ada.Text_IO.Put ("The sequence you thought has to be:");
Test_Sequence := All_Sequences.First_Element;
else
Ada.Text_IO.Put ("The sequence you thought of was:");
end if;
for I in Test_Sequence'Range loop
Ada.Text_IO.Put (Digit'Image (Test_Sequence (I)));
end loop;
end if;
end Solve;
begin
-- output blah blah
Ada.Text_IO.Put_Line ("Bulls and Cows, Your turn!");
Ada.Text_IO.New_Line;
Ada.Text_IO.Put_Line
("Think of a sequence of" &
Integer'Image (Guessing_Length) &
" different digits.");
Ada.Text_IO.Put_Line ("I will try to guess it. For each correctly placed");
Ada.Text_IO.Put_Line ("digit I score 1 Bull. For each digit that is on");
Ada.Text_IO.Put_Line ("the wrong place I score 1 Cow. After each guess");
Ada.Text_IO.Put_Line ("you tell me my score.");
Ada.Text_IO.New_Line;
Ada.Text_IO.Put_Line ("Let's start.");
Ada.Text_IO.New_Line;
-- solve the puzzle
Solve;
end Bulls_Player;

View file

@ -0,0 +1,107 @@
length:=4, i:=0, S:=P(9,length)
Gui, Add, Text, w83 vInfo, Think of a %length%-digit number with no duplicate digits.
Gui, Add, Edit, w40 vBulls
Gui, Add, Text, x+3, Bulls
Gui, Add, Edit, xm w40 vCows
Gui, Add, Text, x+3, Cows
Gui, Add, Button, xm w83 Default vDefault, Start
Gui, Add, Edit, ym w130 r8 vHistory ReadOnly
Gui, Show
Return
ButtonStart:
If Default = Restart
Reload
Gui, Submit, NoHide
GuiControl, Focus, Bulls
If (Bulls = length)
{
GuiControl, , Info, Guessed in %i% tries!
GuiControl, , Default, Restart
Default = Restart
}
Else
{
If i = 0
{
GuiControl, , Default, Submit
GuiControl, , History
}
Else
{
If (StrLen(Bulls) != 1 || StrLen(Cows) != 1)
Return
If Bulls is not digit
Return
If Cows is not digit
Return
GuiControl, , History, % History .= ": " Bulls " Bulls " Cows " Cows`n"
GuiControl, , Bulls
GuiControl, , Cows
S:=Remove(S, Guess, Bulls, Cows)
}
If !S
{
GuiControl, , Info, Invalid response.
GuiControl, , Default, Restart
Default = Restart
}
Else
{
Guess := SubStr(S,1,length)
GuiControl, , History, % History . Guess
GuiControl, , Info, Enter a single digit number of bulls and cows.
i++
}
}
Return
GuiEscape:
GuiClose:
ExitApp
Remove(S, Guess, Bulls, Cows) {
Loop, Parse, S, `n
If (Bulls "," Cows = Response(Guess, A_LoopField))
S2 .= A_LoopField . "`n"
Return SubStr(S2,1,-1)
}
; from http://rosettacode.org/wiki/Bulls and Cows#AutoHotkey
Response(Guess,Code) {
Bulls := 0, Cows := 0
Loop, % StrLen(Code)
If (SubStr(Guess, A_Index, 1) = SubStr(Code, A_Index, 1))
Bulls++
Else If (InStr(Code, SubStr(Guess, A_Index, 1)))
Cows++
Return Bulls "," Cows
}
; from http://rosettacode.org/wiki/Permutations#Alternate_Version
P(n,k="",opt=0,delim="",str="") {
i:=0
If !InStr(n,"`n")
If n in 2,3,4,5,6,7,8,9
Loop, %n%
n := A_Index = 1 ? A_Index : n "`n" A_Index
Else
Loop, Parse, n, %delim%
n := A_Index = 1 ? A_LoopField : n "`n" A_LoopField
If (k = "")
RegExReplace(n,"`n","",k), k++
If k is not Digit
Return "k must be a digit."
If opt not in 0,1,2,3
Return "opt invalid."
If k = 0
Return str
Else
Loop, Parse, n, `n
If (!InStr(str,A_LoopField) || opt & 1)
s .= (!i++ ? (opt & 2 ? str "`n" : "") : "`n" )
. P(n,k-1,opt,delim,str . A_LoopField . delim)
Return s
}

View file

@ -0,0 +1,58 @@
secret$ = ""
REPEAT
c$ = CHR$(&30 + RND(9))
IF INSTR(secret$, c$) = 0 secret$ += c$
UNTIL LEN(secret$) = 4
FOR i% = 1234 TO 9876
possible$ += STR$(i%)
NEXT
PRINT "Guess a four-digit number with no digit used twice."
guesses% = 0
REPEAT
IF LEN(possible$) = 4 THEN
guess$ = possible$
ELSE
guess$ = MID$(possible$, 4*RND(LEN(possible$) / 4) - 3, 4)
ENDIF
PRINT '"Computer guesses " guess$
guesses% += 1
IF guess$ = secret$ PRINT "Correctly guessed after "; guesses% " guesses!" : END
PROCcount(secret$, guess$, bulls%, cows%)
PRINT "giving " ;bulls% " bull(s) and " ;cows% " cow(s)."
i% = 1
REPEAT
temp$ = MID$(possible$, i%, 4)
PROCcount(temp$, guess$, testbulls%, testcows%)
IF bulls%=testbulls% IF cows%=testcows% THEN
i% += 4
ELSE
possible$ = LEFT$(possible$, i%-1) + MID$(possible$, i%+4)
ENDIF
UNTIL i% > LEN(possible$)
IF INSTR(possible$, secret$) = 0 STOP
UNTIL FALSE
END
DEF PROCcount(secret$, guess$, RETURN bulls%, RETURN cows%)
LOCAL i%, c$
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%
ENDPROC

View file

@ -0,0 +1,119 @@
#include <iostream>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <time.h>
//--------------------------------------------------------------------------------------------------
using namespace std;
//--------------------------------------------------------------------------------------------------
const unsigned int LEN = 4;
//--------------------------------------------------------------------------------------------------
class CowsAndBulls_Player
{
public:
CowsAndBulls_Player() { fillPool(); }
void play() { secret = createSecret(); guess(); }
private:
void guess()
{
pair<int, int> res; int cc = 1;
cout << endl << " SECRET: " << secret << endl << "==============" << endl;
cout << "+-----------+---------+--------+\n| GUESS | BULLS | COWS |\n+-----------+---------+--------+\n";
while( true )
{
string gs = gimmeANumber();
if( gs.empty() ) { cout << endl << "Something went wrong with the scoring..." << endl << "Cannot find an answer!" << endl; return; }
if( scoreIt( gs, res ) ) { cout << endl << "I found the secret number!" << endl << "It is: " << gs << endl; return; }
cout << "| " << gs << " | " << setw( 3 ) << res.first << " | " << setw( 3 ) << res.second << " |\n+-----------+---------+--------+\n";
clearPool( gs, res );
}
}
void clearPool( string gs, pair<int, int>& r )
{
vector<string>::iterator pi = pool.begin();
while( pi != pool.end() )
{
if( removeIt( gs, ( *pi ), r ) ) pi = pool.erase( pi );
else pi++;
}
}
string gimmeANumber()
{
if( pool.empty() ) return "";
return pool[rand() % pool.size()];
}
void fillPool()
{
for( int x = 1234; x < 9877; x++ )
{
ostringstream oss; oss << x;
if( check( oss.str() ) ) pool.push_back( oss.str() );
}
}
bool check( string s )
{
for( string::iterator si = s.begin(); si != s.end(); si++ )
{
if( ( *si ) == '0' ) return false;
if( count( s.begin(), s.end(), ( *si ) ) > 1 ) return false;
}
return true;
}
bool removeIt( string gs, string ts, pair<int, int>& res )
{
pair<int, int> tp; getScore( gs, ts, tp );
return tp != res;
}
bool scoreIt( string gs, pair<int, int>& res )
{
getScore( gs, secret, res );
return res.first == LEN;
}
void getScore( string gs, string st, pair<int, int>& pr )
{
pr.first = pr.second = 0;
for( unsigned int ui = 0; ui < LEN; ui++ )
{
if( gs[ui] == st[ui] ) pr.first++;
else
{
for( unsigned int vi = 0; vi < LEN; vi++ )
if( gs[ui] == st[vi] ) pr.second++;
}
}
}
string createSecret()
{
string n = "123456789", rs = "";
while( rs.length() < LEN )
{
int r = rand() % n.length();
rs += n[r]; n.erase( r, 1 );
}
return rs;
}
string secret;
vector<string> pool;
};
//--------------------------------------------------------------------------------------------------
int main( int argc, char* argv[] )
{
srand( static_cast<unsigned int>( time( NULL ) ) ); CowsAndBulls_Player cb;
cb.play(); cout << endl << endl;
return system( "pause" );
}
//--------------------------------------------------------------------------------------------------

View file

@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BullsAndCows
{
class Program
{
const int ANSWER_SIZE = 4;
static IEnumerable<string> Permutations(int size)
{
if (size > 0)
{
foreach (string s in Permutations(size - 1))
foreach (char n in "123456789")
if (!s.Contains(n))
yield return s + n;
}
else
yield return "";
}
static IEnumerable<T> Shuffle<T>(IEnumerable<T> source)
{
Random random = new Random();
List<T> list = source.ToList();
while (list.Count > 0)
{
int ix = random.Next(list.Count);
yield return list[ix];
list.RemoveAt(ix);
}
}
static bool ReadBullsCows(out int bulls, out int cows)
{
string[] input = Console.ReadLine().Split(',').ToArray();
bulls = cows = 0;
if (input.Length < 2)
return false;
else
return int.TryParse(input[0], out bulls)
&& int.TryParse(input[1], out cows);
}
static void Main(string[] args)
{
Console.WriteLine("Bulls and Cows");
Console.WriteLine("==============");
Console.WriteLine();
List<string> answers = Shuffle(Permutations(ANSWER_SIZE)).ToList();
while (answers.Count > 1)
{
string guess = answers[0];
Console.Write("My guess is {0}. How many bulls, cows? ", guess);
int bulls, cows;
if (!ReadBullsCows(out bulls, out cows))
Console.WriteLine("Sorry, I didn't understand that. Please try again.");
else
for (int ans = answers.Count - 1; ans >= 0; ans--)
{
int tb = 0, tc = 0;
for (int ix = 0; ix < ANSWER_SIZE; ix++)
if (answers[ans][ix] == guess[ix])
tb++;
else if (answers[ans].Contains(guess[ix]))
tc++;
if ((tb != bulls) || (tc != cows))
answers.RemoveAt(ans);
}
}
if (answers.Count == 1)
Console.WriteLine("Hooray! The answer is {0}!", answers[0]);
else
Console.WriteLine("No possible answer fits the scores you gave.");
}
}
}

View file

@ -0,0 +1,102 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
char *list;
const char *line = "--------+--------------------\n";
int len = 0;
int irand(int n)
{
int r, rand_max = RAND_MAX - (RAND_MAX % n);
do { r = rand(); } while(r >= rand_max);
return r / (rand_max / n);
}
char* get_digits(int n, char *ret)
{
int i, j;
char d[] = "123456789";
for (i = 0; i < n; i++) {
j = irand(9 - i);
ret[i] = d[i + j];
if (j) d[i + j] = d[i], d[i] = ret[i];
}
return ret;
}
#define MASK(x) (1 << (x - '1'))
int score(const char *digits, const char *guess, int *cow)
{
int i, bits = 0, bull = *cow = 0;
for (i = 0; guess[i] != '\0'; i++)
if (guess[i] != digits[i])
bits |= MASK(digits[i]);
else ++bull;
while (i--) *cow += ((bits & MASK(guess[i])) != 0);
return bull;
}
void pick(int n, int got, int marker, char *buf)
{
int i, bits = 1;
if (got >= n)
strcpy(list + (n + 1) * len++, buf);
else
for (i = 0; i < 9; i++, bits *= 2) {
if ((marker & bits)) continue;
buf[got] = i + '1';
pick(n, got + 1, marker | bits, buf);
}
}
void filter(const char *buf, int n, int bull, int cow)
{
int i = 0, c;
char *ptr = list;
while (i < len) {
if (score(ptr, buf, &c) != bull || c != cow)
strcpy(ptr, list + --len * (n + 1));
else
ptr += n + 1, i++;
}
}
void game(const char *tgt, char *buf)
{
int i, p, bull, cow, n = strlen(tgt);
for (i = 0, p = 1; i < n && (p *= 9 - i); i++);
list = malloc(p * (n + 1));
pick(n, 0, 0, buf);
for (p = 1, bull = 0; n - bull; p++) {
strcpy(buf, list + (n + 1) * irand(len));
bull = score(tgt, buf, &cow);
printf("Guess %2d| %s (from: %d)\n"
"Score | %d bull, %d cow\n%s",
p, buf, len, bull, cow, line);
filter(buf, n, bull, cow);
}
}
int main(int c, char **v)
{
int n = c > 1 ? atoi(v[1]) : 4;
char secret[10] = "", answer[10] = "";
srand(time(0));
printf("%sSecret | %s\n%s", line, get_digits(n, secret), line);
game(secret, answer);
return 0;
}

View file

@ -0,0 +1,15 @@
--------+--------------------
Secret | 5437
--------+--------------------
Guess 1| 7198 (from: 3024)
Score | 0 bull, 1 cow
--------+--------------------
Guess 2| 2386 (from: 720)
Score | 0 bull, 1 cow
--------+--------------------
Guess 3| 5743 (from: 122)
Score | 1 bull, 3 cow
--------+--------------------
Guess 4| 5437 (from: 5)
Score | 4 bull, 0 cow
--------+--------------------

View file

@ -0,0 +1,36 @@
--------+--------------------
Secret | 758214936
--------+--------------------
Guess 1| 245863197 (from: 362880)
Score | 0 bull, 9 cow
--------+--------------------
Guess 2| 964715382 (from: 133496)
Score | 1 bull, 8 cow
--------+--------------------
Guess 3| 614927853 (from: 48722)
Score | 0 bull, 9 cow
--------+--------------------
Guess 4| 567391248 (from: 15926)
Score | 0 bull, 9 cow
--------+--------------------
Guess 5| 839174562 (from: 4473)
Score | 1 bull, 8 cow
--------+--------------------
Guess 6| 489635721 (from: 1503)
Score | 0 bull, 9 cow
--------+--------------------
Guess 7| 723156984 (from: 317)
Score | 2 bull, 7 cow
--------+--------------------
Guess 8| 953278614 (from: 89)
Score | 2 bull, 7 cow
--------+--------------------
Guess 9| 321479685 (from: 24)
Score | 0 bull, 9 cow
--------+--------------------
Guess 10| 893752416 (from: 4)
Score | 1 bull, 8 cow
--------+--------------------
Guess 11| 758214936 (from: 1)
Score | 9 bull, 0 cow
--------+--------------------

View file

@ -0,0 +1,43 @@
(defun random-number ()
(do* ((lst '(1 2 3 4 5 6 7 8 9) (remove d lst))
(l 9 (length lst))
(d (nth (random l) lst) (nth (random l) lst))
(number nil (cons d number)))
((= l 5) number)))
(defun validp (number)
(loop for el in number with rst = (rest number)
do (cond ((= el 0) (return-from validp nil))
((member el rst) (return-from validp nil))
(t (setq rst (rest rst))))
finally (return number)))
(defun bulls (number guess)
(loop for x in number
for y in guess
counting (= x y) into b
finally (return b)))
(defun bulls+cows (number guess)
(loop for x in guess
counting (member x number) into c
finally (return c)))
(defun solve ()
(let ((number (random-number))
(possible-guesses (loop for i from 1234 to 9876
when (validp (map 'list #'digit-char-p (prin1-to-string i))) collect it)))
(format t "Secret: ~a~%" number)
(loop with guess = (nth (random (length possible-guesses)) possible-guesses)
with b = (bulls number guess)
with c = (- (bulls+cows number guess) b)
do (format t "Guess: ~a B: ~a C: ~a~%" guess b c)
(if (= b 4)
(return-from solve (format t "Solution found!")))
(setq possible-guesses (mapcan #'(lambda (x) (if (and (= b (bulls x guess))
(= c (- (bulls+cows x guess) b)))
(list x)))
(remove guess possible-guesses)))
(setq guess (nth (random (length possible-guesses)) possible-guesses))
(setq b (bulls number guess))
(setq c (- (bulls+cows number guess) b)))))

View file

@ -0,0 +1,29 @@
size = 4
scores = [] of Tuple(Int32, Int32)
guesses = [] of Array(Char)
puts "Playing Bulls & Cows with #{size} unique digits."
possible_guesses = ('1'..'9').to_a.permutations(size).shuffle
loop do
guesses << (current_guess = possible_guesses.pop)
print "Guess #{guesses.size} (#{possible_guesses.size}) is #{current_guess.join}. Answer (bulls,cows)? "
bulls, cows = gets.not_nil!.split(',').map(&.to_i)
scores << (score = {bulls, cows})
# handle win
break (puts "Yeah!") if score == {size, 0}
# filter possible guesses
possible_guesses.select! do |guess|
bulls = guess.zip(current_guess).count { |g, cg| g == cg }
cows = size - (guess - current_guess).size - bulls
{bulls, cows} == score
end
# handle 'no possible guesses left'
if possible_guesses.empty?
puts "Error in scoring?"
guesses.zip(scores).each { |g, (b, c)| puts "#{g.join} => bulls #{b} cows #{c}" }
break
end
end

View file

@ -0,0 +1,20 @@
void main() {
import std.stdio, std.random, std.algorithm, std.range, std.ascii;
immutable d9 = "123456789";
auto choices = cartesianProduct(d9, d9, d9, d9).map!(t => [t[]])
.filter!(a => a.sort().uniq.count == 4).array;
do {
const ans = choices[uniform(0, $)];
writef("My guess is %s. How many bulls and cows? ", ans);
immutable score = readln.filter!isDigit.map!q{ a - '0' }.array;
choices = choices.remove!(c => score !=
[c.zip(ans).count!(p => p[0] == p[1]),
c.zip(ans).count!(p => p[0] != p[1] && ans.canFind(p[0]))]);
} while (choices.length > 1);
if (choices.empty)
return "Nothing fits the scores you gave.".writeln;
writeln("Solution found: ", choices[0]);
}

View file

@ -0,0 +1,45 @@
defmodule Bulls_and_cows do
def player(size \\ 4) do
possibility = permute(size) |> Enum.shuffle
player(size, possibility, 1)
end
def player(size, possibility, i) do
guess = hd(possibility)
IO.puts "Guess #{i} is #{Enum.join(guess)} (from #{length(possibility)} possibilities)"
case get_score(size) do
{^size, 0} -> IO.puts "Solved!"
score ->
case select(size, possibility, guess, score) do
[] -> IO.puts "Sorry! I can't find a solution. Possible mistake in the scoring."
selected -> player(size, selected, i+1)
end
end
end
defp get_score(size) do
IO.gets("Answer (Bulls, cows)? ")
|> String.split(~r/\D/, trim: true)
|> Enum.map(&String.to_integer/1)
|> case do
[bulls, cows] when bulls+cows in 0..size -> {bulls, cows}
_ -> get_score(size)
end
end
defp select(size, possibility, guess, score) do
Enum.filter(possibility, fn x ->
bulls = Enum.zip(x, guess) |> Enum.count(fn {n,g} -> n==g end)
cows = size - length(x -- guess) - bulls
{bulls, cows} == score
end)
end
defp permute(size), do: permute(size, Enum.to_list(1..9))
defp permute(0, _), do: [[]]
defp permute(size, list) do
for x <- list, y <- permute(size-1, list--[x]), do: [x|y]
end
end
Bulls_and_cows.player

View file

@ -0,0 +1,84 @@
include std/sequence.e
constant line = "--------+--------------------\n"
constant digits = "123456789"
sequence list = {}
function get_digits(integer n)
integer j
sequence d = digits, ret = ""
for i=1 to n do
j = rand(length(digits)-i)
ret &= d[i+j]
if j then
d[i+j] = d[i]
d[i] = ret[i]
end if
end for
return ret
end function
function MASK(integer x)
return power(2,x-digits[1])
end function
function score(sequence pattern, sequence guess)
integer bits = 0, bull = 0, cow = 0
for i = 1 to length(guess) do
if guess[i] != pattern[i] then
bits += MASK(pattern[i])
else
bull += 1
end if
end for
for i = 1 to length(guess) do
cow += and_bits(bits,MASK(guess[i])) != 0
end for
return {bull, cow}
end function
procedure pick(integer n, integer got, integer marker, sequence buf)
integer bits = 1
if got >= n then
list = append(list,buf)
else
for i = 0 to length(digits)-1 do
if not and_bits(marker,bits) then
buf[got+1] = i+digits[1]
pick(n, got+1, or_bits(marker,bits), buf)
end if
bits *= 2
end for
end if
end procedure
function tester(sequence item, sequence data)
return equal(score(item,data[1]),data[2])
end function
constant tester_id = routine_id("tester")
procedure game(sequence tgt)
integer p, n = length(tgt)
sequence buf = repeat(0,n), bc
list = {}
pick(n,0,0,buf)
p = 1
bc = {0,0}
while bc[1]<n do
buf = list[rand($)]
bc = score(tgt,buf)
printf(1,"Guess %2d| %s (from: %d)\nScore | %d bull, %d cow\n%s",
{p, buf, length(list)} & bc & {line})
list = filter(list, tester_id, {buf, bc})
p+=1
end while
end procedure
constant n = 4
sequence secret = get_digits(n)
printf(1,"%sSecret | %s\n%s", {line, secret, line})
game(secret)

View file

@ -0,0 +1,27 @@
USING: arrays combinators.short-circuit formatting fry io kernel
math math.combinatorics math.functions math.order math.parser
math.ranges random regexp sequences sets splitting ;
: bulls ( seq1 seq2 -- n ) [ = 1 0 ? ] 2map sum ;
: cows ( seq1 seq2 -- n ) [ intersect length ] [ bulls - ] 2bi ;
: score ( seq1 seq2 -- pair ) [ bulls ] [ cows 2array ] 2bi ;
: possibilities ( -- seq ) 9 [1,b] 4 <k-permutations> ;
: pare ( seq guess score -- new-seq ) '[ _ score _ = ] filter ;
: >number ( seq -- n ) reverse [ 10^ * ] map-index sum ;
: >score ( str -- pair ) "," split [ string>number ] map ;
: ask ( n -- ) "My guess is %d. How many bulls, cows? " printf ;
: valid-input? ( str -- ? )
{ [ R/ \d,\d/ matches? ] [ >score sum 0 4 between? ] } 1&& ;
: get-score ( n -- pair )
[ ask ] keep flush readln dup valid-input?
[ nip >score ] [ drop get-score ] if ;
: game ( seq -- )
dup random [
dup >number get-score dup first 4 =
[ 3drop "Success!" print ] [ pare game ] if
] [ drop "Scoring inconsistency." print ] if* ;
possibilities game

View file

@ -0,0 +1,109 @@
module Player
implicit none
contains
subroutine Init(candidates)
integer, intent(in out) :: candidates(:)
integer :: a, b, c, d, n
n = 0
thousands: do a = 1, 9
hundreds: do b = 1, 9
tens: do c = 1, 9
units: do d = 1, 9
if (b == a) cycle hundreds
if (c == b .or. c == a) cycle tens
if (d == c .or. d == b .or. d == a) cycle units
n = n + 1
candidates(n) = a*1000 + b*100 + c*10 + d
end do units
end do tens
end do hundreds
end do thousands
end subroutine init
subroutine Evaluate(bulls, cows, guess, candidates)
integer, intent(in) :: bulls, cows, guess
integer, intent(in out) :: candidates(:)
integer :: b, c, s, i, j
character(4) :: n1, n2
write(n1, "(i4)") guess
do i = 1, size(candidates)
if (candidates(i) == 0) cycle
b = 0
c = 0
write(n2, "(i4)") candidates(i)
do j = 1, 4
s = index(n1, n2(j:j))
if(s /= 0) then
if(s == j) then
b = b + 1
else
c = c + 1
end if
end if
end do
if(.not.(b == bulls .and. c == cows)) candidates(i) = 0
end do
end subroutine Evaluate
function Nextguess(candidates)
integer :: Nextguess
integer, intent(in out) :: candidates(:)
integer :: i
nextguess = 0
do i = 1, size(candidates)
if(candidates(i) /= 0) then
nextguess = candidates(i)
candidates(i) = 0
return
end if
end do
end function
end module Player
program Bulls_Cows
use Player
implicit none
integer :: bulls, cows, initial, guess
integer :: candidates(3024) = 0
real :: rnum
! Fill candidates array with all possible number combinations
call Init(candidates)
! Random initial guess
call random_seed
call random_number(rnum)
initial = 3024 * rnum + 1
guess = candidates(initial)
candidates(initial) = 0
do
write(*, "(a, i4)") "My guess is ", guess
write(*, "(a)", advance = "no") "Please score number of Bulls and Cows: "
read*, bulls, cows
write(*,*)
if (bulls == 4) then
write(*, "(a)") "Solved!"
exit
end if
! We haven't found the solution yet so evaluate the remaining candidates
! and eliminate those that do not match the previous score given
call Evaluate(bulls, cows, guess, candidates)
! Get the next guess from the candidates that are left
guess = Nextguess(candidates)
if(guess == 0) then
! If we get here then no solution is achievable from the scores given or the program is bugged
write(*, "(a)") "Sorry! I can't find a solution. Possible mistake in the scoring"
exit
end if
end do
end program

View file

@ -0,0 +1,96 @@
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
fmt.Println(`Cows and bulls/player
You think of four digit number of unique digits in the range 1 to 9.
I guess. You score my guess:
A correct digit but not in the correct place is a cow.
A correct digit in the correct place is a bull.
You give my score as two numbers separated with a space.`)
// generate possible patterns, store in map
m := make(map[string]int)
var g func([]byte, int)
g = func(digits []byte, fixed int) {
if fixed == 4 {
m[string(digits[:4])] = 0
return
}
for i := fixed; i < len(digits); i++ {
digits[fixed], digits[i] = digits[i], digits[fixed]
g(digits, fixed+1)
digits[fixed], digits[i] = digits[i], digits[fixed]
}
}
g([]byte("123456789"), 0)
// guess/score/eliminate loop
for in := bufio.NewReader(os.Stdin);; {
// pick a value, ie, guess
var guess string
for guess = range m {
delete(m, guess)
break
}
// get and parse score
var c, b uint
for ;; fmt.Println("Score guess as two numbers: cows bulls") {
fmt.Printf("My guess: %s. Score? (c b) ", guess)
score, err := in.ReadString('\n')
if err != nil {
fmt.Println("\nSo, bye.")
return
}
s2 := strings.Fields(score)
if len(s2) == 2 {
c2, err := strconv.ParseUint(s2[0], 10, 0)
if err == nil && c2 <= 4 {
b2, err := strconv.ParseUint(s2[1], 10, 0)
if err == nil && c2+b2 <= 4 {
c = uint(c2)
b = uint(b2)
break
}
}
}
}
// check for win
if b == 4 {
fmt.Println("I did it. :)")
return
}
// eliminate patterns with non-matching scores
for pat := range m {
var cows, bulls uint
for ig, cg := range guess {
switch strings.IndexRune(pat, cg) {
case -1:
default: // I just think cows should go first
cows++
case ig:
bulls++
}
}
if cows != c || bulls != b {
delete(m, pat)
}
}
// check for inconsistency
if len(m) == 0 {
fmt.Println("Oops, check scoring.")
return
}
}
}

View file

@ -0,0 +1,33 @@
import Data.List
import Control.Monad
import System.Random (randomRIO)
import Data.Char(digitToInt)
combinationsOf 0 _ = [[]]
combinationsOf _ [] = []
combinationsOf k (x:xs) = map (x:) (combinationsOf (k-1) xs) ++ combinationsOf k xs
player = do
let ps = concatMap permutations $ combinationsOf 4 ['1'..'9']
play ps where
play ps =
if null ps then
putStrLn "Unable to find a solution"
else do i <- randomRIO(0,length ps - 1)
let p = ps!!i :: String
putStrLn ("My guess is " ++ p) >> putStrLn "How many bulls and cows?"
input <- takeInput
let bc = input ::[Int]
ps' = filter((==sum bc).length. filter id. map (flip elem p))
$ filter((==head bc).length. filter id. zipWith (==) p) ps
if length ps' == 1 then putStrLn $ "The answer is " ++ head ps'
else play ps'
takeInput = do
inp <- getLine
let ui = map digitToInt $ take 2 $ filter(`elem` ['0'..'4']) inp
if sum ui > 4 || length ui /= 2 then
do putStrLn "Wrong input. Try again"
takeInput
else return ui

View file

@ -0,0 +1,14 @@
*Main> player
My guess is 4923
How many bulls and cows?
2 2
My guess is 3924
How many bulls and cows?
1 3
My guess is 4329
How many bulls and cows?
1 3
My guess is 4932
How many bulls and cows?
4 0
The answer is 4932

View file

@ -0,0 +1,17 @@
require'general/misc/prompt'
poss=:1+~.4{."1 (i.!9)A.i.9
fmt=: ' ' -.~ ":
play=: {{
while.1<#poss=.poss do.
echo 'guessing ',fmt guess=.({~ ?@#)poss
bc=. _".prompt 'how many bull and cows? '
poss=.poss #~({.bc)=guess+/@:="1 poss
poss=.poss #~(+/bc)=guess+/@e."1 poss
end.
if.#poss do.
'the answer is ',fmt,poss
else.
'no valid possibilities'
end.
}}

View file

@ -0,0 +1,10 @@
play''
guessing 7461
how many bull and cows? 0 1
guessing 3215
how many bull and cows? 0 3
guessing 2357
how many bull and cows? 2 0
guessing 1359
how many bull and cows? 3 0
the answer is 1358

View file

@ -0,0 +1,80 @@
public class BullsAndCowsPlayerGame {
private static int count;
private static Console io = System.console();
private final GameNumber secret;
private List<AutoGuessNumber> pool = new ArrayList<>();
public BullsAndCowsPlayerGame(GameNumber secret) {
this.secret = secret;
fillPool();
}
private void fillPool() {
for (int i = 123; i < 9877; i++) {
int[] arr = AutoGuessNumber.parseDigits(i, 4);
if (GameNumber.isGuess(arr)) {
pool.add(new AutoGuessNumber(i, 4));
}
}
}
public void play() {
io.printf("Bulls and Cows%n");
io.printf("==============%n");
io.printf("Secret number is %s%n", secret);
do {
AutoGuessNumber guess = guessNumber();
io.printf("Guess #%d is %s from %d%n", count, guess, pool.size());
GuessResult result = secret.match(guess);
if (result != null) {
printScore(io, result);
if (result.isWin()) {
io.printf("The answer is %s%n", guess);
break;
}
clearPool(guess, result);
} else {
io.printf("No more variants%n");
System.exit(0);
}
} while (true);
}
private AutoGuessNumber guessNumber() {
Random random = new Random();
if (pool.size() > 0) {
int number = random.nextInt(pool.size());
count++;
return pool.get(number);
}
return null;
}
private static void printScore(Console io, GuessResult result) {
io.printf("%1$d %2$d%n", result.getBulls(), result.getCows());
}
private void clearPool(AutoGuessNumber guess, GuessResult guessResult) {
pool.remove(guess);
for (int i = 0; i < pool.size(); i++) {
AutoGuessNumber g = pool.get(i);
GuessResult gr = guess.match(g);
if (!guessResult.equals(gr)) {
pool.remove(g);
}
}
}
public static void main(String[] args) {
new BullsAndCowsPlayerGame(new GameNumber()).play();
}
}

View file

@ -0,0 +1,39 @@
public abstract class AbstractGuessNumber {
protected int[] digits;
private int length;
public AbstractGuessNumber(int length) {
this.length = length;
this.digits = new int[this.length];
}
public int[] getDigits() {
return digits;
}
public int getLength() {
return length;
}
public GuessResult match(AbstractGuessNumber guessable) {
int bulls = 0;
int cows = 0;
if (guessable != null) {
for (int i = 0; i < this.getLength(); i++) {
for (int j = 0; j < guessable.getLength(); j++) {
if (digits[i] == guessable.getDigits()[j]) {
if (i == j) {
bulls++;
} else {
cows++;
}
}
}
}
}
return new GuessResult(getLength(), bulls, cows);
}
}

View file

@ -0,0 +1,69 @@
public class GameNumber extends AbstractGuessNumber {
public GameNumber() {
super(4);
defineNumber();
}
public static boolean isGuess(int[] digits) {
return (digits != null && isUnique(digits) && isAllDigits(digits));
}
protected static boolean isAllDigits(int[] array) {
for (int i = 0; i < array.length; i++) {
char digit = (char) (array[i] + '0');
if (!Character.isDigit(digit)) {
return false;
}
}
return true;
}
protected static boolean isUnique(int[] array) {
for (int j = 0; j < array.length; j++) {
int a = array[j];
for (int i = 0; i < j; i++) {
if (a == array[i]) {
// seen this int before
return false;
}
}
}
return true;
}
public static int[] parseDigits(int number, int length) {
int[] arr = new int[length];
int temp = number;
for (int i = length - 1; i >= 0; i--) {
arr[i] = temp % 10;
temp /= 10;
}
return arr;
}
protected void defineNumber() {
int[] arr = generateRandom();
for (int i = 0; i < getLength(); i++) {
digits[i] = arr[i];
}
}
private int[] generateRandom() {
int[] arr;
do {
Random random = new Random();
int number = random.nextInt(9877) + 123;
arr = parseDigits(number, getLength());
} while (!isGuess(arr));
return arr;
}
@Override
public String toString() {
return Arrays.toString(digits);
}
}

View file

@ -0,0 +1,30 @@
public class AutoGuessNumber extends AbstractGuessNumber {
public AutoGuessNumber(int number, int lenght) {
super(lenght);
defineNumber(number);
}
public static int[] parseDigits(int number, int length) {
int[] arr = new int[length];
int temp = number;
for (int i = length - 1; i >= 0; i--) {
arr[i] = temp % 10;
temp /= 10;
}
return arr;
}
protected void defineNumber(int number) {
int[] arr = parseDigits(number, getLength());
for (int i = 0; i < getLength(); i++) {
digits[i] = arr[i];
}
}
@Override
public String toString() {
return Arrays.toString(digits);
}
}

View file

@ -0,0 +1,49 @@
public class GuessResult {
private static int guessNum = 0;
private int bulls;
private int cows;
private int length;
public GuessResult(int length, int bulls, int cows) {
this.length = length;
this.bulls = bulls;
this.cows = cows;
guessNum++;
}
public int getBulls() {
return bulls;
}
public int getCows() {
return cows;
}
public boolean isWin() {
return (bulls == length);
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("GuessResult {");
sb.append("bulls=").append(bulls);
sb.append(", cows=").append(cows);
sb.append('}');
return sb.toString();
}
public int getId() {
return guessNum;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GuessResult that = (GuessResult) o;
return bulls == that.bulls &&
cows == that.cows &&
length == that.length;
}
}

View file

@ -0,0 +1,28 @@
countbulls(a, b) = sum([a[i] == b[i] for i in 1:length(a)])
countcows(a, b) = sum([a[i] == b[j] for i in 1:length(a), j in 1:length(b) if i != j])
validate(a, b) = typeof(a) == Int && typeof(b) == Int && a >= 0 && b >= 0 && a + b < 5
function doguess()
poss = [a for a in collect(Base.product(1:9,1:9,1:9,1:9)) if length(unique(a))[1]==4]
while(length(poss) > 0)
ans = rand(poss, 1)[1]
while true
println("My guess: $(ans[1])$(ans[2])$(ans[3])$(ans[4]). How many bulls and cows?")
regres = match(r"\D*(\d+)\D*(\d+)", readline())
bul, cow = parse(Int,regres[1]), parse(Int,regres[2])
if(validate(bul, cow))
break
else
println("Please enter an integer each for bulls and cows.")
end
end
if(bul == 4)
return ans
end
filter!(i -> (countbulls(ans,i), countcows(ans, i)) == (bul, cow), poss)
end
Base.throw("ERROR: No solutions found. Inconsistent scoring by other player?")
end
answ = doguess()
println("The winning pick: $(answ[1])$(answ[2])$(answ[3])$(answ[4])")

View file

@ -0,0 +1,15 @@
My guess: 9517. How many bulls and cows?
0 1
My guess: 3285. How many bulls and cows?
1 1
My guess: 4298. How many bulls and cows?
0 2
My guess: 2465. How many bulls and cows?
0 2
My guess: 3926. How many bulls and cows?
2 0
My guess: 3724. How many bulls and cows?
3 0
My guess: 3124. How many bulls and cows?
4 0
The winning pick: 3124

View file

@ -0,0 +1,52 @@
// version 1.1.2
import java.util.Random
fun countBullsAndCows(guess: IntArray, answer: IntArray): Pair<Int,Int> {
var bulls = 0
var cows = 0
for ((i, d) in guess.withIndex()) {
if (answer[i] == d) bulls++
else if (d in answer) cows++
}
return bulls to cows
}
fun main(args: Array<String>) {
val r = Random()
val choices = mutableListOf<IntArray>()
// generate all possible distinct 4 digit (1 to 9) integer arrays
for (i in 1..9) {
for (j in 1..9) {
if (j == i) continue
for (k in 1..9) {
if (k == i || k == j) continue
for (l in 1..9) {
if (l == i || l == j || l == k) continue
choices.add(intArrayOf(i, j, k, l))
}
}
}
}
// pick one at random as the answer
val answer = choices[r.nextInt(choices.size)]
// keep guessing, pruning the list as we go based on the score, until answer found
while (true) {
val guess = choices[r.nextInt(choices.size)]
val (bulls, cows) = countBullsAndCows(guess, answer)
println("Guess = ${guess.joinToString("")} Bulls = $bulls Cows = $cows")
if (bulls == 4) {
println("You've just found the answer!")
return
}
for (i in choices.size - 1 downTo 0) {
val (bulls2, cows2) = countBullsAndCows(choices[i], answer)
// if score is no better remove it from the list of choices
if (bulls2 <= bulls && cows2 <= cows) choices.removeAt(i)
}
if (choices.size == 0)
println("Something went wrong as no choices left! Aborting program")
}
}

View file

@ -0,0 +1,99 @@
guesses =0
do while len( secret$) <4 ' zero not allowed <<<<<<<<<
n$ =chr$( int( rnd( 1) *9) +49)
if not( instr( secret$, n$)) then secret$ =secret$ +n$
loop
print " Secretly, my opponent just chose a number. But she didn't tell anyone! "; secret$; "."
print " I can however be given a score for my guesses."
for i =1234 to 9876 ' <<<<<<<<<
if check( str$( i)) =0 then available$ =available$ +" " +str$( i): k =k +1
next i
available$ =trim$( available$) ' remove the surplus, leading space
print
print "Currently holding "; k; " possible numbers. "
while 1
guess$ =word$( available$, 1 +int( k *rnd( 1)), " ")
print
print "Computer guessed "; guess$; " & got ";
bulls =0
cows =0
guesses =guesses +1
r$ =score$( guess$, secret$)
bulls =val( word$( r$, 1, ","))
cows =val( word$( r$, 2, ","))
print bulls; " bull(s), and "; cows; " cow(s), .... ";
if guess$ =secret$ then
print "Computer won after "; guesses; " guesses!";
secs =( time$( "seconds") -now +86400) mod 86400
print " That took "; secs; " seconds. ENDED!"
print
print " Now scroll right to see original choice and check!"
exit while
end if
print " so possible numbers are now only..."
kk =0
new$ =""
for j =1 to k
bullsT =0
cowsT =0
possible$ =word$( available$, j, " ")
r$ =score$( guess$, possible$)
bullsT =val( word$( r$, 1, ","))
cowsT =val( word$( r$, 2, ","))
if ( bullsT =bulls) and ( cowsT =cows) then
new$ =new$ +" " +possible$ ' keep those with same score
kk =kk +1
print possible$; " ";
if ( kk mod 20) =0 then print
end if
scan
next j
available$ =trim$( new$)
k =kk
scan
wend
end
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
next i
score$ =str$( bulls); ","; str$( cows)
end function
function check( i$)
check =0 ' zero flags available: 1 means not available
for i =1 to 3
for j =i +1 to 4
if mid$( i$, i, 1) =mid$( i$, j, 1) then check =1
next j
next i
if instr( i$, "0") then check =1
end function

View file

@ -0,0 +1,111 @@
local line = "---------+----------------------------------+-------+-------+"
local digits = {1,2,3,4,5,6,7,8,9}
function and_bits (a, b)
-- print (a, b)
return a & b -- Lua 5.3
end
function or_bits (a, b)
return a | b -- Lua 5.3
end
function get_digits (n)
local tDigits = {}
for i = 1, #digits do tDigits[i] = digits[i] end
local ret = {}
math.randomseed(os.time())
for i = 1, n do
local d = table.remove (tDigits, math.random(#tDigits))
table.insert (ret, d)
end
return ret
end
function mask (x)
return 3*x-1 -- any function
end
function score (guess, goal)
local bits, bulls, cows = 0, 0, 0
for i = 1, #guess do
if (guess[i] == goal[i]) then
bulls = bulls + 1
else
bits = bits + mask (goal[i])
end
end
for i = 1, #guess do
if not (guess[i] == goal[i]) then
local nCow = (and_bits (bits, mask(guess[i])) == 0) and 0 or 1
cows = cows + nCow
end
end
return bulls, cows
end
function iCopy (list)
local nList = {}
for i = 1, #list do nList[i] = list[i] end
return nList
end
function pick (list, n, got, marker, buf)
-- print ('pick', #list, n)
local bits = 1
if got >= n then
table.insert (list, buf)
else
local bits = 1
for i = 1, #digits do
if and_bits(marker,bits) == 0 then
buf[got+1] = i
pick (list, n, got+1, or_bits (marker, bits), iCopy(buf))
end
bits = bits * 2
end
end
end
function filter_list (list, guess, bulls, cows)
local index = 1
for i = 1, #list do
-- print ('filter_list i: ' .. i)
local scoreBulls, scoreCows = score (guess, list[i])
if bulls == scoreBulls and cows == scoreCows then
list[index] = list[i]
index = index + 1
end
end
for i = #list, index+1, -1 do
table.remove (list, i)
end
end
function game (goal)
local n = #goal
local attempt = 1
local guess = {} -- n-length guess numbers array
for i = 1, n do table.insert (guess, 0) end -- empty buffer
local list = {}
pick (list, n, 0, 0, guess)
local bulls, cows = 0, 0
while true do
guess = list[1]
bulls, cows = score (guess, goal)
print (' Guess ' .. attempt .. ' | ' ..table.concat(guess), '('..#list..' variants) ', bulls, cows)
if bulls == n then return end
filter_list (list, guess, bulls, cows)
attempt = attempt + 1
end
end
local n = 4
local secret = get_digits (n)
print (line..'\nSecret '.. #secret.. ' | '..table.concat(secret) .. ' | Bulls | Cows |' .. '\n' .. line)
game (secret)

View file

@ -0,0 +1,58 @@
function BullsAndCowsPlayer
% Plays the game Bulls and Cows as the player
% Generate list of all possible numbers
nDigits = 4;
lowVal = 1;
highVal = 9;
combs = nchoosek(lowVal:highVal, nDigits);
nCombs = size(combs, 1);
nPermsPerComb = factorial(nDigits);
gList = zeros(nCombs.*nPermsPerComb, nDigits);
for k = 1:nCombs
gList(nPermsPerComb*(k-1)+1:nPermsPerComb*k, :) = perms(combs(k, :));
end
% Prompt user
fprintf('Think of a number with:\n')
fprintf(' %d digits\n', nDigits)
fprintf(' Each digit between %d and %d inclusive\n', lowVal, highVal)
fprintf(' No repeated digits\n')
fprintf('I''ll try to guess that number and you score me:\n')
fprintf(' 1 Bull per correct digit in the correct place\n')
fprintf(' 1 Cow per correct digit in the wrong place\n')
fprintf('Think of your number and press Enter when ready\n')
pause
% Play game until all digits are correct
nBulls = 0;
nGuesses = 0;
while nBulls < 4 && ~isempty(gList)
nList = size(gList, 1);
g = gList(randi(nList), :); % Random guess from list
fprintf('My guess: %s?\n', sprintf('%d', g))
nBulls = input('How many bulls? ');
if nBulls < 4
nCows = input('How many cows? ');
del = false(nList, 1);
for k = 1:nList
del(k) = any([nBulls nCows] ~= CountBullsCows(g, gList(k, :)));
end
gList(del, :) = [];
end
nGuesses = nGuesses+1;
end
if isempty(gList)
fprintf('That''s bull! You messed up your scoring.\n')
else
fprintf('Yay, I won! Only took %d guesses.\n', nGuesses)
end
end
function score = CountBullsCows(guess, correct)
% Checks the guessed array of digits against the correct array to find the score
% Assumes arrays of same length and valid numbers
bulls = guess == correct;
cows = ismember(guess(~bulls), correct);
score = [sum(bulls) sum(cows)];
end

View file

@ -0,0 +1,14 @@
bullCow={Count[#1-#2,0],Length[#1\[Intersection]#2]-Count[#1-#2,0]}&;
Module[{r,input,candidates=Permutations[Range[9],{4}]},
While[True,
r=InputString[];
If[r===$Canceled,Break[],
input=ToExpression/@StringSplit@r;
If[Length@input!=3,Print["Input the guess, number of bulls, number of cows, delimited by space."],
candidates=Select[candidates,bullCow[ToCharacterCode@StringJoin[ToString/@#],ToCharacterCode@ToString@input[[1]]]==input[[2;;3]]&];
candidates=SortBy[candidates,{-3,-1}.bullCow[ToCharacterCode@StringJoin[ToString/@#],ToCharacterCode@ToString@input[[1]]]&];
If[candidates==={},Print["No more candidates."];Break[]];
If[Length@candidates==1,Print["Must be: "<>StringJoin[ToString/@candidates[[1]]]];Break[]];
Print[ToString@Length@candidates<>" candidates remaining."];
Print["Can try "<>StringJoin[ToString/@First@candidates]<>"."];
]]]]

View file

@ -0,0 +1,133 @@
import parseutils
import random
import sequtils
import strformat
import strutils
const
Digits = "123456789"
DigitSet = {Digits[0]..Digits[^1]}
Size = 4
InvalidScore = -1
type
Digit = range['1'..'9']
Score = tuple[bulls, cows: int]
HistItem = tuple[guess: string, bulls, cows: int]
#---------------------------------------------------------------------------------------------------
proc buildChoices(digits: set[Digit]; size: Natural): seq[string] =
## Build the list of choices when starting the game.
if size == 0:
return @[""]
for d in digits:
for s in buildChoices(digits - {d}, size - 1):
result.add(d & s)
#---------------------------------------------------------------------------------------------------
proc getValues(): Score =
## Read the number of bulls and cows provided by the user.
let input = stdin.readLine().strip()
let fields = input.splitWhitespace()
if fields.len != 2 or
fields[0].parseInt(result.bulls, 0) == 0 or result.bulls notin 0..Size or
fields[1].parseInt(result.cows, 0) == 0 or result.cows notin 0..Size:
echo &"Wrong input; expected two number between 0 and {Size}"
return (InvalidScore, InvalidScore)
if result.bulls + result.cows > Size:
echo &"Total number of bulls and cows exceeds {Size}"
return (InvalidScore, InvalidScore)
#---------------------------------------------------------------------------------------------------
func score(value, guess: string): Score =
## Return the score of "guess" against "value".
for idx, digit in guess:
if digit == value[idx]:
inc result.bulls
elif digit in value:
inc result.cows
#---------------------------------------------------------------------------------------------------
proc findError(history: seq[HistItem]) =
## Find the scoring error.
var value: string
## Get the number to find.
while true:
stdout.write("What was the number to find? ")
value = stdin.readLine().strip()
if value.len == Size and allCharsInSet(value, DigitSet) and value.deduplicate.len == Size:
break
# Find inconsistencies.
for (guess, userbulls, usercows) in history:
let (bulls, cows) = score(guess, value)
if userbulls != bulls or usercows != cows:
echo &"For guess {guess}, score was wrong:"
echo &" Expected {bulls} / {cows}, got {userBulls} / {userCows}."
#---------------------------------------------------------------------------------------------------
func suffix(n: Positive): string =
## Return the suffix for an ordinal.
case n
of 1: "st"
of 2: "nd"
of 3: "rd"
else: "th"
#---------------------------------------------------------------------------------------------------
var history: seq[HistItem]
randomize()
var choices = buildChoices(DigitSet, Size)
choices.shuffle()
echo "Choose a number with four unique digits between 1 and 9."
echo "Give the number of bulls and cows separated by one or more spaces."
var guesses = 0
var remaining: seq[string]
while true:
inc guesses
var userbulls, usercows: int
let guess = choices.pop()
echo &"My {guesses}{suffix(guesses)} guess is {guess}"
# Get scoring.
while true:
stdout.write("How many bulls and cows? ")
(userbulls, usercows) = getValues()
if userbulls != InvalidScore and usercows != InvalidScore:
break
if userbulls == Size:
echo &"Victory! I found the number in {guesses} attempts."
break
history.add((guess, userbulls, usercows))
# Eliminate incompatible choices.
remaining.setLen(0)
for choice in choices:
let (bulls, cows) = score(guess, choice)
if bulls == userbulls and cows == usercows:
remaining.add(choice)
if remaining.len == 0:
echo &"There is an impossibility. For some guess you made an error in scoring."
history.findError()
break
choices = move(remaining)

View file

@ -0,0 +1,53 @@
#!/usr/bin/perl
use warnings;
use strict;
use v5.10;
# Build a list of all possible solutions. The regular expression weeds
# out numbers containing zeroes or repeated digits. See how Perl
# automatically converts numbers to strings for us, just because we
# use them as if they were strings:
my @candidates = grep {not /0 | (\d) .* \1 /x} 1234 .. 9876;
# Repeatedly prompt for input until the user supplies a reasonable score.
# The regex validates the user's input and then returns two numbers,
# $+{BULLS} and $+{COWS}.
sub read_score :prototype($) {
(my $guess) = @_;
for (;;) {
say "My guess: $guess (from ", 0+@candidates, " possibilities)";
if (<> =~ / ^ \h* (?<BULLS> \d) \h* (?<COWS> \d) \h* $ /x and
$+{BULLS} + $+{COWS} <= 4) {
return ($+{BULLS}, $+{COWS});
}
say "Please specify the number of bulls and the number of cows";
}
}
sub score_correct :prototype($$$$) {
my ($a, $b, $bulls, $cows) = @_;
# Count the positions at which the digits match:
my $exact = () = grep {substr($a, $_, 1) eq substr($b, $_, 1)} 0 .. 3;
# Cross-match all digits in $a against all digits in $b, using a regex
# (specifically, a character class) instead of an explicit loop:
my $loose = () = $a =~ /[$b]/g;
return $bulls == $exact && $cows == $loose - $exact;
}
do {
# Pick a number, display it, get the score, and discard candidates
# that don't match the score:
my $guess = @candidates[rand @candidates];
my ($bulls, $cows) = read_score $guess;
@candidates = grep {score_correct $_, $guess, $bulls, $cows} @candidates;
} while (@candidates > 1);
say(@candidates?
"Your secret number is @candidates":
"I think you made a mistake with your scoring");

View file

@ -0,0 +1,11 @@
msl@64Lucid:~/perl$ ./bulls-and-cows
My guess: 1869 (from 3024 possibilities)
1 0
My guess: 3265 (from 240 possibilities)
0 2
My guess: 7853 (from 66 possibilities)
1 2
My guess: 7539 (from 7 possibilities)
0 3
Your secret number is 1357
msl@64Lucid:~/perl$

View file

@ -0,0 +1,73 @@
(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">line</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">" +---------+-----------------------------+-------+------+\n"</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">digits</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"123456789"</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">mask</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">-</span><span style="color: #008000;">'1'</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">score</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">guess</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">goal</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">bits</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">bulls</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cows</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">guess</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">guess</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">goal</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">bulls</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">bits</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">mask</span><span style="color: #0000FF;">(</span><span style="color: #000000;">goal</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">guess</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">cows</span> <span style="color: #0000FF;">+=</span> <span style="color: #0000FF;">(</span><span style="color: #7060A8;">and_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bits</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mask</span><span style="color: #0000FF;">(</span><span style="color: #000000;">guess</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]))!=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">bulls</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cows</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">list</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">pick</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">got</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">marker</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">buf</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">got</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">n</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">list</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">list</span><span style="color: #0000FF;">,</span><span style="color: #000000;">buf</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">bits</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">digits</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">and_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">marker</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bits</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">buf</span><span style="color: #0000FF;">[</span><span style="color: #000000;">got</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #008000;">'1'</span>
<span style="color: #000000;">pick</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">got</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">or_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">marker</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bits</span><span style="color: #0000FF;">),</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">buf</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">bits</span> <span style="color: #0000FF;">*=</span> <span style="color: #000000;">2</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">filter_list</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">guess</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">bulls</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cows</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">idx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">bc</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">bulls</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cows</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">list</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">score</span><span style="color: #0000FF;">(</span><span style="color: #000000;">guess</span><span style="color: #0000FF;">,</span><span style="color: #000000;">list</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])=</span><span style="color: #000000;">bc</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">idx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">list</span><span style="color: #0000FF;">[</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">list</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">list</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">list</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">game</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">tgt</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tgt</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">attempt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">pick</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'\0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">guess</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">list</span><span style="color: #0000FF;">[</span><span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">list</span><span style="color: #0000FF;">))]</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">bulls</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cows</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">score</span><span style="color: #0000FF;">(</span><span style="color: #000000;">guess</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tgt</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" | Guess %-2d| %9s %-14s | %d | %d |\n"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">attempt</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">guess</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"(from %d)"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">list</span><span style="color: #0000FF;">)),</span> <span style="color: #000000;">bulls</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cows</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">bulls</span><span style="color: #0000FF;">=</span><span style="color: #000000;">n</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">filter_list</span><span style="color: #0000FF;">(</span><span style="color: #000000;">guess</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">bulls</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cows</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">attempt</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">line</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">N</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">4</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">secret</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">shuffle</span><span style="color: #0000FF;">(</span><span style="color: #000000;">digits</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">N</span><span style="color: #0000FF;">]</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s | Secret | %9s | BULLS | COWS |\n%s"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">line</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">secret</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">line</span><span style="color: #0000FF;">})</span>
<span style="color: #000000;">game</span><span style="color: #0000FF;">(</span><span style="color: #000000;">secret</span><span style="color: #0000FF;">)</span>
<!--

View file

@ -0,0 +1,19 @@
(load "@lib/simul.l")
(de bullsAndCows ()
(let Choices (shuffle (mapcan permute (subsets 4 (range 1 9))))
(use (Guess Bulls Cows)
(loop
(prinl "Guessing " (setq Guess (pop 'Choices)))
(prin "How many bulls and cows? ")
(setq Bulls (read) Cows (read))
(setq Choices
(filter
'((C)
(let B (cnt = Guess C)
(and
(= Bulls B)
(= Cows (- (length (sect Guess C)) B)) ) ) )
Choices ) )
(NIL Choices "No matching solution")
(NIL (cdr Choices) (pack "The answer is " (car Choices))) ) ) ) )

View file

@ -0,0 +1,132 @@
:- module('ia.pl', [tirage/1]).
:- use_module(library(clpfd)).
% to store the previous guesses and the answers
:- dynamic guess/2.
% parameters of the engine
% length of the guess
proposition(4).
% Numbers of digits
% 0 -> 8
digits(8).
% tirage(-)
tirage(Ms) :-
% are there previous guesses ?
( bagof([P, R], guess(P,R), Propositions)
-> tirage(Propositions, Ms)
; % First try
tirage_1(Ms)),
!.
% tirage_1(-)
% We choose the first Len numbers
tirage_1(L):-
proposition(Len),
Max is Len-1,
numlist(0, Max, L).
% tirage(+,-)
tirage(L, Ms) :-
proposition(Len),
length(Ms, Len),
digits(Digits),
% The guess contains only this numbers
Ms ins 0..Digits,
all_different(Ms),
% post the constraints
maplist(placees(Ms), L),
% compute a possible solution
label(Ms).
% placees(+, +])
placees(Sol, [Prop, [BP, MP]]) :-
V #= 0,
% compute the numbers of digits in good places
compte_bien_placees(Sol, Prop, V, BP1),
BP1 #= BP,
% compute the numbers of digits inbad places
compte_mal_placees(Sol, Prop, 0, V, MP1),
MP1 #= MP.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% compte_mal_placees(+, +, +, +, -).
% @arg1 : guess to create
% @arg2 : guess already used
% @arg3 : range of the first digit of the previuos arg
% @arg4 : current counter of the digit in bad places
% @arg5 : final counter of the digit in bad places
%
%
compte_mal_placees(_, [], _, MP, MP).
compte_mal_placees(Sol, [H | T], N, MPC, MPF) :-
compte_une_mal_placee(H, N, Sol, 0, 0, VF),
MPC1 #= MPC + VF,
N1 is N+1,
compte_mal_placees(Sol, T, N1, MPC1, MPF).
% Here we check one digit of an already done guess
% compte_une_mal_placee(+, +, +, +, -).
% @arg1 : the digit
% @arg2 : range of this digit
% @arg3 : guess to create
% we check each digit of this guess
% @arg4 : range of the digit of this guess
% @arg5 : current counter of the digit in bad places
% @arg6 : final counter of the digit in bad places
%
compte_une_mal_placee(_H, _N, [], _, TT, TT).
% digit in the same range, continue
compte_une_mal_placee(H, NH, [_H1 | T], NH, TTC, TTF) :-
NH1 is NH + 1, !,
compte_une_mal_placee(H, NH, T, NH1, TTC, TTF).
% same digit in different places
% increment the counter and continue continue
compte_une_mal_placee(H, NH, [H1 | T], NH1, TTC, TTF) :-
H #= H1,
NH \= NH1,
NH2 is NH1 + 1,
TTC1 #= TTC + 1,
compte_une_mal_placee(H, NH, T, NH2, TTC1, TTF).
compte_une_mal_placee(H, NH, [H1 | T], NH1, TTC, TTF) :-
H #\= H1,
NH2 is NH1 + 1,
compte_une_mal_placee(H, NH, T, NH2, TTC, TTF).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% compte_bien_placees(+, +, +, -)
% @arg1 : guess to create
% @arg2 : previous guess
% @arg3 : current counter of the digit in good places
% @arg4 : final counter of the digit in good places
%
%
compte_bien_placees([], [], MP, MP).
compte_bien_placees([H | T], [H1 | T1], MPC, MPF) :-
H #= H1,
MPC1 #= MPC + 1,
compte_bien_placees(T, T1, MPC1, MPF).
compte_bien_placees([H | T], [H1 | T1], MPC, MPF) :-
H #\= H1,
compte_bien_placees(T, T1, MPC, MPF).

View file

@ -0,0 +1,21 @@
bulls_and_cows :-
retractall('ia.pl':guess(_,_)),
retractall(coups(_)),
assert(coups(1)),
repeat,
( tirage(Ms)
-> maplist(add_1, Ms, Ms1),
atomic_list_concat(Ms1, Guess),
retract(coups(Coup)),
Coup_1 is Coup + 1,
assert(coups(Coup_1)),
format('~w My guess ~w~n', [Coup, Guess]),
write('Bulls : '), read(Bulls),
write('Cows : '), read(Cows), nl,
assert('ia.pl':guess(Ms, [Bulls, Cows])),
Bulls = 4
; writeln('Sorry, I can''t find a solution !'), true).
add_1(X, Y) :-
Y is X + 1.

View file

@ -0,0 +1,106 @@
#answerSize = 4
Structure history
answer.s
bulls.i
cows.i
EndStructure
Procedure evaluateGuesses(*answer.history, List remainingGuesses.s())
Protected i, cows, bulls
ForEach remainingGuesses()
bulls = 0: cows = 0
For i = 1 To #answerSize
If Mid(remainingGuesses(), i, 1) = Mid(*answer\answer, i, 1)
bulls + 1
ElseIf FindString(remainingGuesses(), Mid(*answer\answer, i, 1), 1)
cows + 1
EndIf
Next
If bulls <> *answer\bulls Or cows <> *answer\cows
DeleteElement(remainingGuesses())
EndIf
Next
EndProcedure
Procedure findPermutations(List permutations.s(), elementChar.s, permSize)
Protected i, j, stackDepth, elementCount = Len(elementChar) - 1, working.s = Space(permSize), *working = @working
permSize - 1
Dim stack(permSize) ;holds index states
Dim elements(elementCount)
Dim elementChar.c(elementCount)
For i = 0 To elementCount
elementChar(i) = PeekC(@elementChar + i * SizeOf(Character))
Next
i = 0
Repeat
While i <= elementCount
If elements(i) = 0
stack(stackDepth) = i
If stackDepth = permSize
For j = 0 To permSize
PokeC(*working + j * SizeOf(Character), elementChar(stack(j)))
Next
AddElement(permutations())
permutations() = working
Else
elements(i) = 1
stackDepth + 1
i = 0
Continue ;skip update
EndIf
EndIf
i + 1
Wend
stackDepth - 1
If stackDepth < 0
Break
EndIf
i = stack(stackDepth) + 1
elements(i - 1) = 0
ForEver
EndProcedure
If OpenConsole()
Define guess.s, guessNum, score.s, delimeter.s
NewList remainingGuesses.s()
NewList answer.history()
findPermutations(remainingGuesses(), "123456789", 4)
PrintN("Playing Bulls & Cows with " + Str(#answerSize) + " unique digits." + #CRLF$)
Repeat
If ListSize(remainingGuesses()) = 0
If answer()\bulls = #answerSize And answer()\cows = 0
PrintN(#CRLF$ + "Solved!")
Break ;exit Repeat/Forever
EndIf
PrintN(#CRLF$ + "BadScoring! Nothing fits the scores you gave.")
ForEach answer()
PrintN(answer()\answer + " -> [" + Str(answer()\bulls) + ", " + Str(answer()\cows) + "]")
Next
Break ;exit Repeat/Forever
Else
guessNum + 1
SelectElement(remainingGuesses(), Random(ListSize(remainingGuesses()) - 1))
guess = remainingGuesses()
DeleteElement(remainingGuesses())
Print("Guess #" + Str(guessNum) + " is " + guess + ". What does it score (bulls, cows)?")
score = Input()
If CountString(score, ",") > 0: delimeter = ",": Else: delimeter = " ": EndIf
AddElement(answer())
answer()\answer = guess
answer()\bulls = Val(StringField(score, 1, delimeter))
answer()\cows = Val(StringField(score, 2, delimeter))
evaluateGuesses(@answer(), remainingGuesses())
EndIf
ForEver
Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
CloseConsole()
EndIf

View file

@ -0,0 +1,55 @@
from itertools import permutations
from random import shuffle
try:
raw_input
except:
raw_input = input
try:
from itertools import izip
except:
izip = zip
digits = '123456789'
size = 4
def parse_score(score):
score = score.strip().split(',')
return tuple(int(s.strip()) for s in score)
def scorecalc(guess, chosen):
bulls = cows = 0
for g,c in izip(guess, chosen):
if g == c:
bulls += 1
elif g in chosen:
cows += 1
return bulls, cows
choices = list(permutations(digits, size))
shuffle(choices)
answers = []
scores = []
print ("Playing Bulls & Cows with %i unique digits\n" % size)
while True:
ans = choices[0]
answers.append(ans)
#print ("(Narrowed to %i possibilities)" % len(choices))
score = raw_input("Guess %2i is %*s. Answer (Bulls, cows)? "
% (len(answers), size, ''.join(ans)))
score = parse_score(score)
scores.append(score)
#print("Bulls: %i, Cows: %i" % score)
found = score == (size, 0)
if found:
print ("Ye-haw!")
break
choices = [c for c in choices if scorecalc(c, ans) == score]
if not choices:
print ("Bad scoring? nothing fits those scores you gave:")
print (' ' +
'\n '.join("%s -> %s" % (''.join(an),sc)
for an,sc in izip(answers, scores)))
break

View file

@ -0,0 +1,27 @@
bullsAndCowsPlayer <- function()
{
guesses <- 1234:9876
#The next line is terrible code, but it's the most R way to convert a set of 4-digit numbers to their 4 digits.
guessDigits <- t(sapply(strsplit(as.character(guesses), ""), as.integer))
validGuesses <- guessDigits[apply(guessDigits, 1, function(x) length(unique(x)) == 4 && all(x != 0)), ]
repeat
{
remainingCasesCount <- nrow(validGuesses)
cat("Possibilities remaining:", remainingCasesCount)#Not required, but excellent when debugging.
guess <- validGuesses[sample(remainingCasesCount, 1), ]
guessAsOneNumber <- as.integer(paste(guess, collapse = ""))
bulls <- as.integer(readline(paste0("My guess is ", guessAsOneNumber, ". Bull score? [0-4] ")))
if(bulls == 4) return(paste0("Your number is ", guessAsOneNumber, ". I win!"))
cows <- as.integer(readline("Cow score? [0-4] "))
#If our guess scores y bulls, then only numbers containing exactly y digits with the same value and position (y "pseudoBulls") as in our guess can be correct.
#Accounting for the positions of cows not being fixed, the same argument also applies for them.
#The following lines make us only keep the numbers that have the right pseudoBulls and "pseudoCows" scores, albeit without the need for a pseudoCows function.
#We also use pseudoBulls != 4 to remove our most recent guess, because we know that it cannot be correct.
#Finally, the drop=FALSE flag is needed to stop R converting validGuesses to a vector when there is only one guess left.
pseudoBulls <- function(x) sum(x == guess)
isGuessValid <- function(x) pseudoBulls(x) == bulls && sum(x %in% guess) - pseudoBulls(x) == cows && pseudoBulls(x) != 4
validGuesses <- validGuesses[apply(validGuesses, 1, isGuessValid), , drop = FALSE]
if(nrow(validGuesses) == 0) return("Error: Scoring problem?")
}
}
bullsAndCowsPlayer()

View file

@ -0,0 +1,52 @@
/*REXX program plays the Bulls & Cows game with CBLFs (Carbon Based Life Forms). */
parse arg ? .; if datatype(?,'W') then call random ,,? /*Random seed? Make repeatable*/
L=1234; H=9876; call gen@ /*generate all possibilities. */
do forever; g=random(L,H); if @.g\==. then leave /*obtain a random 1st guess. */
end /*forever*/ /* [↑] obtain rand 1st guess.*/
$$1= ' How many bulls and cows were guessed with '; $$2=" ? [─── or QUIT]"
do until #()<2 | bull==4; say; call ask /*examine @ list; get answer.*/
do ?=L to H; if @.?==. then iterate /*is this already eliminated ?*/
call bull# ?,g /*obtain bulls and cows count.*/
if bull\==bulls | cow\==cows then @.?=. /*eliminate this possibility. */
end /*?*/
end /*until*/
if #==0 then do; call serr "At least one of your responses was invalid."; exit; end
say; say " ╔═════════════════════════════════════════════════╗"
say " ║ ║"
say " ║ Your secret Bulls and Cows number is: " g ""
say " ║ ║"
say " ╚═════════════════════════════════════════════════╝"; say
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
#: #=0; do k=L to H; if @.k==. then iterate; #=#+1; g=k; end; return #
gen@: @.=.; do j=L to H; if \rep() & pos(0, j)==0 then @.j=j; end; return
rep: do k=1 for 3; if pos(substr(j, k, 1), j, k+1)\==0 then return 1; end; return 0
serr: say; say ' ***error*** ' ! arg(1); return
/*──────────────────────────────────────────────────────────────────────────────────────*/
bull#: parse arg n,q; w=length(n); bulls=0 /*W: # digits in N; bull cntr=0 */
do j=1 for w; if substr(n, j, 1) \== substr(q, j, 1) then iterate
bulls=bulls+1; q=overlay(., q, j) /*bump counter; disallow for cow*/
end /*j*/ /* [↑] bull count═══════════════*/
cows=0 /*set the number of cows to zero.*/
do k=1 for w; _=substr(n, k, 1); if pos(_, q)==0 then iterate
cows=cows + 1; q=translate(q, , _) /*bump counter; allow multiple #*/
end /*k*/ /* [↑] cow count═══════════════*/
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
ask: do forever; say $$1 g $$2; pull x 1 bull cow . /*display prompt; obtain answer.*/
select /* [↑] PULL capitalizes the args*/
when abbrev('QUIT', x, 1) then exit /*the user wants to quit playing.*/
when bull == '' then != "no numbers were entered."
when cow == '' then != "not enough numbers were entered."
when words(x) > 2 then != "too many numbers entered: " x
when \datatype(bull, 'W') then != "1st number (bulls) not an integer: " bull
when \datatype(cow , 'W') then != "2nd number (cows) not an integer: " cow
when bull <0 | bull >4 then != "1st number (bulls) not 0 ──► 4: " bull
when cow <0 | cow >4 then != "2nd number (cows) not 0 ──► 4: " cow
when bull + cow > 4 then != "sum of bulls and cows can't be > 4: " x
otherwise !=
end /*select*/
if !\=='' then do; call serr; iterate; end /*prompt the user and try again. */
bull=bull/1; cow=cow/1; return /*normalize bulls & cows numbers.*/
end /*forever*/

View file

@ -0,0 +1,21 @@
#lang racket/base
(require racket/string
racket/list)
(define (permutations-getall items size)
(if (zero? size)
'(())
(for/list ([tail (in-list (permutations-getall items (- size 1)))]
#:when #t
[i (in-list items)]
#:unless (member i tail))
(cons i tail))))
(define digits (list 1 2 3 4 5 6 7 8 9))
(define size 4)
(define all-choices (shuffle (permutations-getall digits size)))
(define (listnum->string list)
(apply string-append (map number->string list)))

View file

@ -0,0 +1,13 @@
(define (parse-score score)
(if (string? score)
(let ([splited-score (string-split score ",")])
(if (= (length (string-split score ",")) 2)
(apply values (map (lambda (s) (string->number (string-trim s))) splited-score))
(values #f #f)))
(values #f #f)))
(define (calculate-score guess chosen)
(define (in-chosen x) (member x chosen))
(let ([bulls (count = guess chosen)]
[cows+bulls (count in-chosen guess)])
(values bulls (- cows+bulls bulls))))

View file

@ -0,0 +1,23 @@
(printf "Playing Bulls & Cows with ~a unique digits\n" size)
(let loop ([choices all-choices] [num 1])
(if (null? choices)
(printf "Bad scoring! nothing fits those scores you gave.")
(let ([guess (car choices)])
#;(printf "(Narrowed to ~a possibilities)\n" (length choices))
(printf "Guess #~a is ~a. Answer: Bulls, Cows? " num (listnum->string guess))
(let-values ([(bulls cows) (parse-score (read-line))])
;parse-score returns (#f #f) on errors
(if (and bulls cows)
(begin
(printf "Bulls: ~a, Cows: ~a\n" bulls cows)
(if (and (= bulls size) (= cows 0))
(printf "Ye-haw!")
(let ()
(define (equal-score? chosen)
(let-values ([(c-bulls c-cows) (calculate-score guess chosen)])
(and (= c-bulls bulls) (= c-cows cows))))
(loop (filter equal-score? choices) (+ num 1)))))
(begin
(printf "Sorry, I didn't understand that. Please try again.\n")
(loop choices num)))))))

View file

@ -0,0 +1,39 @@
# we use the [] reduction meta operator along with the Cartesian Product
# operator X to create the Cartesian Product of four times [1..9] and then get
# all the elements where the number of unique digits is four.
my @candidates = ([X] [1..9] xx 4).grep: *.unique == 4;
repeat {
my $guess = @candidates.pick;
my ($bulls, $cows) = read-score;
@candidates .= grep: &score-correct;
# note how we declare our two subroutines within the repeat block. This
# limits the scope in which the routines are known to the scope in which
# they are needed and saves us a lot of arguments to our two routines.
sub score-correct($a) {
my $exact = [+] $a >>==<< $guess;
# number of elements of $a that match any element of $b
my $loose = +$a.grep: any @$guess;
return $bulls == $exact && $cows == $loose - $exact;
}
sub read-score() {
loop {
my $score = prompt "My guess: {$guess.join}.\n";
if $score ~~ m:s/^ $<bulls>=(\d) $<cows>=(\d) $/
and $<bulls> + $<cows> <= 4 {
return +$<bulls>, +$<cows>;
}
say "Please specify the number of bulls and cows";
}
}
} while @candidates > 1;
say @candidates
?? "Your secret number is {@candidates[0].join}!"
!! "I think you made a mistake with your scoring.";

View file

@ -0,0 +1,32 @@
Red []
digits: charset [#"1" - #"9"] ;; bitset for parse rule in valid function
check: function [s i ][ ;; returns string with bulls -B and cows - C found
return sort append copy "" collect [
repeat pos 4 [ either ( v: pick i pos ) = pick s pos [ keep "B"][ if find s v [keep "C"] ] ]
]
]
valid: function [ i] [ all [ parse i [4 digits] "," 4 = length? unique i ] ] ;; check if number/string is valid
;; collect all possible permutations
possible: collect [ repeat i 9876 [ if valid s: to-string i [ keep s ] ] ] ;; should start at 1234, but for sake of brevity...
forever [ ;; read valid secret number from keyboard...
while [ not valid secret: ask "^/Enter Number with 4 uniq digits (1 - 9 only, q-quit ) " ] [ ;; "^/" is character for newline
either secret = "q" [print "Bye" halt ] [ print [ secret "invalid, Try again !" ] ]
]
results: copy #() ;; map (key-value ) to store each guess and its result
foreach guess possible [
foreach [k v] body-of results [ ;; check guess against previous results
if v <> check guess k [ guess: copy "" break ]
]
if empty? guess [ continue ] ;; check against previous results failed ?
put results guess res: check guess secret ;; store current guess and result in map
if res = "BBBB" [break] ;; number found ? then break foreach loop
]
foreach [k v] body-of results [ print [k "-" v]] ;; display all guesses and their results
print [CR "Found *" last k: keys-of results "* in " length? k " attempts" CR] ;; cr - constant for newline / carriage return
] ;; forever loop

View file

@ -0,0 +1,72 @@
# Project : Bulls and cows/Player
secret = ""
while len(secret) != 4
c = char(48 + random(9))
if substr(secret, c) = 0
secret = secret + c
ok
end
see "secret = " + secret + nl
possible = ""
for i = 1234 to 9876
possible = possible + string(i)
next
see "guess a four-digit number with no digit used twice." + nl
guesses = 0
while true
bulls = 0
cows = 0
if len(possible) = 4
guess = possible
else
guess = substr(possible, 4*random(len(possible) / 4) - 3, 4)
ok
see "computer guesses " + guess + nl
guesses = guesses + 1
if guess = secret
see "correctly guessed after " + guesses + " guesses!" + nl
exit
ok
if len(guess) = 4
count(secret, guess, bulls, cows)
ok
i = 1
testbulls = 0
testcows = 0
while i <= len(possible)
temp = substr(possible, i, 4)
if len(guess) = 4
count(temp, guess, testbulls, testcows)
ok
if bulls=testbulls
if cows=testcows
i = i + 4
ok
else
possible = left(possible, i-1) + substr(possible, i+4)
ok
end
if substr(possible, secret) = 0
exit
ok
end
func count(secret, guess, bulls, cows)
bulls = 0
cows = 0
for nr = 1 to 4
c = secret[nr]
if guess != 0
if guess[nr] = c
bulls = bulls + 1
if substr(guess, c) > 0
cows = cows + 1
ok
ok
ok
next
see "giving " + bulls + " bull(s) and " + cows + " cow(s)." + nl
return [bulls, cows]

View file

@ -0,0 +1,28 @@
size = 4
scores = []
guesses = []
puts "Playing Bulls & Cows with #{size} unique digits."
possible_guesses = [*'1'..'9'].permutation(size).to_a.shuffle
loop do
guesses << current_guess = possible_guesses.pop
print "Guess #{guesses.size} is #{current_guess.join}. Answer (bulls,cows)? "
scores << score = gets.split(',').map(&:to_i)
# handle win
break (puts "Yeah!") if score == [size,0]
# filter possible guesses
possible_guesses.select! do |guess|
bulls = guess.zip(current_guess).count{|g,cg| g == cg}
cows = size - (guess - current_guess).size - bulls
[bulls, cows] == score
end
# handle 'no possible guesses left'
if possible_guesses.empty?
puts "Error in scoring?"
guesses.zip(scores).each{|g, (b, c)| puts "#{g.join} => bulls #{b} cows #{c}"}
break
end
end

View file

@ -0,0 +1,34 @@
def allCombinations: Seq[List[Byte]] = {
(0 to 9).map(_.byteValue).toList.combinations(4).toList.flatMap(_.permutations)
}
def nextGuess(possible: Seq[List[Byte]]): List[Byte] = possible match {
case Nil => throw new IllegalStateException
case List(only) => only
case _ => possible(Random.nextInt(possible.size))
}
def doGuess(guess: List[Byte]): Pair[Int, Int] = {
println("My guess is " + guess);
val arr = readLine().split(' ').map(Integer.valueOf(_))
(arr(0), arr(1))
}
def testGuess(alt: List[Byte], guess: List[Byte]): Pair[Int, Int] = {
val bulls =alt.zip(guess).filter(p => p._1 == p._2).size
val cows = guess.filter(alt.contains(_)).size - bulls
(bulls, cows)
}
def play(possible: Seq[List[Byte]]): List[Byte] = {
val curGuess = nextGuess(possible)
val bc = doGuess(curGuess)
if (bc._1 == 4) { println("Ye-haw!"); curGuess }
else
play(possible.filter(p => testGuess(p, curGuess) == bc))
}
def main(args: Array[String]) {
play(allCombinations)
}

View file

@ -0,0 +1,121 @@
set the remoteWorkInterval to .001 -- optional
repeat forever
repeat forever
set description to "Enter a 4 digit number" & newline & "- zero's excluded" & newline & "- each digit should be unique" & newline
Ask "Enter a Number" title "Bulls & Cows (Player)" message description
put it into num
if num is ""
Answer "" with "Play" or "Quit" title "Quit Bulls & Cows (Player)?"
if it is "Quit"
exit all
end if
end if
set startTime to now
if number of characters in num is 4
if character 1 of num is not equal to character 2 of num
if character 1 of num is not equal to character 3 of num
if character 1 of num is not equal to character 4 of num
if character 2 of num is not equal to character 3 of num
if character 2 of num is not equal to character 4 of num
if character 3 of num is not equal to character 4 of num
if num does not contain 0
exit repeat
end if
end if
end if
end if
end if
end if
end if
end if
end repeat
set guess to 1111
set lastBullQty to 0
set digitLocation to 1
set cowVals to empty
repeat forever
set score to {
bulls: {
qty: 0,
values: {}
},
cows: {
qty: 0,
values: {}
}
}
repeat the number of characters in num times
if character the counter of guess is equal to character the counter of num
add 1 to score.bulls.qty
insert character the counter of guess into score.bulls.values
else
if num contains character the counter of guess
if character the counter of guess is not equal to character the counter of num
if score.bulls.values does not contain character the counter of guess and score.cows.values does not contain character the counter of guess
add 1 to score.cows.qty
if cowVals.(character the counter of guess) is empty
set cowVals.(character the counter of guess) to false
end if
end if
end if
end if
end if
end repeat
if guess is equal to num
put now - startTime into elapsedTime
set displayMessage to "Your Number:" && num & newline & "Guessed Number:" && guess & newline & newline & "Time Elapsed:" && elapsedTime.seconds && seconds
Answer displayMessage with "Play Again" or "Quit" title "Done!"
if it is "Quit"
exit all
end if
exit repeat
else
if the counter is greater than 1
if score.bulls.qty is not lastBullQty
if score.bulls.qty is greater than lastBullQty
if digitLocation is not 4 -- move on to the next digit
add 1 to digitLocation
else
set digitLocation to 1
end if
repeat for each (key,value) in cowVals
if score.bulls.values contains key
set cowVals.(key) to "bull"
else
set cowVals.(key) to false
end if
end repeat
else
subtract 1 from character digitLocation of guess -- stay on current digit
end if
set lastBullQty to score.bulls.qty -- save bull qty
else -- score.bulls.qty = lastBullQty
set cow_guessed to false
if cowVals is not empty
repeat for each (key,value) in cowVals
if value is false
set cow_guessed to true
set cowVals.(key) to true
if digitLocation is not 1
set character digitLocation of guess to key
exit repeat
else
add 1 to character digitLocation of guess
exit repeat
end if
end if
end repeat
if cow_guessed is false
if character digitLocation of guess is greater than 9
set character digitLocation of guess to 0 -- reset the current digit
end if
add 1 to character digitLocation of guess -- increment the current digit
end if
else
add 1 to character digitLocation of guess -- increment the current digit
end if
end if
end if
end if
end repeat
end repeat

View file

@ -0,0 +1,205 @@
#!/usr/local/bin/shale
maths library
file library
string library
lista var
listb var
firstTimeThrough var
guess var
guess0 var
guess1 var
guess2 var
guess3 var
bulls var
cows var
init dup var {
count a:: var
count b:: var
} =
randomDigit dup var {
random maths::() 18 >> 9 % 1 +
} =
makeGuess dup var {
firstTimeThrough {
guess0 randomDigit() =
guess1 randomDigit() =
{ guess1 guess0 == } { guess1 randomDigit() = } while
guess2 randomDigit() =
{ guess2 guess0 == guess2 guess1 == or } { guess2 randomDigit() = } while
guess3 randomDigit() =
{ guess3 guess0 == guess3 guess1 == guess3 guess2 == or or } { guess3 randomDigit() = } while
guess guess3 1000 * guess2 100 * guess1 10 * guess0 + + + =
} {
i var
i random maths::() count lista->:: % =
guess i.value lista->:: value =
guess0 guess 10 % =
guess1 guess 10 / 10 % =
guess2 guess 100 / 10 % =
guess3 guess 1000 / =
} if
} =
getAnswer dup var {
stdin file:: fgets file::() {
atoi string::()
} {
0 exit
} if
} =
getScore dup var {
haveBulls dup var false =
haveCows dup var false =
ans var
{ haveBulls not } {
"Bulls: " print
ans getAnswer() =
ans 0 < ans 4 > and {
"Please try again" println
} {
bulls ans =
haveBulls true =
} if
} while
{ haveCows not } {
"Cows: " print
ans getAnswer() =
ans 0 < ans 4 > and {
"Please try again" println
} {
cows ans =
haveCows true =
} if
} while
} =
check dup var {
d0 dup var swap = // units
d1 dup var swap =
d2 dup var swap =
d3 dup var swap = // thousands
b dup var 0 =
c dup var 0 =
d0 guess0 == { b++ } { d0 guess1 == { d0 guess2 == { d0 guess3 == } or } or { c++ } ifthen } if
d1 guess1 == { b++ } { d1 guess0 == { d1 guess2 == { d1 guess3 == } or } or { c++ } ifthen } if
d2 guess2 == { b++ } { d2 guess0 == { d2 guess1 == { d2 guess3 == } or } or { c++ } ifthen } if
d3 guess3 == { b++ } { d3 guess0 == { d3 guess1 == { d3 guess2 == } or } or { c++ } ifthen } if
b bulls >= c cows >= and
} =
add dup var {
n dup var swap =
n guess != { // never put our own guess back in the list.
i var
i count listb->:: =
i.value listb->:: defined not {
i.value listb->:: var
} ifthen
i.value listb->:: n =
count listb->::++
} ifthen
} =
filterList dup var {
firstTimeThrough {
a var
b var
c var
d var
a 1 =
{ a 10 < } {
b 1 =
{ b 10 < } {
b a != {
c 1 =
{ c 10 < } {
c a != c b != and {
d 1 =
{ d 10 < } {
d a != { d b != d c != and } and {
a b c d check() {
a 1000 * b 100 * c 10 * d + + + add()
} ifthen
} ifthen
d++
} while
} ifthen
c++
} while
} ifthen
b++
} while
a++
} while
} {
i var
j var
n var
count listb->:: 0 =
i 0 =
{ i count lista->:: < } {
n i.value lista->:: =
n 1000 / n 100 / 10 % n 10 / 10 % n 10 % check() {
n.value add()
} ifthen
i++
} while
} if
} =
solve dup var {
t var
f var
n var
lista a &=
listb b &=
firstTimeThrough true =
count a:: 0 =
count b:: 0 =
n 1 =
f 1 =
{ f } {
makeGuess()
guess0 guess1 guess2 guess3 n "\nGuess %d: %d %d %d %d\n" printf
getScore()
bulls 4 == {
"WooHoo, I won!" println
break
} ifthen
filterList()
f count listb->:: =
t lista =
lista listb =
listb t =
firstTimeThrough false =
n++
} while
count lista->:: 0 == {
"I've run out of numbers to choose from." println
} ifthen
} =
init()
{ true } {
solve()
} while

View file

@ -0,0 +1,45 @@
# Build a list of all possible solutions. The regular expression weeds
# out numbers containing zeroes or repeated digits.
var candidates = (1234..9876 -> grep {|n| !("#{n}" =~ /0 | (\d) .*? \1 /x) }.map{.digits});
# Repeatedly prompt for input until the user supplies a reasonable score.
# The regex validates the user's input and then returns two numbers.
func read_score(guess) {
loop {
"My guess: %s (from %d possibilities)\n" \
-> printf(guess.join, candidates.len);
if (var m = (Sys.scanln("bulls cows: ") =~ /^\h*(\d)\h*(\d)\h*$/)) {
var (bulls, cows) = m.cap.map{.to_i}...;
bulls+cows <= 4 && return(bulls, cows);
}
say "Please specify the number of bulls and the number of cows";
}
}
func score_correct(a, b, bulls, cows) {
var (exact, loose) = (0, 0);
for i in ^4 {
a[i] == b[i] ? ++exact
: (a[i]~~b && ++loose)
}
(bulls == exact) && (cows == loose)
}
# Pick a number, display it, get the score, and discard candidates
# that don't match the score:
loop {
var guess = candidates.pick;
var (bulls, cows) = read_score(guess);
candidates.grep!{|n| score_correct(n, guess, bulls, cows) }
candidates.len > 1 || break
}
# Print the secret number or the error message
(
candidates.len == 1 ? ("Your secret number is: %d" % candidates[0].join)
: ("I think you made a mistake with your scoring")
)->say

View file

@ -0,0 +1,52 @@
package require struct::list
package require struct::set
proc scorecalc {guess chosen} {
set bulls 0
set cows 0
foreach g $guess c $chosen {
if {$g eq $c} {
incr bulls
} elseif {$g in $chosen} {
incr cows
}
}
return [list $bulls $cows]
}
# Allow override on command line
set size [expr {$argc ? int($argv) : 4}]
set choices {}
struct::list foreachperm p [split 123456789 ""] {
struct::set include choices [lrange $p 1 $size]
}
set answers {}
set scores {}
puts "Playing Bulls & Cows with $size unique digits\n"
fconfigure stdout -buffering none
while 1 {
set ans [lindex $choices [expr {int(rand()*[llength $choices])}]]
lappend answers $ans
puts -nonewline \
"Guess [llength $answers] is [join $ans {}]. Answer (Bulls, cows)? "
set score [scan [gets stdin] %d,%d]
lappend scores $score
if {$score eq {$size 0}} {
puts "Ye-haw!"
break
}
foreach c $choices[set choices {}] {
if {[scorecalc $c $ans] eq $score} {
lappend choices $c
}
}
if {![llength $choices]} {
puts "Bad scoring? nothing fits those scores you gave:"
foreach a $answers s $scores {
puts " [join $a {}] -> ([lindex $s 0], [lindex $s 1])"
}
break
}
}

View file

@ -0,0 +1,105 @@
Option Explicit
Sub Main_Bulls_And_Cows_Player()
Dim collSoluces As New Collection, Elem As Variant, Soluce As String
Dim strNumber As String, cpt As Byte, p As Byte
Dim i As Byte, Bulls() As Boolean, NbBulls As Byte, Cows As Byte, Poss As Long
Const NUMBER_OF_DIGITS As Byte = 4
strNumber = CreateNb(NUMBER_OF_DIGITS)
Debug.Print "TOSS : " & StrConv(strNumber, vbUnicode)
Debug.Print "---------- START ------------"
Set collSoluces = CollOfPossibleNumbers
Poss = collSoluces.Count
For Each Elem In collSoluces
'Debug.Print "Number of possibilities : " & Poss
Debug.Print "Attempt : " & StrConv(Elem, vbUnicode)
NbBulls = 0: Soluce = Elem
ReDim Bulls(NUMBER_OF_DIGITS - 1)
For i = 1 To NUMBER_OF_DIGITS
If IsBull(strNumber, Mid(Elem, i, 1), i) Then
Bulls(i - 1) = True: NbBulls = NbBulls + 1
RemoveIfNotBull collSoluces, Mid(Elem, i, 1), i
End If
Next i
Cows = 0
For i = 1 To NUMBER_OF_DIGITS
If Not Bulls(i - 1) Then
If IsCow(collSoluces, strNumber, Mid(Elem, i, 1), p) Then
If Not Bulls(p - 1) Then Cows = Cows + 1
End If
End If
Next i
Poss = collSoluces.Count
Debug.Print "Bulls : " & NbBulls & ", Cows : " & Cows
If Poss = 1 Then Exit For
Next
Debug.Print "---------- THE END ------------"
Debug.Print "TOSS WAS : " & StrConv(strNumber, vbUnicode) & " We found : " & StrConv(Soluce, vbUnicode)
End Sub
Function CreateNb(NbDigits As Byte) As String
Dim myColl As New Collection
Dim strTemp As String
Dim bytAlea As Byte
Randomize
Do
bytAlea = Int((Rnd * 9) + 1)
On Error Resume Next
myColl.Add CStr(bytAlea), CStr(bytAlea)
If Err <> 0 Then
On Error GoTo 0
Else
strTemp = strTemp & CStr(bytAlea)
End If
Loop While Len(strTemp) < NbDigits
CreateNb = strTemp
End Function
Function CollOfPossibleNumbers() As Collection
Dim TempColl As New Collection
Dim x As String
Dim i As Long
Dim Flag As Boolean
Dim b As Byte
For i = 1234 To 9876
Flag = False
For b = 1 To 4
x = CStr(i)
If Len(Replace(x, Mid(x, b, 1), "")) < 3 Then
Flag = True: Exit For
End If
Next
If Not Flag Then TempColl.Add x, x
Next i
Set CollOfPossibleNumbers = TempColl
End Function
Function IsBull(strgNb As String, Digit As String, place As Byte) As Boolean
IsBull = (Mid(strgNb, place, 1) = Digit)
End Function
Function IsCow(C As Collection, strgNb As String, Digit As String, place As Byte) As Boolean
If (InStr(strgNb, Digit) > 0) Then
IsCow = True: place = InStr(strgNb, Digit)
RemoveIfNotCow C, Digit
End If
End Function
Sub RemoveIfNotBull(C As Collection, Digit As String, place As Byte)
Dim E As Variant
For Each E In C
If Mid(E, place, 1) <> Digit Then C.Remove E
Next
End Sub
Sub RemoveIfNotCow(C As Collection, Digit As String)
Dim E As Variant
For Each E In C
If (InStr(E, Digit) = 0) Then C.Remove E
Next
End Sub

View file

@ -0,0 +1,57 @@
import "random" for Random
var countBullsAndCows = Fn.new { |guess, answer|
var bulls = 0
var cows = 0
var i = 0
for (d in guess) {
if (answer[i] == d) {
bulls = bulls + 1
} else if (answer.contains(d)) {
cows = cows + 1
}
i = i + 1
}
return [bulls, cows]
}
var r = Random.new()
var choices = []
// generate all possible distinct 4 digit (1 to 9) integer arrays
for (i in 1..9) {
for (j in 1..9) {
if (j != i) {
for (k in 1..9) {
if (k != i && k != j) {
for (l in 1..9) {
if (l != i && l != j && l != k) {
choices.add([i, j, k, l])
}
}
}
}
}
}
}
// pick one at random as the answer
var answer = choices[r.int(choices.count)]
// keep guessing, pruning the list as we go based on the score, until answer found
while (true) {
var guess = choices[r.int(choices.count)]
var bc = countBullsAndCows.call(guess, answer)
System.print("Guess = %(guess.join("")) Bulls = %(bc[0]) Cows = %(bc[1])")
if (bc[0] == 4) {
System.print("You've just found the answer!")
return
}
for (i in choices.count - 1..0) {
var bc2 = countBullsAndCows.call(choices[i], answer)
// if score is no better remove it from the list of choices
if (bc2[0] <= bc[0] && bc2[1] <= bc[1]) choices.removeAt(i)
}
if (choices.count == 0) {
System.print("Something went wrong as no choices left! Aborting program")
}
}

View file

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

View file

@ -0,0 +1,15 @@
d9:="123456789";
choices:=Walker.cproduct(d9,d9,d9,d9).pump(List,// lazy,-->3024, order is important
fcn(list){ s:=list.concat(); (s.unique().len()==4) and s or Void.Skip });
do{
guess:=choices[(0).random(choices.len())];
score:=ask("My guess is %s. How many bulls and cows? ".fmt(guess)).strip();
bulls,cows:=score.split("").apply("toInt"); // "12"-->(1,2)
choices=choices.filter('wrap(c){
bulls==c.zipWith('==,guess).sum(0) and // 0 + True == 1
cows ==c.zipWith('wrap(a,b){ a!=b and guess.holds(a) },guess).sum(0)
});
}while(choices.len()>1);
if(not choices) "Nothing fits the scores you gave.".println();
else "Solution found: ".println(choices[0]);