Bulls and Cows


Task

Create a four digit random number from the digits   1   to   9,   without duplication.

The program should:

   ask for guesses to this number
   reject guesses that are malformed
   print the score for the guess


The score is computed as:

 The player wins if the guess is the same as the randomly chosen number, and the program ends.
 A score of one bull is accumulated for each digit in the guess that equals the corresponding digit in the randomly chosen initial number.
 A score of one cow is accumulated for each digit in the guess that also appears in the randomly chosen number, but in the wrong position.


Related tasks

   Bulls and cows/Player
   Guess the number
   Guess the number/With Feedback
   Mastermind


import ceylon.random {
    DefaultRandom
}
 
shared void run() {
 
    value random = DefaultRandom();
 
    function generateDigits() =>
            random.elements(1..9).distinct.take(4).sequence();
 
    function validate(String guess) {
        variable value ok = true;
        if (!guess.every((Character element) => element.digit)) {
            print("numbers only, please");
            ok = false;
        }
        if ('0' in guess) {
            print("only 1 to 9, please");
            ok = false;
        }
        if (guess.distinct.shorterThan(guess.size)) {
            print("no duplicates, please");
            ok = false;
        }
        if (guess.size != 4) {
            print("4 digits please");
            ok = false;
        }
        return ok;
    }
 
    function score({Integer*} target, {Integer*} guess) {
        variable value bulls = 0;
        variable value cows = 0;
        for ([a, b] in zipPairs(target, guess)) {
            if (a == b) {
                bulls++;
            } else if (target.contains(b)) {
                cows++;
            }
        }
        return [bulls, cows];
    }
 
    while (true) {
        value digits = generateDigits();
        print("I have chosen my four digits, please guess what they are.
               Use only the digits 1 to 9 with no duplicates and enter them with no spaces. eg 1234
               Enter q or Q to quit.");
        while (true) {
            if (exists line = process.readLine()) {
                if (line.uppercased == "Q") {
                    return;
                }
                if (validate(line)) {
                    value guessDigits = line.map((Character element) => Integer.parse(element.string)).narrow<Integer>();
                    value [bulls, cows] = score(digits, guessDigits);
                    if (bulls == 4) {
                        print("You win!");
                        break;
                    }
                    else {
                        print("Bulls: ``bulls``, Cows:  ``cows``");
                    }
                }
            }
        }
    }
}