Z-End

Description of the page content

Conversion of Z-End to several programming languages.

Tags:

This program has been converted to 6 programming languages.

Original

Origin of z-end.bas:

A to Z Book of Computer Games, by Thomas C. McIntire, 1979.

- https://archive.org/details/A_to_Z_Book_of_Computer_Games_1979_Thomas_C_McIntire
- https://archive.org/details/A_to_Z_Book_of_Computer_Games_1979_Thomas_C_McIntire/page/n293/mode/2up
- https://github.com/chaosotter/basic-games
- https://github.com/chaosotter/basic-games/tree/master/games/A%20to%20Z%20Book%20of%20Computer%20Games/Z-End

5 CLS: COLOR 12
10 REM  "Z-END"
15 PRINT TAB(37); "Z-End": PRINT: PRINT
20 REM
25 RANDOMIZE TIMER
30 GOSUB 9000
40 COLOR 10: PRINT "Skip the rules (Y/N)";
50 INPUT Q$: COLOR 15
60 IF LEFT$(Q$, 1) = "Y" OR LEFT$(Q$, 1) = "y" THEN 150
70 COLOR 14: PRINT
80 PRINT "I'll print the alphabet, and you're first.  You type the number of letters"
90 PRINT "that I should omit next time.  We take turns, and the limit per turn is five."
100 PRINT "The one that gets the 'Z' is the loser, and that's Z-End!"
110 PRINT
120 PRINT "Good luck, cuz I'm clever..."
150 PRINT: COLOR 15
155 LET Q$ = " "
160 DATA A,B,C,D,E,F,G,H,I,J,K,L,M
170 DATA N,O,P,Q,R,S,T,U,V,W,X,Y,Z,*
180 LET Z = 1
185 LET Q = 0
190 GOSUB 500
195 IF LEFT$(Q$, 1) = "Y" OR LEFT$(Q$, 1) = "y" THEN 155
200 LET P = 2
205 PRINT
210 COLOR 10: PRINT "Your turn (1-5)";
215 LET Q = 0
220 INPUT Q: COLOR 15
230 IF Q < 1 THEN 300
240 IF Q > 5 THEN 300
250 GOSUB 500
260 IF LEFT$(Q$, 1) = "Y" OR LEFT$(Q$, 1) = "y" THEN 155
270 GOSUB 800
280 GOTO 190
290 PRINT
300 PRINT "Illegal entry -- must be in range 1 to 5!"
310 GOTO 210
500 LET Z = Z + Q
550 FOR I = 1 TO 27
560 READ Z$
570 IF I = Z THEN 590
580 NEXT I
590 LET J = Z
600 COLOR 13: FOR I = J TO 26
610 PRINT Z$;
615 READ Z$
620 NEXT I
630 RESTORE
640 PRINT: COLOR 15
650 IF 26 - Z = 0 THEN 700
660 RETURN
700 PRINT "Z-End -- ";
710 IF P = 1 THEN 780
720 PRINT "Oops!"
730 PRINT
740 COLOR 10: PRINT "Do it again (Y/N)";
750 INPUT Q$: COLOR 15
760 IF LEFT$(Q$, 1) = "Y" OR LEFT$(Q$, 1) = "y" THEN PRINT: PRINT: GOTO 660
765 PRINT: PRINT "Goodbye."
770 END
780 PRINT "Ha ha!"
790 GOTO 730
800 PRINT
810 IF 26 - Z < 6 THEN 900
820 IF 26 - Z > 10 THEN 840
830 GOTO 920
840 LET Q = INT(10 * RND(1))
850 IF Q < 1 THEN 840
860 IF Q > 5 THEN 840
870 PRINT "My pick is"; STR$(Q); "."
880 LET P = 1
890 RETURN
900 LET Q = 26 - Z
910 GOTO 870
920 LET Q = 1
930 GOTO 870
9000 REM  "RANDOM NUMBER ROUTINE"
9010 LET Z = RND(1)
9020 RETURN


In Chapel

// Z-End

// Original version in BASIC:

// A to Z Book of Computer Games, by Thomas C. McIntire, 1979.
//  - https://archive.org/details/A_to_Z_Book_of_Computer_Games_1979_Thomas_C_McIntire/page/n293/mode/2up
//  - https://github.com/chaosotter/basic-games/tree/master/games/A%20to%20Z%20Book%20of%20Computer%20Games/Z-End

// This version in Chapel:
//     Copyright (c) 2026, Marcos Cruz (programandala.net)
//     SPDX-License-Identifier: Fair
//
// Written on 2026-02-09.
//
// Last modified: 20260209T1321+0100.

use IO;
use Random;

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

const BLACK = 0;
const RED = 1;
const GREEN = 2;
const YELLOW = 3;
const BLUE = 4;
const MAGENTA = 5;
const CYAN = 6;
const WHITE = 7;
const DEFAULT = 9;

const STYLE_OFF = 20;
const FOREGROUND = 30;
const BACKGROUND = 40;
const BRIGHT = 60;

const NORMAL_STYLE = 0;

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

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

proc color(n: int) {
    setStyle(n + FOREGROUND);
}

proc resetAttributes() {
    setStyle(NORMAL_STYLE);
}

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

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

// Input {{{1
// =============================================================================

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

proc acceptValidInteger(prompt: string): int {
    var result: int;
    while true {
        var s: string = acceptString(prompt);
        try {
            result = (s): int;
            break;
        }
        catch exc {
            writeln("Integer expected.");
        }
    }
    return result;
}

proc isYes(answer: string): bool {
    select answer.toLower() {
        when "ok", "y", "yeah", "yes" do return true;
        otherwise                     do return false;
    }
}

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

enum Player {
    computer,
    human,
}

const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

proc printRules() {
    clearScreen();
    color(RED);
    writeln("Z-End\n");
    var answer: string = acceptString("Skip the rules? (Y/N) ");
    if !isYes(answer) {
        color(YELLOW);
        writeln();
        writeln("I'll print the alphabet, and you're first.  You type the number of letters");
        writeln("that I should omit next time.  We take turns, and the limit per turn is five.");
        writeln("The one that gets the 'Z' is the loser, and that's Z-End!");
        writeln();
        writeln("Good luck, cuz I'm clever...");
        color(WHITE);
    }
    writeln();
}

var rsInt = new randomStream(int);
var firstLetter: int;

proc computerPick(): int {
    var pick: int;
    var remainingLetters: int = (alphabet.size - firstLetter): int;
    if remainingLetters < 6 {
        pick = remainingLetters - 1;
    } else if remainingLetters > 10 {
        pick = rsInt.next(1, 5);
    } else {
        pick = 1;
    }
    writeln("My pick is ", pick, ".");
    return pick;
}

proc humanPick(): int {
    var pick: int;
    while true {
        pick = acceptValidInteger("Your turn (1-5) ");
        color(WHITE);
        if pick < 1 || pick > 5 {
            writeln("Illegal entry -- must be in range 1 to 5!");
        } else {
            break;
        }
    }
    return pick;
}

proc gameOver(): bool {
    return firstLetter == alphabet.size - 1;
}

proc printAlphabet(omittedLetters: int = 0) {
    firstLetter += omittedLetters;
    color(MAGENTA);
    writeln(alphabet[firstLetter ..]);
    writeln();
    color(WHITE);
}

proc printResult(player: Player) {
    write("Z-End -- ");
    select player {
        when Player.computer do writeln("Ha ha!");
        when Player.human    do writeln("Oops!");
    }
}

proc pick(player: Player): int {
    select player {
        when Player.computer do return computerPick();
        otherwise            do return humanPick();
    }
}

proc playing(player: Player): bool {
    var picked: int = pick(player);
    printAlphabet(omittedLetters = picked);
    if gameOver() {
        printResult(player);
    }
    return !gameOver();
}

proc play() {
    firstLetter = 0;
    printAlphabet();
    while playing(Player.human) && playing(Player.computer) { }
}

proc again(): bool {
    writeln();
    var answer: string = acceptString("Do it again (Y/N) ");
    return isYes(answer);
}

proc main() {
    printRules();
    do {
        play();
    } while again();
    writeln("\nGoodbye.");
}

In D

// Z-End

// Original version in BASIC:

// A to Z Book of Computer Games, by Thomas C. McIntire, 1979.
//  - https://archive.org/details/A_to_Z_Book_of_Computer_Games_1979_Thomas_C_McIntire/page/n293/mode/2up
//  - https://github.com/chaosotter/basic-games/tree/master/games/A%20to%20Z%20Book%20of%20Computer%20Games/Z-End

// This version in D:
//     Copyright (c) 2025, Marcos Cruz (programandala.net)
//     SPDX-License-Identifier: Fair
//
// Written on 2025-12-19.
//
// Last modified: 20251219T1644+0100.

module z_end;

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

enum BLACK = 0;
enum RED = 1;
enum GREEN = 2;
enum YELLOW = 3;
enum BLUE = 4;
enum MAGENTA = 5;
enum CYAN = 6;
enum WHITE = 7;
enum DEFAULT = 9;

enum STYLE_OFF = 20;
enum FOREGROUND = 30;
enum BACKGROUND = 40;
enum BRIGHT = 60;

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 color(int n)
{
    setStyle(n + FOREGROUND);
}

void resetAttributes()
{
    setStyle(NORMAL_STYLE);
}

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

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

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

// Input {{{1
// =============================================================================

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

    color(GREEN);
    scope (exit)
    {
        color(WHITE);
    }
    write(prompt);
    return strip(readln());
}

int acceptValidInteger(string prompt)
{
    int result;
    while (true)
    {
        string s = acceptString(prompt);
        try
        {
            import std.conv : to;

            result = to!int(s);
            break;
        }
        catch (Exception exc)
        {
            import std.stdio : writeln;

            writeln("Integer expected.");
        }
    }
    return result;
}

bool isYes(string answer)
{
    import std.uni : toLower;

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

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

enum Player
{
    computer,
    human,
}

enum alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

void printRules()
{
    import std.stdio : writeln;

    clearScreen();
    color(RED);
    writeln("Z-End\n");
    string answer = acceptString("Skip the rules? (Y/N) ");
    if (!isYes(answer))
    {
        color(YELLOW);
        writeln();
        writeln("I'll print the alphabet, and you're first.  You type the number of letters");
        writeln("that I should omit next time.  We take turns, and the limit per turn is five.");
        writeln("The one that gets the 'Z' is the loser, and that's Z-End!");
        writeln();
        writeln("Good luck, cuz I'm clever...");
        color(WHITE);
    }
    writeln();
}

int firstLetter;

int computerPick()
{
    import std.conv : to;
    import std.stdio : writeln;

    int pick;
    int remainingLetters = to!int(alphabet.length - firstLetter);
    if (remainingLetters < 6)
    {
        pick = remainingLetters - 1;
    }
    else if (remainingLetters > 10)
    {
        import std.random : uniform;
        pick = uniform(1, 5 + 1);
    }
    else
    {
        pick = 1;
    }
    writeln("My pick is ", pick, ".");
    return pick;
}

int humanPick()
{
    import std.stdio : writeln;

    int pick;
    while (true)
    {
        pick = acceptValidInteger("Your turn (1-5) ");
        color(WHITE);
        if (pick < 1 || pick > 5)
        {
            writeln("Illegal entry -- must be in range 1 to 5!");
        }
        else
        {
            break;
        }
    }
    return pick;
}

bool gameOver()
{
    return firstLetter == alphabet.length - 1;
}

void printAlphabet(int omittedLetters = 0)
{
    import std.stdio : writeln;

    firstLetter += omittedLetters;
    color(MAGENTA);
    writeln(alphabet[firstLetter .. $]);
    writeln();
    color(WHITE);
}

void printResult(Player player)
{
    import std.stdio : write;
    import std.stdio : writeln;

    write("Z-End -- ");
    final switch (player)
    {
        case Player.computer:
            writeln("Ha ha!");
            break;
        case Player.human:
            writeln("Oops!");
            break;
    }
}

int pick(Player player)
{
    final switch (player)
    {
        case Player.computer:
            return computerPick();
        case Player.human:
            return humanPick();
    }
}

bool playing(Player player)
{
    int pick = pick(player);
    printAlphabet(omittedLetters: pick);
    if (gameOver())
    {
        printResult(player);
    }
    return !gameOver();
}

void play()
{
    firstLetter = 0;
    printAlphabet();
    while (playing(Player.human) && playing(Player.computer)) { }
}

bool again()
{
    import std.stdio : writeln;

    writeln();
    string answer = acceptString("Do it again (Y/N) ");
    return isYes(answer);
}

void main()
{
    import std.stdio : writeln;

    printRules();
    do
    {
        play();
    } while (again());
    writeln("\nGoodbye.");
}

In FreeBASIC

' Z-End

' Original version in BASIC:

' A to Z Book of Computer Games, by Thomas C. McIntire, 1979.
'  - https://archive.org/details/A_to_Z_Book_of_Computer_Games_1979_Thomas_C_McIntire/page/n293/mode/2up
'  - https://github.com/chaosotter/basic-games/tree/master/games/A%20to%20Z%20Book%20of%20Computer%20Games/Z-End

' This version in FreeBASIC:
'     Copyright (c) 2026, Marcos Cruz (programandala.net)
'     SPDX-License-Identifier: Fair
'
' Written in 2026-09-03/04.
'
' Last modified: 20260904T0024+0200.

const bright as integer => 8

' XXX TODO make an `enum`
const black as integer => 0
const dark_grey as integer => bright + black
const blue as integer => 1
const green as integer => 2
const cyan as integer => 3
const red as integer => 4
const pink as integer => 5
const magenta as integer => bright + pink
const yellow as integer => 6
const grey as integer => 7
const white as integer => bright + grey

const default_ink as integer => white
const alphabet_ink as integer => magenta
const input_ink as integer => bright + green
const instructions_ink as integer => yellow
const title_ink as integer => red

function get_string(prompt as string) as string
    dim typed as string
    color(input_ink)
    print prompt;
    line input typed
    color(default_ink)
    return typed
end function

function is_sign(character as string) as boolean
    assert(len(character) = 1)
    return character = "+" orelse character = "-"
end function

function is_digit(character as string) as boolean
    assert(len(character) = 1)
    return character >= "0" andalso character <= "9"
end function

function is_integer(s as string) as boolean
    for character_position as integer => 1 to len(s)
        dim character as string => mid(s, character_position, 1)
        if character_position = 1 then
            if not is_sign(character) andalso not is_digit(character) then
                return false
            end if
        elseif not is_digit(character) then
            return false
        end if
    next
    return true
end function

function get_number(prompt as string => "") as integer
    dim number as integer
    do
        dim s as string => get_string(prompt)
        if is_integer(s) then
            number => val(s)
            exit do
        else
            print "Integer expected."
        end if
    loop
    return number
end function

function is_yes(answer as string) as boolean
    select case lcase(trim(answer))
        case "ok", "y", "yeah", "yes"
            return true
        case else
            return false
    end select
end function

enum player_id explicit
    computer
    human
end enum

sub print_rules()
    cls
    color(title_ink)
    print !"Z-End\n"
    dim answer as string => get_string("Skip the rules? (Y/N) ")
    if not is_yes(answer) then

        color(instructions_ink)
        print
        print "I'll print the alphabet, and you're first.  You type the number of letters"
        print "that I should omit next time.  We take turns, and the limit per turn is five."
        print "The one that gets the 'Z' is the loser, and that's Z-End!"
        print
        print "Good luck, cuz I'm clever..."
        color(default_ink)
    end if
    print
end sub

function random_in_inclusive_range(first as integer, last as integer) as integer
    return int(rnd * (last - first) + first)
end function

const alphabet as string => "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
dim shared first_letter as integer => 1

function computer_pick() as integer
    dim picked as integer
    dim remaining_letters as integer => len(alphabet) - first_letter + 1
    if remaining_letters < 6 then
        picked => remaining_letters - 1
    elseif remaining_letters > 10 then
        picked => random_in_inclusive_range(1, 5)
    else
        picked => 1
    end if
    print "My pick is " & picked & "."
    return picked
end function

function human_pick() as integer
    dim picked as integer
    do
        picked => get_number("Your turn (1-5) ")
        if picked < 1 or picked > 5 then
            print "Illegal entry -- must be in range 1 to 5!"
        else
            exit do
        end if
    loop
    return picked
end function

function game_over() as boolean
    return first_letter = len(alphabet)
end function

sub print_alphabet(omitted_letters as integer => 0)
    first_letter += omitted_letters
    color(alphabet_ink)
    print mid(alphabet, first_letter)
    print
    color(default_ink)
end sub

sub print_result(player as player_id)
    print "Z-End -- ";
    select case player
        case player_id.computer
            print "Ha ha!"
        case player_id.human
            print "Oops!"
    end select
end sub

function pick(player as player_id) as integer
    select case player
        case player_id.computer
            return computer_pick()
        case player_id.human
            return human_pick()
    end select
end function

function playing(player as player_id) as boolean
    print_alphabet(pick(player))
    if game_over() then
        print_result(player)
    end if
    return not game_over()
end function

sub play()
    first_letter => 1
    print_alphabet()
    do while playing(player_id.human) andalso playing(player_id.computer)
    loop
end sub

function again() as boolean
    print
    dim answer as string => get_string("Do it again (Y/N) ")
    return is_yes(answer)
end function

print_rules()
do
    play()
loop while again()
print !"\nGoodbye."

' vim: filetype=freebasic

In Janet

# Z-End

# Original version in BASIC:

# A to Z Book of Computer Games, by Thomas C. McIntire, 1979.
#  - https://archive.org/details/A_to_Z_Book_of_Computer_Games_1979_Thomas_C_McIntire/page/n293/mode/2up
#  - https://github.com/chaosotter/basic-games/tree/master/games/A%20to%20Z%20Book%20of%20Computer%20Games/Z-End

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

# Terminal {{{1
# =============================================================================

(def black 0)
(def red 1)
(def green 2)
(def yellow 3)
(def blue 4)
(def magenta 5)
(def cyan 6)
(def white 7)
(def default-color 9)

(def style-off 20)
(def foreground 30)
(def background 40)
(def bright 60)

(def NORMAL_STYLE 0)

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

(defn set-style [style]
  (prin (string/format "\x1B[%dm" style)))

(defn color [n]
  (set-style (+ n foreground)))

(defn reset-attributes []
  (set-style NORMAL_STYLE))

(defn erase-screen []
  (prin "\x1B[2J"))

(defn clear-screen []
  (erase-screen)
  (move-cursor-home)
  (reset-attributes))

# Input {{{1
# =============================================================================

(defn accept-string [&opt prompt-text]
  (default prompt-text "> ")
  (color green)
  (defer (color white)
    (do
      (prin prompt-text)
      (flush)
      (string/trim (getline)))))

(defn accept-integer [prompt-text]
  (def input (accept-string prompt-text))
  (def number (scan-number input))
  (if number
    (math/trunc number)
    (do
      (print "Number expected.")
      (accept-integer prompt-text))))

(defn yes? [question]
  (def input (accept-string question))
  (index-of (string/ascii-lower input) ["ok" "y" "yeah" "yes"]))

# Main {{{1
# =============================================================================

(defn print-rules []
  (clear-screen)
  (color red)
  (print "Z-End\n")
  (when (not (yes? "Skip the rules? (Y/N) "))
    (color yellow)
    (print "\nI'll print the alphabet, and you're first.  You type the number of letters")
    (print "that I should omit next time.  We take turns, and the limit per turn is five.")
    (print "The one that gets the 'Z' is the loser, and that's Z-End!\n")
    (print "Good luck, cuz I'm clever..."))
  (print)
  (color white))

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

(defn uniform
  "Return a random integer in the range [minimum maximum)."
  [minimum maximum]
  (+ (math/rng-int random-number-generator (- maximum minimum)) minimum))

(def alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
(var first-letter 0)
(var remaining-letters (- (length alphabet) first-letter))

(def minimum-pick 1)
(def maximum-pick 5)

(defn computer-pick []
  (var pick 0)
  (set remaining-letters (- (length alphabet) first-letter))
  (cond
    (< remaining-letters 6) (set pick (- remaining-letters 1))
    (> remaining-letters > 10) (set pick (uniform minimum-pick (+ maximum-pick 1)))
    (set pick 1))
  (print "My pick is " pick ".")
  pick)

(defn human-pick []
  (var pick 0)
  (forever
    (set
      pick
      (accept-integer
        (string/format "Your turn (%d-%d) " minimum-pick maximum-pick)))
    (if (or (< pick minimum-pick) (> pick maximum-pick))
      (print "Illegal entry -- must be in range 1 to 5!")
      (break)))
  pick)

(defn game-over []
  (= first-letter (- (length alphabet) 1)))

(defn print-alphabet [&opt omitted-letters]
  (default omitted-letters 0)
  (+= first-letter omitted-letters)
  (color magenta)
  (print (string/slice alphabet first-letter))
  (print)
  (color white))

(defn print-result [player]
  (prin "Z-End -- ")
  (case player
    :computer
      (do
        (print "Ha ha!")
        (break))
    :human
      (do
        (print "Oops!")
        (break))))

(defn pick-of [player]
  (case player
    :computer (computer-pick)
    :human (human-pick)))

(defn playing [player]
  (print-alphabet (pick-of player))
  (when (game-over)
    (print-result player))
  (not (game-over)))

(defn play []
  (set first-letter 0)
  (print-alphabet)
  (while (and (playing :human) (playing :computer)) ()))

(defn again []
  (print)
  (yes? "Do it again (Y/N) "))

(defn main [& args]
  (print-rules)
  (forever
    (play)
    (when (not (again)) (break)))
  (print "\nGoodbye."))

In V

/*
Z-End

Original version in BASIC:

A to Z Book of Computer Games, by Thomas C. McIntire, 1979.
 - https://archive.org/details/A_to_Z_Book_of_Computer_Games_1979_Thomas_C_McIntire/page/n293/mode/2up
 - https://github.com/chaosotter/basic-games/tree/master/games/A%20to%20Z%20Book%20of%20Computer%20Games/Z-End

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

Written on 2026-03-11.

Last modified: 20260321T1702+0100.
*/
import encoding.utf8
import os
import rand
import strconv
import term

fn accept_string(prompt string) string {
    return os.input(term.colorize(term.green, prompt))
}

fn accept_integer(prompt string) int {
    mut n := 0
    for {
        n = strconv.atoi(accept_string(prompt)) or { continue }
        break
    }
    return n
}

fn is_yes(answer string) bool {
    match utf8.to_lower(answer) {
        'ok', 'y', 'yeah', 'yes' { return true }
        else { return false }
    }
}

enum Player {
    computer
    human
}

const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

fn print_rules() {
    term.clear()
    println(term.red('Z-End\n'))
    answer := accept_string('Skip the rules? (Y/N) ')
    if !is_yes(answer) {
        println('')
        println(term.yellow("I'll print the alphabet, and you're first.  You type the number of letters"))
        println(term.yellow('that I should omit next time.  We take turns, and the limit per turn is five.'))
        println(term.yellow("The one that gets the 'Z' is the loser, and that's Z-End!"))
        println('')
        println(term.yellow("Good luck, cuz I'm clever..."))
    }
    println('')
}

struct Status {
mut:
    first_letter int
}

fn computer_pick(status Status) int {
    mut pick := 0
    remaining_letters := int(alphabet.len - status.first_letter)
    if remaining_letters < 6 {
        pick = remaining_letters - 1
    } else if remaining_letters > 10 {
        pick = rand.int_in_range(1, 6) or { 1 }
    } else {
        pick = 1
    }
    println('My pick is ${pick}.')
    return pick
}

fn human_pick() int {
    mut pick := 0
    for {
        pick = accept_integer('Your turn (1-5) ')
        if pick < 1 || pick > 5 {
            println('Illegal entry -- must be in range 1 to 5!')
        } else {
            break
        }
    }
    return pick
}

fn game_over(status Status) bool {
    return status.first_letter == alphabet.len - 1
}

fn print_alphabet(omitted_letters int, mut status Status) {
    status.first_letter += omitted_letters
    println(term.colorize(term.magenta, alphabet[status.first_letter..]))
    println('')
}

fn print_result(player Player) {
    print('Z-End -- ')
    match player {
        .computer { println('Ha ha!') }
        .human { println('Oops!') }
    }
}

fn pick(player Player, mut status Status) int {
    match player {
        .computer { return computer_pick(status) }
        .human { return human_pick() }
    }
}

fn playing(player Player, mut status Status) bool {
    picked := pick(player, mut status)
    print_alphabet(picked, mut status)
    if game_over(status) {
        print_result(player)
    }
    return !game_over(status)
}

fn play() {
    mut status := Status{
        first_letter: 0
    }
    print_alphabet(0, mut status)
    for playing(Player.human, mut status) && playing(Player.computer, mut status) {
    }
}

fn again() bool {
    println('')
    answer := os.input_opt('Do it again (Y/N) ') or { '' }
    return is_yes(answer)
}

fn main() {
    print_rules()
    for {
        play()
        if !again() {
            break
        }
    }
    println('\nGoodbye.')
}

In Vala

// Z-End

// Original version in BASIC:

// A to Z Book of Computer Games, by Thomas C. McIntire, 1979.
//  - https://archive.org/details/A_to_Z_Book_of_Computer_Games_1979_Thomas_C_McIntire/page/n293/mode/2up
//  - https://github.com/chaosotter/basic-games/tree/master/games/A%20to%20Z%20Book%20of%20Computer%20Games/Z-End

// This version in Vala:
//   Copyright (c) 2026, Marcos Cruz (programandala.net)
//   SPDX-License-Identifier: Fair
//
// Written on 2026-08-27.
//
// Last modified: 20260828T1048+0200.


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

const int BLACK = 0;
const int RED = 1;
const int GREEN = 2;
const int YELLOW = 3;
const int BLUE = 4;
const int MAGENTA = 5;
const int CYAN = 6;
const int WHITE = 7;
const int DEFAULT = 9;

const int STYLE_OFF = 20;
const int FOREGROUND = 30;
const int BACKGROUND = 40;
const int BRIGHT = 60;

const int NORMAL_STYLE = 0;

const int DEFAULT_COLOR = WHITE;
const int ALPHABET_COLOR = MAGENTA;
const int INPUT_COLOR = GREEN;
const int INSTRUCTIONS_COLOR = YELLOW;
const int TITLE_COLOR = RED;

void move_cursor_home() {
    stdout.printf("\x1B[H");
}

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

void set_color(int n) {
    set_style(n + FOREGROUND);
}

void reset_attributes() {
    set_style(NORMAL_STYLE);
}

void erase_screen() {
    stdout.printf("\x1B[2J");
}

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

// Input {{{1
// =============================================================================

string accept_string(string prompt) {
    string result;
    set_color(INPUT_COLOR);
    stdout.printf(prompt);
    result = stdin.read_line().strip();
    set_color(DEFAULT_COLOR);
    return result;
}

bool is_sign(char character) {
    return character == '+' || character == '-';
}

bool is_digit(char character) {
    return character >= '0' && character <= '9';
}

bool is_integer(string s) {
    for (int c = 0; c < s.length; c++) {
        if (c == 0) {
            if (!is_sign(s[c]) && !is_digit(s[c])) {
                return false;
            }
        } else if (!is_digit(s[c])) {
            return false;
        }
    }
    return true;
}

int accept_integer(string prompt) {
    int result;
    while (true) {
        string s = accept_string(prompt);
        if (is_integer(s)) {
            result = int.parse(s);
            break;
        } else {
            stdout.printf("Integer expected.\n");
        }
    }
    return result;
}

bool is_yes(string s) {
    switch (s.down()) {
        case "ok", "y", "yeah", "yes":
            return true;
        default:
            return false;
    }
}

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

enum player_id {
    computer,
    human,
}

const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

void print_rules() {
    clear_screen();
    set_color(TITLE_COLOR);
    stdout.printf("Z-End\n\n");
    string answer = accept_string("Skip the rules? (Y/N) ");
    if (!is_yes(answer)) {
        set_color(INSTRUCTIONS_COLOR);
        stdout.printf("\n");
        stdout.printf("I'll print the alphabet, and you're first.  You type the number of letters\n");
        stdout.printf("that I should omit next time.  We take turns, and the limit per turn is five.\n");
        stdout.printf("The one that gets the 'Z' is the loser, and that's Z-End!\n");
        stdout.printf("\n");
        stdout.printf("Good luck, cuz I'm clever...\n");
        set_color(DEFAULT_COLOR);
    }
    stdout.printf("\n");
}

int first_letter;

int computer_pick() {
    int picked;
    int remaining_letters = (int) (alphabet.length - first_letter);
    if (remaining_letters < 6) {
        picked = remaining_letters - 1;
    }
    else if (remaining_letters > 10) {
        picked = GLib.Random.int_range(1, 5 + 1);
    }
    else {
        picked = 1;
    }
    stdout.printf(@"My pick is $picked.\n");
    return picked;
}

int human_pick() {
    int picked;
    while (true) {
        picked = accept_integer("Your turn (1-5) ");
        set_color(DEFAULT_COLOR);
        if (picked < 1 || picked > 5) {
            stdout.printf("Illegal entry -- must be in range 1 to 5!\n");
        }
        else {
            break;
        }
    }
    return picked;
}

bool game_over() {
    return first_letter == alphabet.length - 1;
}

void print_alphabet(int omitted_letters = 0) {
    first_letter += omitted_letters;
    set_color(ALPHABET_COLOR);
    stdout.printf(alphabet[first_letter :]);
    stdout.printf("\n\n");
    set_color(DEFAULT_COLOR);
}

void print_result(player_id player) {
    stdout.printf("Z-End -- ");
    switch (player) {
        case player_id.computer:
            stdout.printf("Ha ha!\n");
            break;
        case player_id.human:
            stdout.printf("Oops!\n");
            break;
    }
}

int pick(player_id player) {
    switch (player) {
        case player_id.computer:
            return computer_pick();
        case player_id.human:
            return human_pick();
    }
    assert_not_reached();
}

bool playing(player_id player) {
    int picked = pick(player);
    print_alphabet(picked);
    if (game_over()) {
        print_result(player);
    }
    return !game_over();
}

void play() {
    first_letter = 0;
    print_alphabet();
    while (playing(player_id.human) && playing(player_id.computer)) { }
}

bool again() {
    stdout.printf("\n");
    string answer = accept_string("Do it again (Y/N) ");
    return is_yes(answer);
}

void main() {
    print_rules();
    do {
        play();
    } while (again());
    stdout.printf("\nGoodbye.\n");
}

Related pages

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

External related links