Mugwump
Description of the page content
Conversion of Mugwump to several programming languages.
This program has been converted to 17 programming languages.
Original
Origin of mugwump.bas:
Mugwump (by Bud Valenti's students, Bob Albrecht), 1978.
Creative Computing's BASIC Games.
- https://www.atariarchives.org/basicgames/showpage.php?page=114
- http://vintage-basic.net/games.html
- http://vintage-basic.net/bcg/mugwump.bas
1 PRINT TAB(33);"MUGWUMP"
2 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"
3 PRINT:PRINT:PRINT
4 REM COURTESY PEOPLE'S COMPUTER COMPANY
10 DIM P(4,2)
20 PRINT "THE OBJECT OF THIS GAME IS TO FIND FOUR MUGWUMPS"
30 PRINT "HIDDEN ON A 10 BY 10 GRID. HOMEBASE IS POSITION 0,0."
40 PRINT "ANY GUESS YOU MAKE MUST BE TWO NUMBERS WITH EACH"
50 PRINT "NUMBER BETWEEN 0 AND 9, INCLUSIVE. FIRST NUMBER"
60 PRINT "IS DISTANCE TO RIGHT OF HOMEBASE AND SECOND NUMBER"
70 PRINT "IS DISTANCE ABOVE HOMEBASE."
80 PRINT
90 PRINT "YOU GET 10 TRIES. AFTER EACH TRY, I WILL TELL"
100 PRINT "YOU HOW FAR YOU ARE FROM EACH MUGWUMP."
110 PRINT
240 GOSUB 1000
250 T=0
260 T=T+1
270 PRINT
275 PRINT
290 PRINT "TURN NO.";T;"-- WHAT IS YOUR GUESS";
300 INPUT M,N
310 FOR I=1 TO 4
320 IF P(I,1)=-1 THEN 400
330 IF P(I,1)<>M THEN 380
340 IF P(I,2)<>N THEN 380
350 P(I,1)=-1
360 PRINT "YOU HAVE FOUND MUGWUMP";I
370 GOTO 400
380 D=SQR((P(I,1)-M)^2+(P(I,2)-N)^2)
390 PRINT "YOU ARE";(INT(D*10))/10;"UNITS FROM MUGWUMP";I
400 NEXT I
410 FOR J=1 TO 4
420 IF P(J,1)<>-1 THEN 470
430 NEXT J
440 PRINT
450 PRINT "YOU GOT THEM ALL IN";T;"TURNS!"
460 GOTO 580
470 IF T<10 THEN 260
480 PRINT
490 PRINT "SORRY, THAT'S 10 TRIES. HERE IS WHERE THEY'RE HIDING:"
540 FOR I=1 TO 4
550 IF P(I,1)=-1 THEN 570
560 PRINT "MUGWUMP";I;"IS AT (";P(I,1);",";P(I,2);")"
570 NEXT I
580 PRINT
600 PRINT "THAT WAS FUN! LET'S PLAY AGAIN......."
610 PRINT "FOUR MORE MUGWUMPS ARE NOW IN HIDING."
630 GOTO 240
1000 FOR J=1 TO 2
1010 FOR I=1 TO 4
1020 P(I,J)=INT(10*RND(1))
1030 NEXT I
1040 NEXT J
1050 RETURN
1099 END
In Arturo
; Mugwump
; Original version in BASIC:
; Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA), 1978.
; Slightly modified by Bob Albrecht of People's Computer Company.
; Creative Computing's BASIC Games.
; - https://www.atariarchives.org/basicgames/showpage.php?page=114
; - http://vintage-basic.net/games.html
; This version in Arturo:
; Copyright (c) 2023, Marcos Cruz (programandala.net)
; SPDX-License-Identifier: Fair
;
; Written in 2023-10-19/21
;
; Last modified: 20251205T0047+0100.
; Constants
let 'gridSize 10
let 'firstCoord 0
let 'lastCoord sub gridSize 1
let 'maxTurns 10
let 'mugwumps 4
let 'firstMugwump 0
let 'lastMugwump sub mugwumps 1
; Arrays
let 'mugwumpX array .of: mugwumps 0
let 'mugwumpY array .of: mugwumps 0
let 'mugwumpHidden array .of: mugwumps false
; Variables
let 'found 0 ; counter
; Print the given prompt, wait until the user enters a valid integer
; and return it.
getNumber: function [prompt] [
until [
try? [ let 'number to :integer input prompt ]
] []
number
]
; Return `true` if the given string is "yes" or a synonym.
isYes: function [answer] [
contains? ["ok", "yeah", "yes", "y"] answer
]
; Return `true` if the given string is "no" or a synonym.
isNo: function [answer] [
contains? ["no", "nope", "n"] answer
]
; Print the given prompt, wait until the user enters a valid yes/no
; string, and return `true` for "yes" or `false` for "no".
yes: function [prompt] [
until
[ let 'answer input prompt ]
[ or?
isYes answer
isNo answer
]
isYes answer
]
; Clear the screen, print the credits and ask the user to press enter.
printCredits: function [] [
clear
print "Mugwump\n"
print "Original version in BASIC:"
print " Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA)."
print " Slightly modified by Bob Albrecht of People's Computer Company."
print " Published by Creative Computing (Morristown, New Jersey, USA), 1978."
print " - https://www.atariarchives.org/basicgames/showpage.php?page=114"
print " - http://vintage-basic.net/games.html\n"
print "This version in Arturo:"
print " Copyright (c) 2023, Marcos Cruz (programandala.net)"
print " SPDX-License-Identifier: Fair\n"
input "Press Enter to read the instructions. "
]
; Clear the screen, print the instructions and ask the user to press enter.
printInstructions: function [] [
clear
print "Mugwump\n"
print render "The object of this game is to find |mugwumps| mugwumps"
print render "hidden on a |gridSize| by |gridSize| grid. Homebase is position |firstCoord|,|firstCoord|."
print "Any guess you make must be two numbers with each"
print render "number between |firstCoord| and |lastCoord|, inclusive. First number"
print "is distance to right of homebase and second number"
print "is distance above homebase.\n"
print render "You get |maxTurns| tries. After each try, you will see"
print "how far you are from each mugwump.\n"
input "Press Enter to start. "
]
; Init the mugwumps' positions, `hidden` flags and count.
hideMugwumps: function [] [
loop range firstMugwump lastMugwump 'm [
mugwumpX\[m]: random firstCoord lastCoord
mugwumpY\[m]: random firstCoord lastCoord
mugwumpHidden\[m]: true
]
let 'found 0 ; counter
]
; Print the given prompt, wait until the user enters a valid coord
; and return it.
getCoord: function [prompt] [
while [ true ] [
let 'coord getNumber prompt
if contains? range firstCoord lastCoord coord [ return coord ]
print render "Invalid value |coord|: not in range [|firstCoord|, |lastCoord|]."
]
]
; Return `true` if the given mugwump is hidden in the given coords.
isThere?: function [m x y] [
and?
mugwumpHidden\[m]
and?
equal? mugwumpX\[m] x
equal? mugwumpY\[m] y
]
; Return the distance between the given mugwump and the given coords.
distance: function [m x y] [
to
:integer
round
sqrt
add
pow sub mugwumpX\[m] x 2
pow sub mugwumpY\[m] y 2
]
; Return the given plural or singular ending depending of the given number.
plural: function [n pluralSuffix singularSuffix] [
if? greater? n 1 [ pluralSuffix ] else [ singularSuffix ]
]
; Run the game.
play: function [] [
until [ ; game loop
clear
hideMugwumps
loop range 1 maxTurns 'turn [ ; turns loop
print render "Turn number |turn|\n"
print render "What is your guess (in range [|firstCoord|, |lastCoord|])?"
let 'x getCoord "Distance right of homebase (x-axis): "
let 'y getCoord "Distance above homebase (y-axis): "
print render "\nYour guess is (|x|, |y|)."
loop range firstMugwump lastMugwump 'm [
if isThere? m x y [
mugwumpHidden\[m]: false
inc 'found
print render "You have found mugwump |add m 1|!"
if equal? found mugwumps [ break ]
]
]
if equal? found mugwumps [ break ] ; exit the turns loop
loop range firstMugwump lastMugwump 'm [
if mugwumpHidden\[m] [
print render "You are |distance m y y| units from mugwump |add m 1|."
]
]
print ""
] ; turns loop
if? equal? found mugwumps [
print render "\nYou got them all in |turn| turn|plural turn {s} {}|!\n"
print "That was fun! let's play again…"
print render "|mugwumps| more mugwumps are now in hiding."
] else [
print render "\nSorry, that's |maxTurns| tr|plural maxTurns {ies} {y}|.\n"
print "Here is where they're hiding:"
loop range firstMugwump lastMugwump 'm [
if mugwumpHidden\[m] [
print render "Mugwump |add m 1| is at (|mugwumpX\[m]|, |mugwumpY\[m]|)."
]
]
]
print ""
] [ not? yes "Do you want to play again? " ] ; game loop
]
printCredits
printInstructions
play
In C#
// Mugwump
// Original version in BASIC:
// Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
// Slightly modified by Bob Albrecht of People's Computer Company.
// Published by Creative Computing (Morristown, New Jersey, USA), 1978.
// - https://www.atariarchives.org/basicgames/showpage.php?page=114
// - http://vintage-basic.net/games.html
// - http://vintage-basic.net/bcg/mugwump.bas
// This version in C#:
// Copyright (c) 2024, Marcos Cruz (programandala.net)
// SPDX-License-Identifier: Fair
//
// Written on 2024-12-25.
//
// Last modified: 20251205T1542+0100.
using System;
using System.Linq;
class MugwumpGame
{
const int GRID_SIZE = 10;
const int TURNS = 10;
const int MUGWUMPS = 4;
class Mugwump
{
internal int x = 0;
internal int y = 0;
internal bool hidden = false;
}
static Mugwump[] mugwump = new Mugwump[MUGWUMPS];
static int found; // counter
static string GetString(string prompt)
{
Console.Write(prompt);
return Console.ReadLine();
}
// Print the given prompt, wait until the user enters a valid integer and
// return it.
//
static int GetNumber(string prompt)
{
int n = 0;
while (true)
{
try
{
n = Int32.Parse(GetString(prompt));
break;
}
catch
{
}
}
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;
}
}
}
// Clear the screen, print the credits and ask the user to press enter.
//
static void PrintCredits()
{
Console.Clear();
Console.WriteLine("Mugwump\n");
Console.WriteLine("Original version in BASIC:");
Console.WriteLine(" Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).");
Console.WriteLine(" Slightly modified by Bob Albrecht of People's Computer Company.");
Console.WriteLine(" Published by Creative Computing (Morristown, New Jersey, USA), 1978.");
Console.WriteLine(" - https://www.atariarchives.org/basicgames/showpage.php?page=114");
Console.WriteLine(" - http://vintage-basic.net/games.html\n");
Console.WriteLine("This version in C#:");
Console.WriteLine(" Copyright (c) 2024, Marcos Cruz (programandala.net)");
Console.WriteLine(" SPDX-License-Identifier: Fair\n");
GetString("Press Enter to read the instructions. ");
}
// Clear the screen, print the instructions and ask the user to press enter.
//
static void PrintInstructions()
{
Console.Clear();
Console.WriteLine("Mugwump\n");
Console.WriteLine("The object of this game is to find four mugwumps");
Console.WriteLine("hidden on a 10 by 10 grid. Homebase is position 0,0.");
Console.WriteLine("Any guess you make must be two numbers with each");
Console.WriteLine("number between 0 and 9, inclusive. First number");
Console.WriteLine("is distance to right of homebase and second number");
Console.WriteLine("is distance above homebase.\n");
Console.WriteLine($"You get {TURNS} tries. After each try, you will see");
Console.WriteLine("how far you are from each mugwump.\n");
GetString("Press Enter to start. ");
}
static void InitMugwumps()
{
for (int m = 0; m < MUGWUMPS; m++)
{
mugwump[m] = new Mugwump();
}
}
// Init the mugwumps' positions, `hidden` flags and count.
//
static void HideMugwumps()
{
Random rand = new Random();
for (int m = 0; m < MUGWUMPS; m++)
{
mugwump[m].x = rand.Next(GRID_SIZE);
mugwump[m].y = rand.Next(GRID_SIZE);
mugwump[m].hidden = true;
}
found = 0; // counter
}
// Print the given prompt, wait until the user enters a valid coord and return
// it.
//
static int GetCoord(string prompt)
{
int coord = 0;
while (true)
{
coord = GetNumber(prompt);
if (coord < 0 || coord >= GRID_SIZE)
{
Console.WriteLine($"Invalid value {coord}: not in range [0, {GRID_SIZE - 1}].");
}
else
{
break;
}
}
return coord;
}
// Return `true` if the given mugwump is hidden in the given coords.
//
static bool IsHere(int m, int x, int y)
{
return mugwump[m].hidden && mugwump[m].x == x && mugwump[m].y == y;
}
// Return the distance between the given mugwump and the given coords.
//
static int Distance(int m, int x, int y)
{
return (int) Math.Sqrt
(
Math.Pow((double) (mugwump[m].x - x), 2) +
Math.Pow((double) (mugwump[m].y - y), 2)
);
}
static string Plural(int n, string plural = "s", string singular = "")
{
return n > 1 ? plural : singular;
}
// Run the game.
//
static void Play()
{
int turn = 1; // counter
InitMugwumps();
while (true) {; // game
Console.Clear();
HideMugwumps();
while (turn <= TURNS)
{
Console.WriteLine($"Turn number {turn}\n");
Console.WriteLine($"What is your guess (in range [0, {GRID_SIZE - 1}])?");
int x = GetCoord("Distance right of homebase (x-axis): ");
int y = GetCoord("Distance above homebase (y-axis): ");
Console.WriteLine($"\nYour guess is ({x}, {y}).");
for (int m = 0; m < MUGWUMPS; m++)
{
if (IsHere(m, x, y))
{
mugwump[m].hidden = false;
found++;
Console.WriteLine($"You have found mugwump {m}!");
if (found == MUGWUMPS)
{
goto endTurns;
}
}
}
for (int m = 0; m < MUGWUMPS; m++)
{
if (mugwump[m].hidden)
{
Console.WriteLine($"You are {Distance(m, x, y)} units from mugwump {m}.");
}
}
Console.WriteLine();
turn++;
}; // turns
endTurns:
if (found == MUGWUMPS)
{
Console.WriteLine($"\nYou got them all in {turn} turn{Plural(turn)}!\n");
Console.WriteLine("That was fun! let's play again…");
Console.WriteLine("Four more mugwumps are now in hiding.");
}
else
{
Console.WriteLine($"\nSorry, that's {TURNS} tr{Plural(TURNS, "ies", "y")}.\n");
Console.WriteLine("Here is where they're hiding:");
for (int m = 0; m < MUGWUMPS; m++)
{
if (mugwump[m].hidden)
{
Console.WriteLine($"Mugwump {m} is at ({mugwump[m].x}, {mugwump[m].y}).");
}
}
}
Console.WriteLine();
if (!Yes("Do you want to play again? "))
{
break;
}
}; // game
}
static void Main()
{
PrintCredits();
PrintInstructions();
Play();
}
}
In Chapel
// Mugwump
// Original version in BASIC:
// Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
// Slightly modified by Bob Albrecht of People's Computer Company.
// Published by Creative Computing (Morristown, New Jersey, USA), 1978.
// - https://www.atariarchives.org/basicgames/showpage.php?page=114
// - http://vintage-basic.net/games.html
// This version in Chapel:
// Copyright (c) 2025, Marcos Cruz (programandala.net)
// SPDX-License-Identifier: Fair
//
// Written on 2025-04-07.
//
// Last modified: 20250731T1954+0200.
// Modules {{{1
// =============================================================
import IO;
import Math;
import Random;
// Terminal {{{1
// =============================================================================
const NORMAL_STYLE = 0;
proc moveCursorHome() {
write("\x1B[H");
}
proc setStyle(style: int) {
writef("\x1B[%im", style);
}
proc resetAttributes() {
setStyle(NORMAL_STYLE);
}
proc eraseScreen() {
write("\x1B[2J");
}
proc clearScreen() {
eraseScreen();
resetAttributes();
moveCursorHome();
}
// Data {{{1
// =============================================================================
const GRID_SIZE = 10;
const TURNS = 10;
const MUGWUMPS = 4;
record Mugwump {
var x: int;
var y: int;
var hidden: bool;
}
var mugwump: [0 ..< MUGWUMPS] Mugwump;
var found: int = 0; // counter
// User input {{{1
// =============================================================================
proc acceptString(prompt: string): string {
write(prompt);
IO.stdout.flush();
return IO.readLine().strip();
}
proc acceptValidInteger(prompt: string): int {
var result: int;
while true {
var s: string = acceptString(prompt);
try {
result = (s): int;
break;
}
catch exc {
writeln("Integer expected.");
}
}
return result;
}
proc isYes(s: string): bool {
select s.toLower() {
when "ok", "y", "yeah", "yes" do return true;
otherwise do return false;
}
}
proc isNo(s: string): bool {
select s.toLower() {
when "n", "no", "nope" do return true;
otherwise do return false;
}
}
// Print the given prompt, wait until the user enters a valid yes/no string;
// and return `true` for "yes" or `false` for "no".
//
proc yes(prompt: string): bool {
var result: bool;
while true {
var answer: string = acceptString(prompt);
if isYes(answer) {
result = true;
break;
}
if isNo(answer) {
result = false;
break;
}
}
return result;
}
// Credits and instructions {{{1
// =============================================================================
// Clear the screen, print the credits and ask the user to press enter.
//
proc printCredits() {
clearScreen();
writeln("Mugwump\n");
writeln("Original version in BASIC:");
writeln(" Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).");
writeln(" Slightly modified by Bob Albrecht of People's Computer Company.");
writeln(" Published by Creative Computing (Morristown, New Jersey, USA), 1978.");
writeln(" - https://www.atariarchives.org/basicgames/showpage.php?page=114");
writeln(" - http://vintage-basic.net/games.html\n");
writeln("This version in Chapel:");
writeln(" Copyright (c) 2025, Marcos Cruz (programandala.net)");
writeln(" SPDX-License-Identifier: Fair\n");
acceptString("Press Enter to read the instructions. ");
}
// Clear the screen, print the instructions and ask the user to press enter.
//
proc printInstructions() {
clearScreen();
writeln("Mugwump\n");
writeln("The object of this game is to find four mugwumps");
writeln("hidden on a 10 by 10 grid. Homebase is position 0,0.");
writeln("Any guess you make must be two numbers with each");
writeln("number between 0 and 9, inclusive. First number");
writeln("is distance to right of homebase and second number");
writeln("is distance above homebase.\n");
writef("You get %i tries. After each try, you will see\n", TURNS);
writeln("how far you are from each mugwump.\n");
acceptString("Press Enter to start. ");
}
// Game {{{1
// =============================================================================
proc hideMugwumps() {
var rsInt = new Random.randomStream(int);
for m in 0 ..< MUGWUMPS {
mugwump[m].x = rsInt.next(0, GRID_SIZE - 1);
mugwump[m].y = rsInt.next(0, GRID_SIZE - 1);
mugwump[m].hidden = true;
}
found = 0; // counter
}
// Print the given prompt, wait until the user enters a valid coord and return
// it.
//
proc getCoord(prompt: string): int {
var coord: int = 0;
while true {
coord = acceptValidInteger(prompt);
if coord < 0 || coord >= GRID_SIZE {
writef("Invalid value %i: not in range [0, %i].\n", coord, GRID_SIZE - 1);
} else {
break;
}
}
return coord;
}
// Return `true` if the given mugwump is hidden in the given coords.
//
proc isHere(m: int, x: int, y: int): bool {
return mugwump[m].hidden && mugwump[m].x == x && mugwump[m].y == y;
}
// Return the distance between the given mugwump and the given coords.
//
proc distance(m: int, x: int, y: int): int {
return sqrt(
(mugwump[m].x - x) ** 2.0 +
(mugwump[m].y - y) ** 2.0): int;
}
// Return a plural suffix (default: "s") if the given number is greater than 1
// otherwise return a singular suffix (default: an empty string).
//
proc plural(n: int, pluralSuffix: string = "s", singularSuffix: string = ""): string {
return if n > 1 then pluralSuffix else singularSuffix;
}
// Run the game.
//
proc play() {
var x: int = 0;
var y: int = 0;
while true { // game
clearScreen();
hideMugwumps();
var turn: int = 1;
label turnsLoop while turn <= TURNS {
writef("Turn number %i\n\n", turn);
writef("What is your guess (in range [0, %i])?\n", GRID_SIZE - 1);
x = getCoord("Distance right of homebase (x-axis): ");
y = getCoord("Distance above homebase (y-axis): ");
writef("\nYour guess is (%i, %i).\n", x, y);
for m in 0 ..< MUGWUMPS {
if isHere(m, x, y) {
mugwump[m].hidden = false;
found += 1;
writef("You have found mugwump %i!\n", m);
if found == MUGWUMPS {
break turnsLoop;
}
}
}
for m in 0 ..< MUGWUMPS {
if mugwump[m].hidden {
writef("You are %i units from mugwump %i.\n", distance(m, x, y) , m);
}
}
writeln("");
turn += 1;
} // turns
if found == MUGWUMPS {
writef("\nYou got them all in %i turn%s!\n\n", turn, plural(turn));
writeln("That was fun! let's play again…");
writeln("Four more mugwumps are now in hiding.");
} else {
writef("\nSorry, that's %i tr%s.\n\n", TURNS, plural(TURNS, "ies", "y"));
writeln("Here is where they're hiding:");
for m in 0 ..< MUGWUMPS {
if mugwump[m].hidden {
writef("Mugwump %i is at (%i, %i).\n", m, mugwump[m].x, mugwump[m].y);
}
}
}
if !yes("\nDo you want to play again? ") {
break;
}
} // game
}
// Main {{{1
// =============================================================================
proc initData() {
// Build the `mugwump` array.
for i in 0 ..< MUGWUMPS {
mugwump[i] = new Mugwump();
}
}
proc main() {
printCredits();
printInstructions();
initData();
play();
}
In Crystal
# Mugwump
# Original version in BASIC:
# Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
# Slightly modified by Bob Albrecht of People's Computer Company.
# Published by Creative Computing (Morristown, New Jersey, USA), 1978.
# - https://www.atariarchives.org/basicgames/showpage.php?page=114
# - http://vintage-basic.net/games.html
# This version in Crystal:
# Copyright (c) 2023, Marcos Cruz (programandala.net)
# SPDX-License-Identifier: Fair
#
# Written in 2023-09, 2023-10, 2023-11.
#
# Last modified: 20231104T0057+0100.
GRID_SIZE = 10
TURNS = 10
MUGWUMPS = 4
class Mugwump
property hidden : Bool
property x : Int32
property y : Int32
def initialize
@hidden = true
@x = rand(GRID_SIZE)
@y = rand(GRID_SIZE)
end
def init
initialize
end
def reveal
@hidden = false
end
end
# Moves the cursor to the top left position of the terminal.
def home
print "\e[H"
end
# Clears the terminal and moves the cursor to the top left position.
def clear
print "\e[2J"
home
end
# Prints the given prompt, waits until the user enters a valid integer and
# returns it.
def get_number(prompt : String) : Int
while true
print prompt
begin
n = gets.not_nil!.to_i
break
rescue
puts "Invalid number."
end
end
n
end
# Prompts the user to enter a command and returns it.
def command(prompt = "> ") : String
s = nil
while s.is_a?(Nil)
print prompt
s = gets
end
s
end
# Prints the given prompt and waits until the user enters an empty string.
def press_enter(prompt : String)
until command(prompt) == ""
end
end
# Returns `true` if the given string is "yes" or a synonym.
def is_yes?(answer : String) : Bool
["ok", "yeah", "yes", "y"].any? { |yes| answer.downcase == yes }
end
# Returns `true` if the given string is "no" or a synonym.
def is_no?(answer : String) : Bool
["no", "nope", "n"].any? { |no| answer.downcase == no }
end
# Prints the given prompt, waits until the user enters a valid yes/no
# string, and returns `true` for "yes" or `false` for "no".
def yes?(prompt : String) : Bool
answer = ""
while !(is_yes?(answer) || is_no?(answer))
answer = command(prompt)
end
is_yes?(answer)
end
# Clears the screen, prints the credits and asks the user to press enter.
def print_credits
clear
puts "Mugwump\n"
puts "Original version in BASIC:"
puts " Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA)."
puts " Slightly modified by Bob Albrecht of People's Computer Company."
puts " Published by Creative Computing (Morristown, New Jersey, USA), 1978."
puts " - https://www.atariarchives.org/basicgames/showpage.php?page=114"
puts " - http://vintage-basic.net/games.html\n"
puts "This version in Crystal:"
puts " Copyright (c) 2023, Marcos Cruz (programandala.net)"
puts " SPDX-License-Identifier: Fair\n"
press_enter("Press Enter to read the instructions. ")
end
# Clears the screen, prints the instructions and asks the user to press enter.
def print_instructions
clear
puts "Mugwump\n"
puts "The object of this game is to find four mugwumps"
puts "hidden on a 10 by 10 grid. Homebase is position 0,0."
puts "Any guess you make must be two numbers with each"
puts "number between 0 and 9, inclusive. First number"
puts "is distance to right of homebase and second number"
puts "is distance above homebase.\n"
puts "You get #{TURNS} tries. After each try, you will see"
puts "how far you are from each mugwump.\n"
press_enter("Press Enter to start. ")
end
# Prints the given prompt, then waits until the user enters a valid coord and
# returns it.
def get_coord(prompt : String) : Int
while true
coord = get_number(prompt)
if coord < 0 || coord >= GRID_SIZE
puts "Invalid value #{coord}: not in range [0, #{GRID_SIZE - 1}]."
else
break
end
end
coord
end
# Returns `true` if the given mugwump is hidden in the given coords.
def is_here?(m : Mugwump, x : Int, y : Int) : Bool
m.hidden && m.x == x && m.y == y
end
# Returns the distance between the given mugwump and the given coords.
def distance(m : Mugwump, x : Int, y : Int) : Int
Math.sqrt((m.x - x) ** 2 + (m.y - y) ** 2).to_i
end
# If the given number is greater than 1, this method returns a plural ending
# (default: "s"); otherwise it returns a singular ending (default: an empty
# string).
def plural(n : Int, plural = "s", singular = "") : String
n > 1 ? plural : singular
end
# Prints the mugwumps found in the given coordinates and returns the count.
def found(mugwump : Array(Mugwump), x, y) : Int
found = 0
(0...MUGWUMPS).each do |m|
if is_here?(mugwump[m], x, y)
mugwump[m].reveal
found += 1
puts "You have found mugwump #{m}!"
end
end
found
end
# Runs the game.
def play
found : Int32 # counter
turn : Int32 # counter
mugwump = [] of Mugwump
(0...MUGWUMPS).each do |m|
mugwump << Mugwump.new
end
while true # game
clear
(0...MUGWUMPS).each do |m|
mugwump[m].init
end
found = 0
turn = 1
while turn < TURNS
puts "Turn number #{turn}\n"
puts "What is your guess (in range [0, #{GRID_SIZE - 1}])?"
x = get_coord("Distance right of homebase (x-axis): ")
y = get_coord("Distance above homebase (y-axis): ")
puts "\nYour guess is (#{x}, #{y})."
found += found(mugwump, x, y)
if found == MUGWUMPS
break # turns
else
(0...MUGWUMPS).each do |m|
if mugwump[m].hidden
puts "You are #{distance(mugwump[m], x, y)} units from mugwump #{m}."
end
end
puts
end
turn += 1
end # turns
if found == MUGWUMPS
puts "\nYou got them all in #{turn} turn#{plural(turn)}!\n"
puts "That was fun! let's play again…"
puts "Four more mugwumps are now in hiding."
else
puts "\nSorry, that's #{TURNS} tr#{plural(TURNS, "ies", "y")}.\n"
puts "Here is where they're hiding:"
(0...MUGWUMPS).each do |m|
if mugwump[m].hidden
puts "Mugwump #{m} is at (#{mugwump[m].x}, #{mugwump[m].y})."
end
end
end
puts
if !yes?("Do you want to play again? ")
break # game
end
end # game
end
print_credits
print_instructions
play
In D
// Mugwump
// Original version in BASIC:
// Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
// Slightly modified by Bob Albrecht of People's Computer Company.
// Published by Creative Computing (Morristown, New Jersey, USA), 1978.
// - https://www.atariarchives.org/basicgames/showpage.php?page=114
// - http://vintage-basic.net/games.html
// This version in D:
// Copyright (c) 2025, Marcos Cruz (programandala.net)
// SPDX-License-Identifier: Fair
//
// Written on 2025-03-24.
//
// Last modified: 20251220T0620+0100.
module mugwump;
// Terminal {{{1
// =============================================================================
enum NORMAL_STYLE = 0;
void moveCursorHome()
{
import std.stdio : write;
write("\x1B[H");
}
void setStyle(int style)
{
import std.stdio : writef;
writef("\x1B[%dm", style);
}
void resetAttributes()
{
setStyle(NORMAL_STYLE);
}
void eraseScreen()
{
import std.stdio : write;
write("\x1B[2J");
}
void clearScreen()
{
eraseScreen();
resetAttributes();
moveCursorHome();
}
// Data {{{1
// =============================================================================
enum GRID_SIZE = 10;
enum TURNS = 10;
enum MUGWUMPS = 4;
class Mugwump
{
int x;
int y;
bool hidden;
}
Mugwump[MUGWUMPS] mugwump;
int found = 0; // counter
// User input {{{1
// =============================================================================
string acceptString(string prompt)
{
import std.stdio : readln;
import std.stdio : write;
import std.string : strip;
write(prompt);
return strip(readln());
}
int acceptValidInteger(string prompt)
{
import std.conv : to;
import std.stdio : writeln;
int result;
while (true)
{
string s = acceptString(prompt);
try
{
result = to!int(s);
break;
}
catch (Exception exc)
{
writeln("Integer expected.");
}
}
return result;
}
bool isYes(string s)
{
import std.uni : toLower;
switch (toLower(s))
{
case "ok":
case "y":
case "yeah":
case "yes":
return true;
default:
return false;
}
}
bool isNo(string s)
{
import std.uni : toLower;
switch (toLower(s))
{
case "n":
case "no":
case "nope":
return true;
default:
return false;
}
}
/// Print the given prompt, wait until the user enters a valid yes/no string;
/// and return `true` for "yes" or `false` for "no".
bool yes(string prompt)
{
while (true)
{
string answer = acceptString(prompt);
if (isYes(answer))
{
return true;
}
if (isNo(answer))
{
return false;
}
}
}
// Credits and instructions {{{1
// =============================================================================
/// Clear the screen, print the credits and ask the user to press enter.
void printCredits()
{
import std.stdio : writeln;
clearScreen();
writeln("Mugwump\n");
writeln("Original version in BASIC:");
writeln(" Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).");
writeln(" Slightly modified by Bob Albrecht of People's Computer Company.");
writeln(" Published by Creative Computing (Morristown, New Jersey, USA), 1978.");
writeln(" - https://www.atariarchives.org/basicgames/showpage.php?page=114");
writeln(" - http://vintage-basic.net/games.html\n");
writeln("This version in D:");
writeln(" Copyright (c) 2025, Marcos Cruz (programandala.net)");
writeln(" SPDX-License-Identifier: Fair\n");
acceptString("Press Enter to read the instructions. ");
}
/// Clear the screen, print the instructions and ask the user to press enter.
void printInstructions()
{
import std.stdio : writefln;
import std.stdio : writeln;
clearScreen();
writeln("Mugwump\n");
writeln("The object of this game is to find four mugwumps");
writeln("hidden on a 10 by 10 grid. Homebase is position 0,0.");
writeln("Any guess you make must be two numbers with each");
writeln("number between 0 and 9, inclusive. First number");
writeln("is distance to right of homebase and second number");
writeln("is distance above homebase.\n");
writefln("You get %d tries. After each try, you will see", TURNS);
writeln("how far you are from each mugwump.\n");
acceptString("Press Enter to start. ");
}
// Game {{{1
// =============================================================================
void hideMugwumps()
{
import std.random : uniform;
foreach (int m; 0 .. MUGWUMPS)
{
mugwump[m].x = uniform(0, GRID_SIZE);
mugwump[m].y = uniform(0, GRID_SIZE);
mugwump[m].hidden = true;
}
found = 0; // counter
}
/// Print the given prompt, wait until the user enters a valid coord and return
/// it.
int getCoord(string prompt)
{
import std.stdio : writefln;
int coord = 0;
while (true)
{
coord = acceptValidInteger(prompt);
if (coord < 0 || coord >= GRID_SIZE)
{
writefln("Invalid value %d: not in range [0, %d].", coord, GRID_SIZE - 1);
}
else
{
break;
}
}
return coord;
}
// Return `true` if the given mugwump is hidden in the given coords.
bool isHere(int m, int x, int y)
{
return mugwump[m].hidden && mugwump[m].x == x && mugwump[m].y == y;
}
/// Return the distance between the given mugwump and the given coords.
int distance(int m, int x, int y)
{
import std.math : pow;
import std.math : sqrt;
return cast(int)sqrt(
pow((mugwump[m].x - x), 2.0) +
pow((mugwump[m].y - y), 2.0));
}
/// Return a plural suffix (default: "s") if the given number is greater than 1
/// otherwise return a singular suffix (default: an empty string).
string plural(int n, string pluralSuffix = "s", string singularSuffix = "")
{
return n > 1 ? pluralSuffix : singularSuffix;
}
/// Run the game.
void play()
{
import std.stdio : writefln;
import std.stdio : writeln;
int x = 0;
int y = 0;
int turn = 0; // counter
while (true) { // game
clearScreen();
hideMugwumps();
turnsLoop: for (turn = 1; turn <= TURNS; turn += 1)
{
writefln("Turn number %d\n", turn);
writefln("What is your guess (in range [0, %d])?", GRID_SIZE - 1);
x = getCoord("Distance right of homebase (x-axis): ");
y = getCoord("Distance above homebase (y-axis): ");
writefln("\nYour guess is (%d, %d).", x, y);
foreach (int m; 0 .. MUGWUMPS)
{
if (isHere(m, x, y))
{
mugwump[m].hidden = false;
found += 1;
writefln("You have found mugwump %d!", m);
if (found == MUGWUMPS)
{
break turnsLoop;
}
}
}
foreach (int m; 0 .. MUGWUMPS)
{
if (mugwump[m].hidden)
{
writefln("You are %d units from mugwump %d.", distance(m, x, y) , m);
}
}
writeln();
} // turns
if (found == MUGWUMPS)
{
writefln("\nYou got them all in %d turn%s!\n", turn, plural(turn));
writeln("That was fun! let's play again…");
writeln("Four more mugwumps are now in hiding.");
}
else
{
writefln("\nSorry, that's %d tr%s.\n", TURNS, plural(TURNS, "ies", "y"));
writeln("Here is where they're hiding:");
foreach (int m; 0 .. MUGWUMPS)
{
if (mugwump[m].hidden)
{
writefln("Mugwump %d is at (%d, %d).", m, mugwump[m].x, mugwump[m].y);
}
}
}
if (!yes("\nDo you want to play again? "))
{
break;
}
} // game
}
// Main {{{1
// =============================================================================
void init()
{
// Build the `mugwump` array.
foreach (int i; 0 .. MUGWUMPS)
{
mugwump[i] = new Mugwump();
}
}
void main()
{
printCredits();
printInstructions();
init();
play();
}
In Go
/*
Mugwump
Original version in BASIC:
Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
Slightly modified by Bob Albrecht of People's Computer Company.
Published by Creative Computing (Morristown, New Jersey, USA), 1978.
- https://www.atariarchives.org/basicgames/showpage.php?page=114
- http://vintage-basic.net/games.html
This version in Go:
Copyright (c) 2025, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written on 2025-01-08.
Last modified: 20250108T1558+0100.
*/
package main
import "fmt"
import "math"
import "math/rand"
import "strconv"
import "strings"
// 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 normalAttributes = 0
const foreground = +30
const background = +40
const bright = +60
func clearScreen() {
fmt.Print("\x1B[0;0H\x1B[2J")
}
func moveCursorHome() {
fmt.Print("\x1B[H")
}
func hideCursor() {
fmt.Print("\x1B[?25l")
}
func showCursor() {
fmt.Print("\x1B[?25h")
}
func setColor(color int) {
fmt.Printf("\x1B[%vm", color)
}
// Global variables and constants {{{1
// =============================================================
const defaultInk = foreground + whiteColor
const inputInk = foreground + bright + greenColor
const instructionsInk = foreground + yellowColor
const titleInk = foreground + bright + redColor
const gridSize int = 10
const turns int = 10
const mugwumps int = 4
type Mugwump struct {
x int
y int
hidden bool
}
var mugwump [mugwumps]Mugwump
var found int // counter
// User input {{{1
// =============================================================
// Print the given prompt and wait until the user enters a string.
func getString(prompt string) string {
setColor(inputInk)
defer setColor(defaultInk)
fmt.Print(prompt)
var s = ""
fmt.Scanf("%s", &s)
return s
}
// Print the given prompt and wait until the user enters an integer.
func getNumber(prompt string) int {
var number int64
var err error
setColor(inputInk)
defer setColor(defaultInk)
for {
number, err = strconv.ParseInt(getString(prompt), 10, 0)
if err == nil {
break
} else {
fmt.Println("Integer expected.")
}
}
return int(number)
}
// Print the given prompt and wait until the user presses Enter.
func pressEnter(prompt string) {
getString(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 = getString(prompt)
if isYes(answer) {
return true
}
if isNo(answer) {
return false
}
}
}
// Title, instructions and credits {{{1
// =============================================================
func printTitle() {
setColor(titleInk)
defer setColor(defaultInk)
fmt.Println("Mugwump\n")
}
// Clear the screen, print the credits and ask the user to press enter.
func printCredits() {
clearScreen()
printTitle()
setColor(instructionsInk)
defer setColor(defaultInk)
fmt.Println("Original version in BASIC:")
fmt.Println(" Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).")
fmt.Println(" Slightly modified by Bob Albrecht of People's Computer Company.")
fmt.Println(" Published by Creative Computing (Morristown, New Jersey, USA), 1978.")
fmt.Println(" - https://www.atariarchives.org/basicgames/showpage.php?page=114")
fmt.Println(" - http://vintage-basic.net/games.html\n")
fmt.Println("This version in Go:")
fmt.Println(" Copyright (c) 2025, Marcos Cruz (programandala.net)")
fmt.Println(" SPDX-License-Identifier: Fair\n")
pressEnter("Press Enter to read the instructions. ")
}
// Clear the screen, print the instructions and ask the user to press enter.
func printInstructions() {
clearScreen()
printTitle()
setColor(instructionsInk)
defer setColor(defaultInk)
fmt.Println("The object of this game is to find four mugwumps")
fmt.Println("hidden on a 10 by 10 grid. Homebase is position 0,0.")
fmt.Println("Any guess you make must be two numbers with each")
fmt.Println("number between 0 and 9, inclusive. First number")
fmt.Println("is distance to right of homebase and second number")
fmt.Println("is distance above homebase.\n")
fmt.Printf("You get %v tries. After each try, you will see\n", turns)
fmt.Println("how far you are from each mugwump.\n")
pressEnter("Press Enter to start. ")
}
// Stock functions {{{1
// =============================================================
// Return the given plural ending if the given number is greater than 1;
// otherwise return the given singular ending.
func plural_(n int, plural string, singular string) string {
if n > 1 {
return plural
} else {
return singular
}
}
// Return the plural "s" ending if the given number is greater than 1;
// otherwise return an empty string.
func plural(n int) string {
return plural_(n, "s", "")
}
// Game {{{1
// =============================================================
// Init the mugwumps' positions, `hidden` flags and count.
func hideMugwumps() {
for m := 0; m < mugwumps; m++ {
mugwump[m].x = rand.Intn(gridSize)
mugwump[m].y = rand.Intn(gridSize)
mugwump[m].hidden = true
}
found = 0 // counter
}
// Print the given prompt, wait until the user enters a valid coord and return
// it.
func getCoord(prompt string) (coord int) {
for {
coord = getNumber(prompt)
if coord < 0 || coord >= gridSize {
fmt.Printf("Invalid value %v: not in range [0, %v].\n", coord, gridSize-1)
} else {
break
}
}
return
}
// Return `true` if the given mugwump is hidden in the given coords.
func isHere(m int, x int, y int) bool {
return mugwump[m].hidden && mugwump[m].x == x && mugwump[m].y == y
}
// Return the distance between the given mugwump and the given coords.
func distance(m int, x int, y int) int {
return int(math.Sqrt(
math.Pow(float64(mugwump[m].x-x), 2) +
math.Pow(float64(mugwump[m].y-y), 2)))
}
// Run the game.
func play() {
var x int
var y int
var turn = 0 // counter
for {
clearScreen()
hideMugwumps()
turnsLoop:
for turn = 1; turn <= turns; turn += 1 {
fmt.Printf("Turn number %v\n\n", turn)
fmt.Printf("What is your guess (in range [0, %v])?\n", gridSize-1)
x = getCoord("Distance right of homebase (x-axis): ")
y = getCoord("Distance above homebase (y-axis): ")
fmt.Printf("\nYour guess is (%v, %v).\n", x, y)
for m := 0; m < mugwumps; m++ {
if isHere(m, x, y) {
mugwump[m].hidden = false
found += 1
fmt.Printf("You have found mugwump %v!\n", m)
if found == mugwumps {
break turnsLoop
}
}
}
for m := 0; m < mugwumps; m++ {
if mugwump[m].hidden {
fmt.Printf("You are %v units from mugwump %v.\n", distance(m, x, y), m)
}
}
fmt.Println()
} // turns
if found == mugwumps {
fmt.Printf("\nYou got them all in %v turn%s!\n\n", turn, plural(turn))
fmt.Println("That was fun! let's play again…")
fmt.Println("Four more mugwumps are now in hiding.")
} else {
fmt.Printf("\nSorry, that's %v tr%s.\n\n", turns, plural_(turns, "ies", "y"))
fmt.Println("Here is where they're hiding:")
for m := 0; m < mugwumps; m++ {
if mugwump[m].hidden {
fmt.Printf("Mugwump %v is at (%v, %v).\n", m, mugwump[m].x, mugwump[m].y)
}
}
}
fmt.Println()
if !yes("Do you want to play again? ") {
break
}
}
}
// Main {{{1
// =============================================================
func main() {
printCredits()
printInstructions()
play()
}
In Hare
// Mugwump
//
// Original version in BASIC:
// Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
// Slightly modified by Bob Albrecht of People's Computer Company.
// Published by Creative Computing (Morristown, New Jersey, USA), 1978.
// - https://www.atariarchives.org/basicgames/showpage.php?page=114
// - http://vintage-basic.net/games.html
//
// This version in Hare:
// Copyright (c) 2025, Marcos Cruz (programandala.net)
// SPDX-License-Identifier: Fair
//
// Written in 2025-02-14/15.
//
// Last modified: 20260213T1645+0100.
// Modules {{{1
// =============================================================================
use ascii;
use bufio;
use fmt;
use math;
use math::random;
use os;
use strconv;
use strings;
use time;
// Terminal {{{1
// =============================================================================
def NORMAL_STYLE = 0;
fn move_cursor_home() void = {
fmt::print("\x1B[H")!;
};
fn set_style(style: int) void = {
fmt::printf("\x1B[{}m", style)!;
};
fn reset_attributes() void = {
set_style(NORMAL_STYLE);
};
fn erase_screen() void = {
fmt::print("\x1B[2J")!;
};
fn clear_screen() void = {
erase_screen();
reset_attributes();
move_cursor_home();
};
// Data {{{1
// =============================================================================
def GRID_SIZE = 10;
def TURNS = 10;
def MUGWUMPS = 4;
type Mugwump = struct {
x: int,
y: int,
hidden: bool,
};
let mugwump: [MUGWUMPS]Mugwump = [Mugwump{x = 0, y = 0, hidden = false}...];
let found: int = 0; // counter
// User input {{{1
// =============================================================================
fn print_prompt(prompt: str = "") void = {
fmt::print(prompt)!;
bufio::flush(os::stdout)!;
};
fn accept_string(prompt: str = "") str = {
print_prompt(prompt);
const buffer = match (bufio::read_line(os::stdin)!) {
case let buffer: []u8 =>
yield buffer;
case =>
return "";
};
defer free(buffer);
return strings::dup(strings::fromutf8(buffer)!)!;
};
fn 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_valid_integer(prompt: str, error: str = "Integer expected.") int = {
let result: int = 0;
for (true) {
match (prompted_integer(prompt)) {
case let i: int =>
result = i;
break;
case =>
fmt::println(error)!;
};
};
return result;
};
// Return `true` if the given string is "yes" or a synonym.
//
fn is_yes(s: str) bool = {
const lowercase_s = ascii::strlower(s)!;
defer free(lowercase_s);
return switch(lowercase_s) {
case "ok", "y", "yeah", "yes" =>
yield true;
case =>
yield false;
};
};
// Return `true` if the given string is "no" or a synonym.
//
fn is_no(s: str) bool = {
const lowercase_s = ascii::strlower(s)!;
defer free(lowercase_s);
return switch(lowercase_s) {
case "n", "no", "nope" =>
yield true;
case =>
yield false;
};
};
// Print the given prompt, wait until the user enters a valid yes/no string,
// and return `true` for "yes" or `false` for "no".
//
fn yes(prompt: str) bool = {
for (true) {
let answer = accept_string(prompt);
defer free(answer);
if (is_yes(answer)) {
return true;
};
if (is_no(answer)) {
return false;
};
};
};
// Credits and instructions {{{1
// =============================================================================
// Clear the screen, print the credits and ask the user to press enter.
//
fn print_credits() void = {
clear_screen();
fmt::println("Mugwump\n")!;
fmt::println("Original version in BASIC:")!;
fmt::println(" Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).")!;
fmt::println(" Slightly modified by Bob Albrecht of People's Computer Company.")!;
fmt::println(" Published by Creative Computing (Morristown, New Jersey, USA), 1978.")!;
fmt::println(" - https://www.atariarchives.org/basicgames/showpage.php?page=114")!;
fmt::println(" - http://vintage-basic.net/games.html\n")!;
fmt::println("This version in Hare:")!;
fmt::println(" Copyright (c) 2025, Marcos Cruz (programandala.net)")!;
fmt::println(" SPDX-License-Identifier: Fair\n")!;
accept_string("Press Enter to read the instructions. ");
};
// Clear the screen, print the instructions and ask the user to press enter.
//
fn print_instructions() void = {
clear_screen();
fmt::println("Mugwump\n")!;
fmt::println("The object of this game is to find four mugwumps")!;
fmt::println("hidden on a 10 by 10 grid. Homebase is position 0,0.")!;
fmt::println("Any guess you make must be two numbers with each")!;
fmt::println("number between 0 and 9, inclusive. First number")!;
fmt::println("is distance to right of homebase and second number")!;
fmt::println("is distance above homebase.\n")!;
fmt::printfln("You get {} tries. After each try, you will see", TURNS)!;
fmt::println("how far you are from each mugwump.\n")!;
accept_string("Press Enter to start. ");
};
// Game {{{1
// =============================================================================
// Init the mugwumps' positions, `hidden` flags and count.
//
fn hide_mugwumps() void = {
for (let m = 0; m < MUGWUMPS; m += 1) {
mugwump[m].x = random::u64n(&rand, GRID_SIZE): int;
mugwump[m].y = random::u64n(&rand, GRID_SIZE): int;
mugwump[m].hidden = true;
};
found = 0; // counter
};
// Print the given prompt, wait until the user enters a valid coord and return
// it.
//
fn get_coord(prompt: str) int = {
let coord: int = 0;
for (true) {
coord = prompted_valid_integer(prompt);
if (coord < 0 || coord >= GRID_SIZE) {
fmt::printfln("Invalid value {}: not in range [0, {}].", coord, GRID_SIZE - 1)!;
} else {
break;
};
};
return coord;
};
// Return `true` if the given mugwump is hidden in the given coords.
//
fn is_here(m: int, x: int, y: int) bool = {
return mugwump[m].hidden && mugwump[m].x == x && mugwump[m].y == y;
};
// Return the distance between the given mugwump and the given coords.
//
fn distance(m: int, x: int, y: int) int = {
return math::sqrtf64(
math::powf64((mugwump[m].x - x): f64, 2.0) +
math::powf64((mugwump[m].y - y): f64, 2.0)): int;
};
// Return a plural suffix (default: "s") if the given number is greater than 1
// otherwise return a singular suffix (default: an empty string).
//
fn plural(n: int, plural_suffix: str = "s", singular_suffix: str = "") str = {
return if (n > 1) plural_suffix else singular_suffix;
};
// Run the game.
//
fn play() void = {
let x: int = 0;
let y: int = 0;
let turn: int = 0; // counter
for (true) { // game
clear_screen();
hide_mugwumps();
for :turns_loop (let turn = 1; turn <= TURNS; turn += 1) {
fmt::printfln("Turn number {}\n", turn)!;
fmt::printfln("What is your guess (in range [0, {}])?", GRID_SIZE - 1)!;
x = get_coord("Distance right of homebase (x-axis): ");
y = get_coord("Distance above homebase (y-axis): ");
fmt::printfln("\nYour guess is ({}, {}).", x, y)!;
for (let m = 0; m < MUGWUMPS; m += 1) {
if (is_here(m, x, y)) {
mugwump[m].hidden = false;
found += 1;
fmt::printfln("You have found mugwump {}!", m)!;
if (found == MUGWUMPS) {
break :turns_loop;
};
};
};
for (let m = 0; m < MUGWUMPS; m += 1) {
if (mugwump[m].hidden) {
fmt::printfln("You are {} units from mugwump {}.", distance(m, x, y) , m)!;
};
};
fmt::println()!;
}; // turns
if (found == MUGWUMPS) {
fmt::printfln("\nYou got them all in {} turn{}!\n", turn, plural(turn))!;
fmt::println("That was fun! let's play again…")!;
fmt::println("Four more mugwumps are now in hiding.")!;
} else {
fmt::printfln("\nSorry, that's {} tr{}.\n", TURNS, plural(TURNS, "ies", "y"))!;
fmt::println("Here is where they're hiding:")!;
for (let m = 0; m < MUGWUMPS; m += 1) {
if (mugwump[m].hidden) {
fmt::printfln("Mugwump {} is at ({}, {}).", m, mugwump[m].x, mugwump[m].y)!;
};
};
};
if (!yes("\nDo you want to play again? ")) {
break;
};
}; // game
};
// 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();
print_credits();
print_instructions();
play();
};
In Julia
# Mugwump
# Original version in BASIC:
# Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
# Slightly modified by Bob Albrecht of People's Computer Company.
# Published by Creative Computing (Morristown, New Jersey, USA), 1978.
# - https://www.atariarchives.org/basicgames/showpage.php?page=114
# - http://vintage-basic.net/games.html
# This version in Julia:
# Copyright (c) 2024, Marcos Cruz (programandala.net)
# SPDX-License-Identifier: Fair
#
# Written on 2024-07-02/03.
#
# Last modified: 20241030T0038+0100.
const GRID_SIZE = 10
const TURNS = 10
const MUGWUMPS = 4
mutable struct Mugwump
hidden::Bool
x::Int
y::Int
end
# Move the cursor to the top left position of the terminal.
function home()
print("\e[H")
end
# Clear the terminal and move the cursor to the top left position.
function clear()
print("\e[2J")
home()
end
# Print the given prompt, wait until the user enters a valid integer and return
# it.
function get_number(prompt::String)::Int
n = 0
while true
print(prompt)
n = tryparse(Int, readline())
if isnothing(n)
println("Invalid number.")
else
break
end
end
return n
end
# Prompt the user to enter a command and return it.
function command(prompt = "> ")::String
print(prompt)
return readline()
end
# Print the given prompt and wait until the user enters an empty string.
function press_enter(prompt::String)
while command(prompt) != ""
end
end
# Return `true` if the given string is "yes" or a synonym; otherwise return
# `false`.
function is_yes(answer::String)::Bool
return lowercase(answer) in ["ok", "yeah", "yes", "y"]
end
# Return `true` if the given string is "no" or a synonym; otherwise return
# `false`.
function is_no(answer::String)::Bool
return lowercase(answer) in ["no", "nope", "n"]
end
# Print the given prompt, wait until the user enters a valid yes/no string, and
# return `true` for "yes" or `false` for "no".
function yes(prompt::String)::Bool
answer = ""
while ! (is_yes(answer) || is_no(answer))
answer = command(prompt)
end
return is_yes(answer)
end
# Clear the screen, print the credits and ask the user to press enter.
function print_credits()
clear()
println("Mugwump\n")
println("Original version in BASIC:")
println(" Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).")
println(" Slightly modified by Bob Albrecht of People's Computer Company.")
println(" Published by Creative Computing (Morristown, New Jersey, USA), 1978.")
println(" - https://www.atariarchives.org/basicgames/showpage.php?page=114")
println(" - http://vintage-basic.net/games.html\n")
println("This version in Julia:")
println(" Copyright (c) 2024, Marcos Cruz (programandala.net)")
println(" SPDX-License-Identifier: Fair\n")
press_enter("Press Enter to read the instructions. ")
end
# Clear the screen, print the instructions and ask the user to press enter.
function print_instructions()
clear()
println("Mugwump\n")
println("The object of this game is to find four mugwumps")
println("hidden on a 10 by 10 grid. Homebase is position 0,0.")
println("Any guess you make must be two numbers with each")
println("number between 0 and 9, inclusive. First number")
println("is distance to right of homebase and second number")
println("is distance above homebase.\n")
println("You get $TURNS tries. After each try, you will see")
println("how far you are from each mugwump.\n")
press_enter("Press Enter to start. ")
end
# Print the given prompt, then waits until the user enters a valid coord and
# returns it.
function get_coord(prompt::String)::Int
coord = 0
while true
coord = get_number(prompt)
if coord < 0 || coord >= GRID_SIZE
println("Invalid value $coord: not in range [0, $(GRID_SIZE - 1)].")
else
break
end
end
return coord
end
# Return `true` if the given mugwump is hidden in the given coords.
function is_here(m::Mugwump, x::Int, y::Int)::Bool
return m.hidden && m.x == x && m.y == y
end
# Return the distance between the given mugwump and the given coords.
function distance(m::Mugwump, x::Int, y::Int)::Int
return round(sqrt((m.x - x) ^ 2 + (m.y - y) ^ 2))
end
# If the given number is greater than 1, return the given plural ending
# (default: "s"); otherwise return the given singular ending (default: an empty
# string).
function plural(n::Int, plural = "s", singular = "")::String
return n > 1 ? plural : singular
end
# Print the mugwumps found in the given coordinates and return the count.
function mugwumps_found(mugwump::Array{Mugwump}, x, y)::Int
found = 0
for m in 1 : MUGWUMPS
if is_here(mugwump[m], x, y)
mugwump[m].hidden = false
found += 1
println("You have found mugwump $(m)!")
end
end
return found
end
# Run the game.
function play()
found = 0 # counter
turn = 0 # counter
mugwump = Array{Mugwump, 1}(undef, MUGWUMPS)
while true # game
clear()
for m in 1 : MUGWUMPS
mugwump[m] = Mugwump(
true,
rand(0 : GRID_SIZE - 1),
rand(0 : GRID_SIZE - 1)
)
end
found = 0
turn = 1
while turn < TURNS
println("Turn number $turn\n")
println("What is your guess (in range [0, $(GRID_SIZE - 1)])?")
x = get_coord("Distance right of homebase (x-axis): ")
y = get_coord("Distance above homebase (y-axis): ")
println("\nYour guess is ($x, $y).")
found += mugwumps_found(mugwump, x, y)
if found == MUGWUMPS
break # turns
else
for m in 1 : MUGWUMPS
if mugwump[m].hidden
println("You are $(distance(mugwump[m], x, y)) units from mugwump $m.")
end
end
println()
end
turn += 1
end # turns
if found == MUGWUMPS
println("\nYou got them all in $turn turn$(plural(turn))!\n")
println("That was fun! let's play again…")
println("Four more mugwumps are now in hiding.")
else
println("\nSorry, that's $TURNS tr$(plural(TURNS, "ies", "y")).\n")
println("Here is where they're hiding:")
for m in 1 : MUGWUMPS
if mugwump[m].hidden
println("Mugwump $m is at ($(mugwump[m].x), $(mugwump[m].y)).")
end
end
end
println()
if ! yes("Do you want to play again? ")
break # game
end
end # game
end
print_credits()
print_instructions()
play()
In Kotlin
/*
Mugwump
Original version in BASIC:
Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
Slightly modified by Bob Albrecht of People's Computer Company.
Published by Creative Computing (Morristown, New Jersey, USA), 1978.
- https://www.atariarchives.org/basicgames/showpage.php?page=114
- http://vintage-basic.net/games.html
This version in Kotlin:
Copyright (c) 2023, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written in 2023-10.
Last modified: 20250518T2359+0200.
*/
import kotlin.math.pow
import kotlin.math.sqrt
const val GRID_SIZE = 10
const val TURNS = 10
const val MUGWUMPS = 4
class Mugwump {
var x: Int = 0
var y: Int = 0
var hidden: Boolean = false
}
var mugwump: MutableList<Mugwump> = mutableListOf()
var found: Int = 0 // counter
// Move the cursor to the top left position of the terminal.
fun home() {
print("\u001B[H")
}
// Clear the terminal and move the cursor to the top left position.
fun clear() {
print("\u001B[2J")
home()
}
// Print the given prompt, wait until the user enters a valid integer
// and return it.
fun getNumber(prompt: String): Int {
var number: Int
while (true) {
try {
print(prompt)
number = readln().toInt()
break
}
catch (e: Exception) { }
}
return number
}
// Return `true` if the given string is "yes" or a synonym.
fun isYes(answer: String): Boolean {
when (answer.lowercase()) {
"ok", "yeah", "yes", "y" -> return true
else -> return false
}
}
// Return `true` if the given string is "no" or a synonym.
fun isNo(answer: String): Boolean {
when (answer.lowercase()) {
"no", "nope", "n" -> return true
else -> return false
}
}
// Print the given prompt, wait until the user enters a valid yes/no
// String, and return `true` for "yes" or `false` for "no".
fun yes(prompt: String): Boolean {
var answer = ""
while (!(isYes(answer) || isNo(answer))) {
println(prompt)
answer = readln()
}
return isYes(answer)
}
// Clear the screen, print the credits and ask the user to press enter.
fun printCredits() {
clear()
println("Mugwump\n")
println("Original version in BASIC:")
println(" Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).")
println(" Slightly modified by Bob Albrecht of People's Computer Company.")
println(" Published by Creative Computing (Morristown, New Jersey, USA), 1978.")
println(" - https://www.atariarchives.org/basicgames/showpage.php?page=114")
println(" - http://vintage-basic.net/games.html\n")
println("This version in Kotlin:")
println(" Copyright (c) 2023, Marcos Cruz (programandala.net)")
println(" SPDX-License-Identifier: Fair\n")
print("Press Enter to read the instructions. ")
readln()
}
// Clear the screen, print the instructions and ask the user to press enter.
fun printInstructions() {
clear()
println("Mugwump\n")
println("The object of this game is to find four mugwumps")
println("hidden on a 10 by 10 grid. Homebase is position 0,0.")
println("Any guess you make must be two numbers with each")
println("number between 0 and 9, inclusive. First number")
println("is distance to right of homebase and second number")
println("is distance above homebase.\n")
println("You get $TURNS tries. After each try, you will see")
println("how far you are from each mugwump.\n")
print("Press Enter to start. ")
readln()
}
// Init the mugwumps' positions, `hidden` flags and count.
fun hideMugwumps() {
for (m in mugwump.indices) {
mugwump[m].x = (0..<GRID_SIZE).random()
mugwump[m].y = (0..<GRID_SIZE).random()
mugwump[m].hidden = true
}
found = 0 // counter
}
// Create the mugwumps.
fun createMugwumps() {
for (m in 0..<MUGWUMPS) {
mugwump.add(Mugwump())
}
}
// Print the given prompt, wait until the user enters a valid coord
// and return it.
fun getCoord(prompt: String): Int {
var coord: Int
while (true) {
coord = getNumber(prompt)
if (coord < 0 || coord >= GRID_SIZE) {
println("Invalid value $coord: not in range [0, ${GRID_SIZE - 1}].")
} else {
break
}
}
return coord
}
// Return `true` if the given mugwump is hidden in the given coords.
fun isHere(m: Int, x: Int, y: Int): Boolean {
return mugwump[m].hidden && mugwump[m].x == x && mugwump[m].y == y
}
// Return the distance between the given mugwump and the given coords.
fun distance(m: Int, xCoord: Int, yCoord: Int): Int {
return sqrt((mugwump[m].x.toDouble() - xCoord.toDouble()).pow(2.0) + (mugwump[m].y.toDouble() - yCoord.toDouble()).pow(2.0)).toInt()
}
// Return a plural ending (default: "s") if the given number is greater than 1;
// otherwise return a singular ending (default: an empty string).
fun plural(n: Int, pluralEnding: String = "s", singularEnding: String = ""): String {
return if (n > 1) pluralEnding else singularEnding
}
// Run the game.
fun play() {
var x: Int
var y: Int
createMugwumps()
while (true) { // game
clear()
hideMugwumps()
var turn: Int = 1
turnsLoop@ while (turn <= TURNS) {
println("Turn number $turn\n")
println("What is your guess (in range 0..${GRID_SIZE - 1})?")
x = getCoord("Distance right of homebase (x-axis): ")
y = getCoord("Distance above homebase (y-axis): ")
println("\nYour guess is ($x, $y).")
for (m in mugwump.indices) {
if (isHere(m, x, y)) {
mugwump[m].hidden = false
found += 1
println("You have found mugwump $m!")
if (found == mugwump.size) { break@turnsLoop }
}
}
for (m in mugwump.indices) {
if (mugwump[m].hidden) {
println("You are ${distance(m, x, y)} units from mugwump $m.")
}
}
println()
turn += 1
} // turns
if (found == mugwump.size) {
println("\nYou got them all in $turn ${plural(turn)}!")
println("That was fun! let's play again…")
println("Four more mugwumps are now in hiding.")
} else {
println("Sorry, that's $TURNS tr${plural(TURNS, "ies", "y")}.\n")
println("Here is where they're hiding:")
for (m in mugwump.indices) {
if (mugwump[m].hidden) {
println("Mugwump $m is at (${mugwump[m].x}, ${mugwump[m].y}).")
}
}
}
println()
if (!yes("Do you want to play again? ")) { break }
} // game
}
fun main() {
printCredits()
printInstructions()
play()
}
In Nim
#[
Mugwump
Original version in BASIC:
Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
Slightly modified by Bob Albrecht of People's Computer Company.
Published by Creative Computing (Morristown, New Jersey, USA), 1978.
- https://www.atariarchives.org/basicgames/showpage.php?page=114
- http://vintage-basic.net/games.html
This version in Nim:
Copyright (c) 2025, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written on 2025-01-20.
Last modified: 20250404T0159+0200.
]#
import std/math
import std/random
import std/strutils
import std/terminal
import std/unicode
proc cursorHome() =
setCursorPos(0, 0)
proc clearScreen() =
eraseScreen()
cursorHome()
const gridSize = 10
const turns = 10
const mugwumps = 4
type Mugwump = tuple[
x: int,
y: int,
hidden: bool,
]
var mugwump: array[mugwumps, Mugwump]
var found: int # counter
# Wait until the user enters a string and return it.
#
proc getString(prompt: string): string =
write(stdout, prompt)
result = readLine(stdin)
# Print the given prompt, wait until the user enters a valid integer and
# return it.
#
proc getNumber(prompt: string): int =
var n: int
while true:
try:
write(stdout, prompt)
n = parseInt(readLine(stdin))
break
except ValueError:
discard
result = n
# 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 = getString(prompt)
if isYes(answer):
return true
if isNo(answer):
return false
# Return a plural ending (default: "s") if the given number is greater than 1;
# otherwise return a singular ending (default: an empty string).
#
proc plural(n: int, plural = "s", singular = ""): string =
result = if n > 1: plural else: singular
# Clear the screen, print the credits and ask the user to press enter.
#
proc printCredits() =
clearScreen()
writeLine(stdout, "Mugwump\n")
writeLine(stdout, "Original version in BASIC:")
writeLine(stdout, " Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).")
writeLine(stdout, " Slightly modified by Bob Albrecht of People's Computer Company.")
writeLine(stdout, " Published by Creative Computing (Morristown, New Jersey, USA), 1978.")
writeLine(stdout, " - https://www.atariarchives.org/basicgames/showpage.php?page=114")
writeLine(stdout, " - http://vintage-basic.net/games.html\n")
writeLine(stdout, "This version in Nim:")
writeLine(stdout, " Copyright (c) 2025, Marcos Cruz (programandala.net)")
writeLine(stdout, " SPDX-License-Identifier: Fair")
write(stdout, "\nPress Enter to read the instructions. ")
discard readLine(stdin)
# Clear the screen, print the instructions and ask the user to press enter.
#
proc printInstructions() =
clearScreen()
writeLine(stdout, "Mugwump\n")
writeLine(stdout, "The object of this game is to find four mugwumps")
writeLine(stdout, "hidden on a 10 by 10 grid. Homebase is position 0,0.")
writeLine(stdout, "Any guess you make must be two numbers with each")
writeLine(stdout, "number between 0 and 9, inclusive. First number")
writeLine(stdout, "is distance to right of homebase and second number")
writeLine(stdout, "is distance above homebase.\n")
var tries: string = plural(turns, "tries", "try")
writeLine(stdout, "You get ", turns, " ", tries, ". After each try, you will see")
writeLine(stdout, "how far you are from each mugwump.")
write(stdout, "\nPress Enter to start. ")
discard readLine(stdin)
# Init the mugwumps' positions, `hidden` flags and count.
#
proc hideMugwumps() =
for m in 0 ..< mugwumps:
mugwump[m].x = rand(gridSize - 1)
mugwump[m].y = rand(gridSize - 1)
mugwump[m].hidden = true
found = 0 # counter
# Print the given prompt, wait until the user enters a valid coord and return
# it.
#
proc getCoord(prompt: string): int =
while true:
result = getNumber(prompt)
if result < 0 or result >= gridSize:
writeLine(stdout, "Invalid value ", result, ": not in range [0, ", gridSize - 1, "].")
else:
break
# Return `true` if the given mugwump is hidden in the given coords.
#
proc isHere(m: int, x: int, y: int): bool =
result = mugwump[m].hidden and mugwump[m].x == x and mugwump[m].y == y
# Return the distance between the given mugwump and the given coords.
#
proc distance(m: int, x: int, y: int): int =
result = int(sqrt(
pow(float(mugwump[m].x - x), 2) +
pow(float(mugwump[m].y - y), 2)))
# Run the game.
#
proc play() =
var x: int
var y: int
var turn: int # counter
while true: # game
clearScreen()
hideMugwumps()
block playing:
for turn in 1 ..< turns:
writeLine(stdout, "Turn number ", turn, "\n")
writeLine(stdout, "What is your guess (in range [0, ", gridSize - 1, "])?")
x = getCoord("Distance right of homebase (x-axis): ")
y = getCoord("Distance above homebase (y-axis): ")
writeLine(stdout, "\nYour guess is (", x, ", ", y, ").")
for m in 0 ..< mugwumps:
if isHere(m, x, y):
mugwump[m].hidden = false
found += 1
writeLine(stdout, "You have found mugwump ", m, "!")
if found == mugwumps:
break playing
for m in 0 ..< mugwumps:
if mugwump[m].hidden:
writeLine(stdout, "You are ", distance(m, x, y), " units from mugwump ", m, ".")
writeLine(stdout, "")
if found == mugwumps:
writeLine(stdout, "\nYou got them all in ", turn, " turn", plural(turn), "!")
writeLine(stdout, "\nThat was fun! let's play again…")
writeLine(stdout, "Four more mugwumps are now in hiding.")
else:
var tries: string = plural(turns, "tries", "try")
writeLine(stdout, "\nSorry, that's ", turns, " ", tries, ".")
writeLine(stdout, "\nHere is where they're hiding:")
for m in 0 ..< mugwumps:
if mugwump[m].hidden:
writeLine(stdout, "Mugwump ", m, " is at (", mugwump[m].x, ", ", mugwump[m].y, ").")
writeLine(stdout, "")
if not yes("Do you want to play again? "):
break
printCredits()
printInstructions()
play()
In Odin
/*
Mugwump
Original version in BASIC:
Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
Slightly modified by Bob Albrecht of People's Computer Company.
Published by Creative Computing (Morristown, New Jersey, USA), 1978.
- https://www.atariarchives.org/basicgames/showpage.php?page=114
- http://vintage-basic.net/games.html
This version in Odin:
Copyright (c) 2023, 2025, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written in 2023-03, 2023-09, 2023-12, 2025-02.
Last modified: 20250731T1954+0200.
*/
package mugwump
import "../lib/anodino/src/read"
import "../lib/anodino/src/term"
import "core:fmt"
import "core:math"
import "core:math/rand"
import "core:slice"
import "core:strings"
GRID_SIZE :: 10
TURNS :: 10
MUGWUMPS :: 4
Mugwump :: struct {
x : int,
y : int,
hidden : bool,
}
mugwump : [MUGWUMPS]Mugwump
found : int // counter
// Wait until the user enters a string and return it.
//
get_string :: proc(prompt : string) -> string {
fmt.print(prompt)
return read.a_string() or_else ""
}
// Print the given prompt, wait until the user enters a valid integer and
// return it.
//
get_number :: proc(prompt : string) -> (number : int) {
ok := false
for ; !ok; number, ok = read.a_prompted_int(prompt) {}
return number
}
// Print the given prompt and wait until the user enters an empty string.
//
press_enter :: proc(prompt : string) {
for {
s := get_string(prompt)
if len(s) == 0 do break
defer 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 := get_string(prompt)
defer delete(answer)
if is_yes(answer) do return true
if is_no(answer) do return false
}
}
// Clear the screen, print the credits and ask the user to press enter.
//
print_credits :: proc() {
term.clear_screen()
fmt.println("Mugwump\n")
fmt.println("Original version in BASIC:")
fmt.println(" Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).")
fmt.println(" Slightly modified by Bob Albrecht of People's Computer Company.")
fmt.println(" Published by Creative Computing (Morristown, New Jersey, USA), 1978.")
fmt.println(" - https://www.atariarchives.org/basicgames/showpage.php?page=114")
fmt.println(" - http://vintage-basic.net/games.html\n")
fmt.println("This version in Odin:")
fmt.println(" Copyright (c) 2023, 2025, Marcos Cruz (programandala.net)")
fmt.println(" SPDX-License-Identifier: Fair\n")
press_enter("Press Enter to read the instructions. ")
}
// Clear the screen, print the instructions and ask the user to press enter.
//
print_instructions :: proc() {
term.clear_screen()
fmt.println("Mugwump\n")
fmt.println("The object of this game is to find four mugwumps")
fmt.println("hidden on a 10 by 10 grid. Homebase is position 0,0.")
fmt.println("Any guess you make must be two numbers with each")
fmt.println("number between 0 and 9, inclusive. First number")
fmt.println("is distance to right of homebase and second number")
fmt.println("is distance above homebase.\n")
fmt.printfln("You get %v tries. After each try, you will see", TURNS)
fmt.println("how far you are from each mugwump.\n")
press_enter("Press Enter to start. ")
}
// Init the mugwumps' positions, `hidden` flags and count.
//
hide_mugwumps :: proc() {
for m in 0 ..< MUGWUMPS {
mugwump[m].x = rand.int_max(GRID_SIZE)
mugwump[m].y = rand.int_max(GRID_SIZE)
mugwump[m].hidden = true
}
found = 0 // counter
}
// Print the given prompt, wait until the user enters a valid coord and return
// it.
//
get_coord :: proc(prompt : string) -> (coord : int) {
for {
coord = get_number(prompt)
if coord < 0 || coord >= GRID_SIZE {
fmt.printfln("Invalid value %v: not in range [0, %v].", coord, GRID_SIZE - 1)
} else {
break
}
}
return
}
// Return `true` if the given mugwump is hidden in the given coords.
//
is_here :: proc(m : int, x : int, y : int) -> bool {
return mugwump[m].hidden && mugwump[m].x == x && mugwump[m].y == y
}
// Return the distance between the given mugwump and the given coords.
//
distance :: proc(m : int, x : int, y : int) -> int {
return int(math.sqrt( \
math.pow_f64(f64(mugwump[m].x - x), 2) \
+ math.pow_f64(f64(mugwump[m].y - y), 2)))
}
// Return a plural ending (default: "s") if the given number is greater than 1;
// otherwise return a singular ending (default: an empty string).
//
plural :: proc(n : int, plural := "s", singular := "") -> string {
return n > 1 ? plural : singular
}
// Run the game.
//
play :: proc() {
x, y : int
turn : int // counter
for { // game
term.clear_screen()
hide_mugwumps()
turns_loop: for turn = 1; turn <= TURNS; turn += 1 {
fmt.printfln("Turn number %v\n", turn)
fmt.printfln("What is your guess (in range [0, %v])?", GRID_SIZE - 1)
x = get_coord("Distance right of homebase (x-axis): ")
y = get_coord("Distance above homebase (y-axis): ")
fmt.printfln("\nYour guess is (%v, %v).", x, y)
for m in 0 ..< MUGWUMPS {
if is_here(m, x, y) {
mugwump[m].hidden = false
found += 1
fmt.printfln("You have found mugwump %v!", m)
if found == MUGWUMPS do break turns_loop
}
}
for m in 0 ..< MUGWUMPS {
if mugwump[m].hidden {
fmt.printfln("You are %v units from mugwump %v.", distance(m, x, y) , m)
}
}
fmt.println()
} // turns
if found == MUGWUMPS {
fmt.printfln("\nYou got them all in %v turn%s!\n", turn, plural(turn))
fmt.println("That was fun! let's play again…")
fmt.println("Four more mugwumps are now in hiding.")
} else {
fmt.printfln("\nSorry, that's %v tr%s.\n", TURNS, plural(TURNS, "ies", "y"))
fmt.println("Here is where they're hiding:")
for m in 0 ..< MUGWUMPS {
if mugwump[m].hidden {
fmt.printfln("Mugwump %v is at (%v, %v).", m, mugwump[m].x, mugwump[m].y)
}
}
}
fmt.println()
if !yes("Do you want to play again? ") do break
} // game
}
main :: proc() {
print_credits()
print_instructions()
play()
}
In Pike
#!/usr/bin/env pike
// Mugwump
// Original version in BASIC:
// Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
// Slightly modified by Bob Albrecht of People's Computer Company.
// Published by Creative Computing (Morristown, New Jersey, USA), 1978.
// - https://www.atariarchives.org/basicgames/showpage.php?page=114
// - http://vintage-basic.net/games.html
// This version in Pike:
// Copyright (c) 2025, Marcos Cruz (programandala.net)
// SPDX-License-Identifier: Fair
//
// Written in 2025-03-11/12.
//
// Last modified: 20250731T1954+0200.
// Terminal {{{1
// =============================================================================
constant NORMAL_STYLE = 0;
void move_cursor_home() {
write("\x1B[H");
}
void set_style(int style) {
write("\x1B[%dm", style);
}
void reset_attributes() {
set_style(NORMAL_STYLE);
}
void erase_screen() {
write("\x1B[2J");
}
void clear_screen() {
erase_screen();
reset_attributes();
move_cursor_home();
}
// Data {{{1
// =============================================================================
constant GRID_SIZE = 10;
constant TURNS = 10;
constant MUGWUMPS = 4;
class Mugwump {
int x;
int y;
bool hidden;
}
array(Mugwump) mugwump = allocate(MUGWUMPS);
int found = 0; // counter
// User input {{{1
// =============================================================================
string accept_string(string prompt) {
write(prompt);
return Stdio.stdin->gets();
}
// Print the given prompt, accept a string from the user. If the whole typed
// string is a valid integer (excluding trailing and leading white spaces,
// i.e.: space, tab, newline, carriage return, form feed, vertical tab and all
// the white spaces defined in Unicode), then return the number; otherwise
// return the typed string.
//
int|string accept_integer(string prompt) {
string s = String.trim(accept_string(prompt));
int n = (int) s;
if ((string) n == s) {
return n;
} else {
return s;
}
}
int prompted_valid_integer(string prompt) {
while (true) {
int|string answer = accept_integer(prompt);
if (stringp(answer)) {
write("Integer expected.\n");
} else {
return answer;
}
}
}
bool is_yes(string s) {
switch(lower_case(s)) {
case "ok":
case "y":
case "yeah":
case "yes":
return true;
default:
return false;
}
}
bool is_no(string s) {
switch(lower_case(s)) {
case "n":
case "no":
case "nope":
return true;
default:
return false;
}
}
// Print the given prompt, wait until the user enters a valid yes/no string;
// and return `true` for "yes" or `false` for "no".
//
bool yes(string prompt) {
while (true) {
string answer = accept_string(prompt);
if (is_yes(answer)) {
return true;
}
if (is_no(answer)) {
return false;
}
}
}
// Credits and instructions {{{1
// =============================================================================
// Clear the screen, print the credits and ask the user to press enter.
//
void print_credits() {
clear_screen();
write("Mugwump\n\n");
write("Original version in BASIC:\n");
write(" Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).\n");
write(" Slightly modified by Bob Albrecht of People's Computer Company.\n");
write(" Published by Creative Computing (Morristown, New Jersey, USA), 1978.\n");
write(" - https://www.atariarchives.org/basicgames/showpage.php?page=114\n");
write(" - http://vintage-basic.net/games.html\n\n");
write("This version in Pike:\n");
write(" Copyright (c) 2025, Marcos Cruz (programandala.net)\n");
write(" SPDX-License-Identifier: Fair\n\n");
accept_string("Press Enter to read the instructions. ");
}
// Clear the screen, print the instructions and ask the user to press enter.
//
void print_instructions() {
clear_screen();
write("Mugwump\n\n");
write("The object of this game is to find four mugwumps\n");
write("hidden on a 10 by 10 grid. Homebase is position 0,0.\n");
write("Any guess you make must be two numbers with each\n");
write("number between 0 and 9, inclusive. First number\n");
write("is distance to right of homebase and second number\n");
write("is distance above homebase.\n\n");
write("You get %d tries. After each try, you will see\n", TURNS);
write("how far you are from each mugwump.\n\n");
accept_string("Press Enter to start. ");
}
// Game {{{1
// =============================================================================
void hide_mugwumps() {
for (int m = 0; m < MUGWUMPS; m += 1) {
mugwump[m]->x = random(GRID_SIZE);
mugwump[m]->y = random(GRID_SIZE);
mugwump[m]->hidden = true;
}
found = 0; // counter
}
// Print the given prompt, wait until the user enters a valid coord and return
// it.
//
int get_coord(string prompt) {
int coord = 0;
while (true) {
coord = prompted_valid_integer(prompt);
if (coord < 0 || coord >= GRID_SIZE) {
write("Invalid value %d: not in range [0, %d].\n", coord, GRID_SIZE - 1);
} else {
break;
}
}
return coord;
}
// Return `true` if the given mugwump is hidden in the given coords.
//
bool is_here(int m, int x, int y) {
return mugwump[m]->hidden && mugwump[m]->x == x && mugwump[m]->y == y;
}
// Return the distance between the given mugwump and the given coords.
//
int distance(int m, int x, int y) {
return (int) sqrt(
pow((mugwump[m]->x - x), 2.0) +
pow((mugwump[m]->y - y), 2.0));
}
// Return a plural suffix (default: "s") if the given number is greater than 1
// otherwise return a singular suffix (default: an empty string).
//
string plural(int n, string|void plural_suffix, string|void singular_suffix) {
plural_suffix = plural_suffix || "s";
singular_suffix = singular_suffix || "";
return n > 1 ? plural_suffix : singular_suffix;
}
// Run the game.
//
void play() {
int x = 0;
int y = 0;
int turn = 0; // counter
while (true) { // game
clear_screen();
hide_mugwumps();
turns_loop: for (int turn = 1; turn <= TURNS; turn += 1) {
write("Turn number %d\n\n", turn);
write("What is your guess (in range [0, %d])?\n", GRID_SIZE - 1);
x = get_coord("Distance right of homebase (x-axis): ");
y = get_coord("Distance above homebase (y-axis): ");
write("\nYour guess is (%d, %d).\n", x, y);
for (int m = 0; m < MUGWUMPS; m += 1) {
if (is_here(m, x, y)) {
mugwump[m]->hidden = false;
found += 1;
write("You have found mugwump %d!\n", m);
if (found == MUGWUMPS) {
break turns_loop;
}
}
}
for (int m = 0; m < MUGWUMPS; m += 1) {
if (mugwump[m]->hidden) {
write("You are %d units from mugwump %d.\n", distance(m, x, y) , m);
}
}
write("\n");
} // turns
if (found == MUGWUMPS) {
write("\nYou got them all in %d turn%s!\n\n", turn, plural(turn));
write("That was fun! let's play again…\n");
write("Four more mugwumps are now in hiding.\n");
} else {
write("\nSorry, that's %d tr%s.\n\n", TURNS, plural(TURNS, "ies", "y"));
write("Here is where they're hiding:\n");
for (int m = 0; m < MUGWUMPS; m += 1) {
if (mugwump[m]->hidden) {
write("Mugwump %d is at (%d, %d).\n", m, mugwump[m]->x, mugwump[m]->y);
}
}
}
if (!yes("\nDo you want to play again? ")) {
break;
}
} // game
}
// Main {{{1
// =============================================================================
void init() {
// Build the `mugwump` array.
for (int i = 0; i < MUGWUMPS; i += 1) {
mugwump[i] = Mugwump();
}
}
void main() {
print_credits();
print_instructions();
init();
play();
}
In Python
# Mugwump
# Original version in BASIC:
# Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
# Slightly modified by Bob Albrecht of People's Computer Company.
# Published by Creative Computing (Morristown, New Jersey, USA), 1978.
# - https://www.atariarchives.org/basicgames/showpage.php?page=114
# - http://vintage-basic.net/games.html
# This version in Python:
# Copyright (c) 2024, Marcos Cruz (programandala.net)
# SPDX-License-Identifier: Fair
#
# Written on 2024-10-29.
#
# Last modified: 20241203T2231+0100.
import ast
from dataclasses import dataclass
import math
import os
import random
GRID_SIZE = 10
TURNS = 10
MUGWUMPS = 4
@dataclass
class Mugwump:
hidden: bool
x: int
y: int
# Clear the terminal and move the cursor to the top left position.
def clear():
if os.name == 'nt':
_ = os.system('cls')
else:
# on mac and linux, `os.name` is 'posix'
_ = os.system('clear')
# Print the given prompt, wait until the user enters a valid integer and return
# it.
def get_number(prompt):
while True:
try:
n = ast.literal_eval(input(prompt))
break
except:
print("Not a valid number.")
return n
# Prompt the user to enter a command and return it.
def command(prompt = "> "):
print(prompt, end = "")
return input()
# Print the given prompt and wait until the user enters an empty string.
def press_enter(prompt):
user_input = "X"
while user_input != "":
user_input = command(prompt)
# Return `True` if the given string is "yes" or a synonym; otherwise return
# `False`.
def is_yes(answer):
return answer.lower() in ["ok", "yeah", "yes", "y"]
# Return `True` if the given string is "no" or a synonym; otherwise return
# `False`.
def is_no(answer):
return answer.lower() in ["no", "nope", "n"]
# Print the given prompt, wait until the user enters a valid yes/no string, and
# return `True` for "yes" or `False` for "no".
def yes(prompt):
answer = ""
while not (is_yes(answer) or is_no(answer)):
answer = command(prompt)
return is_yes(answer)
# Clear the screen, print the credits and ask the user to press enter.
def print_credits():
clear()
print("Mugwump\n")
print("Original version in BASIC:")
print(" Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).")
print(" Slightly modified by Bob Albrecht of People's Computer Company.")
print(" Published by Creative Computing (Morristown, New Jersey, USA), 1978.")
print(" - https://www.atariarchives.org/basicgames/showpage.php?page=114")
print(" - http://vintage-basic.net/games.html\n")
print("This version in Python:")
print(" Copyright (c) 2024, Marcos Cruz (programandala.net)")
print(" SPDX-License-Identifier: Fair\n")
press_enter("Press Enter to read the instructions. ")
# Clear the screen, print the instructions and ask the user to press enter.
def print_instructions():
clear()
print("Mugwump\n")
print("The object of this game is to find four mugwumps")
print("hidden on a 10 by 10 grid. Homebase is position 0,0.")
print("Any guess you make must be two numbers with each")
print("number between 0 and 9, inclusive. First number")
print("is distance to right of homebase and second number")
print("is distance above homebase.\n")
print(f"You get {TURNS} tries. After each try, you will see")
print("how far you are from each mugwump.\n")
press_enter("Press Enter to start. ")
# Print the given prompt, then waits until the user enters a valid coord and
# returns it.
def get_coord(prompt):
coord = 0
while True:
coord = get_number(prompt)
if coord < 0 or coord >= GRID_SIZE:
print(f"Invalid value {coord}: not in range [0, {GRID_SIZE - 1}].")
else:
break
return coord
# Return `True` if the given mugwump is hidden in the given coords.
def is_here(m, x, y):
return m.hidden and m.x == x and m.y == y
# Return the distance between the given mugwump and the given coords.
def distance(m, x, y):
return round(math.sqrt((m.x - x) ** 2 + (m.y - y) ** 2))
# If the given number is greater than 1, return the given plural ending
# (default: "s"); otherwise return the given singular ending (default: an empty
# string).
def plural(n, plural = "s", singular = ""):
return plural if n > 1 else singular
# Print the mugwumps found in the given coordinates and return the count.
def mugwumps_found(mugwump, x, y):
found = 0
for m in range(0, MUGWUMPS):
if is_here(mugwump[m], x, y):
mugwump[m].hidden = False
found += 1
print(f"You have found mugwump {m}!")
return found
# Run the game.
def play():
while True : # game
clear()
mugwump = []
for m in range(0, MUGWUMPS):
mugwump.append(
Mugwump(
True,
random.randrange(0, GRID_SIZE),
random.randrange(0, GRID_SIZE)))
found = 0
turn = 1
while turn < TURNS:
print(f"Turn number {turn}\n")
print(f"What is your guess (in range [0, {GRID_SIZE - 1}])?")
x = get_coord("Distance right of homebase (x-axis): ")
y = get_coord("Distance above homebase (y-axis): ")
print(f"\nYour guess is ({x}, {y}).")
found += mugwumps_found(mugwump, x, y)
if found == MUGWUMPS:
break # turns
else:
for m in range(0, MUGWUMPS):
if mugwump[m].hidden:
print("You are", distance(mugwump[m], x, y), f"units from mugwump {m}.")
print()
turn += 1
# end of turns
if found == MUGWUMPS:
print(f"\nYou got them all in {turn} turn", plural(turn), "!\n", sep = "")
print("That was fun! let's play again…")
print("Four more mugwumps are now in hiding.")
else:
print(f"Sorry, that's {TURNS} tr", plural(TURNS, "ies", "y"), ".\n", sep = "")
print("Here is where they're hiding:")
for m in range(0, MUGWUMPS):
if mugwump[m].hidden:
print(f"Mugwump {m} is at (", mugwump[m].x, ", ", mugwump[m].y, ").", sep = "")
print()
if not yes("Do you want to play again? "):
break # game
# end of game
print_credits()
print_instructions()
play()
In Raku
# Mugwump
#
# Original version in BASIC:
# Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
# Slightly modified by Bob Albrecht of People's Computer Company.
# Published by Creative Computing (Morristown, New Jersey, USA), 1978.
# - https://www.atariarchives.org/basicgames/showpage.php?page=114
# - http://vintage-basic.net/games.html
#
# This version in Raku:
# Copyright (c) 2024, Marcos Cruz (programandala.net)
# SPDX-License-Identifier: Fair
#
# Written on 2024-12-07/11.
#
# Last modified: 20241211T1237+0100.
sub clear_screen {
print "\e[0;0H\e[2J";
}
constant $GRID_SIZE = 10;
constant $TURNS = 10;
constant $MUGWUMPS = 4;
class Mugwump {
has Int $.x is rw = 0;
has Int $.y is rw = 0;
has Bool $.hidden is rw = False;
}
my @mugwump of Mugwump;
for 0 ..^ $MUGWUMPS {
push @mugwump, Mugwump.new;
}
my Int $found; # counter
# Print the given prompt, wait until the user enters a valid integer and
# return it.
#
sub prompt_number(Str $prompt --> Int) {
my Int $n;
my Str $s = '';
constant $ERROR = 'Valid integer expected.';
loop {
loop {
$s = prompt($prompt);
if not $s eq '' {
last;
}
put $ERROR;
}
try {
$n = (+$s).Int;
CATCH {
default {
put $ERROR;
next;
}
}
}
last;
}
return $n;
}
# Return `True` if the given string is "yes" or a synonym.
#
sub is_yes(Str $answer --> Bool) {
return $answer.lc (elem) ["ok", "y", "yeah", "yes"]
}
# Return `True` if the given string is "no" or a synonym.
#
sub is_no(Str $answer --> Bool) {
return $answer.lc (elem) ["n", "no", "nope"];
}
# Print the given prompt, wait until the user enters a valid yes/no string,
# and return `True` for "yes" or `False` for "no".
#
sub yes(Str $prompt --> Bool) {
loop {
my $answer = prompt($prompt);
if is_yes($answer) { return True };
if is_no($answer) { return False };
}
}
# Clear the screen, print the credits and ask the user to press enter.
#
sub print_credits {
clear_screen;
put "Mugwump\n";
put 'Original version in BASIC:';
put " Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).";
put " Slightly modified by Bob Albrecht of People's Computer Company.";
put ' Published by Creative Computing (Morristown, New Jersey, USA), 1978.';
put ' - https://www.atariarchives.org/basicgames/showpage.php?page=114';
put " - http://vintage-basic.net/games.html\n";
put 'This version in Raku:';
put ' Copyright (c) 2024, Marcos Cruz (programandala.net)';
put " SPDX-License-Identifier: Fair\n";
prompt 'Press Enter to read the instructions. ';
}
# Clear the screen, print the instructions and ask the user to press enter.
#
sub print_instructions {
clear_screen;
put "Mugwump\n";
put 'The object of this game is to find four mugwumps';
put 'hidden on a 10 by 10 grid. Homebase is position 0,0.';
put 'Any guess you make must be two numbers with each';
put 'number between 0 and 9, inclusive. First number';
put 'is distance to right of homebase and second number';
put "is distance above homebase.\n";
put "You get $TURNS tries. After each try, you will see";
put "how far you are from each mugwump.\n";
prompt 'Press Enter to start. ';
}
# Init the mugwumps' positions, `hidden` flags and count.
#
sub hide_mugwumps {
#say @mugwump[0]; # XXX TMP --> Mugwump.new
for 0 ..^ $MUGWUMPS -> $m {
@mugwump[$m].x = (0 ..^ $GRID_SIZE).pick;
@mugwump[$m].y = (0 ..^ $GRID_SIZE).pick;
@mugwump[$m].hidden = True;
}
$found = 0 ; # counter
}
# Print the given prompt, wait until the user enters a valid coord and return
# it.
#
sub get_coord(Str $prompt --> Int) {
my Int $coord;
loop {
$coord = prompt_number($prompt);
if $coord < 0 or $coord >= $GRID_SIZE {
put "Invalid value $coord: not in range [0, {$GRID_SIZE - 1}].";
} else {
last;
}
}
return $coord;
}
# Return `True` if the given mugwump is hidden in the given coords.
#
sub is_here(Int $m, Int $x, Int $y --> Bool) {
return (@mugwump[$m].hidden and @mugwump[$m].x == $x and @mugwump[$m].y == $y);
}
# Return the distance between the given mugwump and the given coords.
#
sub distance(Int $m, Int $x, Int $y --> Int) {
return Int(sqrt(((@mugwump[$m].x - $x) ** 2) + ((@mugwump[$m].y - $y) ** 2)));
}
# Return a plural ending (default: "s") if the given number is greater than 1;
# otherwise return a singular ending (default: an empty string).
#
sub plural(Int $n, $plural = 's', $singular = '' --> Str) {
return $n > 1 ?? $plural !! $singular;
}
# Run the game.
#
sub play {
my Int $x;
my Int $y;
my Int $turn; # counter
loop { # game
clear_screen;
hide_mugwumps;
TURNS_LOOP: for 1 ..^ $TURNS -> $t {
$turn = $t;
put "Turn number $turn\n";
put "What is your guess (in range [0, {$GRID_SIZE - 1}])?";
$x = get_coord('Distance right of homebase (x-axis): ');
$y = get_coord('Distance above homebase (y-axis): ');
put "\nYour guess is ($x, $y).";
for 0 ..^ $MUGWUMPS -> $m {
if is_here($m, $x, $y) {
@mugwump[$m].hidden = False;
$found += 1;
put "You have found mugwump $m!";
if $found == $MUGWUMPS {
last TURNS_LOOP;
}
}
}
for 0 ..^ $MUGWUMPS -> $m {
if @mugwump[$m].hidden {
put "You are {distance($m, $x, $y)} units from mugwump $m.";
}
}
put '';
} # turns
if $found == $MUGWUMPS {
put "You got them all in $turn turn{plural($turn)}!\n";
put "That was fun! let's play again…";
put 'Four more mugwumps are now in hiding.';
} else {
put "Sorry, that's $TURNS tr{plural($TURNS, "ies", "y")}.\n";
put "Here is where they're hiding:";
for 0 ..^ $MUGWUMPS -> $m {
if @mugwump[$m].hidden {
put "Mugwump $m is at ({@mugwump[$m].x}, {@mugwump[$m].y}).";
}
}
}
put '';
if not yes('Do you want to play again? ') {
last;
}
} # game
}
print_credits;
print_instructions;
play;
In Ring
/*
Mugwump
Original version in BASIC:
Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
Slightly modified by Bob Albrecht of People's Computer Company.
Published by Creative Computing (Morristown, New Jersey, USA), 1978.
- https://www.atariarchives.org/basicgames/showpage.php?page=114
- http://vintage-basic.net/games.html
This version in Ring:
Copyright (c) 2024, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written in 2024-03/04.
Last modified: 20240405T1416+0200.
*/
GRID_SIZE = 10
TURNS = 10
MUGWUMPS = 4
mugwump = list(MUGWUMPS)
found = 0 // counter
# Clear the terminal and move the cursor to the top left position.
func clearScreen()
system("clear")
end
// Return `true` if the given string is "yes" or a synonym.
func isYes(answer) {
switch lower(answer) {
case "y" return true
case "yeah" return true
case "yes" return true
case "ok" return true
else return false
}
}
// Return `true` if the given string is "no" or a synonym.
func isNo(answer) {
switch lower(answer) {
case "n" return true
case "no" return true
case "nope" 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".
func yes(prompt) {
answer = ""
while (!(isYes(answer) || isNo(answer))) {
print(prompt + nl)
answer = getString()
}
return isYes(answer)
}
// Clear the screen, print the credits and ask the user to press enter.
func printCredits() {
clearScreen()
print("Mugwump\n\n")
print("Original version in BASIC:\n")
print(" Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).\n")
print(" Slightly modified by Bob Albrecht of People's Computer Company.\n")
print(" Published by Creative Computing (Morristown, New Jersey, USA), 1978.\n")
print(" - https://www.atariarchives.org/basicgames/showpage.php?page=114\n")
print(" - http://vintage-basic.net/games.html\n\n")
print("This version in Ring:\n")
print(" Copyright (c) 2024, Marcos Cruz (programandala.net)\n")
print(" SPDX-License-Identifier: Fair\n\n")
print("Press Enter to read the instructions. ")
getString()
}
// Clear the screen, print the instructions and ask the user to press enter.
func printInstructions() {
clearScreen()
print("Mugwump\n\n")
print("The object of this game is to find four mugwumps\n")
print("hidden on a 10 by 10 grid. Homebase is position 0,0.\n")
print("Any guess you make must be two numbers with each\n")
print("number between 0 and 9, inclusive. First number\n")
print("is distance to right of homebase and second number\n")
print("is distance above homebase.\n\n")
print("You get #{TURNS} tries. After each try, you will see\n")
print("how far you are from each mugwump.\n\n")
print("Press Enter to start. ")
getString()
}
// Init the mugwumps' positions, `hidden` flags and count.
func hideMugwumps() {
for m = 1 to MUGWUMPS {
mugwump[m].x = random(GRID_SIZE - 1) + 1
mugwump[m].y = random(GRID_SIZE - 1) + 1
mugwump[m].hidden = true
}
found = 0 // counter
}
// Create the mugwumps.
func createMugwumps() {
for m = 1 to MUGWUMPS {
mugwump[m] = new Mugwump { x = 0 y = 0 hidden = false }
}
}
// Print the given prompt, wait until the user enters a valid coord
// and return it.
func getCoord(prompt) {
while (true) {
print(prompt)
coord = getNumber()
if (coord < 0 || coord >= GRID_SIZE) {
print("Invalid value #{coord}: not in range [0, #{GRID_SIZE - 1}].\n")
else
break
}
}
return coord
}
// Return `true` if the given mugwump is hidden in the given coords.
func isHere(m, x, y) {
return mugwump[m].hidden && mugwump[m].x = x && mugwump[m].y = y
}
// Return the distance between the given mugwump and the given coords.
func distance(m, xCoord, yCoord) {
return floor(sqrt(((mugwump[m].x - xCoord) ** 2) + ((mugwump[m].y - yCoord) ** 2)))
}
// Return a plural ending (default: "s") if the given number is greater than 1;
// otherwise return a singular ending (default: an empty string).
func plural(n, pluralEnding, singularEnding) {
if (n > 1) {
if pluralEnding = null {
return "s" // default
else
return pluralEnding
}
else
if singularEnding = null {
return "" // default
else
return singularEnding
}
}
}
// Run the game.
func play() {
createMugwumps()
while (true) { // game
clearScreen()
hideMugwumps()
turn = 1
while (turn <= TURNS) {
print("Turn number #{turn}\n\n")
print("What is your guess (in range 0..#{GRID_SIZE - 1})?\n")
x = getCoord("Distance right of homebase (x-axis): ")
y = getCoord("Distance above homebase (y-axis): ")
print("Your guess is (#{x}, #{y}).\n")
for m = 1 to len(mugwump) {
if (isHere(m, x, y)) {
mugwump[m].hidden = false
found += 1
print("You have found mugwump #{m}!\n")
if (found = len(mugwump)) { break 2 }
}
}
for m = 1 to len(mugwump) {
if (mugwump[m].hidden) {
print("You are #{distance(m, x, y)} units from mugwump #{m}.\n")
}
}
print("\n")
turn += 1
} // turns
if (found = len(mugwump)) {
print("\nYou got them all in #{turn} #{plural(turn, null, null)}!\n")
print("That was fun! let's play again…\n")
print("Four more mugwumps are now in hiding.\n")
else
print("Sorry, that's #{TURNS} tr" + plural(TURNS, "ies", "y") + "\n")
print("Here is where they're hiding:\n")
for m = 1 to len(mugwump) {
if (mugwump[m].hidden) {
print("Mugwump #{m} is at (#{mugwump[m].x}, #{mugwump[m].y}).\n")
}
}
}
print("\n")
if (!yes("Do you want to play again? ")) { break }
} // game
}
func main() {
printCredits()
printInstructions()
play()
}
class Mugwump {
x = 0
y = 0
hidden = false
}
In Scala
// Mugwump
//
// Original version in BASIC:
// Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
// Slightly modified by Bob Albrecht of People's Computer Company.
// Published by Creative Computing (Morristown, New Jersey, USA), 1978.
// - https://www.atariarchives.org/basicgames/showpage.php?page=114
// - http://vintage-basic.net/games.html
//
// This version in Scala:
// Copyright (c) 2023, Marcos Cruz (programandala.net)
// SPDX-License-Identifier: Fair
//
// Written in 2023-09, 2023-11.
//
// Last modified: 20231104T0113+0100.
val GridSize = 10
val Turns = 10
val Mugwumps = 4
class Mugwump :
var hidden : Boolean = true
var x : Int = 0
var y : Int = 0
def reveal() =
hidden = false
def init() =
hidden = true
x = util.Random.nextInt(GridSize)
y = util.Random.nextInt(GridSize)
// Moves the cursor to the top left position of the terminal.
def home() =
print("\u001B[H")
// Clears the terminal and moves the cursor to the top left position.
def clear() =
print("\u001B[2J")
home()
// Prompts the user to enter a command and returns it trimmed.
def command(prompt : String = "> ") : String =
io.StdIn.readLine(prompt).trim
// Prints the given prompt, waits until the user enters a valid integer and
// returns it.
def getNumber(prompt : String) : Int =
var number = 0
var ok = false
while !ok do
try
number = command(prompt).toInt
ok = true
catch
case _ => println("Invalid number.")
number
// Prints the given prompt and waits until the user enters an empty string.
def pressEnter(prompt : String) =
var ok = false
while !ok do
ok = io.StdIn.readLine(prompt) == ""
// Returns `true` if the given string is "yes" or a synonym.
def isYes(answer : String) : Boolean =
answer.toLowerCase match
case "ok" => true
case "yeah" => true
case "yes" => true
case "y" => true
case _ => false
// Returns `true` if the given string is "no" or a synonym.
def isNo(answer : String) : Boolean =
answer.toLowerCase match
case "no" => true
case "nope" => true
case "n" => true
case _ => false
// 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) : Boolean =
var answer : String = ""
while !(isYes(answer) || isNo(answer)) do
answer = command(prompt)
isYes(answer)
// Clears the screen, prints the credits and asks the user to press enter.
def printCredits() =
clear()
println("Mugwump\n")
println("Original version in BASIC:")
println(" Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).")
println(" Slightly modified by Bob Albrecht of People's Computer Company.")
println(" Published by Creative Computing (Morristown, New Jersey, USA), 1978.")
println(" - https://www.atariarchives.org/basicgames/showpage.php?page=114")
println(" - http://vintage-basic.net/games.html\n")
println("This version in Scala:")
println(" Copyright (c) 2023, Marcos Cruz (programandala.net)")
println(" SPDX-License-Identifier: Fair\n")
pressEnter("Press Enter to read the instructions. ")
// Clears the screen, prints the instructions and asks the user to press enter.
def printInstructions() =
clear()
println("Mugwump\n")
println("The object of this game is to find four mugwumps")
println("hidden on a 10 by 10 grid. Homebase is position 0,0.")
println("Any guess you make must be two numbers with each")
println("number between 0 and 9, inclusive. First number")
println("is distance to right of homebase and second number")
println("is distance above homebase.\n")
print(s"You get ${Turns} tries. After each try, you will see\n")
println("how far you are from each mugwump.\n")
pressEnter("Press Enter to start. ")
// Prints the given prompt, then waits until the user enters a valid coord and
// returns it.
def getCoord(prompt : String) : Int =
var coord : Int = 0
var right = false
while !right do
coord = getNumber(prompt)
if coord < 0 || coord >= GridSize then
print(s"Invalid value ${coord}: not in range [0, ${GridSize - 1}].\n")
else
right = true
coord
// Returns `true` if the given mugwump is hidden in the given coords.
def isHere(m : Mugwump, x : Int, y : Int) : Boolean =
m.hidden && m.x == x && m.y == y
// Returns the distance between the given mugwump and the given coords.
def distance(m : Mugwump, x : Int, y : Int) : Int =
math.sqrt(math.pow((m.x - x), 2) + math.pow((m.y - y), 2)).toInt
// If the given number is greater than 1, this method returns a plural ending
// (default: "s"); otherwise it returns a singular ending (default: an empty
// string).
def plural(n : Int, plural : String = "s", singular : String = "") : String =
if n > 1 then plural else singular
// Prints the mugwumps found in the given coordinates and returns the count.
def foundAt(mugwump : Array[Mugwump], x : Int, y : Int) : Int =
var found : Int = 0
for m <- 0 until Mugwumps do
if isHere(mugwump(m), x, y) then
mugwump(m).reveal()
found += 1
print(s"You have found mugwump ${m}!\n")
end if
end for
found
// Runs the game.
def play() =
var found : Int = 0 // counter
var turn : Int = 0 // counter
var m : Int = 0
var x : Int = 0
var y : Int = 0
var gameOver = false
val mugwump = new Array[Mugwump](Mugwumps)
for m <- 0 until Mugwumps do
mugwump(m) = new Mugwump
while !gameOver do // game
clear()
for m <- 0 until Mugwumps do
mugwump(m).init()
found = 0
turn = 0
while turn < Turns && found < Mugwumps do
turn += 1
print(s"Turn number ${turn}\n\n")
print(s"What is your guess (in range [0, ${GridSize - 1}])?\n")
x = getCoord("Distance right of homebase (x-axis): ")
y = getCoord("Distance above homebase (y-axis): ")
print(s"\nYour guess is ($x, $y).\n")
found += foundAt(mugwump, x, y)
if found < Mugwumps then
for m <- 0 until Mugwumps do
if mugwump(m).hidden then
print(s"You are ${distance(mugwump(m), x, y)} units from mugwump ${m}.\n")
end if
end for
println("")
end if
end while // turns
if found == Mugwumps then
print(s"\nYou got them all in ${turn} turn${plural(turn)}!\n\n")
println("That was fun! let's play again…")
println("Four more mugwumps are now in hiding.")
else
print(s"\nSorry, that's ${Turns} tr${plural(Turns, "ies", "y")}.\n\n")
println("Here is where they're hiding:")
for m <- 0 until Mugwumps do
if mugwump(m).hidden then
print(s"Mugwump $m is at (${mugwump(m).x}, ${mugwump(m).y}).\n")
end if
end for
end if
println("")
gameOver = !yes("Do you want to play again? ")
end while // game
@main def main() =
printCredits()
printInstructions()
play()
In V
/*
Mugwump
Original version in BASIC:
Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).
Slightly modified by Bob Albrecht of People's Computer Company.
Published by Creative Computing (Morristown, New Jersey, USA), 1978.
- https://www.atariarchives.org/basicgames/showpage.php?page=114
- http://vintage-basic.net/games.html
This version in V:
Copyright (c) 2025, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written on 2025-01-07
Last modified: 20250406T0126+0200.
*/
import math
import os
import rand
import strconv
import term
const grid_size = 10
const turns = 10
const mugwumps = 4
struct Mugwump {
mut:
x int
y int
hidden bool
}
// Print the given prompt and wait until the user enters a string.
//
fn input_string(prompt string) string {
return os.input(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 enters an empty string.
//
fn press_enter(prompt string) {
for input_string(prompt).len != 0 {}
}
// 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
}
// Clear the screen, print the credits and ask the user to press enter.
//
fn print_credits() {
term.clear()
println('Mugwump\n')
println('Original version in BASIC:')
println(" Written by Bud Valenti's students of Project SOLO (Pittsburg, Pennsylvania, USA).")
println(" Slightly modified by Bob Albrecht of People's Computer Company.")
println(' Published by Creative Computing (Morristown, New Jersey, USA), 1978.')
println(' - https://www.atariarchives.org/basicgames/showpage.php?page=114')
println(' - http://vintage-basic.net/games.html\n')
println('This version in V:')
println(' Copyright (c) 2025, Marcos Cruz (programandala.net)')
println(' SPDX-License-Identifier: Fair\n')
press_enter('Press Enter to read the instructions. ')
}
// Clear the screen, print the instructions and ask the user to press enter.
//
fn print_instructions() {
term.clear()
println('Mugwump\n')
println('The object of this game is to find four mugwumps')
println('hidden on a 10 by 10 grid. Homebase is position 0,0.')
println('Any guess you make must be two numbers with each')
println('number between 0 and 9, inclusive. First number')
println('is distance to right of homebase and second number')
println('is distance above homebase.\n')
println('You get ${turns} tries. After each try, you will see')
println('how far you are from each mugwump.\n')
press_enter('Press Enter to start. ')
}
// Init the mugwumps' positions, `hidden` flags and count.
//
fn hide_mugwumps(mut mugwump [mugwumps]Mugwump) {
for m in 0 .. mugwumps {
mugwump[m].x = rand.intn(grid_size) or { 0 }
mugwump[m].y = rand.intn(grid_size) or { 0 }
mugwump[m].hidden = true
}
}
// Print the given prompt, wait until the user enters a valid coord and return
// it.
//
fn get_coord(prompt string) int {
mut coord := 0
for {
coord = input_int(prompt)
if coord < 0 || coord >= grid_size {
println('Invalid value ${coord}: not in range [0, ${grid_size - 1}].')
} else {
break
}
}
return coord
}
// Return `true` if the given mugwump is hidden in the given coords.
//
fn is_here(m Mugwump, x int, y int) bool {
return m.hidden && m.x == x && m.y == y
}
// Return the distance between the given mugwump and the given coords.
//
fn distance(m Mugwump, x int, y int) int {
return int(math.sqrt(math.pow(f64(m.x - x), 2) + math.pow(f64(m.y - y), 2)))
}
// Return a plural ending (default: "s") if the given number is greater than 1;
// otherwise return a singular ending (default: an empty string).
//
fn plural_(n int, plural string, singular string) string {
return if n > 1 { plural } else { singular }
}
// Return a plural "s" ending if the given number is greater than 1;
// otherwise return an empty string.
//
fn plural(n int) string {
return plural_(n, 's', '')
}
// Run the game.
//
fn play() {
mut mugwump := [mugwumps]Mugwump{}
mut found := 0 // counter
mut x := 0
mut y := 0
mut turn := 0 // counter
for { // game
term.clear()
hide_mugwumps(mut mugwump) // XXX FIXME
found = 0
turns_loop: for turn = 1; turn <= turns; turn += 1 {
println('Turn number ${turn}\n')
println('What is your guess (in range [0, ${grid_size - 1}])?')
x = get_coord('Distance right of homebase (x-axis): ')
y = get_coord('Distance above homebase (y-axis): ')
println('\nYour guess is (${x}, ${y}).')
for m in 0 .. mugwumps {
if is_here(mugwump[m], x, y) {
mugwump[m].hidden = false
found += 1
println('You have found mugwump ${m}!')
if found == mugwumps {
break turns_loop
}
}
}
for m in 0 .. mugwumps {
if mugwump[m].hidden {
println('You are ${distance(mugwump[m], x, y)} units from mugwump ${m}.')
}
}
println('')
} // turns
if found == mugwumps {
println('\nYou got them all in ${turn} turn${plural(turn)}!\n')
println("That was fun! let's play again…")
println('Four more mugwumps are now in hiding.')
} else {
println("\nSorry, that's ${turns} tr${plural_(turns, 'ies', 'y')}.\n")
println("Here is where they're hiding:")
for m in 0 .. mugwumps {
if mugwump[m].hidden {
println('Mugwump ${m} is at (${mugwump[m].x}, ${mugwump[m].y}).')
}
}
}
println('')
if !yes('Do you want to play again? ') {
break
}
} // game
}
fn main() {
print_credits()
print_instructions()
play()
}
