Z-End
Description of the page content
Conversion of Z-End to several programming languages.
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");
}
