Bagels

Description of the page content

Conversion of Bagels to several programming languages.

Tags:

This program has been converted to 20 programming languages.

Original

Origin of bagels.bas:

By D. Resek, P. Rowe, 1978.

Creative Computing's BASIC Games.

- http://vintage-basic.net/games.html
- http://vintage-basic.net/bcg/bagels.bas
- http://www.atariarchives.org/basicgames/showpage.php?page=9

5 PRINT TAB(33);"BAGELS"
10 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY":PRINT:PRINT
15 REM *** BAGLES NUMBER GUESSING GAME
20 REM *** ORIGINAL SOURCE UNKNOWN BUT SUSPECTED TO BE
25 REM *** LAWRENCE HALL OF SCIENCE, U.C. BERKELY
30 DIM A1(6),A(3),B(3)
40 Y=0:T=255
50 PRINT:PRINT:PRINT
70 INPUT "WOULD YOU LIKE THE RULES (YES OR NO)";A$
90 IF LEFT$(A$,1)="N" THEN 150
100 PRINT:PRINT "I AM THINKING OF A THREE-DIGIT NUMBER.  TRY TO GUESS"
110 PRINT "MY NUMBER AND I WILL GIVE YOU CLUES AS FOLLOWS:"
120 PRINT "   PICO   - ONE DIGIT CORRECT BUT IN THE WRONG POSITION"
130 PRINT "   FERMI  - ONE DIGIT CORRECT AND IN THE RIGHT POSITION"
140 PRINT "   BAGELS - NO DIGITS CORRECT"
150 FOR I=1 TO 3
160 A(I)=INT(10*RND(1))
165 IF I-1=0 THEN 200
170 FOR J=1 TO I-1
180 IF A(I)=A(J) THEN 160
190 NEXT J
200 NEXT I
210 PRINT:PRINT "O.K.  I HAVE A NUMBER IN MIND."
220 FOR I=1 TO 20
230 PRINT "GUESS #";I,
240 INPUT A$
245 IF LEN(A$)<>3 THEN 630
250 FOR Z=1 TO 3:A1(Z)=ASC(MID$(A$,Z,1)):NEXT Z
260 FOR J=1 TO 3
270 IF A1(J)<48 THEN 300
280 IF A1(J)>57 THEN 300
285 B(J)=A1(J)-48
290 NEXT J
295 GOTO 320
300 PRINT "WHAT?"
310 GOTO 230
320 IF B(1)=B(2) THEN 650
330 IF B(2)=B(3) THEN 650
340 IF B(3)=B(1) THEN 650
350 C=0:D=0
360 FOR J=1 TO 2
370 IF A(J)<>B(J+1) THEN 390
380 C=C+1
390 IF A(J+1)<>B(J) THEN 410
400 C=C+1
410 NEXT J
420 IF A(1)<>B(3) THEN 440
430 C=C+1
440 IF A(3)<>B(1) THEN 460
450 C=C+1
460 FOR J=1 TO 3
470 IF A(J)<>B(J) THEN 490
480 D=D+1
490 NEXT J
500 IF D=3 THEN 680
505 IF C=0 THEN 545
520 FOR J=1 TO C
530 PRINT "PICO ";
540 NEXT J
545 IF D=0 THEN 580
550 FOR J=1 TO D
560 PRINT "FERMI ";
570 NEXT J
580 IF C+D<>0 THEN 600
590 PRINT "BAGELS";
600 PRINT
605 NEXT I
610 PRINT "OH WELL."
615 PRINT "THAT'S TWNETY GUESSES.  MY NUMBER WAS";100*A(1)+10*A(2)+A(3)
620 GOTO 700
630 PRINT "TRY GUESSING A THREE-DIGIT NUMBER.":GOTO 230
650 PRINT "OH, I FORGOT TO TELL YOU THAT THE NUMBER I HAVE IN MIND"
660 PRINT "HAS NO TWO DIGITS THE SAME.":GOTO 230
680 PRINT "YOU GOT IT!!!":PRINT
690 Y=Y+1
700 INPUT "PLAY AGAIN (YES OR NO)";A$
720 IF LEFT$(A$,1)="YES" THEN 150
730 IF Y=0 THEN 750
740 PRINT:PRINT "A";Y;"POINT BAGELS BUFF!!"
750 PRINT "HOPE YOU HAD FUN.  BYE."
999 END

In Arturo

; Bagels

; Original version in BASIC:
;   D. Resek, P. Rowe, 1978.
;   Creative Computing's BASIC Games.
;   - http://vintage-basic.net/games.html
;   - http://vintage-basic.net/bcg/bagels.bas
;   - http://www.atariarchives.org/basicgames/showpage.php?page=9

; This version in Arturo:
;   Copyright (c) 2023, Marcos Cruz (programandala.net)
;   SPDX-License-Identifier: Fair
;
; Written on 2023-10-19.
;
; Last modified: 20251205T0044+0100.

; Clear the screen, print the credits and wait for a keypress.
printCredits: function [] [
    clear
    print "Bagels"
    print "Number guessing game\n"
    print "Original source unknown but suspected to be:"
    print "    Lawrence Hall of Science, U.C. Berkely.\n"
    print "Original version in BASIC:"
    print "    D. Resek, P. Rowe, 1978."
    print "    Creative computing (Morristown, New Jersey, USA), 1978.\n"
    print "This version in Arturo:"
    print "    Copyright (c) 2023, Marcos Cruz (programandala.net)"
    print "    SPDX-License-Identifier: Fair\n"
    input "Press Enter to read the instructions. "
]

; Clear the screen, print the instructions and wait for a keypress.
printInstructions: function [] [
    clear
    print "Bagels"
    print "Number guessing game\n"
    print "I am thinking of a three-digit number that has no two digits the same."
    print "Try to guess it and I will give you clues as follows:\n"
    print "   PICO   - one digit correct but in the wrong position"
    print "   FERMI  - one digit correct and in the right position"
    print "   BAGELS - no digits correct\n"
    input "Press Enter to start. "
]

DIGITS: 3

randomDigit: array [0 0 0]

; Return an integer array with random digits.
randomNumber: function [] [
    number: array []
    while [ less? size number DIGITS ] [
        digit: random 0 9
        if not? contains? number digit [
            append 'number digit
        ]
    ]
    number
]

; Print the given prompt and get a three-digit number from the user.
userInput: function [prompt] [
    userDigit: array []
    while [ less? size userDigit DIGITS ] [
        inputString: input prompt
        if? less? size inputString DIGITS [
            print ~"Remember it's a |DIGITS|-digit number."
        ] else [
            empty 'userDigit
            loop inputString 'char [
                if? contains? "0123456789" char [
                    digit: to :integer to :string char
                    if? contains? userDigit digit [
                        print "Remember my number has no two digits the same."
                        break
                    ] else [
                        append 'userDigit digit
                    ]
                ] else [
                    print "What?"
                    break
                ]
            ]
        ]
    ]
    userDigit
]

; Return `true` if the given string is "yes" or a synonym.
isYes: function [answer] [
    contains? ["ok", "yeah", "yes", "y"] answer
]

; Return `true` if the given string is "no" or a synonym.
isNo: function [answer] [
    contains? ["no", "nope", "n"] answer
]

; Print the given prompt, wait until the user enters a valid yes/no
; string, and return `true` for "yes" or `false` for "no".
yes: function [prompt] [
    answer: ""
    while [ not? or? isYes answer isNo answer ] [ answer: input prompt ]
    isYes answer
]

; Init and run the game loop.
play: function [] [
    maxTries: 20
    score: 0
    while [ true ] [
        clear
        computerNumber: randomNumber
        print "O.K.  I have a number in mind."
        loop range 1 maxTries [ 'guess ] [
            userNumber: userInput(~"Guess #|pad .with:`0` to :string guess 2 |: ")
            fermi: 0
            pico: 0
            loop range 0 sub DIGITS 1 [ 'i ] [
                loop range 0 sub DIGITS 1 [ 'j ] [
                    if equal? userNumber\[i] computerNumber\[j] [
                        if? equal? i j [ add 'fermi 1 ]
                        else           [ add 'pico  1 ]
                    ]
                ]
            ]
            prints repeat "PICO " pico
            prints repeat "FERMI " fermi
            if equal? add pico fermi 0 [ prints "BAGELS" ]
            print ""
            if equal? fermi DIGITS [ break ]
        ]
        if? equal? fermi DIGITS [
            print "You got it!!!"
            inc score
        ] else [
            print "Oh well."
            prints ~"That's |maxTries| guesses.  My number was "
            loop range 0 sub DIGITS 1 [ 'i ] [ prints computerNumber\[i] ]
            print "."
        ]
        if not? yes("Play again? ") [ break ]
    ]
    if notEqual? score 0 [
        print ~"A |score|-point bagels, buff!!"
    ]
    print "Hope you had fun.  Bye."
]

printCredits
printInstructions
play

In C#

// Bagels

// Original version in BASIC:
//  By D. Resek, P. Rowe, 1978.
//  Creative Computing's BASIC Games.
//  - http://vintage-basic.net/games.html
//  - http://vintage-basic.net/bcg/bagels.bas
//  - http://www.atariarchives.org/basicgames/showpage.php?page=9

// This version in C#:
//  Copyright (c) 2024, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2024-12-25.
//
// Last modified: 20251205T1530+0100.

using System;
using System.Linq;

class bagels
{
    // Clear the screen, display the credits and wait for a keypress.
    //
    static void PrintCredits()
    {
        Console.Clear();
        Console.WriteLine("Bagels");
        Console.WriteLine("Number guessing game\n");
        Console.WriteLine("Original source unknown but suspected to be:");
        Console.WriteLine("    Lawrence Hall of Science, U.C. Berkely.\n");
        Console.WriteLine("Original version in BASIC:");
        Console.WriteLine("    D. Resek, P. Rowe, 1978.");
        Console.WriteLine("    Creative computing (Morristown, New Jersey, USA), 1978.\n");
        Console.WriteLine("This version in C#:");
        Console.WriteLine("    Copyright (c) 2024, Marcos Cruz (programandala.net)");
        Console.WriteLine("    SPDX-License-Identifier: Fair\n");
        Console.Write("Press Enter to read the instructions. ");
        Console.ReadKey();
    }

    // Clear the screen, print the instructions and wait for a keypress.
    //
    static void PrintInstructions()
    {
        Console.Clear();
        Console.WriteLine("Bagels");
        Console.WriteLine("Number guessing game\n");
        Console.WriteLine("I am thinking of a three-digit number that has no two digits the same.");
        Console.WriteLine("Try to guess it and I will give you clues as follows:\n");
        Console.WriteLine("   PICO   - one digit correct but in the wrong position");
        Console.WriteLine("   FERMI  - one digit correct and in the right position");
        Console.WriteLine("   BAGELS - no digits correct");
        Console.Write("\nPress Enter to start. ");
        Console.ReadKey();
    }

    const int DIGITS = 3;

    static int[] randomDigit = new int[DIGITS];

    // Return three random digits.
    //
    static int[] RandomDigits()
    {
        Random rand = new Random();

        for (int i = 0; i < DIGITS; i++)
        {
            while (true)
            {
                digitLoop:
                randomDigit[i] = rand.Next(10);
                for (int j = 0; j < i; j++)
                {
                    if (i != j && randomDigit[i] == randomDigit[j])
                    {
                        goto digitLoop;
                    }
                }
                break;
            }
        }
        return randomDigit;
    }

    // Return `true` if any of the elements of the given array, which contains
    // only numbers in inclusive range 0..9, is repeated; otherwise return
    // `false`.
    //
    static bool IsAnyRepeated(int[] num)
    {
        bool[] present = new bool[10];
        foreach (int n in num)
        {
            if (present[n])
                return true;
            else
                present[n] = true;
        }
        return false;
    }

    // Print the given prompt and update the array whose address is given with a
    // three-digit number from the user.
    //
    static void GetInput(string prompt, ref int[] userDigit)
    {
        // XXX TODO Create a local array, appending every digit after checking
        // the contents, making `IsAnyRepeated` unnecessary.

        while (true)
        {
            getLoop:
            Console.Write(prompt);
            string input = Console.ReadLine();
            if (input.Length != DIGITS)
            {
                Console.WriteLine($"Remember it's a {DIGITS}-digit number.");
                continue;
            }
            char digit;
            for (int i = 0; i < input.Length; i++)
            {
                digit = input[i];
                if (Char.IsDigit(digit))
                {
                    userDigit[i] = ((int) digit) - ((int) '0');
                }
                else
                {
                    Console.WriteLine("What?");
                    goto getLoop;
                }
            }
            if (IsAnyRepeated(userDigit))
            {
                Console.WriteLine("Remember my number has no two digits the same.");
                continue;
            }
            break;
        }
    }

    // Return `true` if the given string is "yes" or a synonym.
    //
    static bool IsYes(string s)
    {
        string[] validOptions = {"ok", "y", "yeah", "yes"};
        return validOptions.Contains(s.ToLower());
    }

    // Return `true` if the given string is "no" or a synonym.
    //
    static bool IsNo(string s)
    {
        string[] validOptions = {"n", "no", "nope"};
        return validOptions.Contains(s.ToLower());
    }

    // Print the given prompt, wait until the user enters a valid yes/no string,
    // and return `true` for "yes" or `false` for "no".
    //
    static bool Yes(string prompt)
    {
        while (true)
        {
            Console.Write(prompt);
            string answer = Console.ReadLine();
            if (IsYes(answer))
            {
                return true;
            }
            if (IsNo(answer))
            {
                return false;
            }
        }
    }

    static void Play()
    {
        const int TRIES = 20;
        int score = 0;
        int fermi = 0; // counter
        int pico = 0; // counter
        int[] userNumber = new int[DIGITS];
        while (true)
        {
            Console.Clear();
            int[] computerNumber = RandomDigits();
            Console.WriteLine("O.K.  I have a number in mind.");
            for (int guess = 1; guess <= TRIES; guess++)
            {
                GetInput($"Guess #{guess}: ", ref userNumber);
                fermi = 0;
                pico = 0;
                for (int i = 0; i < DIGITS; i++)
                {
                    for (int j = 0; j < DIGITS; j++)
                    {
                        if (userNumber[i] == computerNumber[j])
                        {
                            if (i == j)
                            {
                                fermi += 1;
                            }
                            else
                            {
                                pico += 1;
                            }
                        }
                    }
                }
                for (int i = 0; i < pico; i++)
                    Console.Write("PICO ");
                for (int i = 0; i < fermi; i++)
                    Console.Write("FERMI ");
                if (pico + fermi == 0)
                    Console.Write("BAGELS");
                Console.WriteLine();
                if (fermi == DIGITS)
                {
                    break;
                }
            }
            if (fermi == DIGITS)
            {
                Console.WriteLine("You got it!!!");
                score += 1;
            }
            else
            {
                Console.WriteLine("Oh well.");
                Console.Write($"That's {TRIES} guesses.  My number was ");
                for (int i = 0; i < DIGITS; i++)
                {
                    Console.Write(computerNumber[i]);
                }
                Console.WriteLine(".");
            }
            if (!Yes("Play again? "))
            {
                break;
            }
        }
        if (score != 0)
        {
            Console.WriteLine($"A {score}-point bagels, buff!!");
        }
        Console.WriteLine("Hope you had fun.  Bye.");
    }

    static void Main()
    {
        PrintCredits();
        PrintInstructions();
        Play();
    }
}

In Chapel

// Bagels

// Original version in BASIC:
//  D. Resek, P. Rowe, 1978.
//  Creative Computing (Morristown, New Jersey, USA), 1978.

// This version in Chapel:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-04-06.
//
// Last modified: 20250406T1921+0200.

// Modules {{{1
// =============================================================================

import IO;
import Random;

// Terminal {{{1
// =============================================================================

const NORMAL_STYLE = 0;

proc moveCursorHome() {
    write("\x1B[H");
}

proc setStyle(style: int) {
    writef("\x1B[%im", style);
}

proc resetAttributes() {
    setStyle(NORMAL_STYLE);
}

proc eraseScreen() {
    write("\x1B[2J");
}

proc clearScreen() {
    eraseScreen();
    resetAttributes();
    moveCursorHome();
}

// User input {{{1
// =============================================================================

proc acceptString(prompt: string): string {
    write(prompt);
    IO.stdout.flush();
    return IO.readLine().strip();
}

// Return `true` if the given string is "yes" or a synonym.
//
proc isYes(s: string): bool {
    select s.toLower() {
        when "ok", "y", "yeah", "yes" do return true;
        otherwise do return false;
    }
}

// Return `true` if the given string is "no" or a synonym.
//
proc isNo(s: string): bool {
    select s.toLower() {
        when "n", "no", "nope" do return true;
        otherwise do return false;
    }
}

// Print the given prompt, wait until the user enters a valid yes/no string,
// and return `true` for "yes" or `false` for "no".
//
proc yes(prompt: string): bool {
    var result: bool;
    while true {
        var answer: string = acceptString(prompt);
        if isYes(answer) {
            result = true;
            break;
        } else if isNo(answer) {
            result = false;
            break;
        }
    }
    return result;
}

// Credits and instructions {{{1
// =============================================================================

// Clear the screen, display the credits and wait for a keypress.
//
proc printCredits() {
    clearScreen();
    writeln("Bagels");
    writeln("Number guessing game\n");
    writeln("Original source unknown but suspected to be:");
    writeln("    Lawrence Hall of Science, U.C. Berkely.\n");
    writeln("Original version in BASIC:");
    writeln("    D. Resek, P. Rowe, 1978.");
    writeln("    Creative computing (Morristown, New Jersey, USA), 1978.\n");
    writeln("This version in Chapel:");
    writeln("    Copyright (c) 2025, Marcos Cruz (programandala.net)");
    writeln("    SPDX-License-Identifier: Fair\n");
    acceptString("Press Enter to read the instructions. ");
}

// Clear the screen, print the instructions and wait for a keypress.
//
proc printInstructions() {
    clearScreen();
    writeln("Bagels");
    writeln("Number guessing game\n");
    writeln("I am thinking of a three-digit number that has no two digits the same.");
    writeln("Try to guess it and I will give you clues as follows:\n");
    writeln("   PICO   - one digit correct but in the wrong position");
    writeln("   FERMI  - one digit correct and in the right position");
    writeln("   BAGELS - no digits correct\n");
    acceptString("Press Enter to start. ");
}

// Main {{{1
// =============================================================================

const DIGITS = 3;

// Print the given prompt and return an array with a three-digit number type by
// the user.
//
proc getInput(prompt: string): [0 ..< DIGITS] int {
    var userDigit: [0 ..< DIGITS] int;
    const ASCII_0 = '0';
    label getLoop while true {
        var input: string = acceptString(prompt);
        if input.size != DIGITS {
            writef("Remember it's a %i-digit number.\n", DIGITS);
            continue getLoop;
        }
        for pos in 0 ..< input.size {
            var digit: string = input[pos];
            if input[pos].isDigit() {
                userDigit[pos] = digit: int;
            } else {
                writeln("What?");
                continue getLoop;
            }
        }
        if isAnyRepeated(userDigit) {
            writeln("Remember my number has no two digits the same.");
            continue getLoop;
        }
        break;
    }
    return userDigit;
}

// Return three random digits.
//
proc randomNumber(): [0 ..< DIGITS] int {
    var rsInt = new Random.randomStream(int);
    var randomDigit: [0 ..< DIGITS] int;
    for i in 0 ..< DIGITS {
        label digitLoop while true {
            randomDigit[i] = rsInt.next(0, 10 - 1);
            for j in 0 ..< i {
                if i != j && randomDigit[i] == randomDigit[j] {
                    continue digitLoop;
                }
            }
            break;
        }
    }
    return randomDigit;
}

// Return `true` if any of the given numbers is repeated; otherwise return
// `false`.
//
proc isAnyRepeated(numbers: [] int): bool {
    for i0 in 0 ..< numbers.size {
        for i1 in i0 + 1 ..< numbers.size {
            if numbers[i0] == numbers[i1] {
                return true;
            }
        }
    }
    return false;
}

// Init and run the game loop.
//
proc play() {
    const TRIES = 20;
    var score: int = 0;
    var fermi: int = 0; // counter
    var pico: int = 0; // counter
    var computerNumber: [0 ..< DIGITS] int;
    var userNumber: [0 ..< DIGITS] int;
    while true {
        clearScreen();
        computerNumber = randomNumber();
        writeln("O.K.  I have a number in mind.");
        for guess in 1 ..< TRIES + 1 {
            //userNumber = getInput("Guess #%02i: ".format(guess)); // XXX TODO
            userNumber = getInput("Guess #" + guess: string + ": "); // XXX TMP
            fermi = 0;
            pico = 0;
            for i in 0 ..< DIGITS {
                for j in 0 ..< DIGITS {
                    if userNumber[i] == computerNumber[j] {
                        if i == j {
                            fermi += 1;
                        } else {
                            pico += 1;
                        }
                    }
                }
            }
            if pico + fermi == 0 {
                writeln("BAGELS");
            } else {
                writeln( "PICO " * pico, "FERMI " * fermi);
                if fermi == DIGITS {
                    break;
                }
            }
        }
        if fermi == DIGITS {
            writeln("You got it!!!");
            score += 1;
        } else {
            writeln("Oh well.");
            writef("That's %i guesses.  My number was ", TRIES);
            for i in 0 ..< DIGITS {
                write(computerNumber[i]);
            }
            writeln(".");
        }
        if !yes("Play again? ") {
            break;
        }
    }
    if score != 0 {
        writef("A %i-point bagels, buff!!\n", score);
    }
    writeln("Hope you had fun.  Bye.");
}

proc main() {
    printCredits();
    printInstructions();
    play();
}

In Crystal

# Bagels

# Original version in BASIC:
#   D. Resek, P. Rowe, 1978.
#   Creative Computing (Morristown, New Jersey, USA), 1978.

# This version in Crystal:
#   Copyright (c) 2023, Marcos Cruz (programandala.net)
#   SPDX-License-Identifier: Fair
#
# Written in 2023-04, 2023-09, 2023-10.
#
# Last modified: 20250513T0043+0200.

# Moves the cursor to the home position.
def home
  print "\e[H"
end

# Clears the screen and moves the cursor to the home position.
def clear
  print "\e[2J"
  home
end

# Prompts the user to enter a command and returns it.
def command(prompt = "> ") : String
  s = nil
  while s.is_a?(Nil)
    print prompt
    s = gets
  end
  s
end

# Prints the given prompt and waits until the user enters an empty string.
def press_enter(prompt : String)
  until command(prompt) == ""
  end
end

# Returns `true` if the given string is "yes" or a synonym.
def is_yes?(answer : String) : Bool
  ["ok", "yeah", "yes", "y"].any? { |yes| answer.downcase == yes }
end

# Returns `true` if the given string is "no" or a synonym.
def is_no?(answer : String) : Bool
  ["no", "nope", "n"].any? { |no| answer.downcase == no }
end

# Prints the given prompt, waits until the user enters a valid yes/no
# string, and returns `true` for "yes" or `false` for "no".
def yes?(prompt : String) : Bool
  answer = ""
  while !(is_yes?(answer) || is_no?(answer))
    answer = command(prompt)
  end
  is_yes?(answer)
end

# Clears the screen, displays the credits and waits for a keypress.
def print_credits
  clear
  puts "Bagels"
  puts "Number guessing game\n"
  puts "Original source unknown but suspected to be:"
  puts "    Lawrence Hall of Science, U.C. Berkely.\n"
  puts "Original version in BASIC:"
  puts "    D. Resek, P. Rowe, 1978."
  puts "    Creative computing (Morristown, New Jersey, USA), 1978.\n"
  puts "This version in Crystal:"
  puts "    Copyright (c) 2023, Marcos Cruz (programandala.net)"
  puts "    SPDX-License-Identifier: Fair\n"
  press_enter "Press Enter to read the instructions. "
end

# Clears the screen, prints the instructions and waits for a keypress.
def print_instructions
  clear
  puts "Bagels"
  puts "Number guessing game\n"
  puts "I am thinking of a three-digit number that has no two digits the same."
  puts "Try to guess it and I will give you clues as follows:\n"
  puts "   PICO   - one digit correct but in the wrong position"
  puts "   FERMI  - one digit correct and in the right position"
  puts "   BAGELS - no digits correct"
  press_enter "\nPress Enter to start. "
end

DIGITS =  3
TRIES  = 20

# Returns three random digits.
def random : {Int32, Int32, Int32}
  d = [] of Int32
  while d.size < DIGITS
    digit = rand(10)
    while digit.in?(d)
      digit = rand(10)
    end
    d << digit
  end
  {d[0], d[1], d[2]}
end

def other_than_digits?(text : String) : Bool
  text.each_char do |char|
    if !char.number?
      return true
    end
  end
  false
end

# Prints the given prompt and gets a three-digit number from the user.
def input(prompt : String) : {Int32, Int32, Int32}
  user_digit = [] of Int32 # digit value
  while true
    input = command(prompt)
    if input.size != DIGITS
      puts "Remember it's a #{DIGITS}-digit number."
      next
    elsif other_than_digits?(input)
      puts "What?"
      next
    end
    user_digit.clear
    input.each_char do |c|
      user_digit << c.to_i
    end
    if user_digit.uniq.size != user_digit.size
      puts "Remember my number has no two digits the same."
      next
    end
    break
  end
  {user_digit[0], user_digit[1], user_digit[2]}
end

# Inits and runs the game loop.
def play
  computer_number = [DIGITS] of Int32 # random number
  user_number = [DIGITS] of Int32     # user guess
  DIGITS.times do
    computer_number << 0
    user_number << 0
  end
  score = 0
  fermi = 0  # counter
  pico = 0   # counter
  while true # game loop
    clear
    computer_number[0], computer_number[1], computer_number[2] = random
    puts "O.K.  I have a number in mind."
    (0...TRIES).each do |guess|
      user_number[0], user_number[1], user_number[2] = input("Guess ##{guess.to_s.rjust(2, '0')}: ")
      fermi = 0
      pico = 0
      (0...DIGITS).each do |i|
        (0...DIGITS).each do |j|
          if computer_number[i] == user_number[j]
            if i == j
              fermi += 1
            else
              pico += 1
            end
          end
        end
      end
      if pico + fermi == 0
        print "BAGELS"
      else
        print "PICO " * pico
        print "FERMI " * fermi
      end
      puts
      if fermi == DIGITS
        break
      end
    end # tries loop
    if fermi == DIGITS
      puts "You got it!!!"
      score += 1
    else
      puts "Oh well."
      print "That's #{TRIES} guesses.  My number was "
      print 100 * computer_number[0] + 10 * computer_number[1] + computer_number[2], "\n"
    end
    if !yes?("Play again? ")
      break
    end
  end # game loop
  if score != 0
    puts "A #{score}-point bagels, buff!!"
  end
  puts "Hope you had fun.  Bye."
end

print_credits
print_instructions
play

In D

// Bagels

// Original version in BASIC:
//     D. Resek, P. Rowe, 1978.
//     Creative Computing (Morristown, New Jersey, USA), 1978.

// This version in D:
//     Copyright (c) 2025, Marcos Cruz (programandala.net)
//     SPDX-License-Identifier: Fair
//
// Written on 2025-03-24.
//
// Last modified: 20251220T0636+0100.

module bagels;

// Terminal {{{1
// =============================================================================

enum NORMAL_STYLE = 0;

void moveCursorHome()
{
    import std.stdio : write;

    write("\x1B[H");
}

void setStyle(int style)
{
    import std.stdio : writef;

    writef("\x1B[%dm", style);
}

void resetAttributes()
{
    setStyle(NORMAL_STYLE);
}

void eraseScreen()
{
    import std.stdio : write;

    write("\x1B[2J");
}

void clearScreen()
{
    eraseScreen();
    resetAttributes();
    moveCursorHome();
}

// Credits and instructions {{{1
// =============================================================================

// Clear the screen, display the credits and wait for a keypress.
//
void printCredits()
{
    import std.stdio : writeln;

    clearScreen();
    writeln("Bagels");
    writeln("Number guessing game\n");
    writeln("Original source unknown but suspected to be:");
    writeln("    Lawrence Hall of Science, U.C. Berkely.\n");
    writeln("Original version in BASIC:");
    writeln("    D. Resek, P. Rowe, 1978.");
    writeln("    Creative computing (Morristown, New Jersey, USA), 1978.\n");
    writeln("This version in D:");
    writeln("    Copyright (c) 2025, Marcos Cruz (programandala.net)");
    writeln("    SPDX-License-Identifier: Fair\n");
    acceptString("Press Enter to read the instructions. ");
}

// Clear the screen, print the instructions and wait for a keypress.
//
void printInstructions()
{
    import std.stdio : writeln;

    clearScreen();
    writeln("Bagels");
    writeln("Number guessing game\n");
    writeln("I am thinking of a three-digit number that has no two digits the same.");
    writeln("Try to guess it and I will give you clues as follows:\n");
    writeln("   PICO   - one digit correct but in the wrong position");
    writeln("   FERMI  - one digit correct and in the right position");
    writeln("   BAGELS - no digits correct\n");
    acceptString("Press Enter to start. ");
}

// User input {{{1
// =============================================================================

string acceptString(string prompt)
{
    import std.stdio : readln;
    import std.stdio : write;
    import std.string : strip;

    write(prompt);
    return strip(readln());
}

// Return `true` if the given string is "yes" or a synonym.
//
bool isYes(string s)
{
    import std.uni : toLower;

    switch (toLower(s))
    {
        case "ok":
        case "y":
        case "yeah":
        case "yes":
            return true;
        default:
            return false;
    }
}

// Return `true` if the given string is "no" or a synonym.
//
bool isNo(string s)
{
    import std.uni : toLower;

    switch (toLower(s))
    {
        case "n":
        case "no":
        case "nope":
            return true;
        default:
            return false;
    }
}

// Print the given prompt, wait until the user enters a valid yes/no string,
// and return `true` for "yes" or `false` for "no".
//
bool yes(string prompt)
{
    while (true)
    {
        string answer = acceptString(prompt);
        if (isYes(answer))
        {
            return true;
        }
        if (isNo(answer))
        {
            return false;
        }
    }
}

// Main {{{1
// =============================================================================

enum DIGITS = 3;

bool isDigit(int asciiCode)
{
    return (asciiCode >= '0') && (asciiCode <= '9');
}

// Print the given prompt and return an array with a three-digit number typed
// by the user.

int[DIGITS] getInput(string prompt)
{
    import std.stdio : writefln;
    import std.stdio : writeln;

    enum char ASCII_0 = '0';
    int[DIGITS] userDigit;

    getLoop: while (true)
    {
        string input = acceptString(prompt);
        if (input.length != DIGITS)
        {
            writefln("Remember it's a %d-digit number.", DIGITS);
            continue getLoop;
        }
        foreach (int pos; 0 .. cast(int)input.length)
        {
            int digit = input[pos];
            if (isDigit(digit))
            {
                userDigit[pos] = digit - ASCII_0;
            }
            else
            {
                writeln("What?");
                continue getLoop;
            }
        }
        if (isAnyRepeated(userDigit))
        {
            writeln("Remember my number has no two digits the same.");
            continue getLoop;
        }
        break;
    }
    return userDigit;
}

// Return three random digits.

int[DIGITS] randomNumber()
{
    import std.random : uniform;

    int[DIGITS] randomDigit;
    foreach (int i; 0 .. DIGITS)
    {
        digitLoop: while (true)
        {
            randomDigit[i] = uniform(0, 10);
            foreach (int j; 0 .. i)
            {
                if (i != j && randomDigit[i] == randomDigit[j])
                {
                    continue digitLoop;
                }
            }
            break;
        }
    }
    return randomDigit;
}

// Return `true` if any of the given numbers is repeated; otherwise return
// `false`.

bool isAnyRepeated(int[] numbers)
{
    import std.algorithm.comparison : equal;
    import std.algorithm.iteration : uniq;

    auto filteredNumbers = uniq(numbers);
    return !equal(filteredNumbers, numbers);
}

// Init and run the game loop.

void play()
{
    import std.array : replicate;
    import std.format : format;
    import std.stdio : write;
    import std.stdio : writef;
    import std.stdio : writefln;
    import std.stdio : writeln;

    enum TRIES = 20;

    int score = 0;
    int fermi = 0; // counter
    int pico = 0; // counter
    int[DIGITS] computerNumber;
    int[DIGITS] userNumber;

    while (true)
    {
        clearScreen();
        computerNumber = randomNumber();
        writeln("O.K.  I have a number in mind.");
        foreach (int guess; 1 .. TRIES + 1)
        {
            userNumber = getInput(format("Guess #%02d: ", guess));
            fermi = 0;
            pico = 0;
            foreach (int i; 0 .. DIGITS)
            {
                foreach (int j; 0 .. DIGITS)
                {
                    if (userNumber[i] == computerNumber[j])
                    {
                        if (i == j)
                        {
                            fermi += 1;
                        }
                        else
                        {
                            pico += 1;
                        }
                    }
                }
            }
            if (pico + fermi == 0)
            {
                writeln("BAGELS");
            }
            else
            {
                writeln(
                        replicate("PICO ", pico),
                        replicate("FERMI ", fermi)
                        );
                if (fermi == DIGITS)
                {
                    break;
                }
            }
        }
        if (fermi == DIGITS)
        {
            writeln("You got it!!!");
            score += 1;
        }
        else
        {
            writeln("Oh well.");
            writef("That's %d guesses.  My number was ", TRIES);
            foreach (int i; 0 .. DIGITS)
            {
                write(computerNumber[i]);
            }
            writeln(".");
        }
        if (!yes("Play again? "))
        {
            break;
        }
    }
    if (score != 0)
    {
        writefln("A %d-point bagels, buff!!", score);
    }
    writeln("Hope you had fun.  Bye.");
}

void main()
{
    printCredits();
    printInstructions();
    play();
}

In FreeBASIC

/'
Bagels

Original version in BASIC:
    D. Resek, P. Rowe, 1978.
    Creative Computing (Morristown, New Jersey, USA), 1978.

This version in FreeBASIC:
    Copyright (c) 2025, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written on 2025-05-09.

Last modified: 20250509T1728+0200.
'/

sub press_enter(prompt as string)
    print prompt;
    sleep
    do while inkey <> ""
    loop
end sub

sub print_credits()
    cls
    print "Bagels"
    print !"Number guessing game\n"
    print "Original source unknown but suspected to be:"
    print !"    Lawrence Hall of Science, U.C. Berkely.\n"
    print "Original version in BASIC:"
    print "    D. Resek, P. Rowe, 1978."
    print !"    Creative computing (Morristown, New Jersey, USA), 1978.\n"
    print "This version in FreeBASIC:"
    print "    Copyright (c) 2025, Marcos Cruz (programandala.net)"
    print !"    SPDX-License-Identifier: Fair\n"
    press_enter("Press Enter to read the instructions. ")
end sub

sub print_instructions()
    cls
    print "Bagels"
    print !"Number guessing game\n"
    print "I am thinking of a three-digit number that has no two digits the same."
    print !"Try to guess it and I will give you clues as follows:\n"
    print "   PICO   - one digit correct but in the wrong position"
    print "   FERMI  - one digit correct and in the right position"
    print "   BAGELS - no digits correct"
    press_enter(!"\nPress Enter to start. ")
end sub

const NUMBER_OF_DIGITS = 3
const FIRST_DIGIT_INDEX = 0
const LAST_DIGIT_INDEX = NUMBER_OF_DIGITS - 1

sub fill_with_random_digits(d() as integer)
    for i as integer = lbound(d) to ubound(d)
        do while true
            d(i) = int(rnd * 10)
            for j as integer = 0 to i - 1
                if i <> j and d(i) = d(j) then
                    goto choose_again
                end if
            next
            exit do
            choose_again:
        loop
    next
end sub

' Return `true` if any of the given numbers is repeated; otherwise return
' `false`.
'
function is_any_repeated(n() as integer) as boolean
    for i0 as integer = lbound(n) to ubound(n)
        for i1 as integer = i0 + 1 to ubound(n)
            if n(i0) = n(i1) then
                return true
            end if
        next
    next
    return false
end function

' Print the given prompt and update the given array with a three-digit number
' from the user.
'
sub get_input(prompt as string, user_digit() as integer)

    ' XXX TODO Create a local array, appending every digit after checking the contents,
    ' making `is_any_repeated` unnecessary.
    do while true
        get_loop:
        dim user_input as string
        print prompt;
        line input user_input
        if len(user_input) <> NUMBER_OF_DIGITS then
            print "Remember it's a " & NUMBER_OF_DIGITS & "-digit number."
            goto get_loop
        end if
        for i as integer = 1 to len(user_input)
            dim digit as string = mid(user_input, i, 1)
            if instr("0123456789", digit) > 0 then
                user_digit(i - 1) = valint(digit)
            else
                print "What?"
                goto get_loop
            end if
        next
        if is_any_repeated(user_digit()) then
            print "Remember my number has no two digits the same."
        else
            exit do
        end if
    loop

end sub

' Return `true` if the given string is "yes" or a synonym.
'
function is_yes(s as string) as boolean
    select case lcase(s)
        case "ok", "y", "yeah", "yes"
            return true
        case else
            return false
    end select
end function

' Return `true` if the given string is "no" or a synonym.
'
function is_no(s as string) as boolean
    select case lcase(s)
        case "n", "no", "nope"
            return true
        case else
            return false
    end select
end function

' Print the given prompt, wait until the user enters a valid yes/no string,
' and return `true` for "yes" or `false` for "no".
'
function yes(prompt as string) as boolean
    do while true
        dim answer as string
        line input prompt, answer
        if is_yes(answer) then
            return true
        end if
        if is_no(answer) then
            return false
        end if
    loop
end function

' Init and run the game loop.
'
sub play()
    randomize
    const TRIES = 20
    var score = 0
    dim fermi as integer ' counter
    dim pico as integer ' counter
    dim user_number(FIRST_DIGIT_INDEX to LAST_DIGIT_INDEX) as integer
    do while true
        cls
        dim computer_number(FIRST_DIGIT_INDEX to LAST_DIGIT_INDEX) as integer
        fill_with_random_digits(computer_number())
        print "O.K.  I have a number in mind."
        for guess as integer = 1 to TRIES

            ' XXX TMP
            /'
            print "My number: "
            for i as integer = FIRST_DIGIT_INDEX to LAST_DIGIT_INDEX
                print computer_number(i);
            next
            print
            '/

            get_input("Guess #" & guess & ": ", user_number())
            fermi = 0
            pico = 0
            for i as integer = FIRST_DIGIT_INDEX to LAST_DIGIT_INDEX
                for j as integer = FIRST_DIGIT_INDEX to LAST_DIGIT_INDEX
                    if user_number(i) = computer_number(j) then
                        if i = j then
                            fermi += 1
                        else
                            pico += 1
                        end if
                    end if
                next
            next
            if pico + fermi = 0 then
                print "BAGELS"
            else
                for i as integer = 1 to pico
                    print "PICO ";
                next
                for i as integer = 1 to fermi
                    print "FERMI ";
                next
                print
            end if
            if fermi = NUMBER_OF_DIGITS then
                exit for
            end if
        next
        if fermi = NUMBER_OF_DIGITS then
            print "You got it!!!"
            score += 1
        else
            print "Oh well."
            print "That's " & TRIES & " guesses.  My number was "
            for i as integer = FIRST_DIGIT_INDEX to LAST_DIGIT_INDEX
                print computer_number(i);
            next
            print "."
        end if
        if not yes("Play again? ") then
            exit do
        end if
    loop
    if score <> 0 then
        print "A " & score & "-point bagels, buff!!"
    end if
    print "Hope you had fun.  Bye."
end sub

print_credits()
print_instructions()
play()

' vim: filetype=freebasic

In Go

/*
Bagels

Original version in BASIC:
    D. Resek, P. Rowe, 1978.
    Creative Computing (Morristown, New Jersey, USA), 1978.

This version in Go:
    Copyright (c) 2024, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written on 2024-12-29

Last modified: 20250108T1445+0100.
*/

package main

import "fmt"
import "math/rand"
import "strings"
import "time"
import "unicode"

func clearScreen() {

    fmt.Print("\x1B[0;0H\x1B[2J")

}

func input(prompt string) string {

    fmt.Print(prompt)
    var s = ""
    fmt.Scanf("%s", &s)
    return s

}

// Clear the screen, display the credits and wait for a keypress.
func printCredits() {

    clearScreen()
    fmt.Println("Bagels")
    fmt.Println("Number guessing game\n")
    fmt.Println("Original source unknown but suspected to be:")
    fmt.Println("    Lawrence Hall of Science, U.C. Berkely.\n")
    fmt.Println("Original version in BASIC:")
    fmt.Println("    D. Resek, P. Rowe, 1978.")
    fmt.Println("    Creative computing (Morristown, New Jersey, USA), 1978.\n")
    fmt.Println("This version in Go:")
    fmt.Println("    Copyright (c) 2024, Marcos Cruz (programandala.net)")
    fmt.Println("    SPDX-License-Identifier: Fair\n")
    input("Press Enter to read the instructions. ")

}

// Clear the screen, print the instructions and wait for a keypress.
func printInstructions() {

    clearScreen()
    fmt.Println("Bagels")
    fmt.Println("Number guessing game\n")
    fmt.Println("I am thinking of a three-digit number that has no two digits the same.")
    fmt.Println("Try to guess it and I will give you clues as follows:\n")
    fmt.Println("   PICO   - one digit correct but in the wrong position")
    fmt.Println("   FERMI  - one digit correct and in the right position")
    fmt.Println("   BAGELS - no digits correct")
    input("\nPress Enter to start. ")

}

const DIGITS int = 3

var randomDigit [DIGITS]int

// Return three random digits.
func random() []int {

    for i := 0; i < DIGITS; i++ {
    digitLoop:
        for {
            randomDigit[i] = rand.Intn(10)
            for j := 0; j < i; j++ {
                if i != j && randomDigit[i] == randomDigit[j] {
                    continue digitLoop
                }
            }
            break
        }
    }
    return randomDigit[:]

}

// Return `true` if any of the given numbers is repeated; otherwise return
// `false`.
func isAnyRepeated(num []int) bool {

    for i0, n0 := range num[:] {
        for _, n1 := range num[i0+1:] {
            if n0 == n1 {
                return true
            }
        }
    }
    return false

}

// Print the given prompt and update the array whose address is given with a
// three-digit number from the user.
func getInput(prompt string, userDigit *[DIGITS]int) {

    const ASCII_0 int = 48
getLoop:
    for {
        var input string = input(prompt)
        if len(input) != DIGITS {
            fmt.Printf("Remember it's a %v-digit number.\n", DIGITS)
            continue getLoop
        }
        for pos, digit := range input {
            if unicode.IsDigit(digit) {
                // XXX TODO simplify
                userDigit[pos] = int(digit) - ASCII_0
            } else {
                fmt.Println("What?")
                continue getLoop
            }
        }
        if isAnyRepeated(userDigit[:]) {
            fmt.Println("Remember my number has no two digits the same.")
            continue getLoop
        }
        break
    }

}

// Return `true` if the given string is "yes" or a synonym.
func isYes(s string) bool {

    s = strings.ToLower(s)
    for _, valid := range []string{"ok", "y", "yeah", "yes"} {
        if s == valid {
            return true
        }
    }
    return false

}

// Return `true` if the given string is "no" or a synonym.
func isNo(s string) bool {

    s = strings.ToLower(s)
    for _, valid := range []string{"n", "no", "nope"} {
        if s == valid {
            return true
        }
    }
    return false

}

// Print the given prompt, wait until the user enters a valid yes/no string,
// and return `true` for "yes" or `false` for "no".
func yes(prompt string) bool {

    for {
        var answer = input(prompt)
        if isYes(answer) {
            return true
        }
        if isNo(answer) {
            return false
        }
    }

}

// Init and run the game loop.
func play() {

    rand.Seed(time.Now().UTC().UnixNano())

    const TRIES int = 20
    var score int
    var fermi int // counter
    var pico int  // counter
    var userNumber [DIGITS]int

    for {

        clearScreen()
        var computerNumber = random()
        fmt.Println("O.K.  I have a number in mind.")

        for guess := 1; guess <= TRIES; guess++ {
            //fmt.Printf("My number: %v\n", computerNumber) // XXX TMP
            getInput(fmt.Sprintf("Guess #%2v: ", guess), &userNumber)
            fermi = 0
            pico = 0
            for i := 0; i < DIGITS; i++ {
                for j := 0; j < DIGITS; j++ {
                    if userNumber[i] == computerNumber[j] {
                        if i == j {
                            fermi += 1
                        } else {
                            pico += 1
                        }
                    }
                }
            }
            var picos = strings.Repeat("PICO ", pico)
            var fermis = strings.Repeat("FERMI ", fermi)
            fmt.Print(picos)
            fmt.Print(fermis)
            if pico+fermi == 0 {
                fmt.Print("BAGELS")
            }
            fmt.Println()
            if fermi == DIGITS {
                break
            }
        }
        if fermi == DIGITS {
            fmt.Println("You got it!!!")
            score += 1
        } else {
            fmt.Println("Oh well.")
            fmt.Printf("That's %v guesses.  My number was ", TRIES)
            for i := 0; i < DIGITS; i++ {
                fmt.Print(computerNumber[i])
            }
            fmt.Println(".")
        }
        if !yes("Play again? ") {
            break
        }
    }

    if score != 0 {
        fmt.Printf("A %v-point bagels, buff!!\n", score)
    }
    fmt.Println("Hope you had fun.  Bye.")

}

func main() {

    printCredits()
    printInstructions()
    play()

}

In Hare

// Bagels
//
// Original version in BASIC:
//      D. Resek, P. Rowe, 1978.
//      Creative Computing (Morristown, New Jersey, USA), 1978.
//
// This version in Hare:
//      Copyright (c) 2025, Marcos Cruz (programandala.net)
//      SPDX-License-Identifier: Fair
//
// Written in 2025-02-14/15.
//
// Last modified: 20260213T1645+0100.

// Modules {{{1
// =============================================================================

use ascii;
use bufio;
use fmt;
use math::random;
use os;
use strings;
use time;

// Terminal {{{1
// =============================================================================

def NORMAL_STYLE = 0;

fn move_cursor_home() void = {
        fmt::print("\x1B[H")!;
};

fn set_style(style: int) void = {
        fmt::printf("\x1B[{}m", style)!;
};

fn reset_attributes() void = {
        set_style(NORMAL_STYLE);
};

fn erase_screen() void = {
        fmt::print("\x1B[2J")!;
};

fn clear_screen() void = {
        erase_screen();
        reset_attributes();
        move_cursor_home();
};

// Credits and instructions {{{1
// =============================================================================

// Clear the screen, display the credits and wait for a keypress.
//
fn print_credits() void = {
        clear_screen();
        fmt::println("Bagels")!;
        fmt::println("Number guessing game\n")!;
        fmt::println("Original source unknown but suspected to be:")!;
        fmt::println("    Lawrence Hall of Science, U.C. Berkely.\n")!;
        fmt::println("Original version in BASIC:")!;
        fmt::println("    D. Resek, P. Rowe, 1978.")!;
        fmt::println("    Creative computing (Morristown, New Jersey, USA), 1978.\n")!;
        fmt::println("This version in Hare:")!;
        fmt::println("    Copyright (c) 2025, Marcos Cruz (programandala.net)")!;
        fmt::println("    SPDX-License-Identifier: Fair\n")!;
        press_enter("Press Enter to read the instructions. ");
};

// Clear the screen, print the instructions and wait for a keypress.
//
fn print_instructions() void = {
        clear_screen();
        fmt::println("Bagels")!;
        fmt::println("Number guessing game\n")!;
        fmt::println("I am thinking of a three-digit number that has no two digits the same.")!;
        fmt::println("Try to guess it and I will give you clues as follows:\n")!;
        fmt::println("   PICO   - one digit correct but in the wrong position")!;
        fmt::println("   FERMI  - one digit correct and in the right position")!;
        fmt::println("   BAGELS - no digits correct\n")!;
        press_enter("Press Enter to start. ");
};

// Strings {{{1
// =============================================================================

fn repeat(s: str, n: int) str = {
        let result = "";
        for (let i: int = 0; i < n; i += 1) {
                result = strings::concat(result, s)!;
        };
        return result;
};

// User input {{{1
// =============================================================================

fn print_prompt(prompt: str = "") void = {
        fmt::print(prompt)!;
        bufio::flush(os::stdout)!;
};

fn accept_string(prompt: str = "") str = {
        print_prompt(prompt);
        const buffer = match (bufio::read_line(os::stdin)!) {
                case let buffer: []u8 =>
                        yield buffer;
                case =>
                        return "";
                };
        defer free(buffer);
        return strings::dup(strings::fromutf8(buffer)!)!;
};

fn press_enter(prompt: str = "") void = {
        free(accept_string(prompt));
};

// Return `true` if the given string is "yes" or a synonym.
//
fn is_yes(s: str) bool = {
        const lowercase_s = ascii::strlower(s)!;
        defer free(lowercase_s);
        return switch(lowercase_s) {
                case "ok", "y", "yeah", "yes" =>
                        yield true;
                case =>
                        yield false;
        };
};

// Return `true` if the given string is "no" or a synonym.
//
fn is_no(s: str) bool = {
        const lowercase_s = ascii::strlower(s)!;
        defer free(lowercase_s);
        return switch(lowercase_s) {
                case "n", "no", "nope" =>
                        yield true;
                case =>
                        yield false;
        };
};

// Print the given prompt, wait until the user enters a valid yes/no string,
// and return `true` for "yes" or `false` for "no".
//
fn yes(prompt: str) bool = {
        for (true) {
                let answer = accept_string(prompt);
                defer free(answer);
                if (is_yes(answer)) {
                        return true;
                };
                if (is_no(answer)) {
                        return false;
                };
        };
};

// Main {{{1
// =============================================================================

// Print the given prompt and update the array whose address is given with a
// three-digit number from the user.
//
fn get_input(prompt: str, user_digit: *[DIGITS]int) void = {
        def ASCII_0 = 48;
        for :get_loop (true) {
                let input = accept_string(prompt);
                defer free(input);
                if (len(input) != DIGITS) {
                        fmt::printfln("Remember it's a {}-digit number.", DIGITS)!;
                        continue :get_loop;
                };
                for (let pos = 0; pos < len(input): int; pos += 1) {
                        let digit = strings::toutf8(input)[pos];
                        if (ascii::isdigit(digit: rune)) {
                                user_digit[pos] = digit: int - ASCII_0;
                        } else {
                                fmt::println("What?")!;
                                continue :get_loop;
                        };
                };
                if (is_any_repeated(user_digit)) {
                        fmt::println("Remember my number has no two digits the same.")!;
                        continue :get_loop;
                };
                break;
        };
};

def DIGITS = 3;

let random_digit: [DIGITS]int = [0 ...];

// Return three random digits.
//
fn random_number() [DIGITS]int = {
        for (let i = 0; i < DIGITS; i += 1) {
                for :digit_loop (true) {
                        random_digit[i] = random::u64n(&rand, 10): int;
                        for (let j = 0; j < i; j += 1) {
                                if (i != j && random_digit[i] == random_digit[j]) {
                                        continue :digit_loop;
                                };
                        };
                        break;
                };
        };
        return random_digit;
};

// Return `true` if any of the given numbers is repeated; otherwise return
// `false`.
//
fn is_any_repeated(num: []int) bool = {
        const length: int = len(num): int;
        for (let i0 = 0; i0 < length; i0 += 1) {
                for (let n1 .. num[i0 + 1 .. length]) {
                        if (num[i0] == n1) {
                                return true;
                        };
                };
        };
        return false;
};

// Init and run the game loop.
//
fn play() void = {
        def TRIES = 20;
        let score = 0;
        let fermi = 0; // counter
        let pico = 0; // counter
        let user_number: [DIGITS]int = [0...];
        for (true) {
                clear_screen();
                let computer_number = random_number();
                fmt::println("O.K.  I have a number in mind.")!;
                for (let guess = 1; guess <= TRIES; guess += 1) {
                        // XXX TMP
                        // fmt::print("My number: ")!;
                        // for (let i = 0; i < DIGITS; i += 1) {
                        //      fmt::print(computer_number[i])!;
                        // };
                        // fmt::println()!;
                        get_input(fmt::asprintf("Guess #{:_02}: ", guess)!, &user_number);
                        fermi = 0;
                        pico = 0;
                        for (let i = 0; i < DIGITS; i += 1) {
                                for (let j = 0; j < DIGITS; j += 1) {
                                        if (user_number[i] == computer_number[j]) {
                                                if (i == j) {
                                                        fermi += 1;
                                                } else {
                                                        pico += 1;
                                                };
                                        };
                                };
                        };
                        let picos = repeat("PICO ", pico);
                        defer free(picos);
                        let fermis = repeat("FERMI ", fermi);
                        defer free(fermis);
                        fmt::print(picos)!;
                        fmt::print(fermis)!;
                        if (pico + fermi == 0) {
                                fmt::print("BAGELS")!;
                        };
                        fmt::println()!;
                        if (fermi == DIGITS) {
                                break;
                        };
                };
                if (fermi == DIGITS) {
                        fmt::println("You got it!!!")!;
                        score += 1;
                } else {
                        fmt::println("Oh well.")!;
                        fmt::printf("That's {} guesses.  My number was ", TRIES)!;
                        for (let i = 0; i < DIGITS; i += 1) {
                                fmt::print(computer_number[i])!;
                        };
                        fmt::println(".")!;
                };
                if (!yes("Play again? ")) {
                        break;
                };
        };
        if (score != 0) {
                fmt::printfln("A {}-point bagels, buff!!", score)!;
        };
        fmt::println("Hope you had fun.  Bye.")!;
};

let rand: random::random = 0;

fn randomize() void = {
        rand = random::init(time::now(time::clock::MONOTONIC).sec: u64);
};

fn init() void = {
        randomize();
};

export fn main() void = {
        init();
        print_credits();
        print_instructions();
        play();
};

In Janet

# Bagels

# Original version in BASIC:
#   D. Resek, P. Rowe, 1978.
#   Creative Computing (Morristown, New Jersey, USA), 1978.

# This version in Janet:
#   Copyright (c) 2023, Marcos Cruz (programandala.net)
#   SPDX-License-Identifier: Fair
#
# Written in 2025-12-26/27.
#
# Last modified: 20251227T1413+0100.

(defn move-cursor-home []
  (prin "\e[H"))

(defn clear-screen []
  (prin "\e[2J")
  (move-cursor-home))

(defn command [&opt prompt-text]
  (default prompt-text "> ")
  (prin prompt-text)
  (string/trim (getline)))

(defn press-enter [prompt-text]
  (while (not= (command prompt-text) "")) (break))

(defn is-yes? [word]
  (index-of (string/ascii-lower word) ["ok" "y" "yeah" "yes"]))

(defn is-no? [word]
  (index-of (string/ascii-lower word) ["n" "no" "nope"]))

(defn yes? [question]
  (var answer "")
  (while (not (or (is-yes? answer) (is-no? answer)))
    (set answer (command question)))
  (is-yes? answer))

(defn print-credits []
  (clear-screen)
  (print "Bagels")
  (print "Number guessing game\n")
  (print "Original source unknown but suspected to be:")
  (print "    Lawrence Hall of Science, U.C. Berkely.\n")
  (print "Original version in BASIC:")
  (print "    D. Resek, P. Rowe, 1978.")
  (print "    Creative computing (Morristown, New Jersey, USA), 1978.\n")
  (print "This version in Janet:")
  (print "    Copyright (c) 2025, Marcos Cruz (programandala.net)")
  (print "    SPDX-License-Identifier: Fair\n")
  (press-enter "Press Enter to read the instructions. "))

(defn print-instructions []
  (clear-screen)
  (print "Bagels")
  (print "Number guessing game\n")
  (print "I am thinking of a three-digit number that has no two digits the same.")
  (print "Try to guess it and I will give you clues as follows:\n")
  (print "   PICO   - one digit correct but in the wrong position")
  (print "   FERMI  - one digit correct and in the right position")
  (print "   BAGELS - no digits correct\n")
  (press-enter "Press Enter to start. "))

(def digits 3)

(def random-number-generator (math/rng (os/time)))

(defn random-digits
  "Return an array containing `digits` random integer numbers in range [0, 9]"
  []
  (var result @[])
  (while (< (length result) digits)
    (var digit (math/rng-int random-number-generator 10))
    (when (not (has-value? result digit))
      (array/push result digit)))
  result)

(defn digit?
  "Is the string a digit?"
  [s]
  (and
    (= (length s) 1)
    (scan-number s)))

(defn only-digits? [s]
  (string/check-set "0123456789" s))

(defn input [prompt-text]
  `Return an array containing three random integer numbers in range [0, 9],
  out of the string typed in by the user.`

  (var user-digit @[])
  (forever
    (def raw-input (command prompt-text))
    (cond
      (not= (length raw-input) digits)
        (print "Remember it's a " digits "-digit number.")
      (not (only-digits? raw-input))
        (print "What?")
      (not= digits (length (distinct raw-input)))
        (print "Remember my number has no two digits the same.")
      (do
        (for c 0 digits
          (put user-digit c (scan-number (string/slice raw-input c (+ c 1)))))
        (break))))
  user-digit)

(defn play []
  (def tries 20)
  (var computer-number (array/new digits))
  (var user-number (array/new digits))
  (var score 0)
  (var fermi 0) # counter
  (var pico 0) # counter
  (forever
    (clear-screen)
    (set computer-number (random-digits))
    (print "O.K.  I have a number in mind.")
    (for guess 0 tries
      (set user-number
        (input (string "Guess #" (string/format "%02d" guess) ": ")))
      (set fermi 0)
      (set pico 0)
      (for i 0 digits
        (for j 0 digits
          (when (= (get computer-number i) (get user-number j))
            (if (= i j)
              (+= fermi 1)
              (+= pico 1)))))
      (if (= (+ pico fermi) 0)
        (prin "BAGELS")
        (do
          (prin (string/repeat "PICO " pico))
          (prin (string/repeat "FERMI " fermi))))
      (print)
      (when (= fermi digits)
        (break)))
    (if (= fermi digits)
      (do
        (print "You got it!!!")
        (+= score 1))
      (do
        (print "Oh well.")
        (print "That's " tries " guesses.  My number was ")
        (print (get computer-number 0) (get computer-number 1) (get computer-number 2) "\n")))
    (when (not (yes? "Play again? "))
      (break)))
  (when (not= score 0)
    (print "A " score "-point bagels, buff!!"))
  (print "Hope you had fun.  Bye."))

(defn main [& args]
  (print-credits)
  (print-instructions)
  (play))

In Julia

# Bagels

# Original version in BASIC:
#   D. Resek, P. Rowe, 1978.
#   Creative Computing (Morristown, New Jersey, USA), 1978.

# This version in Julia:
#   Copyright (c) 2024, Marcos Cruz (programandala.net)
#   SPDX-License-Identifier: Fair
#
# Written in 2024-07-03/04.
#
# Last modified: 20240704T1235+0200.

# Move the cursor to the home position.

function home()
    print("\e[H")
end

# Clear the screen and move the cursor to the home position.

function clear_screen()
    print("\e[2J")
    home()
end

# Prompt the user to enter a command and return it.

function command(prompt = "> ")::String
    print(prompt)
    return readline()
end

# Print the given prompt and wait until the user enters an empty string.

function press_enter(prompt::String)
    while command(prompt) != ""
    end
end


# Return `true` if the given string is "yes" or a synonym; otherwise return
# `false`.

function is_yes(answer::String)::Bool
    return lowercase(answer) in ["y", "yeah", "yes", "ok"]
end

# Return `true` if the given string is "no" or a synonym; otherwise return
# `false`.

function is_no(answer::String)::Bool
    return lowercase(answer) in ["n", "no", "nope"]
end

# Print the given prompt, wait until the user enters a valid yes/no string, and
# return `true` for "yes" or `false` for "no".

function yes(prompt::String)::Bool
    answer = ""
    while ! (is_yes(answer) || is_no(answer))
        answer = command(prompt)
    end
    return is_yes(answer)
end


# Clear the screen, display the credits and wait for a keypress.

function print_credits()
    clear_screen()
    println("Bagels")
    println("Number guessing game\n")
    println("Original source unknown but suspected to be:")
    println("    Lawrence Hall of Science, U.C. Berkely.\n")
    println("Original version in BASIC:")
    println("    D. Resek, P. Rowe, 1978.")
    println("    Creative computing (Morristown, New Jersey, USA), 1978.\n")
    println("This version in Julia:")
    println("    Copyright (c) 2024, Marcos Cruz (programandala.net)")
    println("    SPDX-License-Identifier: Fair\n")
    press_enter("Press Enter to read the instructions. ")
end

# Clear the screen, print the instructions and wait for a keypress.

function print_instructions()
    clear_screen()
    println("Bagels")
    println("Number guessing game\n")
    println("I am thinking of a three-digit number that has no two digits the same.")
    println("Try to guess it and I will give you clues as follows:\n")
    println("   PICO   - one digit correct but in the wrong position")
    println("   FERMI  - one digit correct and in the right position")
    println("   BAGELS - no digits correct")
    press_enter("\nPress Enter to start. ")
end

const DIGITS        = 3
const MIN_DIGIT     = 0
const MAX_DIGIT     = 9
const INVALID_DIGIT = MAX_DIGIT + 1
const TRIES         = 20

function has_other_than_digits(text::String)::Bool
    for char in text
        if ! isdigit(char)
            return true
        end
    end
    return false
end

# Print the given prompt and get a three-digit number from the user.

function input(prompt::String)::Array{Int64, 1}
    user_digit = Int[]
    while true
        user_input = command(prompt)
        if length(user_input) != DIGITS
            println("Remember it's a $DIGITS-digit number.")
            continue
        elseif has_other_than_digits(user_input)
            println("What?")
            continue
        end
        empty!(user_digit)
        for c in user_input
            push!(user_digit, parse(Int, c))
        end
        user_unique_digit = unique(user_digit)
        if length(user_unique_digit) != length(user_digit)
            println("Remember my number has no two digits the same.")
            continue
        end
        break
    end
    return user_digit
end

# Init and run the game loop.

function play()
    computer_number = [INVALID_DIGIT, INVALID_DIGIT, INVALID_DIGIT]
    user_number = [INVALID_DIGIT, INVALID_DIGIT, INVALID_DIGIT]
    score = 0
    fermi = 0  # counter
    pico = 0   # counter
    while true # game loop
        clear_screen()
        for i in 1 : DIGITS
            while true
                digit = rand(MIN_DIGIT : MAX_DIGIT)
                if digit in computer_number
                    continue
                else
                    computer_number[i] = digit
                    break
                end
            end
        end
        println("O.K.  I have a number in mind.")
        for guess in 1 : TRIES
            user_number = input("Guess #$(lpad(guess, 2, '0')): ")
            fermi = 0
            pico = 0
            for i in 1 : DIGITS
                for j in 1 : DIGITS
                    if computer_number[i] == user_number[j]
                        if i == j
                            fermi += 1
                        else
                            pico += 1
                        end
                    end
                end
            end
            print(repeat("PICO ", pico))
            print(repeat("FERMI ", fermi))
            if pico + fermi == 0
                print("BAGELS")
            end
            println()
            if fermi == DIGITS
                println("You got it!!!")
                score += 1
                break # tries loop
            end
        end # tries loop
        if fermi != DIGITS
            println("Oh well.")
            print("That's $TRIES guesses.  My number was ")
            for i in 1 : DIGITS
                print(computer_number[i])
            end
            println(".")
        end
        if ! yes("Play again? ")
            break # game loop
        end
    end # game loop
    if score != 0
        println("A $score-point bagels, buff!!")
    end
    println("Hope you had fun.  Bye.")
end

print_credits()
print_instructions()
play()

In Kotlin

/*
Bagels

Original version in BASIC:
    D. Resek, P. Rowe, 1978.
    Creative Computing (Morristown, New Jersey, USA), 1978.

This version in Kotlin:
    Copyright (c) 2023, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written in 2023-10.

Last modified: 20250420T0003+0200.
*/


// Move the cursor to the home position.
fun home() {
    print("\u001B[H")
}

// Clear the screen and move the cursor to the home position.
fun clear() {
    print("\u001B[2J")
    home()
}

// Wait until the user presses the Enter key.
// Clear the screen, display the credits and wait for a keypress.
fun printCredits() {
    clear()
    println("Bagels")
    println("Number guessing game\n")
    println("Original source unknown but suspected to be:")
    println("    Lawrence Hall of Science, U.C. Berkely.\n")
    println("Original version in BASIC:")
    println("    D. Resek, P. Rowe, 1978.")
    println("    Creative computing (Morristown, New Jersey, USA), 1978.\n")
    println("This version in Kotlin:")
    println("    Copyright (c) 2023, Marcos Cruz (programandala.net)")
    println("    SPDX-License-Identifier: Fair\n")
    print("Press Enter to read the instructions. ")
    readln()
}

// Clear the screen, print the instructions and wait for a keypress.
fun printInstructions() {
    clear()
    println("Bagels")
    println("Number guessing game\n")
    println("I am thinking of a three-digit number that has no two digits the same.")
    println("Try to guess it and I will give you clues as follows:\n")
    println("   PICO   - one digit correct but in the wrong position")
    println("   FERMI  - one digit correct and in the right position")
    println("   BAGELS - no digits correct")
    print("\nPress Enter to start. ")
    readln()
}

const val DIGITS = 3

// Return three random digits.
fun random(): IntArray {
    var randomDigit = IntArray(DIGITS)
    for (i in 0..<DIGITS) {
        digitLoop@ while (true) {
            randomDigit[i] = (0..9).random()
            for (j in 0..<i) {
                if (i != j && randomDigit[i] == randomDigit[j]) { continue@digitLoop }
            }
            break
        }
    }
    return randomDigit
}

const val ASCII_0 = 48

// Print the given prompt and get a three-digit number from the user.
fun input(prompt: String): IntArray {
    var userDigit = IntArray(DIGITS)
    getLoop@ while (true) {
        print(prompt)
        var input = readln()
        if (input.length != DIGITS) {
            println("Remember it's a $DIGITS-digit number.")
            continue@getLoop
        }
        for ((pos, digit) in input.withIndex()) {
            if (digit.isDigit()) {
                userDigit[pos] = digit.code - ASCII_0
            } else {
                println("What?")
                continue@getLoop
            }
        }
        if (userDigit.distinct().count() != DIGITS) {
            println("Remember my number has no two digits the same.")
            continue@getLoop
        }
        break
    }
    return userDigit
}

// Return `true` if the given String is "yes" or a synonym.
fun isYes(answer: String): Boolean {
    when (answer.lowercase()) {
        "ok", "yeah", "yes", "y" -> return true
        else -> return false
    }
}

// Return `true` if the given String is "no" or a synonym.
fun isNo(answer: String): Boolean {
    when (answer.lowercase()) {
        "no", "nope", "n" -> return true
        else -> return false
    }
}

// Print the given prompt, wait until the user enters a valid yes/no
// String, and return `true` for "yes" or `false` for "no".
fun yes(prompt: String): Boolean {
    var answer = ""
    while (!(isYes(answer) || isNo(answer))) {
        print(prompt)
        answer = readln()
    }
    return isYes(answer)
}

const val TRIES = 20

// Init and run the game loop.
fun play() {
    var score = 0
    while (true) {
        clear()
        var computerNumber = random()
        var fermi = 0
        println("O.K. I have a number in mind.")
        for (guess in 1..TRIES) {
            var userNumber = input("Guess #${guess.toString().padStart(2, '0')}: ")
            fermi = 0
            var pico = 0
            for (i in 0..<DIGITS) {
                for (j in 0..<DIGITS) {
                    if (userNumber[i] == computerNumber[j]) {
                        if (i == j) {
                            fermi += 1
                        } else {
                            pico += 1
                        }
                    }
                }
            }
            print("PICO ".repeat(pico))
            print("FERMI ".repeat(fermi))
            if (pico + fermi == 0) { print("BAGELS") }
            println()
            if (fermi == DIGITS) { break }
        }
        if (fermi == DIGITS) {
            println("You got it!!!")
            score += 1
        } else {
            println("Oh well.")
            print("That's $TRIES guesses.  My number was ")
            for (i in 0..<DIGITS) { print(computerNumber[i]) }
            println(".")
        }
        if (!yes("Play again? ")) { break }
    }
    if (score != 0) {
        println("A $score-point bagels, buff!!")
    }
    println("Hope you had fun.  Bye.")
}

fun main() {
    printCredits()
    printInstructions()
    play()
}

In Nim

#[
Bagels

Original version in BASIC:
  D. Resek, P. Rowe, 1978.
  Creative Computing (Morristown, New Jersey, USA), 1978.

This version in Nim:
  Copyright (c) 2025, Marcos Cruz (programandala.net)
  SPDX-License-Identifier: Fair

Written in 2025-01-19/20.

Last modified: 20250124T0133+0100.
]#

import std/random
import std/sequtils
import std/strformat
import std/strutils
import std/terminal
import std/unicode

proc cursorHome() =
  setCursorPos(0, 0)

proc clearScreen() =
  eraseScreen()
  cursorHome()

# Clear the screen, display the credits and wait for a keypress.
#
proc printCredits() =

  clearScreen()
  writeLine(stdout, "Bagels")
  writeLine(stdout, "Number guessing game\n")
  writeLine(stdout, "Original source unknown but suspected to be:")
  writeLine(stdout, "    Lawrence Hall of Science, U.C. Berkely.\n")
  writeLine(stdout, "Original version in BASIC:")
  writeLine(stdout, "    D. Resek, P. Rowe, 1978.")
  writeLine(stdout, "    Creative computing (Morristown, New Jersey, USA), 1978.\n")
  writeLine(stdout, "This version in Nim:")
  writeLine(stdout, "    Copyright (c) 2025, Marcos Cruz (programandala.net)")
  writeLine(stdout, "    SPDX-License-Identifier: Fair\n")
  write(stdout, "Press Enter to read the instructions. ")
  discard readLine(stdin)

# Clear the screen, print the instructions and wait for a keypress.
#
proc printInstructions() =

  clearScreen()
  writeLine(stdout, "Bagels")
  writeLine(stdout, "Number guessing game\n")
  writeLine(stdout, "I am thinking of a three-digit number that has no two digits the same.")
  writeLine(stdout, "Try to guess it and I will give you clues as follows:\n")
  writeLine(stdout, "   PICO   - one digit correct but in the wrong position")
  writeLine(stdout, "   FERMI  - one digit correct and in the right position")
  writeLine(stdout, "   BAGELS - no digits correct")
  write(stdout, "\nPress Enter to start. ")
  discard readLine(stdin)

const digits = 3

# Return a sequence containing as many random digits as the value of the
# `digits` constant.
#
proc random(): seq[int]  =
  while len(result) < digits:
    var digit = rand(9)
    if digit notin result:
      add(result, digit)

# Print the given prompt and update the array whose address is given with a
# three-digit number from the user.
#
proc getInput(prompt: string, userDigit: var array[digits, int]) =

  var ok = false
  while not ok:
    write(stdout, prompt)
    var input = readLine(stdin)
    if len(input) != digits:
      writeLine(stdout, "Remember it's a ", digits, "-digit number.")
      continue
    ok = true
    for pos, charDigit in input:
      if isDigit(charDigit):
        var stringDigit = newStringOfCap(1)
        add(stringDigit, charDigit)
        userDigit[pos] = parseInt(stringDigit)
      else:
        ok = false
        writeLine(stdout, "What?")
        break
    if ok and len(deduplicate(userDigit)) < digits:
      writeLine(stdout, "Remember my number has no two digits the same.")
      ok = false

# Return `true` if the given string is "yes" or a synonym.
#
proc isYes(s: string): bool  =

  return toLower(s) in ["ok", "y", "yeah", "yes"]

# Return `true` if the given string is "no" or a synonym.
#
proc isNo(s: string): bool  =

  return toLower(s) in ["n", "no", "nope"]

# Print the given prompt, wait until the user enters a valid yes/no string,
# and return `true` for "yes" or `false` for "no".
#
proc yes(prompt: string): bool  =

  while true:
    write(stdout, prompt)
    var answer = readLine(stdin)
    if isYes(answer):
      return true
    if isNo(answer):
      return false

# Init and run the game loop.
#
proc play() =

  const tries = 20
  var score = 0
  var fermi: int # counter
  var pico: int # counter
  var userNumber: array[digits, int]
  while true:
    clearScreen()
    var computerNumber = random()
    writeLine(stdout, "O.K.  I have a number in mind.")
    for guess in 1 .. tries:
      # writeLine(stdout, "My number: ", computerNumber) # XXX TMP
      getInput(fmt"Guess #{guess:00}: ", userNumber)
      fermi = 0
      pico = 0
      for i in 0 ..< digits:
        for j in 0 ..< digits:
          if userNumber[i] == computerNumber[j]:
            if i == j:
              fermi += 1
            else:
              pico += 1

      write(stdout, repeat("PICO ", pico))
      write(stdout, repeat("FERMI ", fermi))
      if pico + fermi == 0:
        write(stdout, "BAGELS")
      writeLine(stdout, "")
      if fermi == digits:
        break
    if fermi == digits:
      writeLine(stdout, "You got it!!!")
      score += 1
    else:
      writeLine(stdout, "Oh well.")
      write(stdout, "That's ", tries, " guesses.  My number was ")
      for i in 0 ..< digits:
        write(stdout, computerNumber[i])
      writeLine(stdout, ".")
    if not yes("Play again? "):
      break
  if score != 0:
    writeLine(stdout, "A ", score, "-point bagels, buff!!")
  writeLine(stdout, "Hope you had fun.  Bye.")

printCredits()
printInstructions()
play()

In Odin

/*
Bagels

Original version in BASIC:
    D. Resek, P. Rowe, 1978.
    Creative Computing (Morristown, New Jersey, USA), 1978.

This version in Odin:
    Copyright (c) 2023, 2024, 2025, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written in 2023-04, 2023-09/10, 2023-12, 2024-12, 2025-02.

Last modified: 20250407T1920+0200.
*/

package bagels

import "../lib/anodino/src/read"
import "../lib/anodino/src/term"
import "core:fmt"
import "core:math/rand"
import "core:slice"
import "core:strings"
import "core:unicode"

press_enter :: proc(prompt: string) {

    s, _ := read.a_prompted_string(prompt)
    delete(s)

}

// Clear the screen, display the credits and wait for a keypress.
//
print_credits :: proc() {

    term.clear_screen()
    fmt.println("Bagels")
    fmt.println("Number guessing game\n")
    fmt.println("Original source unknown but suspected to be:")
    fmt.println("    Lawrence Hall of Science, U.C. Berkely.\n")
    fmt.println("Original version in BASIC:")
    fmt.println("    D. Resek, P. Rowe, 1978.")
    fmt.println("    Creative computing (Morristown, New Jersey, USA), 1978.\n")
    fmt.println("This version in Odin:")
    fmt.println("    Copyright (c) 2023, 2024, 2025, Marcos Cruz (programandala.net)")
    fmt.println("    SPDX-License-Identifier: Fair\n")
    press_enter("Press Enter to read the instructions. ")

}

// Clear the screen, print the instructions and wait for a keypress.
//
print_instructions :: proc() {

    term.clear_screen()
    fmt.println("Bagels")
    fmt.println("Number guessing game\n")
    fmt.println("I am thinking of a three-digit number that has no two digits the same.")
    fmt.println("Try to guess it and I will give you clues as follows:\n")
    fmt.println("   PICO   - one digit correct but in the wrong position")
    fmt.println("   FERMI  - one digit correct and in the right position")
    fmt.println("   BAGELS - no digits correct")
    press_enter("\nPress Enter to start. ")

}

DIGITS :: 3

random_digit : [DIGITS]int

// Return three random digits.
//
random :: proc() -> []int {

    for i in 0 ..< DIGITS {
        digit_loop: for {
            random_digit[i] = rand.int_max(10)
            for j in 0 ..< i {
                if i != j && random_digit[i] == random_digit[j] do continue digit_loop
            }
            break
        }
    }
    return random_digit[:]

}

// Return `true` if any of the given numbers is repeated; otherwise return
// `false`.
//
is_any_repeated :: proc(num : []int) -> bool {

    for n0, i0 in num[:] {
        for n1 in num[i0 + 1 : len(num)] {
            if n0 == n1 do return true
        }
    }
    return false

}

// Print the given prompt and update the array whose address is given with a
// three-digit number from the user.
//
get_input :: proc(prompt : string, user_digit : ^[DIGITS]int) {

    // XXX TODO Create a local array, appending every digit after checking the contents,
    // making `is_any_repeated` unnecessary.
    ASCII_0 :: 48
    get_loop: for {
        input, ok := read.a_prompted_string(prompt)
        defer delete(input)
        if !ok do input = ""
        if len(input) != DIGITS {
            fmt.printfln("Remember it's a %v-digit number.", DIGITS)
            continue get_loop
        }
        for digit, pos in input {
            if unicode.is_digit(digit) {
                user_digit^[pos] = int(digit) - ASCII_0
            } else {
                fmt.println("What?")
                continue get_loop
            }
        }
        if is_any_repeated(user_digit[:]) {
            fmt.println("Remember my number has no two digits the same.")
            continue get_loop
        }
        break
    }

}

// Return `true` if the given string is "yes" or a synonym.
//
is_yes :: proc(s : string) -> bool {

    lowercase_s := strings.to_lower(s)
    defer delete(lowercase_s)
    return slice.any_of([]string{"ok", "y", "yeah", "yes"}, lowercase_s)

}

// Return `true` if the given string is "no" or a synonym.
//
is_no :: proc(s : string) -> bool {

    lowercase_s := strings.to_lower(s)
    defer delete(lowercase_s)
    return slice.any_of([]string{"n", "no", "nope"}, lowercase_s)

}

// Print the given prompt, wait until the user enters a valid yes/no string,
// and return `true` for "yes" or `false` for "no".
//
yes :: proc(prompt : string) -> bool {

    for {
        answer, ok := read.a_prompted_string(prompt)
        defer delete(answer)
        if !ok do answer = ""
        if is_yes(answer) do return true
        if is_no(answer) do return false
    }

}

// Init and run the game loop.
//
play :: proc() {

    TRIES  :: 20
    score := 0
    fermi : int // counter
    pico  : int // counter
    user_number : [DIGITS]int
    for {
        term.clear_screen()
        computer_number := random()
        fmt.println("O.K.  I have a number in mind.")
        for guess in 1 ..= TRIES {
            // fmt.printfln("My number: %v", computer_number) // XXX TMP
            get_input(fmt.tprintf("Guess #%2v: ", guess), &user_number)
            fermi = 0
            pico = 0
            for i in 0 ..< DIGITS {
                for j in 0 ..< DIGITS {
                    if user_number[i] == computer_number[j] {
                        if i == j {
                            fermi += 1
                        } else {
                            pico += 1
                        }
                    }
                }
            }
            picos := strings.repeat("PICO ", pico)
            defer delete(picos)
            fermis := strings.repeat("FERMI ", fermi)
            defer delete(fermis)
            fmt.print(picos)
            fmt.print(fermis)
            if pico + fermi == 0 do fmt.print("BAGELS")
            fmt.println()
            if fermi == DIGITS do break
        }
        if fermi == DIGITS {
            fmt.println("You got it!!!")
            score += 1
        } else {
            fmt.println("Oh well.")
            fmt.printf("That's %v guesses.  My number was ", TRIES)
            for i in 0 ..< DIGITS do fmt.print(computer_number[i])
            fmt.println(".")
        }
        if !yes("Play again? ") do break
    }
    if score != 0 {
        fmt.printfln("A %v-point bagels, buff!!", score)
    }
    fmt.println("Hope you had fun.  Bye.")

}

main :: proc() {

    print_credits()
    print_instructions()
    play()

}

In Pike

#!/usr/bin/env pike

// Bagels

// Original version in BASIC:
//  D. Resek, P. Rowe, 1978.
//  Creative Computing (Morristown, New Jersey, USA), 1978.

// This version in Pike:
//  Copyright (c) 2025, Marcos Cruz (programandala.net)
//  SPDX-License-Identifier: Fair
//
// Written on 2025-03-10.
//
// Last modified: 20250324T1737+0100.

// Terminal {{{1
// =============================================================================

constant NORMAL_STYLE = 0;

void move_cursor_home() {
    write("\x1B[H");
}

void set_style(int style) {
    write("\x1B[%dm", style);
}

void reset_attributes() {
    set_style(NORMAL_STYLE);
}

void erase_screen() {
    write("\x1B[2J");
}

void clear_screen() {
    erase_screen();
    reset_attributes();
    move_cursor_home();
}

// Credits and instructions {{{1
// =============================================================================

// Clear the screen, display the credits and wait for a keypress.
//
void print_credits() {
    clear_screen();
    write("Bagels\n");
    write("Number guessing game\n\n");
    write("Original source unknown but suspected to be:\n");
    write("    Lawrence Hall of Science, U.C. Berkely.\n\n");
    write("Original version in BASIC:\n");
    write("    D. Resek, P. Rowe, 1978.\n");
    write("    Creative computing (Morristown, New Jersey, USA), 1978.\n\n");
    write("This version in Pike:\n");
    write("    Copyright (c) 2025, Marcos Cruz (programandala.net)\n");
    write("    SPDX-License-Identifier: Fair\n\n");
    accept_string("Press Enter to read the instructions. ");
}

// Clear the screen, print the instructions and wait for a keypress.
//
void print_instructions() {
    clear_screen();
    write("Bagels\n");
    write("Number guessing game\n\n");
    write("I am thinking of a three-digit number that has no two digits the same.\n");
    write("Try to guess it and I will give you clues as follows:\n\n");
    write("   PICO   - one digit correct but in the wrong position\n");
    write("   FERMI  - one digit correct and in the right position\n");
    write("   BAGELS - no digits correct\n\n");
    accept_string("Press Enter to start. ");
}

// User input {{{1
// =============================================================================

string accept_string(string prompt) {
    write(prompt);
    return Stdio.stdin->gets();
}

// Return `true` if the given string is "yes" or a synonym.
//
bool is_yes(string s) {
    switch(lower_case(s)) {
        case "ok":
        case "y":
        case "yeah":
        case "yes":
            return true;
        default:
            return false;
    }
}

// Return `true` if the given string is "no" or a synonym.
//
bool is_no(string s) {
    switch(lower_case(s)) {
        case "n":
        case "no":
        case "nope":
            return true;
        default:
            return false;
    }
}

// Print the given prompt, wait until the user enters a valid yes/no string,
// and return `true` for "yes" or `false` for "no".
//
bool yes(string prompt) {
    while (true) {
        string answer = accept_string(prompt);
        if (is_yes(answer)) {
            return true;
        }
        if (is_no(answer)) {
            return false;
        }
    }
}

// Main {{{1
// =============================================================================

constant DIGITS = 3;

bool is_digit(int ascii_code) {
    return (ascii_code >= '0') && (ascii_code <= '9');
}

// Print the given prompt and return an array with a three-digit number type by
// the user.
//
array(int) get_input(string prompt) {
    array(int) user_digit = allocate(DIGITS);
    constant ASCII_0 = '0';
    get_loop: while (true) {
        string input = accept_string(prompt);
        if (sizeof(input) != DIGITS) {
            write("Remember it's a %d-digit number.\n", DIGITS);
            continue get_loop;
        }
        for (int pos = 0; pos < sizeof(input); pos += 1) {
            int digit = input[pos];
            if (is_digit(digit)) {
                user_digit[pos] = digit - ASCII_0;
            } else {
                write("What?\n");
                continue get_loop;
            }
        }
        if (is_any_repeated(user_digit)) {
            write("Remember my number has no two digits the same.\n");
            continue get_loop;
        }
        break;
    }
    return user_digit;
}

// Return three random digits.
//
array(int) random_number() {
    array(int) random_digit = allocate(DIGITS);
    for (int i = 0; i < DIGITS; i += 1) {
        digit_loop: while (true) {
            random_digit[i] = random(10);
            for (int j = 0; j < i; j += 1) {
                if (i != j && random_digit[i] == random_digit[j]) {
                    continue digit_loop;
                }
            }
            break;
        }
    }
    return random_digit;
}

// Return `true` if any of the given numbers is repeated; otherwise return
// `false`.
//
bool is_any_repeated(array(int) numbers) {
    array(int) filtered_numbers = Array.uniq(numbers);
    return !equal(filtered_numbers, numbers);
}

// Init and run the game loop.
//
void play() {
    constant TRIES = 20;
    int score = 0;
    int fermi = 0; // counter
    int pico = 0; // counter
    array(int) computer_number = allocate(DIGITS);
    array(int) user_number = allocate(DIGITS);
    while (true) {
        clear_screen();
        array(int) computer_number = random_number();
        write("O.K.  I have a number in mind.\n");
        for (int guess = 1; guess <= TRIES; guess += 1) {
            // XXX TMP
            // write("My number: ");
            // for (int i = 0; i < DIGITS; i += 1) {
            //  write("%d", computer_number[i]);
            // }
            // write("\n");
            user_number = get_input(sprintf("Guess #%02d: ", guess));
            fermi = 0;
            pico = 0;
            for (int i = 0; i < DIGITS; i += 1) {
                for (int j = 0; j < DIGITS; j += 1) {
                    if (user_number[i] == computer_number[j]) {
                        if (i == j) {
                            fermi += 1;
                        } else {
                            pico += 1;
                        }
                    }
                }
            }
            if (pico + fermi == 0) {
                write("BAGELS\n");
            } else {
                write("%s%s\n", "PICO " * pico, "FERMI " * fermi);
                if (fermi == DIGITS) {
                    break;
                }
            }
        }
        if (fermi == DIGITS) {
            write("You got it!!!\n");
            score += 1;
        } else {
            write("Oh well.\n");
            write("That's %d guesses.  My number was ", TRIES);
            for (int i = 0; i < DIGITS; i += 1) {
                write("%d", computer_number[i]);
            }
            write(".\n");
        }
        if (!yes("Play again? ")) {
            break;
        }
    }
    if (score != 0) {
        write("A %d-point bagels, buff!!\n", score);
    }
    write("Hope you had fun.  Bye.\n");
}

void main() {
    print_credits();
    print_instructions();
    play();
}

In Python

# Bagels

# Original version in BASIC:
#   D. Resek, P. Rowe, 1978.
#   Creative Computing (Morristown, New Jersey, USA), 1978.

# This version in Python:
#   Copyright (c) 2024, Marcos Cruz (programandala.net)
#   SPDX-License-Identifier: Fair
#
# Written on 2024-10-29.
#
# Last modified: 20241203T2230+0100.

import os
import random

# Clear the screen and move the cursor to the home position.

def clear_screen():
    if os.name == 'nt':
        _ = os.system('cls')
    else:
        # on mac and linux, `os.name` is 'posix'
        _ = os.system('clear')

# Prompt the user to enter a command and return it.

def command(prompt = "> "):
    return input(prompt)

# Print the given prompt and wait until the user enters an empty string.

def press_enter(prompt):
    user_input = "X"
    while user_input != "":
        user_input = command(prompt)

# Return `True` if the given string is "yes" or a synonym; otherwise return
# `False`.

def is_yes(answer):
    return answer.lower() in ["y", "yeah", "yes", "ok"]

# Return `True` if the given string is "no" or a synonym; otherwise return
# `False`.

def is_no(answer):
    return answer.lower() in ["n", "no", "nope"]

# Print the given prompt, wait until the user enters a valid yes/no string, and
# return `True` for "yes" or `False` for "no".

def yes(prompt):
    answer = ""
    while not (is_yes(answer) or is_no(answer)):
        answer = command(prompt)
    return is_yes(answer)

# Clear the screen, display the credits and wait for a keypress.

def print_credits():
    clear_screen()
    print("Bagels")
    print("Number guessing game\n")
    print("Original source unknown but suspected to be:")
    print("    Lawrence Hall of Science, U.C. Berkely.\n")
    print("Original version in BASIC:")
    print("    D. Resek, P. Rowe, 1978.")
    print("    Creative computing (Morristown, New Jersey, USA), 1978.\n")
    print("This version in Python:")
    print("    Copyright (c) 2024, Marcos Cruz (programandala.net)")
    print("    SPDX-License-Identifier: Fair\n")
    press_enter("Press Enter to read the instructions. ")

# Clear the screen, print the instructions and wait for a keypress.

def print_instructions():
    clear_screen()
    print("Bagels")
    print("Number guessing game\n")
    print("I am thinking of a three-digit number that has no two digits the same.")
    print("Try to guess it and I will give you clues as follows:\n")
    print("   PICO   - one digit correct but in the wrong position")
    print("   FERMI  - one digit correct and in the right position")
    print("   BAGELS - no digits correct")
    press_enter("\nPress Enter to start. ")

DIGITS        = 3
MIN_DIGIT     = 0
MAX_DIGIT     = 9
INVALID_DIGIT = MAX_DIGIT + 1
TRIES         = 20

def has_other_than_digits(text):
    for char in text:
        if not char.isdigit():
            return True
    return False

# Print the given prompt and get a three-digit number from the user.

def input_digits(prompt):
    user_digit = []
    while True:
        user_input = command(prompt)
        if len(user_input) != DIGITS:
            print(f"Remember it's a {DIGITS}-digit number.")
            continue
        elif has_other_than_digits(user_input):
            print("What?")
            continue
        user_digit.clear()
        for c in user_input:
            user_digit.append(int(c))
        if len(set(user_digit)) != len(user_digit):
            print("Remember my number has no two digits the same.")
            continue
        break
    return user_digit

# Init and run the game loop.

def play():
    computer_number = [INVALID_DIGIT, INVALID_DIGIT, INVALID_DIGIT]
    user_number = [INVALID_DIGIT, INVALID_DIGIT, INVALID_DIGIT]
    score = 0
    fermi = 0  # counter
    pico = 0   # counter
    while True: # game loop
        clear_screen()
        for i in range(0, DIGITS):
            while True:
                digit = random.randrange(MIN_DIGIT, MAX_DIGIT + 1)
                if digit in computer_number:
                    continue
                else:
                    computer_number[i] = digit
                    break
        print("O.K.  I have a number in mind.")
        for guess in range(0, TRIES):
            user_number = input_digits("Guess #" + str(guess).zfill(2) + ": ")
            fermi = 0
            pico = 0
            for i in range(0, DIGITS):
                for j in range(0, DIGITS):
                    if computer_number[i] == user_number[j]:
                        if i == j:
                            fermi += 1
                        else:
                            pico += 1
            print("PICO " * pico, end = "")
            print("FERMI " * fermi, end = "")
            if pico + fermi == 0:
                print("BAGELS", end = "")
            print()
            if fermi == DIGITS:
                print("You got it!!!")
                score += 1
                break # tries loop
        # end of tries loop
        if fermi != DIGITS:
            print("Oh well.")
            print(f"That's {TRIES} guesses.  My number was ", end = "")
            for i in range(0, DIGITS):
                print(computer_number[i], end = "")
            print(".")
        if not yes("Play again? "):
            break # game loop
    # end of game loop
    if score != 0:
        print(f"A {score}-point bagels, buff!!")
    print("Hope you had fun.  Bye.")

print_credits()
print_instructions()
play()

In Raku

# Bagels

# Original version in BASIC:
#   D. Resek, P. Rowe, 1978.
#   Creative Computing (Morristown, New Jersey, USA), 1978.

# This version in Raku:
#   Copyright (c) 2024, Marcos Cruz (programandala.net)
#   SPDX-License-Identifier: Fair
#
# Written in 2024-12.
#
# Last modified: 20241211T1933+0100.

sub clear_screen {

    print "\e[0;0H\e[2J";

}

sub print_credits {

    clear_screen;
    put "Bagels";
    put "Number guessing game\n";
    put "Original source unknown but suspected to be:";
    put "    Lawrence Hall of Science, U.C. Berkely.\n";
    put "Original version in BASIC:";
    put "    D. Resek, P. Rowe, 1978.";
    put "    Creative computing (Morristown, New Jersey, USA), 1978.\n";
    put "This version in Raku:";
    put "    Copyright (c) 2024, Marcos Cruz (programandala.net)";
    put "    SPDX-License-Identifier: Fair\n";
    prompt "Press Enter to read the instructions. ";

}

sub print_instructions {

    clear_screen;
    put "Bagels";
    put "Number guessing game\n";
    put "I am thinking of a three-digit number that has no two digits the same.";
    put "Try to guess it and I will give you clues as follows:\n";
    put "   PICO   - one digit correct but in the wrong position";
    put "   FERMI  - one digit correct and in the right position";
    put "   BAGELS - no digits correct";
    prompt "\nPress Enter to start. ";

}

constant $DIGITS = 3;

# Return three random digits in an integer array.
sub random_number(--> Array) {

    my Int @random_digit = ();

    while @random_digit.elems < $DIGITS {
        loop {
            @random_digit.push((0 .. 9).pick);
            if @random_digit.unique.elems == @random_digit.elems {
                last;
            }
            @random_digit.pop
        }
    }

    return @random_digit;

}

# Print the given prompt and get a three-digit number from the user.
sub input(Str $prompt --> Array) {

    my Int @user_digit = ();
    PROMPT: loop {
        my $input = prompt($prompt);
        if $input.chars != $DIGITS {
            put "Remember it's a {$DIGITS}-digit number.";
            next PROMPT;
        }
        for $input.comb -> $digit {
            try {
                @user_digit.push(+$digit);
                CATCH {
                    default {
                        put "What?";
                        next PROMPT;
                    }
                }
            }
        }
        if @user_digit.unique.elems < $DIGITS {
            put "Remember my number has no two digits the same.";
            next PROMPT;
        }
        last;
    }
    return @user_digit;

}

# Return `True` if the given string is "yes" or a synonym.
sub is_yes(Str $answer --> Bool ) {

    return $answer.lc (elem) ["ok", "y", "yeah", "yes"]

}

# Return `True` if the given string is "no" or a synonym.
sub is_no(Str $answer --> Bool) {

    return $answer.lc (elem) ["n", "no", "nope"];

}

# Print the given prompt, wait until the user enters a valid yes/no
# string, and return `True` for "yes" or `False` for "no".
sub yes(Str $prompt --> Bool) {

    loop {
        my $answer = prompt($prompt);
        if is_yes($answer) { return True };
        if is_no($answer) { return False };
    }

}

# Init and run the game loop.
sub play {

    constant $TRIES = 20;
    my Int $score = 0;
    my Int $fermi; # counter
    my Int $pico;  # counter
    loop {
        clear_screen;
        my @computer_number = random_number;
        put "O.K.  I have a number in mind.";
        for 1 .. $TRIES -> $guess {
            my @user_number = input(sprintf("Guess #%02d: ", $guess));
            $fermi = 0;
            $pico = 0;
            for 0 ..^ $DIGITS -> $i {
                for 0 ..^ $DIGITS -> $j {
                    if @user_number[$i] == @computer_number[$j] {
                        if $i == $j {
                            $fermi += 1;
                        } else {
                            $pico += 1;
                        }
                    }
                }
            }
            print "PICO " x $pico;
            print "FERMI " x $fermi;
            if $pico + $fermi == 0 { print "BAGELS" };
            put "";
            if $fermi == $DIGITS { last };
        }
        if $fermi == $DIGITS {
            put "You got it!!!";
            $score += 1;
        } else {
            put "Oh well.";
            put "That's $TRIES guesses.  My number was {@computer_number.join}.";
        }
        if !yes("Play again? ") { last };
    }
    if $score != 0 {
        put "A {$score}-point bagels, buff!!";
    }
    put "Hope you had fun.  Bye.";

}

print_credits;
print_instructions;
play;

In Ring

# Bagels

# Original version in BASIC:
#   D. Resek, P. Rowe, 1978.
#   Creative Computing (Morristown, New Jersey, USA), 1978.

# This version in Ring:
#   Copyright (c) 2024, Marcos Cruz (programandala.net)
#   SPDX-License-Identifier: Fair
#
# Written in 2024-04-05/09
#
# Last modified: 20240409T1055+0200.

ASCII_0 = 48
DIGITS =  3
TRIES  = 20
MAX_DIGIT = 9

# Clear the screen and move the cursor to the home position.
func clearScreen
    system("clear")
end

# Prompt the user to enter a command and return it.
func command(prompt)
    if prompt = null
        prompt = "> "
    end
    print(prompt)
    return getString()
end

# Print the given prompt and wait until the user enters an empty string.
func pressEnter(prompt)
    while command(prompt) != ""
    end
end

# Return `true` if the given string is "yes" or a synonym.
func isItYes(answer)
    switch lower(answer)
    case "ok"
        return true
    case "y"
        return true
    case "yeah"
        return true
    case "yes"
        return true
    else
        return false
    end
end

# Return `true` if the given string is "no" or a synonym.
func isItNo(answer)
    switch lower(answer)
    case "n"
        return true
    case "no"
        return true
    case "nope"
        return true
    else
        return false
    end
end

# Print the given prompt, wait until the user enters a valid yes/no
# string, and return `true` for "yes" or `false` for "no".
func yes(prompt)
    answer = ""
    while not (isItYes(answer) || isItNo(answer))
        answer = command(prompt)
    end
    return isItYes(answer)
end

# Clear the screen, display the credits and wait for a keypress.
func printCredits
    clearScreen()
    print("Bagels\n")
    print("Number guessing game\n\n")
    print("Original source unknown but suspected to be:\n")
    print("    Lawrence Hall of Science, U.C. Berkely.\n\n")
    print("Original version in BASIC:\n")
    print("    D. Resek, P. Rowe, 1978.\n")
    print("    Creative computing (Morristown, New Jersey, USA), 1978.\n\n")
    print("This version in Ring:\n")
    print("    Copyright (c) 2024, Marcos Cruz (programandala.net)\n")
    print("    SPDX-License-Identifier: Fair\n\n")
    pressEnter("Press Enter to read the instructions. ")
end

# Clear the screen, print the instructions and wait for a keypress.
func printInstructions
    clearScreen()
    print("Bagels\n")
    print("Number guessing game\n\n")
    print("I am thinking of a three-digit number that has no two digits the same.\n")
    print("Try to guess it and I will give you clues as follows:\n\n")
    print("   PICO   - one digit correct but in the wrong position\n")
    print("   FERMI  - one digit correct and in the right position\n")
    print("   BAGELS - no digits correct\n")
    pressEnter("\nPress Enter to start. ")
end

# Print the given prompt and return a three-digit number from the user.
func userInput(prompt)
    userNumber = list(DIGITS)
    while true
        inputString = command(prompt)
        if len(inputString) != DIGITS
            print("Remember it's a #{DIGITS}-digit number.\n")
            continue
        end
        if not isDigit(inputString)
            print("What?\n")
            continue
        end
        for digit = 1 to DIGITS
            userNumber[digit] = inputString[digit]
        next
        for digit = 1 to DIGITS
            if find(userNumber, userNumber[digit]) != digit
                print("Remember my number has no two digits the same.\n")
                continue 2
            end
        next
        break
    end
    return userNumber
end

# Init and run the game loop.
func play
    computerNumber = list(DIGITS) # random number
    userNumber = list(DIGITS) # user guess
    score = 0
    fermi = 0  # counter
    pico = 0   # counter
    while true # game loop
        clearScreen()
        for digit = 1 to DIGITS
            computerNumber[digit] = -1
        end
        for digit = 1 to DIGITS
            computerNumber[digit] = random(MAX_DIGIT)
            while find(computerNumber, computerNumber[digit]) != digit
                computerNumber[digit] = random(MAX_DIGIT)
            end
        end
        print("O.K.  I have a number in mind.\n")
        for guess = 1 to TRIES
            if guess < 10
                guessNumber = "#0" + guess
            else
                guessNumber = "#" + guess
            end
            userNumber = userInput("Guess " + guessNumber + ": ")
            fermi = 0
            pico = 0
            for i = 1 to DIGITS
                for j = 1 to DIGITS
                    if computerNumber[i] = userNumber[j]
                        if i = j
                            fermi += 1
                        else
                            pico += 1
                        end
                    end
                next
            next
            for x = 1 to pico
                print("PICO ")
            next
            for x = 1 to fermi
                print("FERMI ")
            next
            if pico + fermi = 0
                print("BAGELS")
            end
            print("\n")
            if fermi = DIGITS
                break
            end
        end # tries loop
        if fermi = DIGITS
            print("You got it!!!\n")
            score += 1
        else
            print("Oh well.\n")
            print("That's #{TRIES} guesses.  My number was ")
            print("" + computerNumber[1] + computerNumber[2] + computerNumber[3] + ".\n")
        end
        if not yes("Play again? ")
            break
        end
    end # game loop
    if score != 0
        print("A #{score}-point bagels, buff!!\n")
    end
    print("Hope you had fun.  Bye.\n")
end

func main()
    printCredits()
    printInstructions()
    play()
end

In Scala

/*
Bagels

Original version in BASIC:
  D. Resek, P. Rowe, 1978.
  Creative Computing (Morristown, New Jersey, USA), 1978.

This version in Scala:
  Copyright (c) 2023, Marcos Cruz (programandala.net)
  SPDX-License-Identifier: Fair

Written in 2023-09/10, 2023-11.

Last modified: 20231104T0112+0100.
*/

// Move the cursor to the home position.
def home() =
  print("\u001B[H")

// Clear the screen and move the cursor to the home position.
def clear() =
  print("\u001B[2J")
  home()

// Print the given prompt and wait until the user enters an empty string.
def pressEnter(prompt : String) =
  var ok = false
  while !ok do
    ok = io.StdIn.readLine(prompt) == ""
  end while

def printTitle() =
  clear()
  println("Bagels")
  println("Number guessing game\n")

// Clear the screen, display the credits and wait for a keypress.
def printCredits() =
  printTitle()
  println("Original source unknown but suspected to be:")
  println("    Lawrence Hall of Science, U.C. Berkely.\n")
  println("Original version in BASIC:")
  println("    D. Resek, P. Rowe, 1978.")
  println("    Creative computing (Morristown, New Jersey, USA), 1978.\n")
  println("This version in Scala:")
  println("    Copyright (c) 2023, Marcos Cruz (programandala.net)")
  println("    SPDX-License-Identifier: Fair\n")
  pressEnter("Press Enter to read the instructions. ")

// Clear the screen, print the instructions and wait for a keypress.
def printInstructions() =
  printTitle()
  println("I am thinking of a three-digit number that has no two digits the same.")
  println("Try to guess it and I will give you clues as follows:\n")
  println("   PICO   - one digit correct but in the wrong position")
  println("   FERMI  - one digit correct and in the right position")
  println("   BAGELS - no digits correct")
  pressEnter("\nPress Enter to start. ")

val Digits = 3

// Return three random digits.
def random() : Array[Int]  =
  val randomDigit = new Array[Int](Digits)
  var digit = 0
  for i <- 0 until Digits do
    var validDigit = false
    while !validDigit do
      digit = util.Random.nextInt(10)
      validDigit = !randomDigit.contains(digit)
    end while
    randomDigit(i) = digit
  end for
  randomDigit

// Prints the given prompt, waits until the user enters a valid integer and
// returns it.
def getNumber(prompt : String) : Int =
  var number = 0
  var ok = false
  while !ok do
    try
      number = io.StdIn.readLine(prompt).trim.toInt
      ok = true
    catch
    case _ => println("Invalid number.")
  end while
  number

// Prompts the user to enter a command and returns it trimmed.
def getString(prompt : String = "> ") : String =
  io.StdIn.readLine(prompt).trim

// Return `true` if any of the elements of the given string is repeated;
// otherwise return `false`.
def isAnyRepeated(s: String) : Boolean =
  s.size != s.toSet.size

def containsOnlyDigits(s: String) : Boolean =
  var ok = true
  s.foreach(char => ok = ok && char.toChar.isDigit)
  ok

// Print the given prompt and get a three-digit number from the user.
def input(prompt : String) : Array[Int]  =
  val ASCII_0 = 48
  val userDigit = new Array[Int](Digits)
  var inputString = ""
  var done = false
  while !done do
    inputString = getString(prompt)
    if inputString.size != Digits then
      println(s"Remember it's a ${Digits}-digit number.")
    else
      if containsOnlyDigits(inputString) then
        if isAnyRepeated(inputString) then
          println("Remember my number has no two digits the same.")
        else
          done = true
        end if
      else
        println("What?")
      end if
    end if
  end while
  for i <- 0 until Digits do
    userDigit(i) = inputString(i).asDigit
  end for
  userDigit

// Return `true` if the given string is "yes" or a synonym.
def isYes(answer : String) : Boolean  =
  Array("ok", "yeah", "yes", "y").contains(answer)

// Return `true` if the given string is "no" or a synonym.
def isNo(answer : String) : Boolean  =
  Array("no", "nope", "n").contains(answer)

// Print the given prompt, wait until the user enters a valid yes/no
// string, and return `true` for "yes" or `false` for "no".
def yes(prompt : String) : Boolean  =
  var answer = ""
  while !(isYes(answer) || isNo(answer)) do
    answer = getString(prompt)
  isYes(answer)

// Init and run the game loop.
def play() =
  val TRIES = 20
  var score = 0
  var playing = true
  var userNumber = new Array[Int](Digits)
  while playing do
    clear()
    var computerNumber = random()
    println("O.K.  I have a number in mind.")
    var fermi = 0
    var pico  = 0
    var guess = 1 // counter
    while fermi != Digits && guess <= TRIES do
      userNumber = input(s"Guess #${guess}: ")
      fermi = 0
      pico = 0
      for i <- 0 until Digits do
        for j <- 0 until Digits do
          if computerNumber(i) == userNumber(j) then
            if i == j then
              fermi += 1
            else
              pico += 1
            end if
          end if
        end for
      end for
      print("PICO ".repeat(pico))
      print("FERMI ".repeat(fermi))
      if pico + fermi == 0 then
        print("BAGELS")
      end if
      println()
      guess += 1
    end while
    if fermi == Digits then
      println("You got it!!!")
      score += 1
    else
      println("Oh well.")
      print(s"That's $TRIES guesses.  My number was ")
      computerNumber.foreach(print)
      println(".")
    end if
    if !yes("Play again? ") then
      playing = false
    end if
  end while // play loop
  if score != 0 then
    println(s"A ${score}-point bagels, buff!!")
  end if
  println("Hope you had fun.  Bye.")

@main def main() =
  printCredits()
  printInstructions()
  play()

In Swift

/*
Bagels

Original version in BASIC:
    D. Resek, P. Rowe, 1978.
    Creative Computing (Morristown, New Jersey, USA), 1978.

This version in Swift:
    Copyright (c) 2025, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written on 2025-04-24.

Last modified: 20250424T2222+0200.
*/

// Terminal {{{1
// =============================================================================

// Move the cursor to the home position.
func moveCursorHome() {
    print("\u{001B}[H", terminator: "")
}

// Clear the screen and move the cursor to the home position.
func clearScreen() {
    print("\u{001B}[2J", terminator: "")
    moveCursorHome()
}

// User input {{{1
// =============================================================================

func promptedString(with prompt: String) -> String {
    while true {
        print(prompt, terminator: "")
        if let input = readLine() {
            return input
        }
    }
}

func promptedInteger(with prompt: String) -> Int {
    while true {
        print(prompt, terminator: "")
        if let input = readLine(), let number = Int(input) {
            return number
        } else {
            print("Integer expected.")
        }
    }
}


func pressEnter(prompt: String) {
    print(prompt, terminator: "")
    let _ = readLine()
}

// Return `true` if the given string is "yes" or a synonym.
//
func isYes(_ s: String) -> Bool {
    return ["ok", "y", "yeah", "yes"].contains(s.lowercased())
}

// Return `true` if the given string is "no" or a synonym.
//
func isNo(_ s: String) -> Bool {
    return ["n", "no", "nope"].contains(s.lowercased())
}

// Print the given prompt, wait until the user enters a valid yes/no string,
// and return `true` for "yes" or `false` for "no".
//
func yes(prompt: String) -> Bool {
    while true {
        let answer = promptedString(with: prompt)
        if isYes(answer) {
            return true
        }
        if isNo(answer) {
            return false
        }
    }
}

// Credits and instructions {{{1
// =============================================================================

func printCredits() {
    clearScreen()
    print("Bagels")
    print("Number guessing game\n")
    print("Original source unknown but suspected to be:")
    print("    Lawrence Hall of Science, U.C. Berkely.\n")
    print("Original version in BASIC:")
    print("    D. Resek, P. Rowe, 1978.")
    print("    Creative computing (Morristown, New Jersey, USA), 1978.\n")
    print("This version in Swift:")
    print("    Copyright (c) 2025, Marcos Cruz (programandala.net)")
    print("    SPDX-License-Identifier: Fair\n")
    pressEnter(prompt: "Press Enter to read the instructions. ")
}

func printInstructions() {
    clearScreen()
    print("Bagels")
    print("Number guessing game\n")
    print("I am thinking of a three-digit number that has no two digits the same.")
    print("Try to guess it and I will give you clues as follows:\n")
    print("   PICO   - one digit correct but in the wrong position")
    print("   FERMI  - one digit correct and in the right position")
    print("   BAGELS - no digits correct")
    pressEnter(prompt: "\nPress Enter to start. ")
}

// Main {{{1
// =============================================================================

let DIGITS = 3

func randomNumber() -> [Int] {
    var randomDigits = [Int]()
    for _ in 0 ..< DIGITS {
        var digit: Int
        repeat {
            digit = Int.random(in: 0 ..< 10)
        } while randomDigits.contains(digit)
        randomDigits.append(digit)
    }
    return randomDigits
}

func userInput(prompt: String) -> [Int] {
    var number = [Int]()
    askForNumber: while true {
        let input = promptedString(with: prompt)
        if (input).count != DIGITS {
            print("Remember it's a \(DIGITS)-digit number.")
            continue askForNumber
        }
        for digitPosition in 0 ..< DIGITS {
            let digitIndex = input.index(input.startIndex, offsetBy: digitPosition)
            let digit = input[digitIndex]
            if "0" ... "9" ~= digit {
                let numericDigit = Int(String(digit))!
                if !number.contains(numericDigit) {
                    number.append(numericDigit)
                } else {
                    print("Remember my number has no two digits the same.")
                    continue askForNumber
                }
            } else {
                print("What?")
                continue askForNumber
            }
        }
        break
    }
    return number
}

// Game {{{1
// =============================================================================

// Init and run the game loop.
//
func play() {
    let TRIES = 20
    var score = 0
    var fermi = 0 // counter
    var pico = 0 // counter
    var userNumber: [Int]
    while true {
        clearScreen()
        let computerNumber = randomNumber()
        print("O.K.  I have a number in mind.")
        for guess in 1 ... TRIES {
            // print("My number: \(computerNumber)") // XXX TMP
            userNumber = userInput(prompt: "Guess #" + String(guess) + ": ")
            fermi = 0
            pico = 0
            for i in 0 ..< DIGITS {
                for j in 0 ..< DIGITS {
                    if userNumber[i] == computerNumber[j] {
                        if i == j {
                            fermi += 1
                        } else {
                            pico += 1
                        }
                    }
                }
            }
            if pico + fermi == 0 {
                print("BAGELS")
            } else {
                print(String(repeating: "PICO ", count: pico), terminator: "")
                print(String(repeating: "FERMI ", count: fermi))
            }
            if fermi == DIGITS {
                break
            }
        }
        if fermi == DIGITS {
            print("You got it!!!")
            score += 1
        } else {
            print("Oh well.")
            print("That's \(TRIES) guesses.  My number was ",terminator: "")
            for i in 0 ..< DIGITS {
                print(computerNumber[i], terminator: "")
            }
            print(".")
        }
        if !yes(prompt: "Play again? ") {
            break
        }
    }
    if score != 0 {
        print("A \(score)-point bagels, buff!!")
    }
    print("Hope you had fun.  Bye.")
}

printCredits()
printInstructions()
play()

In V

/*
Bagels

Original version in BASIC:
    D. Resek, P. Rowe, 1978.
    Creative Computing (Morristown, New Jersey, USA), 1978.

This version in V:
    Copyright (c) 2025, Marcos Cruz (programandala.net)
    SPDX-License-Identifier: Fair

Written on 2025-01-03, 2025-01-18.

Last modified: 20250731T1954+0200.
*/
import arrays
import os
import rand
import strings
import term

fn print_credits() {
    term.clear()
    println('Bagels')
    println('Number guessing game\n')
    println('Original source unknown but suspected to be:')
    println('    Lawrence Hall of Science, U.C. Berkely.\n')
    println('Original version in BASIC:')
    println('    D. Resek, P. Rowe, 1978.')
    println('    Creative computing (Morristown, New Jersey, USA), 1978.\n')
    println('This version in V:')
    println('    Copyright (c) 2025, Marcos Cruz (programandala.net)')
    println('    SPDX-License-Identifier: Fair\n')
    os.input('Press Enter to read the instructions. ')
}

fn print_instructions() {
    term.clear()
    println('Bagels')
    println('Number guessing game\n')
    println('I am thinking of a three-digit number that has no two digits the same.')
    println('Try to guess it and I will give you clues as follows:\n')
    println('   PICO   - one digit correct but in the wrong position')
    println('   FERMI  - one digit correct and in the right position')
    println('   BAGELS - no digits correct')
    os.input('\nPress Enter to start. ')
}

const digits = 3

// Print the given prompt and update the array whose address is given with a
// three-digit number from the user.
//
fn get_input(prompt string, mut user_digit []int) {
    asking: for {
        input := os.input(prompt)
        if input.len != digits {
            println("Remember it's a ${digits}-digit number.")
            continue asking
        }
        for i, digit in input {
            if u8(digit).is_digit() {
                user_digit[i] = int(digit) - int(`0`)
            } else {
                println('What?')
                continue asking
            }
        }
        if arrays.distinct[int](*user_digit).len < digits {
            println('Remember my number has no two digits the same.')
            continue asking
        }
        break
    }
}

// Return `true` if the given string is "yes" or a synonym.
//
fn is_yes(s string) bool {
    return ['ok', 'y', 'yeah', 'yes'].any(it == s.to_lower())
}

// Return `true` if the given string is "no" or a synonym.
//
fn is_no(s string) bool {
    return ['n', 'no', 'nope'].any(it == s.to_lower())
}

// Print the given prompt, wait until the user enters a valid yes/no string,
// and return `true` for "yes" or `false` for "no".
//
fn yes(prompt string) bool {
    mut result := false
    for {
        answer := os.input(prompt)
        if is_yes(answer) {
            result = true
            break
        }
        if is_no(answer) {
            result = false
            break
        }
    }
    return result
}

const tries = 20
const all_digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

// Init and run the game loop.
//
fn play() {
    mut score := 0
    mut fermi := 0 // counter
    mut pico := 0 // counter
    mut user_number := []int{len: digits}
    for {
        term.clear()
        mut computer_number := rand.choose(all_digits, 3) or { [1, 2, 3] }
        println('O.K.  I have a number in mind.')
        for guess := 1; guess <= tries; guess++ {
            get_input('Guess #${guess:2}: ', mut user_number)
            fermi = 0
            pico = 0
            for i in 0 .. digits {
                for j in 0 .. digits {
                    if user_number[i] == computer_number[j] {
                        if i == j {
                            fermi += 1
                        } else {
                            pico += 1
                        }
                    }
                }
            }
            print(strings.repeat_string('PICO ', pico))
            print(strings.repeat_string('FERMI ', fermi))
            if pico + fermi == 0 {
                print('BAGELS')
            }
            println('')
            if fermi == digits {
                break
            }
        }
        if fermi == digits {
            println('You got it!!!')
            score += 1
        } else {
            println('Oh well.')
            print("That's ${tries} guesses.  My number was ")
            for i in 0 .. digits {
                print(computer_number[i])
            }
            println('.')
        }
        if !yes('Play again? ') {
            break
        }
    }
    if score != 0 {
        println('A ${score}-point bagels, buff!!')
    }
    println('Hope you had fun.  Bye.')
}

fn main() {
    print_credits()
    print_instructions()
    play()
}

Related pages

Basics off
Metaproject about the "Basics of…" projects.

External related links