High Noon
Descripción del contenido de la página
Conversión de High Noon a varios lenguajes de programación.
Este programa ha sido convertido a 12 lenguajes de programación.
Original
Origin of high_noon.bas:
Designed and programmed by Chris Gaylo, Syosset High School, New York,
1970-09-12.
Original listing:
- http://mybitbox.com/highnoon-1970/
Play online:
- http://mybitbox.com/highnoon/
Code transcriptions:
- https://github.com/MrMethor/Highnoon-BASIC/
- https://github.com/mad4j/basic-highnoon/blob/master/HIGHNOON.BAS
Version modified for QB64:
- https://github.com/mad4j/basic-highnoon/blob/master/HIGHNOON64.BAS
' HIGHNOON
' QB64 ADAPTATION BY DANIELE OLMISANI, 2014
' ORIGINALLY DESIGNED AND PROGRAMMED BY CHRIS GAYLO, SYOSSET H.S.--9/12/70
RANDOMIZE TIMER
PRINT "H I G H N O O N"
PRINT "----------------"
PRINT
PRINT "YOU HAVE BEEN CHALLENGED TO A SHOWDOWN BY BLACK BART, ONE OF"
PRINT "THE MEANEST DESPERADOES WEST OF THE ALLEGHENY MOUNTAINS."
PRINT "WHILE YOU ARE WALKING DOWN A DUSTY, DESERTED SIDE STREET,"
PRINT "BLACK BART EMERGES FROM A SALOON ONE HUNDRED PACES AWAY. BY"
PRINT "AGREEMENT, YOU EACH HAVE FOUR CARTRIDGES IN YOUR SIX-GUNS."
PRINT "YOUR MARKSMANSHIP EQUALS HIS. AT THE START OF THE WALKM NEI-"
PRINT "THER OF YOU CAN POSSIBLY HIT THE OTHER, AND AT THE END OF"
PRINT "THE WALK, NEITHER CAN MISS. THE CLOSER YOU GET, THE BETTER"
PRINT "YOUR CHANCES OF HITTING BART, BUT HE ALSO HAS BETER CHANCES"
PRINT "OF HITTING YOU."
GameInit:
LET X = 100
NewStrategy:
PRINT
PRINT "------------------------------------------"
PRINT "YOU ARE NOW"; X; "PACES APART FROM BART"
PRINT
PRINT "STRATEGIES:"
PRINT "1. ADVANCE"
PRINT "2. STAND STILL"
PRINT "3. FIRE"
PRINT "4. JUMP BEHIND THE WATERING TROUGH"
PRINT "5. GIVE UP"
PRINT "6. TURN TAIL AND RUN"
DO
INPUT "WHAT IS YOUR STRATEGY"; B
IF B < 1 OR B > 6 THEN
PRINT "YOU SURE AREN'T GOING TO LIVE VERY LONG IF YOU CAN'T EVEN"
PRINT "FOLLOW DIRECTIONS"
END IF
LOOP WHILE B < 1 OR B > 6
ON B GOTO AdvanceStrategy, StandStillStrategy, FireStrategy, 1410, 1510, 1610
AdvanceStrategy:
DO
PRINT
INPUT "HOW MANY PACES DO YOU ADVANCE"; S
IF S < 0 THEN
PRINT "NONE OF THIS NEGATIVE STUFF PARTNER, ONLY POSITIVE NUMBERS"
END IF
IF S > 10 THEN
PRINT "NOBODY CAN WALK THAT FAST"
END IF
LOOP WHILE S < 0 OR S > 10
X = X - S
GOTO BartStrategy
FireStrategy:
690 C = C + 1
700 IF C <= 4 THEN 750
710 PRINT "NICE GOING, ACE, YOU'VE RUN OUT OF SHELLS."
720 PRINT "NOW BART WON'T SHOOT UNTIL YOU TOUCH NOSES."
730 PRINT "YOU BETTER THINK OF SOMETHING FAST. (LIKE RUN)"
740 GOTO 1040
750 W = RND(-1) * 10
760 IF W > X / 10 THEN 820
770 IF C = 2 THEN 1820
780 IF C = 3 THEN 1840
790 PRINT "WHAT A LOUSY SHOT."
800 IF C = 4 THEN 710
810 GOTO 1460
820 PRINT "WHAT A SHOT, YOU GOT BLACK BART RIGHT BETWEEN THE EYES."
830 PRINT
840 PRINT
850 PRINT "AS MAYOR OF DODGE CITY, AND ON BEHALF OF ITS CITIZENS,"
860 PRINT "I EXTEND TO YOU OUR THANKS, AND PRESENT YOU WITH THIS"
870 PRINT "REWARD, A CHECK FOR $20,000, FOR KILLING BLACK BART."
880 PRINT
890 PRINT "******************************************************"
900 PRINT
910 PRINT "CHECK NO."; 1000 * RND(-1); " AUG."; INT(10 + 10 * RND(0)); "TH. 1889"
920 PRINT " CASHIER'S RECEIT---BANK OF DODGE CITY"
930 PRINT
940 PRINT " PAY TO THE BEARER ON DEMAND"
950 PRINT
960 PRINT " THE SUM OF"
970 PRINT
980 PRINT " TWENTY THOUSAND DOLLARS-------------------$20,000"
990 PRINT
1000 PRINT "******************************************************"
1010 PRINT
1020 PRINT "DON'T SPEND IT ALL IN ONE PLACE."
1030 GOTO 2080
BartStrategy:
1040 IF X < 10 THEN 1120
1050 Q = RND(-1) * 10
1060 IF Q > 5 THEN 1120
1070 Z = INT(2 + RND(-1) * 9)
1080 PRINT "BLACK BART MOVES"; Z; "PACES"
1090 X = X - Z
1100 PRINT "YOU ARE NOW"; X; "PACES APART"
1110 GOTO NewStrategy
1120 P = P + 1
1130 IF C > 4 THEN 1070
1140 IF P <= 4 THEN 1200
1150 IF P = 5 THEN 1180
1160 IF P > 6 THEN 2020
1170 GOTO 1070
1180 PRINT "NOW IS YOUR CHANCE, BART IS OUT OF SHELLS"
1190 GOTO 1070
1200 R = RND(-1) * 10
1210 PRINT "BART FIRES . . . . . ."
1220 IF R > X / 10 THEN 1300
1230 PRINT "A MISS . . . ."
1240 IF P = 2 THEN 1890
1250 IF P = 3 THEN 1940
1260 IF P > 4 THEN 1070
1270 IF P = 4 THEN 1960
1280 PRINT "WHEW, WERE YOU LUCKY. THAT BULLET JUST MISSED YOUR HEAD."
1290 GOTO 1490
1300 IF B = 4 THEN 1910
1310 PRINT "BART SHOT YOU RIGHT THROUGH THE HEART THAT TIME."
1320 PRINT "YOU WENT KICKIN' WITH YOUR BOOTS ON."
1330 GOTO 2080
StandStillStrategy:
PRINT "THAT MOVE MADE YOU A PERFECT STATIONARY TARGET"
GOTO BartStrategy
1410 T = T + 1
1420 IF T > 3 THEN 2060
1430 IF T > 3 THEN 2060
1440 PRINT "NOT A BAD MANEUVER, YOU THREW BART'S STRATEGY OFF"
1450 GOTO 1040
1460 IF P > 4 THEN 1050
1470 PRINT "YOU NOW HAVE"; 4 - C; "SHELLS TO BART'S"; 4 - P; "SHELLS."
1480 GOTO 1040
1490 PRINT "YOU NOW HAVE"; 4 - C; "SHELLS TO BART'S"; 4 - P; "SHELLS."
1500 GOTO NewStrategy
1510 PRINT "BLACK BART ACCEPTS. THE CONDITIONS ARE THAT HE WON'T SHOOT YOU"
1520 PRINT "IF YOU TAKE THE FIRST STAGE OUT OF TOWN AND NEVER COME BACK"
1530 PRINT "AGREED";
1540 INPUT H$
1550 IF H$ = "NO" THEN 1590
1570 PRINT "A VERY WISE DECISION."
1580 GOTO 2080
1590 PRINT "OH WELL, BACK TO THE SHOWDOWN"
1600 GOTO NewStrategy
1610 PRINT "HOW FAR DID YOU RUN";
1620 INPUT F
1630 IF F < 50 THEN 1670
1640 PRINT "MAN, DID HE RUN. HE RAN SO FAST EVEN DOGS COULDN'T"
1650 PRINT "CATCH HIM"
1660 GOTO 2080
1670 IF P >= 4 THEN 1770
1680 PRINT "BLACK BART FIRES"; 4 - P; "SHELLS......."
1690 IF 4 - P > 1 THEN 1730
1700 PRINT "HE GOT YOU RIGHT IN THE BACK. THATS WHAT YOU DESERVE"
1710 PRINT "FOR RUNNING"
1720 GOTO 2080
1730 PRINT "BLACK BART UNLOADED HIS GUN, ONCE IN YOUR BACK"
1740 PRINT "AND"; 3 - P; "TIMES IN YOUR A**. NOW YOU CAN'T EVEN REST IN"
1750 PRINT "PEACE."
1760 GOTO 2080
1770 PRINT "YOU WERE LUCKY, BART CAN ONLY THROW HIS GUN AT YOU, HE"
1780 PRINT "DOESN'T HAVE ANY SHELLS LEFT. YOU SHOULD REALLY BE DEAD."
1790 GOTO 2080
1800 IF P = 2 THEN 1940
1810 IF P = 3 THEN 1960
1820 PRINT "GRAZED BART IN THE RIGHT ARM"
1830 GOTO 1040
1840 PRINT "HE'S HIT IN THE LEFT SHOULDER, FORCING HIM TO USE HIS RIGHT"
1850 PRINT "HAND TO SHOOT WITH"
1860 GOTO 1040
1870 PRINT "THAT WAS YOUR LAST SHOT, YOU MISSED"
1880 GOTO 1040
1890 PRINT "BUT BART GOT YOU IN THE RIGHT SHIN."
1900 GOTO NewStrategy
1910 PRINT "THAT TRICK JUST SAVED YOUT LIFE. BART'S BULLET"
1920 PRINT "WAS STOPPED BY THE WOOD SIDES OF THE TROUGH."
1930 GOTO NewStrategy
1940 PRINT "THOUGH BART GOT YOU ON THE LEFT SIDE OF YOUR JAW."
1950 GOTO NewStrategy
1960 PRINT "BURT MUST HAVE JERKED THE TRIGGER"
1970 GOTO NewStrategy
2020 PRINT "BART JUST HI-TAILED IT OUT OF TOWN RATHER THAN FACE YOU WITH-"
2030 PRINT "OUT A LOADED GUN. YOU CAN REST ASSURED THAT BART WON'T EVER"
2040 PRINT "SHOW HIS FACE AROUND THIS TOWN AGAIN."
2050 GOTO 2080
2060 PRINT "HOW MANY WATERING TROUGHS DO YOU THINK ARE ON THIS STREET"
2070 GOTO NewStrategy
2080 PRINT
2090 PRINT "C.G. INC."
2100 REM THE VARIABLE USAGE IS AS FOLLOWS:
2110 REM D$--INSTRUCTION NEED
2120 REM A$--INTENT TO CONTINUE THE GAME AFTER RECEIVNIG INSTRUCTIONS
2130 REM A---STORES YOUR LUCKY NUMBER
2140 REM I---USED FOR THE RANDOM GENERATOR
2150 REM X---DENOTES THE DISTANCE BETWEEN YOU
2160 REM B---DENOTES THE NUMBER OF YOUR MOVE
2170 REM S---THE NUMBER OF PACES YOU ADVANCE
2180 REM C---COUNTER FOR THE NUMBER OF YOU SHELLS
2190 REM W---RANDOM NUMBER FOR HITTING OF BART
2200 REM Q---RANDOM NUMBER FOR BART'S CHOICE OF WALK OR FIRE
2210 REM Z---RANDOM NUMB BOR THE PACES BART ADVANCES
2220 REM P---COUNTER FOR BART'S REMAINING SHELLS
2230 REM R---RANDOM NUMBER FORBART HITTING YOU
2240 REM T---COUNTER FOR THE NUMBER OF WATERING TROUGHS
2250 REM F---DISTANCE YOU RUN
2260 REM H$--DECISION ON GIVING UP
2270 END
En C#
// High Noon
// Original version in BASIC:
// Designed and programmed by Chris Gaylo, Syosset High School, New York, 1970-09-12.
// http://mybitbox.com/highnoon-1970/
// http://mybitbox.com/highnoon/
// Transcriptions:
// https://github.com/MrMethor/Highnoon-BASIC/
// https://github.com/mad4j/basic-highnoon/
// Version modified for QB64:
// By Daniele Olmisani, 2014.
// https://github.com/mad4j/basic-highnoon/
// This improved remake in C#:
// Copyright (c) 2024, Marcos Cruz (programandala.net)
// SPDX-License-Identifier: Fair
//
// Written in 2024-12-25/26.
//
// Last modified: 20251205T1540+0100.
using System;
using System.Linq;
class HighNoon
{
static Random rand = new Random();
// Global variables and constants {{{1
// =============================================================
const ConsoleColor DEFAULT_COLOR = ConsoleColor.White;
const ConsoleColor INPUT_COLOR = ConsoleColor.Green;
const ConsoleColor INSTRUCTIONS_COLOR = ConsoleColor.DarkYellow;
const ConsoleColor TITLE_COLOR = ConsoleColor.Red;
const int INITIAL_DISTANCE = 100;
const int INITIAL_BULLETS = 4;
const int MAX_WATERING_TROUGHS = 3;
static int distance; // distance between both gunners, in paces
static string strategy; // player's strategy
static int playerBullets;
static int opponentBullets;
// User input {{{1
// =============================================================
// Print the given prompt and wait until the user enters a string.
//
static string GetString(string prompt = "")
{
Console.ForegroundColor = INPUT_COLOR;
Console.Write(prompt);
string input = Console.ReadLine();
Console.ForegroundColor = DEFAULT_COLOR;
return input;
}
// Print the given prompt and wait until the user enters an integer.
//
static int GetInteger(string prompt = "")
{
int n = 0;
Console.ForegroundColor = INPUT_COLOR;
while (true)
{
try
{
n = Int32.Parse(GetString(prompt));
break;
}
catch
{
}
}
Console.ForegroundColor = DEFAULT_COLOR;
return n;
}
// 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)
{
string answer = GetString(prompt);
if (IsYes(answer))
{
return true;
}
if (IsNo(answer))
{
return false;
}
}
}
// Title, instructions and credits {{{1
// =============================================================
// Print the title at the current cursor position.
//
static void PrintTitle()
{
Console.ForegroundColor = TITLE_COLOR;
Console.WriteLine("High Noon");
Console.ForegroundColor = DEFAULT_COLOR;
}
static void PrintCredits()
{
PrintTitle();
Console.WriteLine("\nOriginal version in BASIC:");
Console.WriteLine(" Designed and programmend by Chris Gaylo, 1970.");
Console.WriteLine(" http://mybitbox.com/highnoon-1970/");
Console.WriteLine(" http://mybitbox.com/highnoon/");
Console.WriteLine("Transcriptions:");
Console.WriteLine(" https://github.com/MrMethor/Highnoon-BASIC/");
Console.WriteLine(" https://github.com/mad4j/basic-highnoon/");
Console.WriteLine("Version modified for QB64:");
Console.WriteLine(" By Daniele Olmisani, 2014.");
Console.WriteLine(" https://github.com/mad4j/basic-highnoon/");
Console.WriteLine("This improved remake in C#:");
Console.WriteLine(" Copyright (c) 2024, Marcos Cruz (programandala.net)");
Console.WriteLine(" SPDX-License-Identifier: Fair");
}
static void PrintInstructions()
{
PrintTitle();
Console.ForegroundColor = INSTRUCTIONS_COLOR;
Console.WriteLine("\nYou have been challenged to a showdown by Black Bart, one of");
Console.WriteLine("the meanest desperadoes west of the Allegheny mountains.");
Console.WriteLine("\nWhile you are walking down a dusty, deserted side street,");
Console.WriteLine("Black Bart emerges from a saloon one hundred paces away.");
Console.Write($"\nBy agreement, you each have {INITIAL_BULLETS} bullets in your six-guns.");
Console.WriteLine("\nYour marksmanship equals his. At the start of the walk nei-");
Console.WriteLine("ther of you can possibly hit the other, and at the end of");
Console.WriteLine("the walk, neither can miss. the closer you get, the better");
Console.WriteLine("your chances of hitting black Bart, but he also has beter");
Console.WriteLine("chances of hitting you.");
Console.ForegroundColor = DEFAULT_COLOR;
}
// Game loop {{{1
// =============================================================
static string PluralSuffix(int n)
{
return n == 1 ? "" : "s";
}
static void PrintShellsLeft()
{
if (playerBullets == opponentBullets)
{
Console.WriteLine($"Both of you have {playerBullets} bullets.");
}
else
{
Console.WriteLine
(
"You now have {0} bullet{1} to Black Bart's {2} bullet{3}.",
playerBullets,
PluralSuffix(playerBullets),
opponentBullets,
PluralSuffix(opponentBullets)
);
}
}
static void PrintCheck()
{
Console.WriteLine("******************************************************");
Console.WriteLine("* *");
Console.WriteLine("* BANK OF DODGE CITY *");
Console.WriteLine("* CASHIER'S RECEIT *");
Console.WriteLine("* *");
Console.WriteLine("* CHECK NO. {0:0000} AUGUST {1}TH, 1889 *",
rand.Next(1000),
10 + rand.Next(10));
Console.WriteLine("* *");
Console.WriteLine("* *");
Console.WriteLine("* PAY TO THE BEARER ON DEMAND THE SUM OF *");
Console.WriteLine("* *");
Console.WriteLine("* TWENTY THOUSAND DOLLARS-------------------$20,000 *");
Console.WriteLine("* *");
Console.WriteLine("******************************************************");
}
static void GetReward()
{
Console.WriteLine("As mayor of Dodge City, and on behalf of its citizens,");
Console.WriteLine("I extend to you our thanks, and present you with this");
Console.WriteLine("reward, a check for $20,000, for killing Black Bart.\n\n");
PrintCheck();
Console.WriteLine("\n\nDon't spend it all in one place.");
}
static void MoveTheOpponent()
{
int paces = 2 + rand.Next(8);
Console.WriteLine($"Black Bart moves {paces} paces.");
distance -= paces;
}
// Maybe move the opponent; if so, return `true`, otherwise return `false`. A
// true `silent` flag allows to omit the message when the opponent doesn't
// move.
//
static bool MaybeMoveTheOpponent(bool silent = false)
{
if (rand.Next(2) == 0) { // 50% chances
MoveTheOpponent();
return true;
}
else
{
if (! silent)
{
Console.WriteLine("Black Bart stands still.");
}
return false;
}
}
static bool MissedShot()
{
return rand.NextDouble() * 10 <= (double) distance / 10;
}
// Handle the opponent's shot and return a flag with the result: if the
// opponent kills the player, return `true`; otherwise return `false`.
//
static bool TheOpponentFiresAndKills()
{
Console.WriteLine("Black Bart fires…");
opponentBullets -= 1;
if (MissedShot())
{
Console.WriteLine("A miss…");
switch (opponentBullets)
{
case 3:
Console.WriteLine("Whew, were you lucky. That bullet just missed your head.");
break;
case 2:
Console.WriteLine("But Black Bart got you in the right shin.");
break;
case 1:
Console.WriteLine("Though Black Bart got you on the left side of your jaw.");
break;
case 0:
Console.WriteLine("Black Bart must have jerked the trigger.");
break;
}
}
else
{
if (strategy == "j")
{
Console.WriteLine("That trick just saved yout life. Black Bart's bullet");
Console.WriteLine("was stopped by the wood sides of the trough.");
}
else
{
Console.WriteLine("Black Bart shot you right through the heart that time.");
Console.WriteLine("You went kickin' with your boots on.");
return true;
}
}
return false;
}
// Handle the opponent's strategy and return a flag with the result: if the
// opponent runs or kills the player, return `true`; otherwise return `false`.
//
static bool TheOpponentKillsOrRuns()
{
if (distance >= 10 || playerBullets == 0)
{
if (MaybeMoveTheOpponent(silent: true))
{
return false;
}
}
if (opponentBullets > 0)
{
return TheOpponentFiresAndKills();
}
else
{
if (playerBullets > 0)
{
if (rand.Next(2) == 0)
{
{;
} // 50% chances
Console.WriteLine("Now is your chance, Black Bart is out of bullets.");
}
else
{
Console.WriteLine("Black Bart just hi-tailed it out of town rather than face you");
Console.WriteLine("without a loaded gun. You can rest assured that Black Bart");
Console.WriteLine("won't ever show his face around this town again.");
return true;
}
}
}
return false;
}
static void Play()
{
distance = INITIAL_DISTANCE;
int wateringTroughs = 0;
playerBullets = INITIAL_BULLETS;
opponentBullets = INITIAL_BULLETS;
while (true)
{
Console.WriteLine($"You are now {distance} paces apart from Black Bart.");
PrintShellsLeft();
Console.ForegroundColor = INSTRUCTIONS_COLOR;
Console.WriteLine("\nStrategies:");
Console.WriteLine(" [A]dvance");
Console.WriteLine(" [S]tand still");
Console.WriteLine(" [F]ire");
Console.WriteLine(" [J]ump behind the watering trough");
Console.WriteLine(" [G]ive up");
Console.WriteLine(" [T]urn tail and run");
Console.ForegroundColor = DEFAULT_COLOR;
strategy = (GetString("What is your strategy? ")).ToLower();
switch (strategy)
{
case "a": // advance
while (true)
{
int paces = GetInteger("How many paces do you advance? ");
if (paces < 0)
{
Console.WriteLine("None of this negative stuff, partner, only positive numbers.");
}
else if (paces > 10)
{
Console.WriteLine("Nobody can walk that fast.");
}
else
{
distance -= paces;
break;
}
}
break;
case "s": // stand still
Console.WriteLine("That move made you a perfect stationary target.");
break;
case "f": // fire
if (playerBullets == 0)
{
Console.WriteLine("You don't have any bullets left.");
}
else
{
playerBullets -= 1;
if (MissedShot())
{
switch (playerBullets)
{
case 2:
Console.WriteLine("Grazed Black Bart in the right arm.");
break;
case 1:
Console.WriteLine("He's hit in the left shoulder, forcing him to use his right");
Console.WriteLine("hand to shoot with.");
break;
}
Console.WriteLine("What a lousy shot.");
if (playerBullets == 0)
{
Console.WriteLine("Nice going, ace, you've run out of bullets.");
if (opponentBullets != 0)
{
Console.WriteLine("Now Black Bart won't shoot until you touch noses.");
Console.WriteLine("You better think of something fast (like run).");
}
}
}
else
{
Console.WriteLine("What a shot, you got Black Bart right between the eyes.");
GetString("\nPress the Enter key to get your reward. ");
Console.Clear();
GetReward();
return;
}
}
break;
case "j": // jump
if (wateringTroughs == MAX_WATERING_TROUGHS)
{
Console.WriteLine("How many watering troughs do you think are on this street?");
strategy = "";
}
else
{
wateringTroughs += 1;
Console.WriteLine("You jump behind the watering trough.");
Console.WriteLine("Not a bad maneuver to threw Black Bart's strategy off.");
}
break;
case "g": // give up
Console.WriteLine("Black Bart accepts. The conditions are that he won't shoot you");
Console.WriteLine("if you take the first stage out of town and never come back.");
if (Yes("Agreed? "))
{
Console.WriteLine("A very wise decision.");
return;
}
else
{
Console.WriteLine("Oh well, back to the showdown.");
}
break;
case "t": // turn tail and run
// The more bullets of the opponent, the less chances to escape.
if (rand.Next(opponentBullets + 2) == 0)
{
Console.WriteLine("Man, you ran so fast even dogs couldn't catch you.");
}
else
{
switch (opponentBullets)
{
case 0:
Console.WriteLine("You were lucky, Black Bart can only throw his gun at you, he");
Console.WriteLine("doesn't have any bullets left. You should really be dead.");
break;
case 1:
Console.WriteLine("Black Bart fires his last bullet…");
Console.WriteLine("He got you right in the back. That's what you deserve, for running.");
break;
case 2:
Console.WriteLine("Black Bart fires and got you twice: in your back");
Console.WriteLine("and your ass. Now you can't even rest in peace.");
break;
case 3:
Console.WriteLine("Black Bart unloads his gun, once in your back");
Console.WriteLine("and twice in your ass. Now you can't even rest in peace.");
break;
case 4:
Console.WriteLine("Black Bart unloads his gun, once in your back");
Console.WriteLine("and three times in your ass. Now you can't even rest in peace.");
break;
}
opponentBullets = 0;
}
return;
default:
Console.WriteLine("You sure aren't going to live very long if you can't even follow directions.");
break;
}; // strategy switch
if (TheOpponentKillsOrRuns())
{
break;
}
if (playerBullets + opponentBullets == 0)
{
Console.WriteLine("The showdown must end, because nobody has bullets left.");
break;
}
Console.WriteLine();
}; // showdown loop
}
// Main {{{1
// =============================================================
static void Main()
{
Console.Clear();
PrintCredits();
GetString("\nPress the Enter key to read the instructions. ");
Console.Clear();
PrintInstructions();
GetString("\nPress the Enter key to start. ");
Console.Clear();
Play();
}
}
En Chapel
// High Noon
// Original version in BASIC:
// Designed and programmed by Chris Gaylo, Syosset High School, New York, 1970-09-12.
// http://mybitbox.com/highnoon-1970/
// http://mybitbox.com/highnoon/
// Transcriptions:
// https://github.com/MrMethor/Highnoon-BASIC/
// https://github.com/mad4j/basic-highnoon/
// Version modified for QB64:
// By Daniele Olmisani, 2014.
// https://github.com/mad4j/basic-highnoon/
// Improved remake in D:
// Copyright (c) 2025, Marcos Cruz (programandala.net)
// SPDX-License-Identifier: Fair
// This improved remake in Chapel:
// Copyright (c) 2026, Marcos Cruz (programandala.net)
// SPDX-License-Identifier: Fair
//
// Written on 2026-02-08.
//
// Last modified: 20260208T2232+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 hideCursor() {
write("\x1B[?25l");
}
proc showCursor() {
write("\x1B[?25h");
}
proc setStyle(style: int) {
writef("\x1B[%im", style);
}
proc resetAttributes() {
setStyle(NORMAL_STYLE);
}
proc eraseScreen() {
write("\x1B[2J");
}
proc clearScreen() {
eraseScreen();
resetAttributes();
moveCursorHome();
}
// Global variables and constants {{{1
// =============================================================
const DEFAULT_INK = FOREGROUND + WHITE;
const INPUT_INK = FOREGROUND + BRIGHT + GREEN;
const INSTRUCTIONS_INK = FOREGROUND + YELLOW;
const TITLE_INK = FOREGROUND + BRIGHT + RED;
const INITIAL_DISTANCE = 100;
const INITIAL_BULLETS = 4;
const MAX_WATERING_TROUGHS = 3;
var distance: int = 0; // distance between both gunners, in paces
var playerBullets: int = 0;
var opponentBullets: int = 0;
var rsInt = new randomStream(int);
var rsReal = new randomStream(real);
// User input {{{1
// =============================================================================
proc acceptString(prompt: string): string {
write(prompt);
IO.stdout.flush();
return IO.readLine().strip();
}
/// Print the given prompt and wait until the user enters a string.
proc getString(prompt: string): string {
setStyle(INPUT_INK);
var s: string = acceptString(prompt);
setStyle(DEFAULT_INK);
return s;
}
/// Print the given prompt, accept a string from the user. If the typed string
/// is a valid integer return it; otherwise return 0.
proc getInteger(prompt: string): int {
var result: int;
var s: string = acceptString(prompt);
try {
result = (s): int;
}
catch exc {
result = 0;
}
return result;
}
/// 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 = getString(prompt);
if isYes(answer) {
result = true;
break;
}
if isNo(answer) {
result = false;
break;
}
}
return result;
}
// Title, instructions and credits {{{1
// =============================================================
proc printTitle() {
setStyle(TITLE_INK);
writeln("High Noon");
setStyle(DEFAULT_INK);
}
proc printCredits() {
printTitle();
writeln("\nOriginal version in BASIC:");
writeln(" Designed and programmend by Chris Gaylo, 1970.");
writeln(" http://mybitbox.com/highnoon-1970/");
writeln(" http://mybitbox.com/highnoon/");
writeln("Transcriptions:");
writeln(" https://github.com/MrMethor/Highnoon-BASIC/");
writeln(" https://github.com/mad4j/basic-highnoon/");
writeln("Version modified for QB64:");
writeln(" By Daniele Olmisani, 2014.");
writeln(" https://github.com/mad4j/basic-highnoon/");
writeln("Improved remake in D:");
writeln(" Copyright (c) 2025, Marcos Cruz (programandala.net)");
writeln(" SPDX-License-Identifier: Fair");
writeln("This improved remake in Chapel:");
writeln(" Copyright (c) 2026, Marcos Cruz (programandala.net)");
writeln(" SPDX-License-Identifier: Fair");
}
proc printInstructions() {
printTitle();
setStyle(INSTRUCTIONS_INK);
writeln("\nYou have been challenged to a showdown by Black Bart, one of");
writeln("the meanest desperadoes west of the Allegheny mountains.");
writeln("\nWhile you are walking down a dusty, deserted side street,");
writeln("Black Bart emerges from a saloon one hundred paces away.");
writef("\nBy agreement, you each have %i bullets in your six-guns.", INITIAL_BULLETS);
writeln("\nYour marksmanship equals his. At the start of the walk nei-");
writeln("ther of you can possibly hit the other, and at the end of");
writeln("the walk, neither can miss. the closer you get, the better");
writeln("your chances of hitting black Bart, but he also has beter");
writeln("chances of hitting you.");
setStyle(DEFAULT_INK);
}
// Game loop {{{1
// =============================================================
proc pluralSuffix(n: int): string {
select n {
when 1 { return ""; }
otherwise { return "s"; }
}
}
proc printShellsLeft() {
if playerBullets == opponentBullets {
writef("Both of you have %i bullets.\n", playerBullets);
} else {
writef(
"You now have %i bullet%s to Black Bart's %i bullet%s.\n",
playerBullets,
pluralSuffix(playerBullets),
opponentBullets,
pluralSuffix(opponentBullets));
}
}
proc printCheck() {
writeln("******************************************************");
writeln("* *");
writeln("* BANK OF DODGE CITY *");
writeln("* CASHIER'S RECEIT *");
writeln("* *");
writef("* CHECK NO. %04i AUGUST %iTH, 1889 *\n",
rsInt.next(0, 1000 - 1),
10 + rsInt.next(0, 10 - 1));
writeln("* *");
writeln("* *");
writeln("* PAY TO THE BEARER ON DEMAND THE SUM OF *");
writeln("* *");
writeln("* TWENTY THOUSAND DOLLARS-------------------$20,000 *");
writeln("* *");
writeln("******************************************************");
}
proc getReward() {
writeln("As mayor of Dodge City, and on behalf of its citizens,");
writeln("I extend to you our thanks, and present you with this");
writeln("reward, a check for $20,000, for killing Black Bart.\n\n");
printCheck();
writeln("\n\nDon't spend it all in one place.");
}
proc moveTheOpponent() {
var paces: int = 2 + rsInt.next(0, 8 - 1);
writef("Black Bart moves %i paces.\n", paces);
distance -= paces;
}
/// Maybe move the opponent; if so, return `true`, otherwise return `false`. A
/// true `silent` flag allows to omit the message when the opponent doesn't
/// move.
proc maybeMoveTheOpponent(silent: bool): bool {
if rsInt.next(0, 2 - 1) == 0 { // 50% chances
moveTheOpponent();
return true;
} else {
if !silent {
writeln("Black Bart stands still.");
}
return false;
}
}
proc missedShot(): bool {
return rsReal.next() * 10.0 <= (distance / 10);
}
/// Handle the opponent's shot and return a flag with the result: if the
/// opponent kills the player, return `true`; otherwise return `false`.
proc theOpponentFiresAndKills(playerStrategy: string): bool {
writeln("Black Bart fires…");
opponentBullets -= 1;
if missedShot() {
writeln("A miss…");
select opponentBullets {
when 3 {
writeln("Whew, were you lucky. That bullet just missed your head.");
}
when 2 {
writeln("But Black Bart got you in the right shin.");
}
when 1 {
writeln("Though Black Bart got you on the left side of your jaw.");
}
when 0 {
writeln("Black Bart must have jerked the trigger.");
}
}
} else {
if playerStrategy == "j" {
writeln("That trick just saved yout life. Black Bart's bullet");
writeln("was stopped by the wood sides of the trough.");
} else {
writeln("Black Bart shot you right through the heart that time.");
writeln("You went kickin' with your boots on.");
return true;
}
}
return false;
}
/// Handle the opponent's strategy and return a flag with the result: if the
/// opponent runs or kills the player, return `true`; otherwise return `false`.
proc theOpponentKillsOrRuns(playerStrategy: string): bool {
if distance >= 10 || playerBullets == 0 {
if maybeMoveTheOpponent(true) {
return false;
}
}
if opponentBullets > 0 {
return theOpponentFiresAndKills(playerStrategy);
} else {
if playerBullets > 0 {
if rsInt.next(0, 2 - 1) == 0 { // 50% chances
writeln("Now is your chance, Black Bart is out of bullets.");
} else {
writeln("Black Bart just hi-tailed it out of town rather than face you");
writeln("without a loaded gun. You can rest assured that Black Bart");
writeln("won't ever show his face around this town again.");
return true;
}
}
}
return false;
}
proc play() {
distance = INITIAL_DISTANCE;
var wateringTroughs: int = 0;
playerBullets = INITIAL_BULLETS;
opponentBullets = INITIAL_BULLETS;
label showdown while true {
writef("You are now %i paces apart from Black Bart.\n", distance);
printShellsLeft();
setStyle(INSTRUCTIONS_INK);
writeln("\nStrategies:");
writeln(" [A]dvance");
writeln(" [S]tand still");
writeln(" [F]ire");
writeln(" [J]ump behind the watering trough");
writeln(" [G]ive up");
writeln(" [T]urn tail and run");
setStyle(DEFAULT_INK);
var playerStrategy: string = (getString("What is your strategy? ")).toLower();
select playerStrategy {
when "a" { // advance
while true {
var paces: int = getInteger("How many paces do you advance? ");
if paces < 0 {
writeln("None of this negative stuff, partner, only positive numbers.");
} else if paces > 10 {
writeln("Nobody can walk that fast.");
} else {
distance -= paces;
break;
}
}
}
when "s" { // stand still
writeln("That move made you a perfect stationary target.");
}
when "f" { // fire
if playerBullets == 0 {
writeln("You don't have any bullets left.");
} else {
playerBullets -= 1;
if missedShot() {
select playerBullets {
when 2 {
writeln("Grazed Black Bart in the right arm.");
}
when 1 {
writeln("He's hit in the left shoulder, forcing him to use his right");
writeln("hand to shoot with.");
}
}
writeln("What a lousy shot.");
if playerBullets == 0 {
writeln("Nice going, ace, you've run out of bullets.");
if opponentBullets != 0 {
writeln("Now Black Bart won't shoot until you touch noses.");
writeln("You better think of something fast (like run).");
}
}
} else {
writeln("What a shot, you got Black Bart right between the eyes.");
acceptString("\nPress the Enter key to get your reward. ");
clearScreen();
getReward();
break showdown;
}
}
}
when "j" { // jump
if wateringTroughs == MAX_WATERING_TROUGHS {
writeln("How many watering troughs do you think are on this street?");
playerStrategy = "";
} else {
wateringTroughs += 1;
writeln("You jump behind the watering trough.");
writeln("Not a bad maneuver to threw Black Bart's strategy off.");
}
}
when "g" { // give up
writeln("Black Bart accepts. The conditions are that he won't shoot you");
writeln("if you take the first stage out of town and never come back.");
if yes("Agreed? ") {
writeln("A very wise decision.");
break showdown;
} else {
writeln("Oh well, back to the showdown.");
}
}
when "t" { // turn tail and run
// The more bullets of the opponent, the less chances to escape.
if rsInt.next(0, (opponentBullets + 2 - 1)) == 0 {
writeln("Man, you ran so fast even dogs couldn't catch you.");
} else {
select opponentBullets {
when 0 {
writeln("You were lucky, Black Bart can only throw his gun at you, he");
writeln("doesn't have any bullets left. You should really be dead.");
}
when 1 {
writeln("Black Bart fires his last bullet…");
writeln("He got you right in the back. That's what you deserve, for running.");
}
when 2 {
writeln("Black Bart fires and got you twice: in your back");
writeln("and your ass. Now you can't even rest in peace.");
}
when 3 {
writeln("Black Bart unloads his gun, once in your back");
writeln("and twice in your ass. Now you can't even rest in peace.");
}
when 4 {
writeln("Black Bart unloads his gun, once in your back");
writeln("and three times in your ass. Now you can't even rest in peace.");
}
}
opponentBullets = 0;
}
break showdown;
} otherwise {
writeln("You sure aren't going to live very long if you can't even follow directions.");
}
} // strategy switch
if theOpponentKillsOrRuns(playerStrategy) {
break;
}
if playerBullets + opponentBullets == 0 {
writeln("The showdown must end, because nobody has bullets left.");
break;
}
writeln();
} // showdown loop
}
// Main {{{1
// =============================================================
proc main() {
clearScreen();
printCredits();
acceptString("\nPress the Enter key to read the instructions. ");
clearScreen();
printInstructions();
acceptString("\nPress the Enter key to start. ");
clearScreen();
play();
}
En Crystal
# High Noon
# Original version in BASIC:
# Designed and programmed by Chris Gaylo, Syosset High School, New York, 1970-09-12.
# http://mybitbox.com/highnoon-1970/
# http://mybitbox.com/highnoon/
#
# Transcriptions:
# https://github.com/MrMethor/Highnoon-BASIC/
# https://github.com/mad4j/basic-highnoon/
#
# Version modified for QB64:
# By Daniele Olmisani, 2014.
# https://github.com/mad4j/basic-highnoon/
# This improved remake in Crystal:
# Copyright (c) 2024, Marcos Cruz (programandala.net)
# SPDX-License-Identifier: Fair
#
# Written in 2024-11-27/28.
#
# Last modified: 20250421T0020+0200.
# Terminal {{{1
# ==============================================================================
# Screen colors
BLACK = 0
RED = 1
GREEN = 2
YELLOW = 3
BLUE = 4
MAGENTA = 5
CYAN = 6
WHITE = 7
DEFAULT = 9
# Screen attributes
NORMAL = 0
# Screen color offsets
FOREGROUND = +30
BRIGHT = +60
# 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_screen
print "\e[2J"
home
end
def set_color(color : Int)
print "\e[#{color}m"
end
def set_attribute(attr : Int)
print "\e[0;#{attr}m"
end
# Sets the cursor position to the given coordinates (the top left position is 1, 1).
def set_cursor_position(line, column : Int)
print "\e[#{line};#{column}H"
end
def erase_line_right
print "\e[K"
end
def hide_cursor
print "\e[?25l"
end
def show_cursor
print "\e[?25h"
end
# Globals {{{1
# =============================================================
DEFAULT_INK = FOREGROUND + WHITE
INPUT_INK = FOREGROUND + BRIGHT + GREEN
INSTRUCTIONS_INK = FOREGROUND + YELLOW
TITLE_INK = FOREGROUND + BRIGHT + RED
INITIAL_DISTANCE = 100
INITIAL_BULLETS = 4
MAX_WATERING_TROUGHS = 3
class Global
class_property distance : Int32 = INITIAL_DISTANCE # distance between both gunners, in paces
class_property strategy : String = "" # player's strategy
class_property player_bullets : Int32 = INITIAL_BULLETS
class_property opponent_bullets : Int32 = INITIAL_BULLETS
end
# User input {{{1
# =============================================================
# Prints the given prompt and waits until the user enters an integer; if the
# user input is not a valid integer, returns 0 instead.
def input_int(prompt : String = "") : Int
set_color(INPUT_INK)
print prompt
number = gets.not_nil!.to_i rescue 0
set_color(DEFAULT_INK)
return number
end
# Prints the given prompt and waits until the user enters a string.
def input_string(prompt = "") : String
s = nil
set_color(INPUT_INK)
while s.is_a?(Nil)
print prompt
s = gets
end
set_color(DEFAULT_INK)
s
end
# Prints the given prompt and waits until the user presses Enter.
def press_enter(prompt : String)
input_string(prompt)
end
# Returns `true` if the given string is "yes" or a synonym.
def is_yes?(s : String) : Bool
return s.downcase.in?(["ok", "y", "yeah", "yes"])
end
# Returns `true` if the given string is "no" or a synonym.
def is_no?(s : String) : Bool
return s.downcase.in?(["n", "no", "nope"])
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
while true
answer = input_string(prompt)
if is_yes?(answer)
return true
end
if is_no?(answer)
return false
end
end
end
# Title, instructions and credits {{{1
# =============================================================
# Print the title at the current cursor position.
def print_title
set_color(TITLE_INK)
puts "High Noon"
set_color(DEFAULT_INK)
end
def print_credits
print_title
puts "\nOriginal version in BASIC:"
puts " Designed and programmend by Chris Gaylo, 1970."
puts " http://mybitbox.com/highnoon-1970/"
puts " http://mybitbox.com/highnoon/"
puts "Transcriptions:"
puts " https://github.com/MrMethor/Highnoon-BASIC/"
puts " https://github.com/mad4j/basic-highnoon/"
puts "Version modified for QB64:"
puts " By Daniele Olmisani, 2014."
puts " https://github.com/mad4j/basic-highnoon/"
puts "This improved remake in Crystal:"
puts " Copyright (c) 2024, Marcos Cruz (programandala.net)"
puts " SPDX-License-Identifier: Fair"
end
def print_instructions
print_title
set_color(INSTRUCTIONS_INK)
puts "\nYou have been challenged to a showdown by Black Bart, one of"
puts "the meanest desperadoes west of the Allegheny mountains."
puts "\nWhile you are walking down a dusty, deserted side street,"
puts "Black Bart emerges from a saloon one hundred paces away."
puts "\nBy agreement, you each have #{INITIAL_BULLETS} bullets in your six-guns."
puts "Your marksmanship equals his. At the start of the walk nei-"
puts "ther of you can possibly hit the other, and at the end of"
puts "the walk, neither can miss. the closer you get, the better"
puts "your chances of hitting black Bart, but he also has beter"
puts "chances of hitting you."
set_color(DEFAULT_INK)
end
# Game loop {{{1
# =============================================================
def plural_suffix(n : Int) : String
case n
when 1; return ""
else return "s"
end
end
def print_shells_left
if Global.player_bullets == Global.opponent_bullets
puts "Both of you have #{Global.player_bullets} bullets."
else
print "You now have #{Global.player_bullets} bullet#{plural_suffix(Global.player_bullets)} "
puts "to Black Bart's #{Global.opponent_bullets} bullet#{plural_suffix(Global.opponent_bullets)}."
end
end
def print_check
puts "******************************************************"
puts "* *"
puts "* BANK OF DODGE CITY *"
puts "* CASHIER'S RECEIT *"
puts "* *"
puts "* CHECK NO. #{rand(1000..9999)} AUGUST #{10 + rand(10)}TH, 1889 *"
puts "* *"
puts "* *"
puts "* PAY TO THE BEARER ON DEMAND THE SUM OF *"
puts "* *"
puts "* TWENTY THOUSAND DOLLARS-------------------$20,000 *"
puts "* *"
puts "******************************************************"
end
def get_reward
puts "As mayor of Dodge City, and on behalf of its citizens,"
puts "I extend to you our thanks, and present you with this"
puts "reward, a check for $20,000, for killing Black Bart."
puts
puts
print_check
puts "\n\nDon't spend it all in one place."
end
def move_the_opponent
paces = 2 + rand(8)
puts "Black Bart moves #{paces} paces."
Global.distance -= paces
end
# Maybe move the opponent; if so, return `true`, otherwise return `false`.
# A true `silent` flag allows to omit the message when the opponent doesn't move.
def maybe_move_the_opponent(silent = false) : Bool
if rand(2) == 0 # 50% chances
move_the_opponent()
return true
else
if !silent
puts "Black Bart stands still."
end
return false
end
end
def missed_shot : Bool
# XXX TODO check
return rand(10) <= Global.distance // 10
end
# Handle the opponent's shot and return a flag with the result: if the
# opponent kills the player, return `true`; otherwise return `false`.
def the_opponent_fires_and_kills : Bool
puts "Black Bart fires…"
Global.opponent_bullets -= 1
if missed_shot()
puts "A miss…"
case Global.opponent_bullets
when 3
puts "Whew, were you lucky. That bullet just missed your head."
when 2
puts "But Black Bart got you in the right shin."
when 1
puts "Though Black Bart got you on the left side of your jaw."
when 0
puts "Black Bart must have jerked the trigger."
end
else
if Global.strategy == "j"
puts "That trick just saved yout life. Black Bart's bullet"
puts "was stopped by the wood sides of the trough."
else
puts "Black Bart shot you right through the heart that time."
puts "You went kickin' with your boots on."
return true
end
end
return false
end
# Handle the opponent's strategy and return a flag with the result: if the
# opponent runs or kills the player, return `true`; otherwise return `false`.
def the_opponent_kills_or_runs : Bool
if Global.distance >= 10 || Global.player_bullets == 0
if maybe_move_the_opponent(silent = true)
return false
end
end
if Global.opponent_bullets > 0
return the_opponent_fires_and_kills()
else
if Global.player_bullets > 0
if rand(2) == 0 # 50% chances
puts "Now is your chance, Black Bart is out of bullets."
else
puts "Black Bart just hi-tailed it out of town rather than face you"
puts "without a loaded gun. You can rest assured that Black Bart"
puts "won't ever show his face around this town again."
return true
end
end
end
return false
end
def play
watering_troughs = 0
while true # showdown loop
puts "You are now #{Global.distance} paces apart from Black Bart."
print_shells_left()
set_color(INSTRUCTIONS_INK)
puts "\nStrategies:"
puts " [A]dvance"
puts " [S]tand still"
puts " [F]ire"
puts " [J]ump behind the watering trough"
puts " [G]ive up"
puts " [T]urn tail and run"
set_color(DEFAULT_INK)
Global.strategy = input_string("\nWhat is your strategy? ").upcase
case Global.strategy
when "A" # advance
while true
paces = input_int("How many paces do you advance? ")
if paces < 0
puts "None of this negative stuff, partner, only positive numbers."
elsif paces > 10
puts "Nobody can walk that fast."
else
Global.distance -= paces
break
end
end
when "S" # stand still
puts "That move made you a perfect stationary target."
when "F" # fire
if Global.player_bullets == 0
puts "You don't have any bullets left."
else
Global.player_bullets -= 1
if missed_shot()
case Global.player_bullets
when 2
puts "Grazed Black Bart in the right arm."
when 1
puts "He's hit in the left shoulder, forcing him to use his right"
puts "hand to shoot with."
end
puts "What a lousy shot."
if Global.player_bullets == 0
puts "Nice going, ace, you've run out of bullets."
if Global.opponent_bullets != 0
puts "Now Black Bart won't shoot until you touch noses."
puts "You better think of something fast (like run)."
end
end
else
puts "What a shot, you got Black Bart right between the eyes."
press_enter("\nPress the Enter key to get your reward. ")
clear_screen
get_reward
break
end
end
when "J" # jump
if watering_troughs == MAX_WATERING_TROUGHS
puts "How many watering troughs do you think are on this street?"
Global.strategy = ""
else
watering_troughs += 1
puts "You jump behind the watering trough."
puts "Not a bad maneuver to threw Black Bart's strategy off."
end
when "G" # give up
puts "Black Bart accepts. The conditions are that he won't shoot you"
puts "if you take the first stage out of town and never come back."
if yes?("Agreed? ")
puts "A very wise decision."
break
else
puts "Oh well, back to the showdown."
end
when "T" # turn tail and run
# The more bullets of the opponent, the less chances to escape.
if rand(Global.opponent_bullets + 2) == 0 # XXX TODO check rand.int_max
puts "Man, you ran so fast even dogs couldn't catch you."
else
case Global.opponent_bullets
when 0
puts "You were lucky, Black Bart can only throw his gun at you, he"
puts "doesn't have any bullets left. You should really be dead."
when 1
puts "Black Bart fires his last bullet…"
puts "He got you right in the back. That's what you deserve, for running."
when 2
puts "Black Bart fires and got you twice: in your back"
puts "and your ass. Now you can't even rest in peace."
when 3
puts "Black Bart unloads his gun, once in your back"
puts "and twice in your ass. Now you can't even rest in peace."
when 4
puts "Black Bart unloads his gun, once in your back"
puts "and three times in your ass. Now you can't even rest in peace."
end
Global.opponent_bullets = 0
end
break
else
puts "You sure aren't going to live very long if you can't even follow directions."
puts
end # strategy case
if the_opponent_kills_or_runs()
break
end
if Global.player_bullets + Global.opponent_bullets == 0
puts "The showdown must end, because nobody has bullets left."
break
end
puts
end # showdown loop
end
# Main {{{1
# =============================================================
clear_screen
print_credits
press_enter("\nPress the Enter key to read the instructions. ")
clear_screen
print_instructions
press_enter("\nPress the Enter key to start. ")
clear_screen
play
En D
// High Noon
// Original version in BASIC:
// Designed and programmed by Chris Gaylo, Syosset High School, New York, 1970-09-12.
// http://mybitbox.com/highnoon-1970/
// http://mybitbox.com/highnoon/
// Transcriptions:
// https://github.com/MrMethor/Highnoon-BASIC/
// https://github.com/mad4j/basic-highnoon/
// Version modified for QB64:
// By Daniele Olmisani, 2014.
// https://github.com/mad4j/basic-highnoon/
// This improved remake in D:
// Copyright (c) 2025, Marcos Cruz (programandala.net)
// SPDX-License-Identifier: Fair
//
// Written on 2025-03-23.
//
// Last modified: 20251220T0654+0100.
module high_noon;
// 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 hideCursor()
{
import std.stdio : write;
write("\x1B[?25l");
}
void showCursor()
{
import std.stdio : write;
write("\x1B[?25h");
}
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();
}
// Global variables and constants {{{1
// =============================================================
enum DEFAULT_INK = FOREGROUND + WHITE;
enum INPUT_INK = FOREGROUND + BRIGHT + GREEN;
enum INSTRUCTIONS_INK = FOREGROUND + YELLOW;
enum TITLE_INK = FOREGROUND + BRIGHT + RED;
enum INITIAL_DISTANCE = 100;
enum INITIAL_BULLETS = 4;
enum MAX_WATERING_TROUGHS = 3;
int distance = 0; // distance between both gunners, in paces
int playerBullets = 0;
int opponentBullets = 0;
// User input {{{1
// =============================================================================
string acceptString(string prompt)
{
import std.stdio : readln;
import std.stdio : write;
import std.string : strip;
write(prompt);
return strip(readln());
}
/// Print the given prompt and wait until the user enters a string.
string getString(string prompt)
{
setStyle(INPUT_INK);
string s = acceptString(prompt);
setStyle(DEFAULT_INK);
return s;
}
/// Print the given prompt, accept a string from the user. If the typed string
/// is a valid integer return it; otherwise return 0.
int getInteger(string prompt)
{
import std.conv : to;
int result;
string s = acceptString(prompt);
try
{
result = to!int(s);
}
catch (Exception exc)
{
result = 0;
}
return result;
}
/// 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 = getString(prompt);
if (isYes(answer))
{
return true;
}
if (isNo(answer))
{
return false;
}
}
}
// Title, instructions and credits {{{1
// =============================================================
void printTitle()
{
import std.stdio : writeln;
setStyle(TITLE_INK);
writeln("High Noon");
setStyle(DEFAULT_INK);
}
void printCredits()
{
import std.stdio : writeln;
printTitle();
writeln("\nOriginal version in BASIC:");
writeln(" Designed and programmend by Chris Gaylo, 1970.");
writeln(" http://mybitbox.com/highnoon-1970/");
writeln(" http://mybitbox.com/highnoon/");
writeln("Transcriptions:");
writeln(" https://github.com/MrMethor/Highnoon-BASIC/");
writeln(" https://github.com/mad4j/basic-highnoon/");
writeln("Version modified for QB64:");
writeln(" By Daniele Olmisani, 2014.");
writeln(" https://github.com/mad4j/basic-highnoon/");
writeln("This improved remake in D:");
writeln(" Copyright (c) 2025, Marcos Cruz (programandala.net)");
writeln(" SPDX-License-Identifier: Fair");
}
void printInstructions()
{
import std.stdio : writef;
import std.stdio : writeln;
printTitle();
setStyle(INSTRUCTIONS_INK);
writeln("\nYou have been challenged to a showdown by Black Bart, one of");
writeln("the meanest desperadoes west of the Allegheny mountains.");
writeln("\nWhile you are walking down a dusty, deserted side street,");
writeln("Black Bart emerges from a saloon one hundred paces away.");
writef("\nBy agreement, you each have %d bullets in your six-guns.", INITIAL_BULLETS);
writeln("\nYour marksmanship equals his. At the start of the walk nei-");
writeln("ther of you can possibly hit the other, and at the end of");
writeln("the walk, neither can miss. the closer you get, the better");
writeln("your chances of hitting black Bart, but he also has beter");
writeln("chances of hitting you.");
setStyle(DEFAULT_INK);
}
// Game loop {{{1
// =============================================================
string pluralSuffix(int n)
{
switch (n)
{
case 1: return "";
default: return "s";
}
}
void printShellsLeft()
{
import std.stdio : writef;
import std.stdio : writefln;
if (playerBullets == opponentBullets)
{
writefln("Both of you have %d bullets.", playerBullets);
}
else
{
writef(
"You now have %d bullet%s to Black Bart's %d bullet%s.\n",
playerBullets,
pluralSuffix(playerBullets),
opponentBullets,
pluralSuffix(opponentBullets));
}
}
void printCheck()
{
import std.random : uniform;
import std.stdio : writefln;
import std.stdio : writeln;
writeln("******************************************************");
writeln("* *");
writeln("* BANK OF DODGE CITY *");
writeln("* CASHIER'S RECEIT *");
writeln("* *");
writefln("* CHECK NO. %04d AUGUST %dTH, 1889 *",
uniform(0, 1000),
10 + uniform(0, 10));
writeln("* *");
writeln("* *");
writeln("* PAY TO THE BEARER ON DEMAND THE SUM OF *");
writeln("* *");
writeln("* TWENTY THOUSAND DOLLARS-------------------$20,000 *");
writeln("* *");
writeln("******************************************************");
}
void getReward()
{
import std.stdio : writeln;
writeln("As mayor of Dodge City, and on behalf of its citizens,");
writeln("I extend to you our thanks, and present you with this");
writeln("reward, a check for $20,000, for killing Black Bart.\n\n");
printCheck();
writeln("\n\nDon't spend it all in one place.");
}
void moveTheOpponent()
{
import std.random : uniform;
import std.stdio : writefln;
int paces = 2 + uniform(0, 8);
writefln("Black Bart moves %d paces.", paces);
distance -= paces;
}
/// Maybe move the opponent; if so, return `true`, otherwise return `false`. A
/// true `silent` flag allows to omit the message when the opponent doesn't
/// move.
bool maybeMoveTheOpponent(bool silent)
{
import std.random : uniform;
import std.stdio : writeln;
if (uniform(0, 2) == 0) { // 50% chances
moveTheOpponent();
return true;
}
else
{
if (!silent)
{
writeln("Black Bart stands still.");
}
return false;
}
}
bool missedShot()
{
import std.random : uniform01;
return uniform01() * 10.0 <= (distance / 10);
}
/// Handle the opponent's shot and return a flag with the result: if the
/// opponent kills the player, return `true`; otherwise return `false`.
bool theOpponentFiresAndKills(string playerStrategy)
{
import std.stdio : writeln;
writeln("Black Bart fires…");
opponentBullets -= 1;
if (missedShot())
{
writeln("A miss…");
final switch (opponentBullets)
{
case 3:
writeln("Whew, were you lucky. That bullet just missed your head.");
break;
case 2:
writeln("But Black Bart got you in the right shin.");
break;
case 1:
writeln("Though Black Bart got you on the left side of your jaw.");
break;
case 0:
writeln("Black Bart must have jerked the trigger.");
}
}
else
{
if (playerStrategy == "j")
{
writeln("That trick just saved yout life. Black Bart's bullet");
writeln("was stopped by the wood sides of the trough.");
}
else
{
writeln("Black Bart shot you right through the heart that time.");
writeln("You went kickin' with your boots on.");
return true;
}
}
return false;
}
/// Handle the opponent's strategy and return a flag with the result: if the
/// opponent runs or kills the player, return `true`; otherwise return `false`.
bool theOpponentKillsOrRuns(string playerStrategy)
{
import std.random : uniform;
import std.stdio : writeln;
if (distance >= 10 || playerBullets == 0)
{
if (maybeMoveTheOpponent(true))
{
return false;
}
}
if (opponentBullets > 0)
{
return theOpponentFiresAndKills(playerStrategy);
}
else
{
if (playerBullets > 0)
{
if (uniform(0, 2) == 0) { // 50% chances
writeln("Now is your chance, Black Bart is out of bullets.");
}
else
{
writeln("Black Bart just hi-tailed it out of town rather than face you");
writeln("without a loaded gun. You can rest assured that Black Bart");
writeln("won't ever show his face around this town again.");
return true;
}
}
}
return false;
}
void play()
{
import std.random : uniform;
import std.stdio : writefln;
import std.stdio : writeln;
import std.uni : toLower;
distance = INITIAL_DISTANCE;
int wateringTroughs = 0;
playerBullets = INITIAL_BULLETS;
opponentBullets = INITIAL_BULLETS;
showdown: while (true)
{
writefln("You are now %d paces apart from Black Bart.", distance);
printShellsLeft();
setStyle(INSTRUCTIONS_INK);
writeln("\nStrategies:");
writeln(" [A]dvance");
writeln(" [S]tand still");
writeln(" [F]ire");
writeln(" [J]ump behind the watering trough");
writeln(" [G]ive up");
writeln(" [T]urn tail and run");
setStyle(DEFAULT_INK);
string playerStrategy = toLower(getString("What is your strategy? "));
switch (playerStrategy)
{
case "a": // advance
while (true)
{
int paces = getInteger("How many paces do you advance? ");
if (paces < 0)
{
writeln("None of this negative stuff, partner, only positive numbers.");
}
else if (paces > 10)
{
writeln("Nobody can walk that fast.");
}
else
{
distance -= paces;
break;
}
}
break;
case "s": // stand still
writeln("That move made you a perfect stationary target.");
break;
case "f": // fire
if (playerBullets == 0)
{
writeln("You don't have any bullets left.");
}
else
{
playerBullets -= 1;
if (missedShot())
{
switch (playerBullets)
{
case 2:
writeln("Grazed Black Bart in the right arm.");
break;
case 1:
writeln("He's hit in the left shoulder, forcing him to use his right");
writeln("hand to shoot with.");
break;
default:
break;
}
writeln("What a lousy shot.");
if (playerBullets == 0)
{
writeln("Nice going, ace, you've run out of bullets.");
if (opponentBullets != 0)
{
writeln("Now Black Bart won't shoot until you touch noses.");
writeln("You better think of something fast (like run).");
}
}
}
else
{
writeln("What a shot, you got Black Bart right between the eyes.");
acceptString("\nPress the Enter key to get your reward. ");
clearScreen();
getReward();
break showdown;
}
}
break;
case "j": // jump
if (wateringTroughs == MAX_WATERING_TROUGHS)
{
writeln("How many watering troughs do you think are on this street?");
playerStrategy = "";
}
else
{
wateringTroughs += 1;
writeln("You jump behind the watering trough.");
writeln("Not a bad maneuver to threw Black Bart's strategy off.");
}
break;
case "g": // give up
writeln("Black Bart accepts. The conditions are that he won't shoot you");
writeln("if you take the first stage out of town and never come back.");
if (yes("Agreed? "))
{
writeln("A very wise decision.");
break showdown;
}
else
{
writeln("Oh well, back to the showdown.");
}
break;
case "t": // turn tail and run
// The more bullets of the opponent, the less chances to escape.
if (uniform(0, (opponentBullets + 2)) == 0)
{
writeln("Man, you ran so fast even dogs couldn't catch you.");
}
else
{
final switch (opponentBullets)
{
case 0:
writeln("You were lucky, Black Bart can only throw his gun at you, he");
writeln("doesn't have any bullets left. You should really be dead.");
break;
case 1:
writeln("Black Bart fires his last bullet…");
writeln("He got you right in the back. That's what you deserve, for running.");
break;
case 2:
writeln("Black Bart fires and got you twice: in your back");
writeln("and your ass. Now you can't even rest in peace.");
break;
case 3:
writeln("Black Bart unloads his gun, once in your back");
writeln("and twice in your ass. Now you can't even rest in peace.");
break;
case 4:
writeln("Black Bart unloads his gun, once in your back");
writeln("and three times in your ass. Now you can't even rest in peace.");
}
opponentBullets = 0;
}
break showdown;
default:
writeln("You sure aren't going to live very long if you can't even follow directions.");
} // strategy switch
if (theOpponentKillsOrRuns(playerStrategy))
{
break;
}
if (playerBullets + opponentBullets == 0)
{
writeln("The showdown must end, because nobody has bullets left.");
break;
}
writeln();
} // showdown loop
}
// Main {{{1
// =============================================================
void main()
{
clearScreen();
printCredits();
acceptString("\nPress the Enter key to read the instructions. ");
clearScreen();
printInstructions();
acceptString("\nPress the Enter key to start. ");
clearScreen();
play();
}
En Go
/*
High Noon
Original version in BASIC:
Designed and programmed by Chris Gaylo, Syosset High School, New York, 1970-09-12.
http://mybitbox.com/highnoon-1970/
http://mybitbox.com/highnoon/
Transcriptions:
https://github.com/MrMethor/Highnoon-BASIC/
https://github.com/mad4j/basic-highnoon/
Version modified for QB64:
By Daniele Olmisani, 2014.
https://github.com/mad4j/basic-highnoon/
This improved remake in Go:
Copyright (c) 2025, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written on 2025-01-05.
Last modified: 20250112T0201+0100.
*/
package main
import "fmt"
import "math/rand"
import "strconv"
import "strings"
import "time"
// Global variables and constants {{{1
// =============================================================
const defaultInk = foreground + whiteColor
const inputInk = foreground + bright + greenColor
const instructionsInk = foreground + yellowColor
const titleInk = foreground + bright + redColor
const initialDistance int = 100
const initialBullets int = 4
const maxWateringTroughs int = 3
var distance int // distance between both gunners, in paces
var strategy string // player's strategy
var playerBullets int
var opponentBullets int
// Console {{{1
// =============================================================
const blackColor = 0
const redColor = 1
const greenColor = 2
const yellowColor = 3
const blueColor = 4
const magentaColor = 5
const cyanColor = 6
const whiteColor = 7
const defaultColor = 9
const foreground = +30
const background = +40
const bright = +60
func clearScreen() {
fmt.Print("\x1B[0;0H\x1B[2J")
}
// Set the color.
func set_color(color int) {
fmt.Printf("\x1B[%vm", color)
}
// User input {{{1
// =============================================================
// Print the given prompt and wait until the user enters an integer.
func inputInt(prompt string) int {
var number int64
var err error
set_color(inputInk)
defer set_color(defaultInk)
for {
number, err = strconv.ParseInt(inputString(prompt), 10, 0)
if err == nil {
break
} else {
fmt.Println("Integer expected.")
}
}
return int(number)
}
// Print the given prompt and wait until the user enters a string.
func inputString(prompt string) string {
set_color(inputInk)
defer set_color(defaultInk)
fmt.Print(prompt)
var s = ""
fmt.Scanf("%s", &s)
return s
}
// Print the given prompt and wait until the user presses Enter.
func pressEnter(prompt string) {
inputString(prompt)
}
// Return `true` if the given string is "yes" or a synonym.
func isYes(s string) bool {
switch strings.ToLower(strings.TrimSpace(s)) {
case "ok", "yeah", "yes", "y":
return true
default:
return false
}
}
// Return `true` if the given string is "no" or a synonym.
func isNo(s string) bool {
switch strings.ToLower(strings.TrimSpace(s)) {
case "n", "no", "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".
func yes(prompt string) bool {
for {
var answer = inputString(prompt)
if isYes(answer) {
return true
}
if isNo(answer) {
return false
}
}
}
// Title, instructions and credits {{{1
// =============================================================
// Print the title at the current cursor position.
func printTitle() {
set_color(titleInk)
fmt.Println("High Noon")
set_color(defaultInk)
}
func printCredits() {
printTitle()
fmt.Println("\nOriginal version in BASIC:")
fmt.Println(" Designed and programmend by Chris Gaylo, 1970.")
fmt.Println(" http://mybitbox.com/highnoon-1970/")
fmt.Println(" http://mybitbox.com/highnoon/")
fmt.Println("Transcriptions:")
fmt.Println(" https://github.com/MrMethor/Highnoon-BASIC/")
fmt.Println(" https://github.com/mad4j/basic-highnoon/")
fmt.Println("Version modified for QB64:")
fmt.Println(" By Daniele Olmisani, 2014.")
fmt.Println(" https://github.com/mad4j/basic-highnoon/")
fmt.Println("This improved remake in Go:")
fmt.Println(" Copyright (c) 2025, Marcos Cruz (programandala.net)")
fmt.Println(" SPDX-License-Identifier: Fair")
}
func printInstructions() {
printTitle()
set_color(instructionsInk)
defer set_color(defaultInk)
fmt.Println("\nYou have been challenged to a showdown by Black Bart, one of")
fmt.Println("the meanest desperadoes west of the Allegheny mountains.")
fmt.Println("\nWhile you are walking down a dusty, deserted side street,")
fmt.Println("Black Bart emerges from a saloon one hundred paces away.")
fmt.Printf("\nBy agreement, you each have %v bullets in your six-guns.", initialBullets)
fmt.Println("\nYour marksmanship equals his. At the start of the walk nei-")
fmt.Println("ther of you can possibly hit the other, and at the end of")
fmt.Println("the walk, neither can miss. the closer you get, the better")
fmt.Println("your chances of hitting black Bart, but he also has beter")
fmt.Println("chances of hitting you.")
}
// Game loop {{{1
// =============================================================
func pluralSuffix(n int) string {
switch n {
case 1:
return ""
default:
return "s"
}
}
func printShellsLeft() {
if playerBullets == opponentBullets {
fmt.Printf("Both of you have %v bullets.\n", playerBullets)
} else {
fmt.Printf(
"You now have %v bullet%s to Black Bart's %v bullet%s.\n",
playerBullets,
pluralSuffix(playerBullets),
opponentBullets,
pluralSuffix(opponentBullets))
}
}
func printCheck() {
fmt.Println("******************************************************")
fmt.Println("* *")
fmt.Println("* BANK OF DODGE CITY *")
fmt.Println("* CASHIER'S RECEIT *")
fmt.Println("* *")
fmt.Printf("* CHECK NO. %04v AUGUST %vTH, 1889 *\n",
rand.Intn(1000),
10+rand.Intn(10))
fmt.Println("* *")
fmt.Println("* *")
fmt.Println("* PAY TO THE BEARER ON DEMAND THE SUM OF *")
fmt.Println("* *")
fmt.Println("* TWENTY THOUSAND DOLLARS-------------------$20,000 *")
fmt.Println("* *")
fmt.Println("******************************************************")
}
func getReward() {
fmt.Println("As mayor of Dodge City, and on behalf of its citizens,")
fmt.Println("I extend to you our thanks, and present you with this")
fmt.Println("reward, a check for $20,000, for killing Black Bart.\n\n")
printCheck()
fmt.Println("\n\nDon't spend it all in one place.")
}
func moveTheOpponent() {
var paces = 2 + rand.Intn(8)
fmt.Printf("Black Bart moves %v paces.\n", paces)
distance -= paces
}
// Maybe move the opponent; if so, return `true`, otherwise return `false`. A
// true `silent` flag allows to omit the message when the opponent doesn't
// move.
func theOpponentMoves(silent bool) bool {
if rand.Intn(2) == 0 { // 50% chances
moveTheOpponent()
return true
} else {
if !silent {
fmt.Println("Black Bart stands still.")
}
return false
}
}
func missedShot() bool {
return rand.Float64()*10 <= float64(distance/10)
}
// Handle the opponent's shot and return a flag with the result: if the
// opponent kills the player, return `true`; otherwise return `false`.
func theOpponentFiresAndKills() bool {
fmt.Println("Black Bart fires…")
opponentBullets -= 1
if missedShot() {
fmt.Println("A miss…")
switch opponentBullets {
case 3:
fmt.Println("Whew, were you lucky. That bullet just missed your head.")
case 2:
fmt.Println("But Black Bart got you in the right shin.")
case 1:
fmt.Println("Though Black Bart got you on the left side of your jaw.")
case 0:
fmt.Println("Black Bart must have jerked the trigger.")
}
} else {
if strategy == "j" {
fmt.Println("That trick just saved yout life. Black Bart's bullet")
fmt.Println("was stopped by the wood sides of the trough.")
} else {
fmt.Println("Black Bart shot you right through the heart that time.")
fmt.Println("You went kickin' with your boots on.")
return true
}
}
return false
}
// Handle the opponent's strategy and return a flag with the result: if the
// opponent runs or kills the player, return `true`; otherwise return `false`.
func theOpponentKillsOrRuns() bool {
if distance >= 10 || playerBullets == 0 {
if theOpponentMoves(true) {
return false
}
}
if opponentBullets > 0 {
return theOpponentFiresAndKills()
} else {
if playerBullets > 0 {
if rand.Intn(2) == 0 { // 50% chances
fmt.Println("Now is your chance, Black Bart is out of bullets.")
} else {
fmt.Println("Black Bart just hi-tailed it out of town rather than face you")
fmt.Println("without a loaded gun. You can rest assured that Black Bart")
fmt.Println("won't ever show his face around this town again.")
return true
}
}
}
return false
}
func play() {
rand.Seed(time.Now().UTC().UnixNano())
distance = initialDistance
var wateringTroughs = 0
playerBullets = initialBullets
opponentBullets = initialBullets
showdown:
for {
fmt.Printf("You are now %v paces apart from Black Bart.\n", distance)
printShellsLeft()
set_color(instructionsInk)
fmt.Println("\nStrategies:")
fmt.Println(" [A]dvance")
fmt.Println(" [S]tand still")
fmt.Println(" [F]ire")
fmt.Println(" [J]ump behind the watering trough")
fmt.Println(" [G]ive up")
fmt.Println(" [T]urn tail and run")
set_color(defaultInk)
strategy = strings.ToLower(inputString("What is your strategy? "))
switch strategy {
case "a": // advance
for {
var paces = inputInt("How many paces do you advance? ")
if paces < 0 {
fmt.Println("None of this negative stuff, partner, only positive numbers.")
} else if paces > 10 {
fmt.Println("Nobody can walk that fast.")
} else {
distance -= paces
break
}
}
case "s": // stand still
fmt.Println("That move made you a perfect stationary target.")
case "f": // fire
if playerBullets == 0 {
fmt.Println("You don't have any bullets left.")
} else {
playerBullets -= 1
if missedShot() {
switch playerBullets {
case 2:
fmt.Println("Grazed Black Bart in the right arm.")
case 1:
fmt.Println("He's hit in the left shoulder, forcing him to use his right")
fmt.Println("hand to shoot with.")
}
fmt.Println("What a lousy shot.")
if playerBullets == 0 {
fmt.Println("Nice going, ace, you've run out of bullets.")
if opponentBullets != 0 {
fmt.Println("Now Black Bart won't shoot until you touch noses.")
fmt.Println("You better think of something fast (like run).")
}
}
} else {
fmt.Println("What a shot, you got Black Bart right between the eyes.")
pressEnter("\nPress the Enter key to get your reward. ")
clearScreen()
getReward()
break showdown
}
}
case "j": // jump
if wateringTroughs == maxWateringTroughs {
fmt.Println("How many watering troughs do you think are on this street?")
strategy = ""
} else {
wateringTroughs += 1
fmt.Println("You jump behind the watering trough.")
fmt.Println("Not a bad maneuver to threw Black Bart's strategy off.")
}
case "g": // give up
fmt.Println("Black Bart accepts. The conditions are that he won't shoot you")
fmt.Println("if you take the first stage out of town and never come back.")
if yes("Agreed? ") {
fmt.Println("A very wise decision.")
break showdown
} else {
fmt.Println("Oh well, back to the showdown.")
}
case "t": // turn tail and run
// The more bullets of the opponent, the less chances to escape.
if rand.Intn(opponentBullets+2) == 0 {
fmt.Println("Man, you ran so fast even dogs couldn't catch you.")
} else {
switch opponentBullets {
case 0:
fmt.Println("You were lucky, Black Bart can only throw his gun at you, he")
fmt.Println("doesn't have any bullets left. You should really be dead.")
case 1:
fmt.Println("Black Bart fires his last bullet…")
fmt.Println("He got you right in the back. That's what you deserve, for running.")
case 2:
fmt.Println("Black Bart fires and got you twice: in your back")
fmt.Println("and your ass. Now you can't even rest in peace.")
case 3:
fmt.Println("Black Bart unloads his gun, once in your back")
fmt.Println("and twice in your ass. Now you can't even rest in peace.")
case 4:
fmt.Println("Black Bart unloads his gun, once in your back")
fmt.Println("and three times in your ass. Now you can't even rest in peace.")
}
opponentBullets = 0
}
break showdown
default:
fmt.Println("You sure aren't going to live very long if you can't even follow directions.")
} // strategy switch
if theOpponentKillsOrRuns() {
break
}
if playerBullets+opponentBullets == 0 {
fmt.Println("The showdown must end, because nobody has bullets left.")
break
}
fmt.Println()
} // showdown loop
}
// Main {{{1
// =============================================================
func main() {
clearScreen()
printCredits()
pressEnter("\nPress the Enter key to read the instructions. ")
clearScreen()
printInstructions()
pressEnter("\nPress the Enter key to start. ")
clearScreen()
play()
}
En Hare
// High Noon
//
// Original version in BASIC:
// Designed and programmed by Chris Gaylo, Syosset High School, New York, 1970-09-12.
// http://mybitbox.com/highnoon-1970/
// http://mybitbox.com/highnoon/
//
// Transcriptions:
// https://github.com/MrMethor/Highnoon-BASIC/
// https://github.com/mad4j/basic-highnoon/
//
// Version modified for QB64:
// By Daniele Olmisani, 2014.
// https://github.com/mad4j/basic-highnoon/
//
// This improved remake in Hare:
// Copyright (c) 2025, Marcos Cruz (programandala.net)
// SPDX-License-Identifier: Fair
//
// Written on 2025-02-17.
//
// Last modified: 20260213T1645+0100.
// Modules {{{1
// =============================================================================
use ascii;
use bufio;
use fmt;
use math::random;
use os;
use strconv;
use strings;
use time;
// 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 = 9;
def STYLE_OFF = 20;
def FOREGROUND = 30;
def BACKGROUND = 40;
def BRIGHT = 60;
def NORMAL_STYLE = 0;
fn move_cursor_home() void = {
fmt::print("\x1B[H")!;
};
fn hide_cursor() void = {
fmt::print("\x1B[?25l")!;
};
fn show_cursor() void = {
fmt::print("\x1B[?25h")!;
};
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();
};
// Global variables and constants {{{1
// =============================================================
def DEFAULT_INK = FOREGROUND + WHITE;
def INPUT_INK = FOREGROUND + BRIGHT + GREEN;
def INSTRUCTIONS_INK = FOREGROUND + YELLOW;
def TITLE_INK = FOREGROUND + BRIGHT + RED;
def INITIAL_DISTANCE = 100;
def INITIAL_BULLETS = 4;
def MAX_WATERING_TROUGHS = 3;
let distance: int = 0; // distance between both gunners, in paces
let player_bullets: int = 0;
let opponent_bullets: int = 0;
// 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)!)!;
};
// Print the given prompt and wait until the user enters a string.
//
fn get_string(prompt: str = "") str = {
set_style(INPUT_INK);
defer set_style(DEFAULT_INK);
return accept_string(prompt);
};
fn press_enter(prompt: str) void = {
free(accept_string(prompt));
};
fn accept_integer() (int | ...strconv::error) = {
const s = accept_string();
defer free(s);
return strconv::stoi(s);
};
fn prompted_integer(prompt: str) (int | ...strconv::error) = {
fmt::print(prompt)!;
bufio::flush(os::stdout)!;
return accept_integer();
};
fn prompted_integer_or_0(prompt: str) int = {
match (prompted_integer(prompt)) {
case let i: int =>
return i;
case =>
return 0;
};
};
// Print the given prompt and wait until the user enters an integer.
//
fn get_integer(prompt: str = "") int = {
set_style(INPUT_INK);
defer set_style(DEFAULT_INK);
return prompted_integer_or_0(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 = get_string(prompt);
defer free(answer);
if (is_yes(answer)) {
return true;
};
if (is_no(answer)) {
return false;
};
};
};
// Title, instructions and credits {{{1
// =============================================================
// Print the title at the current cursor position.
//
fn print_title() void = {
set_style(TITLE_INK);
fmt::println("High Noon")!;
set_style(DEFAULT_INK);
};
fn print_credits() void = {
print_title();
fmt::println("\nOriginal version in BASIC:")!;
fmt::println(" Designed and programmend by Chris Gaylo, 1970.")!;
fmt::println(" http://mybitbox.com/highnoon-1970/")!;
fmt::println(" http://mybitbox.com/highnoon/")!;
fmt::println("Transcriptions:")!;
fmt::println(" https://github.com/MrMethor/Highnoon-BASIC/")!;
fmt::println(" https://github.com/mad4j/basic-highnoon/")!;
fmt::println("Version modified for QB64:")!;
fmt::println(" By Daniele Olmisani, 2014.")!;
fmt::println(" https://github.com/mad4j/basic-highnoon/")!;
fmt::println("This improved remake in Hare:")!;
fmt::println(" Copyright (c) 2025, Marcos Cruz (programandala.net)")!;
fmt::println(" SPDX-License-Identifier: Fair")!;
};
fn print_instructions() void = {
print_title();
set_style(INSTRUCTIONS_INK);
defer set_style(DEFAULT_INK);
fmt::println("\nYou have been challenged to a showdown by Black Bart, one of")!;
fmt::println("the meanest desperadoes west of the Allegheny mountains.")!;
fmt::println("\nWhile you are walking down a dusty, deserted side street,")!;
fmt::println("Black Bart emerges from a saloon one hundred paces away.")!;
fmt::printf("\nBy agreement, you each have {} bullets in your six-guns.", INITIAL_BULLETS)!;
fmt::println("\nYour marksmanship equals his. At the start of the walk nei-")!;
fmt::println("ther of you can possibly hit the other, and at the end of")!;
fmt::println("the walk, neither can miss. the closer you get, the better")!;
fmt::println("your chances of hitting black Bart, but he also has beter")!;
fmt::println("chances of hitting you.")!;
};
// Game loop {{{1
// =============================================================
fn plural_suffix(n: int) str = {
switch (n) {
case 1 => return "";
case => return "s";
};
};
fn print_shells_left() void = {
if (player_bullets == opponent_bullets) {
fmt::printfln("Both of you have {} bullets.", player_bullets)!;
} else {
fmt::printf(
"You now have {} bullet{} to Black Bart's {} bullet{}.\n",
player_bullets,
plural_suffix(player_bullets),
opponent_bullets,
plural_suffix(opponent_bullets))!;
};
};
fn print_check() void = {
fmt::println("******************************************************")!;
fmt::println("* *")!;
fmt::println("* BANK OF DODGE CITY *")!;
fmt::println("* CASHIER'S RECEIT *")!;
fmt::println("* *")!;
fmt::printfln("* CHECK NO. {:_04} AUGUST {}TH, 1889 *",
random::u64n(&rand, 1000),
10: u64 + random::u64n(&rand, 10: u64))!;
fmt::println("* *")!;
fmt::println("* *")!;
fmt::println("* PAY TO THE BEARER ON DEMAND THE SUM OF *")!;
fmt::println("* *")!;
fmt::println("* TWENTY THOUSAND DOLLARS-------------------$20,000 *")!;
fmt::println("* *")!;
fmt::println("******************************************************")!;
};
fn get_reward() void = {
fmt::println("As mayor of Dodge City, and on behalf of its citizens,")!;
fmt::println("I extend to you our thanks, and present you with this")!;
fmt::println("reward, a check for $20,000, for killing Black Bart.\n\n")!;
print_check();
fmt::println("\n\nDon't spend it all in one place.")!;
};
fn move_the_opponent() void = {
let paces = 2 + random::u64n(&rand, 8): int;
fmt::printfln("Black Bart moves {} paces.", paces)!;
distance -= paces;
};
// Maybe move the opponent; if so, return `true`, otherwise return `false`. A
// true `silent` flag allows to omit the message when the opponent doesn't
// move.
//
fn maybe_move_the_opponent(silent: bool = false) bool = {
if (random::u64n(&rand, 2) == 0) { // 50% chances
move_the_opponent();
return true;
} else {
if (! silent) {
fmt::println("Black Bart stands still.")!;
};
return false;
};
};
fn missed_shot() bool = {
return random::f64rand(&rand) * 10.0 <= (distance / 10): f64;
};
// Handle the opponent's shot and return a flag with the result: if the
// opponent kills the player, return `true`; otherwise return `false`.
//
fn the_opponent_fires_and_kills(player_strategy: str) bool = {
fmt::println("Black Bart fires…")!;
opponent_bullets -= 1;
if (missed_shot()) {
fmt::println("A miss…")!;
switch (opponent_bullets) {
case 3 =>
fmt::println("Whew, were you lucky. That bullet just missed your head.")!;
case 2 =>
fmt::println("But Black Bart got you in the right shin.")!;
case 1 =>
fmt::println("Though Black Bart got you on the left side of your jaw.")!;
case 0 =>
fmt::println("Black Bart must have jerked the trigger.")!;
case =>
void;
};
} else {
if (player_strategy == "j") {
fmt::println("That trick just saved yout life. Black Bart's bullet")!;
fmt::println("was stopped by the wood sides of the trough.")!;
} else {
fmt::println("Black Bart shot you right through the heart that time.")!;
fmt::println("You went kickin' with your boots on.")!;
return true;
};
};
return false;
};
// Handle the opponent's strategy and return a flag with the result: if the
// opponent runs or kills the player, return `true`; otherwise return `false`.
//
fn the_opponent_kills_or_runs(player_strategy: str) bool = {
if (distance >= 10 || player_bullets == 0) {
if (maybe_move_the_opponent(true)) {
return false;
};
};
if (opponent_bullets > 0) {
return the_opponent_fires_and_kills(player_strategy);
} else {
if (player_bullets > 0) {
if (random::u64n(&rand, 2) == 0) { // 50% chances
fmt::println("Now is your chance, Black Bart is out of bullets.")!;
} else {
fmt::println("Black Bart just hi-tailed it out of town rather than face you")!;
fmt::println("without a loaded gun. You can rest assured that Black Bart")!;
fmt::println("won't ever show his face around this town again.")!;
return true;
};
};
};
return false;
};
fn play() void = {
distance = INITIAL_DISTANCE;
let watering_troughs = 0;
player_bullets = INITIAL_BULLETS;
opponent_bullets = INITIAL_BULLETS;
for :showdown (true) {
fmt::printfln("You are now {} paces apart from Black Bart.", distance)!;
print_shells_left();
set_style(INSTRUCTIONS_INK);
fmt::println("\nStrategies:")!;
fmt::println(" [A]dvance")!;
fmt::println(" [S]tand still")!;
fmt::println(" [F]ire")!;
fmt::println(" [J]ump behind the watering trough")!;
fmt::println(" [G]ive up")!;
fmt::println(" [T]urn tail and run")!;
set_style(DEFAULT_INK);
let player_strategy = ascii::strlower(get_string("What is your strategy?! "))!;
defer free(player_strategy);
switch (player_strategy) {
case "a" => // advance
for (true) {
let paces = get_integer("How many paces do you advance? ");
if (paces < 0) {
fmt::println("None of this negative stuff, partner, only positive numbers.")!;
} else if (paces > 10) {
fmt::println("Nobody can walk that fast.")!;
} else {
distance -= paces;
break;
};
};
case "s" => // stand still
fmt::println("That move made you a perfect stationary target.")!;
case "f" => // fire
if (player_bullets == 0) {
fmt::println("You don't have any bullets left.")!;
} else {
player_bullets -= 1;
if (missed_shot()) {
switch (player_bullets) {
case 2 =>
fmt::println("Grazed Black Bart in the right arm.")!;
case 1 =>
fmt::println("He's hit in the left shoulder, forcing him to use his right")!;
fmt::println("hand to shoot with.")!;
case =>
void;
};
fmt::println("What a lousy shot.")!;
if (player_bullets == 0) {
fmt::println("Nice going, ace, you've run out of bullets.")!;
if (opponent_bullets != 0) {
fmt::println("Now Black Bart won't shoot until you touch noses.")!;
fmt::println("You better think of something fast (like run).")!;
};
};
} else {
fmt::println("What a shot, you got Black Bart right between the eyes.")!;
press_enter("\nPress the Enter key to get your reward. ");
clear_screen();
get_reward();
break :showdown;
};
};
case "j" => // jump
if (watering_troughs == MAX_WATERING_TROUGHS) {
fmt::println("How many watering troughs do you think are on this street?")!;
player_strategy = "";
} else {
watering_troughs += 1;
fmt::println("You jump behind the watering trough.")!;
fmt::println("Not a bad maneuver to threw Black Bart's strategy off.")!;
};
case "g" => // give up
fmt::println("Black Bart accepts. The conditions are that he won't shoot you")!;
fmt::println("if you take the first stage out of town and never come back.")!;
if (yes("Agreed? ")) {
fmt::println("A very wise decision.")!;
break :showdown;
} else {
fmt::println("Oh well, back to the showdown.")!;
};
case "t" => // turn tail and run
// The more bullets of the opponent, the less chances to escape.
if (random::u64n(&rand, (opponent_bullets + 2): u64) == 0) {
fmt::println("Man, you ran so fast even dogs couldn't catch you.")!;
} else {
switch (opponent_bullets) {
case 0 =>
fmt::println("You were lucky, Black Bart can only throw his gun at you, he")!;
fmt::println("doesn't have any bullets left. You should really be dead.")!;
case 1 =>
fmt::println("Black Bart fires his last bullet…")!;
fmt::println("He got you right in the back. That's what you deserve, for running.")!;
case 2 =>
fmt::println("Black Bart fires and got you twice: in your back")!;
fmt::println("and your ass. Now you can't even rest in peace.")!;
case 3 =>
fmt::println("Black Bart unloads his gun, once in your back")!;
fmt::println("and twice in your ass. Now you can't even rest in peace.")!;
case 4 =>
fmt::println("Black Bart unloads his gun, once in your back")!;
fmt::println("and three times in your ass. Now you can't even rest in peace.")!;
case =>
void;
};
opponent_bullets = 0;
};
break :showdown;
case =>
fmt::println("You sure aren't going to live very long if you can't even follow directions.")!;
}; // strategy switch
if (the_opponent_kills_or_runs(player_strategy)) {
break;
};
if (player_bullets + opponent_bullets == 0) {
fmt::println("The showdown must end, because nobody has bullets left.")!;
break;
};
fmt::println()!;
}; // showdown loop
};
// Main {{{1
// =============================================================
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();
clear_screen();
print_credits();
press_enter("\nPress the Enter key to read the instructions. ");
clear_screen();
print_instructions();
press_enter("\nPress the Enter key to start. ");
clear_screen();
play();
};
En Kotlin
/*
High Noon
Original version in BASIC:
Designed and programmed by Chris Gaylo, Syosset High School, New York, 1970-09-12.
http://mybitbox.com/highnoon-1970/
http://mybitbox.com/highnoon/
Transcriptions:
https://github.com/MrMethor/Highnoon-BASIC/
https://github.com/mad4j/basic-highnoon/
Version modified for QB64:
By Daniele Olmisani, 2014.
https://github.com/mad4j/basic-highnoon/
Improved remake in Odin:
Copyright (c) 2023, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written in 2023-11-24/25.
This conversion from Odin to Kotlin:
Copyright (c) 2023, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written in 2023-11-26/27.
Last modified: 20260205T1349+0100.
*/
import kotlin.random.Random
// Terminal {{{1
// =============================================================
const val BLACK = 0
const val RED = 1
const val GREEN = 2
const val YELLOW = 3
const val BLUE = 4
const val MAGENTA = 5
const val CYAN = 6
const val WHITE = 7
const val DEFAULT = 9
const val FOREGROUND = +30
const val BRIGHT = +60
// Move the cursor to the top left position of the terminal.
fun moveCursorHome() {
print("\u001B[H")
}
// Clear the terminal and move the cursor to the top left position.
fun clearScreen() {
print("\u001B[2J")
moveCursorHome()
}
// Set the color.
fun setColor(color: Int) {
print("\u001B[${color}m")
}
// Global variables and constants {{{1
// =============================================================
const val DEFAULT_INK = WHITE + FOREGROUND
const val INPUT_INK = GREEN + BRIGHT + FOREGROUND
const val INSTRUCTIONS_INK = YELLOW + FOREGROUND
const val TITLE_INK = RED + BRIGHT + FOREGROUND
const val INITIAL_DISTANCE = 100
const val INITIAL_BULLETS = 4
const val MAX_WATERING_TROUGHS = 3
var distance = 0// distance between both gunners, in paces
var strategy = "" // player's strategy
var playerBullets = 0
var opponentBullets = 0
// User input {{{1
// =============================================================
// Print the given prompt in the correspondent color, wait until the user
// enters a string and return it parsed as an `int`; if no appropriate value
// could be found, or if the input string contained more than just the number,
// return 0. Restore the default color.
fun inputInt(prompt: String): Int {
setColor(INPUT_INK)
print(prompt)
val input = readln()
var number : Int
try {
number = input.toInt()
}
catch (e: NumberFormatException) {
number = 0
}
setColor(DEFAULT_INK)
return number
}
// Print the given prompt and wait until the user enters a string.
fun inputString(prompt: String = ""): String {
setColor(INPUT_INK)
print(prompt)
setColor(DEFAULT_INK)
return readln()
}
// Print the given prompt and wait until the user presses Enter.
fun pressEnter(prompt: String) {
inputString(prompt)
}
// 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 {
while (true) {
var answer = inputString(prompt)
if (isYes(answer) ) return true
if (isNo(answer) ) return false
}
}
// Title, instructions and credits {{{1
// =============================================================
const val TITLE = "High Noon"
// Print the title at the current cursor position.
fun printTitle() {
setColor(TITLE_INK)
println(TITLE)
setColor(DEFAULT_INK)
}
fun printCredits() {
printTitle()
println("\nOriginal version in BASIC:")
println(" Designed and programmend by Chris Gaylo, 1970.")
println(" http://mybitbox.com/highnoon-1970/")
println(" http://mybitbox.com/highnoon/")
println("Transcriptions:")
println(" https://github.com/MrMethor/Highnoon-BASIC/")
println(" https://github.com/mad4j/basic-highnoon/")
println("Version modified for QB64:")
println(" By Daniele Olmisani, 2014.")
println(" https://github.com/mad4j/basic-highnoon/")
println("This improved remake in Kotlin:")
println(" Copyright (c) 2023, Marcos Cruz (programandala.net)")
println(" SPDX-License-Identifier: Fair")
}
fun printInstructions() {
printTitle()
setColor(INSTRUCTIONS_INK)
println("\nYou have been challenged to a showdown by Black Bart, one of")
println("the meanest desperadoes west of the Allegheny mountains.")
println("\nWhile you are walking down a dusty, deserted side street,")
println("Black Bart emerges from a saloon one hundred paces away.")
println("\nBy agreement, you each have $INITIAL_BULLETS bullets in your six-guns.")
println("\nYour marksmanship equals his. At the start of the walk nei-")
println("ther of you can possibly hit the other, and at the end of")
println("the walk, neither can miss. the closer you get, the better")
println("your chances of hitting black Bart, but he also has beter")
println("chances of hitting you.")
setColor(DEFAULT_INK)
}
// Game loop {{{1
// =============================================================
fun pluralSuffix(n: Int): String {
when (n) {
1 -> return ""
else -> return "s"
}
}
fun printShellsLeft() {
if (playerBullets == opponentBullets) {
println("Both of you have $playerBullets bullets.")
} else {
println(
"You now have $playerBullets bullet${pluralSuffix(playerBullets)} to Black Bart's $opponentBullets bullet${pluralSuffix(opponentBullets)}."
)
}
}
fun printCheck() {
val check = (0..999).random().toString().padStart(4, '0')
val day = 10 + (0..9).random()
println("******************************************************")
println("* *")
println("* BANK OF DODGE CITY *")
println("* CASHIER'S RECEIT *")
println("* *")
println("* CHECK NO. $check AUGUST ${day}TH, 1889 *")
println("* *")
println("* *")
println("* PAY TO THE BEARER ON DEMAND THE SUM OF *")
println("* *")
println("* TWENTY THOUSAND DOLLARS-------------------$20,000 *")
println("* *")
println("******************************************************")
}
fun getReward() {
println("As mayor of Dodge City, and on behalf of its citizens,")
println("I extend to you our thanks, and present you with this")
println("reward, a check for $20,000, for killing Black Bart.\n\n")
printCheck()
println("\n\nDon't spend it all in one place.")
}
fun moveTheOpponent() {
var paces = 2 + (0..7).random()
println("Black Bart moves $paces paces.")
distance -= paces
}
// Maybe move the opponent; if so, return `true`, otherwise return `false`.
// A true `silent` flag allows to omit the message when the opponent doesn't move.
fun maybeMoveTheOpponent(silent : Boolean = false): Boolean {
if ((0..1).random() == 0) { // 50% chances
moveTheOpponent()
return true
} else {
if (! silent) {
println("Black Bart stands still.")
}
return false
}
}
fun missedShot(): Boolean {
return Random.nextDouble() * 10 <= distance / 10.toDouble()
}
// Handle the opponent's shot and return a flag with the result: if the
// opponent kills the player, return `true`; otherwise return `false`.
fun theOpponentFiresAndKills(): Boolean {
println("Black Bart fires…")
opponentBullets -= 1
if (missedShot()) {
println("A miss…")
when (opponentBullets) {
3 -> println("Whew, were you lucky. That bullet just missed your head.")
2 -> println("But Black Bart got you in the right shin.")
1 -> println("Though Black Bart got you on the left side of your jaw.")
0 -> println("Black Bart must have jerked the trigger.")
}
} else {
if (strategy == "j") {
println("That trick just saved yout life. Black Bart's bullet")
println("was stopped by the wood sides of the trough.")
} else {
println("Black Bart shot you right through the heart that time.")
println("You went kickin' with your boots on.")
return true
}
}
return false
}
// Handle the opponent's strategy and return a flag with the result: if the
// opponent runs or kills the player, return `true`; otherwise return `false`.
fun theOpponentKillsOrRuns(): Boolean {
if (distance >= 10 || playerBullets == 0) {
if (maybeMoveTheOpponent(silent = true) ) return false
}
if (opponentBullets > 0) {
return theOpponentFiresAndKills()
} else {
if (playerBullets > 0) {
if ((0..1).random() == 0) { // 50% chances
println("Now is your chance, Black Bart is out of bullets.")
} else {
println("Black Bart just hi-tailed it out of town rather than face you")
println("without a loaded gun. You can rest assured that Black Bart")
println("won't ever show his face around this town again.")
return true
}
}
}
return false
}
fun play() {
distance = INITIAL_DISTANCE
var wateringTroughs = 0
playerBullets = INITIAL_BULLETS
opponentBullets = INITIAL_BULLETS
showdown@ while (true) {
println("You are now $distance paces apart from Black Bart.")
printShellsLeft()
setColor(INSTRUCTIONS_INK)
println("\nStrategies:")
println(" [A]dvance")
println(" [S]tand still")
println(" [F]ire")
println(" [J]ump behind the watering trough")
println(" [G]ive up")
println(" [T]urn tail and run")
setColor(DEFAULT_INK)
strategy = inputString("What is your strategy? ").lowercase()
when (strategy) {
"a" -> { // advance
while (true) {
var paces = inputInt("How many paces do you advance? ")
if (paces < 0) {
println("None of this negative stuff, partner, only positive numbers.")
} else if (paces > 10) {
println("Nobody can walk that fast.")
} else {
distance -= paces
break
}
}
}
"s" -> { // stand still
println("That move made you a perfect stationary target.")
}
"f" -> { // fire
if (playerBullets == 0) {
println("You don't have any bullets left.")
} else {
playerBullets -= 1
if (missedShot()) {
when (playerBullets) {
2 ->
println("Grazed Black Bart in the right arm.")
1 -> {
println("He's hit in the left shoulder, forcing him to use his right")
println("hand to shoot with.")
}
}
println("What a lousy shot.")
if (playerBullets == 0) {
println("Nice going, ace, you've run out of bullets.")
if (opponentBullets != 0) {
println("Now Black Bart won't shoot until you touch noses.")
println("You better think of something fast (like run).")
}
}
} else {
println("What a shot, you got Black Bart right between the eyes.")
pressEnter("\nPress the Enter key to get your reward. ")
clearScreen()
getReward()
break@showdown
}
}
}
"j" -> { // jump
if (wateringTroughs == MAX_WATERING_TROUGHS) {
println("How many watering troughs do you think are on this street?")
strategy = ""
} else {
wateringTroughs += 1
println("You jump behind the watering trough.")
println("Not a bad maneuver to threw Black Bart's strategy off.")
}
}
"g" -> { // give up
println("Black Bart accepts. The conditions are that he won't shoot you")
println("if you take the first stage out of town and never come back.")
if (yes("Agreed? ")) {
println("A very wise decision.")
break@showdown
} else {
println("Oh well, back to the showdown.")
}
}
"t" -> { // turn tail and run
// The more bullets of the opponent, the less chances to escape.
if (((0..(opponentBullets + 1)).random()) == 0) {
println("Man, you ran so fast even dogs couldn't catch you.")
} else {
when (opponentBullets) {
0 -> {
println("You were lucky, Black Bart can only throw his gun at you, he")
println("doesn't have any bullets left. You should really be dead.")
}
1 -> {
println("Black Bart fires his last bullet…",)
println("He got you right in the back. That's what you deserve, for running.")
}
2 -> {
println("Black Bart fires and got you twice: in your back")
println("and your ass. Now you can't even rest in peace.")
}
3 -> {
println("Black Bart unloads his gun, once in your back")
println("and twice in your ass. Now you can't even rest in peace.")
}
4 -> {
println("Black Bart unloads his gun, once in your back")
println("and three times in your ass. Now you can't even rest in peace.")
}
}
opponentBullets = 0
}
break@showdown
}
else -> println("You sure aren't going to live very long if you can't even follow directions.")
} // strategy switch
if (theOpponentKillsOrRuns() ) break
if (playerBullets + opponentBullets == 0) {
println("The showdown must end, because nobody has bullets left.")
break
}
println()
} // showdown loop
}
// Main {{{1
// =============================================================
fun main() {
clearScreen()
printCredits()
pressEnter("\nPress the Enter key to read the instructions. ")
clearScreen()
printInstructions()
pressEnter("\nPress the Enter key to start. ")
clearScreen()
play()
}
En Nim
#[
High Noon
Original version in BASIC:
Designed and programmed by Chris Gaylo, Syosset High School, New York, 1970-09-12.
http://mybitbox.com/highnoon-1970/
http://mybitbox.com/highnoon/
Transcriptions:
https://github.com/MrMethor/Highnoon-BASIC/
https://github.com/mad4j/basic-highnoon/
Version modified for QB64:
By Daniele Olmisani, 2014.
https://github.com/mad4j/basic-highnoon/
Improved remake in Odin:
Copyright (c) 2023, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
This improved remake in Nim:
Copyright (c) 2025, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written on 2025-01-21.
Last modified: 20250404T0159+0200.
]#
import std/math
import std/random
import std/strformat
import std/strutils
import std/terminal
import std/unicode
# Terminal {{{1
# =============================================================
proc cursorHome() =
setCursorPos(0, 0)
proc clearScreen() =
eraseScreen()
cursorHome()
# Global variables and constants {{{1
# =============================================================
type Color = tuple [
foreground: ForegroundColor,
bright: bool,
]
const defaultInk: Color = (fgWhite, false)
const inputInk: Color = (fgGreen, true)
const instructionsInk: Color = (fgYellow, false)
const titleInk: Color = (fgRed, false)
const initialDistance = 100
const initialBullets = 4
const maxWateringTroughs = 3
var distance: int # distance between both gunners, in paces
var strategy: string # player's strategy
var playerBullets: int
var opponentBullets: int
# User input {{{1
# =============================================================
# Print the given prompt and wait until the user enters an integer.
#
proc inputInt(prompt = ""): int =
write(stdout, ansiForegroundColorCode(inputInk.foreground, inputInk.bright))
defer: write(stdout, ansiForegroundColorCode(defaultInk.foreground, defaultInk.bright))
while true:
try:
write(stdout, prompt)
result = parseInt(readLine(stdin))
break
except ValueError:
result = 0
# Print the given prompt and wait until the user enters a string.
#
proc inputString(prompt = ""): string =
write(stdout, ansiForegroundColorCode(inputInk.foreground, inputInk.bright))
defer: write(stdout, ansiForegroundColorCode(defaultInk.foreground, defaultInk.bright))
write(stdout, prompt)
result = readLine(stdin)
# Print the given prompt and wait until the user presses Enter.
#
proc pressAnyKey(prompt: string) =
write(stdout, prompt)
discard getch()
# Return `true` if the given string is "yes" or a synonym.
#
proc isYes(s: string): bool =
result = toLower(s) in ["ok", "y", "yeah", "yes"]
# Return `true` if the given string is "no" or a synonym.
#
proc isNo(s: string): bool =
result = 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:
var answer = inputString(prompt)
if isYes(answer):
return true
if isNo(answer):
return false
# Title, instructions and credits {{{1
# =============================================================
# Print the title at the current cursor position.
#
proc printTitle() =
write(stdout, ansiForegroundColorCode(titleInk.foreground, titleInk.bright))
writeLine(stdout, "High Noon")
write(stdout, ansiForegroundColorCode(defaultInk.foreground, defaultInk.bright))
proc printCredits() =
printTitle()
writeLine(stdout, "\nOriginal version in BASIC:")
writeLine(stdout, " Designed and programmend by Chris Gaylo, 1970.")
writeLine(stdout, " http://mybitbox.com/highnoon-1970/")
writeLine(stdout, " http://mybitbox.com/highnoon/")
writeLine(stdout, "Transcriptions:")
writeLine(stdout, " https://github.com/MrMethor/Highnoon-BASIC/")
writeLine(stdout, " https://github.com/mad4j/basic-highnoon/")
writeLine(stdout, "Version modified for QB64:")
writeLine(stdout, " By Daniele Olmisani, 2014.")
writeLine(stdout, " https://github.com/mad4j/basic-highnoon/")
writeLine(stdout, "This improved remake in Nim:")
writeLine(stdout, " Copyright (c) 2025, Marcos Cruz (programandala.net)")
writeLine(stdout, " SPDX-License-Identifier: Fair")
proc printInstructions() =
printTitle()
write(stdout, ansiForegroundColorCode(instructionsInk.foreground, instructionsInk.bright))
defer: write(stdout, ansiForegroundColorCode(defaultInk.foreground, defaultInk.bright))
writeLine(stdout, "\nYou have been challenged to a showdown by Black Bart, one of")
writeLine(stdout, "the meanest desperadoes west of the Allegheny mountains.")
writeLine(stdout, "\nWhile you are walking down a dusty, deserted side street,")
writeLine(stdout, "Black Bart emerges from a saloon one hundred paces away.")
write(stdout, "\nBy agreement, you each have ", initialBullets, " bullets in your six-guns.")
writeLine(stdout, "\nYour marksmanship equals his. At the start of the walk nei-")
writeLine(stdout, "ther of you can possibly hit the other, and at the end of")
writeLine(stdout, "the walk, neither can miss. the closer you get, the better")
writeLine(stdout, "your chances of hitting black Bart, but he also has beter")
writeLine(stdout, "chances of hitting you.")
# Game loop {{{1
# =============================================================
proc pluralSuffix(n: int): string =
case n:
of 1: return ""
else: return "s"
proc printShellsLeft() =
if playerBullets == opponentBullets:
writeLine(stdout, "Both of you have ", playerBullets, " bullets.")
else:
writeLine(stdout, "You now have ", playerBullets, " bullet", pluralSuffix(playerBullets), " to Black Bart's ", opponentBullets, " bullet", pluralSuffix(opponentBullets), ".")
proc printCheck() =
writeLine(stdout, "******************************************************")
writeLine(stdout, "* *")
writeLine(stdout, "* BANK OF DODGE CITY *")
writeLine(stdout, "* CASHIER'S RECEIT *")
writeLine(stdout, "* *")
writeLine(stdout, fmt"* CHECK NO. {rand(1000 - 1):04} AUGUST ", 10 + rand(10 - 1), "TH, 1889 *")
writeLine(stdout, "* *")
writeLine(stdout, "* *")
writeLine(stdout, "* PAY TO THE BEARER ON DEMAND THE SUM OF *")
writeLine(stdout, "* *")
writeLine(stdout, "* TWENTY THOUSAND DOLLARS-------------------$20,000 *")
writeLine(stdout, "* *")
writeLine(stdout, "******************************************************")
proc getReward() =
writeLine(stdout, "As mayor of Dodge City, and on behalf of its citizens,")
writeLine(stdout, "I extend to you our thanks, and present you with this")
writeLine(stdout, "reward, a check for $20,000, for killing Black Bart.\n\n")
printCheck()
writeLine(stdout, "\n\nDon't spend it all in one place.")
proc moveTheOpponent() =
var paces = 2 + rand(8 - 1)
writeLine(stdout, "Black Bart moves ", paces, " paces.")
distance -= paces
# Maybe move the opponent; if so, return `true`, otherwise return `false`. A
# true `silent` flag allows to omit the message when the opponent doesn't
# move.
#
proc maybeMoveTheOpponent(silent = false): bool =
if rand(1) == 0: # 50% chances
moveTheOpponent()
return true
else:
if not silent:
writeLine(stdout, "Black Bart stands still.")
return false
proc missedShot(): bool =
result = rand(1.0) * 10 <= float(distance / 10)
# Handle the opponent's shot and return a flag with the result: if the
# opponent kills the player, return `true`; otherwise return `false`.
#
proc theOpponentFiresAndKills(): bool =
writeLine(stdout, "Black Bart fires…")
opponentBullets -= 1
if missedShot():
writeLine(stdout, "A miss…")
case opponentBullets:
of 3:
writeLine(stdout, "Whew, were you lucky. That bullet just missed your head.")
of 2:
writeLine(stdout, "But Black Bart got you in the right shin.")
of 1:
writeLine(stdout, "Though Black Bart got you on the left side of your jaw.")
of 0:
writeLine(stdout, "Black Bart must have jerked the trigger.")
else:
discard
else:
if strategy == "j":
writeLine(stdout, "That trick just saved yout life. Black Bart's bullet")
writeLine(stdout, "was stopped by the wood sides of the trough.")
else:
writeLine(stdout, "Black Bart shot you right through the heart that time.")
writeLine(stdout, "You went kickin' with your boots on.")
return true
result = false
# Handle the opponent's strategy and return a flag with the result: if the
# opponent runs or kills the player, return `true`; otherwise return `false`.
#
proc theOpponentKillsOrRuns(): bool =
if distance >= 10 or playerBullets == 0:
if maybeMoveTheOpponent(silent = true):
return false
if opponentBullets > 0:
return theOpponentFiresAndKills()
else:
if playerBullets > 0:
if rand(1) == 0: # 50% chances
writeLine(stdout, "Now is your chance, Black Bart is out of bullets.")
else:
writeLine(stdout, "Black Bart just hi-tailed it out of town rather than face you")
writeLine(stdout, "without a loaded gun. You can rest assured that Black Bart")
writeLine(stdout, "won't ever show his face around this town again.")
return true
result = false
proc play() =
distance = initialDistance
var wateringTroughs = 0
playerBullets = initialBullets
opponentBullets = initialBullets
block showdown:
while true:
writeLine(stdout, "You are now ", distance, " paces apart from Black Bart.")
printShellsLeft()
write(stdout, ansiForegroundColorCode(instructionsInk.foreground, instructionsInk.bright))
writeLine(stdout, "\nStrategies:")
writeLine(stdout, " [A]dvance")
writeLine(stdout, " [S]tand still")
writeLine(stdout, " [F]ire")
writeLine(stdout, " [J]ump behind the watering trough")
writeLine(stdout, " [G]ive up")
writeLine(stdout, " [T]urn tail and run")
write(stdout, ansiForegroundColorCode(defaultInk.foreground, defaultInk.bright))
strategy = toLower(inputString("What is your strategy? "))
case strategy:
of "a": # advance
while true:
var paces = inputInt("How many paces do you advance? ")
if paces < 0:
writeLine(stdout, "None of this negative stuff, partner, only positive numbers.")
elif paces > 10:
writeLine(stdout, "Nobody can walk that fast.")
else:
distance -= paces
break
of "s": # stand still
writeLine(stdout, "That move made you a perfect stationary target.")
of "f": # fire
if playerBullets == 0:
writeLine(stdout, "You don't have any bullets left.")
else:
playerBullets -= 1
if missedShot():
case playerBullets:
of 2:
writeLine(stdout, "Grazed Black Bart in the right arm.")
of 1:
writeLine(stdout, "He's hit in the left shoulder, forcing him to use his right")
writeLine(stdout, "hand to shoot with.")
else:
discard
writeLine(stdout, "What a lousy shot.")
if playerBullets == 0:
writeLine(stdout, "Nice going, ace, you've run out of bullets.")
if opponentBullets != 0:
writeLine(stdout, "Now Black Bart won't shoot until you touch noses.")
writeLine(stdout, "You better think of something fast (like run).")
else:
writeLine(stdout, "What a shot, you got Black Bart right between the eyes.")
pressAnyKey("\nPress any key to get your reward. ")
clearScreen()
getReward()
break showdown
of "j": # jump
if wateringTroughs == maxWateringTroughs:
writeLine(stdout, "How many watering troughs do you think are on this street?")
strategy = ""
else:
wateringTroughs += 1
writeLine(stdout, "You jump behind the watering trough.")
writeLine(stdout, "Not a bad maneuver to threw Black Bart's strategy off.")
of "g": # give up
writeLine(stdout, "Black Bart accepts. The conditions are that he won't shoot you")
writeLine(stdout, "if you take the first stage out of town and never come back.")
if yes("Agreed? "):
writeLine(stdout, "A very wise decision.")
break showdown
else:
writeLine(stdout, "Oh well, back to the showdown.")
of "t": # turn tail and run
# The more bullets of the opponent, the less chances to escape.
if rand(opponentBullets + 2 - 1) == 0:
writeLine(stdout, "Man, you ran so fast even dogs couldn't catch you.")
else:
case opponentBullets:
of 0:
writeLine(stdout, "You were lucky, Black Bart can only throw his gun at you, he")
writeLine(stdout, "doesn't have any bullets left. You should really be dead.")
of 1:
writeLine(stdout, "Black Bart fires his last bullet…")
writeLine(stdout, "He got you right in the back. That's what you deserve, for running.")
of 2:
writeLine(stdout, "Black Bart fires and got you twice: in your back")
writeLine(stdout, "and your ass. Now you can't even rest in peace.")
of 3:
writeLine(stdout, "Black Bart unloads his gun, once in your back")
writeLine(stdout, "and twice in your ass. Now you can't even rest in peace.")
of 4:
writeLine(stdout, "Black Bart unloads his gun, once in your back")
writeLine(stdout, "and three times in your ass. Now you can't even rest in peace.")
else:
discard
opponentBullets = 0
break showdown
else:
writeLine(stdout, "You sure aren't going to live very long if you can't even follow directions.")
# end of strategy case
if theOpponentKillsOrRuns():
break
if playerBullets + opponentBullets == 0:
writeLine(stdout, "The showdown must end, because nobody has bullets left.")
break
writeLine(stdout, "")
# end of showdown block
# Main {{{1
# =============================================================
randomize()
clearScreen()
printCredits()
pressAnyKey("\nPress any key to read the instructions. ")
clearScreen()
printInstructions()
pressAnyKey("\nPress any key to start. ")
clearScreen()
play()
En Odin
/*
High Noon
Original version in BASIC:
Designed and programmed by Chris Gaylo, Syosset High School, New York, 1970-09-12.
http://mybitbox.com/highnoon-1970/
http://mybitbox.com/highnoon/
Transcriptions:
https://github.com/MrMethor/Highnoon-BASIC/
https://github.com/mad4j/basic-highnoon/
Version modified for QB64:
By Daniele Olmisani, 2014.
https://github.com/mad4j/basic-highnoon/
This improved remake in Odin:
Copyright (c) 2023, 2025, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written in 2023-11, 2023-12, 2025-02.
Last modified: 20250407T1920+0200.
*/
package high_noon
import "../lib/anodino/src/basic"
import "../lib/anodino/src/read"
import "../lib/anodino/src/term"
import "core:fmt"
import "core:math/rand"
import "core:slice"
import "core:strings"
// Global variables and constants {{{1
// =============================================================
DEFAULT_INK :: basic.WHITE
INPUT_INK :: basic.BRIGHT_GREEN
INSTRUCTIONS_INK :: basic.YELLOW
TITLE_INK :: basic.BRIGHT_RED
INITIAL_DISTANCE :: 100
INITIAL_BULLETS :: 4
MAX_WATERING_TROUGHS :: 3
distance : int // distance between both gunners, in paces
player_bullets : int
opponent_bullets : int
// User input {{{1
// =============================================================
// Print the given prompt and wait until the user enters an integer.
//
input_int :: proc(prompt : string = "") -> int {
basic.color(INPUT_INK)
defer basic.color(DEFAULT_INK)
fmt.print(prompt)
return read.an_int_or_0()
}
// Print the given prompt and wait until the user enters a string.
//
input_string :: proc(prompt : string = "") -> (string, bool) {
basic.color(INPUT_INK)
defer basic.color(DEFAULT_INK)
fmt.print(prompt)
return read.a_string()
}
// Print the given prompt and wait until the user presses Enter.
//
press_enter :: proc(prompt : string) {
s, _ := input_string(prompt)
delete(s)
}
// 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, _ := input_string(prompt)
defer delete(answer)
if is_yes(answer) do return true
if is_no(answer) do return false
}
}
// Title, instructions and credits {{{1
// =============================================================
// Print the title at the current cursor position.
//
print_title :: proc() {
basic.color(TITLE_INK)
fmt.println("High Noon")
basic.color(DEFAULT_INK)
}
print_credits :: proc() {
print_title()
fmt.println("\nOriginal version in BASIC:")
fmt.println(" Designed and programmend by Chris Gaylo, 1970.")
fmt.println(" http://mybitbox.com/highnoon-1970/")
fmt.println(" http://mybitbox.com/highnoon/")
fmt.println("Transcriptions:")
fmt.println(" https://github.com/MrMethor/Highnoon-BASIC/")
fmt.println(" https://github.com/mad4j/basic-highnoon/")
fmt.println("Version modified for QB64:")
fmt.println(" By Daniele Olmisani, 2014.")
fmt.println(" https://github.com/mad4j/basic-highnoon/")
fmt.println("This improved remake in Odin:")
fmt.println(" Copyright (c) 2023, 2025, Marcos Cruz (programandala.net)")
fmt.println(" SPDX-License-Identifier: Fair")
}
print_instructions :: proc() {
print_title()
basic.color(INSTRUCTIONS_INK)
defer basic.color(DEFAULT_INK)
fmt.println("\nYou have been challenged to a showdown by Black Bart, one of")
fmt.println("the meanest desperadoes west of the Allegheny mountains.")
fmt.println("\nWhile you are walking down a dusty, deserted side street,")
fmt.println("Black Bart emerges from a saloon one hundred paces away.")
fmt.printf("\nBy agreement, you each have %v bullets in your six-guns.", INITIAL_BULLETS)
fmt.println("\nYour marksmanship equals his. At the start of the walk nei-")
fmt.println("ther of you can possibly hit the other, and at the end of")
fmt.println("the walk, neither can miss. the closer you get, the better")
fmt.println("your chances of hitting black Bart, but he also has beter")
fmt.println("chances of hitting you.")
}
// Game loop {{{1
// =============================================================
plural_suffix :: proc(n : int) -> string {
switch n {
case 1 : return ""
case : return "s"
}
}
print_shells_left :: proc() {
if player_bullets == opponent_bullets {
fmt.printfln("Both of you have %v bullets.", player_bullets)
} else {
fmt.printf(
"You now have %v bullet%s to Black Bart's %v bullet%s.\n",
player_bullets,
plural_suffix(player_bullets),
opponent_bullets,
plural_suffix(opponent_bullets))
}
}
print_check :: proc() {
fmt.println("******************************************************")
fmt.println("* *")
fmt.println("* BANK OF DODGE CITY *")
fmt.println("* CASHIER'S RECEIT *")
fmt.println("* *")
fmt.printfln("* CHECK NO. %04v AUGUST %vTH, 1889 *",
rand.int_max(1000),
10 + rand.int_max(10))
fmt.println("* *")
fmt.println("* *")
fmt.println("* PAY TO THE BEARER ON DEMAND THE SUM OF *")
fmt.println("* *")
fmt.println("* TWENTY THOUSAND DOLLARS-------------------$20,000 *")
fmt.println("* *")
fmt.println("******************************************************")
}
get_reward :: proc() {
fmt.println("As mayor of Dodge City, and on behalf of its citizens,")
fmt.println("I extend to you our thanks, and present you with this")
fmt.println("reward, a check for $20,000, for killing Black Bart.\n\n")
print_check()
fmt.println("\n\nDon't spend it all in one place.")
}
move_the_opponent :: proc() {
paces := 2 + rand.int_max(8)
fmt.printfln("Black Bart moves %v paces.", paces)
distance -= paces
}
// Maybe move the opponent; if so, return `true`, otherwise return `false`. A
// true `silent` flag allows to omit the message when the opponent doesn't
// move.
//
maybe_move_the_opponent :: proc(silent := false) -> bool {
if rand.int_max(2) == 0 { // 50% chances
move_the_opponent()
return true
} else {
if ! silent {
fmt.println("Black Bart stands still.")
}
return false
}
}
the_opponent_moves :: maybe_move_the_opponent
missed_shot :: proc() -> bool {
return rand.float64() * 10 <= f64(distance / 10)
}
// Handle the opponent's shot and return a flag with the result: if the
// opponent kills the player, return `true`; otherwise return `false`.
//
the_opponent_fires_and_kills :: proc(strategy: string) -> bool {
fmt.println("Black Bart fires…")
opponent_bullets -= 1
if missed_shot() {
fmt.println("A miss…")
switch opponent_bullets {
case 3 :
fmt.println("Whew, were you lucky. That bullet just missed your head.")
case 2 :
fmt.println("But Black Bart got you in the right shin.")
case 1 :
fmt.println("Though Black Bart got you on the left side of your jaw.")
case 0 :
fmt.println("Black Bart must have jerked the trigger.")
}
} else {
if strategy == "j" {
fmt.println("That trick just saved yout life. Black Bart's bullet")
fmt.println("was stopped by the wood sides of the trough.")
} else {
fmt.println("Black Bart shot you right through the heart that time.")
fmt.println("You went kickin' with your boots on.")
return true
}
}
return false
}
// Handle the opponent's strategy and return a flag with the result: if the
// opponent runs or kills the player, return `true`; otherwise return `false`.
//
the_opponent_kills_or_runs :: proc(strategy: string) -> bool {
if distance >= 10 || player_bullets == 0 {
if the_opponent_moves(silent = true) do return false
}
if opponent_bullets > 0 {
return the_opponent_fires_and_kills(strategy)
} else {
if player_bullets > 0 {
if rand.int_max(2) == 0 { // 50% chances
fmt.println("Now is your chance, Black Bart is out of bullets.")
} else {
fmt.println("Black Bart just hi-tailed it out of town rather than face you")
fmt.println("without a loaded gun. You can rest assured that Black Bart")
fmt.println("won't ever show his face around this town again.")
return true
}
}
}
return false
}
play :: proc() {
distance = INITIAL_DISTANCE
watering_troughs := 0
player_bullets = INITIAL_BULLETS
opponent_bullets = INITIAL_BULLETS
showdown: for {
fmt.printfln("You are now %v paces apart from Black Bart.", distance)
print_shells_left()
basic.color(INSTRUCTIONS_INK)
fmt.println("\nStrategies:")
fmt.println(" [A]dvance")
fmt.println(" [S]tand still")
fmt.println(" [F]ire")
fmt.println(" [J]ump behind the watering trough")
fmt.println(" [G]ive up")
fmt.println(" [T]urn tail and run")
basic.color(DEFAULT_INK)
raw_strategy, _ := input_string("What is your strategy? ")
defer delete(raw_strategy)
strategy := strings.to_lower(raw_strategy)
defer delete(strategy)
switch strategy {
case "a" : // advance
for {
paces := input_int("How many paces do you advance? ")
if paces < 0 {
fmt.println("None of this negative stuff, partner, only positive numbers.")
} else if paces > 10 {
fmt.println("Nobody can walk that fast.")
} else {
distance -= paces
break
}
}
case "s" : // stand still
fmt.println("That move made you a perfect stationary target.")
case "f" : // fire
if player_bullets == 0 {
fmt.println("You don't have any bullets left.")
} else {
player_bullets -= 1
if missed_shot() {
switch player_bullets {
case 2 :
fmt.println("Grazed Black Bart in the right arm.")
case 1 :
fmt.println("He's hit in the left shoulder, forcing him to use his right")
fmt.println("hand to shoot with.")
}
fmt.println("What a lousy shot.")
if player_bullets == 0 {
fmt.println("Nice going, ace, you've run out of bullets.")
if opponent_bullets != 0 {
fmt.println("Now Black Bart won't shoot until you touch noses.")
fmt.println("You better think of something fast (like run).")
}
}
} else {
fmt.println("What a shot, you got Black Bart right between the eyes.")
press_enter("\nPress the Enter key to get your reward. ")
term.clear_screen()
get_reward()
break showdown
}
}
case "j" : // jump
if watering_troughs == MAX_WATERING_TROUGHS {
fmt.println("How many watering troughs do you think are on this street?")
strategy = ""
} else {
watering_troughs += 1
fmt.println("You jump behind the watering trough.")
fmt.println("Not a bad maneuver to threw Black Bart's strategy off.")
}
case "g" : // give up
fmt.println("Black Bart accepts. The conditions are that he won't shoot you")
fmt.println("if you take the first stage out of town and never come back.")
if yes("Agreed? ") {
fmt.println("A very wise decision.")
break showdown
} else {
fmt.println("Oh well, back to the showdown.")
}
case "t" : // turn tail and run
// The more bullets of the opponent, the less chances to escape.
if rand.int_max(opponent_bullets + 2) == 0 {
fmt.println("Man, you ran so fast even dogs couldn't catch you.")
} else {
switch opponent_bullets {
case 0 :
fmt.println("You were lucky, Black Bart can only throw his gun at you, he")
fmt.println("doesn't have any bullets left. You should really be dead.")
case 1 :
fmt.println("Black Bart fires his last bullet…")
fmt.println("He got you right in the back. That's what you deserve, for running.")
case 2 :
fmt.println("Black Bart fires and got you twice: in your back")
fmt.println("and your ass. Now you can't even rest in peace.")
case 3 :
fmt.println("Black Bart unloads his gun, once in your back")
fmt.println("and twice in your ass. Now you can't even rest in peace.")
case 4 :
fmt.println("Black Bart unloads his gun, once in your back")
fmt.println("and three times in your ass. Now you can't even rest in peace.")
}
opponent_bullets = 0
}
break showdown
case :
fmt.println("You sure aren't going to live very long if you can't even follow directions.")
} // strategy switch
if the_opponent_kills_or_runs(strategy) do break
if player_bullets + opponent_bullets == 0 {
fmt.println("The showdown must end, because nobody has bullets left.")
break
}
fmt.println()
} // showdown loop
}
// Main {{{1
// =============================================================
main :: proc() {
basic.randomize()
term.clear_screen()
print_credits()
press_enter("\nPress the Enter key to read the instructions. ")
term.clear_screen()
print_instructions()
press_enter("\nPress the Enter key to start. ")
term.clear_screen()
play()
}
En Pike
#!/usr/bin/env pike
// High Noon
// Original version in BASIC:
// Designed and programmed by Chris Gaylo, Syosset High School, New York, 1970-09-12.
// http://mybitbox.com/highnoon-1970/
// http://mybitbox.com/highnoon/
// Transcriptions:
// https://github.com/MrMethor/Highnoon-BASIC/
// https://github.com/mad4j/basic-highnoon/
// Version modified for QB64:
// By Daniele Olmisani, 2014.
// https://github.com/mad4j/basic-highnoon/
// This improved remake in Pike:
// Copyright (c) 2025, Marcos Cruz (programandala.net)
// SPDX-License-Identifier: Fair
//
// Written on 2025-03-10.
//
// Last modified: 20250323T2314+0100.
// Terminal {{{1
// =============================================================================
constant BLACK = 0;
constant RED = 1;
constant GREEN = 2;
constant YELLOW = 3;
constant BLUE = 4;
constant MAGENTA = 5;
constant CYAN = 6;
constant WHITE = 7;
constant DEFAULT = 9;
constant STYLE_OFF = 20;
constant FOREGROUND = 30;
constant BACKGROUND = 40;
constant BRIGHT = 60;
constant NORMAL_STYLE = 0;
void move_cursor_home() {
write("\x1B[H");
}
void hide_cursor() {
write("\x1B[?25l");
}
void show_cursor() {
write("\x1B[?25h");
}
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();
}
// Global variables and constants {{{1
// =============================================================
constant DEFAULT_INK = FOREGROUND + WHITE;
constant INPUT_INK = FOREGROUND + BRIGHT + GREEN;
constant INSTRUCTIONS_INK = FOREGROUND + YELLOW;
constant TITLE_INK = FOREGROUND + BRIGHT + RED;
constant INITIAL_DISTANCE = 100;
constant INITIAL_BULLETS = 4;
constant MAX_WATERING_TROUGHS = 3;
int distance = 0; // distance between both gunners, in paces
int player_bullets = 0;
int opponent_bullets = 0;
// User input {{{1
// =============================================================================
string accept_string(string prompt) {
write(prompt);
return Stdio.stdin->gets();
}
// Print the given prompt and wait until the user enters a string.
//
string get_string(string prompt) {
set_style(INPUT_INK);
string s = accept_string(prompt);
set_style(DEFAULT_INK);
return s;
}
int accept_integer(string prompt) {
// NB The casting accepts any valid integer at the start of the string
// and ignores the rest; if no valid integer is found at the start of
// the string, zero is returned.
return (int) accept_string(prompt);
}
// Print the given prompt and wait until the user enters an integer.
//
int get_integer(string prompt) {
set_style(INPUT_INK);
int n = accept_integer(prompt);
set_style(DEFAULT_INK);
return n;
}
// 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 = get_string(prompt);
if (is_yes(answer)) {
return true;
}
if (is_no(answer)) {
return false;
}
}
}
// Title, instructions and credits {{{1
// =============================================================
void print_title() {
set_style(TITLE_INK);
write("High Noon\n");
set_style(DEFAULT_INK);
}
void print_credits() {
print_title();
write("\nOriginal version in BASIC:\n");
write(" Designed and programmend by Chris Gaylo, 1970.\n");
write(" http://mybitbox.com/highnoon-1970/\n");
write(" http://mybitbox.com/highnoon/\n");
write("Transcriptions:\n");
write(" https://github.com/MrMethor/Highnoon-BASIC/\n");
write(" https://github.com/mad4j/basic-highnoon/\n");
write("Version modified for QB64:\n");
write(" By Daniele Olmisani, 2014.\n");
write(" https://github.com/mad4j/basic-highnoon/\n");
write("This improved remake in Pike:\n");
write(" Copyright (c) 2025, Marcos Cruz (programandala.net)\n");
write(" SPDX-License-Identifier: Fair\n");
}
void print_instructions() {
print_title();
set_style(INSTRUCTIONS_INK);
write("\nYou have been challenged to a showdown by Black Bart, one of\n");
write("the meanest desperadoes west of the Allegheny mountains.\n");
write("\nWhile you are walking down a dusty, deserted side street,\n");
write("Black Bart emerges from a saloon one hundred paces away.\n");
write("\nBy agreement, you each have %d bullets in your six-guns.", INITIAL_BULLETS);
write("\nYour marksmanship equals his. At the start of the walk nei-\n");
write("ther of you can possibly hit the other, and at the end of\n");
write("the walk, neither can miss. the closer you get, the better\n");
write("your chances of hitting black Bart, but he also has beter\n");
write("chances of hitting you.\n");
set_style(DEFAULT_INK);
}
// Game loop {{{1
// =============================================================
string plural_suffix(int n) {
switch (n) {
case 1: return "";
default: return "s";
}
}
void print_shells_left() {
if (player_bullets == opponent_bullets) {
write("Both of you have %d bullets.\n", player_bullets);
} else {
write(
"You now have %d bullet%s to Black Bart's %d bullet%s.\n",
player_bullets,
plural_suffix(player_bullets),
opponent_bullets,
plural_suffix(opponent_bullets));
}
}
void print_check() {
write("******************************************************\n");
write("* *\n");
write("* BANK OF DODGE CITY *\n");
write("* CASHIER'S RECEIT *\n");
write("* *\n");
write("* CHECK NO. %04d AUGUST %dTH, 1889 *\n",
random(1000),
10 + random(10));
write("* *\n");
write("* *\n");
write("* PAY TO THE BEARER ON DEMAND THE SUM OF *\n");
write("* *\n");
write("* TWENTY THOUSAND DOLLARS-------------------$20,000 *\n");
write("* *\n");
write("******************************************************\n");
}
void get_reward() {
write("As mayor of Dodge City, and on behalf of its citizens,\n");
write("I extend to you our thanks, and present you with this\n");
write("reward, a check for $20,000, for killing Black Bart.\n\n\n");
print_check();
write("\n\nDon't spend it all in one place.\n");
}
void move_the_opponent() {
int paces = 2 + random(8);
write("Black Bart moves %d paces.\n", paces);
distance -= paces;
}
// Maybe move the opponent; if so, return `true`, otherwise return `false`. A
// true `silent` flag allows to omit the message when the opponent doesn't
// move.
//
bool maybe_move_the_opponent(bool silent) {
if (random(2) == 0) { // 50% chances
move_the_opponent();
return true;
} else {
if (!silent) {
write("Black Bart stands still.\n");
}
return false;
}
}
bool missed_shot() {
return random(1.0) * 10.0 <= (distance / 10);
}
// Handle the opponent's shot and return a flag with the result: if the
// opponent kills the player, return `true`; otherwise return `false`.
//
bool the_opponent_fires_and_kills(string player_strategy) {
write("Black Bart fires…\n");
opponent_bullets -= 1;
if (missed_shot()) {
write("A miss…\n");
switch (opponent_bullets) {
case 3:
write("Whew, were you lucky. That bullet just missed your head.\n");
break;
case 2:
write("But Black Bart got you in the right shin.\n");
break;
case 1:
write("Though Black Bart got you on the left side of your jaw.\n");
break;
case 0:
write("Black Bart must have jerked the trigger.\n");
}
} else {
if (player_strategy == "j") {
write("That trick just saved yout life. Black Bart's bullet\n");
write("was stopped by the wood sides of the trough.\n");
} else {
write("Black Bart shot you right through the heart that time.\n");
write("You went kickin' with your boots on.\n");
return true;
}
}
return false;
}
// Handle the opponent's strategy and return a flag with the result: if the
// opponent runs or kills the player, return `true`; otherwise return `false`.
//
bool the_opponent_kills_or_runs(string player_strategy) {
if (distance >= 10 || player_bullets == 0) {
if (maybe_move_the_opponent(true)) {
return false;
}
}
if (opponent_bullets > 0) {
return the_opponent_fires_and_kills(player_strategy);
} else {
if (player_bullets > 0) {
if (random(2) == 0) { // 50% chances
write("Now is your chance, Black Bart is out of bullets.\n");
} else {
write("Black Bart just hi-tailed it out of town rather than face you\n");
write("without a loaded gun. You can rest assured that Black Bart\n");
write("won't ever show his face around this town again.\n");
return true;
}
}
}
return false;
}
void play() {
distance = INITIAL_DISTANCE;
int watering_troughs = 0;
player_bullets = INITIAL_BULLETS;
opponent_bullets = INITIAL_BULLETS;
showdown: while (true) {
write("You are now %d paces apart from Black Bart.\n", distance);
print_shells_left();
set_style(INSTRUCTIONS_INK);
write("\nStrategies:\n");
write(" [A]dvance\n");
write(" [S]tand still\n");
write(" [F]ire\n");
write(" [J]ump behind the watering trough\n");
write(" [G]ive up\n");
write(" [T]urn tail and run\n");
set_style(DEFAULT_INK);
string player_strategy = lower_case(get_string("What is your strategy? "));
switch (player_strategy) {
case "a": // advance
while (true) {
int paces = get_integer("How many paces do you advance? ");
if (paces < 0) {
write("None of this negative stuff, partner, only positive numbers.\n");
} else if (paces > 10) {
write("Nobody can walk that fast.\n");
} else {
distance -= paces;
break;
}
}
break;
case "s": // stand still
write("That move made you a perfect stationary target.\n");
break;
case "f": // fire
if (player_bullets == 0) {
write("You don't have any bullets left.\n");
} else {
player_bullets -= 1;
if (missed_shot()) {
switch (player_bullets) {
case 2:
write("Grazed Black Bart in the right arm.\n");
break;
case 1:
write("He's hit in the left shoulder, forcing him to use his right\n");
write("hand to shoot with.\n");
}
write("What a lousy shot.\n");
if (player_bullets == 0) {
write("Nice going, ace, you've run out of bullets.\n");
if (opponent_bullets != 0) {
write("Now Black Bart won't shoot until you touch noses.\n");
write("You better think of something fast (like run).\n");
}
}
} else {
write("What a shot, you got Black Bart right between the eyes.\n");
accept_string("\nPress the Enter key to get your reward. ");
clear_screen();
get_reward();
break showdown;
}
}
break;
case "j": // jump
if (watering_troughs == MAX_WATERING_TROUGHS) {
write("How many watering troughs do you think are on this street?\n");
player_strategy = "";
} else {
watering_troughs += 1;
write("You jump behind the watering trough.\n");
write("Not a bad maneuver to threw Black Bart's strategy off.\n");
}
break;
case "g": // give up
write("Black Bart accepts. The conditions are that he won't shoot you\n");
write("if you take the first stage out of town and never come back.\n");
if (yes("Agreed? ")) {
write("A very wise decision.\n");
break showdown;
} else {
write("Oh well, back to the showdown.\n");
}
break;
case "t": // turn tail and run
// The more bullets of the opponent, the less chances to escape.
if (random((opponent_bullets + 2)) == 0) {
write("Man, you ran so fast even dogs couldn't catch you.\n");
} else {
switch (opponent_bullets) {
case 0:
write("You were lucky, Black Bart can only throw his gun at you, he\n");
write("doesn't have any bullets left. You should really be dead.\n");
break;
case 1:
write("Black Bart fires his last bullet…\n");
write("He got you right in the back. That's what you deserve, for running.\n");
break;
case 2:
write("Black Bart fires and got you twice: in your back\n");
write("and your ass. Now you can't even rest in peace.\n");
break;
case 3:
write("Black Bart unloads his gun, once in your back\n");
write("and twice in your ass. Now you can't even rest in peace.\n");
break;
case 4:
write("Black Bart unloads his gun, once in your back\n");
write("and three times in your ass. Now you can't even rest in peace.\n");
}
opponent_bullets = 0;
}
break showdown;
default:
write("You sure aren't going to live very long if you can't even follow directions.\n");
} // strategy switch
if (the_opponent_kills_or_runs(player_strategy)) {
break;
}
if (player_bullets + opponent_bullets == 0) {
write("The showdown must end, because nobody has bullets left.\n");
break;
}
write("\n");
} // showdown loop
}
// Main {{{1
// =============================================================
void main() {
clear_screen();
print_credits();
accept_string("\nPress the Enter key to read the instructions. ");
clear_screen();
print_instructions();
accept_string("\nPress the Enter key to start. ");
clear_screen();
play();
}
En Raku
# High Noon
#
# Original version in BASIC:
# Designed and programmed by Chris Gaylo, Syosset High School, New York, 1970-09-12.
# http://mybitbox.com/highnoon-1970/
# http://mybitbox.com/highnoon/
#
# Transcriptions:
# https://github.com/MrMethor/Highnoon-BASIC/
# https://github.com/mad4j/basic-highnoon/
#
# Version modified for QB64:
# By Daniele Olmisani, 2014.
# https://github.com/mad4j/basic-highnoon/
#
# This improved remake in Raku:
# Copyright (c) 2025, Marcos Cruz (programandala.net)
# SPDX-License-Identifier: Fair
#
# Written in 2025-01-23/24.
#
# Last modified: 20250731T1726+0200.
# Terminal {{{1
# ==============================================================
constant $BLACK = 0;
constant $RED = 1;
constant $GREEN = 2;
constant $YELLOW = 3;
constant $BLUE = 4;
constant $MAGENTA = 5;
constant $CYAN = 6;
constant $WHITE = 7;
constant $DEFAULT = 9;
constant $STYLE_OFF = +20;
constant $FOREGROUND = +30;
constant $BACKGROUND = +40;
constant $BRIGHT = +60;
constant $NORMAL = 0;
constant $RESET_ALL = $NORMAL;
constant $BOLD = 1;
constant $DIM = 2;
constant $ITALIC = 3;
constant $UNDERLINE = 4;
constant $UNDERSCORE = $UNDERLINE;
constant $BLINK = 5;
constant $OVERLINE = 6;
constant $RAPID_BLINK = $OVERLINE;
constant $INVERT = 7;
constant $REVERSE = $INVERT;
constant $HIDDEN = 8;
constant $CROSSED_OUT = 9;
constant $STRIKE = $CROSSED_OUT;
constant $NO_STYLE = $STYLE_OFF;
# Move the cursor to the home position.
sub move_cursor_home {
print "\e[H";
}
# Erase the screen.
sub erase_screen {
print "\e[2J";
}
# Reset the attributes.
sub reset_attributes {
set_color $RESET_ALL;
}
# Erase the screen, reset the attributes and move the cursor to the home position.
sub clear_screen {
erase_screen;
reset_attributes;
move_cursor_home;
}
# Set the color.
sub set_color(Int $color) {
print "\e[{$color}m";
}
# Set the attribute.
sub set_attribute(Int $attr) {
print "\e[0;{$attr}m";
}
# Make the cursor invisible.
sub hide_cursor {
print "\e[?25l";
}
# Make the cursor visible.
sub show_cursor {
print "\e[?25h";
}
# Global variables and constants {{{1
# =============================================================
constant DEFAULT_INK = $FOREGROUND + $WHITE;
constant INPUT_INK = $FOREGROUND + $BRIGHT + $GREEN;
constant INSTRUCTIONS_INK = $FOREGROUND + $YELLOW;
constant TITLE_INK = $FOREGROUND + $BRIGHT + $RED;
constant INITIAL_DISTANCE = 100;
constant INITIAL_BULLETS = 4;
constant MAX_WATERING_TROUGHS = 3;
my $distance = 0; # distance between both gunners, in paces
my $strategy = ''; # player's strategy
my $player_bullets = 0;
my $opponent_bullets = 0;
# User input {{{1
# =============================================================
# Print the given prompt and wait until the user enters an integer.
#
sub input_int(Str $prompt = '' --> Int) {
my Int $n;
set_color INPUT_INK;
loop {
try {
$n = +prompt $prompt;
CATCH {
default {
put 'Integer expected.';
next;
}
}
}
last;
}
set_color DEFAULT_INK;
return floor $n;
}
# Print the given prompt and wait until the user enters a string.
#
sub input_string(Str $prompt = '' --> Str) {
set_color INPUT_INK;
my $result = prompt $prompt;
set_color DEFAULT_INK;
return $result;
}
# Print the given prompt and wait until the user presses Enter.
#
sub press_enter(Str $prompt) {
input_string($prompt);
}
# Return `True` if the given string is 'yes' or a synonym.
#
sub is_yes(Str $s --> Bool) {
return $s.lc (elem) ["ok", "y", "yeah", "yes"]
}
# Return `True` if the given string is 'no' or a synonym.
#
sub is_no(Str $s --> Bool) {
return $s.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 = input_string prompt;
if is_yes $answer { return True; }
if is_no $answer { return False; }
}
}
# Title, instructions and credits {{{1
# =============================================================
# Print the title at the current cursor position.
#
sub print_title {
set_color TITLE_INK;
put 'High Noon';
set_color DEFAULT_INK;
}
sub print_credits {
print_title;
put "\nOriginal version in BASIC:";
put ' Designed and programmend by Chris Gaylo, 1970.';
put ' http://mybitbox.com/highnoon-1970/';
put ' http://mybitbox.com/highnoon/';
put 'Transcriptions:';
put ' https://github.com/MrMethor/Highnoon-BASIC/';
put ' https://github.com/mad4j/basic-highnoon/';
put 'Version modified for QB64:';
put ' By Daniele Olmisani, 2014.';
put ' https://github.com/mad4j/basic-highnoon/';
put 'This improved remake in Raku:';
put ' Copyright (c) 2025, Marcos Cruz (programandala.net)';
put ' SPDX-License-Identifier: Fair';
}
sub print_instructions {
print_title;
set_color INSTRUCTIONS_INK;
put "\nYou have been challenged to a showdown by Black Bart, one of";
put 'the meanest desperadoes west of the Allegheny mountains.';
put "\nWhile you are walking down a dusty, deserted side street,";
put 'Black Bart emerges from a saloon one hundred paces away.';
printf "\nBy agreement, you each have %i bullets in your six-guns.", INITIAL_BULLETS;
put "\nYour marksmanship equals his. At the start of the walk nei-";
put 'ther of you can possibly hit the other, and at the end of';
put 'the walk, neither can miss. the closer you get, the better';
put 'your chances of hitting black Bart, but he also has beter';
put 'chances of hitting you.';
set_color DEFAULT_INK;
}
# Game loop {{{1
# =============================================================
sub plural_suffix(Int $n --> Str) {
given $n {
when 1 { return ''; }
default { return 's'; }
}
}
sub print_shells_left {
if $player_bullets == $opponent_bullets {
printf("Both of you have %i bullets.\n", $player_bullets);
} else {
printf(
"You now have %i bullet%s to Black Bart's %i bullet%s.\n",
$player_bullets,
plural_suffix($player_bullets),
$opponent_bullets,
plural_suffix($opponent_bullets));
}
}
sub print_check {
put '******************************************************';
put '* *';
put '* BANK OF DODGE CITY *';
put "* CASHIER'S RECEIT *";
put '* *';
printf("* CHECK NO. %04i AUGUST %iTH, 1889 *\n",
(0 .. 1000).pick,
10 + (0 .. 10).pick);
put '* *';
put '* *';
put '* PAY TO THE BEARER ON DEMAND THE SUM OF *';
put '* *';
put '* TWENTY THOUSAND DOLLARS-------------------$20,000 *';
put '* *';
put '******************************************************';
}
sub get_reward {
put 'As mayor of Dodge City, and on behalf of its citizens,';
put 'I extend to you our thanks, and present you with this';
put "reward, a check for $20,000, for killing Black Bart.\n\n";
print_check;
put "\n\nDon't spend it all in one place.";
}
sub move_the_opponent {
my $paces = 2 + (0 .. 8).pick;
printf("Black Bart moves %s paces.\n", $paces);
$distance -= $paces;
}
# Maybe move the opponent; if so, return `True`, otherwise return `False`. A
# true `silent` flag allows to omit the message when the opponent doesn't
# move.
#
sub maybe_move_the_opponent(Int $silent = False --> Bool) {
if (0 .. 2).pick == 0 {; # 50% chances
move_the_opponent;
return True;
} else {
if not $silent {
put 'Black Bart stands still.';
}
return False;
}
}
sub missed_shot(--> Bool) {
return 1.rand * 10 <= $distance / 10;
}
# Handle the opponent's shot and return a flag with the result: if the
# opponent kills the player, return `True`; otherwise return `False`.
#
sub the_opponent_fires_and_kills(--> Bool) {
put 'Black Bart fires…';
$opponent_bullets -= 1;
if missed_shot() {
put 'A miss…';
given $opponent_bullets {
}
when 3 {
put 'Whew, were you lucky. That bullet just missed your head.';
}
when 2 {
put 'But Black Bart got you in the right shin.';
}
when 1 {
put 'Though Black Bart got you on the left side of your jaw.';
}
when 0 {
put 'Black Bart must have jerked the trigger.';
}
} else {
if $strategy == 'j' {
put "That trick just saved yout life. Black Bart's bullet";
put 'was stopped by the wood sides of the trough.';
} else {
put 'Black Bart shot you right through the heart that time.';
put "You went kickin' with your boots on.";
return True;
}
}
return False;
}
# Handle the opponent's strategy and return a flag with the result: if the
# opponent runs or kills the player, return `True`; otherwise return `False`.
#
sub the_opponent_kills_or_runs(--> Bool) {
if $distance >= 10 or $player_bullets == 0 {
if maybe_move_the_opponent(True) { return False; }
}
if $opponent_bullets > 0 {
return the_opponent_fires_and_kills;
} else {
if $player_bullets > 0 {
if (0 .. 2).pick == 0 {; # 50% chances
put 'Now is your chance, Black Bart is out of bullets.';
} else {
put 'Black Bart just hi-tailed it out of town rather than face you';
put 'without a loaded gun. You can rest assured that Black Bart';
put "won't ever show his face around this town again.";
return True;
}
}
}
return False;
}
sub play {
$distance = INITIAL_DISTANCE;
my $watering_troughs = 0;
$player_bullets = INITIAL_BULLETS;
$opponent_bullets = INITIAL_BULLETS;
SHOWDOWN:
loop {
printf("You are now %i paces apart from Black Bart.\n", $distance);
print_shells_left;
set_color INSTRUCTIONS_INK;
put "\nStrategies:";
put ' [A]dvance';
put ' [S]tand still';
put ' [F]ire';
put ' [J]ump behind the watering trough';
put ' [G]ive up';
put ' [T]urn tail and run';
set_color DEFAULT_INK;
$strategy = input_string('What is your strategy? ').lc;
given $strategy {
when 'a' { # advance
loop {
my $paces = input_int('How many paces do you advance? ');
if $paces < 0 {
put 'None of this negative stuff, partner, only positive numbers.';
} elsif $paces > 10 {
put 'Nobody can walk that fast.';
} else {
$distance -= $paces;
last;
}
}
}
when 's' { # stand still
put 'That move made you a perfect stationary target.';
}
when 'f' { # fire
if $player_bullets == 0 {
put "You don't have any bullets left.";
} else {
$player_bullets -= 1;
if missed_shot() {
given $player_bullets {
}
when 2 {
put 'Grazed Black Bart in the right arm.';
}
when 1 {
put "He's hit in the left shoulder, forcing him to use his right";
put 'hand to shoot with.';
}
put 'What a lousy shot.';
if $player_bullets == 0 {
put "Nice going, ace, you've run out of bullets.";
if $opponent_bullets != 0 {
put "Now Black Bart won't shoot until you touch noses.";
put 'You better think of something fast (like run).';
}
}
} else {
put 'What a shot, you got Black Bart right between the eyes.';
press_enter("\nPress the Enter key to get your reward. ");
clear_screen;
get_reward;
last SHOWDOWN;
}
}
}
when 'j' { # jump
if $watering_troughs == MAX_WATERING_TROUGHS {
put 'How many watering troughs do you think are on this street?';
$strategy = '';
} else {
$watering_troughs += 1;
put 'You jump behind the watering trough.';
put "Not a bad maneuver to threw Black Bart's strategy off.";
}
}
when 'g' { # give up
put "Black Bart accepts. The conditions are that he won't shoot you";
put 'if you take the first stage out of town and never come back.';
if yes('Agreed? ') {
put 'A very wise decision.';
last SHOWDOWN;
} else {
put 'Oh well, back to the showdown.';
}
}
when 't' { # turn tail and run
# The more bullets of the opponent, the less chances to escape.
if (0 .. $opponent_bullets + 2).pick == 0 {
put "Man, you ran so fast even dogs couldn't catch you.";
} else {
given $opponent_bullets {
when 0 {
put 'You were lucky, Black Bart can only throw his gun at you, he';
put "doesn't have any bullets left. You should really be dead.";
}
when 1 {
put 'Black Bart fires his last bullet…';
put "He got you right in the back. That's what you deserve, for running.";
}
when 2 {
put 'Black Bart fires and got you twice: in your back';
put "and your ass. Now you can't even rest in peace.";
}
when 3 {
put 'Black Bart unloads his gun, once in your back';
put "and twice in your ass. Now you can't even rest in peace.";
}
when 4 {
put 'Black Bart unloads his gun, once in your back';
put "and three times in your ass. Now you can't even rest in peace.";
}
}
$opponent_bullets = 0;
}
last SHOWDOWN;
}
default {
put "You sure aren't going to live very long if you can't even follow directions.";
}
} # strategy given
if the_opponent_kills_or_runs() { last; }
if $player_bullets + $opponent_bullets == 0 {
put 'The showdown must end, because nobody has bullets left.';
last;
}
put '';
} # showdown loop
}
# Main {{{1
# =============================================================
clear_screen;
print_credits;
press_enter "\nPress the Enter key to read the instructions. ";
clear_screen;
print_instructions;
press_enter "\nPress the Enter key to start. ";
clear_screen;
play;
En V
/*
High Noon
Original version in BASIC:
Designed and programmed by Chris Gaylo, Syosset High School, New York, 1970-09-12.
http://mybitbox.com/highnoon-1970/
http://mybitbox.com/highnoon/
Transcriptions:
https://github.com/MrMethor/Highnoon-BASIC/
https://github.com/mad4j/basic-highnoon/
Version modified for QB64:
By Daniele Olmisani, 2014.
https://github.com/mad4j/basic-highnoon/
This improved remake in V:
Copyright (c) 2025, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written in 2025-01-05/07.
Last modified: 20250714T1332+0200.
*/
import os
import rand
import strconv
import term
// Constants {{{1
// =============================================================
const default_ink = term.white
const input_ink = term.bright_green
const instructions_ink = term.yellow
const title_ink = term.bright_red
const initial_distance = 100
const initial_bullets = 4
const max_watering_troughs = 3
// User input {{{1
// =============================================================
// Print the given prompt and wait until the user enters a string.
//
fn input_string(prompt string) string {
return os.input(term.colorize(input_ink, prompt))
}
// Print the given prompt and wait until the user enters an integer.
//
fn input_int(prompt string) int {
mut n := 0
for {
n = strconv.atoi(input_string(prompt)) or { continue }
break
}
return n
}
// Print the given prompt and wait until the user presses Enter.
//
fn press_enter(prompt string) {
input_string(prompt)
}
// 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 := input_string(prompt)
if is_yes(answer) {
result = true
break
}
if is_no(answer) {
result = false
break
}
}
return result
}
// Title, instructions and credits {{{1
// =============================================================
// Print the title at the current cursor position.
//
fn print_title() {
println(term.colorize(title_ink, 'High Noon'))
}
fn print_credits() {
print_title()
println('\nOriginal version in BASIC:')
println(' Designed and programmend by Chris Gaylo, 1970.')
println(' http://mybitbox.com/highnoon-1970/')
println(' http://mybitbox.com/highnoon/')
println('Transcriptions:')
println(' https://github.com/MrMethor/Highnoon-BASIC/')
println(' https://github.com/mad4j/basic-highnoon/')
println('Version modified for QB64:')
println(' By Daniele Olmisani, 2014.')
println(' https://github.com/mad4j/basic-highnoon/')
println('This improved remake in V:')
println(' Copyright (c) 2025, Marcos Cruz (programandala.net)')
println(' SPDX-License-Identifier: Fair')
}
fn print_instructions() {
print_title()
instructions := '\nYou have been challenged to a showdown by Black Bart, one of\n' +
'the meanest desperadoes west of the Allegheny mountains.\n' +
'\nWhile you are walking down a dusty, deserted side street,\n' +
'Black Bart emerges from a saloon one hundred paces away.\n' +
'\nBy agreement, you each have ${initial_bullets} bullets in your six-guns.\n' +
'\nYour marksmanship equals his. At the start of the walk nei-\n' +
'ther of you can possibly hit the other, and at the end of\n' +
'the walk, neither can miss. the closer you get, the better\n' +
'your chances of hitting black Bart, but he also has beter\n' + 'chances of hitting you.\n'
println(term.colorize(instructions_ink, instructions))
}
// Game {{{1
// =============================================================
struct Showdown {
mut:
player_bullets int
opponent_bullets int
distance int // distance between both gunners, in paces
strategy string
}
fn plural_suffix(n int) string {
return if n == 1 { '' } else { 's' }
}
fn print_shells_left(showdown Showdown) {
if showdown.player_bullets == showdown.opponent_bullets {
println('Both of you have ${showdown.player_bullets} bullets.')
} else {
print("You now have ${showdown.player_bullets} bullet${plural_suffix(showdown.player_bullets)} to Black Bart's ${showdown.opponent_bullets} bullet${plural_suffix(showdown.opponent_bullets)}.\n")
}
}
fn print_check() {
check := rand.intn(1000) or { 0 }
day := 10 + rand.intn(10) or { 0 }
println('******************************************************')
println('* *')
println('* BANK OF DODGE CITY *')
println("* CASHIER'S RECEIT *")
println('* *')
println('* CHECK NO. ${check:04} AUGUST ${day}TH, 1889 *')
println('* *')
println('* *')
println('* PAY TO THE BEARER ON DEMAND THE SUM OF *')
println('* *')
println('* TWENTY THOUSAND DOLLARS-------------------$20,000 *')
println('* *')
println('******************************************************')
}
fn get_reward() {
println('As mayor of Dodge City, and on behalf of its citizens,')
println('I extend to you our thanks, and present you with this')
println('reward, a check for $20,000, for killing Black Bart.\n\n')
print_check()
println("\n\nDon't spend it all in one place.")
}
fn move_the_opponent(mut showdown Showdown) {
paces := 2 + rand.intn(8) or { 0 }
println('Black Bart moves ${paces} paces.')
showdown.distance -= paces
}
// Maybe move the opponent; if so, return `true`, otherwise return `false`. A
// true `silent` flag allows to omit the message when the opponent doesn't
// move.
//
fn the_opponent_moves(silent bool, mut showdown Showdown) bool {
if rand.intn(2) or { 0 } == 0 { // 50% chances
move_the_opponent(mut showdown)
return true
} else {
if !silent {
println('Black Bart stands still.')
}
return false
}
}
fn missed_shot(showdown Showdown) bool {
return rand.f64() * 10 <= f64(showdown.distance / 10)
}
// Handle the opponent's shot and return a flag with the result: if the
// opponent kills the player, return `true`; otherwise return `false`.
//
fn the_opponent_fires_and_kills(mut showdown Showdown) bool {
println('Black Bart fires…')
showdown.opponent_bullets -= 1
if missed_shot(showdown) {
println('A miss…')
match showdown.opponent_bullets {
3 {
println('Whew, were you lucky. That bullet just missed your head.')
}
2 {
println('But Black Bart got you in the right shin.')
}
1 {
println('Though Black Bart got you on the left side of your jaw.')
}
0 {
println('Black Bart must have jerked the trigger.')
}
else {}
}
} else {
if showdown.strategy == 'j' {
println("That trick just saved yout life. Black Bart's bullet")
println('was stopped by the wood sides of the trough.')
} else {
println('Black Bart shot you right through the heart that time.')
println("You went kickin' with your boots on.")
return true
}
}
return false
}
// Handle the opponent's strategy and return a flag with the result: if the
// opponent runs or kills the player, return `true`; otherwise return `false`.
//
fn the_opponent_kills_or_runs(mut showdown Showdown) bool {
if showdown.distance >= 10 || showdown.player_bullets == 0 {
if the_opponent_moves(true, mut showdown) {
return false
}
}
if showdown.opponent_bullets > 0 {
return the_opponent_fires_and_kills(mut showdown)
} else {
if showdown.player_bullets > 0 {
if rand.intn(2) or { 0 } == 0 { // 50% chances
println('Now is your chance, Black Bart is out of bullets.')
} else {
println('Black Bart just hi-tailed it out of town rather than face you')
println('without a loaded gun. You can rest assured that Black Bart')
println("won't ever show his face around this town again.")
return true
}
}
}
return false
}
fn play() {
mut showdown := Showdown{
distance: initial_distance
player_bullets: initial_bullets
opponent_bullets: initial_bullets
}
mut watering_troughs := 0
showdown: for {
println('You are now ${showdown.distance} paces apart from Black Bart.')
print_shells_left(showdown)
println(term.colorize(instructions_ink, '\nStrategies:'))
menu := ['[A]dvance', '[S]tand still', '[F]ire', '[J]ump behind the watering trough',
'[G]ive up', '[T]urn tail and run']
for item in menu {
println(term.colorize(instructions_ink, ' ' + item))
}
showdown.strategy = input_string('What is your strategy? ').to_lower()
match showdown.strategy {
'a' { // advance
for {
paces := input_int('How many paces do you advance? ')
if paces < 0 {
println('None of this negative stuff, partner, only positive numbers.')
} else if paces > 10 {
println('Nobody can walk that fast.')
} else {
showdown.distance -= paces
break
}
}
}
's' { // stand still
println('That move made you a perfect stationary target.')
}
'f' { // fire
if showdown.player_bullets == 0 {
println("You don't have any bullets left.")
} else {
showdown.player_bullets -= 1
if missed_shot(showdown) {
match showdown.player_bullets {
2 {
println('Grazed Black Bart in the right arm.')
}
1 {
println("He's hit in the left shoulder, forcing him to use his right")
println('hand to shoot with.')
}
else {}
}
println('What a lousy shot.')
if showdown.player_bullets == 0 {
println("Nice going, ace, you've run out of bullets.")
if showdown.opponent_bullets != 0 {
println("Now Black Bart won't shoot until you touch noses.")
println('You better think of something fast (like run).')
}
}
} else {
println('What a shot, you got Black Bart right between the eyes.')
press_enter('\nPress the Enter key to get your reward. ')
term.clear()
get_reward()
break showdown
}
}
}
'j' { // jump
if watering_troughs == max_watering_troughs {
println('How many watering troughs do you think are on this street?')
showdown.strategy = ''
} else {
watering_troughs += 1
println('You jump behind the watering trough.')
println("Not a bad maneuver to threw Black Bart's strategy off.")
}
}
'g' { // give up
println("Black Bart accepts. The conditions are that he won't shoot you")
println('if you take the first stage out of town and never come back.')
if yes('Agreed? ') {
println('A very wise decision.')
break showdown
} else {
println('Oh well, back to the showdown.')
}
}
't' { // turn tail and run
// The more bullets of the opponent, the less chances to escape.
if rand.intn(showdown.opponent_bullets + 2) or { 0 } == 0 {
println("Man, you ran so fast even dogs couldn't catch you.")
} else {
match showdown.opponent_bullets {
0 {
println('You were lucky, Black Bart can only throw his gun at you, he')
println("doesn't have any bullets left. You should really be dead.")
}
1 {
println('Black Bart fires his last bullet…')
println("He got you right in the back. That's what you deserve, for running.")
}
2 {
println('Black Bart fires and got you twice: in your back')
println("and your ass. Now you can't even rest in peace.")
}
3 {
println('Black Bart unloads his gun, once in your back')
println("and twice in your ass. Now you can't even rest in peace.")
}
4 {
println('Black Bart unloads his gun, once in your back')
println("and three times in your ass. Now you can't even rest in peace.")
}
else {}
}
showdown.opponent_bullets = 0
}
break showdown
}
else {
println("You sure aren't going to live very long if you can't even follow directions.")
}
} // strategy switch
if the_opponent_kills_or_runs(mut showdown) {
break
}
if showdown.player_bullets + showdown.opponent_bullets == 0 {
println('The showdown must end, because nobody has bullets left.')
break
}
println('')
} // showdown loop
}
// Main {{{1
// =============================================================
fn main() {
term.clear()
print_credits()
press_enter('\nPress the Enter key to read the instructions. ')
term.clear()
print_instructions()
press_enter('\nPress the Enter key to start. ')
term.clear()
play()
}
