Bug
Descrition del contenete del págine
Conversion de Bug a pluri lingues de programation.
Ti-ci programa esset convertet a 15 lingues de programation.
Originale
Origin of bug.bas:
By Brian Leibowitz, 1978.
Creative Computing's BASIC Games.
- http://vintage-basic.net/games.html
- http://vintage-basic.net/bcg/bug.bas
- https://www.atariarchives.org/basicgames/showpage.php?page=30
- http://www.retroarchive.org/cpm/games/ccgames.zip
10 PRINT TAB(34);"BUG"
20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"
30 PRINT:PRINT:PRINT
40 REM
50 A=0: B=0: H=0: L=0: N=0: P=0: Q=0: R=0: S=0: T=0: U=0: V=0: Y=0
60 PRINT "THE GAME BUG"
70 PRINT "I HOPE YOU ENJOY THIS GAME."
80 PRINT
90 PRINT "DO YOU WANT INSTRUCTIONS";
100 INPUT Z$
110 IF Z$="NO" THEN 300
120 PRINT "THE OBJECT OF BUG IS TO FINISH YOUR BUG BEFORE I FINISH"
130 PRINT "MINE. EACH NUMBER STANDS FOR A PART OF THE BUG BODY."
140 PRINT "I WILL ROLL THE DIE FOR YOU, TELL YOU WHAT I ROLLED FOR YOU"
150 PRINT "WHAT THE NUMBER STANDS FOR, AND IF YOU CAN GET THE PART."
160 PRINT "IF YOU CAN GET THE PART I WILL GIVE IT TO YOU."
170 PRINT "THE SAME WILL HAPPEN ON MY TURN."
180 PRINT "IF THERE IS A CHANGE IN EITHER BUG I WILL GIVE YOU THE"
190 PRINT "OPTION OF SEEING THE PICTURES OF THE BUGS."
200 PRINT "THE NUMBERS STAND FOR PARTS AS FOLLOWS:"
210 PRINT "NUMBER","PART","NUMBER OF PART NEEDED"
220 PRINT "1","BODY","1"
230 PRINT "2","NECK","1"
240 PRINT "3","HEAD","1"
250 PRINT "4","FEELERS","2"
260 PRINT "5","TAIL","1"
270 PRINT "6","LEGS","6"
280 PRINT
290 PRINT
300 IF Y>0 THEN 2480
310 Z=INT(6*RND(1)+1)
320 C=1
330 PRINT "YOU ROLLED A";Z
340 ON Z GOTO 350,430,540,650,760,870
350 PRINT "1=BODY"
360 IF B=1 THEN 410
370 PRINT "YOU NOW HAVE A BODY."
380 B=1
390 C=0
400 GOTO 970
410 PRINT "YOU DO NOT NEED A BODY."
420 GOTO 970
430 PRINT "2=NECK"
440 IF N=1 THEN 500
450 IF B=0 THEN 520
460 PRINT "YOU NOW HAVE A NECK."
470 N=1
480 C=0
490 GOTO 970
500 PRINT "YOU DO NOT NEED A NECK."
510 GOTO 970
520 PRINT "YOU DO NOT HAVE A BODY."
530 GOTO 970
540 PRINT "3=HEAD"
550 IF N=0 THEN 610
560 IF H=1 THEN 630
570 PRINT "YOU NEEDED A HEAD."
580 H=1
590 C=0
600 GOTO 970
610 PRINT "YOU DO NOT HAVE A NECK."
620 GOTO 970
630 PRINT "YOU HAVE A HEAD."
640 GOTO 970
650 PRINT "4=FEELERS"
660 IF H=0 THEN 740
670 IF A=2 THEN 720
680 PRINT "I NOW GIVE YOU A FEELER."
690 A=A+1
700 C=0
710 GOTO 970
720 PRINT "YOU HAVE TWO FEELERS ALREADY."
730 GOTO 970
740 PRINT "YOU DO NOT HAVE A HEAD."
750 GOTO 970
760 PRINT "5=TAIL"
770 IF B=0 THEN 830
780 IF T=1 THEN 850
790 PRINT "I NOW GIVE YOU A TAIL."
800 T=T+1
810 C=0
820 GOTO 970
830 PRINT "YOU DO NOT HAVE A BODY."
840 GOTO 970
850 PRINT "YOU ALREADY HAVE A TAIL."
860 GOTO 970
870 PRINT "6=LEG"
880 IF L=6 THEN 940
890 IF B=0 THEN 960
900 L=L+1
910 C=0
920 PRINT "YOU NOW HAVE";L;"LEGS."
930 GOTO 970
940 PRINT "YOU HAVE 6 FEET ALREADY."
950 GOTO 970
960 PRINT "YOU DO NOT HAVE A BODY."
970 X=INT(6*RND(1)+1)
971 PRINT
975 FOR DELAY=1 TO 2000:NEXT DELAY
980 PRINT "I ROLLED A";X
990 ON X GOTO 1000,1080,1190,1300,1410,1520
1000 PRINT "1=BODY"
1010 IF P=1 THEN 1060
1020 PRINT "I NOW HAVE A BODY."
1030 C=0
1040 P=1
1050 GOTO 1630
1060 PRINT "I DO NOT NEED A BODY."
1070 GOTO 1630
1080 PRINT "2=NECK"
1090 IF Q=1 THEN 1150
1100 IF P=0 THEN 1170
1110 PRINT "I NOW HAVE A NECK."
1120 Q=1
1130 C=0
1140 GOTO 1630
1150 PRINT "I DO NOT NEED A NECK."
1160 GOTO 1630
1170 PRINT "I DO NOT HAVE A BODY."
1180 GOTO 1630
1190 PRINT "3=HEAD"
1200 IF Q=0 THEN 1260
1210 IF R=1 THEN 1280
1220 PRINT "I NEEDED A HEAD."
1230 R=1
1240 C=0
1250 GOTO 1630
1260 PRINT "I DO NOT HAVE A NECK."
1270 GOTO 1630
1280 PRINT "I DO NOT NEED A HEAD."
1290 GOTO 1630
1300 PRINT "4=FEELERS"
1310 IF R=0 THEN 1390
1320 IF S=2 THEN 1370
1330 PRINT "I GET A FEELER."
1340 S=S+1
1350 C=0
1360 GOTO 1630
1370 PRINT "I HAVE 2 FEELERS ALREADY."
1380 GOTO 1630
1390 PRINT "I DO NOT HAVE A HEAD."
1400 GOTO 1630
1410 PRINT "5=TAIL"
1420 IF P=0 THEN 1480
1430 IF U=1 THEN 1500
1440 PRINT "I NOW HAVE A TAIL."
1450 U=1
1460 C=0
1470 GOTO 1630
1480 PRINT "I DO NOT HAVE A BODY."
1490 GOTO 1630
1500 PRINT "I DO NOT NEED A TAIL."
1510 GOTO 1630
1520 PRINT "6=LEGS"
1530 IF V=6 THEN 1590
1540 IF P=0 THEN 1610
1550 V=V+1
1560 C=0
1570 PRINT "I NOW HAVE";V;"LEGS."
1580 GOTO 1630
1590 PRINT,"I HAVE 6 FEET."
1600 GOTO 1630
1610 PRINT "I DO NOT HAVE A BODY."
1620 GOTO 1630
1630 IF A=2 AND T=1 AND L=6 THEN 1650
1640 GOTO 1670
1650 PRINT "YOUR BUG IS FINISHED."
1660 Y=Y+1
1670 IF S=2 AND P=1 AND V=6 THEN 1690
1680 GOTO 1710
1690 PRINT "MY BUG IS FINISHED."
1700 Y=Y+2
1710 IF C=1 THEN 300
1720 PRINT "DO YOU WANT THE PICTURES";
1730 INPUT Z$
1740 IF Z$="NO" THEN 300
1750 PRINT "*****YOUR BUG*****"
1760 PRINT
1770 PRINT
1780 IF A=0 THEN 1860
1790 FOR Z=1 TO 4
1800 FOR X=1 TO A
1810 PRINT TAB(10);
1820 PRINT "A ";
1830 NEXT X
1840 PRINT
1850 NEXT Z
1860 IF H=0 THEN 1880
1870 GOSUB 2470
1880 IF N=0 THEN 1920
1890 FOR Z=1 TO 2
1900 PRINT " N N"
1910 NEXT Z
1920 IF B=0 THEN 2000
1930 PRINT " BBBBBBBBBBBB"
1940 FOR Z=1 TO 2
1950 PRINT " B B"
1960 NEXT Z
1970 IF T<>1 THEN 1990
1980 PRINT "TTTTTB B"
1990 PRINT " BBBBBBBBBBBB"
2000 IF L=0 THEN 2080
2010 FOR Z=1 TO 2
2020 PRINT TAB(5);
2030 FOR X=1 TO L
2040 PRINT " L";
2050 NEXT X
2060 PRINT
2070 NEXT Z
2080 FOR Z=1 TO 4
2090 PRINT
2100 NEXT Z
2110 PRINT "*****MY BUG*****"
2120 PRINT
2130 PRINT
2140 PRINT
2150 IF S=0 THEN 2230
2160 FOR Z=1 TO 4
2170 PRINT TAB(10);
2180 FOR X=1 TO S
2190 PRINT "F ";
2200 NEXT X
2210 PRINT
2220 NEXT Z
2230 IF R<>1 THEN 2250
2240 GOSUB 2470
2250 IF Q=0 THEN 2280
2260 PRINT " N N"
2270 PRINT " N N"
2280 IF P=0 THEN 2360
2290 PRINT " BBBBBBBBBBBB"
2300 FOR Z=1 TO 2
2310 PRINT " B B"
2320 NEXT Z
2330 IF U<>1 THEN 2350
2340 PRINT "TTTTTB B"
2350 PRINT " BBBBBBBBBBBB"
2360 IF V=0 THEN 2450
2370 FOR Z=1 TO 2
2380 PRINT TAB(5);
2390 FOR X=1 TO V
2400 PRINT " L";
2410 NEXT X
2420 PRINT
2430 NEXT Z
2450 IF Y<>0 THEN 2540
2460 GOTO 300
2470 PRINT " HHHHHHH"
2480 PRINT " H H"
2490 PRINT " H O O H"
2500 PRINT " H H"
2510 PRINT " H V H"
2520 PRINT " HHHHHHH"
2530 RETURN
2540 PRINT "I HOPE YOU ENJOYED THE GAME, PLAY IT AGAIN SOON!!"
2550 END
In Arturo
; Bug
; Original version in BASIC:
; Brian Leibowitz, 1978.
; Creative Computing's BASIC Games.
; - http://vintage-basic.net/games.html
; - http://vintage-basic.net/bcg/bug.bas
; - https://www.atariarchives.org/basicgames/showpage.php?page=30
; - http://www.retroarchive.org/cpm/games/ccgames.zip
; This version in Arturo:
; Copyright (c) 2023, Marcos Cruz (programandala.net)
; SPDX-License-Identifier: Fair
;
; Written in 2023-10.
;
; Last modified: 20251205T0045+0100.
bugRecord: dictionary [
body: false
neck: false
head: false
feelers: 0
feelerType: ' '
tail: false
legs: 0
]
playerRecord: dictionary [
pronoun: ""
possessive: ""
bug: bugRecord
]
; Players.
computer: new playerRecord
computer\bug: new bugRecord
human: new playerRecord
human\bug: new bugRecord
; Bug body parts.
partNumber: dictionary [
body: 1
neck: 2
head: 3
feeler: 4
tail: 5
leg: 6
]
partName: array [
""
"body"
"neck"
"head"
"feeler"
"tail"
"leg"
]
; Bug body attributes.
bodyHeight: 2
feelerLength: 4
legLength: 2
maxFeelers: 2
maxLegs: 6
neckLength: 2
; Move the cursor up by the given number of rows (defaults to 1), without
; changing the column position.
cursorUp: function [ rows ] [
prints render "\e[|rows|A"
]
; Erase the current line, without moving the cursor position.
eraseLine: function [ ] [
prints "\e[2K"
]
; Move the cursor to the previous row, without changing the column position,
; and erase its line.
erasePreviousLine: function [ ] [
cursorUp 1
eraseLine
]
; Clear the screen, display the credits and wait for a keypress.
printCredits: function [ ] [
clear
print "Bug\n"
print "Original version in BASIC:"
print " Brian Leibowitz, 1978."
print " Creative computing (Morristown, New Jersey, USA), 1978.\n"
print "This version in Arturo:"
print " Copyright (c) 2023, Marcos Cruz (programandala.net)"
print " SPDX-License-Identifier: Fair\n"
input "Press Enter to read the instructions. "
]
instructions: {:
The object is to finish your bug before I finish mine. Each number
stands for a part of the bug body.
I will roll the die for you, tell you what I rolled for you, what the
number stands for, and if you can get the part. If you can get the
part I will give it to you. The same will happen on my turn.
If there is a change in either bug I will give you the option of
seeing the pictures of the bugs. The numbers stand for parts as
follows:
:}
; Capitalize the first character of `s` and convert the rest of `s` to
; lowercase.
toCapital: function [ s ] [
capitalize lower s
]
; ; Print a table with the bug parts' description.
printPartsTable: function [ ] [
columns: 3
columnWidth: 8
columnSeparation: 2
; Headers
header: [ "Number" "Part" "Quantity" ]
loop range 0 sub columns 1 'i [
prints pad .right header\[ i ] add columnWidth columnSeparation
]
print ""
; Rulers
loop range 1 columns 'i [
prints repeat "-" columnWidth
if? less? i columns [ prints repeat " " columnSeparation ]
]
print ""
; Data
partQuantity: array .of: add size partNumber 1 0
partQuantity\[ partNumber\body ]: 1
partQuantity\[ partNumber\neck ]: 1
partQuantity\[ partNumber\head ]: 1
partQuantity\[ partNumber\feeler ]: 2
partQuantity\[ partNumber\tail ]: 1
partQuantity\[ partNumber\leg ]: 6
loop range partNumber\body partNumber\leg 'part [
prints pad .right to :string part add columnWidth columnSeparation
prints pad .right toCapital partName\[part] add columnWidth columnSeparation
print partQuantity\[ part ]
]
]
; Clear the screen, print the instructions and wait for a keypress.
printInstructions: function [ ] [
clear
print "Bug"
print instructions
printPartsTable
input "\nPress Enter to start. "
]
; Print a bug head.
printHead: function [ ] [
print " HHHHHHH"
print " H H"
print " H O O H"
print " H H"
print " H V H"
print " HHHHHHH"
]
; Print the given bug.
printBug: function [ bug ] [
if greater? bug\feelers 0 [
loop range 0 sub feelerLength 1 'i [
prints " "
loop range 0 sub bug\feelers 1 'j [
prints render " |bug\feelerType|"
]
print ""
]
]
if bug\head [
printHead
]
if bug\neck [
loop range 0 sub neckLength 1 'i [
print " N N"
]
]
if bug\body [
print " BBBBBBBBBBBB"
loop range 0 sub bodyHeight 1 'i [
print " B B"
]
if bug\tail [
print "TTTTTB B"
]
print " BBBBBBBBBBBB"
]
if greater? bug\legs 0 [
loop range 0 sub legLength 1 'i [
prints " "
loop range 0 sub bug\legs 1 'j [
prints " L"
]
print ""
]
]
print ""
]
; Return `true` if the given bug is finished; otherwise return `false`.
isFinished?: function [ bug ] [
and?
and?
equal? bug\feelers maxFeelers
bug\tail
equal? bug\legs maxLegs
]
; Return a random number from 1 to 6 (inclusive).
dice: function [ ] [
random 1 6
]
; Array to convert a number to its equilavent text.
asText: [ "no" "a" "two" "three" "four" "five" "six" ]
; Return the proper plural ending depending of the given number.
pluralEnding: function [ n ] [
if? greater? n 1 [ "s" ] else [ "" ]
]
; Return a string containing the given number and noun in their proper form.
plural: function [ noun number ] [
render "|asText\[number]| |noun||pluralEnding number|"
]
; Add the given part to the given player's bug.
addPart: function [ part player ] [
changed: false
case [ part ]
when? [ equal? partNumber\body ] [
if? player\bug\body [
print render ", but |player\pronoun| already have a body."
] else [
print render "; |player\pronoun| now have a body:"
player\bug\body: true
changed: true
]
]
when? [ equal? partNumber\neck ] [
if? player\bug\neck [
print render ", but |player\pronoun| you already have a neck."
] else [
if? not? player\bug\body [
print render ", but |player\pronoun| need a body first."
] else [
print render "; |player\pronoun| now have a neck:"
player\bug\neck: true
changed: true
]
]
]
when? [ equal? partNumber\head ] [
if? player\bug\head [
print render ", but |player\pronoun| already have a head."
] else [
if? not? player\bug\neck [
print render ", but |player\pronoun| need a a neck first."
] else [
print render "; |player\pronoun| now have a head:"
player\bug\head: true
changed: true
]
]
]
when? [ equal? partNumber\feeler ] [
if? equal? player\bug\feelers maxFeelers [
print render ", but |player\pronoun| have two feelers already."
] else [
if? not? player\bug\head [
print render ", but |player\pronoun| need a head first."
] else [
player\bug\feelers: player\bug\feelers + 1
prints render "; |player\pronoun| now have "
prints plural "feeler" player\bug\feelers
print ":"
changed: true
]
]
]
when? [ equal? partNumber\tail ] [
if? player\bug\tail [
print render ", but |player\pronoun| already have a tail."
] else [
if? not? player\bug\body [
print render ", but |player\pronoun| need a body first."
] else [
print render "; |player\pronoun| now have a tail:"
player\bug\tail: true
changed: true
]
]
]
when? [ equal? partNumber\leg ] [
if? equal? player\bug\legs maxLegs [
print render ", but |player\pronoun| have |asText\[maxLegs]| feet already."
] else [
if? not? player\bug\body [
print render ", but |player\pronoun| need a body first."
] else [
player\bug\legs: player\bug\legs + 1
prints render "; |player\pronoun| now have "
prints plural "leg" player\bug\legs
print ":"
changed: true
]
]
]
else [ ]
changed
]
; Ask the user to press the Enter key, wait for the input, then erase the
; prompt text.
prompt: function [ ] [
input "Press Enter to roll the dice. "
erasePreviousLine
]
; Play one turn for the given player, rolling the dice and updating his bug.
turn: function [ player ] [
prompt
number: dice
prints render "|toCapital player\pronoun| rolled a |number| (|partName\[number]|)"
if addPart number player [
print ""
printBug player\bug
]
]
; Return `true` if both bugs are finished, otherwise return `false`.
tie?: function [ ] [
and? isFinished? human\bug isFinished? computer\bug
]
; Print a message about the winner.
printWinner: function [ ] [
if? tie? [
print "Both of our bugs are finished in the same number of turns!"
] else [
if? isFinished? human\bug [ prints human\possessive ]
else [ prints computer\possessive ]
print " bug is finished."
]
]
; Return `true` if any bug is finished; otherwise return `false`.
gameOver?: function [ ] [
or? isFinished? human\bug isFinished? computer\bug
]
; Execute the game loop.
play: function [ ] [
clear
until [
turn human
turn computer
] [ gameOver? ]
printWinner
]
; Init the players' data before a new game.
init: function [ ] [
human\pronoun: "you"
human\possessive: "Your"
human\bug\feelerType: 'A'
computer\pronoun: "I"
computer\possessive: "My"
computer\bug\feelerType: 'F'
]
init
printCredits
printInstructions
play
print "I hope you enjoyed the game, play it again soon!!"
In C#
// Bug
// Original version in BASIC:
// Brian Leibowitz, 1978.
// Creative Computing's BASIC Games.
// - http://vintage-basic.net/games.html
// - http://vintage-basic.net/bcg/bug.bas
// - https://www.atariarchives.org/basicgames/showpage.php?page=30
// - http://www.retroarchive.org/cpm/games/ccgames.zip
// This version in C#:
// Copyright (c) 2024, Marcos Cruz (programandala.net)
// SPDX-License-Identifier: Fair
//
// Written in 2024-12-20/21.
//
// Last modified: 20251205T1532+0100.
using System;
class BugGame
{
class ABug
{
internal bool body = false;
internal bool neck = false;
internal bool head = false;
internal int feelers = 0;
internal char feelerType = ' ';
internal bool tail = false;
internal int legs = 0;
}
class Player
{
internal string pronoun = "";
internal string possessive = "";
internal ABug bug = new ABug();
}
static Player computer = new Player();
static Player human = new Player();
enum Part {body = 1, neck, head, feeler, tail, leg};
static int parts = Enum.GetNames(typeof(Part)).Length;
// Bug body attributes.
//
const int BODY_HEIGHT = 2;
const int FEELER_LENGTH = 4;
const int LEG_LENGTH = 2;
const int MAX_FEELERS = 2;
const int MAX_LEGS = 6;
const int NECK_LENGTH = 2;
static void PrintCredits()
{
Console.Clear();
Console.WriteLine("Bug\n");
Console.WriteLine("Original version in BASIC:");
Console.WriteLine(" Brian Leibowitz, 1978.");
Console.WriteLine(" Creative computing (Morristown, New Jersey, USA), 1978.\n");
Console.WriteLine("This version in C#:");
Console.WriteLine(" Copyright (c) 2024, Marcos Cruz (programandala.net)");
Console.WriteLine(" SPDX-License-Identifier: Fair\n");
Console.Write("Press Enter to read the instructions. ");
Console.ReadKey();
}
// Return the given string with its first character in uppercase and the
// rest in lowercase.
//
static string Capitalized(string str)
{
if (string.IsNullOrEmpty(str))
{
return string.Empty;
}
else
{
return char.ToUpper(str[0]) + str.Substring(1).ToLower();
}
}
// Write the given string the given number of times.
//
static void WriteTimes(string s, int n)
{
for (int t = 0; t < n; t++)
{
Console.Write(s);
}
}
// Print a table with the description of the bug parts.
//
static void PrintPartsTable()
{
const int COLUMNS = 3;
const int COLUMN_WIDTH = 8;
const int COLUMN_SEPARATION = 2;
// Headers
string[] header = {"Number", "Part", "Quantity"};
for (int i = 0; i < COLUMNS; i++)
{
Console.Write(header[i].PadRight(COLUMN_WIDTH + COLUMN_SEPARATION));
}
Console.WriteLine();
// Rulers
for (int i = 0; i < COLUMNS; i++)
{
WriteTimes("-", COLUMN_WIDTH);
if (i != COLUMNS - 1)
{
WriteTimes(" ", COLUMN_SEPARATION);
}
}
Console.WriteLine();
// Data
int[] partQuantity = new int[parts + 1];
partQuantity[(int) Part.body] = 1;
partQuantity[(int) Part.neck] = 1;
partQuantity[(int) Part.head] = 1;
partQuantity[(int) Part.feeler] = 2;
partQuantity[(int) Part.tail] = 1;
partQuantity[(int) Part.leg] = 6;
for (Part p = Part.body; (int) p < parts; p++)
{
Console.Write($"{(int) p}".PadRight(COLUMN_WIDTH + COLUMN_SEPARATION));
Console.Write(Capitalized(Enum.GetName(typeof(Part), p).PadRight(COLUMN_WIDTH + COLUMN_SEPARATION)));
Console.WriteLine(partQuantity[(int) p]);
}
}
static void PrintInstructions()
{
Console.Clear();
Console.WriteLine("Bug\n");
Console.WriteLine("The object is to finish your bug before I finish mine. Each number");
Console.WriteLine("stands for a part of the bug body.\n");
Console.WriteLine("I will roll the die for you, tell you what I rolled for you, what the");
Console.WriteLine("number stands for, and if you can get the part. If you can get the");
Console.WriteLine("part I will give it to you. The same will happen on my turn.\n");
Console.WriteLine("If there is a change in either bug I will give you the option of");
Console.WriteLine("seeing the pictures of the bugs. The numbers stand for parts as");
Console.WriteLine("follows:\n");
PrintPartsTable();
Console.Write("\nPress Enter to start. ");
Console.ReadKey();
}
// Print the given bug.
//
static void PrintBug(ABug bug)
{
if (bug.feelers > 0)
{
for (int i = 0; i < FEELER_LENGTH; i++)
{
Console.Write(" ");
for (int j = 0; j < bug.feelers; j++)
{
Console.Write($" {bug.feelerType}");
}
Console.WriteLine();
}
}
if (bug.head)
{
Console.WriteLine(" HHHHHHH");
Console.WriteLine(" H H");
Console.WriteLine(" H O O H");
Console.WriteLine(" H H");
Console.WriteLine(" H V H");
Console.WriteLine(" HHHHHHH");
}
if (bug.neck)
{
for (int i = 0; i < NECK_LENGTH; i++)
{
Console.WriteLine(" N N");
}
}
if (bug.body)
{
Console.WriteLine(" BBBBBBBBBBBB");
for (int i = 0; i < BODY_HEIGHT; i++)
{
Console.WriteLine(" B B");
}
if (bug.tail)
{
Console.WriteLine("TTTTTB B");
}
Console.WriteLine(" BBBBBBBBBBBB");
}
if (bug.legs > 0)
{
for (int i = 0; i < LEG_LENGTH; i++)
{
Console.Write(" ");
for (int j = 0; j < bug.legs; j++)
{
Console.Write(" L");
}
Console.WriteLine();
}
}
}
// Return `true` if the given bug is finished; otherwise return `false`.
//
static bool Finished(ABug bug)
{
return bug.feelers == MAX_FEELERS && bug.tail && bug.legs == MAX_LEGS;
}
// Return a random number from 1 to 6 (inclusive).
//
static int Dice()
{
Random rand = new Random();
return rand.Next(6) + 1;
}
// Array to convert a number to its equilavent text.
//
static string[] asText =
{
"no",
"a",
"two",
"three",
"four",
"five",
"six" }; // MAX_LEGS
// Return a string containing the given number and noun in their proper
// form.
//
static string Plural(int number, string noun)
{
return $"{asText[number]} {noun}{((number > 1) ? "s" : "")}";
}
// Add the given part to the given player's bug.
//
static bool AddPart(Part part, Player player)
{
bool changed = false;
switch (part)
{
case Part.body:
if (player.bug.body)
{
Console.WriteLine($", but {player.pronoun} already have a body.");
}
else
{
Console.WriteLine($"; {player.pronoun} now have a body:");
player.bug.body = true;
changed = true;
}
break;
case Part.neck:
if (player.bug.neck)
{
Console.WriteLine($", but {player.pronoun} already have a neck.");
}
else if (!player.bug.body)
{
Console.WriteLine($", but {player.pronoun} need a body first.");
}
else
{
Console.WriteLine($"; {player.pronoun} now have a neck:");
player.bug.neck = true;
changed = true;
}
break;
case Part.head:
if (player.bug.head)
{
Console.WriteLine($", but {player.pronoun} already have a head.");
}
else if (!player.bug.neck)
{
Console.WriteLine($", but {player.pronoun} need a a neck first.");
}
else
{
Console.WriteLine($"; {player.pronoun} now have a head:");
player.bug.head = true;
changed = true;
}
break;
case Part.feeler:
if (player.bug.feelers == MAX_FEELERS)
{
Console.WriteLine($", but {player.pronoun} have two feelers already.");
}
else if (!player.bug.head)
{
Console.WriteLine($", but {player.pronoun} need a head first.");
}
else
{
player.bug.feelers += 1;
Console.Write($"; {player.pronoun} now have",
Plural(player.bug.feelers, "feeler"));
Console.WriteLine(":");
changed = true;
}
break;
case Part.tail:
if (player.bug.tail)
{
Console.WriteLine($", but {player.pronoun} already have a tail.");
}
else if (!player.bug.body)
{
Console.WriteLine($", but {player.pronoun} need a body first.");
}
else
{
Console.WriteLine($"; {player.pronoun} now have a tail:");
player.bug.tail = true;
changed = true;
}
break;
case Part.leg:
if (player.bug.legs == MAX_LEGS)
{
Console.WriteLine($", but {player.pronoun} have {asText[MAX_LEGS]} feet already.");
}
else if (!player.bug.body)
{
Console.WriteLine($", but {player.pronoun} need a body first.");
}
else
{
player.bug.legs += 1;
Console.Write($"; {player.pronoun} now have {Plural(player.bug.legs, "leg")}");
Console.WriteLine(":");
changed = true;
}
break;
}
return changed;
}
// Ask the user to press the Enter key, wait for the input, then erase the;
// prompt text.
//
static void Prompt()
{
Console.Write("Press Enter to roll the dice. ");
Console.ReadKey();
}
// Play one turn for the given player, rolling the dice and updating his bug.
//
static void Turn(Player player)
{
Prompt();
int number = Dice();
Part part = (Part) number;
Console.Write($"{Capitalized(player.pronoun)} rolled a {number} ({part})");
if (AddPart(part, player))
{
Console.WriteLine();
PrintBug(player.bug);
}
Console.WriteLine();
}
// Print a message about the winner.
//
static void PrintWinner()
{
if (Finished(human.bug) && Finished(computer.bug))
{
Console.WriteLine("Both of our bugs are finished in the same number of turns!");
}
else if (Finished(human.bug))
{
Console.WriteLine($"{human.possessive} bug is finished.");
}
else if (Finished(computer.bug))
{
Console.WriteLine($"{computer.possessive} bug is finished.");
}
}
static bool GameOver()
{
return Finished(human.bug) || Finished(computer.bug);
}
// Execute the game loop.
//
static void Play()
{
Console.Clear();
while (!GameOver())
{
Turn(human);
Turn(computer);
}
PrintWinner();
}
// Init the players' data before a new game.
//
static void Init()
{
human.pronoun = "you";
human.possessive = "Your";
human.bug.feelerType = 'A';
computer.pronoun = "I";
computer.possessive = "My";
computer.bug.feelerType = 'F';
}
static void Main()
{
Init();
PrintCredits();
PrintInstructions();
Play();
Console.WriteLine("I hope you enjoyed the game, play it again soon!!");
}
}
In Chapel
/*
Bug
Original version in BASIC:
Brian Leibowitz, 1978.
Creative Computing (Morristown, New Jersey, USA), 1978.
This version in Chapel:
Copyright (c) 2025, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written on 2025-04-07.
Last modified 20250407T0201+0200.
*/
import IO;
import Random;
record Bug {
var body: bool;
var neck: bool;
var head: bool;
var feelers: int;
var feelerType: string;
var tail: bool;
var legs: int;
var finished: bool;
}
record Player {
var pronoun: string;
var possessive: string;
var bug: Bug;
}
var computer: Player;
var human: Player;
/// Bug body parts.
enum Part { body = 1, neck, head, feeler, tail, leg }
// Bug body attributes.
const bodyHeight = 2;
const feelerLength = 4;
const legLength = 2;
const maxFeelers = 2;
const maxLegs = 6;
const neckLength = 2;
/// Clear the screen, reset the attributes and move the cursor to the
/// home position.
proc clear() {
write("\x1B[2J\x1B[0m\x1B[H");
}
/// Move the cursor up by the given number of rows (defaults to 1),
/// without changing the column position.
proc cursorUp(rows: int = 1) {
write("\x1B[", rows, "A");
}
/// Erase the current line, without moving the cursor position.
proc eraseLine() {
write("\x1B[2K");
}
/// Move the cursor to the previous row, without changing
/// the column position, and erase its line.
proc erasePreviousLine() {
cursorUp();
eraseLine();
}
proc pressEnter(prompt: string) {
write(prompt);
IO.stdout.flush();
IO.readLine();
}
/// Clear the screen, display the credits and wait for a keypress.
proc printCredits() {
clear();
writeln("Bug\n");
writeln("Original version in BASIC:");
writeln(" Brian Leibowitz, 1978.");
writeln(" Creative computing (Morristown, New Jersey, USA), 1978.\n");
writeln("This version in Chapel:");
writeln(" Copyright (c) 2025, Marcos Cruz (programandala.net)");
writeln(" SPDX-License-Identifier: Fair\n");
pressEnter("Press Enter to read the instructions. ");
}
const instructions: string = """
The object is to finish your bug before I finish mine. Each number
stands for a part of the bug body.
I will roll the die for you, tell you what I rolled for you, what the
number stands for, and if you can get the part. If you can get the
part I will give it to you. The same will happen on my turn.
If there is a change in either bug I will give you the option of
seeing the pictures of the bugs. The numbers stand for parts as
follows:
""";
proc leftJustified(s: string, width: int): string {
return s + " " * (width - s.size);
}
/// Print a table with the bug parts' description.
proc printPartsTable() {
const columns = 3;
const columnWidth = 8;
const columnSeparation = 2;
// Headers
var header: [0 .. 2] string = ["Number", "Part", "Quantity"];
for i in 0 ..< columns {
write(leftJustified(header[i], columnWidth + columnSeparation));
}
writeln();
// Rulers
for i in 1 .. columns {
write(
"-" * columnWidth,
(if i < columns then " " * columnSeparation else "")
);
}
writeln();
// Data
var partQuantity: [Part.body .. Part.leg] int;
partQuantity[Part.body] = 1;
partQuantity[Part.neck] = 1;
partQuantity[Part.head] = 1;
partQuantity[Part.feeler] = 2;
partQuantity[Part.tail] = 1;
partQuantity[Part.leg] = 6;
for part in Part {
writeln(
leftJustified((part: int): string, columnWidth + columnSeparation),
leftJustified(((part): string).toTitle(), columnWidth + columnSeparation),
partQuantity[part]
);
}
}
/// Clear the screen, print the instructions and wait for a keypress.
proc printInstructions() {
clear();
writeln("Bug");
writeln(instructions);
printPartsTable();
pressEnter("\nPress Enter to start. ");
}
/// Print a bug head.
proc printHead() {
writeln(" HHHHHHH");
writeln(" H H");
writeln(" H O O H");
writeln(" H H");
writeln(" H V H");
writeln(" HHHHHHH");
}
/// Print the given bug.
proc printBug(bug: Bug) {
if bug.feelers {
for 0 ..< feelerLength {
write(" ");
for 0 ..< bug.feelers {
write(" ", bug.feelerType);
}
writeln();
}
}
if bug.head {
printHead();
}
if bug.neck {
for 0 ..< neckLength {
writeln(" N N");
}
}
if bug.body {
writeln(" BBBBBBBBBBBB");
for 0 ..< bodyHeight {
writeln(" B B");
}
if bug.tail {
writeln("TTTTTB B");
}
writeln(" BBBBBBBBBBBB");
}
if bug.legs {
for 0 ..< legLength {
write(" ");
for 0 ..< bug.legs {
write(" L");
}
writeln();
}
}
}
/// Return `true` if the given bug is finished; otherwise return `false`.
proc finished(bug: Bug): bool {
return bug.feelers == maxFeelers && bug.tail && bug.legs == maxLegs;
}
var rsInt = new Random.randomStream(int);
/// Return a random number between 1 and 6 (inclusive).
proc dice(): int {
return rsInt.next(1, 6);
}
/// Array to convert a number to its equilavent text.
var asText: [0 .. 6] string = [
"no",
"a",
"two",
"three",
"four",
"five",
"six" ]; // maxLegs
/// Return a string containing the given number
/// and the given noun in their proper form.
proc plural(number: int, noun: string): string {
return asText[number] + " " + noun + (if number > 1 then "s" else "");
}
/// Add the given part to the given player's bug.
proc addPart(part: Part, inout player: Player): bool {
var changed: bool = false;
select part {
when Part.body {
if player.bug.body {
writeln(", but ", player.pronoun, " already have a body.");
} else {
writeln("; ", player.pronoun, " now have a body:");
player.bug.body = true;
changed = true;
}
}
when Part.neck {
if player.bug.neck {
writeln(", but ", player.pronoun, " you already have a neck.");
} else if !player.bug.body {
writeln(", but ", player.pronoun, " need a body first.");
} else {
writeln("; ", player.pronoun, " now have a neck:");
player.bug.neck = true;
changed = true;
}
}
when Part.head {
if player.bug.head {
writeln(", but ", player.pronoun, " already have a head.");
} else if !player.bug.neck {
writeln(", but ", player.pronoun, " need a a neck first.");
} else {
writeln("; ", player.pronoun, " now have a head:");
player.bug.head = true;
changed = true;
}
}
when Part.feeler {
if player.bug.feelers == maxFeelers {
writeln(", but ", player.pronoun, " have two feelers already.");
} else if !player.bug.head {
writeln(", but ", player.pronoun, " need a head first.");
} else {
player.bug.feelers += 1;
writeln("; ", player.pronoun, " now have ",
plural(player.bug.feelers, "feeler"), ":");
changed = true;
}
}
when Part.tail {
if player.bug.tail {
writeln(", but ", player.pronoun, " already have a tail.");
} else if !player.bug.body {
writeln(", but ", player.pronoun, " need a body first.");
} else {
writeln("; ", player.pronoun, " now have a tail:");
player.bug.tail = true;
changed = true;
}
}
when Part.leg {
if player.bug.legs == maxLegs {
writeln(", but ", player.pronoun, " have ",
asText[maxLegs], " feet already.");
} else if !player.bug.body {
writeln(", but ", player.pronoun, " need a body first.");
} else {
player.bug.legs += 1;
writeln("; ", player.pronoun, " now have ",
plural(player.bug.legs, "leg"), ":");
changed = true;
}
}
}
return changed;
}
/// Ask the user to press the Enter key, wait for the input
/// and then erase the prompt text.
proc prompt() {
pressEnter("Press Enter to roll the dice. ");
erasePreviousLine();
}
/// Play one turn for the given player, rolling the dice
/// and updating his bug.
proc turn(inout player: Player) {
prompt();
var number: int = dice();
var part: Part = number: Part;
write((player.pronoun).toTitle(), " rolled a ", number, " (", part, ")");
if addPart(part, player) {
writeln();
printBug(player.bug);
player.bug.finished = finished(player.bug);
}
writeln();
}
/// Print a message about the winner.
proc printWinner() {
select true {
when human.bug.finished && computer.bug.finished do
writeln("Both of our bugs are finished in the same number of turns!");
when finished(human.bug) do
writeln(human.possessive, " bug is finished.");
when finished(computer.bug) do
writeln(computer.possessive, " bug is finished.");
}
}
/// Return `true` if either bug is finished, i.e. the game ending condition.
proc gameOver(): bool {
return human.bug.finished || computer.bug.finished;
}
/// Execute the game loop.
proc play() {
clear();
do {
turn(human);
turn(computer);
} while !gameOver();
printWinner();
}
/// Init player data before a new game.
proc initData() {
human.pronoun = "you";
human.possessive = "Your";
human.bug.feelerType = 'A';
human.bug.finished = false;
computer.pronoun = "I";
computer.possessive = "My";
computer.bug.feelerType = 'F';
computer.bug.finished = false;
}
proc main() {
initData();
printCredits();
printInstructions();
play();
writeln("I hope you enjoyed the game, play it again soon!!");
}
In Crystal
# Bug
# Original version in BASIC:
# Brian Leibowitz, 1978.
# Creative Computing (Morristown, New Jersey, USA), 1978.
# This version in Crystal:
# Copyright (c) 2023, 2024, Marcos Cruz (programandala.net)
# SPDX-License-Identifier: Fair
#
# Written in 2023-09, 2023-10, 2023-11, 2024-07.
# Last modified: 20251228T0052+0100.
class Bug
property body : Bool
property neck : Bool
property head : Bool
property feelers : Int32
property feeler_type : Char
property tail : Bool
property legs : Int32
def initialize
@body = false
@neck = false
@head = false
@feelers = 0
@feeler_type = '|'
@tail = false
@legs = 0
end
end
class Player
property pronoun : String
property possessive : String
property bug : Bug
def initialize
@pronoun = ""
@possessive = ""
@bug = Bug.new
end
end
# Bug body parts.
enum Part
Body = 1
Neck
Head
Feeler
Tail
Leg
end
FIRST_PART = Part::Body.value
LAST_PART = Part::Leg.value
PART_NAME = ["body", "neck", "head", "feeler", "tail", "leg"]
PART_QUANTITY = [1, 1, 1, 2, 1, 6]
# Bug body attributes.
BODY_HEIGHT = 2
FEELER_LENGTH = 4
LEG_LENGTH = 2
MAX_FEELERS = 2
MAX_LEGS = 6
NECK_LENGTH = 2
# Moves the cursor to the home position.
def home
print "\e[H"
end
# Clears the screen and moves the cursor to the home position.
def clear
print "\e[2J"
home
end
# Moves the cursor up by the given number of rows (defaults to 1), without
# changing the column position.
def cursor_up(rows = 1)
print "\e[#{rows}A"
end
# Erases the current line, without moving the cursor position.
def erase_line
print "\e[2K"
end
# Moves the cursor to the previous row, without changing the column position,
# and erases its line.
def erase_previous_line
cursor_up
erase_line
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
# Clears the screen, displays the credits and waits for the Enter key to be
# pressed.
def print_credits
clear
puts "Bug"
puts
puts "Original version in BASIC:"
puts " Brian Leibowitz, 1978."
puts " Creative computing (Morristown, New Jersey, USA), 1978."
puts
puts "This version in Crystal:"
puts " Copyright (c) 2023, 2024, Marcos Cruz (programandala.net)"
puts " SPDX-License-Identifier: Fair"
puts
press_enter "Press Enter to read the instructions. "
end
INSTRUCTIONS = "
The object is to finish your bug before I finish mine. Each number
stands for a part of the bug body.
I will roll the die for you, tell you what I rolled for you, what the
number stands for, and if you can get the part. If you can get the
part I will give it to you. The same will happen on my turn.
If there is a change in either bug I will give you the option of
seeing the pictures of the bugs. The numbers stand for parts as
follows:
"
COLUMNS = 3
COLUMN_WIDTH = 8
COLUMN_SEPARATION = 2
# Prints a table with the bug parts' description.
def print_parts_table
# Headers
header = ["Number", "Part", "Quantity"]
(0...COLUMNS).each do |i|
print header[i].ljust(COLUMN_WIDTH + COLUMN_SEPARATION)
end
puts
# Rulers
(0...COLUMNS).each do |i|
print "-" * COLUMN_WIDTH, i == COLUMNS - 1 ? "" : " " * COLUMN_SEPARATION
end
puts
# Data
(FIRST_PART..LAST_PART).each do |n|
print \
n.to_s.ljust(COLUMN_WIDTH + COLUMN_SEPARATION),
PART_NAME[n - 1].capitalize.ljust(COLUMN_WIDTH + COLUMN_SEPARATION),
PART_QUANTITY[n - 1], "\n"
end
end
# Clears the screen, prints the instructions and waits for a keypress.
def print_instructions
clear
puts "Bug"
puts INSTRUCTIONS, "\n"
print_parts_table
press_enter "\nPress Enter to start. "
end
# Prints a bug head.
def print_head
puts " HHHHHHH"
puts " H H"
puts " H O O H"
puts " H H"
puts " H V H"
puts " HHHHHHH"
end
# Prints the given bug.
def print_bug(bug : Bug)
if bug.feelers > 0
(0...FEELER_LENGTH).each do |i|
print " "
(0...bug.feelers).each do |j|
print " #{bug.feeler_type}"
end
puts
end
end
if bug.head
print_head
end
if bug.neck
(0...NECK_LENGTH).each do |i|
puts " N N"
end
end
if bug.body
puts " BBBBBBBBBBBB"
(0...BODY_HEIGHT).each do |i|
puts " B B"
end
if bug.tail
puts "TTTTTB B"
end
puts " BBBBBBBBBBBB"
end
if bug.legs > 0
(0...LEG_LENGTH).each do |i|
print " "
(0...bug.legs).each do |j|
print " L"
end
puts
end
end
end
# Returns `true` if the given bug is finished; otherwise returns `false`.
def finished?(bug : Bug) : Bool
bug.feelers == MAX_FEELERS && bug.tail && bug.legs == MAX_LEGS
end
# Array to convert a number to its equilavent text.
AS_TEXT = ["no", "a", "two", "three", "four", "five", "six"]
# Returns a string containing the given number and noun in their proper form.
def plural(number : Int, noun : String) : String
AS_TEXT[number] + " " + noun + (number > 1 ? "s" : "")
end
# Adds the given part to the given player's bug.
def add_part(part : Int32, player : Player) : Bool
changed = false
case part
when Part::Body.value
if player.bug.body
puts ", but #{player.pronoun} already have a body."
else
puts "; #{player.pronoun} now have a body:"
player.bug.body = true
changed = true
end
when Part::Neck.value
if player.bug.neck
puts ", but #{player.pronoun} already have a neck."
elsif !player.bug.body
puts ", but #{player.pronoun} need a body first."
else
puts "; #{player.pronoun} now have a neck:"
player.bug.neck = true
changed = true
end
when Part::Head.value
if player.bug.head
puts ", but #{player.pronoun} already have a head."
elsif !player.bug.neck
puts ", but #{player.pronoun} need a a neck first."
else
puts "; #{player.pronoun} now have a head:"
player.bug.head = true
changed = true
end
when Part::Feeler.value
if player.bug.feelers == MAX_FEELERS
puts ", but #{player.pronoun} have two feelers already."
elsif !player.bug.head
puts ", but #{player.pronoun} need a head first."
else
player.bug.feelers += 1
print "; #{player.pronoun} now have #{plural(player.bug.feelers, "feeler")}"
puts ":"
changed = true
end
when Part::Tail.value
if player.bug.tail
puts ", but #{player.pronoun} already have a tail."
elsif !player.bug.body
puts ", but #{player.pronoun} need a body first."
else
puts "; #{player.pronoun} now have a tail:"
player.bug.tail = true
changed = true
end
when Part::Leg.value
if player.bug.legs == MAX_LEGS
print ", but #{player.pronoun} have #{AS_TEXT[MAX_LEGS]} feet already."
elsif !player.bug.body
puts ", but #{player.pronoun} need a body first."
else
player.bug.legs += 1
print "; #{player.pronoun} now have #{plural(player.bug.legs, "leg")}"
puts ":"
changed = true
end
end
changed
end
# Asks the user to press the Enter key, waits for the input, then erases the
# prompt text.
def prompt
press_enter "Press Enter to roll the dice. "
erase_previous_line
end
# Plays one turn for the given player, rolling the dice and updating his bug.
def turn(player : Player)
prompt
part = rand(FIRST_PART..LAST_PART) # dice
print "#{player.pronoun.capitalize} rolled a #{part} (#{PART_NAME[part - 1]})"
if add_part(part, player)
puts
print_bug(player.bug)
end
puts
end
# Prints a message about the winner.
def print_winner(p1, p2 : Player)
if finished?(p1.bug) && finished?(p2.bug)
puts "Both of our bugs are finished in the same number of turns!"
elsif finished?(p1.bug)
puts "#{p1.possessive} bug is finished."
elsif finished?(p2.bug)
puts "#{p2.possessive} bug is finished."
end
end
# Inits the data of a player.
def init(player : Player, pronoun : String, possessive : String, feeler_type : Char)
player.pronoun = pronoun
player.possessive = possessive
player.bug.feeler_type = feeler_type
end
# Executes the game loop.
def play
clear
computer = Player.new
human = Player.new
init human, "you", "your", 'A'
init computer, "I", "My", 'F'
while !(finished?(human.bug) || finished?(computer.bug))
turn human
turn computer
end
print_winner human, computer
end
print_credits
print_instructions
play
puts "I hope you enjoyed the game, play it again soon!!"
In D
/*
Bug
Original version in BASIC:
Brian Leibowitz, 1978.
Creative Computing (Morristown, New Jersey, USA), 1978.
This version in D:
Copyright (c) 2023, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written in 2023-03-26/29.
Last modified 20251220T0637+0100.
*/
module bug;
/// Bug type.
struct Bug
{
bool body;
bool neck;
bool head;
int feelers;
char feelerType;
bool tail;
int legs;
bool finished;
}
/// Player type.
struct Player
{
string pronoun;
string possessive;
Bug bug;
}
/// Players.
Player computer, human;
/// Bug body parts.
enum Part { body = 1, neck, head, feeler, tail, leg }
// Bug body attributes.
enum bodyHeight = 2;
enum feelerLength = 4;
enum legLength = 2;
enum maxFeelers = 2;
enum maxLegs = 6;
enum neckLength = 2;
/// Clear the screen, reset the attributes and move the cursor to the
/// home position.
void clear()
{
import std.stdio : write;
write("\033[2J\033[0m\033[H");
}
/// Move the cursor up by the given number of rows (defaults to 1),
/// without changing the column position.
void cursorUp(int rows = 1)
{
import std.stdio : write;
write("\033[", rows, "A");
}
/// Erase the current line, without moving the cursor position.
void eraseLine()
{
import std.stdio : write;
write("\033[2K");
}
/// Move the cursor to the previous row, without changing
/// the column position, and erase its line.
void erasePreviousLine()
{
cursorUp();
eraseLine();
}
/// Clear the screen, display the credits and wait for a keypress.
void printCredits()
{
import std.stdio : readln;
import std.stdio : write;
import std.stdio : writeln;
clear();
writeln("Bug\n");
writeln("Original version in BASIC:");
writeln(" Brian Leibowitz, 1978.");
writeln(" Creative computing (Morristown, New Jersey, USA), 1978.\n");
writeln("This version in D:");
writeln(" Copyright (c) 2023, Marcos Cruz (programandala.net)");
writeln(" SPDX-License-Identifier: Fair\n");
write("Press Enter to read the instructions. ");
readln();
}
string instructions = "
The object is to finish your bug before I finish mine. Each number
stands for a part of the bug body.
I will roll the die for you, tell you what I rolled for you, what the
number stands for, and if you can get the part. If you can get the
part I will give it to you. The same will happen on my turn.
If there is a change in either bug I will give you the option of
seeing the pictures of the bugs. The numbers stand for parts as
follows:
";
/// Print a table with the bug parts' description.
void printPartsTable()
{
import std.array : replicate;
import std.conv : to;
import std.stdio : write;
import std.stdio : writeln;
import std.string : capitalize, leftJustify;
enum columns = 3;
enum columnWidth = 8;
enum columnSeparation = 2;
// Headers
string[] header = ["Number", "Part", "Quantity"];
foreach (i; 0 .. columns)
{
write(leftJustify(header[i], columnWidth + columnSeparation));
}
writeln();
// Rulers
foreach (i; 0 .. columns)
{
write(
replicate("-", columnWidth),
(i == columns - 1 ? "" : replicate(" ", columnSeparation)));
}
writeln();
// Data
int[Part] partQuantity;
partQuantity[Part.body] = 1;
partQuantity[Part.neck] = 1;
partQuantity[Part.head] = 1;
partQuantity[Part.feeler] = 2;
partQuantity[Part.tail] = 1;
partQuantity[Part.leg] = 6;
for (Part part = Part.min; part <= Part.max; ++part)
{
writeln(
leftJustify(to!string(to!int(part)), columnWidth + columnSeparation),
leftJustify(capitalize(to!string(part)), columnWidth + columnSeparation),
partQuantity[part]
);
}
}
/// Clear the screen, print the instructions and wait for a keypress.
void printInstructions()
{
import std.stdio : readln;
import std.stdio : write;
import std.stdio : writeln;
clear();
writeln("Bug");
writeln(instructions);
printPartsTable();
write("\nPress Enter to start. ");
readln();
}
/// Print a bug head.
void printHead()
{
import std.stdio : writeln;
writeln(" HHHHHHH");
writeln(" H H");
writeln(" H O O H");
writeln(" H H");
writeln(" H V H");
writeln(" HHHHHHH");
}
/// Print the given bug.
void printBug(Bug bug)
{
import std.stdio : write;
import std.stdio : writeln;
if (bug.feelers)
{
foreach (i; 0 .. feelerLength)
{
write(" ");
foreach (j; 0 .. bug.feelers)
{
write(" ", bug.feelerType);
}
writeln();
}
}
if (bug.head)
{
printHead();
}
if (bug.neck)
{
foreach (i; 0 .. neckLength)
{
writeln(" N N");
}
}
if (bug.body)
{
writeln(" BBBBBBBBBBBB");
foreach (i; 0 .. bodyHeight)
{
writeln(" B B");
}
if (bug.tail)
{
writeln("TTTTTB B");
}
writeln(" BBBBBBBBBBBB");
}
if (bug.legs)
{
foreach (i; 0 .. legLength)
{
write(" ");
foreach (j; 0 .. bug.legs)
{
write(" L");
}
writeln();
}
}
}
/// Return `true` if the given bug is finished; otherwise return `false`.
bool finished(Bug bug)
{
return bug.feelers == maxFeelers && bug.tail && bug.legs == maxLegs;
}
/// Return a random number between 1 and 6 (inclusive).
int dice()
{
import std.random : uniform;
return uniform(1, 7);
}
/// Array to convert a number to its equilavent text.
string[] asText = [
"no",
"a",
"two",
"three",
"four",
"five",
"six" ]; // maxLegs
/// Return a string containing the given number
/// and the given noun in their proper form.
string plural(int number, string noun)
{
return asText[number] ~ " " ~ noun ~ ((number > 1) ? "s" : "");
}
/// Add the given part to the given player's bug.
bool addPart(Part part, ref Player player)
{
import std.stdio : writeln;
bool changed = false;
final switch (part)
{
case Part.body:
if (player.bug.body)
{
writeln(", but ", player.pronoun, " already have a body.");
}
else
{
writeln("; ", player.pronoun, " now have a body:");
player.bug.body = true;
changed = true;
}
break;
case Part.neck:
if (player.bug.neck)
{
writeln(", but ", player.pronoun, " you already have a neck.");
}
else if (!player.bug.body)
{
writeln(", but ", player.pronoun, " need a body first.");
}
else
{
writeln("; ", player.pronoun, " now have a neck:");
player.bug.neck = true;
changed = true;
}
break;
case Part.head:
if (player.bug.head)
{
writeln(", but ", player.pronoun, " already have a head.");
}
else if (!player.bug.neck)
{
writeln(", but ", player.pronoun, " need a a neck first.");
}
else
{
writeln("; ", player.pronoun, " now have a head:");
player.bug.head = true;
changed = true;
}
break;
case Part.feeler:
if (player.bug.feelers == maxFeelers)
{
writeln(", but ", player.pronoun, " have two feelers already.");
}
else if (!player.bug.head)
{
writeln(", but ", player.pronoun, " need a head first.");
}
else
{
player.bug.feelers++;
writeln("; ", player.pronoun, " now have ",
plural(player.bug.feelers, "feeler"), ":");
changed = true;
}
break;
case Part.tail:
if (player.bug.tail)
{
writeln(", but ", player.pronoun, " already have a tail.");
}
else if (!player.bug.body)
{
writeln(", but ", player.pronoun, " need a body first.");
}
else
{
writeln("; ", player.pronoun, " now have a tail:");
player.bug.tail = true;
changed = true;
}
break;
case Part.leg:
if (player.bug.legs == maxLegs)
{
writeln(", but ", player.pronoun, " have ",
asText[maxLegs], " feet already.");
}
else if (!player.bug.body)
{
writeln(", but ", player.pronoun, " need a body first.");
}
else
{
player.bug.legs++;
writeln("; ", player.pronoun, " now have ",
plural(player.bug.legs, "leg"), ":");
changed = true;
}
break;
}
return changed;
}
/// Ask the user to press the Enter key, wait for the input
/// and then erase the prompt text.
void prompt()
{
import std.stdio : readln;
import std.stdio : write;
write("Press Enter to roll the dice. ");
readln();
erasePreviousLine();
}
/// Play one turn for the given player, rolling the dice
/// and updating his bug.
void turn(ref Player player)
{
import std.stdio : write;
import std.stdio : writeln;
import std.string : capitalize;
import std.string : strip;
prompt();
int number = dice();
Part part = cast(Part)number;
write(capitalize(player.pronoun), " rolled a ", number, " (", part, ")");
if (addPart(part, player))
{
writeln();
printBug(player.bug);
player.bug.finished = finished(player.bug);
}
writeln();
}
/// Print a message about the winner.
void printWinner()
{
import std.stdio : writeln;
if (human.bug.finished && computer.bug.finished)
{
writeln("Both of our bugs are finished in the same number of turns!");
}
else if (finished(human.bug))
{
writeln(human.possessive, " bug is finished.");
}
else if (finished(computer.bug))
{
writeln(computer.possessive, " bug is finished.");
}
}
/// Return `true` if either bug is finished, i.e. the game ending condition.
bool gameOver()
{
return human.bug.finished || computer.bug.finished;
}
/// Execute the game loop.
void play()
{
clear();
do
{
turn(human);
turn(computer);
} while (!gameOver());
printWinner();
}
/// Init player data before a new game.
void init()
{
human.pronoun = "you";
human.possessive = "Your";
human.bug.feelerType = 'A';
human.bug.finished = false;
computer.pronoun = "I";
computer.possessive = "My";
computer.bug.feelerType = 'F';
computer.bug.finished = false;
}
void main()
{
import std.stdio : writeln;
init();
printCredits();
printInstructions();
play();
writeln("I hope you enjoyed the game, play it again soon!!");
}
In Hare
// Bug
//
// Original version in BASIC:
// Brian Leibowitz, 1978.
// Creative Computing (Morristown, New Jersey, USA), 1978.
//
// This version in Hare:
// Copyright (c) 2025, Marcos Cruz (programandala.net)
// SPDX-License-Identifier: Fair
//
// Written in 2025-02-12/15.
//
// Last modified: 20260213T1645+0100.
// Modules {{{1
// =============================================================================
use ascii;
use bufio;
use fmt;
use math::random;
use os;
use strconv;
use strings;
use time;
// Data {{{1
// =============================================================================
type Bug = struct {
body: bool,
neck: bool,
head: bool,
feelers: int,
feeler_type: rune,
tail: bool,
legs: int,
};
type Player = struct {
pronoun: str,
possessive: str,
bug: Bug,
};
let computer = Player {
pronoun = "I",
possessive = "My",
bug = Bug {
body = false,
neck = false,
head = false,
feelers = 0,
feeler_type = 'F',
tail = false,
legs = 0,
}
};
let human = Player {
pronoun = "you",
possessive = "Your",
bug = Bug {
body = false,
neck = false,
head = false,
feelers = 0,
feeler_type = 'A',
tail = false,
legs = 0,
}
};
type bug_part = enum int {BODY = 1, NECK, HEAD, FEELER, TAIL, LEG};
def FIRST_PART = bug_part::BODY: int;
def LAST_PART = bug_part::LEG: int;
fn part_quantity(part: bug_part) int = {
return switch (part) {
case bug_part::BODY => yield 1;
case bug_part::NECK => yield 1;
case bug_part::HEAD => yield 1;
case bug_part::FEELER => yield 2;
case bug_part::TAIL => yield 1;
case bug_part::LEG => yield 6;
};
};
fn part_name(part: bug_part) str = {
return switch (part) {
case bug_part::BODY => yield "body";
case bug_part::NECK => yield "neck";
case bug_part::HEAD => yield "head";
case bug_part::FEELER => yield "feeler";
case bug_part::TAIL => yield "tail";
case bug_part::LEG => yield "leg";
};
};
// Bug body attributes.
//
def BODY_HEIGHT = 2;
def FEELER_LENGTH = 4;
def LEG_LENGTH = 2;
def MAX_FEELERS = 2;
def MAX_LEGS = 6;
def NECK_LENGTH = 2;
// Terminal {{{1
// =============================================================================
def NORMAL_STYLE = 0;
fn move_cursor_home() void = {
fmt::print("\x1B[H")!;
};
fn move_cursor_up(lines: int = 1) void = {
fmt::printf("\x1B[{}A", lines)!;
};
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();
};
// Erase the entire current line and move the cursor to the start of the line.
//
fn erase_line() void = {
fmt::print("\x1B[2K")!;
};
// User input {{{1
// =============================================================================
fn print_prompt(prompt: str = "") void = {
fmt::print(prompt)!;
bufio::flush(os::stdout)!;
};
fn accept_string(prompt: str = "") str = {
print_prompt(prompt);
const buffer = match (bufio::read_line(os::stdin)!) {
case let buffer: []u8 =>
yield buffer;
case =>
return "";
};
defer free(buffer);
return strings::dup(strings::fromutf8(buffer)!)!;
};
fn press_enter(prompt: str = "") void = {
free(accept_string(prompt));
};
// Credits and instructions {{{1
// =============================================================================
// Clear the screen, display the credits and wait for a keypress.
//
fn print_credits() void = {
clear_screen();
fmt::println("Bug\n")!;
fmt::println("Original version in BASIC:")!;
fmt::println(" Brian Leibowitz, 1978.")!;
fmt::println(" Creative computing (Morristown, New Jersey, USA), 1978.\n")!;
fmt::println("This version in Hare:")!;
fmt::println(" Copyright (c) 2025, Marcos Cruz (programandala.net)")!;
fmt::println(" SPDX-License-Identifier: Fair\n")!;
press_enter("Press Enter to read the instructions. ");
};
def INSTRUCTIONS = `
The object is to finish your bug before I finish mine. Each number
stands for a part of the bug body.
I will roll the die for you, tell you what I rolled for you, what the
number stands for, and if you can get the part. If you can get the
part I will give it to you. The same will happen on my turn.
If there is a change in either bug I will give you the option of
seeing the pictures of the bugs. The numbers stand for parts as
follows:
`;
// Clear the screen, print the instructions and wait for a keypress.
//
fn print_instructions() void = {
clear_screen();
fmt::println("Bug")!;
fmt::println(INSTRUCTIONS)!;
print_parts_table();
press_enter("\nPress Enter to start. ");
};
// Strings {{{1
// =============================================================================
fn to_capital(s: str) str = {
const initial = ascii::strupper(strings::sub(s, 0, 1))!;
defer free(initial);
return strings::concat(initial, strings::sub(s, 1))!;
};
fn repeat(s: str, n: int) str = {
let result = "";
for (let i: int = 0; i < n; i += 1) {
result = strings::concat(result, s)!;
};
return result;
};
// Pseudo-random numbers {{{1
// =============================================================================
let rand: random::random = 0;
// Return a random number from 1 to 6 (inclusive).
//
fn dice(r: *random::random) int = {
return (random::u32n(r, 6) + 1): int;
};
fn randomize() void = {
rand = random::init(time::now(time::clock::MONOTONIC).sec: u64);
};
// Main {{{1
// =============================================================================
// Print a table with the description of the bug parts.
//
fn print_parts_table() void = {
def COLUMNS = 3;
def COLUMN_WIDTH = 8;
def COLUMN_SEPARATION = 2;
const format_string = strings::concat(
"{:-",
strconv::itos(COLUMN_WIDTH + COLUMN_SEPARATION),
"}")!;
// Headers
const header: [_]str = ["Number", "Part", "Quantity"];
for (let i = 0; i < COLUMNS; i += 1) {
fmt::printf(format_string, header[i])!;
};
fmt::println()!;
// Rulers
const ruler = repeat("-", COLUMN_WIDTH);
defer free(ruler);
const padding = repeat(" ", COLUMN_SEPARATION - 1);
defer free(padding);
for (let i = 0; i < COLUMNS; i += 1) {
fmt::print(ruler, if (i == COLUMNS - 1) "" else padding)!;
};
fmt::println()!;
// Data
for (let p = FIRST_PART; p <= LAST_PART; p += 1) {
let part = p: bug_part;
fmt::printf(format_string, p)!;
let name = to_capital(part_name(part));
defer free(name);
fmt::printf(format_string, name)!;
fmt::printf(format_string, part_quantity(part))!;
fmt::println()!;
};
};
// Print a bug head.
//
fn print_head() void = {
fmt::println(" HHHHHHH")!;
fmt::println(" H H")!;
fmt::println(" H O O H")!;
fmt::println(" H H")!;
fmt::println(" H V H")!;
fmt::println(" HHHHHHH")!;
};
// Print the given bug.
//
fn print_bug(bug: Bug) void = {
if (bug.feelers > 0) {
for (let i = 0; i < FEELER_LENGTH; i += 1) {
fmt::print(" ")!;
for (let i = 0; i < bug.feelers; i += 1) {
fmt::print(" ", bug.feeler_type)!;
};
fmt::println()!;
};
};
if (bug.head) {
print_head();
};
if (bug.neck) {
for (let i = 0; i < NECK_LENGTH; i += 1) {
fmt::println(" N N")!;
};
};
if (bug.body) {
fmt::println(" BBBBBBBBBBBB")!;
for (let i = 0; i < BODY_HEIGHT; i += 1) {
fmt::println(" B B")!;
};
if (bug.tail) {
fmt::println("TTTTTB B")!;
};
fmt::println(" BBBBBBBBBBBB")!;
};
if (bug.legs > 0) {
for (let i = 0; i < LEG_LENGTH; i += 1) {
fmt::print(" ")!;
for (let i = 0; i < bug.legs; i += 1) {
fmt::print(" L")!;
};
fmt::println()!;
};
};
};
// Return `true` if the given bug is finished; otherwise return `false`.
//
fn finished(bug: Bug) bool = {
return bug.feelers == MAX_FEELERS && bug.tail && bug.legs == MAX_LEGS;
};
// Array to convert a number to its equilavent text.
//
let as_text: [_]str = [
"no",
"a",
"two",
"three",
"four",
"five",
"six" ]; // MAX_LEGS
// Return a string containing the given number and noun in their proper form.
//
fn plural(number: int, noun: str) str = {
return strings::concat(
as_text[number],
" ",
noun,
if (number > 1) "s" else ""
)!;
};
// Add the given part to the given player's bug.
//
fn add_part(part: bug_part, player: *Player) bool = {
let changed: bool = false;
switch (part) {
case bug_part::BODY =>
if (player.bug.body) {
fmt::println(", but", player.pronoun, "already have a body.")!;
} else {
fmt::println(";", player.pronoun, "now have a body:")!;
player.bug.body = true;
changed = true;
};
case bug_part::NECK =>
if (player.bug.neck) {
fmt::println(", but", player.pronoun, "already have a neck.")!;
} else if (!player.bug.body) {
fmt::println(", but", player.pronoun, "need a body first.")!;
} else {
fmt::println(";", player.pronoun, "now have a neck:")!;
player.bug.neck = true;
changed = true;
};
case bug_part::HEAD =>
if (player.bug.head) {
fmt::println(", but", player.pronoun, "already have a head.")!;
} else if (!player.bug.neck) {
fmt::println(", but", player.pronoun, "need a a neck first.")!;
} else {
fmt::println(";", player.pronoun, "now have a head:")!;
player.bug.head = true;
changed = true;
};
case bug_part::FEELER =>
if (player.bug.feelers == MAX_FEELERS) {
fmt::println(", but", player.pronoun, "have two feelers already.")!;
} else if (!player.bug.head) {
fmt::println(", but", player.pronoun, "need a head first.")!;
} else {
player.bug.feelers += 1;
fmt::print(";", player.pronoun, "now have",
plural(player.bug.feelers, "feeler"))!;
fmt::println(":")!;
changed = true;
};
case bug_part::TAIL =>
if (player.bug.tail) {
fmt::println(", but", player.pronoun, "already have a tail.")!;
} else if (!player.bug.body) {
fmt::println(", but", player.pronoun, "need a body first.")!;
} else {
fmt::println(";", player.pronoun, "now have a tail:")!;
player.bug.tail = true;
changed = true;
};
case bug_part::LEG =>
if (player.bug.legs == MAX_LEGS) {
fmt::println(", but", player.pronoun, "have",
as_text[MAX_LEGS], "feet already.")!;
} else if (!player.bug.body) {
fmt::println(", but", player.pronoun, "need a body first.")!;
} else {
player.bug.legs += 1;
fmt::print(";", player.pronoun, "now have",
plural(player.bug.legs, "leg"))!;
fmt::println(":")!;
changed = true;
};
};
return changed;
};
// Play one turn for the given player, rolling the dice and updating his bug.
//
fn turn(player: *Player) void = {
press_enter("Press Enter to roll the dice. ");
move_cursor_up(1);
erase_line();
const number: int = dice(&rand);
const part = number: bug_part;
const pronoun = to_capital(player.pronoun);
defer free(pronoun);
fmt::printf("{} rolled a {} ({})", pronoun, number, part_name(part))!;
if (add_part(part, player)) {
fmt::println()!;
print_bug(player.bug);
};
fmt::println()!;
};
// Print a message about the winner.
//
fn print_winner() void = {
if (finished(human.bug) && finished(computer.bug)) {
fmt::println("Both of our bugs are finished in the same number of turns!")!;
} else if (finished(human.bug)) {
fmt::println(human.possessive, "bug is finished.")!;
} else if (finished(computer.bug)) {
fmt::println(computer.possessive, "bug is finished.")!;
};
};
// Return `true` if either bug is finished, i.e. the game ending condition.
//
fn game_over() bool = {
return finished(human.bug) || finished(computer.bug);
};
// Execute the game loop.
//
fn play() void = {
clear_screen();
for (!game_over()) {
turn(&human);
turn(&computer);
};
print_winner();
};
fn init() void = {
randomize();
};
fn bye() void = {
fmt::println("I hope you enjoyed the game, play it again soon!!")!;
};
export fn main() void = {
init();
print_credits();
print_instructions();
play();
bye();
};
In Janet
# Bug
# Original version in BASIC:
# Brian Leibowitz, 1978.
# Creative Computing (Morristown, New Jersey, USA), 1978.
# This version in Janet:
# Copyright (c) 2025, Marcos Cruz (programandala.net)
# SPDX-License-Identifier: Fair
#
# Written in 2025-12-27/30.
# Last modified: 20251230T1346+0100.
(def player-model
@{:pronoun ""
:possesive ""
:body false
:neck false
:head false
:feelers 0
:feeler-type "|"
:tail false
:legs 0})
(def player
@{:human
(table/setproto
@{:pronoun "you"
:possessive "your"
:feeler-type "A"}
player-model)
:computer
(table/setproto
@{:pronoun "I"
:possessive "my"
:feeler-type "F"}
player-model)})
(def body 1)
(def neck 2)
(def head 3)
(def feeler 4)
(def tail 5)
(def leg 6)
(def first-part body)
(def last-part leg)
(def part-name ["body" "neck" "head" "feeler" "tail" "leg"])
(def part-quantity [1 1 1 2 1 6])
(def body-height 2)
(def feeler-length 4)
(def leg-length 2)
(def max-feelers 2)
(def max-legs 6)
(def neck-length 2)
(defn move-cursor-home []
(prin "\e[H"))
(defn clear-screen []
(prin "\e[2J")
(move-cursor-home))
(defn move-cursor-up [&opt rows]
(default rows 1)
(prin "\e[" rows "A"))
(defn erase-line []
(prin "\e[2K"))
(defn erase-previous-line []
(move-cursor-up)
(erase-line))
(defn command [&opt prompt-text]
(default prompt-text "> ")
(prin prompt-text)
(flush)
(string/trim (getline)))
(defn press-enter [prompt-text]
(unless (= (length (command prompt-text)) 0)) (break))
(defn print-credits []
(clear-screen)
(print "Bug\n")
(print "Original version in BASIC:")
(print " Brian Leibowitz, 1978.")
(print " Creative computing (Morristown, New Jersey, USA), 1978.\n")
(print "This version in Janet:")
(print " Copyright (c) 2025, Marcos Cruz (programandala.net)")
(print " SPDX-License-Identifier: Fair\n")
(press-enter "Press Enter to read the instructions. "))
(def columns 3)
(def column-width 8)
(def column-separation 2)
(defn capitalized [s]
(string (string/ascii-upper (string/slice s 0 1)) (string/slice s 1)))
(defn left-justified [s n]
(string/format (string "%-" n "s") s))
(defn print-parts-table []
(def width (+ column-width column-separation))
# Headers
(def header ["Number" "Part" "Quantity"])
(for i 0 columns
(prin (left-justified (get header i) width)))
(print)
# Rulers
(for i 0 columns
(prin
(string/repeat "-" column-width)
(unless (= i (- columns 1))
(string/repeat " " column-separation))))
(print)
# Data
(for n first-part (+ last-part 1)
(print
(left-justified (string n) width)
(left-justified (capitalized (get part-name (- n 1))) width)
(get part-quantity (- n 1)))))
(defn print-instructions []
(clear-screen)
(print "Bug\n")
(print
`The object is to finish your bug before I finish mine. Each number
stands for a part of the bug body.
I will roll the die for you, tell you what I rolled for you, what the
number stands for, and if you can get the part. If you can get the
part I will give it to you. The same will happen on my turn.
If there is a change in either bug I will give you the option of
seeing the pictures of the bugs. The numbers stand for parts as
follows:`)
(print)
(print-parts-table)
(press-enter "\nPress Enter to start. "))
(defn print-head []
(print " HHHHHHH")
(print " H H")
(print " H O O H")
(print " H H")
(print " H V H")
(print " HHHHHHH"))
(defn print-bug [player]
(when (> (get player :feelers) 0)
(for i 0 feeler-length
(prin " ")
(for j 0 (get player :feelers)
(prin " " (get player :feeler-type)))
(print)))
(when (get player :head)
(print-head))
(when (get player :neck)
(for i 0 neck-length
(print " N N")))
(when (get player :body)
(print " BBBBBBBBBBBB")
(for i 0 body-height
(print " B B"))
(when (get player :tail)
(print "TTTTTB B"))
(print " BBBBBBBBBBBB"))
(when (> (get player :legs) 0)
(for i 0 leg-length
(prin " ")
(for j 0 (get player :legs)
(prin " L"))
(print))))
(def as-text ["no" "a" "two" "three" "four" "five" "six"])
(defn plural [number noun]
(string (get as-text number) " " noun (when (> number 1) "s")))
(defn add-part [part player]
(var changed false)
(case part
body
(if (get player :body)
(print ", but " (get player :pronoun) " already have a body.")
(do
(print "; " (get player :pronoun) " now have a body:")
(put player :body true)
(set changed true)))
neck
(cond
(get player :neck)
(print ", but " (get player :pronoun) " already have a neck.")
(not (get player :body))
(print ", but " (get player :pronoun) " need a body first.")
(do
(print "; " (get player :pronoun) " now have a neck:")
(put player :neck true)
(set changed true)))
head
(cond
(get player :head)
(print ", but " (get player :pronoun) " already have a head.")
(not (get player :neck))
(print ", but " (get player :pronoun) " need a a neck first.")
(do
(print "; " (get player :pronoun) " now have a head:")
(put player :head true)
(set changed true)))
feeler
(cond
(= (get player :feelers) max-feelers)
(print ", but " (get player :pronoun) " have two feelers already.")
(not (get player :head))
(print ", but " (get player :pronoun) " need a head first.")
(do
(+= (player :feelers) 1)
(prin
"; " (get player :pronoun) " now have "
(plural (get player :feelers) "feeler"))
(print ":")
(set changed true)))
tail
(cond
(get player :tail)
(print ", but " (get player :pronoun) " already have a tail.")
(not (get player :body))
(print ", but " (get player :pronoun) " need a body first.")
(do
(print "; " (get player :pronoun) " now have a tail:")
(put player :tail true)
(set changed true)))
leg
(cond
(= (get player :legs) max-legs)
(prin
", but " (get player :pronoun)
" have " (get as-text max-legs) " feet already.")
(not (get player :body))
(print ", but " (get player :pronoun) " need a body first.")
(do
(+= (player :legs) 1)
(prin
"; " (get player :pronoun)
" now have " (plural (get player :legs) "leg"))
(print ":")
(set changed true))))
changed)
(defn prompt-player []
(press-enter "Press Enter to roll the dice. ")
(erase-previous-line))
(defn random-int-in-range [minimum maximum]
(def random-number-generator (math/rng (os/cryptorand 16)))
(+ (math/rng-int random-number-generator (- maximum minimum)) minimum))
(defn dice []
(random-int-in-range first-part (+ 1 last-part)))
(defn turn [player]
(prompt-player)
(def part (dice))
(prin
(capitalized (get player :pronoun))
" rolled a " part " (" (get part-name (- part 1)) ")")
(when (add-part part player)
(print)
(print-bug player))
(print))
(defn finished? [player-id]
(and
(= max-feelers (get (get player player-id) :feelers))
(get (get player player-id) :tail)
(= max-legs (get (get player player-id) :legs))))
(defn print-finished [player-id]
(print (capitalized (get (get player player-id) :possessive)) " bug is finished."))
(defn print-winner []
(cond
(and (finished? :human) (finished? :computer))
(print "Both of our bugs are finished in the same number of turns!")
(finished? :human)
(print-finished :human)
(finished? :computer)
(print-finished :computer)))
(defn play []
(clear-screen)
(while (not (or (finished? :human) (finished? :computer)))
(turn (get player :human))
(turn (get player :computer)))
(print-winner))
(defn main [& args]
(print-credits)
(print-instructions)
(play)
(print "I hope you enjoyed the game, play it again soon!!"))
In Julia
# Bug
# Original version in BASIC:
# Brian Leibowitz, 1978.
# Creative Computing (Morristown, New Jersey, USA), 1978.
# This version in Julia:
# Copyright (c) 2024, Marcos Cruz (programandala.net)
# SPDX-License-Identifier: Fair
#
# Written on 2024-07-04.
# Last modified: 20240705T1630+0200.
mutable struct Bug
body::Bool
neck::Bool
head::Bool
feelers::Int
feeler_type::Char
tail::Bool
legs::Int
end
mutable struct Player
pronoun::String
possessive::String
bug::Bug
end
# Bug body parts.
@enum Part begin
body = 1
neck
head
feeler
tail
leg
end
const FIRST_PART = Int(body)
const LAST_PART = Int(leg)
const PARTS = LAST_PART
const PART_NAME = ["body", "neck", "head", "feeler", "tail", "leg"]
const PART_QUANTITY = [1, 1, 1, 2, 1, 6]
# Bug body attributes.
const BODY_HEIGHT = 2
const FEELER_LENGTH = 4
const LEG_LENGTH = 2
const MAX_FEELERS = 2
const MAX_LEGS = 6
const NECK_LENGTH = 2
# Move the cursor to the home position.
function home()
print("\e[H")
end
# Clear the screen and move the cursor to the home position.
function clear_screen()
print("\e[2J")
home()
end
# Move the cursor up by the given number of rows (the default is 1), without
# changing the column position.
function cursor_up(rows = 1)
print("\e[$(rows)A")
end
# Erase the current line, without moving the cursor position.
function erase_line()
print("\e[2K")
end
# Move the cursor to the previous row, without changing the column position,
# and erase its line.
function erase_previous_line()
cursor_up()
erase_line()
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
# Clear the screen, display the credits and wait for the Enter key to be
# pressed.
function print_credits()
clear_screen()
println("Bug\n")
println("Original version in BASIC:")
println(" Brian Leibowitz, 1978.")
println(" Creative computing (Morristown, New Jersey, USA), 1978.\n")
println("This version in Julia:")
println(" Copyright (c) 2024, Marcos Cruz (programandala.net)")
println(" SPDX-License-Identifier: Fair\n")
press_enter("Press Enter to read the instructions. ")
end
const COLUMNS = 3
const COLUMN_WIDTH = 8
const COLUMN_SEPARATION = 2
# Print a table with the bug parts' description.
function print_parts_table()
# Headers
header = ["Number", "Part", "Quantity"]
for i in 1 : COLUMNS
print(rpad(header[i], COLUMN_WIDTH + COLUMN_SEPARATION))
end
println()
# Rulers
for i in 1 : COLUMNS
print(repeat("-", COLUMN_WIDTH), i == COLUMNS ? "" : repeat(' ', COLUMN_SEPARATION))
end
println()
# Data
for n in FIRST_PART : LAST_PART
println(
rpad(n, COLUMN_WIDTH + COLUMN_SEPARATION),
rpad(uppercasefirst(PART_NAME[n]), COLUMN_WIDTH + COLUMN_SEPARATION),
PART_QUANTITY[n])
end
end
# Clear the screen, print the instructions and wait for a keypress.
function print_instructions()
clear_screen()
println("Bug")
println("""
The object is to finish your bug before I finish mine. Each number
stands for a part of the bug body.
I will roll the die for you, tell you what I rolled for you, what the
number stands for, and if you can get the part. If you can get the
part I will give it to you. The same will happen on my turn.
If there is a change in either bug I will give you the option of
seeing the pictures of the bugs. The numbers stand for parts as
follows:
"""
)
print_parts_table()
press_enter("\nPress Enter to start. ")
end
# Print a bug head.
function print_head()
println(" HHHHHHH")
println(" H H")
println(" H O O H")
println(" H H")
println(" H V H")
println(" HHHHHHH")
end
# Print the given bug.
function print_bug(bug::Bug)
if bug.feelers > 0
for i in 0 : FEELER_LENGTH - 1
print(" ")
for j in 0 : bug.feelers - 1
print(" ", bug.feeler_type)
end
println()
end
end
if bug.head
print_head()
end
if bug.neck
for i in 0 : NECK_LENGTH - 1
println(" N N")
end
end
if bug.body
println(" BBBBBBBBBBBB")
for i in 0 : BODY_HEIGHT - 1
println(" B B")
end
if bug.tail
println("TTTTTB B")
end
println(" BBBBBBBBBBBB")
end
if bug.legs > 0
for i in 0 : LEG_LENGTH - 1
print(" ")
for j in 0 : bug.legs - 1
print(" L")
end
println()
end
end
end
# Return `true` if the given bug is finished; otherwise return `false`.
function is_finished(bug::Bug)::Bool
return bug.feelers == MAX_FEELERS && bug.tail && bug.legs == MAX_LEGS
end
# Array to convert a number to its equilavent text.
const AS_TEXT = ["a", "two", "three", "four", "five", "six"]
# Return a string containing the given number and noun in their proper form.
function plural(number::Int, noun::String)::String
return AS_TEXT[number] * " " * noun * (number > 1 ? "s" : "")
end
# Add the given part to the given player's bug.
function add_part(part::Int, player::Player)::Bool
changed = false
if part == Int(body)
if player.bug.body
print(", but ", player.pronoun, " already have a body.\n")
else
print("; ", player.pronoun, " now have a body:\n")
player.bug.body = true
changed = true
end
elseif part == Int(neck)
if player.bug.neck
print(", but ", player.pronoun, " already have a neck.\n")
elseif ! player.bug.body
print(", but ", player.pronoun, " need a body first.\n")
else
print("; ", player.pronoun, " now have a neck:\n")
player.bug.neck = true
changed = true
end
elseif part == Int(head)
if player.bug.head
print(", but ", player.pronoun, " already have a head.\n")
elseif ! player.bug.neck
print(", but ", player.pronoun, " need a a neck first.\n")
else
print("; ", player.pronoun, " now have a head:\n")
player.bug.head = true
changed = true
end
elseif part == Int(feeler)
if player.bug.feelers == MAX_FEELERS
print(", but ", player.pronoun, " have two feelers already.\n")
elseif ! player.bug.head
print(", but ", player.pronoun, " need a head first.\n")
else
player.bug.feelers += 1
print("; ", player.pronoun, " now have ", plural(player.bug.feelers, "feeler"))
println(":")
changed = true
end
elseif part == Int(tail)
if player.bug.tail
print(", but ", player.pronoun, " already have a tail.\n")
elseif ! player.bug.body
print(", but ", player.pronoun, " need a body first.\n")
else
print("; ", player.pronoun, " now have a tail:\n")
player.bug.tail = true
changed = true
end
elseif part == Int(leg)
if player.bug.legs == MAX_LEGS
print(", but ", player.pronoun, " have ", AS_TEXT[MAX_LEGS], " feet already.")
elseif ! player.bug.body
print(", but ", player.pronoun, " need a body first.\n")
else
player.bug.legs += 1
print("; ", player.pronoun, " now have ", plural(player.bug.legs, "leg"))
println(":")
changed = true
end
end
return changed
end
# Ask the user to press the Enter key, wait for the input, then erase the
# prompt text.
function prompt()
press_enter("Press Enter to roll the dice. ")
erase_previous_line()
end
# Play one turn for the given player, rolling the dice and updating his bug.
function turn(player::Player)
prompt()
part = rand(FIRST_PART : LAST_PART) # dice
print("$(uppercasefirst(player.pronoun)) rolled a $part ($(PART_NAME[part]))")
if add_part(part, player)
println()
print_bug(player.bug)
end
println()
end
# Print a message about the winner.
function print_winner(p1, p2::Player)
if is_finished(p1.bug) && is_finished(p2.bug)
println("Both of our bugs are finished in the same number of turns!")
elseif is_finished(p1.bug)
print(p1.possessive, " bug is finished.\n")
elseif is_finished(p2.bug)
print(p2.possessive, " bug is finished.\n")
end
end
# Return a new player initialized with the given data.
function new_player(pronoun::String, possessive::String, feeler_type::Char)
bug = Bug(false, false, false, 0, feeler_type, false, 0)
return Player(pronoun, possessive, bug)
end
# Execute the game loop.
function play()
clear_screen()
computer = new_player("you", "your", 'A')
human = new_player("I", "My", 'F')
while ! (is_finished(human.bug) || is_finished(computer.bug))
turn(human)
turn(computer)
end
print_winner(human, computer)
end
print_credits()
print_instructions()
play()
println("I hope you enjoyed the game, play it again soon!!")
In Kotlin
/*
Bug
Original version in BASIC:
Brian Leibowitz, 1978.
Creative Computing (Morristown, New Jersey, USA), 1978.
This version in Kotlin:
Copyright (c) 2023, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written on 2023-10-26.
Last modified: 20250518T2359+0200.
*/
class Bug (
var body: Boolean,
var neck: Boolean,
var head: Boolean,
var feelers: Int,
val feelerType: Char,
var tail: Boolean,
var legs: Int,
)
class Player (
val pronoun: String,
val possessive: String,
val bug: Bug,
)
val computer = Player("I", "My", Bug(false, false, false, 0, 'F', false, 0))
val human = Player("you", "Your", Bug(false, false, false, 0, 'A', false, 0))
enum class Part {Body, Neck, Head, Feeler, Tail, Leg}
// Bug body attributes.
const val BODY_HEIGHT = 2
const val FEELER_LENGTH = 4
const val LEG_LENGTH = 2
const val MAX_FEELERS = 2
const val MAX_LEGS = 6
const val NECK_LENGTH = 2
// Move the cursor to the home position.
fun home() {
print("\u001B[H")
}
// Clear the screen and move the cursor to the home position.
fun clear() {
print("\u001B[2J")
home()
}
// Move the cursor up by the given number of rows (defaults to 1), without
// changing the column position.
fun cursorUp(rows: Short = 1) {
print("\u001B[${rows}A")
}
// Erase the current line, without moving the cursor position.
fun eraseLine() {
print("\u001B[2K")
}
// Move the cursor to the previous row, without changing the column position,
// and erase its line.
fun erasePreviousLine() {
cursorUp()
eraseLine()
}
// Print the given prompt and wait until the user presses the Enter key.
fun pressEnter(prompt: String) {
print(prompt)
readln()
}
// Clear the screen, display the credits and wait for a keypress.
fun printCredits() {
clear()
println("Bug\n")
println("Original version in BASIC:")
println(" Brian Leibowitz, 1978.")
println(" Creative computing (Morristown, New Jersey, USA), 1978.\n")
println("This version in Kotlin:")
println(" Copyright (c) 2023, Marcos Cruz (programandala.net)")
println(" SPDX-License-Identifier: Fair\n")
pressEnter("Press Enter to read the instructions. ")
}
const val instructions = """
The object is to finish your bug before I finish mine. Each number
stands for a part of the bug body.
I will roll the die for you, tell you what I rolled for you, what the
number stands for, and if you can get the part. If you can get the
part I will give it to you. The same will happen on my turn.
If there is a change in either bug I will give you the option of
seeing the pictures of the bugs. The numbers stand for parts as
follows:
"""
// Print a table with the bug parts' description.
fun printPartsTable() {
val COLUMNS = 3
val COLUMN_WIDTH = 8
val COLUMN_SEPARATION = 2
// Headers
val header = arrayOf<String>("Number", "Part", "Quantity")
for (i in 0..<COLUMNS) {
print(header[i].padEnd(COLUMN_WIDTH + COLUMN_SEPARATION))
}
println()
// Rulers
for (i in 0..<COLUMNS) {
print("-".repeat(COLUMN_WIDTH))
print(if (i == COLUMNS - 1) "" else " ".repeat(COLUMN_SEPARATION))
}
println()
// Data
val partQuantity = arrayOf(1, 1, 1, 2, 1, 6)
for (part in enumValues<Part>()) {
print((part.ordinal + 1).toString().padEnd(COLUMN_WIDTH + COLUMN_SEPARATION))
print(part.toString().padEnd(COLUMN_WIDTH + COLUMN_SEPARATION))
println(partQuantity[part.ordinal])
}
}
// Clear the screen, print the instructions and wait for a keypress.
fun printInstructions() {
clear()
println("Bug")
println(instructions)
printPartsTable()
pressEnter("\nPress Enter to start. ")
}
// Print a bug head.
fun printHead() {
println(" HHHHHHH")
println(" H H")
println(" H O O H")
println(" H H")
println(" H V H")
println(" HHHHHHH")
}
// Print the given bug.
fun printBug(bug: Bug) {
if (bug.feelers > 0) {
for (i in 0..<FEELER_LENGTH) {
print(" ")
for (j in 0..<bug.feelers) {
print(" ${bug.feelerType}")
}
println()
}
}
if (bug.head) {
printHead()
}
if (bug.neck) {
for (i in 0..<NECK_LENGTH) {
println(" N N")
}
}
if (bug.body) {
println(" BBBBBBBBBBBB")
for (i in 0..<BODY_HEIGHT) {
println(" B B")
}
if (bug.tail) {
println("TTTTTB B")
}
println(" BBBBBBBBBBBB")
}
if (bug.legs > 0) {
for (i in 0..<LEG_LENGTH) {
print(" ")
for (j in 0..<bug.legs) {
print(" L")
}
println()
}
}
}
// Return `true` if the given bug is finished; otherwise return `false`.
fun finished(bug: Bug): Boolean {
return bug.feelers == MAX_FEELERS && bug.tail && bug.legs == MAX_LEGS
}
// Array to convert a number to its equilavent text.
val asText = arrayOf<String>(
"no",
"a",
"two",
"three",
"four",
"five",
"six") // MAX_LEGS
// Return a string containing the given number and noun in their proper form.
fun plural(number: Int, noun: String): String {
return "${asText[number]} $noun${if (number > 1) "s" else ""}"
}
// Add the given part to the given player's bug, if needed; return `true` if the
// bug was changed, otherwise return `false`.
fun addPart(part: Part, player: Player): Boolean {
when (part) {
Part.Body ->
if (player.bug.body) {
println(", but ${player.pronoun} already have a body.")
} else {
player.bug.body = true
println("; ${player.pronoun} now have a body:")
return true
}
Part.Neck ->
if (player.bug.neck) {
println(", but ${player.pronoun} you already have a neck.")
} else if (!player.bug.body) {
println(", but ${player.pronoun} need a body first.")
} else {
player.bug.neck = true
println("; ${player.pronoun} now have a neck:")
return true
}
Part.Head ->
if (player.bug.head) {
println(", but ${player.pronoun} already have a head.")
} else if (!player.bug.neck) {
println(", but ${player.pronoun} need a a neck first.")
} else {
player.bug.head = true
println("; ${player.pronoun} now have a head:")
return true
}
Part.Feeler ->
if (player.bug.feelers == MAX_FEELERS) {
println(", but ${player.pronoun} have two feelers already.")
} else if (!player.bug.head) {
println(", but ${player.pronoun} need a head first.")
} else {
player.bug.feelers += 1
println("; ${player.pronoun} now have ${plural(player.bug.feelers, "feeler")}:")
return true
}
Part.Tail ->
if (player.bug.tail) {
println(", but ${player.pronoun} already have a tail.")
} else if (!player.bug.body) {
println(", but ${player.pronoun} need a body first.")
} else {
player.bug.tail = true
println("; ${player.pronoun} now have a tail:")
return true
}
Part.Leg ->
if (player.bug.legs == MAX_LEGS) {
println(", but ${player.pronoun} have ${asText[MAX_LEGS]} feet already.")
} else if (!player.bug.body) {
println(", but ${player.pronoun} need a body first.")
} else {
player.bug.legs += 1
println("; ${player.pronoun} now have ${plural(player.bug.legs, "leg")}:")
return true
}
}
return false
}
// Ask the user to press the Enter key, wait for the input, then erase the
// prompt text.
fun prompt() {
pressEnter("Press Enter to roll the dice. ")
erasePreviousLine()
}
// Play one turn for the given player, rolling the dice and updating his bug.
fun turn(player: Player) {
prompt()
val number: Int = (0..<enumValues<Part>().size).random()
val part : Part = enumValues<Part>()[number]
print(player.pronoun.lowercase().replaceFirstChar{it.uppercase()})
print(" rolled a ${number + 1} (${part.toString().lowercase()})")
if (addPart(part, player)) {
println()
printBug(player.bug)
}
println()
}
// Print a message about the winner.
fun printWinner() {
if (finished(human.bug) && finished(computer.bug)) {
println("Both of our bugs are finished in the same number of turns!")
} else if (finished(human.bug)) {
println("${human.possessive} bug is finished.")
} else if (finished(computer.bug)) {
println("${computer.possessive} bug is finished.")
}
}
// Return `true` if either bug is finished, i.e. the game ending condition.
fun gameOver(): Boolean {
return finished(human.bug) || finished(computer.bug)
}
// Execute the game loop.
fun play() {
clear()
while (!gameOver()) {
turn(human)
turn(computer)
}
printWinner()
}
fun main() {
printCredits()
printInstructions()
play()
println("I hope you enjoyed the game, play it again soon!!")
}
In Nim
#[
Bug
Original version in BASIC:
Brian Leibowitz, 1978.
Creative Computing (Morristown, New Jersey, USA), 1978.
This version in Nim:
Copyright (c) 2025, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written on 2025-01-20.
Last modified: 20250405T0304+0200.
]#
import std/random
import std/strformat
import std/strutils
import std/terminal
import std/unicode
type Bug = tuple [
body: bool,
neck: bool,
head: bool,
feelers: int,
feelerType: char,
tail: bool,
legs: int ]
type Player = tuple [
pronoun: string,
possessive: string,
bug: Bug ]
var computer: Player
var human: Player
const bugParts = 6
type Part = enum
body = 1, neck, head, feeler, tail, leg
# Bug body attributes.
#
const bodyHeight = 2
const feelerLength = 4
const legLength = 2
const maxFeelers = 2
const maxLegs = 6
const neckLength = 2
proc cursorHome() =
setCursorPos(0, 0)
proc clearScreen() =
eraseScreen()
cursorHome()
# Move the cursor to the previous row, without changing the column position,
# and erase its line.
#
proc erasePreviousLine() =
cursorUp()
eraseLine()
# Clear the screen, display the credits and wait for a keypress.
#
proc printCredits() =
clearScreen()
writeLine(stdout, "Bug\n")
writeLine(stdout, "Original version in BASIC:")
writeLine(stdout, " Brian Leibowitz, 1978.")
writeLine(stdout, " Creative computing (Morristown, New Jersey, USA), 1978.\n")
writeLine(stdout, "This version in Nim:")
writeLine(stdout, " Copyright (c) 2025, Marcos Cruz (programandala.net)")
writeLine(stdout, " SPDX-License-Identifier: Fair\n")
write(stdout, "Press Enter to read the instructions. ")
discard readLine(stdin)
const instructions = """
The object is to finish your bug before I finish mine. Each number
stands for a part of the bug body.
I will roll the die for you, tell you what I rolled for you, what the
number stands for, and if you can get the part. If you can get the
part I will give it to you. The same will happen on my turn.
If there is a change in either bug I will give you the option of
seeing the pictures of the bugs. The numbers stand for parts as
follows:
"""
# Print a table with the bug parts' description.
#
proc printPartsTable() =
const columns = 3
const columnWidth = 8
const columnSeparation = 2
var padding: string
# Headers
const header: array[3, string] = ["Number", "Part", "Quantity"]
for i in 0 ..< columns:
padding = repeat(" ", columnWidth + columnSeparation - len(header[i]))
write(stdout, header[i], padding)
writeLine(stdout, "")
# Rulers
const ruler = repeat("-", columnWidth)
for i in 0 ..< columns:
padding = if i == columns - 1: "" else: repeat(" ", columnSeparation)
write(stdout, ruler, padding)
writeLine(stdout, "")
# Data
var partQuantity: array[bugParts, int] = [1, 1, 1, 2, 1, 6]
for part in Part:
padding = repeat(" ", columnWidth + columnSeparation - len($int(part)))
write(stdout, int(part), padding)
padding = repeat(" ", columnWidth + columnSeparation - len($part))
write(stdout, capitalize($part), padding)
writeLine(stdout, partQuantity[int(part) - 1])
proc printInstructions() =
clearScreen()
writeLine(stdout, "Bug\n")
writeLine(stdout, instructions)
printPartsTable()
write(stdout, "\nPress Enter to start. ")
discard readLine(stdin)
proc printHead() =
writeLine(stdout, " HHHHHHH")
writeLine(stdout, " H H")
writeLine(stdout, " H O O H")
writeLine(stdout, " H H")
writeLine(stdout, " H V H")
writeLine(stdout, " HHHHHHH")
proc printBug(bug: Bug) =
if bug.feelers > 0:
for _ in 0 ..< feelerLength:
write(stdout, " ")
for _ in 0 ..< bug.feelers:
write(stdout, " ", bug.feelerType)
writeLine(stdout, "")
if bug.head:
printHead()
if bug.neck:
for _ in 0 ..< neckLength:
writeLine(stdout, " N N")
if bug.body:
writeLine(stdout, " BBBBBBBBBBBB")
for _ in 0 ..< bodyHeight:
writeLine(stdout, " B B")
if bug.tail:
writeLine(stdout, "TTTTTB B")
writeLine(stdout, " BBBBBBBBBBBB")
if bug.legs > 0:
for _ in 0 ..< legLength:
write(stdout, " ")
for _ in 0 ..< bug.legs:
write(stdout, " L")
writeLine(stdout, "")
proc finished(bug: Bug): bool =
return bug.feelers == maxFeelers and bug.tail and bug.legs == maxLegs
proc dice(): int =
return rand(1 .. 6)
const asText: array[maxLegs + 1, string] = [
"no",
"a",
"two",
"three",
"four",
"five",
"six" ]
# Return a string containing the given number and noun in their proper form.
#
proc plural(number: int, noun: string): string =
let ending = if number > 1: "s" else: ""
return fmt" {asText[number]} {noun}{ending}"
# Add the given part to the given player's bug.
#
proc addPart(part: var Part, player: var Player): bool =
var changed: bool = false
case part:
of Part.body:
if player.bug.body:
writeLine(stdout, ", but ", player.pronoun, " already have a body.")
else:
writeLine(stdout, "; ", player.pronoun, " now have a body:")
player.bug.body = true
changed = true
of Part.neck:
if player.bug.neck:
writeLine(stdout, ", but ", player.pronoun, " already have a neck.")
elif not player.bug.body:
writeLine(stdout, ", but ", player.pronoun, " need a body first.")
else:
writeLine(stdout, "; ", player.pronoun, " now have a neck:")
player.bug.neck = true
changed = true
of Part.head:
if player.bug.head:
writeLine(stdout, ", but ", player.pronoun, " already have a head.")
elif not player.bug.neck:
writeLine(stdout, ", but ", player.pronoun, " need a a neck first.")
else:
writeLine(stdout, "; ", player.pronoun, " now have a head:")
player.bug.head = true
changed = true
of Part.feeler:
if player.bug.feelers == maxFeelers:
writeLine(stdout, ", but ", player.pronoun, " have two feelers already.")
elif not player.bug.head:
writeLine(stdout, ", but ", player.pronoun, " need a head first.")
else:
player.bug.feelers += 1
write(stdout, "; ", player.pronoun, " now have",
plural(player.bug.feelers, "feeler"))
writeLine(stdout, ":")
changed = true
of Part.tail:
if player.bug.tail:
writeLine(stdout, ", but ", player.pronoun, " already have a tail.")
elif not player.bug.body:
writeLine(stdout, ", but ", player.pronoun, " need a body first.")
else:
writeLine(stdout, "; ", player.pronoun, " now have a tail:")
player.bug.tail = true
changed = true
of Part.leg:
if player.bug.legs == maxLegs:
writeLine(stdout, ", but ", player.pronoun, " have",
asText[maxLegs], "feet already.")
elif not player.bug.body:
writeLine(stdout, ", but ", player.pronoun, " need a body first.")
else:
player.bug.legs += 1
write(stdout, "; ", player.pronoun, " now have",
plural(player.bug.legs, "leg"))
writeLine(stdout, ":")
changed = true
return changed
# Ask the user to press the Enter key, wait for the input, then erase the
# prompt text.
#
proc prompt() =
write(stdout, "Press Enter to roll the dice. ")
discard readLine(stdin)
erasePreviousLine()
# Play one turn for the given player, rolling the dice and updating his bug.
#
proc turn(player: var Player) =
prompt()
var number: int = dice()
var part = Part(number)
write(stdout, capitalize(player.pronoun), " rolled a ", number, " (", part, ")")
if addPart(part, player):
writeLine(stdout, "")
printBug(player.bug)
writeLine(stdout, "")
proc printWinner() =
if finished(human.bug) and finished(computer.bug):
writeLine(stdout, "Both of our bugs are finished in the same number of turns!")
elif finished(human.bug):
writeLine(stdout, human.possessive, " bug is finished.")
elif finished(computer.bug):
writeLine(stdout, computer.possessive, " bug is finished.")
proc gameOver(): bool =
return finished(human.bug) or finished(computer.bug)
proc play() =
clearScreen()
while not gameOver():
turn(human)
turn(computer)
printWinner()
# Init the players' data before a new game.
#
proc init() =
human.pronoun = "you"
human.possessive = "Your"
human.bug.feelerType = 'A'
computer.pronoun = "I"
computer.possessive = "My"
computer.bug.feelerType = 'F'
init()
printCredits()
printInstructions()
play()
writeLine(stdout, "I hope you enjoyed the game, play it again soon!!")
In Odin
/*
Bug
Original version in BASIC:
Brian Leibowitz, 1978.
Creative Computing (Morristown, New Jersey, USA), 1978.
This version in Odin:
Copyright (c) 2023, 2024, 2025, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written in 2023-03, 2023-09, 2023-10, 2023-12, 2024-05, 2024-07, 2024-12, 2025-02.
Last modified: 20250227T1849+0100.
*/
package bug
import "../lib/anodino/src/read"
import "../lib/anodino/src/str"
import "../lib/anodino/src/term"
import "core:fmt"
import "core:math/rand"
import "core:strings"
// Bug type.
//
Bug :: struct {
body : bool,
neck : bool,
head : bool,
feelers : int,
feeler_type : rune,
tail : bool,
legs : int,
}
// Player type.
//
Player :: struct {
pronoun : string,
possessive : string,
bug : Bug,
}
// Players.
//
computer, human : Player
// Bug body parts.
//
Part :: enum {body = 1, neck, head, feeler, tail, leg}
// Bug body attributes.
//
BODY_HEIGHT :: 2
FEELER_LENGTH :: 4
LEG_LENGTH :: 2
MAX_FEELERS :: 2
MAX_LEGS :: 6
NECK_LENGTH :: 2
// Move the cursor to the previous row, without changing the column position,
// and erase its line.
//
erase_previous_line :: proc() {
term.move_cursor_up()
term.erase_line()
}
// Clear the screen, display the credits and wait for a keypress.
//
print_credits :: proc() {
term.clear_screen()
fmt.println("Bug\n")
fmt.println("Original version in BASIC:")
fmt.println(" Brian Leibowitz, 1978.")
fmt.println(" Creative computing (Morristown, New Jersey, USA), 1978.\n")
fmt.println("This version in Odin:")
fmt.println(" Copyright (c) 2023, 2024, 2025, Marcos Cruz (programandala.net)")
fmt.println(" SPDX-License-Identifier: Fair\n")
s, _ := read.a_prompted_string("Press Enter to read the instructions. ")
delete(s)
}
INSTRUCTIONS :: `
The object is to finish your bug before I finish mine. Each number
stands for a part of the bug body.
I will roll the die for you, tell you what I rolled for you, what the
number stands for, and if you can get the part. If you can get the
part I will give it to you. The same will happen on my turn.
If there is a change in either bug I will give you the option of
seeing the pictures of the bugs. The numbers stand for parts as
follows:
`
// Print a table with the bug parts' description.
//
print_parts_table :: proc() {
COLUMNS :: 3
COLUMN_WIDTH :: 8
COLUMN_SEPARATION :: 2
// Headers
header := []string{"Number", "Part", "Quantity"}
for i in 0 ..< COLUMNS {
justified_header := strings.left_justify(header[i], COLUMN_WIDTH + COLUMN_SEPARATION, " ")
defer delete(justified_header)
fmt.print(justified_header)
}
fmt.println()
// Rulers
ruler := strings.repeat("-", COLUMN_WIDTH)
defer delete(ruler)
padding := strings.repeat(" ", COLUMN_SEPARATION)
defer delete(padding)
for i in 0 ..< COLUMNS {
fmt.print(ruler, i == COLUMNS - 1 ? "" : padding, sep = "")
}
fmt.println()
// Data
part_quantity : [len(Part) + 1]int
part_quantity[Part.body] = 1
part_quantity[Part.neck] = 1
part_quantity[Part.head] = 1
part_quantity[Part.feeler] = 2
part_quantity[Part.tail] = 1
part_quantity[Part.leg] = 6
for part in Part {
part_number := fmt.tprint(int(part))
justified_part_number := strings.left_justify(part_number, COLUMN_WIDTH + COLUMN_SEPARATION, " ")
defer delete(justified_part_number)
part_name := fmt.tprint(part)
capital_part_name := str.to_capital(part_name)
defer delete(capital_part_name)
justified_part_name := strings.left_justify(capital_part_name, COLUMN_WIDTH + COLUMN_SEPARATION, " ")
defer delete(justified_part_name)
fmt.println(justified_part_number, justified_part_name, part_quantity[part], sep = "")
}
}
// Clear the screen, print the instructions and wait for a keypress.
//
print_instructions :: proc() {
term.clear_screen()
fmt.println("Bug")
fmt.println(INSTRUCTIONS)
print_parts_table()
s, _ := read.a_prompted_string("\nPress Enter to start. ")
delete(s)
}
// Print a bug head.
//
print_head :: proc() {
fmt.println(" HHHHHHH")
fmt.println(" H H")
fmt.println(" H O O H")
fmt.println(" H H")
fmt.println(" H V H")
fmt.println(" HHHHHHH")
}
// Print the given bug.
//
print_bug :: proc(bug : Bug) {
if bug.feelers > 0 {
for _ in 0 ..< FEELER_LENGTH {
fmt.print(" ")
for _ in 0 ..< bug.feelers {
fmt.print(" ", bug.feeler_type)
}
fmt.println()
}
}
if bug.head {
print_head()
}
if bug.neck {
for _ in 0 ..< NECK_LENGTH {
fmt.println(" N N")
}
}
if bug.body {
fmt.println(" BBBBBBBBBBBB")
for _ in 0 ..< BODY_HEIGHT {
fmt.println(" B B")
}
if bug.tail {
fmt.println("TTTTTB B")
}
fmt.println(" BBBBBBBBBBBB")
}
if bug.legs > 0 {
for _ in 0 ..< LEG_LENGTH {
fmt.print(" ")
for _ in 0 ..< bug.legs {
fmt.print(" L")
}
fmt.println()
}
}
}
// Return `true` if the given bug is finished; otherwise return `false`.
//
finished :: proc(bug : Bug) -> bool {
return bug.feelers == MAX_FEELERS && bug.tail && bug.legs == MAX_LEGS
}
// Return a random number from 1 to 6 (inclusive).
//
dice :: proc() -> int {
return rand.int_max(6) + 1
}
// Array to convert a number to its equilavent text.
//
as_text := []string{
"no",
"a",
"two",
"three",
"four",
"five",
"six" } // MAX_LEGS
// Return a string containing the given number and noun in their proper form.
//
plural :: proc(number : int, noun : string) -> string {
return fmt.tprint(as_text[number], " ", noun, (number > 1) ? "s" : "", sep = "")
}
// Add the given part to the given player's bug.
//
add_part :: proc(part : Part, player : ^Player) -> bool {
changed : bool = false
#partial switch (part) {
case Part.body:
if player^.bug.body {
fmt.println(", but", player^.pronoun, "already have a body.")
} else {
fmt.println(";", player^.pronoun, "now have a body:")
player^.bug.body = true
changed = true
}
case Part.neck:
if player^.bug.neck {
fmt.println(", but", player^.pronoun, "already have a neck.")
} else if !player^.bug.body {
fmt.println(", but", player^.pronoun, "need a body first.")
} else {
fmt.println(";", player^.pronoun, "now have a neck:")
player^.bug.neck = true
changed = true
}
case Part.head:
if player^.bug.head {
fmt.println(", but", player^.pronoun, "already have a head.")
} else if !player^.bug.neck {
fmt.println(", but", player^.pronoun, "need a a neck first.")
} else {
fmt.println(";", player^.pronoun, "now have a head:")
player^.bug.head = true
changed = true
}
case Part.feeler:
if player^.bug.feelers == MAX_FEELERS {
fmt.println(", but", player^.pronoun, "have two feelers already.")
} else if !player^.bug.head {
fmt.println(", but", player^.pronoun, "need a head first.")
} else {
player^.bug.feelers += 1
fmt.print(";", player^.pronoun, "now have",
plural(player^.bug.feelers, "feeler"))
fmt.println(":")
changed = true
}
case Part.tail:
if player^.bug.tail {
fmt.println(", but", player^.pronoun, "already have a tail.")
} else if !player^.bug.body {
fmt.println(", but", player^.pronoun, "need a body first.")
} else {
fmt.println(";", player^.pronoun, "now have a tail:")
player^.bug.tail = true
changed = true
}
case Part.leg:
if player^.bug.legs == MAX_LEGS {
fmt.println(", but", player^.pronoun, "have",
as_text[MAX_LEGS], "feet already.")
} else if !player^.bug.body {
fmt.println(", but", player^.pronoun, "need a body first.")
} else {
player^.bug.legs += 1
fmt.print(";", player^.pronoun, "now have",
plural(player^.bug.legs, "leg"))
fmt.println(":")
changed = true
}
}
return changed
}
// Ask the user to press the Enter key, wait for the input, then erase the
// prompt text.
//
prompt :: proc() {
s, _ := read.a_prompted_string("Press Enter to roll the dice. ")
delete(s)
erase_previous_line()
}
// Play one turn for the given player, rolling the dice and updating his bug.
//
turn :: proc(player : ^Player) {
prompt()
number : int = dice()
part := Part(number)
pronoun := str.to_capital(player^.pronoun)
defer delete(pronoun)
fmt.printf("%s rolled a %i (%s)", pronoun, number, part)
if add_part(part, player) {
fmt.println()
print_bug(player^.bug)
}
fmt.println()
}
// Print a message about the winner.
//
print_winner :: proc() {
if finished(human.bug) && finished(computer.bug) {
fmt.println("Both of our bugs are finished in the same number of turns!")
} else if finished(human.bug) {
fmt.println(human.possessive, "bug is finished.")
} else if finished(computer.bug) {
fmt.println(computer.possessive, "bug is finished.")
}
}
// Return `true` if either bug is finished, i.e. the game ending condition.
//
game_over :: proc() -> bool {
return finished(human.bug) || finished(computer.bug)
}
// Execute the game loop.
//
play :: proc() {
term.clear_screen()
for !game_over() {
turn(&human)
turn(&computer)
}
print_winner()
}
// Init the players' data before a new game.
//
init :: proc() {
human.pronoun = "you"
human.possessive = "Your"
human.bug.feeler_type = 'A'
computer.pronoun = "I"
computer.possessive = "My"
computer.bug.feeler_type = 'F'
}
main :: proc() {
init()
print_credits()
print_instructions()
play()
fmt.println("I hope you enjoyed the game, play it again soon!!")
}
In Pike
#!/usr/bin/env pike
// Bug
// Original version in BASIC:
// Brian Leibowitz, 1978.
// Creative Computing (Morristown, New Jersey, USA), 1978.
// This version in Pike:
// Copyright (c) 2025, Marcos Cruz (programandala.net)
// SPDX-License-Identifier: Fair
//
// Written on 2025-03-10.
//
// Last modified: 20250312T1154+0100.
// Data {{{1
// =============================================================================
class Bug {
bool body;
bool neck;
bool head;
int feelers;
string feeler_type;
bool tail;
int legs;
}
class Player {
string pronoun;
string possessive;
Bug bug;
}
Player computer = Player();
Player human = Player();
void init_data() {
computer.pronoun = "I";
computer.possessive = "My";
computer.bug = Bug();
computer.bug.body = false;
computer.bug.neck = false;
computer.bug.head = false;
computer.bug.feelers = 0;
computer.bug.feeler_type = "F";
computer.bug.tail = false;
computer.bug.legs = 0;
human.pronoun = "you";
human.possessive = "Your";
human.bug = Bug();
human.bug.body = false;
human.bug.neck = false;
human.bug.head = false;
human.bug.feelers = 0;
human.bug.feeler_type = "A";
human.bug.tail = false;
human.bug.legs = 0;
}
enum Bug_part {
BODY = 1,
NECK,
HEAD,
FEELER,
TAIL,
LEG,
}
constant FIRST_PART = BODY;
constant LAST_PART = LEG;
int part_quantity(Bug_part part) {
switch (part) {
case BODY: return 1;
case NECK: return 1;
case HEAD: return 1;
case FEELER: return 2;
case TAIL: return 1;
case LEG: return 6;
}
}
string part_name(Bug_part part) {
switch (part) {
case BODY: return "body";
case NECK: return "neck";
case HEAD: return "head";
case FEELER: return "feeler";
case TAIL: return "tail";
case LEG: return "leg";
}
}
// Bug body attributes.
//
constant BODY_HEIGHT = 2;
constant FEELER_LENGTH = 4;
constant LEG_LENGTH = 2;
constant MAX_FEELERS = 2;
constant MAX_LEGS = 6;
constant NECK_LENGTH = 2;
// Terminal {{{1
// =============================================================================
constant NORMAL_STYLE = 0;
void move_cursor_home() {
write("\x1B[H");
}
void move_cursor_up() {
write("\x1B[1A");
}
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();
}
// Erase the entire current line and move the cursor to the start of the line.
//
void erase_line() {
write("\x1B[2K");
}
// User input {{{1
// =============================================================================
string accept_string(string prompt) {
write(prompt);
return Stdio.stdin.gets();
}
// Credits and instructions {{{1
// =============================================================================
// Clear the screen, display the credits and wait for a keypress.
//
void print_credits() {
clear_screen();
write("Bug\n\n");
write("Original version in BASIC:\n");
write(" Brian Leibowitz, 1978.\n");
write(" Creative computing (Morristown, New Jersey, USA), 1978.\n\n");
write("This version in Pike:\n");
write(" Copyright (c) 2025, Marcos Cruz (programandala.net)\n");
write(" SPDX-License-Identifier: Fair\n\n");
accept_string("Press Enter to read the instructions. ");
}
constant INSTRUCTIONS =
"The object is to finish your bug before I finish mine. Each number\n" +
"stands for a part of the bug body.\n" +
"\n" +
"I will roll the die for you, tell you what I rolled for you, what the\n" +
"number stands for, and if you can get the part. If you can get the\n" +
"part I will give it to you. The same will happen on my turn.\n" +
"\n" +
"If there is a change in either bug I will give you the option of\n" +
"seeing the pictures of the bugs. The numbers stand for parts as\n" +
"follows:\n";
// Clear the screen, print the instructions and wait for a keypress.
//
void print_instructions() {
clear_screen();
write("Bug\n\n");
write("%s\n", INSTRUCTIONS);
print_parts_table();
accept_string("\nPress Enter to start. ");
}
// Pseudo-random numbers {{{1
// =============================================================================
// Return a random number from 1 to 6 (inclusive).
//
int dice() {
return (random(6) + 1);
}
// Main {{{1
// =============================================================================
// Print a table with the description of the bug parts.
//
void print_parts_table() {
constant COLUMNS = 3;
constant COLUMN_WIDTH = 8;
constant COLUMN_SEPARATION = 2;
string format_string = "%-" + (string) (COLUMN_WIDTH + COLUMN_SEPARATION) + "s";
// Headers
array(string) header = ({"Number", "Part", "Quantity"});
for (int i = 0; i < COLUMNS; i += 1) {
write(format_string, header[i]);
}
write("\n");
// Rulers
string ruler = "-" * COLUMN_WIDTH;
string padding = " " * COLUMN_SEPARATION;
for (int i = 0; i < COLUMNS; i += 1) {
write("%s%s", ruler, i == COLUMNS - 1 ? "" : padding);
}
write("\n");
// Data
for (Bug_part part = FIRST_PART; part <= LAST_PART; part += 1) {
write(format_string, (string) part);
string name = String.capitalize(part_name(part));
write(format_string, name);
write(format_string, (string) part_quantity(part));
write("\n");
}
}
// Print a bug head.
//
void print_head() {
write(" HHHHHHH\n");
write(" H H\n");
write(" H O O H\n");
write(" H H\n");
write(" H V H\n");
write(" HHHHHHH\n");
}
// Print the given bug.
//
void print_bug(Bug bug) {
if (bug.feelers > 0) {
for (int i = 0; i < FEELER_LENGTH; i += 1) {
write(" ");
for (int i = 0; i < bug.feelers; i += 1) {
write(" %s", bug.feeler_type);
}
write("\n");
}
}
if (bug.head) {
print_head();
}
if (bug.neck) {
for (int i = 0; i < NECK_LENGTH; i += 1) {
write(" N N\n");
}
}
if (bug.body) {
write(" BBBBBBBBBBBB\n");
for (int i = 0; i < BODY_HEIGHT; i += 1) {
write(" B B\n");
}
if (bug.tail) {
write("TTTTTB B\n");
}
write(" BBBBBBBBBBBB\n");
}
if (bug.legs > 0) {
for (int i = 0; i < LEG_LENGTH; i += 1) {
write(" ");
for (int i = 0; i < bug.legs; i += 1) {
write(" L");
}
write("\n");
}
}
}
// Return `true` if the given bug is finished; otherwise return `false`.
//
bool finished(Bug bug) {
return bug.feelers == MAX_FEELERS && bug.tail && bug.legs == MAX_LEGS;
}
// Array to convert a number to its equilavent text.
//
array(string) as_text = ({
"no",
"a",
"two",
"three",
"four",
"five",
"six" }); // MAX_LEGS
// Return a string containing the given number and noun in their proper form.
//
string plural(int number, string noun) {
return as_text[number] + " " + noun + ((number > 1) ? "s" : "");
}
// Add the given part to the given player's bug.
//
bool add_part(Bug_part part, Player player) {
bool changed = false;
switch (part) {
case BODY:
if (player.bug.body) {
write(", but %s already have a body.\n", player.pronoun);
} else {
write("; %s now have a body:\n", player.pronoun);
player.bug.body = true;
changed = true;
}
break;
case NECK:
if (player.bug.neck) {
write(", but %s already have a neck.\n", player.pronoun);
} else if (!player.bug.body) {
write(", but %s need a body first.\n", player.pronoun);
} else {
write("; %s now have a neck:\n", player.pronoun);
player.bug.neck = true;
changed = true;
}
break;
case HEAD:
if (player.bug.head) {
write(", but %s already have a head.\n", player.pronoun);
} else if (!player.bug.neck) {
write(", but %s need a a neck first.\n", player.pronoun);
} else {
write("; %s now have a head:\n", player.pronoun);
player.bug.head = true;
changed = true;
}
break;
case FEELER:
if (player.bug.feelers == MAX_FEELERS) {
write(", but %s have two feelers already.\n", player.pronoun);
} else if (!player.bug.head) {
write(", but %s need a head first.\n", player.pronoun);
} else {
player.bug.feelers += 1;
write("; %s now have %s", player.pronoun, plural(player.bug.feelers, "feeler"));
write(":\n");
changed = true;
}
break;
case TAIL:
if (player.bug.tail) {
write(", but %s already have a tail.\n", player.pronoun);
} else if (!player.bug.body) {
write(", but %s need a body first.\n", player.pronoun);
} else {
write("; %s now have a tail:\n", player.pronoun);
player.bug.tail = true;
changed = true;
}
break;
case LEG:
if (player.bug.legs == MAX_LEGS) {
write(", but %s have %s feet already.", player.pronoun, as_text[MAX_LEGS]);
} else if (!player.bug.body) {
write(", but %s need a body first.\n", player.pronoun);
} else {
player.bug.legs += 1;
write("; %s now have %s", player.pronoun, plural(player.bug.legs, "leg"));
write(":\n");
changed = true;
}
}
return changed;
}
// Play one turn for the given player, rolling the dice and updating his bug.
//
void turn(Player player) {
accept_string("Press Enter to roll the dice. ");
move_cursor_up();
erase_line();
int part = dice();
string pronoun = String.capitalize(player.pronoun);
write("%s rolled a %d (%s)", pronoun, part, part_name(part));
if (add_part(part, player)) {
write("\n");
print_bug(player.bug);
}
write("\n");
}
// Print a message about the winner.
//
void print_winner() {
if (finished(human.bug) && finished(computer.bug)) {
write("Both of our bugs are finished in the same number of turns!\n");
} else if (finished(human.bug)) {
write("%s bug is finished.\n", human.possessive);
} else if (finished(computer.bug)) {
write("%s bug is finished.\n", computer.possessive);
}
}
// Return `true` if either bug is finished, i.e. the game ending condition.
//
bool game_over() {
return finished(human.bug) || finished(computer.bug);
}
// Execute the game loop.
//
void play() {
clear_screen();
while (!game_over()) {
turn(human);
turn(computer);
}
print_winner();
}
void bye() {
write("I hope you enjoyed the game, play it again soon!!\n");
}
void main() {
init_data();
print_credits();
print_instructions();
play();
bye();
}
In Raku
# Bug
# Original version in BASIC:
# Brian Leibowitz, 1978.
# Creative Computing (Morristown, New Jersey, USA), 1978.
# This version in Raku:
# Copyright (c) 2024, Marcos Cruz (programandala.net)
# SPDX-License-Identifier: Fair
#
# Written in 2024-12-11/12.
#
# Last modified: 20241212T1012+0100.
class Bug {
has Bool $.body is rw = False;
has Bool $.neck is rw = False;
has Bool $.head is rw = False;
has Int $.feelers is rw = 0;
has Str $.feeler_type is rw = '';
has Bool $.tail is rw = False;
has Int $.legs is rw = 0;
}
class Player {
has Str $.pronoun is rw = '';
has Str $.possessive is rw = '';
has Bug $.bug is rw = Bug.new();
}
my Player $computer = Player.new;
my Player $human = Player.new;
# Bug body parts.
#
constant $BODY = 0;
constant $NECK = 1;
constant $HEAD = 2;
constant $FEELER = 3;
constant $TAIL = 4;
constant $LEG = 5;
constant @PART_NAME = ('body', 'neck', 'head', 'feeler', 'tail', 'leg');
constant @PART_QUANTITY = (1, 1, 1, 2, 1, 6);
# Bug body attributes.
#
constant $BODY_HEIGHT = 2;
constant $FEELER_LENGTH = 4;
constant $LEG_LENGTH = 2;
constant $MAX_FEELERS = 2;
constant $MAX_LEGS = 6;
constant $NECK_LENGTH = 2;
# Move the cursor to the home position.
#
sub move_cursor_home {
print "\e[H";
}
# Erase the screen.
#
sub erase_screen {
print "\e[2J";
}
# Set the color.
#
sub set_color(Int $color) {
print "\e[{$color}m";
}
# Reset the attributes.
#
sub reset_attributes {
constant $RESET_ALL = 0;
set_color($RESET_ALL);
}
# Erase the screen, reset the attributes and move the cursor to the home position.
sub clear_screen {
erase_screen;
reset_attributes;
move_cursor_home;
}
# Move the cursor up the given number of positions (1 by default).
sub move_cursor_up(Int $n = 1) {
print "\e[{$n}A";
}
# Erase the entire current line and move the cursor to the start of the line.
#
sub erase_line {
print "\e[2K";
}
# Move the cursor to the previous row, without changing the column position,
# and erase its line.
#
sub erase_previous_line {
move_cursor_up;
erase_line;
}
# Clear the screen, display the credits and wait for a keypress.
#
sub print_credits {
clear_screen;
put "Bug\n";
put 'Original version in BASIC:';
put ' Brian Leibowitz, 1978.';
put " Creative computing (Morristown, New Jersey, USA), 1978.\n";
put 'This version in Raku:';
put ' Copyright (c) 2024, Marcos Cruz (programandala.net)';
put " SPDX-License-Identifier: Fair\n";
prompt 'Press Enter to read the instructions. ';
}
constant $INSTRUCTIONS = '
The object is to finish your bug before I finish mine. Each number
stands for a part of the bug body.
I will roll the die for you, tell you what I rolled for you, what the
number stands for, and if you can get the part. If you can get the
part I will give it to you. The same will happen on my turn.
If there is a change in either bug I will give you the option of
seeing the pictures of the bugs. The numbers stand for parts as
follows:
';
# Return the given string padded with the given char at the right, up to the
# given width.
#
sub left_justify(Str $s, Int $width, Str $char --> Str) {
return $s ~ (' ' x ($width - $s.chars));
}
# Print a table with the bug parts' description.
#
sub print_parts_table {
constant $COLUMNS = 3;
constant $COLUMN_WIDTH = 8;
constant $COLUMN_SEPARATION = 2;
# Headers
my $header = ('Number', 'Part', 'Quantity');
for 0 ..^ $COLUMNS -> $i {
print left_justify($header[$i], $COLUMN_WIDTH + $COLUMN_SEPARATION, ' ');
}
put '';
# Rulers
for 0 ..^ $COLUMNS -> $i {
print '-' x $COLUMN_WIDTH;
print $i == $COLUMNS ?? '' !! ' ' x $COLUMN_SEPARATION;
}
put '';
# Data
for $BODY .. $LEG -> $part {
print left_justify(($part + 1).Str, $COLUMN_WIDTH + $COLUMN_SEPARATION, ' ');
print left_justify(@PART_NAME[$part].tc, $COLUMN_WIDTH + $COLUMN_SEPARATION, ' ');
put @PART_QUANTITY[$part];
}
}
# Clear the screen, print the instructions and wait for a keypress.
#
sub print_instructions {
clear_screen;
put 'Bug';
put $INSTRUCTIONS;
print_parts_table;
prompt "\nPress Enter to start. ";
}
# Print a bug head.
#
sub print_head {
put ' HHHHHHH';
put ' H H';
put ' H O O H';
put ' H H';
put ' H V H';
put ' HHHHHHH';
}
# Print the given bug.
#
sub print_bug(Bug $bug) {
if $bug.feelers > 0 {
for 0 ..^ $FEELER_LENGTH {
print ' ';
for 0 ..^ $bug.feelers {
print ' ', $bug.feeler_type;
}
put '';
}
}
if $bug.head {
print_head;
}
if $bug.neck {
for 0 ..^ $NECK_LENGTH {
put ' N N';
}
}
if $bug.body {
put ' BBBBBBBBBBBB';
for 0 ..^ $BODY_HEIGHT -> $i {
put ' B B';
}
if $bug.tail {
put 'TTTTTB B';
}
put ' BBBBBBBBBBBB';
}
if $bug.legs > 0 {
for 0 ..^ $LEG_LENGTH -> $i {
print ' ';
for 0 ..^ $bug.legs -> $j {
print ' L';
}
put '';
}
}
}
# Return `True` if the given bug is finished; otherwise return `False`.
#
sub finished(Bug $bug --> Bool) {
return ($bug.feelers == $MAX_FEELERS and $bug.tail and $bug.legs == $MAX_LEGS);
}
# Array to convert a number to its equilavent text.
#
constant @AS_TEXT = (
'no',
'a',
'two',
'three',
'four',
'five',
'six' ); # $MAX_LEGS
# Return a string containing the given number and noun in their proper form.
#
sub plural(Int $number, Str $noun --> Str) {
return "@AS_TEXT[$number] $noun {($number > 1) ?? 's' !! ''}";
}
# Add the given part to the given player's bug.
#
sub add_part(Int $part, Player $player --> Bool) {
my Bool $changed = False;
given ($part) {
when $BODY {
if $player.bug.body {
put ", but {$player.pronoun} already have a body.";
} else {
put "; {$player.pronoun} now have a body:";
$player.bug.body = True;
$changed = True;
}
}
when $NECK {
if $player.bug.neck {
put ", but {$player.pronoun} already have a neck.";
} elsif not $player.bug.body {
put ", but {$player.pronoun} need a body first.";
} else {
put "; {$player.pronoun} now have a neck:";
$player.bug.neck = True;
$changed = True;
}
}
when $HEAD {
if $player.bug.head {
put ", but {$player.pronoun} already have a head.";
} elsif not $player.bug.neck {
put ", but {$player.pronoun} need a a neck first.";
} else {
put "; {$player.pronoun} now have a head:";
$player.bug.head = True;
$changed = True;
}
}
when $FEELER {
if $player.bug.feelers == $MAX_FEELERS {
put ", but {$player.pronoun} have two feelers already.";
} elsif not $player.bug.head {
put ", but {$player.pronoun} need a head first.";
} else {
$player.bug.feelers += 1;
put "; {$player.pronoun} now have {plural($player.bug.feelers, 'feeler')}:";
$changed = True;
}
}
when $TAIL {
if $player.bug.tail {
put ", but {$player.pronoun} already have a tail.";
} elsif not $player.bug.body {
put ", but {$player.pronoun} need a body first.";
} else {
put "; {$player.pronoun} now have a tail:";
$player.bug.tail = True;
$changed = True;
}
}
when $LEG {
if $player.bug.legs == $MAX_LEGS {
put ", but {$player.pronoun} have {@AS_TEXT[$MAX_LEGS]} feet already.";
} elsif not $player.bug.body {
put ", but, {$player.pronoun} need a body first.";
} else {
$player.bug.legs += 1;
put "; {$player.pronoun} now have {plural($player.bug.legs, 'leg')}:";
$changed = True;
}
}
}
return $changed;
}
# Ask the user to press the Enter key, wait for the input, then erase the
# prompt text.
#
sub prompt_dice {
prompt('Press Enter to roll the dice. ');
erase_previous_line;
}
# Play one turn for the given player, rolling the dice and updating his bug.
#
sub turn(Player $player) {
prompt_dice;
my Int $part = (0 .. 5).pick;
print "{$player.pronoun.tc} rolled a {$part + 1} ({@PART_NAME[$part]})";
if add_part($part, $player) {
put '';
print_bug($player.bug);
}
put '';
}
# Print a message about the winner.
#
sub print_winner {
if finished($human.bug) and finished($computer.bug) {
put 'Both of our bugs are finished in the same number of turns!';
} elsif finished($human.bug) {
put "{$human.possessive} bug is finished.";
} elsif finished($computer.bug) {
put "{$computer.possessive} bug is finished.";
}
}
# Return `True` if either bug is finished, i.e. the game ending condition.
#
sub game_over(--> Bool) {
return finished($human.bug) or finished($computer.bug);
}
# Execute the game loop.
#
sub play {
clear_screen;
while not game_over() {
turn($human);
turn($computer);
};
print_winner;
}
# Init the players' data before a new game.
#
sub init {
$human.pronoun = 'you';
$human.possessive = 'Your';
$human.bug.feeler_type = 'A';
$computer.pronoun = 'I';
$computer.possessive = 'My';
$computer.bug.feeler_type = 'F';
}
init;
print_credits;
print_instructions;
play;
put 'I hope you enjoyed the game, play it again soon!!';
In Swift
/*
Bug
Original version in BASIC:
Brian Leibowitz, 1978.
Creative Computing (Morristown, New Jersey, USA), 1978.
This version in Swift:
Copyright (c) 2023, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written in 2023-11-04/05.
Last modified: 20231105T0109+0100.
*/
struct Bug {
var body: Bool = false
var neck: Bool = false
var head: Bool = false
var feelers: Int = 0
var feelerType: Character = " "
var tail: Bool = false
var legs: Int = 0
}
struct Player {
var pronoun: String = ""
var possessive: String = ""
var bug: Bug = Bug()
}
// Players.
var computer = Player(pronoun: "I", possessive: "My")
computer.bug.feelerType = "F"
var human = Player(pronoun: "you", possessive: "Your")
human.bug.feelerType = "A"
enum Part: Int, CaseIterable {
case Body = 1, Neck, Head, Feeler, Tail, Leg
func quantity() -> Int {
switch self {
case .Body: return 1
case .Neck: return 1
case .Head: return 1
case .Feeler: return 2
case .Tail: return 1
case .Leg: return 6
}
}
}
// Bug body attributes.
let BODY_HEIGHT = 2
let FEELER_LENGTH = 4
let LEG_LENGTH = 2
let MAX_FEELERS = 2
let MAX_LEGS = 6
let NECK_LENGTH = 2
// Move the cursor to the home position.
func home() {
print("\u{001B}[H", terminator: "")
}
// Clear the screen and move the cursor to the home position.
func clear() {
print("\u{001B}[2J", terminator: "")
home()
}
// Move the cursor up by the given number of rows (defaults to 1), without
// changing the column position.
func cursorUp(rows: UInt8 = 1) {
print("\u{001B}[\(rows)A", terminator: "")
}
// Erase the current line, without moving the cursor position.
func eraseLine() {
print("\u{001B}[2K", terminator: "")
}
// Move the cursor to the previous row, without changing the column position,
// and erase its line.
func erasePreviousLine() {
cursorUp()
eraseLine()
}
// Clear the screen, display the credits and wait for a keypress.
func printCredits() {
clear()
print("Bug\n")
print("Original version in BASIC:")
print(" Brian Leibowitz, 1978.")
print(" Creative computing (Morristown, New Jersey, USA), 1978.\n")
print("This version in Swift:")
print(" Copyright (c) 2023, Marcos Cruz (programandala.net)")
print(" SPDX-License-Identifier: Fair\n")
print("Press Enter to read the instructions. ", terminator: "")
let _ = readLine()
}
let instructions = """
The object is to finish your bug before I finish mine. Each number
stands for a part of the bug body.
I will roll the die for you, tell you what I rolled for you, what the
number stands for, and if you can get the part. If you can get the
part I will give it to you. The same will happen on my turn.
If there is a change in either bug I will give you the option of
seeing the pictures of the bugs. The numbers stand for parts as
follows:
"""
extension String {
func capitalized() -> String {
return self.prefix(1).uppercased() + self.dropFirst()
}
}
func leftJustify(text: String, width: Int, pad: String) -> String {
return String((text + String(repeating: pad, count: width)).prefix(width))
}
// Print a table with the bug parts' description.
func printPartsTable() {
let COLUMNS = 3
let COLUMN_WIDTH = 8
let RULER = String(repeating: "-", count: COLUMN_WIDTH)
let COLUMN_SEPARATION = 2
let SEPARATOR = String(repeating: " ", count: COLUMN_SEPARATION)
let headers = ["Number", "Part", "Quantity"]
for header in headers {
print(
leftJustify(text: header, width: COLUMN_WIDTH, pad: " "),
terminator: SEPARATOR
)
}
print()
// Rulers
for _ in 0 ..< COLUMNS {
print(RULER, terminator: SEPARATOR)
}
print()
// Data
for part in Part.allCases {
print(
leftJustify(text: String(part.rawValue), width: COLUMN_WIDTH, pad: " "),
leftJustify(text: String(describing: part), width: COLUMN_WIDTH, pad: " "),
part.quantity(),
separator: SEPARATOR,
terminator: ""
)
print()
}
}
// Clear the screen, print the instructions and wait for a keypress.
func printInstructions() {
clear()
print("Bug\n")
print(instructions)
print()
printPartsTable()
print("\nPress Enter to start. ", terminator: "")
let _ = readLine()
}
// Print a bug head.
func printHead() {
print(" HHHHHHH")
print(" H H")
print(" H O O H")
print(" H H")
print(" H V H")
print(" HHHHHHH")
}
// Print the given bug.
func printBug(bug: Bug) {
if bug.feelers > 0 {
for _ in 0 ..< FEELER_LENGTH {
print(" ", terminator: "")
for _ in 0 ..< bug.feelers {
print(" ", bug.feelerType, terminator: "")
}
print()
}
}
if bug.head {
printHead()
}
if bug.neck {
for _ in 0 ..< NECK_LENGTH {
print(" N N")
}
}
if bug.body {
print(" BBBBBBBBBBBB")
for _ in 0 ..< BODY_HEIGHT {
print(" B B")
}
if bug.tail {
print("TTTTTB B")
}
print(" BBBBBBBBBBBB")
}
if bug.legs > 0 {
for _ in 0 ..< LEG_LENGTH {
print(" ", terminator: "")
for _ in 0 ..< bug.legs {
print(" L", terminator: "")
}
print()
}
}
}
// Return `true` if the given bug is finished; otherwise return `false`.
func finished(bug: Bug) -> Bool {
return bug.feelers == MAX_FEELERS && bug.tail && bug.legs == MAX_LEGS
}
// Array to convert a number to its equilavent text.
let asText = [
"no",
"a",
"two",
"three",
"four",
"five",
"six" ] // MAX_LEGS
// Return a string containing the given number and noun in their proper form.
func plural(number: Int, noun: String) -> String {
return "\(asText[number]) \(noun)\((number > 1) ? "s" : "")"
}
// Add the given part to the given player's bug.
func addPart(part: Part, player: inout Player) -> Bool {
var changed = false
switch part {
case Part.Body:
if player.bug.body {
print(", but", player.pronoun, "already have a body.")
} else {
print(";", player.pronoun, "now have a body:")
player.bug.body = true
changed = true
}
case Part.Neck:
if player.bug.neck {
print(", but", player.pronoun, "you already have a neck.")
} else if !player.bug.body {
print(", but", player.pronoun, "need a body first.")
} else {
print(";", player.pronoun, "now have a neck:")
player.bug.neck = true
changed = true
}
case Part.Head:
if player.bug.head {
print(", but", player.pronoun, "already have a head.")
} else if !player.bug.neck {
print(", but", player.pronoun, "need a a neck first.")
} else {
print(";", player.pronoun, "now have a head:")
player.bug.head = true
changed = true
}
case Part.Feeler:
if player.bug.feelers == MAX_FEELERS {
print(", but", player.pronoun, "have two feelers already.")
} else if !player.bug.head {
print(", but", player.pronoun, "need a head first.")
} else {
player.bug.feelers += 1
print("; \(player.pronoun) now have \(plural(number: player.bug.feelers, noun: "feeler")):")
changed = true
}
case Part.Tail:
if player.bug.tail {
print(", but", player.pronoun, "already have a tail.")
} else if !player.bug.body {
print(", but", player.pronoun, "need a body first.")
} else {
print(";", player.pronoun, "now have a tail:")
player.bug.tail = true
changed = true
}
case Part.Leg:
if player.bug.legs == MAX_LEGS {
print(", but", player.pronoun, "have",
asText[MAX_LEGS], "feet already.")
} else if !player.bug.body {
print(", but", player.pronoun, "need a body first.")
} else {
player.bug.legs += 1
print("; \(player.pronoun) now have \(plural(number: player.bug.legs, noun: "leg")):")
changed = true
}
}
return changed
}
// Ask the user to press the Enter key, wait for the input, then erase the
// prompt text.
func prompt() {
print("Press Enter to roll the dice. ", terminator: "")
let _ = readLine()
erasePreviousLine()
}
// Play one turn for the given player, rolling the dice and updating his bug.
func turn(_ player: inout Player) {
prompt()
let number = Int.random(in: 1...6)
let part = Part(rawValue: number)!
print("\(player.pronoun.capitalized()) rolled a \(number) (\(String(describing: part).lowercased()))", terminator: "")
if addPart(part: part, player: &player) {
print()
printBug(bug: player.bug)
}
print()
}
// Print a message about the winner.
func printWinner() {
if finished(bug: human.bug) && finished(bug: computer.bug) {
print("Both of our bugs are finished in the same number of turns!")
} else if finished(bug: human.bug) {
print(human.possessive, "bug is finished.")
} else if finished(bug: computer.bug) {
print(computer.possessive, "bug is finished.")
}
}
// Return `true` if either bug is finished, i.e. the game ending condition.
func gameOver() -> Bool {
return finished(bug: human.bug) || finished(bug: computer.bug)
}
// Execute the game loop.
func play() {
clear()
while !gameOver() {
turn(&human)
turn(&computer)
}
printWinner()
}
printCredits()
printInstructions()
play()
print("I hope you enjoyed the game, play it again soon!!")
In V
/*
Bug
Original version in BASIC:
Brian Leibowitz, 1978.
Creative Computing (Morristown, New Jersey, USA), 1978.
This version in V:
Copyright (c) 2025, Marcos Cruz (programandala.net)
SPDX-License-Identifier: Fair
Written on 2025-01-04.
Last modified: 20250504T0045+0200.
*/
import os
import rand
import strings
import term
struct Bug {
mut:
body bool
neck bool
head bool
feelers int
feeler_type rune
tail bool
legs int
}
struct Player {
mut:
pronoun string
possessive string
bug Bug
}
enum Part {
body
neck
head
feeler
tail
leg
}
// Bug body attributes.
//
const body_height = 2
const feeler_length = 4
const leg_length = 2
const max_feelers = 2
const max_legs = 6
const neck_length = 2
// Clear the screen, display the credits and wait for a keypress.
//
fn print_credits() {
term.clear()
println('Bug\n')
println('Original version in BASIC:')
println(' Brian Leibowitz, 1978.')
println(' Creative computing (Morristown, New Jersey, USA), 1978.\n')
println('This version in V:')
println(' Copyright (c) 2025, Marcos Cruz (programandala.net)')
println(' SPDX-License-Identifier: Fair\n')
os.input('Press Enter to read the instructions. ')
}
const columns = 3
const column_width = 8
const column_separation = 2
// Return the given string padded with spaces at the right up to
// the given total length.
//
fn left_justified(s string, l int) string {
return s + strings.repeat(` `, l - s.len)
}
// Print a table with the bug parts' description.
//
fn print_parts_table() {
// Headers
header := ['Number', 'Part', 'Quantity']
for i in 0 .. columns {
print(left_justified(header[i], column_width + column_separation))
}
println('')
// Rulers
ruler := strings.repeat(`-`, column_width)
for i in 0 .. columns {
print(ruler)
if i != columns - 1 {
print(strings.repeat(` `, column_separation))
}
}
println('')
// Data
part_quantity := [1, 1, 1, 2, 1, 6]
mut i := 1
$for part in Part.values {
print(left_justified('${i}', column_width + column_separation))
print(left_justified('${part.name.capitalize()}', column_width + column_separation))
println(part_quantity[part.value])
i++
}
}
// Clear the screen, print the instructions and wait for a keypress.
//
fn print_instructions() {
term.clear()
println('Bug')
println('\nThe object is to finish your bug before I finish mine. Each number')
println('stands for a part of the bug body.')
println('\nI will roll the die for you, tell you what I rolled for you, what the')
println('number stands for, and if you can get the part. If you can get the')
println('part I will give it to you. The same will happen on my turn.')
println('\nIf there is a change in either bug I will give you the option of')
println('seeing the pictures of the bugs. The numbers stand for parts as')
println('follows:\n')
print_parts_table()
os.input('\nPress Enter to start. ')
}
// Print a bug head.
//
fn print_head() {
println(' HHHHHHH')
println(' H H')
println(' H O O H')
println(' H H')
println(' H V H')
println(' HHHHHHH')
}
// Print the given bug.
//
fn print_bug(bug Bug) {
if bug.feelers > 0 {
for _ in 0 .. feeler_length {
print(' ')
for _ in 0 .. bug.feelers {
print(' ${bug.feeler_type}')
}
println('')
}
}
if bug.head {
print_head()
}
if bug.neck {
for _ in 0 .. neck_length {
println(' N N')
}
}
if bug.body {
println(' BBBBBBBBBBBB')
for _ in 0 .. body_height {
println(' B B')
}
if bug.tail {
println('TTTTTB B')
}
println(' BBBBBBBBBBBB')
}
if bug.legs > 0 {
for _ in 0 .. leg_length {
print(' ')
for _ in 0 .. bug.legs {
print(' L')
}
println('')
}
}
}
// Return `true` if the given bug is finished; otherwise return `false`.
//
fn finished(bug Bug) bool {
return bug.feelers == max_feelers && bug.tail && bug.legs == max_legs
}
// Return a random number from 1 to 6 (inclusive).
//
fn dice() int {
return rand.intn(6) or { 0 } + 1
}
// Array to convert a number to its equilavent text.
//
const as_text = ['no', 'a', 'two', 'three', 'four', 'five', 'six']
// Return a string containing the given number and noun in their proper form.
//
fn plural(number int, noun string) string {
return as_text[number] + ' ' + noun + (if number > 1 {
's'
} else {
''
})
}
// Add the given part to the given player's bug.
//
fn add_part(part Part, mut player Player) bool {
mut changed := false
match part {
.body {
if player.bug.body {
println(', but ${player.pronoun} already have a body.')
} else {
println('; ${player.pronoun} now have a body:')
player.bug.body = true
changed = true
}
}
.neck {
if player.bug.neck {
println(', but ${player.pronoun} already have a neck.')
} else if !player.bug.body {
println(', but ${player.pronoun} need a body first.')
} else {
println('; ${player.pronoun} now have a neck:')
player.bug.neck = true
changed = true
}
}
.head {
if player.bug.head {
println(', but ${player.pronoun} already have a head.')
} else if !player.bug.neck {
println(', but ${player.pronoun} need a a neck first.')
} else {
println('; ${player.pronoun} now have a head:')
player.bug.head = true
changed = true
}
}
.feeler {
if player.bug.feelers == max_feelers {
println(', but ${player.pronoun} have two feelers already.')
} else if !player.bug.head {
println(', but ${player.pronoun} need a head first.')
} else {
player.bug.feelers += 1
print('; ${player.pronoun} now have ${plural(player.bug.feelers, 'feeler')}')
println(':')
changed = true
}
}
.tail {
if player.bug.tail {
println(', but ${player.pronoun} already have a tail.')
} else if !player.bug.body {
println(', but ${player.pronoun} need a body first.')
} else {
println('; ${player.pronoun} now have a tail:')
player.bug.tail = true
changed = true
}
}
.leg {
if player.bug.legs == max_legs {
println(', but ${player.pronoun} have ${as_text[max_legs]} feet already.')
} else if !player.bug.body {
println(', but ${player.pronoun} need a body first.')
} else {
player.bug.legs += 1
print('; ${player.pronoun} now have ${plural(player.bug.legs, 'leg')}')
println(':')
changed = true
}
}
}
return changed
}
// Ask the user to press the Enter key, wait for the input, then erase the
// prompt text.
//
fn prompt() {
os.input('Press Enter to roll the dice. ')
term.clear_previous_line()
}
// Play one turn for the given player, rolling the dice and updating his bug.
//
fn turn(mut player Player) {
prompt()
number := dice()
unsafe {
part := Part(number - 1)
print('${player.pronoun.capitalize()} rolled a ${number} (${part})')
if add_part(part, mut player) {
println('')
print_bug(player.bug)
}
}
println('')
}
// Print a message about the winner.
//
fn print_winner(human Player, computer Player) {
if finished(human.bug) && finished(computer.bug) {
println('Both of our bugs are finished in the same number of turns!')
} else if finished(human.bug) {
println('${human.possessive} bug is finished.')
} else if finished(computer.bug) {
println('${computer.possessive} bug is finished.')
}
}
// Return `true` if either bug is finished, i.e. the game ending condition.
//
fn game_over(human Player, computer Player) bool {
return finished(human.bug) || finished(computer.bug)
}
// Execute the game loop.
//
fn play() {
term.clear()
mut computer := Player{
pronoun: 'you'
possessive: 'Your'
bug: Bug{
feeler_type: `A`
}
}
mut human := Player{
pronoun: 'I'
possessive: 'My'
bug: Bug{
feeler_type: `F`
}
}
for !game_over(human, computer) {
turn(mut human)
turn(mut computer)
}
print_winner(human, computer)
}
fn main() {
print_credits()
print_instructions()
play()
println('I hope you enjoyed the game, play it again soon!!')
}
