mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 23:26:40 -08:00
Merge branch 'coding-horror:main' into main
This commit is contained in:
@@ -1,7 +1,16 @@
|
||||
### Acey Ducey
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=2
|
||||
This is a simulation of the Acey Ducey card game. In the game, the dealer (the computer) deals two cards face up. You have an option to bet or not to bet depending on whether or not you feel the next card dealt will have a value between the first two.
|
||||
|
||||
Your initial money is set to $100; you may want to alter this value if you want to start with more or less than $100. The game keeps going on until you lose all your money or interrupt the program.
|
||||
|
||||
The original program author was Bill Palmby of Prairie View, Illinois.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=2)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=17)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
80 PRINT"IF YOU DO NOT WANT TO BET, INPUT A 0"
|
||||
100 N=100
|
||||
110 Q=100
|
||||
120 PRINT "YOU NOW HAVE";Q;"DOLLARS."
|
||||
120 PRINT "YOU NOW HAVE ";Q;" DOLLARS."
|
||||
130 PRINT
|
||||
140 GOTO 260
|
||||
210 Q=Q+M
|
||||
|
||||
6
01_Acey_Ducey/javascript/.prettierrc.json
Normal file
6
01_Acey_Ducey/javascript/.prettierrc.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 4,
|
||||
"semi": true,
|
||||
"singleQuote": true
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>ACEY DUCEY</title>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="output" style="font-size: 12pt;"></pre>
|
||||
|
||||
<pre id="output" style="font-size: 12pt"></pre>
|
||||
<script src="aceyducey.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,135 +1,216 @@
|
||||
// ACEY DUCEY
|
||||
//
|
||||
// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
|
||||
//
|
||||
// UTILITY VARIABLES
|
||||
|
||||
function print(str)
|
||||
{
|
||||
document.getElementById("output").appendChild(document.createTextNode(str));
|
||||
// By default:
|
||||
// — Browsers have a window object
|
||||
// — Node.js does not
|
||||
// Checking for an undefined window object is a loose check
|
||||
// to enable browser and Node.js support
|
||||
const isRunningInBrowser = typeof window !== 'undefined';
|
||||
|
||||
// To easily validate input strings with utility functions
|
||||
const validLowerCaseYesStrings = ['yes', 'y'];
|
||||
const validLowerCaseNoStrings = ['no', 'n'];
|
||||
const validLowerCaseYesAndNoStrings = [
|
||||
...validLowerCaseYesStrings,
|
||||
...validLowerCaseNoStrings,
|
||||
];
|
||||
// UTILITY VARIABLES
|
||||
|
||||
// Function to get a random number (card) 2-14 (ACE is 14)
|
||||
function getRandomCard() {
|
||||
// In our game, the value of ACE is greater than face cards;
|
||||
// instead of having the value of ACE be 1, we’ll have it be 14.
|
||||
// So, we want to shift the range of random numbers from 1-13 to 2-14
|
||||
let min = 2;
|
||||
let max = 14;
|
||||
// Return random integer between two values, inclusive
|
||||
return Math.floor(Math.random() * (max - min + 1) + min);
|
||||
}
|
||||
|
||||
function input()
|
||||
{
|
||||
var input_element;
|
||||
var input_str;
|
||||
|
||||
return new Promise(function (resolve) {
|
||||
input_element = document.createElement("INPUT");
|
||||
|
||||
print("? ");
|
||||
input_element.setAttribute("type", "text");
|
||||
input_element.setAttribute("length", "50");
|
||||
document.getElementById("output").appendChild(input_element);
|
||||
input_element.focus();
|
||||
input_str = undefined;
|
||||
input_element.addEventListener("keydown", function (event) {
|
||||
if (event.keyCode == 13) {
|
||||
input_str = input_element.value;
|
||||
document.getElementById("output").removeChild(input_element);
|
||||
print(input_str);
|
||||
print("\n");
|
||||
resolve(input_str);
|
||||
}
|
||||
});
|
||||
});
|
||||
function newGameCards() {
|
||||
let cardOne = getRandomCard();
|
||||
let cardTwo = getRandomCard();
|
||||
let cardThree = getRandomCard();
|
||||
// We want:
|
||||
// 1. cardOne and cardTwo to be different cards
|
||||
// 2. cardOne to be lower than cardTwo
|
||||
// So, while cardOne is greater than or equal too cardTwo
|
||||
// we will continue to generate random cards.
|
||||
while (cardOne >= cardTwo) {
|
||||
cardOne = getRandomCard();
|
||||
cardTwo = getRandomCard();
|
||||
}
|
||||
return [cardOne, cardTwo, cardThree];
|
||||
}
|
||||
|
||||
function tab(space)
|
||||
{
|
||||
var str = "";
|
||||
while (space-- > 0)
|
||||
str += " ";
|
||||
return str;
|
||||
// Function to get card value
|
||||
function getCardValue(card) {
|
||||
let faceOrAce = {
|
||||
11: 'JACK',
|
||||
12: 'QUEEN',
|
||||
13: 'KING',
|
||||
14: 'ACE',
|
||||
};
|
||||
// If card value matches a key in faceOrAce, use faceOrAce value;
|
||||
// Else, return undefined and handle with the Nullish Coalescing Operator (??)
|
||||
// and default to card value.
|
||||
let cardValue = faceOrAce[card] ?? card;
|
||||
return cardValue;
|
||||
}
|
||||
|
||||
print(tab(26) + "ACEY DUCEY CARD GAME\n");
|
||||
print(tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");
|
||||
print("\n");
|
||||
print("\n");
|
||||
print("ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER\n");
|
||||
print("THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP\n");
|
||||
print("YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING\n");
|
||||
print("ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE\n");
|
||||
print("A VALUE BETWEEN THE FIRST TWO.\n");
|
||||
print("IF YOU DO NOT WANT TO BET, INPUT A 0\n");
|
||||
print(spaces(26) + 'ACEY DUCEY CARD GAME');
|
||||
print(spaces(15) + 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n');
|
||||
print('ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER');
|
||||
print('THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP');
|
||||
print('YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING');
|
||||
print('ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE');
|
||||
print('A VALUE BETWEEN THE FIRST TWO.');
|
||||
print("IF YOU DO NOT WANT TO BET, INPUT '0'");
|
||||
|
||||
function show_card(card)
|
||||
{
|
||||
if (card < 11)
|
||||
print(card + "\n");
|
||||
else if (card == 11)
|
||||
print("JACK\n");
|
||||
else if (card == 12)
|
||||
print("QUEEN\n");
|
||||
else if (card == 13)
|
||||
print("KING\n");
|
||||
else
|
||||
print("ACE\n");
|
||||
}
|
||||
main();
|
||||
|
||||
// Main program
|
||||
async function main()
|
||||
{
|
||||
q = 100;
|
||||
while (1) {
|
||||
print("YOU NOW HAVE " + q + " DOLLARS.\n");
|
||||
print("\n");
|
||||
|
||||
do {
|
||||
print("HERE ARE YOUR NEXT TWO CARDS: \n");
|
||||
do {
|
||||
a = Math.floor(Math.random() * 13 + 2);
|
||||
b = Math.floor(Math.random() * 13 + 2);
|
||||
} while (a >= b) ;
|
||||
show_card(a);
|
||||
show_card(b);
|
||||
print("\n");
|
||||
while (1) {
|
||||
print("\n");
|
||||
print("WHAT IS YOUR BET");
|
||||
m = parseInt(await input());
|
||||
if (m > 0) {
|
||||
if (m > q) {
|
||||
print("SORRY, MY FRIEND, BUT YOU BET TOO MUCH.\n");
|
||||
print("YOU HAVE ONLY " + q + "DOLLARS TO BET.\n");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
m = 0;
|
||||
print("CHICKEN!!\n");
|
||||
print("\n");
|
||||
break;
|
||||
}
|
||||
} while (m == 0) ;
|
||||
c = Math.floor(Math.random() * 13 + 2);
|
||||
show_card(c);
|
||||
if (c > a && c < b) {
|
||||
print("YOU WIN!!!\n");
|
||||
q = q + m;
|
||||
} else {
|
||||
print("SORRY, YOU LOSE\n");
|
||||
if (m >= q) {
|
||||
print("\n");
|
||||
print("\n");
|
||||
print("SORRY, FRIEND, BUT YOU BLEW YOUR WAD.\n");
|
||||
print("\n");
|
||||
print("\n");
|
||||
print("TRY AGAIN (YES OR NO)");
|
||||
a = await input();
|
||||
print("\n");
|
||||
print("\n");
|
||||
if (a == "YES") {
|
||||
q = 100;
|
||||
async function main() {
|
||||
let bet;
|
||||
let availableDollars = 100;
|
||||
|
||||
// Loop game forever
|
||||
while (true) {
|
||||
let [cardOne, cardTwo, cardThree] = newGameCards();
|
||||
|
||||
print(`YOU NOW HAVE ${availableDollars} DOLLARS.\n`);
|
||||
|
||||
print('HERE ARE YOUR NEXT TWO CARDS: ');
|
||||
print(getCardValue(cardOne));
|
||||
print(getCardValue(cardTwo));
|
||||
print('');
|
||||
|
||||
// Loop until receiving a valid bet
|
||||
let validBet = false;
|
||||
while (!validBet) {
|
||||
print('\nWHAT IS YOUR BET? ');
|
||||
bet = parseInt(await input(), 10);
|
||||
let minimumRequiredBet = 0;
|
||||
if (bet > minimumRequiredBet) {
|
||||
if (bet > availableDollars) {
|
||||
print('SORRY, MY FRIEND, BUT YOU BET TOO MUCH.');
|
||||
print(`YOU HAVE ONLY ${availableDollars} DOLLARS TO BET.`);
|
||||
} else {
|
||||
print("O.K., HOPE YOU HAD FUN!");
|
||||
validBet = true;
|
||||
}
|
||||
} else {
|
||||
// Does not meet minimum required bet
|
||||
print('CHICKEN!!');
|
||||
print('');
|
||||
}
|
||||
}
|
||||
|
||||
print('\n\nHERE IS THE CARD WE DREW: ');
|
||||
print(getCardValue(cardThree));
|
||||
|
||||
// Determine if player won or lost
|
||||
if (cardThree > cardOne && cardThree < cardTwo) {
|
||||
print('YOU WIN!!!');
|
||||
availableDollars = availableDollars + bet;
|
||||
} else {
|
||||
print('SORRY, YOU LOSE');
|
||||
|
||||
if (bet >= availableDollars) {
|
||||
print('');
|
||||
print('');
|
||||
print('SORRY, FRIEND, BUT YOU BLEW YOUR WAD.');
|
||||
print('');
|
||||
print('');
|
||||
print('TRY AGAIN (YES OR NO)');
|
||||
|
||||
let tryAgainInput = await input();
|
||||
|
||||
print('');
|
||||
print('');
|
||||
|
||||
if (isValidYesNoString(tryAgainInput)) {
|
||||
availableDollars = 100;
|
||||
} else {
|
||||
print('O.K., HOPE YOU HAD FUN!');
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
q = q - m;
|
||||
availableDollars = availableDollars - bet;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
// UTILITY FUNCTIONS
|
||||
function isValidYesNoString(string) {
|
||||
return validLowerCaseYesAndNoStrings.includes(string.toLowerCase());
|
||||
}
|
||||
|
||||
function isValidYesString(string) {
|
||||
return validLowerCaseYesStrings.includes(string.toLowerCase());
|
||||
}
|
||||
|
||||
function isValidNoString(string) {
|
||||
return validLowerCaseNoStrings.includes(string.toLowerCase());
|
||||
}
|
||||
|
||||
function print(string) {
|
||||
if (isRunningInBrowser) {
|
||||
// Adds trailing newline to match console.log behavior
|
||||
document
|
||||
.getElementById('output')
|
||||
.appendChild(document.createTextNode(string + '\n'));
|
||||
} else {
|
||||
console.log(string);
|
||||
}
|
||||
}
|
||||
|
||||
function input() {
|
||||
if (isRunningInBrowser) {
|
||||
// Accept input from the browser DOM input
|
||||
return new Promise((resolve) => {
|
||||
const outputElement = document.querySelector('#output');
|
||||
const inputElement = document.createElement('input');
|
||||
outputElement.append(inputElement);
|
||||
inputElement.focus();
|
||||
|
||||
inputElement.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'Enter') {
|
||||
const result = inputElement.value;
|
||||
inputElement.remove();
|
||||
print(result);
|
||||
print('');
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Accept input from the command line in Node.js
|
||||
// See: https://nodejs.dev/learn/accept-input-from-the-command-line-in-nodejs
|
||||
return new Promise(function (resolve) {
|
||||
const readline = require('readline').createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
readline.question('', function (input) {
|
||||
resolve(input);
|
||||
readline.close();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function printInline(string) {
|
||||
if (isRunningInBrowser) {
|
||||
document
|
||||
.getElementById('output')
|
||||
.appendChild(document.createTextNode(string));
|
||||
} else {
|
||||
process.stdout.write(string);
|
||||
}
|
||||
}
|
||||
|
||||
function spaces(numberOfSpaces) {
|
||||
return ' '.repeat(numberOfSpaces);
|
||||
}
|
||||
|
||||
// UTILITY FUNCTIONS
|
||||
|
||||
@@ -85,6 +85,7 @@ end;
|
||||
|
||||
constructor TGame.Create;
|
||||
begin
|
||||
Randomize;
|
||||
FDeck:= TDeck.Create;
|
||||
end;
|
||||
|
||||
@@ -99,7 +100,6 @@ begin
|
||||
ClrScr;
|
||||
PrintGreeting;
|
||||
repeat
|
||||
Randomize;
|
||||
FStash:= 100;
|
||||
repeat
|
||||
PrintBalance;
|
||||
|
||||
@@ -118,10 +118,10 @@ begin
|
||||
end;
|
||||
|
||||
begin
|
||||
Randomize;
|
||||
ClrScr;
|
||||
PrintGreeting;
|
||||
repeat
|
||||
Randomize;
|
||||
Stash:= 100;
|
||||
repeat
|
||||
PrintBalance;
|
||||
|
||||
@@ -78,7 +78,7 @@ if __name__ == "__main__":
|
||||
"""
|
||||
Acey-Ducey is played in the following manner
|
||||
The dealer (computer) deals two cards face up
|
||||
You have an option to be or not bet depending
|
||||
You have an option to bet or not bet depending
|
||||
on whether or not you feel the card will have
|
||||
a value between the first two.
|
||||
If you do not want to bet, input a 0
|
||||
|
||||
128
01_Acey_Ducey/python/acey_ducey_oo.py
Normal file
128
01_Acey_Ducey/python/acey_ducey_oo.py
Normal file
@@ -0,0 +1,128 @@
|
||||
#
|
||||
# AceyDuchy
|
||||
#
|
||||
# From: BASIC Computer Games (1978)
|
||||
# Edited by David Ahl
|
||||
#
|
||||
# "The original BASIC program author was Bill Palmby
|
||||
# of Prairie View, Illinois."
|
||||
#
|
||||
# Python port by Aviyam Fischer, 2022
|
||||
#
|
||||
######################################################
|
||||
|
||||
class Card:
|
||||
def __init__(self, suit, rank):
|
||||
self.suit = suit
|
||||
self.rank = rank
|
||||
|
||||
def __str__(self):
|
||||
r = self.rank
|
||||
if r == 11:
|
||||
r = 'J'
|
||||
elif r == 12:
|
||||
r = 'Q'
|
||||
elif r == 13:
|
||||
r = 'K'
|
||||
elif r == 14:
|
||||
r = 'A'
|
||||
return f'{r}{self.suit}'
|
||||
|
||||
|
||||
class Deck:
|
||||
def __init__(self):
|
||||
self.cards = []
|
||||
self.build()
|
||||
|
||||
def build(self):
|
||||
for suit in ['\u2665', '\u2666', '\u2663', '\u2660']:
|
||||
for rank in range(1, 14):
|
||||
self.cards.append(Card(suit, rank))
|
||||
|
||||
def shuffle(self):
|
||||
import random
|
||||
random.shuffle(self.cards)
|
||||
|
||||
def deal(self):
|
||||
return self.cards.pop()
|
||||
|
||||
|
||||
class Game:
|
||||
def __init__(self):
|
||||
self.deck = Deck()
|
||||
self.deck.shuffle()
|
||||
self.card_a = self.deck.deal()
|
||||
self.card_b = self.deck.deal()
|
||||
self.money = 100
|
||||
self.not_done = True
|
||||
|
||||
def play(self):
|
||||
while self.not_done:
|
||||
while self.money > 0:
|
||||
card_a = self.card_a
|
||||
card_b = self.card_b
|
||||
|
||||
if card_a.rank > card_b.rank:
|
||||
card_a, card_b = card_b, card_a
|
||||
|
||||
if card_a.rank == card_b.rank:
|
||||
self.card_b = self.deck.deal()
|
||||
card_b = self.card_b
|
||||
|
||||
print(f'You have:\t ${self.money} ')
|
||||
print(f'Your cards:\t {card_a} {card_b}')
|
||||
|
||||
bet = int(input('What is your bet? '))
|
||||
player_card = self.deck.deal()
|
||||
if 0 < bet <= self.money:
|
||||
|
||||
print(f'Your deal:\t {player_card}')
|
||||
if card_a.rank < player_card.rank < card_b.rank:
|
||||
print('You Win!')
|
||||
self.money += bet
|
||||
else:
|
||||
print('You Lose!')
|
||||
self.money -= bet
|
||||
self.not_done = False
|
||||
else:
|
||||
print('Chicken!')
|
||||
print(f'Your deal should have been: {player_card}')
|
||||
if card_a.rank < player_card.rank < card_b.rank:
|
||||
print(f'You could have won!')
|
||||
else:
|
||||
print(f'You would lose, so it was wise of you to chicken out!')
|
||||
|
||||
self.not_done = False
|
||||
break
|
||||
|
||||
if len(self.deck.cards) <= 3:
|
||||
print('You ran out of cards. Game over.')
|
||||
self.not_done = False
|
||||
break
|
||||
|
||||
self.card_a = self.deck.deal()
|
||||
self.card_b = self.deck.deal()
|
||||
|
||||
if self.money == 0:
|
||||
self.not_done = False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('''
|
||||
Acey Ducey is a card game where you play against the computer.
|
||||
The Dealer(computer) will deal two cards facing up.
|
||||
You have an option to bet or not bet depending on whether or not you
|
||||
feel the card will have a value between the first two.
|
||||
If you do not want to bet input a 0
|
||||
''')
|
||||
GAME_OVER = False
|
||||
|
||||
while not GAME_OVER:
|
||||
game = Game()
|
||||
game.play()
|
||||
print(f'You have ${game.money} left')
|
||||
print('Would you like to play again? (y/n)')
|
||||
if input() == 'n':
|
||||
GAME_OVER = True
|
||||
|
||||
print('\nThanks for playing!')
|
||||
@@ -174,7 +174,7 @@ print("OK Hope you had fun\n")
|
||||
#
|
||||
# Give the user the ability to quit the game, perhaps
|
||||
# by typing "quit" instead of making a bet. Provide a
|
||||
# final assement based on how much of the original
|
||||
# final assessment based on how much of the original
|
||||
# bankroll they have left.
|
||||
#
|
||||
# Or have the game run for a set number of rounds or
|
||||
|
||||
@@ -56,9 +56,9 @@ while true # Game loop
|
||||
puts
|
||||
puts "HERE ARE YOUR NEXT TWO CARDS:"
|
||||
|
||||
# Randomly draw two cards from 2 to 14 and make sure the first card is lower in value than the second
|
||||
# Randomly draw two cards and make sure the first card is lower in value than the second
|
||||
# Using array destructuring, this sorted array can be assigned to `first_card` and `second_card`
|
||||
first_card, second_card = [rand(2..14), rand(2..14)].sort
|
||||
first_card, second_card = (2...14).to_a.shuffle.pop(2).sort
|
||||
|
||||
# Helper method to convert a numeric card into a String for printing
|
||||
def card_name(card)
|
||||
|
||||
25
01_Acey_Ducey/vbnet/AceyDucy.sln
Normal file
25
01_Acey_Ducey/vbnet/AceyDucy.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "AceyDucy", "AceyDucy\AceyDucy.vbproj", "{37496710-B458-4502-ADCB-4C57203866F9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{37496710-B458-4502-ADCB-4C57203866F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{37496710-B458-4502-ADCB-4C57203866F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{37496710-B458-4502-ADCB-4C57203866F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{37496710-B458-4502-ADCB-4C57203866F9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C01D9DAE-644C-455F-8365-E14E49074BC3}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
9
01_Acey_Ducey/vbnet/AceyDucy/AceyDucy.vbproj
Normal file
9
01_Acey_Ducey/vbnet/AceyDucy/AceyDucy.vbproj
Normal file
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>AceyDucy</RootNamespace>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
178
01_Acey_Ducey/vbnet/AceyDucy/Program.vb
Normal file
178
01_Acey_Ducey/vbnet/AceyDucy/Program.vb
Normal file
@@ -0,0 +1,178 @@
|
||||
Imports System
|
||||
|
||||
''' <summary>
|
||||
''' This is a modern adapation of Acey Ducey from BASIC Computer Games.
|
||||
'''
|
||||
''' The structural changes primarily consist of replacing the many GOTOs with
|
||||
''' Do/Loop constructs to force the continual execution of the program.
|
||||
'''
|
||||
''' Because modern Basic allows multi-line If/Then blocks, many GOTO jumps were
|
||||
''' able to be eliminated and the logic was able to be moved to more relevant areas,
|
||||
''' For example, the increment/decrement of the player's balance could be in the same
|
||||
''' area as the notification of win/loss.
|
||||
'''
|
||||
''' Some modern improvements were added, primarily the inclusion of a function, which
|
||||
''' eliminated a thrice-repeated block of logic to display the card value. The archaic
|
||||
''' RND function is greatly simplified with the .NET Framework's Random class.
|
||||
'''
|
||||
''' Elementary comments are provided for non-programmers or novices.
|
||||
''' </summary>
|
||||
Module Program
|
||||
Sub Main(args As String())
|
||||
' These are the variables that will hold values during the program's execution
|
||||
Dim input As String
|
||||
Dim rnd As New Random ' You can create a new instance of an object during declaration
|
||||
Dim currentBalance As Integer = 100 ' You can set a initial value at declaration
|
||||
Dim currentWager As Integer
|
||||
Dim cardA, cardB, cardC As Integer ' You can specify multiple variables of the same type in one declaration statement
|
||||
|
||||
' Display the opening title and instructions
|
||||
' Use a preceding $ to insert calculated values within the string using {}
|
||||
Console.WriteLine($"{Space((Console.WindowWidth \ 2) - 10)}ACEY DUCEY CARD GAME")
|
||||
Console.WriteLine($"{Space((Console.WindowWidth \ 2) - 21)}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
||||
Console.WriteLine("")
|
||||
Console.WriteLine("")
|
||||
Console.WriteLine("ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER")
|
||||
Console.WriteLine("THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP")
|
||||
Console.WriteLine("YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING")
|
||||
Console.WriteLine("ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE")
|
||||
Console.WriteLine("A VALUE BETWEEN THE FIRST TWO.")
|
||||
Console.WriteLine("IF YOU DO NOT WANT TO BET, INPUT A 0")
|
||||
|
||||
Do ' This loop continues as long as the player wants to keep playing
|
||||
|
||||
Do ' This loop continues as long as the player has money to play
|
||||
|
||||
Console.WriteLine("")
|
||||
Console.WriteLine($"YOU NOW HAVE {currentBalance} DOLLARS.")
|
||||
Console.WriteLine("")
|
||||
|
||||
Console.WriteLine("HERE ARE YOUR NEXT TWO CARDS:")
|
||||
|
||||
' We need to ensure that card B is a higher value for our later comparison,
|
||||
' so we will loop until we have two cards that meet this criteria
|
||||
Do
|
||||
cardA = rnd.Next(2, 14)
|
||||
cardB = rnd.Next(2, 14)
|
||||
|
||||
Loop While cardA > cardB
|
||||
|
||||
' We use a function to display the text value of the numeric card value
|
||||
' because we do this 3 times and a function reduces repetition of code
|
||||
Console.WriteLine(DisplayCard(cardA))
|
||||
Console.WriteLine(DisplayCard(cardB))
|
||||
|
||||
Do ' This loop continues until the player provides a valid wager value
|
||||
Console.WriteLine("")
|
||||
Console.WriteLine("WHAT IS YOUR BET")
|
||||
|
||||
currentWager = 0
|
||||
input = Console.ReadLine
|
||||
|
||||
' Any input from the console is a string, but we require a number.
|
||||
' Test the input to make sure it is a numeric value.
|
||||
If Integer.TryParse(input, currentWager) Then
|
||||
' Test to ensure the player has not wagered more than their balance
|
||||
If currentWager > currentBalance Then
|
||||
Console.WriteLine("SORRY, MY FRIEND, BUT YOU BET TOO MUCH.")
|
||||
Console.WriteLine($"YOU HAVE ONLY {currentBalance} DOLLARS TO BET.")
|
||||
|
||||
Else
|
||||
' The player has provided a numeric value that is less/equal to their balance,
|
||||
' exit the loop and continue play
|
||||
Exit Do
|
||||
|
||||
End If ' check player balance
|
||||
|
||||
End If ' check numeric input
|
||||
|
||||
Loop ' wager loop
|
||||
|
||||
' If the player is wagering, draw the third card, otherwise, mock them.
|
||||
If currentWager > 0 Then
|
||||
cardC = rnd.Next(2, 14)
|
||||
|
||||
Console.WriteLine(DisplayCard(cardC))
|
||||
|
||||
' The effort we made to have two cards in numeric order earlier makes this check easier,
|
||||
' otherwise we would have to have a second check in the opposite direction
|
||||
If cardC < cardA OrElse cardC >= cardB Then
|
||||
Console.WriteLine("SORRY, YOU LOSE")
|
||||
currentBalance -= currentWager ' Shorthand code to decrement a number (currentBalance=currentBalance - currentWager)
|
||||
|
||||
Else
|
||||
Console.WriteLine("YOU WIN!!!")
|
||||
currentBalance += currentWager ' Shorthand code to increment a number (currentBalance=currentBalance + currentWager)
|
||||
|
||||
End If
|
||||
|
||||
Else
|
||||
Console.WriteLine("CHICKEN!!")
|
||||
Console.WriteLine("")
|
||||
|
||||
End If
|
||||
|
||||
Loop While currentBalance > 0 ' loop as long as the player has money
|
||||
|
||||
' At this point, the player has no money (currentBalance=0). Inform them of such.
|
||||
Console.WriteLine("")
|
||||
Console.WriteLine("SORRY, FRIEND, BUT YOU BLEW YOUR WAD.")
|
||||
Console.WriteLine("")
|
||||
Console.WriteLine("")
|
||||
|
||||
' We will loop to ensure the player provides some answer.
|
||||
Do
|
||||
Console.WriteLine("TRY AGAIN (YES OR NO)")
|
||||
Console.WriteLine("")
|
||||
|
||||
input = Console.ReadLine
|
||||
|
||||
Loop While String.IsNullOrWhiteSpace(input)
|
||||
|
||||
' We will assume that the player wants to play again only if they answer yes.
|
||||
' (yeah and ya are valid as well, because we only check the first letter)
|
||||
If input.Substring(0, 1).Equals("y", StringComparison.CurrentCultureIgnoreCase) Then ' This allows upper and lower case to be entered.
|
||||
currentBalance = 100 ' Reset the players balance before restarting
|
||||
|
||||
Else
|
||||
' Exit the outer loop which will end the game.
|
||||
Exit Do
|
||||
|
||||
End If
|
||||
|
||||
Loop ' The full game loop
|
||||
|
||||
Console.WriteLine("O.K., HOPE YOU HAD FUN!")
|
||||
|
||||
End Sub
|
||||
|
||||
' This function is called for each of the 3 cards used in the game.
|
||||
' The input and the output are both consistent, making it a good candidate for a function.
|
||||
Private Function DisplayCard(value As Integer) As String
|
||||
' We check the value of the input and run a block of code for whichever
|
||||
' evaluation matches
|
||||
Select Case value
|
||||
Case 2 To 10 ' Case statements can be ranges of values, also multiple values (Case 2,3,4,5,6,7,8,9,10)
|
||||
Return value.ToString
|
||||
|
||||
Case 11
|
||||
Return "JACK"
|
||||
|
||||
Case 12
|
||||
Return "QUEEN"
|
||||
|
||||
Case 13
|
||||
Return "KING"
|
||||
|
||||
Case 14
|
||||
Return "ACE"
|
||||
|
||||
End Select
|
||||
|
||||
' Although we have full knowledge of the program and never plan to send an invalid
|
||||
' card value, it's important to provide a message for the next developer who won't
|
||||
Throw New ArgumentOutOfRangeException("Card value must be between 2 and 14")
|
||||
|
||||
End Function
|
||||
|
||||
End Module
|
||||
@@ -1,7 +1,14 @@
|
||||
### Amazing
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=3
|
||||
This program will print out a different maze every time it is run and guarantees only one path through. You can choose the dimensions of the maze — i.e. the number of squares wide and long.
|
||||
|
||||
The original program author was Jack Hauber of Windsor, Connecticut.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=3)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=18)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,22 @@
|
||||
### Animal
|
||||
|
||||
Unlike other computer games in which the computer picks a number or letter and you must guess what it is, in this game _you_ think of an animal and the _computer_ asks you questions and tries to guess the name of your animal. If the computer guesses incorrectly, it will ask you for a question that differentiates the animal you were thinking of. In this way the computer “learns” new animals. Questions to differentiate new animals should be input without a question mark.
|
||||
|
||||
This version of the game does not have a SAVE feature. If your system allows, you may modify the program to save and reload the array when you want to play the game again. This way you can save what the computer learns over a series of games.
|
||||
|
||||
At any time if you reply “LIST” to the question “ARE YOU THINKING OF AN ANIMAL,” the computer will tell you all the animals it knows so far.
|
||||
|
||||
The program starts originally by knowing only FISH and BIRD. As you build up a file of animals you should use broad, general questions first and then narrow down to more specific ones with later animals. For example, if an elephant was to be your first animal, the computer would ask for a question to distinguish an elephant from a bird. Naturally, there are hundreds of possibilities, however, if you plan to build a large file of animals a good question would be “IS IT A MAMMAL.”
|
||||
|
||||
This program can be easily modified to deal with categories of things other than animals by simply modifying the initial data and the dialogue references to animals. In an educational environment, this would be a valuable program to teach the distinguishing characteristics of many classes of objects — rock formations, geography, marine life, cell structures, etc.
|
||||
|
||||
Originally developed by Arthur Luehrmann at Dartmouth College, Animal was subsequently shortened and modified by Nathan Teichholtz at DEC and Steve North at Creative Computing.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=4
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=4)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=19)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
119
03_Animal/kotlin/Animal.kt
Normal file
119
03_Animal/kotlin/Animal.kt
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* ANIMAL
|
||||
*
|
||||
*
|
||||
* Converted from BASIC to Kotlin by John Long (@patimen)
|
||||
*
|
||||
* Animal is basically a perfect example of a binary tree. Implement it
|
||||
* as such, with the QuestionNode either having an answer if it is a terminal node
|
||||
* or a Question
|
||||
*/
|
||||
|
||||
fun main() {
|
||||
printIntro()
|
||||
val rootQuestionNode =
|
||||
QuestionOrAnswer(question = Question("DOES IT SWIM", QuestionOrAnswer("FISH"), QuestionOrAnswer("BIRD")))
|
||||
while (true) {
|
||||
val choice = ask("ARE YOU THINKING OF AN ANIMAL")
|
||||
when {
|
||||
choice == "LIST" -> printKnownAnimals(rootQuestionNode)
|
||||
choice.startsWith("Q") -> return
|
||||
choice.startsWith("Y") -> {
|
||||
// A wrong answer means it's a new animal!
|
||||
val wrongAnswer = rootQuestionNode.getWrongAnswer()
|
||||
if (wrongAnswer == null) {
|
||||
// The computer got the right answer!
|
||||
println("WHY NOT TRY ANOTHER ANIMAL?")
|
||||
} else {
|
||||
// Get a new question to ask next time
|
||||
wrongAnswer.askForInformationAndSave()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Takes care of asking a question (on the same line) and getting
|
||||
// an answer or a blank string
|
||||
fun ask(question: String): String {
|
||||
print("$question? ")
|
||||
return readLine()?.uppercase() ?: ""
|
||||
}
|
||||
|
||||
// Special case for a "yes or no" question, returns true of yes
|
||||
fun askYesOrNo(question: String): Boolean {
|
||||
return generateSequence {
|
||||
print("$question? ")
|
||||
readLine()
|
||||
}.firstNotNullOf { yesOrNo(it) }
|
||||
}
|
||||
|
||||
// If neither Y (true) or N (false), return null, so the above sequence
|
||||
// will just keep executing until it gets the answer
|
||||
private fun yesOrNo(string: String): Boolean? =
|
||||
when (string.uppercase().firstOrNull()) {
|
||||
'Y' -> true
|
||||
'N' -> false
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun printKnownAnimals(question: QuestionOrAnswer) {
|
||||
println("\nANIMALS I ALREADY KNOW ARE:")
|
||||
val animals = question.getAnswers().chunked(4)
|
||||
animals.forEach { line ->
|
||||
// The '*' in front of line.toTypedArray() "spreads" the array as a list of parameters instead
|
||||
System.out.printf("%-15s".repeat(line.size), *line.toTypedArray())
|
||||
println()
|
||||
}
|
||||
}
|
||||
|
||||
private fun printIntro() {
|
||||
println(" ANIMAL")
|
||||
println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
||||
println("\n\n")
|
||||
println("PLAY 'GUESS THE ANIMAL'")
|
||||
println("\n")
|
||||
println("THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.")
|
||||
}
|
||||
|
||||
class QuestionOrAnswer(private var answer: String? = null, var question: Question? = null) {
|
||||
fun getAnswers(): List<String> = answer?.let { listOf(it) } ?: question!!.getAnswers()
|
||||
fun getWrongAnswer(): QuestionOrAnswer? {
|
||||
if (answer != null) {
|
||||
// "takeUnless" will return null if the answer is "yes". In this case
|
||||
// we will return the "wrong answer", aka the terminal answer that was incorrect
|
||||
return this.takeUnless { askYesOrNo("IS IT A $answer") }
|
||||
}
|
||||
return question?.getWrongAnswer()
|
||||
}
|
||||
|
||||
fun askForInformationAndSave() {
|
||||
//Failed to get it right and ran out of questions
|
||||
//Let's ask the user for the new information
|
||||
val newAnimal = ask("THE ANIMAL YOU WERE THINKING OF WAS A")
|
||||
val newQuestion = ask("PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A \n$newAnimal FROM A $answer\n")
|
||||
val newAnswer = askYesOrNo("FOR A $newAnimal THE ANSWER WOULD BE")
|
||||
|
||||
val trueAnswer = if (newAnswer) newAnimal else answer
|
||||
val falseAnswer = if (newAnswer) answer else newAnimal
|
||||
// Replace our answer with null and set the question with the data we just got
|
||||
// This makes it a question instead of an answer
|
||||
this.answer = null
|
||||
this.question = Question(newQuestion, QuestionOrAnswer(trueAnswer), QuestionOrAnswer(falseAnswer))
|
||||
}
|
||||
}
|
||||
|
||||
class Question(
|
||||
private val question: String,
|
||||
private val trueAnswer: QuestionOrAnswer,
|
||||
private val falseAnswer: QuestionOrAnswer
|
||||
) {
|
||||
fun getAnswers(): List<String> = trueAnswer.getAnswers() + falseAnswer.getAnswers()
|
||||
|
||||
fun getWrongAnswer(): QuestionOrAnswer? =
|
||||
if (askYesOrNo(question)) {
|
||||
trueAnswer.getWrongAnswer()
|
||||
} else {
|
||||
falseAnswer.getWrongAnswer()
|
||||
}
|
||||
}
|
||||
3
03_Animal/kotlin/README.md
Normal file
3
03_Animal/kotlin/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Kotlin](https://kotlinlang.org/)
|
||||
223
03_Animal/perl/animal.pl
Executable file
223
03_Animal/perl/animal.pl
Executable file
@@ -0,0 +1,223 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use 5.010; # To get 'state' and 'say'
|
||||
|
||||
use strict; # Require explicit declaration of variables
|
||||
use warnings; # Enable optional compiler warnings
|
||||
|
||||
use English; # Use more friendly names for Perl's magic variables
|
||||
use Term::ReadLine; # Prompt and return user input
|
||||
|
||||
our $VERSION = '0.000_01';
|
||||
|
||||
# The Perl ref() built-in returns 'HASH' for a hash reference. But we
|
||||
# make it a manifest constant just to avoid typos.
|
||||
use constant REF_HASH => ref {};
|
||||
|
||||
print <<'EOD';
|
||||
ANIMAL
|
||||
Creative Computing Morristown, New Jersey
|
||||
|
||||
|
||||
|
||||
Play 'Guess the Animal'
|
||||
Think of an animal and the computer will try to guess it.
|
||||
|
||||
EOD
|
||||
|
||||
# We keep the accumulated data in a tree structure, initialized here. As
|
||||
# we accumulate animals, we replace the 'yes' or 'no' keys with new hash
|
||||
# references.
|
||||
my $database = {
|
||||
question => 'Does it swim', # Initial question
|
||||
yes => 'fish', # Result of answering 'y'
|
||||
no => 'bird', # Result of answering 'n'
|
||||
};
|
||||
|
||||
while ( 1 ) {
|
||||
|
||||
my $resp = get_input(
|
||||
'Are you thinking of an an animal? [y/n/list]: '
|
||||
);
|
||||
|
||||
if ( $resp =~ m/ \A y /smxi ) {
|
||||
# If we got an answer beginning with 'y', walk the database
|
||||
walk_tree( $database );
|
||||
} elsif ( $resp =~ m/ \A list \z /smxi ) {
|
||||
# If we got 'list', list the currently-known animals.
|
||||
say '';
|
||||
say 'Animals I already know are:';
|
||||
say " $_" for sort( list_animals( $database ) );
|
||||
}
|
||||
}
|
||||
|
||||
# Get input from the user. The arguments are:
|
||||
# * The prompt
|
||||
# * A reference to validation code. This code receives the response in
|
||||
# $ARG and returns true for a valid response.
|
||||
# * A warning to print if the response is not valid. This must end in a
|
||||
# return.
|
||||
# The first valid response is returned. An end-of-file terminates the
|
||||
# script.
|
||||
sub get_input {
|
||||
my ( $prompt, $validate, $warning ) = @ARG;
|
||||
|
||||
# If no validator is passed, default to one that always returns
|
||||
# true.
|
||||
$validate ||= sub { 1 };
|
||||
|
||||
# Create the readline object. The 'state' causes the variable to be
|
||||
# initialized only once, no matter how many times this subroutine is
|
||||
# called. The do { ... } is a compound statement used because we
|
||||
# need to tweak the created object before we store it.
|
||||
state $term = do {
|
||||
my $obj = Term::ReadLine->new( 'animal' );
|
||||
$obj->ornaments( 0 );
|
||||
$obj;
|
||||
};
|
||||
|
||||
while ( 1 ) { # Iterate indefinitely
|
||||
|
||||
# Read the input into the topic variable, localized to prevent
|
||||
# Spooky Action at a Distance. We exit on undef, which signals
|
||||
# end-of-file.
|
||||
exit unless defined( local $ARG = $term->readline( $prompt ) );
|
||||
|
||||
# Return the input if it is valid.
|
||||
return $ARG if $validate->();
|
||||
|
||||
# Issue the warning, and go around the merry-go-round again.
|
||||
warn $warning;
|
||||
}
|
||||
}
|
||||
|
||||
# Get a yes-or-no answer. The argument is the prompt, which will have
|
||||
# '? [y/n]: ' appended. The donkey work is done by get_input(), which is
|
||||
# requested to validate the response as beginning with 'y' or 'n',
|
||||
# case-insensitive. The return is a true value for 'y' and a false value
|
||||
# for 'n'.
|
||||
sub get_yes_no {
|
||||
my ( $prompt ) = @ARG;
|
||||
state $map_answer = {
|
||||
n => 0,
|
||||
y => 1,
|
||||
};
|
||||
my $resp = lc get_input(
|
||||
"$prompt? [y/n]: ",
|
||||
sub { m/ \A [yn] /smxi },
|
||||
"Please respond 'y' or 'n'\n",
|
||||
);
|
||||
return $map_answer->{ substr $resp, 0, 1 };
|
||||
}
|
||||
|
||||
# Recurse through the database, returning the names of all animals in
|
||||
# it, in an undefined order.
|
||||
sub list_animals {
|
||||
my ( $node ) = @ARG;
|
||||
return $node unless REF_HASH eq ref $node;
|
||||
return( map { list_animals( $node->{$_} ) } qw{ yes no } );
|
||||
}
|
||||
|
||||
# Find or create the desired animal.
|
||||
# Ask the question stored in the node given in its argument. If the key
|
||||
# selected by the answer ('yes' or 'no') is another node, recurse. If it
|
||||
# is an animal name, confirm it, or add a new animal as appropriate.
|
||||
sub walk_tree {
|
||||
my ( $node ) = @ARG;
|
||||
|
||||
# Ask the question associated with this node. Turn the true/false
|
||||
# response into 'yes' or 'no', since those are the names of the
|
||||
# respective keys.
|
||||
my $resp = get_yes_no ( $node->{question} ) ? 'yes' : 'no';
|
||||
|
||||
# Chose the datum for the response.
|
||||
my $choice = $node->{ $resp };
|
||||
|
||||
# If the datum is a hash reference
|
||||
if ( REF_HASH eq ref $choice ) {
|
||||
|
||||
# Recurse into it
|
||||
walk_tree( $choice );
|
||||
|
||||
# Otherwise it is an actual animal (i.e. terminal node). Check it.
|
||||
} else {
|
||||
|
||||
# If this is not the animal the player was thinking of
|
||||
unless ( get_yes_no( "Is it a $choice" ) ) {
|
||||
|
||||
# Find out what animal the player was thinking of
|
||||
my $animal = lc get_input(
|
||||
'The animal you were thinking of was a ',
|
||||
);
|
||||
|
||||
# Get a yes/no question that distinguishes the animal the
|
||||
# player was thinking of from the animal we found in the
|
||||
# tree.
|
||||
say 'Please type in a question that would distinguish a';
|
||||
my $question = get_input( "$animal from a $choice: " );
|
||||
|
||||
# Find out whether the new animal is selected by 'yes' or
|
||||
# 'no'. If 'no', swap the original animal with the new one
|
||||
# for convenience.
|
||||
( $choice, $animal ) = ( $animal, $choice ) if get_yes_no(
|
||||
"For a $animal the answer would be",
|
||||
);
|
||||
|
||||
# Replace the animal we originally found by a new node
|
||||
# giving the original animal, the new animal, and the
|
||||
# question that distinguishes them.
|
||||
$node->{ $resp } = {
|
||||
question => $question,
|
||||
no => $animal,
|
||||
yes => $choice,
|
||||
};
|
||||
}
|
||||
|
||||
# Find out if the player wants to play again. If not, exit. If
|
||||
# so, just return.
|
||||
say '';
|
||||
exit unless get_yes_no( 'Why not try another animal' );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 TITLE
|
||||
|
||||
animal.pl - Play the game 'animal' from Basic Computer Games
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
animal.pl
|
||||
|
||||
=head1 DETAILS
|
||||
|
||||
This Perl script is a port of C<animal>, which is the 3ed entry in Basic
|
||||
Computer Games.
|
||||
|
||||
The original BASIC was greatly complicated by the need to emulate a
|
||||
binary tree with an array. The implementation using hashes as nodes in
|
||||
an actual binary tree is much simpler.
|
||||
|
||||
=head1 PORTED BY
|
||||
|
||||
Thomas R. Wyant, III F<wyant at cpan dot org>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
Copyright (C) 2022 by Thomas R. Wyant, III
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl 5.10.0. For more details, see the Artistic
|
||||
License 1.0 at
|
||||
L<https://www.perlfoundation.org/artistic-license-10.html>, and/or the
|
||||
Gnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
without any warranty; without even the implied warranty of
|
||||
merchantability or fitness for a particular purpose.
|
||||
|
||||
=cut
|
||||
|
||||
# ex: set expandtab tabstop=4 textwidth=72 :
|
||||
@@ -1,7 +1,38 @@
|
||||
### Awari
|
||||
|
||||
Awari is an ancient African game played with seven sticks and thirty-six stones or beans laid out as shown above. The board is divided into six compartments or pits on each side. In addition, there are two special home pits at the ends.
|
||||
|
||||
A move is made by taking all the beans from any (non-empty) pit on your own side. Starting from the pit to the right of this one, these beans are ‘sown’ one in each pit working around the board anticlockwise.
|
||||
|
||||
A turn consists of one or two moves. If the last bean of your move is sown in your own home you may take a second move.
|
||||
|
||||
If the last bean sown in a move lands in an empty pit, provided that the opposite pit is not empty, all the beans in the opposite pit, together with the last bean sown are ‘captured’ and moved to the player’s home.
|
||||
|
||||
When either side is empty, the game is finished. The player with the most beans in his home has won.
|
||||
|
||||
In the computer version, the board is printed as 14 numbers representing the 14 pits.
|
||||
|
||||
```
|
||||
3 3 3 3 3 3
|
||||
0 0
|
||||
3 3 3 3 3 3
|
||||
```
|
||||
|
||||
The pits on your (lower) side are numbered 1-6 from left to right. The pits on my (the computer’s) side are numbered from my left (your right).
|
||||
|
||||
To make a move you type in the number of a pit. If the last bean lands in your home, the computer types ‘AGAIN?’ and then you type in your second move.
|
||||
|
||||
The computer’s move is typed, followed by a diagram of the board in its new state. The computer always offers you the first move. This is considered to be a slight advantage.
|
||||
|
||||
There is a learning mechanism in the program that causes the play of the computer to improve as it playes more games.
|
||||
|
||||
The original version of Awari is adopted from one originally written by Geoff Wyvill of Bradford, Yorkshire, England.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=6
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=6)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=21)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
264
04_Awari/csharp/Game.cs
Normal file
264
04_Awari/csharp/Game.cs
Normal file
@@ -0,0 +1,264 @@
|
||||
namespace Awari;
|
||||
|
||||
public class Game
|
||||
{
|
||||
public int[] PlayerPits => _beans[0..6];
|
||||
public int[] ComputerPits => _beans[7..13];
|
||||
public int PlayerHome => _beans[_playerHome];
|
||||
public int ComputerHome => _beans[_computerHome];
|
||||
|
||||
private bool IsDone =>
|
||||
PlayerPits.All(b => b == 0) // if all the player's pits are empty
|
||||
|| ComputerPits.All(b => b == 0); // or if all the computer's pits are empty
|
||||
|
||||
public GameState State { get; private set; }
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
State = GameState.PlayerMove;
|
||||
|
||||
Array.Fill(_beans, _initialPitValue);
|
||||
_beans[_playerHome] = 0;
|
||||
_beans[_computerHome] = 0;
|
||||
|
||||
_moveCount = 0;
|
||||
_notWonGameMoves[^1] = 0;
|
||||
}
|
||||
|
||||
public bool IsLegalPlayerMove(int move) =>
|
||||
move is > 0 and < 7
|
||||
&& _beans[move - 1] > 0; // arrays are zero-based, but moves are one-based
|
||||
|
||||
public void PlayerMove(int move) => MoveAndRegister(move - 1, _playerHome);
|
||||
|
||||
public List<int> ComputerTurn()
|
||||
{
|
||||
// keep a list of moves made by the computer in a single turn (1 or 2)
|
||||
List<int> moves = new();
|
||||
|
||||
moves.Add(ComputerMove()); // ComputerMove() returns the move made
|
||||
|
||||
// only if a second move is possible, do it
|
||||
if (State == GameState.ComputerSecondMove)
|
||||
moves.Add(ComputerMove());
|
||||
|
||||
return moves;
|
||||
}
|
||||
|
||||
public GameOutcome GetOutcome()
|
||||
{
|
||||
if (State != GameState.Done)
|
||||
throw new InvalidOperationException("Game is not yet done.");
|
||||
|
||||
int difference = _beans[_playerHome] - _beans[_computerHome];
|
||||
var winner = difference switch
|
||||
{
|
||||
< 0 => GameWinner.Computer,
|
||||
0 => GameWinner.Draw,
|
||||
> 0 => GameWinner.Player,
|
||||
};
|
||||
|
||||
return new GameOutcome(winner, Math.Abs(difference));
|
||||
}
|
||||
|
||||
private void MoveAndRegister(int pit, int homePosition)
|
||||
{
|
||||
int lastMovedBean = Move(_beans, pit, homePosition);
|
||||
|
||||
// encode moves by player and computer into a 'base 6' number
|
||||
// e.g. if the player moves 5, the computer moves 2, and the player moves 4,
|
||||
// that would be encoded as ((5 * 6) * 6) + (2 * 6) + 4 = 196
|
||||
if (pit > 6) pit -= 7;
|
||||
_moveCount++;
|
||||
if (_moveCount < 9)
|
||||
_notWonGameMoves[^1] = _notWonGameMoves[^1] * 6 + pit;
|
||||
|
||||
// determine next state based on current state, whether the game's done, and whether the last moved bean moved
|
||||
// into the player's home position
|
||||
State = (State, IsDone, lastMovedBean == homePosition) switch
|
||||
{
|
||||
(_, true, _) => GameState.Done,
|
||||
(GameState.PlayerMove, _, true) => GameState.PlayerSecondMove,
|
||||
(GameState.PlayerMove, _, false) => GameState.ComputerMove,
|
||||
(GameState.PlayerSecondMove, _, _) => GameState.ComputerMove,
|
||||
(GameState.ComputerMove, _, true) => GameState.ComputerSecondMove,
|
||||
(GameState.ComputerMove, _, false) => GameState.PlayerMove,
|
||||
(GameState.ComputerSecondMove, _, _) => GameState.PlayerMove,
|
||||
_ => throw new InvalidOperationException("Unexpected game state"),
|
||||
};
|
||||
|
||||
// do some bookkeeping if the game is done, but not won by the computer
|
||||
if (State == GameState.Done
|
||||
&& _beans[_playerHome] >= _beans[_computerHome])
|
||||
// add an entry for the next game
|
||||
_notWonGameMoves.Add(0);
|
||||
}
|
||||
|
||||
private static int Move(int[] beans, int pit, int homePosition)
|
||||
{
|
||||
int beansToMove = beans[pit];
|
||||
beans[pit] = 0;
|
||||
|
||||
// add the beans that were in the pit to other pits, moving clockwise around the board
|
||||
for (; beansToMove >= 1; beansToMove--)
|
||||
{
|
||||
// wrap around if pit exceeds 13
|
||||
pit = (pit + 1) % 14;
|
||||
|
||||
beans[pit]++;
|
||||
}
|
||||
|
||||
if (beans[pit] == 1 // if the last bean was sown in an empty pit
|
||||
&& pit is not _playerHome and not _computerHome // which is not either player's home
|
||||
&& beans[12 - pit] != 0) // and the pit opposite is not empty
|
||||
{
|
||||
// move the last pit sown and the _beans in the pit opposite to the player's home
|
||||
beans[homePosition] = beans[homePosition] + beans[12 - pit] + 1;
|
||||
beans[pit] = 0;
|
||||
beans[12 - pit] = 0;
|
||||
}
|
||||
|
||||
return pit;
|
||||
}
|
||||
|
||||
private int ComputerMove()
|
||||
{
|
||||
int move = DetermineComputerMove();
|
||||
MoveAndRegister(move, homePosition: _computerHome);
|
||||
|
||||
// the result is only used to return it to the application, so translate it from an array index (between 7 and
|
||||
// 12) to a pit number (between 1 and 6)
|
||||
return move - 6;
|
||||
}
|
||||
|
||||
private int DetermineComputerMove()
|
||||
{
|
||||
int bestScore = -99;
|
||||
int move = 0;
|
||||
|
||||
// for each of the computer's possible moves, simulate them to calculate a score and pick the best one
|
||||
for (int j = 7; j < 13; j++)
|
||||
{
|
||||
if (_beans[j] <= 0)
|
||||
continue;
|
||||
|
||||
int score = SimulateMove(j);
|
||||
|
||||
if (score >= bestScore)
|
||||
{
|
||||
move = j;
|
||||
bestScore = score;
|
||||
}
|
||||
}
|
||||
|
||||
return move;
|
||||
}
|
||||
|
||||
private int SimulateMove(int move)
|
||||
{
|
||||
// make a copy of the current state, so we can safely mess with it
|
||||
var hypotheticalBeans = new int[14];
|
||||
_beans.CopyTo(hypotheticalBeans, 0);
|
||||
|
||||
// simulate the move in our copy
|
||||
Move(hypotheticalBeans, move, homePosition: _computerHome);
|
||||
|
||||
// determine the 'best' move the player could make after this (best for them, not for the computer)
|
||||
int score = ScoreBestNextPlayerMove(hypotheticalBeans);
|
||||
|
||||
// score this move by calculating how far ahead we would be after the move, and subtracting the player's next
|
||||
// move score
|
||||
score = hypotheticalBeans[_computerHome] - hypotheticalBeans[_playerHome] - score;
|
||||
|
||||
// have we seen the current set of moves before in a drawn/lost game? after 8 moves it's unlikely we'll find any
|
||||
// matches, since games will have diverged. also we don't have space to store that many moves.
|
||||
if (_moveCount < 8)
|
||||
{
|
||||
int translatedMove = move - 7; // translate from 7 through 12 to 0 through 5
|
||||
|
||||
// if the first two moves in this game were 1 and 2, and this hypothetical third move would be a 3,
|
||||
// movesSoFar would be (1 * 36) + (2 * 6) + 3 = 51
|
||||
int movesSoFar = _notWonGameMoves[^1] * 6 + translatedMove;
|
||||
|
||||
// since we store moves as a 'base 6' number, we need to divide stored moves by a power of 6
|
||||
// let's say we've a stored lost game where the moves were, in succession, 1 through 8, the value stored
|
||||
// would be:
|
||||
// 8 + (7 * 6) + (6 * 36) + (5 * 216) + (4 * 1296) + (3 * 7776) + (2 * 46656) + (1 * 279936) = 403106
|
||||
// to figure out the first three moves, we'd need to divide by 7776, resulting in 51.839...
|
||||
double divisor = Math.Pow(6.0, 7 - _moveCount);
|
||||
|
||||
foreach (int previousGameMoves in _notWonGameMoves)
|
||||
// if this combination of moves so far ultimately resulted in a draw/loss, give it a lower score
|
||||
// note that this can happen multiple times
|
||||
if (movesSoFar == (int) (previousGameMoves / divisor + 0.1))
|
||||
score -= 2;
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
private static int ScoreBestNextPlayerMove(int[] hypotheticalBeans)
|
||||
{
|
||||
int bestScore = 0;
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (hypotheticalBeans[i] <= 0)
|
||||
continue;
|
||||
|
||||
int score = ScoreNextPlayerMove(hypotheticalBeans, i);
|
||||
|
||||
if (score > bestScore)
|
||||
bestScore = score;
|
||||
}
|
||||
|
||||
return bestScore;
|
||||
}
|
||||
|
||||
private static int ScoreNextPlayerMove(int[] hypotheticalBeans, int move)
|
||||
{
|
||||
// figure out where the last bean will land
|
||||
int target = hypotheticalBeans[move] + move;
|
||||
int score = 0;
|
||||
|
||||
// if it wraps around, that means the player is adding to his own pits, which is good
|
||||
if (target > 13)
|
||||
{
|
||||
// prevent overrunning the number of pits we have
|
||||
target %= 14;
|
||||
score = 1;
|
||||
}
|
||||
|
||||
// if the player's move ends up in an empty pit, add the value of the pit on the opposite side to the score
|
||||
if (hypotheticalBeans[target] == 0 && target is not _playerHome and not _computerHome)
|
||||
score += hypotheticalBeans[12 - target];
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
private const int _playerHome = 6;
|
||||
private const int _computerHome = 13;
|
||||
private const int _initialPitValue = 3;
|
||||
|
||||
private readonly int[] _beans = new int[14];
|
||||
private readonly List<int> _notWonGameMoves = new() { 0 }; // not won means draw or lose
|
||||
private int _moveCount;
|
||||
}
|
||||
|
||||
public enum GameState
|
||||
{
|
||||
PlayerMove,
|
||||
PlayerSecondMove,
|
||||
ComputerMove,
|
||||
ComputerSecondMove,
|
||||
Done,
|
||||
}
|
||||
|
||||
public enum GameWinner
|
||||
{
|
||||
Player,
|
||||
Computer,
|
||||
Draw,
|
||||
}
|
||||
|
||||
public record struct GameOutcome(GameWinner Winner, int Difference);
|
||||
98
04_Awari/csharp/Program.cs
Normal file
98
04_Awari/csharp/Program.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using Awari;
|
||||
|
||||
Console.WriteLine(Tab(34) + "AWARI");
|
||||
Console.WriteLine(Tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
|
||||
|
||||
Game game = new();
|
||||
|
||||
while (true)
|
||||
{
|
||||
game.Reset();
|
||||
DisplayGame();
|
||||
|
||||
while (game.State != GameState.Done)
|
||||
{
|
||||
switch (game.State)
|
||||
{
|
||||
case GameState.PlayerMove:
|
||||
PlayerMove(second: false);
|
||||
break;
|
||||
case GameState.PlayerSecondMove:
|
||||
PlayerMove(second: true);
|
||||
break;
|
||||
case GameState.ComputerMove:
|
||||
ComputerTurn();
|
||||
break;
|
||||
}
|
||||
|
||||
DisplayGame();
|
||||
}
|
||||
|
||||
var outcome = game.GetOutcome();
|
||||
|
||||
string outcomeLabel =
|
||||
outcome.Winner switch
|
||||
{
|
||||
GameWinner.Computer => $"I WIN BY {outcome.Difference} POINTS",
|
||||
GameWinner.Draw => "DRAWN GAME",
|
||||
GameWinner.Player => $"YOU WIN BY {outcome.Difference} POINTS",
|
||||
_ => throw new InvalidOperationException($"Unexpected winner {outcome.Winner}."),
|
||||
};
|
||||
Console.WriteLine(outcomeLabel);
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
void DisplayGame()
|
||||
{
|
||||
// display the computer's pits
|
||||
Console.Write(" ");
|
||||
foreach (var pit in game.ComputerPits.Reverse())
|
||||
Console.Write($"{pit,2} ");
|
||||
Console.WriteLine();
|
||||
|
||||
// display both homes
|
||||
Console.WriteLine($"{game.ComputerHome,2}{Tab(19)}{game.PlayerHome,2}");
|
||||
|
||||
// display the player's pits
|
||||
Console.Write(" ");
|
||||
foreach (var pit in game.PlayerPits)
|
||||
Console.Write($"{pit,2} ");
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
void PlayerMove(bool second = false)
|
||||
{
|
||||
int move = GetMove(second);
|
||||
game.PlayerMove(move);
|
||||
}
|
||||
|
||||
int GetMove(bool second)
|
||||
{
|
||||
string prompt = second ? "AGAIN? " : "YOUR MOVE? ";
|
||||
|
||||
while (true)
|
||||
{
|
||||
Console.Write(prompt);
|
||||
|
||||
string input = Console.ReadLine() ?? "";
|
||||
|
||||
// input must be a number between 1 and 6, and the pit must have > 0 beans
|
||||
if (int.TryParse(input, out int move)
|
||||
&& game.IsLegalPlayerMove(move))
|
||||
return move;
|
||||
|
||||
Console.WriteLine("ILLEGAL MOVE");
|
||||
}
|
||||
}
|
||||
|
||||
void ComputerTurn()
|
||||
{
|
||||
var moves = game.ComputerTurn();
|
||||
string movesString = string.Join(",", moves);
|
||||
|
||||
Console.WriteLine($"MY MOVE IS {movesString}");
|
||||
}
|
||||
|
||||
string Tab(int n) => new(' ', n);
|
||||
11
04_Awari/csharp/csharp.csproj
Normal file
11
04_Awari/csharp/csharp.csproj
Normal file
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>Awari</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,7 +1,20 @@
|
||||
### Bagels
|
||||
|
||||
In this game, the computer picks a 3-digit secret number using the digits 0 to 9 and you attempt to guess what it is. You are allowed up to twenty guesses. No digit is repeated. After each guess the computer will give you clues about your guess as follows:
|
||||
|
||||
- PICO One digit is correct, but in the wrong place
|
||||
- FERMI One digit is in the correct place
|
||||
- BAGELS No digit is correct
|
||||
|
||||
You will learn to draw inferences from the clues and, with practice, you’ll learn to improve your score. There are several good strategies for playing Bagels. After you have found a good strategy, see if you can improve it. Or try a different strategy altogether to see if it is any better. While the program allows up to twenty guesses, if you use a good strategy it should not take more than eight guesses to get any number.
|
||||
|
||||
The original authors of this program are D. Resek and P. Rowe of the Lawrence Hall of Science, Berkeley, California.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=9
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=9)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=21)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
195
05_Bagels/perl/bagels.pl
Executable file
195
05_Bagels/perl/bagels.pl
Executable file
@@ -0,0 +1,195 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# global variable declaration (just the user's score)
|
||||
my($Y) = 0;
|
||||
|
||||
|
||||
# yes_input is a subroutine that returns a true value
|
||||
# if the first character of the user's input from STDIN
|
||||
# is a 'Y' (checking case-insensitively via regex)
|
||||
sub yes_input {
|
||||
chomp(my $A = <STDIN>);
|
||||
return $A =~ m/^Y/i;
|
||||
}
|
||||
|
||||
# Main code starts here.
|
||||
|
||||
print ' 'x32; print "Bagels\n";
|
||||
print ' 'x14; print "Creative Computing Morristown, New Jersey\n\n";
|
||||
|
||||
# Provide instructions if requested
|
||||
print "Would you like the rules (yes or no)? ";
|
||||
if (yes_input()) {
|
||||
|
||||
# Print out the instructions using a here doc
|
||||
# (useful for large blocks of text)
|
||||
print <<HERE;
|
||||
|
||||
I am thinking of a three-digit number. Try to guess
|
||||
my number and I will give you clues as follows:
|
||||
PICO - one digit correct but in the wrong position
|
||||
FERMI - one digit correct and in the right place
|
||||
BAGELS - no digits correct
|
||||
HERE
|
||||
}
|
||||
|
||||
# There are three code loops here. The outermost one, labeled 'PLAY',
|
||||
# performs one game start to finish every time it runs.
|
||||
# The next loop is a for loop that implements the required 20 guesses.
|
||||
# And the innermost loop, labeled 'CHECK', does the game logic of
|
||||
# checking the user's guess to make sure it's valid, figuring out
|
||||
# the response, and rewarding the user if they won.
|
||||
|
||||
PLAY: while (1) {
|
||||
|
||||
# The computer's number is three randomly selected unique digits.
|
||||
# To generate the number, 3 digits are randomly splice()d out
|
||||
# of the @DIGITS array, which is initialized with the digits 0 to 9.
|
||||
my @DIGITS = (0..9);
|
||||
my @A = ();
|
||||
push @A, splice(@DIGITS, int(rand(scalar @DIGITS)), 1) for 1..3;
|
||||
|
||||
print "\n";
|
||||
print "O.K. I have a number in mind.\n";
|
||||
|
||||
for my $i (1..20) {
|
||||
|
||||
# Note that the CHECK loop will automatically loop to ask
|
||||
# for the user's input, and it's only with the 'next' and
|
||||
# 'last' statements that this loop is exited. So if the
|
||||
# user's input is somehow invalid, we just print out an
|
||||
# appropriate message. Execution will by default return
|
||||
# to the start of the loop, and only leaves the loop if
|
||||
# the user's input is successfully parsed and accepted
|
||||
# (look for the 'next' and 'last' statements below).
|
||||
|
||||
CHECK: while (1) {
|
||||
printf("Guess # %2d ? ", $i);
|
||||
chomp(my $A = <STDIN>);
|
||||
|
||||
# Use a regex to check if the user entered three digits,
|
||||
# and complain if they did not.
|
||||
if ($A !~ m{^(\d)(\d)(\d)$}) {
|
||||
print "What?\n";
|
||||
# Program execution will now pass through the rest
|
||||
# of the logic below and loop back to the start
|
||||
# of the CHECK loop.
|
||||
} else {
|
||||
|
||||
# As a side effect of the regex match above, the
|
||||
# $1, $2, and $3 variables are each of the digits
|
||||
# of the user's guess. Perl treats numbers and
|
||||
# strings interchangably, so we will not have to
|
||||
# use the ASC() conversion functions required
|
||||
# by the BASIC program.
|
||||
my @B = ($1,$2,$3);
|
||||
|
||||
# Check for duplicate digits in the user's guess
|
||||
if ($B[0] == $B[1] || $B[0] == $B[2] || $B[1] == $B[2]) {
|
||||
print "Oh, I forgot to tell you that the number I have in mind\n";
|
||||
print "has no two digits the same.\n";
|
||||
# Again, no further action is required here
|
||||
# because we want to loop back to the start
|
||||
# of the CHECK loop.
|
||||
} else {
|
||||
|
||||
# This code block is the actual game logic, so
|
||||
# it's executed only if the user's input has
|
||||
# passed all the above checks.
|
||||
my($C,$D);
|
||||
$C = 0; $D = 0;
|
||||
|
||||
# As a replacement for the original BASIC logic,
|
||||
# this for loop works over an anonymous array of
|
||||
# pairs of digits to compare the computer's and
|
||||
# the user's digits to see how many similar ones
|
||||
# there are. Keep in mind that Perl arrays are
|
||||
# zero-indexed, so we're comparing items numbered
|
||||
# 0, 1, and 2, instead of 1, 2, and 3 in BASIC.
|
||||
|
||||
for my $PAIR ( [0,1], [1,0], [1,2], [2,1], [0,2], [2,0] ) {
|
||||
if ($A[$PAIR->[0]] == $B[$PAIR->[1]]) {
|
||||
++$C;
|
||||
}
|
||||
}
|
||||
|
||||
# Check for digits that are correctly guessed
|
||||
for my $i (0..2) {
|
||||
if ($A[$i] == $B[$i]) {
|
||||
++$D;
|
||||
}
|
||||
}
|
||||
|
||||
# If the user guessed all 3 digits they get
|
||||
# a point, and the 'PLAY' loop is restarted
|
||||
# (see the 'continue' loop below)
|
||||
if ($D == 3) {
|
||||
print "You got it!!!\n\n";
|
||||
++$Y;
|
||||
next PLAY;
|
||||
}
|
||||
|
||||
# Print out the clues. The 'x' operator
|
||||
# prints out the string the indicated number
|
||||
# of times. The "BAGELS" line uses Perl's
|
||||
# ternary operator to print the word if
|
||||
# the expression ($C + $D) is equal to 0.
|
||||
|
||||
printf("%s%s%s\n",
|
||||
"PICO " x$C,
|
||||
"FERMI "x$D,
|
||||
($C+$D==0 ? "BAGELS" : '')
|
||||
);
|
||||
|
||||
# Program execution leaves the CHECK loop and
|
||||
# goes to the next iteration of the $i loop.
|
||||
last CHECK;
|
||||
|
||||
} # end of game logic else block
|
||||
} # end of regex match else block
|
||||
|
||||
# If program execution reaches this particular point,
|
||||
# then the user's input has not been accepted (the
|
||||
# only ways out of this loop are the "next PLAY" statement
|
||||
# when the user wins, and the "last CHECK" statement
|
||||
# when the user's input is successfully parsed).
|
||||
# So the program execution goes back to the top of the
|
||||
# CHECK loop, printing the request for user input
|
||||
# again.
|
||||
|
||||
} # end of CHECK loop
|
||||
|
||||
# This location is reached by the "last CHECK" statement,
|
||||
# and it's another execution of the $i loop.
|
||||
|
||||
} # end of $i loop
|
||||
|
||||
# If program execution reaches here, the user has guessed 20
|
||||
# times and not won.
|
||||
|
||||
print "Oh well.\n";
|
||||
printf("That's twenty guesses. My number was %s\n", join('',@A));
|
||||
|
||||
} # end of the PLAY loop
|
||||
|
||||
# This 'continue' block is executed before the conditional part of the
|
||||
# PLAY loop is evaluated, so we can ask if the user wants another game
|
||||
# (i.e., if we should restart the PLAY loop).
|
||||
|
||||
continue {
|
||||
|
||||
# This 'continue' loop is reached either when the PLAY loop has completed
|
||||
# or via the 'next PLAY' statement when the user wins a game. In either
|
||||
# case we ask if the player wants to go again, and use the 'last'
|
||||
# statement to exit the loop if the response is not yes.
|
||||
print "Play again (yes or no) ? ";
|
||||
last unless yes_input();
|
||||
}
|
||||
|
||||
# And as in the original BASIC program, print out
|
||||
# the user's score only if it is > 0.
|
||||
printf("A %d point bagels buff!\n", $Y) if $Y > 0;
|
||||
print "Hope you had fun. Bye.\n";
|
||||
@@ -1,7 +1,14 @@
|
||||
### Banner
|
||||
|
||||
This program creates a large banner on a terminal of any message you input. The letters may be any dimension of you wish although the letter height plus distance from left-hand side should not exceed 6 inches. Experiment with the height and width until you get a pleasing effect on whatever terminal you are using.
|
||||
|
||||
This program was written by Leonard Rosendust of Brooklyn, New York.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=10
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=10)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=25)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,30 @@
|
||||
### Basketball
|
||||
|
||||
This program simulates a game of basketball between Dartmouth College and an opponent of your choice. You are the Dartmouth captain and control the type of shot and defense during the course of the game.
|
||||
|
||||
There are four types of shots:
|
||||
1. Long Jump Shot (30ft)
|
||||
2. Short Jump Shot (15ft)
|
||||
3. Lay Up
|
||||
4. Set Shot
|
||||
|
||||
Both teams use the same defense, but you may call it:
|
||||
- Enter (6): Press
|
||||
- Enter (6.5): Man-to-man
|
||||
- Enter (7): Zone
|
||||
- Enter (7.5): None
|
||||
|
||||
To change defense, type “0” as your next shot.
|
||||
|
||||
Note: The game is biased slightly in favor of Dartmouth. The average probability of a Dartmouth shot being good is 62.95% compared to a probability of 61.85% for their opponent. (This makes the sample run slightly remarkable in that Cornell won by a score of 45 to 42 Hooray for the Big Red!)
|
||||
|
||||
Charles Bacheller of Dartmouth College was the original author of this game.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=12
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=12)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=27)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,20 @@
|
||||
### Batnum
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=14
|
||||
The game starts with an imaginary pile of objects, coins for example. You and your opponent (the computer) alternately remove objects from the pile. You specify in advance the minimum and maximum number of objects that can be taken on each turn. You also specify in advance how winning is defined:
|
||||
1. To take the last object
|
||||
2. To avoid taking the last object
|
||||
|
||||
You may also determine whether you or the computer go first.
|
||||
|
||||
The strategy of this game is based on modulo arithmetic. If the maximum number of objects a player may remove in a turn is M, then to gain a winning position a player at the end of his turn must leave a stack of 1 modulo (M+1) coins. If you don’t understand this, play the game 23 Matches first, then BATNUM, and have fun!
|
||||
|
||||
BATNUM is a generalized version of a great number of manual remove-the-object games. The original computer version was written by one of the two originators of the BASIC language, John Kemeny of Dartmouth College.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=14)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=29)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,27 @@
|
||||
### Battle
|
||||
|
||||
BATTLE is based on the popular game Battleship which is primarily played to familiarize people with the location and designation of points on a coordinate plane.
|
||||
|
||||
BATTLE first randomly sets up the bad guy’s fleet disposition on a 6 by 6 matrix or grid. The fleet consists of six ships:
|
||||
- Two destroyers (ships number 1 and 2) which are two units long
|
||||
- Two cruisers (ships number 3 and 4) which are three units long
|
||||
- Two aircraft carriers (ships number 5 and 6) which are four units long
|
||||
|
||||
The program then prints out this fleet disposition in a coded or disguised format (see the sample computer print-out). You then proceed to sink the various ships by typing in the coordinates (two digits. each from 1 to 6, separated by a comma) of the place where you want to drop a bomb, if you’ll excuse the expression. The computer gives the appropriate response (splash, hit, etc.) which you should record on a 6 by 6 matrix. You are thus building a representation of the actual fleet disposition which you will hopefully use to decode the coded fleet disposition printed out by the computer. Each time a ship is sunk, the computer prints out which ships have been sunk so far and also gives you a “SPLASH/HIT RATIO.”
|
||||
|
||||
The first thing you should learn is how to locate and designate positions on the matrix, and specifically the difference between “3,4” and “4,3.” Our method corresponds to the location of points on the coordinate plane rather than the location of numbers in a standard algebraic matrix: the first number gives the column counting from left to right and the second number gives the row counting from bottom to top.
|
||||
|
||||
The second thing you should learn about is the splash/hit ratio. “What is a ratio?” A good reply is “It’s a fraction or quotient.” Specifically, the spash/hit ratio is the number of splashes divided by the number of hits. If you had 9 splashes and 15 hits, the ratio would be 9/15 or 3/5, both of which are correct. The computer would give this splash/hit ratio as .6.
|
||||
|
||||
The main objective and primary education benefit of BATTLE comes from attempting to decode the bas guys’ fleet disposition code. To do this, you must make a comparison between the coded matrix and the actual matrix which you construct as you play the game.
|
||||
|
||||
The original author of both the program and these descriptive notes is Ray Westergard of Lawrence Hall of Science, Berkeley, California.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=15
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=15)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=30)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
### Blackjack
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=18
|
||||
This is a simulation of the card game of Blackjack or 21, Las Vegas style. This rather comprehensive version allows for up to seven players. On each hand a player may get another card (a hit), stand, split a hand in the event two identical cards were received or double down. Also, the dealer will ask for an insurance bet if he has an exposed ace.
|
||||
|
||||
Cards are automatically reshuffled as the 51st card is reached. For greater realism, you may wish to change this to the 41st card. Actually, fanatical purists will want to modify the program so it uses three decks of cards instead of just one.
|
||||
|
||||
This program originally surfaced at Digital Equipment Corp.; the author is unknown.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=18)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=33)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
### Bombardment
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=22
|
||||
BOMBARDMENT is played on two, 5x5 grids or boards with 25 outpost locations numbered 1 to 25. Both you and the computer have four platoons of troops that can be located at any four outposts on your respective grids.
|
||||
|
||||
At the start of the game, you locate (or hide) your four platoons on your grid. The computer does the same on it’s grid. You then take turns firing missiles or bombs at each other’s outposts trying to destroy all four platoons. The one who finds all four opponents’ platoons first, wins.
|
||||
|
||||
This program was slightly modified from the original written by Martin Burdash of Parlin, New Jersey.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=22)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=37)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
### Bombs Away
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=24
|
||||
In this program, you fly a World War II bomber for one of the four protagonists of the war. You then pick your target or the type of plane you are flying. Depending on your flying experience and the quality of enemy defenders, you then may accomplish your mission, get shot down, or make it back through enemy fire. In any case, you get a chance to fly again.
|
||||
|
||||
David Ahl modified the original program which was created by David Sherman while a student at Curtis Jr. High School, Sudbury, Massachusetts.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=24)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=39)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
31
12_Bombs_Away/csharp/BombsAway.sln
Normal file
31
12_Bombs_Away/csharp/BombsAway.sln
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.32014.148
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BombsAwayConsole", "BombsAwayConsole\BombsAwayConsole.csproj", "{D80015FA-423C-4A16-AA2B-16669245AD59}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BombsAwayGame", "BombsAwayGame\BombsAwayGame.csproj", "{F57AEC18-FEE9-4F08-9F20-DFC56EFE6BFC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{D80015FA-423C-4A16-AA2B-16669245AD59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D80015FA-423C-4A16-AA2B-16669245AD59}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D80015FA-423C-4A16-AA2B-16669245AD59}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D80015FA-423C-4A16-AA2B-16669245AD59}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F57AEC18-FEE9-4F08-9F20-DFC56EFE6BFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F57AEC18-FEE9-4F08-9F20-DFC56EFE6BFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F57AEC18-FEE9-4F08-9F20-DFC56EFE6BFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F57AEC18-FEE9-4F08-9F20-DFC56EFE6BFC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {39B2ECFB-037D-4335-BBD2-64892E953DD4}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BombsAwayGame\BombsAwayGame.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
134
12_Bombs_Away/csharp/BombsAwayConsole/ConsoleUserInterface.cs
Normal file
134
12_Bombs_Away/csharp/BombsAwayConsole/ConsoleUserInterface.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
namespace BombsAwayConsole;
|
||||
|
||||
/// <summary>
|
||||
/// Implements <see cref="BombsAwayGame.IUserInterface"/> by writing to and reading from <see cref="Console"/>.
|
||||
/// </summary>
|
||||
internal class ConsoleUserInterface : BombsAwayGame.IUserInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// Write message to console.
|
||||
/// </summary>
|
||||
/// <param name="message">Message to display.</param>
|
||||
public void Output(string message)
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write choices with affixed indexes, allowing the user to choose by index.
|
||||
/// </summary>
|
||||
/// <param name="message">Message to display.</param>
|
||||
/// <param name="choices">Choices to display.</param>
|
||||
/// <returns>Choice that user picked.</returns>
|
||||
public int Choose(string message, IList<string> choices)
|
||||
{
|
||||
IEnumerable<string> choicesWithIndexes = choices.Select((choice, index) => $"{choice}({index + 1})");
|
||||
string choiceText = string.Join(", ", choicesWithIndexes);
|
||||
Output($"{message} -- {choiceText}");
|
||||
|
||||
ISet<ConsoleKey> allowedKeys = ConsoleKeysFromList(choices);
|
||||
ConsoleKey? choice;
|
||||
do
|
||||
{
|
||||
choice = ReadChoice(allowedKeys);
|
||||
if (choice is null)
|
||||
{
|
||||
Output("TRY AGAIN...");
|
||||
}
|
||||
}
|
||||
while (choice is null);
|
||||
|
||||
return ListIndexFromConsoleKey(choice.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert the given list to its <see cref="ConsoleKey"/> equivalents. This generates keys that map
|
||||
/// the first element to <see cref="ConsoleKey.D1"/>, the second element to <see cref="ConsoleKey.D2"/>,
|
||||
/// and so on, up to the last element of the list.
|
||||
/// </summary>
|
||||
/// <param name="list">List whose elements will be converted to <see cref="ConsoleKey"/> equivalents.</param>
|
||||
/// <returns><see cref="ConsoleKey"/> equivalents from <paramref name="list"/>.</returns>
|
||||
private ISet<ConsoleKey> ConsoleKeysFromList(IList<string> list)
|
||||
{
|
||||
IEnumerable<int> indexes = Enumerable.Range((int)ConsoleKey.D1, list.Count);
|
||||
return new HashSet<ConsoleKey>(indexes.Cast<ConsoleKey>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert the given console key to its list index equivalent. This assumes the key was generated from
|
||||
/// <see cref="ConsoleKeysFromList(IList{string})"/>
|
||||
/// </summary>
|
||||
/// <param name="key">Key to convert to its list index equivalent.</param>
|
||||
/// <returns>List index equivalent of key.</returns>
|
||||
private int ListIndexFromConsoleKey(ConsoleKey key)
|
||||
{
|
||||
return key - ConsoleKey.D1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a key from the console and return it if it is in the given allowed keys.
|
||||
/// </summary>
|
||||
/// <param name="allowedKeys">Allowed keys.</param>
|
||||
/// <returns>Key read from <see cref="Console"/>, if it is in <paramref name="allowedKeys"/>; null otherwise./></returns>
|
||||
private ConsoleKey? ReadChoice(ISet<ConsoleKey> allowedKeys)
|
||||
{
|
||||
ConsoleKeyInfo keyInfo = ReadKey();
|
||||
return allowedKeys.Contains(keyInfo.Key) ? keyInfo.Key : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read key from <see cref="Console"/>.
|
||||
/// </summary>
|
||||
/// <returns>Key read from <see cref="Console"/>.</returns>
|
||||
private ConsoleKeyInfo ReadKey()
|
||||
{
|
||||
ConsoleKeyInfo result = Console.ReadKey(intercept: false);
|
||||
// Write a blank line to the console so the displayed key is on its own line.
|
||||
Console.WriteLine();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allow user to choose 'Y' or 'N' from <see cref="Console"/>.
|
||||
/// </summary>
|
||||
/// <param name="message">Message to display.</param>
|
||||
/// <returns>True if user chose 'Y', false if user chose 'N'.</returns>
|
||||
public bool ChooseYesOrNo(string message)
|
||||
{
|
||||
Output(message);
|
||||
ConsoleKey? choice;
|
||||
do
|
||||
{
|
||||
choice = ReadChoice(new HashSet<ConsoleKey>(new[] { ConsoleKey.Y, ConsoleKey.N }));
|
||||
if (choice is null)
|
||||
{
|
||||
Output("ENTER Y OR N");
|
||||
}
|
||||
}
|
||||
while (choice is null);
|
||||
|
||||
return choice.Value == ConsoleKey.Y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get integer by reading a line from <see cref="Console"/>.
|
||||
/// </summary>
|
||||
/// <returns>Integer read from <see cref="Console"/>.</returns>
|
||||
public int InputInteger()
|
||||
{
|
||||
bool resultIsValid;
|
||||
int result;
|
||||
do
|
||||
{
|
||||
string? integerText = Console.ReadLine();
|
||||
resultIsValid = int.TryParse(integerText, out result);
|
||||
if (!resultIsValid)
|
||||
{
|
||||
Output("PLEASE ENTER A NUMBER");
|
||||
}
|
||||
}
|
||||
while (!resultIsValid);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
26
12_Bombs_Away/csharp/BombsAwayConsole/Program.cs
Normal file
26
12_Bombs_Away/csharp/BombsAwayConsole/Program.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using BombsAwayConsole;
|
||||
using BombsAwayGame;
|
||||
|
||||
/// Create and play <see cref="Game"/>s using a <see cref="ConsoleUserInterface"/>.
|
||||
PlayGameWhileUserWantsTo(new ConsoleUserInterface());
|
||||
|
||||
void PlayGameWhileUserWantsTo(ConsoleUserInterface ui)
|
||||
{
|
||||
do
|
||||
{
|
||||
new Game(ui).Play();
|
||||
}
|
||||
while (UserWantsToPlayAgain(ui));
|
||||
}
|
||||
|
||||
bool UserWantsToPlayAgain(IUserInterface ui)
|
||||
{
|
||||
bool result = ui.ChooseYesOrNo("ANOTHER MISSION (Y OR N)?");
|
||||
if (!result)
|
||||
{
|
||||
Console.WriteLine("CHICKEN !!!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
22
12_Bombs_Away/csharp/BombsAwayGame/AlliesSide.cs
Normal file
22
12_Bombs_Away/csharp/BombsAwayGame/AlliesSide.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace BombsAwayGame;
|
||||
|
||||
/// <summary>
|
||||
/// Allies protagonist. Can fly missions in a Liberator, B-29, B-17, or Lancaster.
|
||||
/// </summary>
|
||||
internal class AlliesSide : MissionSide
|
||||
{
|
||||
public AlliesSide(IUserInterface ui)
|
||||
: base(ui)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string ChooseMissionMessage => "AIRCRAFT";
|
||||
|
||||
protected override IList<Mission> AllMissions => new Mission[]
|
||||
{
|
||||
new("LIBERATOR", "YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI."),
|
||||
new("B-29", "YOU'RE DUMPING THE A-BOMB ON HIROSHIMA."),
|
||||
new("B-17", "YOU'RE CHASING THE BISMARK IN THE NORTH SEA."),
|
||||
new("LANCASTER", "YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.")
|
||||
};
|
||||
}
|
||||
9
12_Bombs_Away/csharp/BombsAwayGame/BombsAwayGame.csproj
Normal file
9
12_Bombs_Away/csharp/BombsAwayGame/BombsAwayGame.csproj
Normal file
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
8
12_Bombs_Away/csharp/BombsAwayGame/EnemyArtillery.cs
Normal file
8
12_Bombs_Away/csharp/BombsAwayGame/EnemyArtillery.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace BombsAwayGame;
|
||||
|
||||
/// <summary>
|
||||
/// Represents enemy artillery.
|
||||
/// </summary>
|
||||
/// <param name="Name">Name of artillery type.</param>
|
||||
/// <param name="Accuracy">Accuracy of artillery. This is the `T` variable in the original BASIC.</param>
|
||||
internal record class EnemyArtillery(string Name, int Accuracy);
|
||||
58
12_Bombs_Away/csharp/BombsAwayGame/Game.cs
Normal file
58
12_Bombs_Away/csharp/BombsAwayGame/Game.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
namespace BombsAwayGame;
|
||||
|
||||
/// <summary>
|
||||
/// Plays the Bombs Away game using a supplied <see cref="IUserInterface"/>.
|
||||
/// </summary>
|
||||
public class Game
|
||||
{
|
||||
private readonly IUserInterface _ui;
|
||||
|
||||
/// <summary>
|
||||
/// Create game instance using the given UI.
|
||||
/// </summary>
|
||||
/// <param name="ui">UI to use for game.</param>
|
||||
public Game(IUserInterface ui)
|
||||
{
|
||||
_ui = ui;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Play game. Choose a side and play the side's logic.
|
||||
/// </summary>
|
||||
public void Play()
|
||||
{
|
||||
_ui.Output("YOU ARE A PILOT IN A WORLD WAR II BOMBER.");
|
||||
Side side = ChooseSide();
|
||||
side.Play();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a <see cref="Side"/>.
|
||||
/// </summary>
|
||||
/// <param name="Name">Name of side.</param>
|
||||
/// <param name="CreateSide">Create instance of side that this descriptor represents.</param>
|
||||
private record class SideDescriptor(string Name, Func<Side> CreateSide);
|
||||
|
||||
/// <summary>
|
||||
/// Choose side and return a new instance of that side.
|
||||
/// </summary>
|
||||
/// <returns>New instance of side that was chosen.</returns>
|
||||
private Side ChooseSide()
|
||||
{
|
||||
SideDescriptor[] sides = AllSideDescriptors;
|
||||
string[] sideNames = sides.Select(a => a.Name).ToArray();
|
||||
int index = _ui.Choose("WHAT SIDE", sideNames);
|
||||
return sides[index].CreateSide();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// All side descriptors.
|
||||
/// </summary>
|
||||
private SideDescriptor[] AllSideDescriptors => new SideDescriptor[]
|
||||
{
|
||||
new("ITALY", () => new ItalySide(_ui)),
|
||||
new("ALLIES", () => new AlliesSide(_ui)),
|
||||
new("JAPAN", () => new JapanSide(_ui)),
|
||||
new("GERMANY", () => new GermanySide(_ui)),
|
||||
};
|
||||
}
|
||||
21
12_Bombs_Away/csharp/BombsAwayGame/GermanySide.cs
Normal file
21
12_Bombs_Away/csharp/BombsAwayGame/GermanySide.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace BombsAwayGame;
|
||||
|
||||
/// <summary>
|
||||
/// Germany protagonist. Can fly missions to Russia, England, and France.
|
||||
/// </summary>
|
||||
internal class GermanySide : MissionSide
|
||||
{
|
||||
public GermanySide(IUserInterface ui)
|
||||
: base(ui)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string ChooseMissionMessage => "A NAZI, EH? OH WELL. ARE YOU GOING FOR";
|
||||
|
||||
protected override IList<Mission> AllMissions => new Mission[]
|
||||
{
|
||||
new("RUSSIA", "YOU'RE NEARING STALINGRAD."),
|
||||
new("ENGLAND", "NEARING LONDON. BE CAREFUL, THEY'VE GOT RADAR."),
|
||||
new("FRANCE", "NEARING VERSAILLES. DUCK SOUP. THEY'RE NEARLY DEFENSELESS.")
|
||||
};
|
||||
}
|
||||
38
12_Bombs_Away/csharp/BombsAwayGame/IUserInterface.cs
Normal file
38
12_Bombs_Away/csharp/BombsAwayGame/IUserInterface.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace BombsAwayGame;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an interface for supplying data to the game.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Abstracting the UI allows us to concentrate its concerns in one part of our code and to change UI behavior
|
||||
/// without creating any risk of changing the game logic. It also allows us to supply an automated UI for tests.
|
||||
/// </remarks>
|
||||
public interface IUserInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// Display the given message.
|
||||
/// </summary>
|
||||
/// <param name="message">Message to display.</param>
|
||||
void Output(string message);
|
||||
|
||||
/// <summary>
|
||||
/// Choose an item from the given choices.
|
||||
/// </summary>
|
||||
/// <param name="message">Message to display.</param>
|
||||
/// <param name="choices">Choices to choose from.</param>
|
||||
/// <returns>Index of choice in <paramref name="choices"/> that user chose.</returns>
|
||||
int Choose(string message, IList<string> choices);
|
||||
|
||||
/// <summary>
|
||||
/// Allow user to choose Yes or No.
|
||||
/// </summary>
|
||||
/// <param name="message">Message to display.</param>
|
||||
/// <returns>True if user chose Yes, false if user chose No.</returns>
|
||||
bool ChooseYesOrNo(string message);
|
||||
|
||||
/// <summary>
|
||||
/// Get integer from user.
|
||||
/// </summary>
|
||||
/// <returns>Integer supplied by user.</returns>
|
||||
int InputInteger();
|
||||
}
|
||||
21
12_Bombs_Away/csharp/BombsAwayGame/ItalySide.cs
Normal file
21
12_Bombs_Away/csharp/BombsAwayGame/ItalySide.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace BombsAwayGame;
|
||||
|
||||
/// <summary>
|
||||
/// Italy protagonist. Can fly missions to Albania, Greece, and North Africa.
|
||||
/// </summary>
|
||||
internal class ItalySide : MissionSide
|
||||
{
|
||||
public ItalySide(IUserInterface ui)
|
||||
: base(ui)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string ChooseMissionMessage => "YOUR TARGET";
|
||||
|
||||
protected override IList<Mission> AllMissions => new Mission[]
|
||||
{
|
||||
new("ALBANIA", "SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE."),
|
||||
new("GREECE", "BE CAREFUL!!!"),
|
||||
new("NORTH AFRICA", "YOU'RE GOING FOR THE OIL, EH?")
|
||||
};
|
||||
}
|
||||
38
12_Bombs_Away/csharp/BombsAwayGame/JapanSide.cs
Normal file
38
12_Bombs_Away/csharp/BombsAwayGame/JapanSide.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace BombsAwayGame;
|
||||
|
||||
/// <summary>
|
||||
/// Japan protagonist. Flies a kamikaze mission, which has a different logic from <see cref="MissionSide"/>s.
|
||||
/// </summary>
|
||||
internal class JapanSide : Side
|
||||
{
|
||||
public JapanSide(IUserInterface ui)
|
||||
: base(ui)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform a kamikaze mission. If first kamikaze mission, it will succeed 65% of the time. If it's not
|
||||
/// first kamikaze mission, perform an enemy counterattack.
|
||||
/// </summary>
|
||||
public override void Play()
|
||||
{
|
||||
UI.Output("YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.");
|
||||
|
||||
bool isFirstMission = UI.ChooseYesOrNo("YOUR FIRST KAMIKAZE MISSION(Y OR N)?");
|
||||
if (!isFirstMission)
|
||||
{
|
||||
// LINE 207 of original BASIC: hitRatePercent is initialized to 0,
|
||||
// but R, the type of artillery, is not initialized at all. Setting
|
||||
// R = 1, which is to say EnemyArtillery = Guns, gives the same result.
|
||||
EnemyCounterattack(Guns, hitRatePercent: 0);
|
||||
}
|
||||
else if (RandomFrac() > 0.65)
|
||||
{
|
||||
MissionSucceeded();
|
||||
}
|
||||
else
|
||||
{
|
||||
MissionFailed();
|
||||
}
|
||||
}
|
||||
}
|
||||
8
12_Bombs_Away/csharp/BombsAwayGame/Mission.cs
Normal file
8
12_Bombs_Away/csharp/BombsAwayGame/Mission.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace BombsAwayGame;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a mission that can be flown by a <see cref="MissionSide"/>.
|
||||
/// </summary>
|
||||
/// <param name="Name">Name of mission.</param>
|
||||
/// <param name="Description">Description of mission.</param>
|
||||
internal record class Mission(string Name, string Description);
|
||||
208
12_Bombs_Away/csharp/BombsAwayGame/MissionSide.cs
Normal file
208
12_Bombs_Away/csharp/BombsAwayGame/MissionSide.cs
Normal file
@@ -0,0 +1,208 @@
|
||||
namespace BombsAwayGame;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a protagonist that chooses a standard (non-kamikaze) mission.
|
||||
/// </summary>
|
||||
internal abstract class MissionSide : Side
|
||||
{
|
||||
/// <summary>
|
||||
/// Create instance using the given UI.
|
||||
/// </summary>
|
||||
/// <param name="ui">UI to use.</param>
|
||||
public MissionSide(IUserInterface ui)
|
||||
: base(ui)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reasonable upper bound for missions flown previously.
|
||||
/// </summary>
|
||||
private const int MaxMissionCount = 160;
|
||||
|
||||
/// <summary>
|
||||
/// Choose a mission and attempt it. If attempt fails, perform an enemy counterattack.
|
||||
/// </summary>
|
||||
public override void Play()
|
||||
{
|
||||
Mission mission = ChooseMission();
|
||||
UI.Output(mission.Description);
|
||||
|
||||
int missionCount = MissionCountFromUI();
|
||||
CommentOnMissionCount(missionCount);
|
||||
|
||||
AttemptMission(missionCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Choose a mission.
|
||||
/// </summary>
|
||||
/// <returns>Mission chosen.</returns>
|
||||
private Mission ChooseMission()
|
||||
{
|
||||
IList<Mission> missions = AllMissions;
|
||||
string[] missionNames = missions.Select(a => a.Name).ToArray();
|
||||
int index = UI.Choose(ChooseMissionMessage, missionNames);
|
||||
return missions[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Message to display when choosing a mission.
|
||||
/// </summary>
|
||||
protected abstract string ChooseMissionMessage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// All aviailable missions to choose from.
|
||||
/// </summary>
|
||||
protected abstract IList<Mission> AllMissions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Get mission count from UI. If mission count exceeds a reasonable maximum, ask UI again.
|
||||
/// </summary>
|
||||
/// <returns>Mission count from UI.</returns>
|
||||
private int MissionCountFromUI()
|
||||
{
|
||||
const string HowManyMissions = "HOW MANY MISSIONS HAVE YOU FLOWN?";
|
||||
string inputMessage = HowManyMissions;
|
||||
|
||||
bool resultIsValid;
|
||||
int result;
|
||||
do
|
||||
{
|
||||
UI.Output(inputMessage);
|
||||
result = UI.InputInteger();
|
||||
if (result < 0)
|
||||
{
|
||||
UI.Output($"NUMBER OF MISSIONS CAN'T BE NEGATIVE.");
|
||||
resultIsValid = false;
|
||||
}
|
||||
else if (result > MaxMissionCount)
|
||||
{
|
||||
resultIsValid = false;
|
||||
UI.Output($"MISSIONS, NOT MILES...{MaxMissionCount} MISSIONS IS HIGH EVEN FOR OLD-TIMERS.");
|
||||
inputMessage = "NOW THEN, " + HowManyMissions;
|
||||
}
|
||||
else
|
||||
{
|
||||
resultIsValid = true;
|
||||
}
|
||||
}
|
||||
while (!resultIsValid);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display a message about the given mission count, if it is unusually high or low.
|
||||
/// </summary>
|
||||
/// <param name="missionCount">Mission count to comment on.</param>
|
||||
private void CommentOnMissionCount(int missionCount)
|
||||
{
|
||||
if (missionCount >= 100)
|
||||
{
|
||||
UI.Output("THAT'S PUSHING THE ODDS!");
|
||||
}
|
||||
else if (missionCount < 25)
|
||||
{
|
||||
UI.Output("FRESH OUT OF TRAINING, EH?");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt mission.
|
||||
/// </summary>
|
||||
/// <param name="missionCount">Number of missions previously flown. Higher mission counts will yield a higher probability of success.</param>
|
||||
private void AttemptMission(int missionCount)
|
||||
{
|
||||
if (missionCount < RandomInteger(0, MaxMissionCount))
|
||||
{
|
||||
MissedTarget();
|
||||
}
|
||||
else
|
||||
{
|
||||
MissionSucceeded();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display message indicating that target was missed. Choose enemy artillery and perform a counterattack.
|
||||
/// </summary>
|
||||
private void MissedTarget()
|
||||
{
|
||||
UI.Output("MISSED TARGET BY " + (2 + RandomInteger(0, 30)) + " MILES!");
|
||||
UI.Output("NOW YOU'RE REALLY IN FOR IT !!");
|
||||
|
||||
// Choose enemy and counterattack.
|
||||
EnemyArtillery enemyArtillery = ChooseEnemyArtillery();
|
||||
|
||||
if (enemyArtillery == Missiles)
|
||||
{
|
||||
EnemyCounterattack(enemyArtillery, hitRatePercent: 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int hitRatePercent = EnemyHitRatePercentFromUI();
|
||||
if (hitRatePercent < MinEnemyHitRatePercent)
|
||||
{
|
||||
UI.Output("YOU LIE, BUT YOU'LL PAY...");
|
||||
MissionFailed();
|
||||
}
|
||||
else
|
||||
{
|
||||
EnemyCounterattack(enemyArtillery, hitRatePercent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Choose enemy artillery from UI.
|
||||
/// </summary>
|
||||
/// <returns>Artillery chosen.</returns>
|
||||
private EnemyArtillery ChooseEnemyArtillery()
|
||||
{
|
||||
EnemyArtillery[] artilleries = new EnemyArtillery[] { Guns, Missiles, Both };
|
||||
string[] artilleryNames = artilleries.Select(a => a.Name).ToArray();
|
||||
int index = UI.Choose("DOES THE ENEMY HAVE", artilleryNames);
|
||||
return artilleries[index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Minimum allowed hit rate percent.
|
||||
/// </summary>
|
||||
private const int MinEnemyHitRatePercent = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum allowed hit rate percent.
|
||||
/// </summary>
|
||||
private const int MaxEnemyHitRatePercent = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Get the enemy hit rate percent from UI. Value must be between zero and <see cref="MaxEnemyHitRatePercent"/>.
|
||||
/// If value is less than <see cref="MinEnemyHitRatePercent"/>, mission fails automatically because the user is
|
||||
/// assumed to be untruthful.
|
||||
/// </summary>
|
||||
/// <returns>Enemy hit rate percent from UI.</returns>
|
||||
private int EnemyHitRatePercentFromUI()
|
||||
{
|
||||
UI.Output($"WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS ({MinEnemyHitRatePercent} TO {MaxEnemyHitRatePercent})");
|
||||
|
||||
bool resultIsValid;
|
||||
int result;
|
||||
do
|
||||
{
|
||||
result = UI.InputInteger();
|
||||
// Let them enter a number below the stated minimum, as they will be caught and punished.
|
||||
if (0 <= result && result <= MaxEnemyHitRatePercent)
|
||||
{
|
||||
resultIsValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
resultIsValid = false;
|
||||
UI.Output($"NUMBER MUST BE FROM {MinEnemyHitRatePercent} TO {MaxEnemyHitRatePercent}");
|
||||
}
|
||||
}
|
||||
while (!resultIsValid);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
97
12_Bombs_Away/csharp/BombsAwayGame/Side.cs
Normal file
97
12_Bombs_Away/csharp/BombsAwayGame/Side.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
namespace BombsAwayGame;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a protagonist in the game.
|
||||
/// </summary>
|
||||
internal abstract class Side
|
||||
{
|
||||
/// <summary>
|
||||
/// Create instance using the given UI.
|
||||
/// </summary>
|
||||
/// <param name="ui">UI to use.</param>
|
||||
public Side(IUserInterface ui)
|
||||
{
|
||||
UI = ui;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Play this side.
|
||||
/// </summary>
|
||||
public abstract void Play();
|
||||
|
||||
/// <summary>
|
||||
/// User interface supplied to ctor.
|
||||
/// </summary>
|
||||
protected IUserInterface UI { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Random-number generator for this play-through.
|
||||
/// </summary>
|
||||
private readonly Random _random = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a random floating-point number greater than or equal to zero, and less than one.
|
||||
/// </summary>
|
||||
/// <returns>Random floating-point number greater than or equal to zero, and less than one.</returns>
|
||||
protected double RandomFrac() => _random.NextDouble();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a random integer in a range.
|
||||
/// </summary>
|
||||
/// <param name="minValue">The inclusive lower bound of the number returned.</param>
|
||||
/// <param name="maxValue">The exclusive upper bound of the number returned.</param>
|
||||
/// <returns>Random integer in a range.</returns>
|
||||
protected int RandomInteger(int minValue, int maxValue) => _random.Next(minValue: minValue, maxValue: maxValue);
|
||||
|
||||
/// <summary>
|
||||
/// Display messages indicating the mission succeeded.
|
||||
/// </summary>
|
||||
protected void MissionSucceeded()
|
||||
{
|
||||
UI.Output("DIRECT HIT!!!! " + RandomInteger(0, 100) + " KILLED.");
|
||||
UI.Output("MISSION SUCCESSFUL.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Guns type of enemy artillery.
|
||||
/// </summary>
|
||||
protected EnemyArtillery Guns { get; } = new("GUNS", 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Missiles type of enemy artillery.
|
||||
/// </summary>
|
||||
protected EnemyArtillery Missiles { get; } = new("MISSILES", 35);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Both Guns and Missiles type of enemy artillery.
|
||||
/// </summary>
|
||||
protected EnemyArtillery Both { get; } = new("BOTH", 35);
|
||||
|
||||
/// <summary>
|
||||
/// Perform enemy counterattack using the given artillery and hit rate percent.
|
||||
/// </summary>
|
||||
/// <param name="artillery">Enemy artillery to use.</param>
|
||||
/// <param name="hitRatePercent">Hit rate percent for enemy.</param>
|
||||
protected void EnemyCounterattack(EnemyArtillery artillery, int hitRatePercent)
|
||||
{
|
||||
if (hitRatePercent + artillery.Accuracy > RandomInteger(0, 100))
|
||||
{
|
||||
MissionFailed();
|
||||
}
|
||||
else
|
||||
{
|
||||
UI.Output("YOU MADE IT THROUGH TREMENDOUS FLAK!!");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display messages indicating the mission failed.
|
||||
/// </summary>
|
||||
protected void MissionFailed()
|
||||
{
|
||||
UI.Output("* * * * BOOM * * * *");
|
||||
UI.Output("YOU HAVE BEEN SHOT DOWN.....");
|
||||
UI.Output("DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR");
|
||||
UI.Output("LAST TRIBUTE...");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,16 @@
|
||||
### Bounce
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=25
|
||||
This program plots a bouncing ball. Most computer plots run along the paper in the terminal (top to bottom); however, this plot is drawn horizontally on the paper (left to right).
|
||||
|
||||
You may specify the initial velocity of the ball and the coefficient of elasticity of the ball (a superball is about 0.85 — other balls are much less). You also specify the time increment to be used in “strobing” the flight of the ball. In other words, it is as though the ball is thrown up in a darkened room and you flash a light at fixed time intervals and photograph the progress of the ball.
|
||||
|
||||
The program was originally written by Val Skalabrin while he was at DEC.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=25)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=40)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
### Bowling
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=26
|
||||
This is a simulated bowling game for up to four players. You play 10 frames. To roll the ball, you simply type “ROLL.” After each roll, the computer will show you a diagram of the remaining pins (“0” means the pin is down, “+” means it is still standing), and it will give you a roll analysis:
|
||||
- GUTTER
|
||||
- STRIKE
|
||||
- SPARE
|
||||
- ERROR (on second ball if pins still standing)
|
||||
|
||||
Bowling was written by Paul Peraino while a student at Woodrow Wilson High School, San Francisco, California.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=26)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=41)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
### Boxing
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=28
|
||||
This program simulates a three-round Olympic boxing match. The computer coaches one of the boxers and determines his punches and defences, while you do the same for your boxer. At the start of the match, you may specify your man’s best punch and his vulnerability.
|
||||
|
||||
There are approximately seven major punches per round, although this may be varied. The best out if three rounds wins.
|
||||
|
||||
Jesse Lynch of St. Paul, Minnesota created this program.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=28)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=43)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
### Bug
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=30
|
||||
The object of this game is to finish your drawing of a bug before the computer finishes.
|
||||
|
||||
You and the computer roll a die alternately with each number standing for a part of the bug. You must add the parts in the right order; in other words, you cannot have a neck until you have a body, you cannot have a head until you have a neck, and so on. After each new part has been added, you have the option of seeing pictures of the two bugs.
|
||||
|
||||
If you elect to see all the pictures, this program has the ability of consuming well over six feet of terminal paper per run. We can only suggest recycling the paper by using the other side.
|
||||
|
||||
Brian Leibowitz wrote this program while in the 7th grade at Harrison Jr-Se High School in Harrison, New York.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=30)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=45)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,25 @@
|
||||
### Bullfight
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=32
|
||||
In this simulated bullfight, you are the matador — i.e., the one with the principle role and the one who must kill the bull or be killed (or run from the ring).
|
||||
|
||||
On each pass of the bull, you may try:
|
||||
- 0: Veronica (dangerous inside move of the cape)
|
||||
- 1: Less dangerous outside move of the cape
|
||||
- 2: Ordinary swirl of the cape
|
||||
|
||||
Or you may try to kill the bull:
|
||||
- 4: Over the horns
|
||||
- 5: In the chest
|
||||
|
||||
The crowd will determine what award you deserve, posthumously if necessary. The braver you are, the better the reward you receive. It’s nice to stay alive too. The better the job the picadores and toreadores do, the better your chances.
|
||||
|
||||
David Sweet of Dartmouth wrote the original version of this program. It was then modified by students at Lexington High School and finally by Steve North of Creative Computing.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=32)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=47)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,36 @@
|
||||
### Bullseye
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=34
|
||||
In this game, up to 20 players throw darts at a target with 10-, 20-, 30-, and 40-point zones. The objective is to get 200 points.
|
||||
|
||||
You have a choice of three methods of throwing:
|
||||
|
||||
| Throw | Description | Probable Score |
|
||||
|-------|--------------------|---------------------------|
|
||||
| 1 | Fast overarm | Bullseye or complete miss |
|
||||
| 2 | Controlled overarm | 10, 20, or 30 points |
|
||||
| 3 | Underarm | Anything |
|
||||
|
||||
You will find after playing a while that different players will swear by different strategies. However, considering the expected score per throw by always using throw 3:
|
||||
|
||||
| Score (S) | Probability (P) | S x P |
|
||||
|-----------|-----------------|-------|
|
||||
| 40 | 1.00-.95 = .05 | 2 |
|
||||
| 30 | .95-.75 = .20 | 6 |
|
||||
| 30 | .75-.45 = .30 | 6 |
|
||||
| 10 | .45-.05 = .40 | 4 |
|
||||
| 0 | .05-.00 = .05 | 0 |
|
||||
|
||||
Expected score per throw = 18
|
||||
|
||||
Calculate the expected score for the other throws and you may be surprised!
|
||||
|
||||
The program was written by David Ahl of Creative Computing.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=34)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=49)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
10
18_Bullseye/csharp/Bullseye.csproj
Normal file
10
18_Bullseye/csharp/Bullseye.csproj
Normal file
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
22
18_Bullseye/csharp/Bullseye.sln
Normal file
22
18_Bullseye/csharp/Bullseye.sln
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30114.105
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bullseye", "Bullseye.csproj", "{04C164DB-594F-41C4-BC0E-0A203A5536C7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{04C164DB-594F-41C4-BC0E-0A203A5536C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{04C164DB-594F-41C4-BC0E-0A203A5536C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{04C164DB-594F-41C4-BC0E-0A203A5536C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{04C164DB-594F-41C4-BC0E-0A203A5536C7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
237
18_Bullseye/csharp/BullseyeGame.cs
Normal file
237
18_Bullseye/csharp/BullseyeGame.cs
Normal file
@@ -0,0 +1,237 @@
|
||||
namespace Bullseye
|
||||
{
|
||||
/// <summary>
|
||||
/// Class encompassing the game
|
||||
/// </summary>
|
||||
public class BullseyeGame
|
||||
{
|
||||
private readonly List<Player> _players;
|
||||
|
||||
// define a constant for the winning score so that it is
|
||||
// easy to change again in the future
|
||||
private const int WinningScore = 200;
|
||||
|
||||
public BullseyeGame()
|
||||
{
|
||||
// create the initial list of players; list is empty, but
|
||||
// the setup of the game will add items to this list
|
||||
_players = new List<Player>();
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
PrintIntroduction();
|
||||
|
||||
SetupGame();
|
||||
|
||||
PlayGame();
|
||||
|
||||
PrintResults();
|
||||
}
|
||||
|
||||
private void SetupGame()
|
||||
{
|
||||
// First, allow the user to enter how many players are going
|
||||
// to play. This could be weird if the user enters negative
|
||||
// numbers, words, or too many players, so there are some
|
||||
// extra checks on the input to make sure the user didn't do
|
||||
// anything too crazy. Loop until the user enters valid input.
|
||||
bool validPlayerCount;
|
||||
int playerCount;
|
||||
do
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.Write("HOW MANY PLAYERS? ");
|
||||
string? input = Console.ReadLine();
|
||||
|
||||
// assume the user has entered something incorrect - the
|
||||
// next steps will validate the input
|
||||
validPlayerCount = false;
|
||||
|
||||
if (Int32.TryParse(input, out playerCount))
|
||||
{
|
||||
if (playerCount > 0 && playerCount <= 20)
|
||||
{
|
||||
validPlayerCount = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("YOU MUST ENTER A NUMBER BETWEEN 1 AND 20!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("YOU MUST ENTER A NUMBER");
|
||||
}
|
||||
|
||||
}
|
||||
while (!validPlayerCount);
|
||||
|
||||
// Next, allow the user to enter names for the players; as each
|
||||
// name is entered, create a Player object to track the name
|
||||
// and their score, and save the object to the list in this class
|
||||
// so the rest of the game has access to the set of players
|
||||
for (int i = 0; i < playerCount; i++)
|
||||
{
|
||||
string? playerName = String.Empty;
|
||||
do
|
||||
{
|
||||
Console.Write($"NAME OF PLAYER #{i+1}? ");
|
||||
playerName = Console.ReadLine();
|
||||
|
||||
// names can be any sort of text, so allow whatever the user
|
||||
// enters as long as it isn't a blank space
|
||||
}
|
||||
while (String.IsNullOrWhiteSpace(playerName));
|
||||
|
||||
_players.Add(new Player(playerName));
|
||||
}
|
||||
}
|
||||
|
||||
private void PlayGame()
|
||||
{
|
||||
Random random = new Random(DateTime.Now.Millisecond);
|
||||
|
||||
int round = 0;
|
||||
bool isOver = false;
|
||||
do
|
||||
{
|
||||
// starting a new round, increment the counter
|
||||
round++;
|
||||
Console.WriteLine($"ROUND {round}");
|
||||
Console.WriteLine("--------------");
|
||||
|
||||
foreach (Player player in _players)
|
||||
{
|
||||
// ask the user how they want to throw
|
||||
Console.Write($"{player.Name.ToUpper()}'S THROW: ");
|
||||
string? input = Console.ReadLine();
|
||||
|
||||
// based on the input, figure out the probabilities
|
||||
int[] probabilities;
|
||||
switch (input)
|
||||
{
|
||||
case "1":
|
||||
{
|
||||
probabilities = new int[] { 65, 55, 50, 50 };
|
||||
break;
|
||||
}
|
||||
case "2":
|
||||
{
|
||||
probabilities = new int[] { 99, 77, 43, 1 };
|
||||
break;
|
||||
}
|
||||
case "3":
|
||||
{
|
||||
probabilities = new int[] { 95, 75, 45, 5 };
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// in case the user types something bad, pretend it's
|
||||
// as if they tripped over themselves while throwing
|
||||
// the dart - they'll either hit a bullseye or completely
|
||||
// miss
|
||||
probabilities = new int[] { 95, 95, 95, 95 };
|
||||
Console.Write("TRIP! ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Next() returns a number in the range: min <= num < max, so specify 101
|
||||
// as the maximum so that 100 is a number that could be returned
|
||||
int chance = random.Next(0, 101);
|
||||
|
||||
if (chance > probabilities[0])
|
||||
{
|
||||
player.Score += 40;
|
||||
Console.WriteLine("BULLSEYE!! 40 POINTS!");
|
||||
}
|
||||
else if (chance > probabilities[1])
|
||||
{
|
||||
player.Score += 30;
|
||||
Console.WriteLine("30-POINT ZONE!");
|
||||
}
|
||||
else if (chance > probabilities[2])
|
||||
{
|
||||
player.Score += 20;
|
||||
Console.WriteLine("20-POINT ZONE");
|
||||
}
|
||||
else if (chance > probabilities[3])
|
||||
{
|
||||
player.Score += 10;
|
||||
Console.WriteLine("WHEW! 10 POINTS.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// missed it
|
||||
Console.WriteLine("MISSED THE TARGET! TOO BAD.");
|
||||
}
|
||||
|
||||
// check to see if the player has won - if they have, then
|
||||
// break out of the loops
|
||||
if (player.Score > WinningScore)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("WE HAVE A WINNER!!");
|
||||
Console.WriteLine($"{player.Name.ToUpper()} SCORED {player.Score} POINTS.");
|
||||
Console.WriteLine();
|
||||
|
||||
isOver = true; // out of the do/while round loop
|
||||
break; // out of the foreach (player) loop
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
while (!isOver);
|
||||
}
|
||||
|
||||
private void PrintResults()
|
||||
{
|
||||
// For bragging rights, print out all the scores, but sort them
|
||||
// by who had the highest score
|
||||
var sorted = _players.OrderByDescending(p => p.Score);
|
||||
|
||||
// padding is used to get things to line up nicely - the results
|
||||
// should look something like:
|
||||
// PLAYER SCORE
|
||||
// Bravo 210
|
||||
// Charlie 15
|
||||
// Alpha 1
|
||||
Console.WriteLine("PLAYER SCORE");
|
||||
foreach (var player in sorted)
|
||||
{
|
||||
Console.WriteLine($"{player.Name.PadRight(12)} {player.Score.ToString().PadLeft(5)}");
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("THANKS FOR THE GAME.");
|
||||
}
|
||||
|
||||
private void PrintIntroduction()
|
||||
{
|
||||
Console.WriteLine(Title);
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(Introduction);
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(Operations);
|
||||
}
|
||||
|
||||
private const string Title = @"
|
||||
BULLSEYE
|
||||
CREATIVE COMPUTING MORRISTOWN, NEW JERSEY";
|
||||
|
||||
private const string Introduction = @"
|
||||
IN THIS GAME, UP TO 20 PLAYERS THROW DARTS AT A TARGET
|
||||
WITH 10, 20, 30, AND 40 POINT ZONES. THE OBJECTIVE IS
|
||||
TO GET 200 POINTS.";
|
||||
|
||||
private const string Operations = @"
|
||||
THROW DESCRIPTION PROBABLE SCORE
|
||||
1 FAST OVERARM BULLSEYE OR COMPLETE MISS
|
||||
2 CONTROLLED OVERARM 10, 20, OR 30 POINTS
|
||||
3 UNDERARM ANYTHING";
|
||||
}
|
||||
}
|
||||
28
18_Bullseye/csharp/Player.cs
Normal file
28
18_Bullseye/csharp/Player.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace Bullseye
|
||||
{
|
||||
/// <summary>
|
||||
/// Object to track the name and score of a player
|
||||
/// </summary>
|
||||
public class Player
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a play with the given name
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the player</param>
|
||||
public Player(string name)
|
||||
{
|
||||
Name = name;
|
||||
Score = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name of the player
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current score of the player
|
||||
/// </summary>
|
||||
public int Score { get; set; }
|
||||
}
|
||||
}
|
||||
14
18_Bullseye/csharp/Program.cs
Normal file
14
18_Bullseye/csharp/Program.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace Bullseye
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
// Entry point to the application; create an instance of the
|
||||
// game class and call Run()
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
new BullseyeGame().Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
### Bunny
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=35
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=35)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=50)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
### Buzzword
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=36
|
||||
This program is an invaluable aid for preparing speeches and briefings about educational technology. This buzzword generator provides sets of three highly-acceptable words to work into your material. Your audience will never know that the phrases don’t really mean much of anything because they sound so great! Full instructions for running are given in the program.
|
||||
|
||||
This version of Buzzword was written by David Ahl.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=36)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=51)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
8
20_Buzzword/csharp/Buzzword.csproj
Normal file
8
20_Buzzword/csharp/Buzzword.csproj
Normal file
@@ -0,0 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
25
20_Buzzword/csharp/Buzzword.sln
Normal file
25
20_Buzzword/csharp/Buzzword.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.810.15
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Buzzword", "Buzzword.csproj", "{E342DEB2-F009-47FD-85F6-E84965EAAB56}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E342DEB2-F009-47FD-85F6-E84965EAAB56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E342DEB2-F009-47FD-85F6-E84965EAAB56}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E342DEB2-F009-47FD-85F6-E84965EAAB56}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E342DEB2-F009-47FD-85F6-E84965EAAB56}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {52F15A7F-671A-470D-91CE-F3B629B989B7}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
115
20_Buzzword/csharp/Program.cs
Normal file
115
20_Buzzword/csharp/Program.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
|
||||
namespace Buzzword
|
||||
{
|
||||
class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// Displays header.
|
||||
/// </summary>
|
||||
static void Header()
|
||||
{
|
||||
Console.WriteLine("Buzzword generator".PadLeft(26));
|
||||
Console.WriteLine("Creating Computing Morristown, New Jersey".PadLeft(15));
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
// Information for the user about possible key input.
|
||||
static string keys = "type a 'Y' for another phrase or 'N' to quit";
|
||||
|
||||
/// <summary>
|
||||
/// Displays instructions.
|
||||
/// </summary>
|
||||
static void Instructions()
|
||||
{
|
||||
Console.WriteLine("This program prints highly acceptable phrases in\n"
|
||||
+ "'educator-speak' that you can work into reports\n"
|
||||
+ "and speeches. Whenever a question mark is printed,\n"
|
||||
+ $"{keys}.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
Console.Write("Here's the first phrase:");
|
||||
}
|
||||
|
||||
static string[] Words = new[]
|
||||
{ "ability", "basal", "behavioral", "child-centered",
|
||||
"differentiated", "discovery", "flexible", "heterogenous",
|
||||
"homogeneous", "manipulative", "modular", "tavistock",
|
||||
"individualized", "learning", "evaluative", "objective",
|
||||
"cognitive", "enrichment", "scheduling", "humanistic",
|
||||
"integrated", "non-graded", "training", "vertical age",
|
||||
"motivational", "creative", "grouping", "modification",
|
||||
"accountability", "process", "core curriculum", "algorithm",
|
||||
"performance", "reinforcement", "open classroom", "resource",
|
||||
"structure", "facility", "environment" };
|
||||
|
||||
/// <summary>
|
||||
/// Capitalizes first letter of given string.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns>string</returns>
|
||||
static string Capitalize(string input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
return string.Empty;
|
||||
|
||||
return char.ToUpper(input[0]) + input[1..];
|
||||
}
|
||||
|
||||
// Seed has been calculated to get the same effect as in original,
|
||||
// at least in first phrase
|
||||
static readonly Random rnd = new Random(1486);
|
||||
|
||||
/// <summary>
|
||||
/// Generates random phrase from words available in Words array.
|
||||
/// </summary>
|
||||
/// <returns>String representing random phrase where first letter is capitalized.</returns>
|
||||
static string GeneratePhrase()
|
||||
{
|
||||
// Indexing from 0, so had to decrease generated numbers
|
||||
return $"{Capitalize(Words[rnd.Next(13)])} "
|
||||
+ $"{Words[rnd.Next(13, 26)]} "
|
||||
+ $"{Words[rnd.Next(26, 39)]}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles user input. On wrong input it displays information about
|
||||
/// valid keys in infinite loop.
|
||||
/// </summary>
|
||||
/// <returns>True if user pressed 'Y', false if 'N'.</returns>
|
||||
static bool Decision()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Console.Write("?");
|
||||
var answer = Console.ReadKey();
|
||||
if (answer.Key == ConsoleKey.Y)
|
||||
return true;
|
||||
else if (answer.Key == ConsoleKey.N)
|
||||
return false;
|
||||
else
|
||||
Console.WriteLine($"\n{keys}");
|
||||
}
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Header();
|
||||
Instructions();
|
||||
|
||||
while (true)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(GeneratePhrase());
|
||||
Console.WriteLine();
|
||||
|
||||
if (!Decision())
|
||||
break;
|
||||
}
|
||||
|
||||
Console.WriteLine("\nCome back when you need help with another report!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,23 @@
|
||||
### Calendar
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=37
|
||||
This program prints out a calendar for any year. You must specify the starting day of the week of the year:
|
||||
- 0: Sunday
|
||||
- -1: Monday
|
||||
- -2: Tuesday
|
||||
- -3: Wednesday
|
||||
- -4: Thursday
|
||||
- -5: Friday
|
||||
- -6: Saturday
|
||||
|
||||
You can determine this by using the program WEEKDAY. You must also make two changes for leap years. The program listing describes the necessary changes. Running the program produces a nice 12-month calendar.
|
||||
|
||||
The program was written by Geoffrey Chase of the Abbey, Portsmouth, Rhode Island.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=37)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=52)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
9
21_Calendar/csharp/21_calendar.csproj
Normal file
9
21_Calendar/csharp/21_calendar.csproj
Normal file
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<RootNamespace>_21_calendar</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
25
21_Calendar/csharp/21_calendar.sln
Normal file
25
21_Calendar/csharp/21_calendar.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31613.86
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "21_calendar", "21_calendar.csproj", "{99AB85E1-A42B-4FEF-8BA6-0ED877F05249}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{99AB85E1-A42B-4FEF-8BA6-0ED877F05249}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{99AB85E1-A42B-4FEF-8BA6-0ED877F05249}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{99AB85E1-A42B-4FEF-8BA6-0ED877F05249}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{99AB85E1-A42B-4FEF-8BA6-0ED877F05249}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {1B423C35-492F-4AF8-97FC-BEC69B44EC8D}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
144
21_Calendar/csharp/Program.cs
Normal file
144
21_Calendar/csharp/Program.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
|
||||
/*
|
||||
21_Calendar in C# for basic-computer-games
|
||||
Converted by luminoso-256
|
||||
*/
|
||||
|
||||
namespace _21_calendar
|
||||
{
|
||||
class Program
|
||||
{
|
||||
//basic has a TAB function. We do not by default, so we make our own!
|
||||
static string Tab(int numspaces)
|
||||
{
|
||||
string space = "";
|
||||
//loop as many times as there are spaces specified, and add a space each time
|
||||
while (numspaces > 0)
|
||||
{
|
||||
//add the space
|
||||
space += " ";
|
||||
//decrement the loop variable so we don't keep going forever!
|
||||
numspaces--;
|
||||
}
|
||||
return space;
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// print the "title" of our program
|
||||
// the usage of Write*Line* means we do not have to specify a newline (\n)
|
||||
Console.WriteLine(Tab(32) + "CALENDAR");
|
||||
Console.WriteLine(Tab(15) + "CREATE COMPUTING MORRISTOWN, NEW JERSEY");
|
||||
//give us some space.
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine("");
|
||||
|
||||
//establish some variables needed to print out a calculator
|
||||
|
||||
//the length of each month in days. On a leap year, the start of this would be
|
||||
// 0, 31, 29 to account for Feb. the 0 at the start is for days elapsed to work right in Jan.
|
||||
int[] monthLengths = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // m in original source
|
||||
|
||||
//the starting day of the month. in 1979 this was monday
|
||||
// 0 = sun, -1 = mon, -2 = tue, -3 = wed, etc.
|
||||
int day = -1; // called d in original source
|
||||
|
||||
//how much time in the year has gone by?
|
||||
int elapsed = 0; // called s in original source
|
||||
|
||||
//loop through printing all the months.
|
||||
for (int month = 1; month <= 12; month++) //month is called n in original source
|
||||
{
|
||||
//pad some space
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine("");
|
||||
//increment days elapsed
|
||||
elapsed += monthLengths[month - 1];
|
||||
//build our header for this month of the calendar
|
||||
string header = "** " + elapsed;
|
||||
//add padding as needed
|
||||
while (header.Length < 7)
|
||||
{
|
||||
header += " ";
|
||||
}
|
||||
for (int i = 1; i <= 18; i++)
|
||||
{
|
||||
header += "*";
|
||||
}
|
||||
//determine what month it is, add text accordingly
|
||||
switch (month) {
|
||||
case 1: header += " JANUARY "; break;
|
||||
case 2: header += " FEBRUARY"; break;
|
||||
case 3: header += " MARCH "; break;
|
||||
case 4: header += " APRIL "; break;
|
||||
case 5: header += " MAY "; break;
|
||||
case 6: header += " JUNE "; break;
|
||||
case 7: header += " JULY "; break;
|
||||
case 8: header += " AUGUST "; break;
|
||||
case 9: header += "SEPTEMBER"; break;
|
||||
case 10: header += " OCTOBER "; break;
|
||||
case 11: header += " NOVEMBER"; break;
|
||||
case 12: header += " DECEMBER"; break;
|
||||
}
|
||||
//more padding
|
||||
for (int i = 1; i <= 18; i++)
|
||||
{
|
||||
header += "*";
|
||||
}
|
||||
header += " ";
|
||||
// how many days left till the year's over?
|
||||
header += (365 - elapsed) + " **"; // on leap years 366
|
||||
Console.WriteLine(header);
|
||||
//dates
|
||||
Console.WriteLine(" S M T W T F S");
|
||||
Console.WriteLine(" ");
|
||||
|
||||
string weekOutput = "";
|
||||
for (int i = 1; i <= 59; i++)
|
||||
{
|
||||
weekOutput += "*";
|
||||
}
|
||||
//init some vars ahead of time
|
||||
int g = 0;
|
||||
int d2 = 0;
|
||||
//go through the weeks and days
|
||||
for (int week = 1; week <= 6; week++)
|
||||
{
|
||||
Console.WriteLine(weekOutput);
|
||||
weekOutput = " ";
|
||||
for (g = 1; g <= 7; g++)
|
||||
{
|
||||
//add one to the day
|
||||
day++;
|
||||
d2 = day - elapsed;
|
||||
//check if we're done with this month
|
||||
if (d2 > monthLengths[month])
|
||||
{
|
||||
week = 6;
|
||||
break;
|
||||
}
|
||||
//should we print this day?
|
||||
if (d2 > 0)
|
||||
{
|
||||
weekOutput += d2;
|
||||
}
|
||||
//padding
|
||||
while (weekOutput.Length < 4 + 8 * g)
|
||||
{
|
||||
weekOutput += " ";
|
||||
}
|
||||
}
|
||||
if (d2 == monthLengths[month])
|
||||
{
|
||||
day += g;
|
||||
break;
|
||||
}
|
||||
}
|
||||
day -= g;
|
||||
Console.WriteLine(weekOutput);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,12 @@
|
||||
### Change
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=39
|
||||
In this program, the computer pretends it is the cashier at your friendly neighborhood candy store. You tell it the cost of the item(s) you are buying, the amount of your payment, and it will automatically (!) determine your correct change. Aren’t machines wonderful? Dennis Lunder of People’s Computer Company wrote this program.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=39)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=54)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
8
22_Change/csharp/Change.csproj
Normal file
8
22_Change/csharp/Change.csproj
Normal file
@@ -0,0 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
25
22_Change/csharp/Change.sln
Normal file
25
22_Change/csharp/Change.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.810.16
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Change", "Change.csproj", "{AE094667-8496-4ECF-8B42-B1648EE26073}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{AE094667-8496-4ECF-8B42-B1648EE26073}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AE094667-8496-4ECF-8B42-B1648EE26073}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AE094667-8496-4ECF-8B42-B1648EE26073}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AE094667-8496-4ECF-8B42-B1648EE26073}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {65684CBD-CD74-46AF-8E9E-0F69DCF72697}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
129
22_Change/csharp/Program.cs
Normal file
129
22_Change/csharp/Program.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
|
||||
namespace Change
|
||||
{
|
||||
class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// Prints header.
|
||||
/// </summary>
|
||||
static void Header()
|
||||
{
|
||||
Console.WriteLine("Change".PadLeft(33));
|
||||
Console.WriteLine("Creative Computing Morristown, New Jersey".PadLeft(15));
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("I, your friendly microcomputer, will determine\n"
|
||||
+ "the correct change for items costing up to $100.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets user input for price and payment.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// False if any input can't be parsed to double. Price and payment returned would be 0.
|
||||
/// True if it was possible to parse inputs into doubles. Price and payment returned
|
||||
/// would be as provided by the user.
|
||||
/// </returns>
|
||||
static (bool status, double price, double payment) GetInput()
|
||||
{
|
||||
Console.Write("Cost of item? ");
|
||||
var priceString = Console.ReadLine();
|
||||
if (!double.TryParse(priceString, out double price))
|
||||
{
|
||||
Console.WriteLine($"{priceString} isn't a number!");
|
||||
return (false, 0, 0);
|
||||
}
|
||||
|
||||
Console.Write("Amount of payment? ");
|
||||
var paymentString = Console.ReadLine();
|
||||
if (!double.TryParse(paymentString, out double payment))
|
||||
{
|
||||
Console.WriteLine($"{paymentString} isn't a number!");
|
||||
return (false, 0, 0);
|
||||
}
|
||||
|
||||
return (true, price, payment);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prints bills and coins for given change.
|
||||
/// </summary>
|
||||
/// <param name="change"></param>
|
||||
static void PrintChange(double change)
|
||||
{
|
||||
var tens = (int)(change / 10);
|
||||
if (tens > 0)
|
||||
Console.WriteLine($"{tens} ten dollar bill(s)");
|
||||
|
||||
var temp = change - (tens * 10);
|
||||
var fives = (int)(temp / 5);
|
||||
if (fives > 0)
|
||||
Console.WriteLine($"{fives} five dollar bill(s)");
|
||||
|
||||
temp -= fives * 5;
|
||||
var ones = (int)temp;
|
||||
if (ones > 0)
|
||||
Console.WriteLine($"{ones} one dollar bill(s)");
|
||||
|
||||
temp -= ones;
|
||||
var cents = temp * 100;
|
||||
var half = (int)(cents / 50);
|
||||
if (half > 0)
|
||||
Console.WriteLine($"{half} one half dollar(s)");
|
||||
|
||||
temp = cents - (half * 50);
|
||||
var quarters = (int)(temp / 25);
|
||||
if (quarters > 0)
|
||||
Console.WriteLine($"{quarters} quarter(s)");
|
||||
|
||||
temp -= quarters * 25;
|
||||
var dimes = (int)(temp / 10);
|
||||
if (dimes > 0)
|
||||
Console.WriteLine($"{dimes} dime(s)");
|
||||
|
||||
temp -= dimes * 10;
|
||||
var nickels = (int)(temp / 5);
|
||||
if (nickels > 0)
|
||||
Console.WriteLine($"{nickels} nickel(s)");
|
||||
|
||||
temp -= nickels * 5;
|
||||
var pennies = (int)(temp + 0.5);
|
||||
if (pennies > 0)
|
||||
Console.WriteLine($"{pennies} penny(s)");
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Header();
|
||||
|
||||
while (true)
|
||||
{
|
||||
(bool result, double price, double payment) = GetInput();
|
||||
if (!result)
|
||||
continue;
|
||||
|
||||
var change = payment - price;
|
||||
if (change == 0)
|
||||
{
|
||||
Console.WriteLine("Correct amount, thank you!");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (change < 0)
|
||||
{
|
||||
Console.WriteLine($"Sorry, you have short-changed me ${price - payment:N2}!");
|
||||
continue;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Your change ${change:N2}");
|
||||
PrintChange(change);
|
||||
Console.WriteLine("Thank you, come again!");
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
68
22_Change/perl/change.pl
Executable file
68
22_Change/perl/change.pl
Executable file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use v5.24; # for say and use strict
|
||||
use warnings;
|
||||
|
||||
sub get_pennies {
|
||||
my $query = shift;
|
||||
|
||||
print "$query? ";
|
||||
my $in = <>;
|
||||
chomp $in;
|
||||
$in =~ /([\d.]+)/; # the first match of digits and decimal points
|
||||
return int( $1 * 100 );
|
||||
}
|
||||
|
||||
sub make_change {
|
||||
my $change = shift;
|
||||
|
||||
state %change_options = (
|
||||
'Penny' => { value => 1, plural => 'Pennies' },
|
||||
'Nickel' => { value => 5 },
|
||||
'Dime' => { value => 10 },
|
||||
'Quarter' => { value => 25 },
|
||||
'One Half Dollar' => { value => 50 },
|
||||
'One Dollar Bill' => { value => 100 * 1 },
|
||||
'Five Dollar Bill' => { value => 100 * 5 },
|
||||
'10 Dollar Bill' => { value => 100 * 10 },
|
||||
);
|
||||
|
||||
foreach my $unit ( sort { $change_options{$b}->{value} <=> $change_options{$a}->{value} } keys %change_options ) {
|
||||
my $value = $change_options{$unit}->{value};
|
||||
next if $value > $change;
|
||||
my $number = int( $change / $value );
|
||||
if ( $number > 1 ) {
|
||||
$unit = exists $change_options{$unit}->{plural} ? $change_options{$unit}->{plural} : "${unit}s";
|
||||
}
|
||||
say "$number $unit";
|
||||
$change -= $number * $value;
|
||||
}
|
||||
}
|
||||
|
||||
print <<'__END_OF_INTRO';
|
||||
Change
|
||||
Creative Computing Morristown, New Jersey
|
||||
|
||||
|
||||
I, Your friendly microcomputer, will determine
|
||||
the correct change for items costing up to $100.
|
||||
|
||||
|
||||
__END_OF_INTRO
|
||||
|
||||
while ( 1 ) {
|
||||
my $cost = get_pennies( 'Cost of item' );
|
||||
my $payment = get_pennies( 'Amount of payment');
|
||||
|
||||
my $change = $payment - $cost;
|
||||
my $change_formatted = sprintf( "%.2f", $change / 100 );
|
||||
if ( $change == 0 ) {
|
||||
say 'Correct amount, thank you.';
|
||||
} elsif ( $change < 0 ) {
|
||||
say 'Sorry, you have short-changed me $', abs($change_formatted);
|
||||
} else {
|
||||
say 'Your change, $', $change_formatted;
|
||||
make_change( $change );
|
||||
say "Thank you, come again\n\n";
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,16 @@
|
||||
### Checkers
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=40
|
||||
This program plays checkers. The pieces played by the computer are marked with an “X”, yours are marked “O”. A move is made by specifying the coordinates of the piece to be moved (X, Y). Home (0,0) is in the bottom left and X specifies distance to the right of home (i.e., column) and Y specifies distance above home (i.e. row). You then specify where you wish to move to.
|
||||
|
||||
THe original version of the program by Alan Segal was not able to recognize (or permit) a double or triple jump. If you tried one, it was likely that your piece would disappear altogether!
|
||||
|
||||
Steve North of Creative Computing rectified this problem and Lawrence Neal contributed modifications to allow the program to tell which player has won the game. The computer does not play a particularly good game but we leave it to _you_ to improve that.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=40)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=55)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
### Chemist
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=42
|
||||
The fictitious chemical, kryptocyanic acid, can only be diluted by the ratio of 7 parts water to 3 parts acid. Any other ratio causes an unstable compound which soon explodes. Given an amount of acid, you must determine how much water to add to the dilution. If you’re more than 5% off, you lose one of your nine lives. The program continues to play until you lose all nine lives or until it is interrupted.
|
||||
|
||||
It was originally written by Wayne Teeter of Ridgecrest, California.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=42)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=57)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -8,30 +8,30 @@ print "THE FICTITIOUS CHECMICAL KRYPTOCYANIC ACID CAN ONLY BE\n";
|
||||
print "DILUTED BY THE RATIO OF 7 PARTS WATER TO 3 PARTS ACID.\n";
|
||||
print "IF ANY OTHER RATIO IS ATTEMPTED, THE ACID BECOMES UNSTABLE\n";
|
||||
print "AND SOON EXPLODES. GIVEN THE AMOUNT OF ACID, YOU MUST\n";
|
||||
print "DECIDE WHO MUCH WATER TO ADD FOR DILUTION. IF YOU MISS\n";
|
||||
print "DECIDE HOW MUCH WATER TO ADD FOR DILUTION. IF YOU MISS\n";
|
||||
print "YOU FACE THE CONSEQUENCES.\n";
|
||||
|
||||
my $T=0;
|
||||
while ($T<9) {
|
||||
my $A= int(rand(1)*50);
|
||||
my $A= int(rand(50) + 1);
|
||||
my $W= 7*$A/3;
|
||||
print "$A LITERS OF KRYPTOCYANIC ACID. HOW MUCH WATER ($W)";
|
||||
print "? "; chomp(my $R = <STDIN>);
|
||||
print " $A LITERS OF KRYPTOCYANIC ACID. HOW MUCH WATER? ";
|
||||
chomp(my $R = <STDIN>);
|
||||
my $D= abs($W-$R);
|
||||
if ($D>$W/20) {
|
||||
print " SIZZLE! YOU HAVE JUST BEEN DESALINATED INTO A BLOB\n";
|
||||
print " OF QUIVERING PROTOPLASM!\n";
|
||||
print " HOWEVER, YOU MAY TRY AGAIN WITH ANOTHER LIFE.\n";
|
||||
print "SIZZLE! YOU HAVE JUST BEEN DESALINATED INTO A BLOB\n";
|
||||
print "OF QUIVERING PROTOPLASM!\n";
|
||||
print "HOWEVER, YOU MAY TRY AGAIN WITH ANOTHER LIFE.\n";
|
||||
print "\n";
|
||||
$T++;
|
||||
} else {
|
||||
print " GOOD JOB! YOU MAY BREATHE NOW, BUT DON'T INHALE THE FUMES!\n";
|
||||
} else {
|
||||
print "GOOD JOB! YOU MAY BREATHE NOW, BUT DON'T INHALE THE FUMES!\n";
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print " YOUR 9 LIVES ARE USED, BUT YOU WILL BE LONG REMEMBERED FOR\n";
|
||||
print " YOUR CONTRIBUTIONS TO THE FIELD OF COMIC BOOK CHEMISTRY.\n";
|
||||
print "YOUR 9 LIVES ARE USED, BUT YOU WILL BE LONG REMEMBERED FOR\n";
|
||||
print "YOUR CONTRIBUTIONS TO THE FIELD OF COMIC BOOK CHEMISTRY.\n";
|
||||
exit;
|
||||
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
### Chief
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=43
|
||||
In the words of the program author, John Graham, “CHIEF is designed to give people (mostly kids) practice in the four operations (addition, multiplication, subtraction, and division).
|
||||
|
||||
It does this while giving people some fun. And then, if the people are wrong, it shows them how they should have done it.
|
||||
|
||||
CHIEF was written by John Graham of Upper Brookville, New York.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=43)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=58)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
### Chomp
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=44
|
||||
This program is an adaptation of a mathematical game originally described by Martin Gardner in the January 1973 issue of _Scientific American_. Up to a 9x9 grid is set up by you with the upper left square in a poison square. This grid is the cookie. Players alternately chomp away at the cookie from the lower right. To take a chomp, input a row and column number of one of the squares remaining on the cookie. All of the squares below and to the right of that square, including that square, disappear.
|
||||
|
||||
Any number of people can play — the computer is only the moderator; it is not a player. Two-person strategies are interesting to work out but strategies when three or more people are playing are the real challenge.
|
||||
|
||||
The computer version of the game was written by Peter Sessions of People’s Computer Company.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=44)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=59)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
173
26_Chomp/perl/chomp.pl
Normal file
173
26_Chomp/perl/chomp.pl
Normal file
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
|
||||
my @cookie;
|
||||
|
||||
&main;
|
||||
|
||||
sub main {
|
||||
my $answer = 1;
|
||||
until ($answer == 0) {
|
||||
$answer=&game_play;
|
||||
}
|
||||
}
|
||||
|
||||
sub game_play {
|
||||
|
||||
# the initial game set up
|
||||
&print_intro;
|
||||
my ($players,$rows,$cols) = &get_user_info;
|
||||
&create_gameboard($rows,$cols);
|
||||
&print_gameboard($rows,$cols);
|
||||
my $game_over = 0;
|
||||
my $player = 0;
|
||||
|
||||
# continuous loop until the poison pill is swallowed
|
||||
until ($game_over == 1) {
|
||||
if ($player > ($players-1)) { #checks to make sure we're just looping thru valid players
|
||||
$player = 0;
|
||||
}
|
||||
$player++;
|
||||
my ($user_row,$user_col) = &get_player_row_col($player,$rows,$cols);
|
||||
if ($cookie[$user_row][$user_col] == -1) {
|
||||
print "YOU LOSE, PLAYER $player\n\n";
|
||||
print "AGAIN (1=YES, 0=NO!)\n";
|
||||
my $answer=<STDIN>;
|
||||
chomp($answer);
|
||||
return($answer);
|
||||
}
|
||||
&modify_gameboard($rows,$cols,$user_row,$user_col);
|
||||
&print_gameboard($rows,$cols);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub get_player_row_col {
|
||||
my ($player,$row,$col) = @_;
|
||||
my @coords;
|
||||
my $validity="invalid";
|
||||
# Getting coordinates from user
|
||||
until ($validity eq "valid") {
|
||||
print "PLAYER $player COORDINATES OF CHOMP (ROW,COLUMN)\n";
|
||||
my $input=<STDIN>;
|
||||
chomp($input);
|
||||
@coords = split/,/,$input;
|
||||
|
||||
#verifying coordinates are valid
|
||||
if ($coords[0] < 1 || $coords[0] > $row || $coords[1] < 1 || $coords[1] > $col || $cookie[$coords[0]][$coords[1]] == 0) {
|
||||
print "NO FAIR. YOU'RE TRYING TO CHOMP ON EMPTY SPACE!\n";
|
||||
}
|
||||
else {
|
||||
$validity="valid";
|
||||
}
|
||||
}
|
||||
return($coords[0],$coords[1]);
|
||||
}
|
||||
|
||||
sub get_user_info {
|
||||
my ($players,$rows,$cols)=0;
|
||||
until ($players > 0) {
|
||||
print "HOW MANY PLAYERS\n";
|
||||
$players=<STDIN>;
|
||||
chomp($players);
|
||||
}
|
||||
until ($rows > 0 && $rows < 10) {
|
||||
print "HOW MANY ROWS\n";
|
||||
$rows=<STDIN>;
|
||||
chomp($rows);
|
||||
if ($rows > 9) {
|
||||
print "TOO MANY ROWS (9 IS MAXIMUM). NOW, ";
|
||||
}
|
||||
}
|
||||
until ($cols > 0 && $cols < 10) {
|
||||
print "HOW MANY COLUMNS\n";
|
||||
$cols=<STDIN>;
|
||||
chomp($cols);
|
||||
if ($cols > 9) {
|
||||
print "TOO MANY COLUMNS (9 IS MAXIMUM). NOW, ";
|
||||
}
|
||||
}
|
||||
return($players,$rows,$cols);
|
||||
}
|
||||
|
||||
sub print_intro{
|
||||
print ' ' x 33 . "CHOMP\n";
|
||||
print ' ' x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n";
|
||||
print "THIS IS THE GAME OF CHOMP (SCIENTIFIC AMERICAN, JAN 1973)\n";
|
||||
print "DO YOU WANT THE RULES (1=YES, 0=NO!)";
|
||||
my $answer = <STDIN>;
|
||||
chomp($answer);
|
||||
if ($answer == 0) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
print "CHOMP IS FOR 1 OR MORE PLAYERS (HUMANS ONLY).\n\n";
|
||||
print "HERE'S HOW A BOARD LOOKS (THIS ONE IS 5 BY 7):\n";
|
||||
&create_gameboard(5,7);
|
||||
&print_gameboard(5,7);
|
||||
print "THE BOARD IS A BIG COOKIE - R ROWS HIGH AND C COLUMNS\n";
|
||||
print "WIDE. YOU INPUT R AND C AT THE START. IN THE UPPER LEFT\n";
|
||||
print "CORNER OF THE COOKIE IS A POISON SQUARE (P). THE ONE WHO\n";
|
||||
print "CHOMPS THE POISON SQUARE LOSES. TO TAKE A CHOMP, TYPE THE\n";
|
||||
print "ROW AND COLUMN OF ONE OF THE SQUARES ON THE COOKIE.\n";
|
||||
print "ALL OF THE SQUARES BELOW AND TO THE RIGHT OF THAT SQUARE\n";
|
||||
print "(INCLUDING THAT SQUARE, TOO) DISAPPEAR -- CHOMP!!\n";
|
||||
print "NO FAIR CHOMPING SQUARES THAT HAVE ALREADY BEEN CHOMPED,\n";
|
||||
print "OR THAT ARE OUTSIDE THE ORIGINAL DIMENSIONS OF THE COOKIE.\n\n";
|
||||
print "HERE WE GO...\n";
|
||||
undef @cookie;
|
||||
}
|
||||
}
|
||||
|
||||
#initial creation of the gameboard
|
||||
sub create_gameboard {
|
||||
my $rows = shift;
|
||||
my $cols = shift;
|
||||
foreach my $row (1..($rows)) {
|
||||
foreach my $col (1..($cols)) {
|
||||
$cookie[$row][$col]=1;
|
||||
}
|
||||
}
|
||||
$cookie[1][1]=-1;
|
||||
}
|
||||
|
||||
#modification of the gameboard based on the input from the player
|
||||
sub modify_gameboard {
|
||||
my ($rows,$cols,$user_row,$user_col) = @_;
|
||||
foreach my $row ($user_row..($rows)) {
|
||||
foreach my $col ($user_col..($cols)) {
|
||||
$cookie[$row][$col]=" ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#prints the gameboard based on the current state of the gameboard
|
||||
sub print_gameboard {
|
||||
my ($rows,$cols) = @_;
|
||||
foreach my $col (1..$cols) {
|
||||
if ($col == $cols) {
|
||||
print "$col\n";
|
||||
}
|
||||
elsif ($col == 1) {
|
||||
print "\t $col ";
|
||||
}
|
||||
else {
|
||||
print "$col ";
|
||||
}
|
||||
}
|
||||
foreach my $row (1..($rows)) {
|
||||
print "\t$row ";
|
||||
foreach my $col (1..($cols)) {
|
||||
if ($cookie[$row][$col] == 1) {
|
||||
print "* ";
|
||||
}
|
||||
if ($cookie[$row][$col] == 0) {
|
||||
print " ";
|
||||
}
|
||||
if ($cookie[$row][$col] == -1) {
|
||||
print "P ";
|
||||
}
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,18 @@
|
||||
### Civil War
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=46
|
||||
This simulation is based on 14 battles in the Civil War. Facts and figures are based on the actual occurrence. If you follow the same strategy used in the actual battle, the results will be the same. Generally, this is a good strategy since the generals in the Civil War were fairly good military strategists. However, you can frequently outperform the Civil War generals, particularly in cases where they did not have good enemy intelligence and consequently followed a poor course of action. Naturally, it helps to know your Civil War history, although the computer gives yuo the rudiments.
|
||||
|
||||
After each of the 14 battles, your casualties are compared to the actual casualties of the battle, and you are told whether you win or lose the battle.
|
||||
|
||||
You may play Civil War alone in which case the program simulates the Union general. Or two players may play in which case the computer becomes the moderator.
|
||||
|
||||
Civil War was written in 1968 by three Students in Lexington High School, Massachusetts: L. Cram, L. Goodie, and D. Hibbard. It was modified into a 2-player game by G. Paul and R. Hess of TIES, St. Paul, Minnesota.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=46)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=61)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
### Combat
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=50
|
||||
In this game, you are fighting a small-scale war with the computer. You have 72,000 troops which you first ust distribute among your Army, Navy, and Air Force. You may distribute them in any way you choose as long as you don’t use more than 72,000.
|
||||
|
||||
You then attack your opponent (the computer) and input which service and the number of men you wish to use. The computer then tells you the outcome of the battle, gives you the current statistics and allows you to determine your next move.
|
||||
|
||||
After the second battle, it is decided from the total statistics whether you win or lose or if a treaty is signed.
|
||||
|
||||
This program was created by Bob Dores of Milton, Massachusetts.
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=50)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=65)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
### Craps
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=52
|
||||
This game simulates the game of craps played according to standard Nevada craps table rules. That is:
|
||||
1. A 7 or 11 on the first roll wins
|
||||
2. A 2, 3, or 12 on the first roll loses
|
||||
3. Any other number rolled becomes your “point.”
|
||||
- You continue to roll, if you get your point, you win.
|
||||
- If you roll a 7, you lose and the dice change hands when this happens.
|
||||
|
||||
This version of craps was modified by Steve North of Creative Computing. It is based on an original which appeared one day on a computer at DEC.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=52)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=67)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
79
29_Craps/python/craps.py
Normal file
79
29_Craps/python/craps.py
Normal file
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env python3
|
||||
"""This game simulates the games of craps played according to standard Nevada craps table rules.
|
||||
|
||||
That is:
|
||||
|
||||
1. A 7 or 11 on the first roll wins
|
||||
2. A 2, 3, or 12 on the first roll loses
|
||||
3. Any other number rolled becomes your "point." You continue to roll; if you get your point you win. If you
|
||||
roll a 7, you lose and the dice change hands when this happens.
|
||||
|
||||
This version of craps was modified by Steve North of Creative Computing. It is based on an original which
|
||||
appeared one day one a computer at DEC.
|
||||
"""
|
||||
from random import randint
|
||||
|
||||
|
||||
def throw_dice():
|
||||
return randint(1, 6) + randint(1, 6)
|
||||
|
||||
|
||||
print(" " * 33 + "Craps")
|
||||
print(" " * 15 + "Creative Computing Morristown, New Jersey")
|
||||
print()
|
||||
print()
|
||||
print()
|
||||
|
||||
winnings = 0
|
||||
print("2,3,12 are losers; 4,5,6,8,9,10 are points; 7,11 are natural winners.")
|
||||
|
||||
play_again = True
|
||||
while play_again:
|
||||
wager = int(input("Input the amount of your wager: "))
|
||||
|
||||
print("I will now throw the dice")
|
||||
roll_1 = throw_dice()
|
||||
|
||||
if roll_1 in [7, 11]:
|
||||
print(f"{roll_1} - natural.... a winner!!!!")
|
||||
print(f"{roll_1} pays even money, you win {wager} dollars")
|
||||
winnings += wager
|
||||
elif roll_1 == 2:
|
||||
print(f"{roll_1} - snake eyes.... you lose.")
|
||||
print(f"You lose {wager} dollars")
|
||||
winnings -= wager
|
||||
elif roll_1 in [3, 12]:
|
||||
print(f"{roll_1} - craps.... you lose.")
|
||||
print(f"You lose {wager} dollars")
|
||||
winnings -= wager
|
||||
else:
|
||||
print(f"{roll_1} is the point. I will roll again")
|
||||
roll_2 = 0
|
||||
while roll_2 not in [roll_1, 7]:
|
||||
roll_2 = throw_dice()
|
||||
if roll_2 == 7:
|
||||
print(f"{roll_2} - craps. You lose.")
|
||||
print(f"You lose $ {wager}")
|
||||
winnings -= wager
|
||||
elif roll_2 == roll_1:
|
||||
print(f"{roll_1} - a winner.........congrats!!!!!!!!")
|
||||
print(f"{roll_1} at 2 to 1 odds pays you...let me see... {2 * wager} dollars")
|
||||
winnings += 2 * wager
|
||||
else:
|
||||
print(f"{roll_2} - no point. I will roll again")
|
||||
|
||||
m = input(" If you want to play again print 5 if not print 2: ")
|
||||
if winnings < 0:
|
||||
print(f"You are now under ${-winnings}")
|
||||
elif winnings > 0:
|
||||
print(f"You are now ahead ${winnings}")
|
||||
else:
|
||||
print("You are now even at 0")
|
||||
play_again = (m == "5")
|
||||
|
||||
if winnings < 0:
|
||||
print(f"Too bad, you are in the hole. Come again.")
|
||||
elif winnings > 0:
|
||||
print(f"Congratulations---you came out a winner. Come again.")
|
||||
else:
|
||||
print(f"Congratulations---you came out even, not bad for an amateur")
|
||||
@@ -1,7 +1,14 @@
|
||||
### Cube
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=53
|
||||
CUBE is a game played on the facing sides of a cube with a side dimension of 2. A location is designated by three numbers — e.g., 1, 2, 1. The object is to travel from 1, 1, 1 to 3, 3, 3 by moving one horizontal or vertical (not diagonal) square at a time without striking one of 5 randomly placed landmines. You are staked to $500; prior to each play of the game you may make a wager whether you will reach your destination. You lose if you hit a mine or try to make an illegal move — i.e., change more than one digit from your previous position.
|
||||
|
||||
Cube was created by Jerimac Ratliff of Fort Worth, Texas.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=53)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=68)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
### Depth Charge
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=55
|
||||
In this program you are captain of the destroyer USS Computer. An enemy submarine has been causing trouble and your mission is to destroy it. You may select the seize of the “cube” of water you wish to search in. The computer then determines how many depth charges you get to destroy the submarine.
|
||||
|
||||
Each depth charge is exploded by you specifying a trio of numbers; the first two are the surface coordinates (X,Y), the third is the depth. After each depth charge, your sonar observer will tell you where the explosion was relative to the submarine.
|
||||
|
||||
Dana Noftle wrote this program while a student at Acton High School, Acton, Massachusetts.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=55)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=70)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
69
31_Depth_Charge/ruby/.editorconfig
Normal file
69
31_Depth_Charge/ruby/.editorconfig
Normal file
@@ -0,0 +1,69 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
# .editorconfig
|
||||
|
||||
# Please see doc/developer_notes.md
|
||||
# If you find anything egregious or missing, please consider submitting a pull request
|
||||
# to https://github.com/theias/ias_package_shell
|
||||
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Sensible defaults for everything
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# JavaScript
|
||||
[**.js]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
|
||||
# Ruby
|
||||
[**.rb]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Python
|
||||
[**.py]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
insert_final_newline = true
|
||||
|
||||
# Perl
|
||||
[**.pl]
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
[**.pm]
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
|
||||
# PHP
|
||||
[**.php]
|
||||
charset = utf-8
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
# Makefiles
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
[**.gmk]
|
||||
indent_style = tab
|
||||
|
||||
# Configuration Files
|
||||
# Matches the exact files either package.json or .travis.yml
|
||||
[{package.json,.travis.yml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# Diff files
|
||||
[*.{diff,patch}]
|
||||
trim_trailing_whitespace = false
|
||||
211
31_Depth_Charge/ruby/depthcharge.rb
Executable file
211
31_Depth_Charge/ruby/depthcharge.rb
Executable file
@@ -0,0 +1,211 @@
|
||||
#!/usr/bin/ruby
|
||||
|
||||
class DepthCharge
|
||||
|
||||
def run_game
|
||||
output_title()
|
||||
while true
|
||||
printf("----------\n")
|
||||
print_instructions()
|
||||
setup_game()
|
||||
printf("\n")
|
||||
game_loop()
|
||||
break if ! get_input_another_game()
|
||||
end
|
||||
|
||||
# 420 PRINT "OK. HOPE YOU ENJOYED YOURSELF." : GOTO 600
|
||||
printf("OK. HOPE YOU ENJOYED YOURSELF.\n")
|
||||
end
|
||||
|
||||
def output_title
|
||||
printf("--- DEPTH CHARGE ---\n")
|
||||
printf("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n")
|
||||
printf("\n")
|
||||
end
|
||||
|
||||
def get_input_y_or_n(message)
|
||||
while true
|
||||
print(message)
|
||||
|
||||
value = gets.chomp
|
||||
|
||||
if (value == 'Y' || value == 'y')
|
||||
return true
|
||||
elsif value == 'N' || value == 'n'
|
||||
return false
|
||||
end
|
||||
|
||||
printf("PLEASE ENTER Y/y OR N/n...\n\n")
|
||||
end
|
||||
end
|
||||
|
||||
def get_input_positive_integer(message)
|
||||
|
||||
while true
|
||||
print(message)
|
||||
value = gets.chomp
|
||||
if (value == 'd')
|
||||
debug_game()
|
||||
next
|
||||
end
|
||||
|
||||
the_input = Integer(value) rescue nil
|
||||
|
||||
if the_input == nil || the_input < 0
|
||||
printf("PLEASE ENTER A POSITIVE NUMBER\n\n")
|
||||
next
|
||||
|
||||
end
|
||||
|
||||
return the_input
|
||||
end
|
||||
end
|
||||
|
||||
def get_search_area_dimension
|
||||
# 20 INPUT "DIMENSION OF SEARCH AREA";G: PRINT
|
||||
@search_area_dimension = get_input_positive_integer("DIMENSION OF SEARCH AREA: ")
|
||||
# 30 N=INT(LOG(G)/LOG(2))+1
|
||||
|
||||
@num_tries = Integer(
|
||||
Math.log(@search_area_dimension)/Math.log(2)
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
def print_instructions
|
||||
# 40 PRINT "YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER"
|
||||
# 50 PRINT "AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR"
|
||||
# 60 PRINT "MISSION IS TO DESTROY IT. YOU HAVE";N;"SHOTS."
|
||||
# 70 PRINT "SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A"
|
||||
# 80 PRINT "TRIO OF NUMBERS -- THE FIRST TWO ARE THE"
|
||||
# 90 PRINT "SURFACE COORDINATES; THE THIRD IS THE DEPTH."
|
||||
# 100 PRINT : PRINT "GOOD LUCK !": PRINT
|
||||
printf( <<~INSTRUCTIONS
|
||||
YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER
|
||||
AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR
|
||||
MISSION IS TO DESTROY IT.
|
||||
|
||||
SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A
|
||||
TRIO OF NUMBERS -- THE FIRST TWO ARE THE
|
||||
SURFACE COORDINATES (X, Y):
|
||||
WEST < X < EAST
|
||||
SOUTH < Y < NORTH
|
||||
|
||||
THE THIRD IS THE DEPTH (Z):
|
||||
SHALLOW < Z < DEEP
|
||||
|
||||
GOOD LUCK !
|
||||
|
||||
INSTRUCTIONS
|
||||
)
|
||||
end
|
||||
|
||||
def debug_game
|
||||
printf("@enemy_x: %d\n", @enemy_x)
|
||||
printf("@enemy_y: %d\n", @enemy_y)
|
||||
printf("@enemy_z: %d\n", @enemy_z)
|
||||
printf("@num_tries: %d\n", @num_tries)
|
||||
printf("@trial: %d\n", @trial)
|
||||
printf("\n")
|
||||
end
|
||||
|
||||
def setup_game
|
||||
get_search_area_dimension()
|
||||
setup_enemy()
|
||||
end
|
||||
|
||||
def setup_enemy
|
||||
# 110 A=INT(G*RND(1)) : B=INT(G*RND(1)) : C=INT(G*RND(1))
|
||||
@enemy_x = rand(1..@search_area_dimension)
|
||||
@enemy_y = rand(1..@search_area_dimension)
|
||||
@enemy_z = rand(1..@search_area_dimension)
|
||||
end
|
||||
|
||||
def game_loop
|
||||
# 120 FOR D=1 TO N : PRINT : PRINT "TRIAL #";D; : INPUT X,Y,Z
|
||||
for @trial in 1..@num_tries do
|
||||
output_game_status()
|
||||
|
||||
@shot_x = get_input_positive_integer("X: ")
|
||||
@shot_y = get_input_positive_integer("Y: ")
|
||||
@shot_z = get_input_positive_integer("Z: ")
|
||||
|
||||
# 130 IF ABS(X-A)+ABS(Y-B)+ABS(Z-C)=0 THEN 300
|
||||
if (
|
||||
(@enemy_x - @shot_x).abs \
|
||||
+ (@enemy_y - @shot_y).abs \
|
||||
+ (@enemy_z - @shot_z).abs \
|
||||
== 0
|
||||
)
|
||||
you_win()
|
||||
return
|
||||
else
|
||||
# 140 GOSUB 500 : PRINT : NEXT D
|
||||
missed_shot()
|
||||
end
|
||||
end
|
||||
|
||||
printf("\n")
|
||||
|
||||
you_lose()
|
||||
|
||||
end
|
||||
|
||||
def output_game_status
|
||||
printf("YOU HAVE %d SHOTS REMAINING.\n", @num_tries - @trial + 1)
|
||||
printf("TRIAL \#%d\n", @trial)
|
||||
end
|
||||
def you_win
|
||||
printf("B O O M ! ! YOU FOUND IT IN %d TRIES!\n\n", @trial )
|
||||
end
|
||||
def missed_shot
|
||||
missed_directions = []
|
||||
|
||||
# 530 IF X>A THEN PRINT "EAST";
|
||||
# 540 IF X<A THEN PRINT "WEST";
|
||||
if @shot_x > @enemy_x
|
||||
missed_directions.push('TOO FAR EAST')
|
||||
elsif @shot_x < @enemy_x
|
||||
missed_directions.push('TOO FAR WEST')
|
||||
end
|
||||
|
||||
# 510 IF Y>B THEN PRINT "NORTH";
|
||||
# 520 IF Y<B THEN PRINT "SOUTH";
|
||||
if @shot_y > @enemy_y
|
||||
missed_directions.push('TOO FAR NORTH')
|
||||
elsif @shot_y < @enemy_y
|
||||
missed_directions.push('TOO FAR SOUTH')
|
||||
end
|
||||
|
||||
# 560 IF Z>C THEN PRINT " TOO LOW."
|
||||
# 570 IF Z<C THEN PRINT " TOO HIGH."
|
||||
# 580 IF Z=C THEN PRINT " DEPTH OK."
|
||||
if @shot_z > @enemy_z
|
||||
missed_directions.push('TOO DEEP')
|
||||
elsif @shot_z < @enemy_z
|
||||
missed_directions.push('TOO SHALLOW')
|
||||
end
|
||||
|
||||
# 500 PRINT "SONAR REPORTS SHOT WAS ";
|
||||
printf("SONAR REPORTS SHOT WAS: \n")
|
||||
printf("%s\n", "\t" + missed_directions.join("\n\t"))
|
||||
# 550 IF Y<>B OR X<>A THEN PRINT " AND";
|
||||
# 590 RETURN
|
||||
end
|
||||
|
||||
def you_lose
|
||||
# You took too long!
|
||||
printf("YOU HAVE BEEN TORPEDOED! ABANDON SHIP!\n")
|
||||
printf("THE SUBMARINE WAS AT %d %d %d\n", @enemy_x, @enemy_y, @enemy_z)
|
||||
|
||||
end
|
||||
|
||||
def get_input_another_game
|
||||
# 400 PRINT : PRINT: INPUT "ANOTHER GAME (Y OR N)";A$
|
||||
return get_input_y_or_n("ANOTHER GAME (Y OR N): ")
|
||||
# 410 IF A$="Y" THEN 100
|
||||
end
|
||||
end
|
||||
|
||||
game = DepthCharge.new
|
||||
game.run_game()
|
||||
@@ -1,7 +1,14 @@
|
||||
### Diamond
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=56
|
||||
This program fills an 8.5x11 piece of paper with diamonds (plotted on a hard-copy terminal, of course). The program asks for an odd number to be input in the range 5 to 31. The diamonds printed will be this number of characters high and wide. The number of diamonds across the page will vary from 12 for 5-character wide diamonds to 1 for a diamond 31-characters wide. You can change the content of the pattern if you wish.
|
||||
|
||||
The program was written by David Ahl of Creative Computing.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=56)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=71)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,21 @@
|
||||
### Dice
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=57
|
||||
Not exactly a game, this program simulates rolling a pair of dice a large number of times and prints out the frequency distribution. You simply input the number of rolls. It is interesting to see how many rolls are necessary to approach the theoretical distribution:
|
||||
|
||||
| | | |
|
||||
|---|------|------------|
|
||||
| 2 | 1/36 | 2.7777...% |
|
||||
| 3 | 2/36 | 5.5555...% |
|
||||
| 4 | 3/36 | 8.3333...% |
|
||||
etc.
|
||||
|
||||
Daniel Freidus wrote this program while in the seventh grade at Harrison Jr-Sr High School, Harrison, New York.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=57)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=72)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
### Digits
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=58
|
||||
The player writes down a set of 30 numbers (0, 1, or 2) at random prior to playing the game. The computer program, using pattern recognition techniques, attempts to guess the next number in your list.
|
||||
|
||||
The computer asks for 10 numbers at a time. It always guesses first and then examines the next number to see if it guessed correctly. By pure luck (or chance or probability), the computer ought to be right 10 times. It is uncanny how much better it generally does than that!
|
||||
|
||||
This program originated at Dartmouth; original author unknown.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=58)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=73)
|
||||
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
### Even Wins
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=60
|
||||
This is a game between you and the computer. To play, an odd number of objects (marbles, chips, matches) are placed in a row. You take turns with the computer picking up between one and four objects each turn. The game ends when there are no objects left, and the winner is the one with an even number of objects picked up.
|
||||
|
||||
Two versions of this game are included. While to the player they appear similar, the programming approach is quite different. EVEN WINS, the first version, is deterministic — i.e., the computer plays by fixed, good rules and is impossible to beat if you don’t know how to play the game. It always starts with 27 objects, although you may change this.
|
||||
|
||||
The second version, GAME OF EVEN WINS, is much more interesting because the computer starts out only knowing the rules of the game. Using simple techniques of artificial intelligence (cybernetics), the computer gradually learns to play this game from its mistakes until it plays a very good game. After 20 games, the computer is a challenge to beat. Variation in the human’s style of play seems to make the computer learn more quickly. If you plot the learning curve of this program, it closely resembles classical human learning curves from psychological experiments.
|
||||
|
||||
Eric Peters at DEC wrote the GAME OF EVEN WINS. The original author of EVEN WINS is unknown.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=60)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=75)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
206
35_Even_Wins/python/evenwins.py
Normal file
206
35_Even_Wins/python/evenwins.py
Normal file
@@ -0,0 +1,206 @@
|
||||
# evenwins.py
|
||||
|
||||
#
|
||||
# This version of evenwins.bas based on game decscription and does *not*
|
||||
# follow the source. The computer chooses marbles at random.
|
||||
#
|
||||
# For simplicity, global variables are used to store the game state.
|
||||
# A good exercise would be to replace this with a class.
|
||||
#
|
||||
# The code is not short, but hopefully it is easy for beginners to understand
|
||||
# and modify.
|
||||
#
|
||||
# Infinite loops of the style "while True:" are used to simplify some of the
|
||||
# code. The "continue" keyword is used in a few places to jump back to the top
|
||||
# of the loop. The "return" keyword is also used to break out of functions.
|
||||
# This is generally considered poor style, but in this case it simplifies the
|
||||
# code and makes it easier to read (at least in my opinion). A good exercise
|
||||
# would be to remove these infinite loops, and uses of continue, to follow a
|
||||
# more structured style.
|
||||
#
|
||||
|
||||
import random
|
||||
|
||||
# global variables
|
||||
marbles_in_middle = -1
|
||||
human_marbles = -1
|
||||
computer_marbles = -1
|
||||
whose_turn = ''
|
||||
|
||||
# Only called during development for serious errors that are due to mistakes
|
||||
# in the program. Should never be called during a regular game.
|
||||
def serious_error(msg):
|
||||
print('serious_error: ' + msg)
|
||||
exit(1)
|
||||
|
||||
def welcome_screen():
|
||||
print('Welcome to Even Wins!')
|
||||
print('Based on evenwins.bas from Creative Computing')
|
||||
print()
|
||||
print('Even Wins is a two-person game. You start with')
|
||||
print('27 marbles in the middle of the table.')
|
||||
print()
|
||||
print('Players alternate taking marbles from the middle.')
|
||||
print('A player can take 1 to 4 marbles on their turn, and')
|
||||
print('turns cannot be skipped. The game ends when there are')
|
||||
print('no marbles left, and the winner is the one with an even')
|
||||
print('number of marbles.')
|
||||
print()
|
||||
|
||||
def marbles_str(n):
|
||||
if n == 1: return '1 marble'
|
||||
return f'{n} marbles'
|
||||
|
||||
def choose_first_player():
|
||||
global whose_turn
|
||||
while True:
|
||||
ans = input('Do you want to play first? (y/n) --> ')
|
||||
if ans == 'y':
|
||||
whose_turn = 'human'
|
||||
return
|
||||
elif ans == 'n':
|
||||
whose_turn = 'computer'
|
||||
return
|
||||
else:
|
||||
print()
|
||||
print('Please enter "y" if you want to play first,')
|
||||
print('or "n" if you want to play second.')
|
||||
print()
|
||||
|
||||
def next_player():
|
||||
global whose_turn
|
||||
if whose_turn == 'human':
|
||||
whose_turn = 'computer'
|
||||
elif whose_turn == 'computer':
|
||||
whose_turn = 'human'
|
||||
else:
|
||||
serious_error(f'play_game: unknown player {whose_turn}')
|
||||
|
||||
# Converts a string s to an int, if possible.
|
||||
def to_int(s):
|
||||
try:
|
||||
n = int(s)
|
||||
return True, n
|
||||
except:
|
||||
return False, 0
|
||||
|
||||
def print_board():
|
||||
global marbles_in_middle
|
||||
global human_marbles
|
||||
global computer_marbles
|
||||
print()
|
||||
print(f' marbles in the middle: {marbles_in_middle} ' + marbles_in_middle*'*')
|
||||
print(f' # marbles you have: {human_marbles}')
|
||||
print(f'# marbles computer has: {computer_marbles}')
|
||||
print()
|
||||
|
||||
def human_turn():
|
||||
global marbles_in_middle
|
||||
global human_marbles
|
||||
|
||||
# get number in range 1 to min(4, marbles_in_middle)
|
||||
max_choice = min(4, marbles_in_middle)
|
||||
print("It's your turn!")
|
||||
while True:
|
||||
s = input(f'Marbles to take? (1 - {max_choice}) --> ')
|
||||
ok, n = to_int(s)
|
||||
if not ok:
|
||||
print()
|
||||
print(f' Please enter a whole number from 1 to {max_choice}')
|
||||
print()
|
||||
continue
|
||||
if n < 1:
|
||||
print()
|
||||
print(' You must take at least 1 marble!')
|
||||
print()
|
||||
continue
|
||||
if n > max_choice:
|
||||
print()
|
||||
print(f' You can take at most {marbles_str(max_choice)}')
|
||||
print()
|
||||
continue
|
||||
print()
|
||||
print(f'Okay, taking {marbles_str(n)} ...')
|
||||
marbles_in_middle -= n
|
||||
human_marbles += n
|
||||
return
|
||||
|
||||
def game_over():
|
||||
global marbles_in_middle
|
||||
global human_marbles
|
||||
global computer_marbles
|
||||
print()
|
||||
print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
|
||||
print('!! All the marbles are taken: Game Over!')
|
||||
print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
|
||||
print()
|
||||
print_board()
|
||||
if human_marbles % 2 == 0:
|
||||
print('You are the winner! Congratulations!')
|
||||
else:
|
||||
print('The computer wins: all hail mighty silicon!')
|
||||
print('')
|
||||
|
||||
def computer_turn():
|
||||
global marbles_in_middle
|
||||
global computer_marbles
|
||||
|
||||
print("It's the computer's turn ...")
|
||||
max_choice = min(4, marbles_in_middle)
|
||||
|
||||
# choose at random
|
||||
n = random.randint(1, max_choice)
|
||||
print(f'Computer takes {marbles_str(n)} ...')
|
||||
marbles_in_middle -= n
|
||||
computer_marbles += n
|
||||
|
||||
def play_game():
|
||||
global marbles_in_middle
|
||||
global human_marbles
|
||||
global computer_marbles
|
||||
|
||||
# initialize the game state
|
||||
marbles_in_middle = 27
|
||||
human_marbles = 0
|
||||
computer_marbles = 0
|
||||
print_board()
|
||||
|
||||
while True:
|
||||
if marbles_in_middle == 0:
|
||||
game_over()
|
||||
return
|
||||
elif whose_turn == 'human':
|
||||
human_turn()
|
||||
print_board()
|
||||
next_player()
|
||||
elif whose_turn == 'computer':
|
||||
computer_turn()
|
||||
print_board()
|
||||
next_player()
|
||||
else:
|
||||
serious_error(f'play_game: unknown player {whose_turn}')
|
||||
|
||||
def main():
|
||||
global whose_turn
|
||||
|
||||
welcome_screen()
|
||||
|
||||
while True:
|
||||
choose_first_player()
|
||||
play_game()
|
||||
|
||||
# ask if the user if they want to play again
|
||||
print()
|
||||
again = input('Would you like to play again? (y/n) --> ')
|
||||
if again == 'y':
|
||||
print()
|
||||
print("Ok, let's play again ...")
|
||||
print()
|
||||
else:
|
||||
print()
|
||||
print('Ok, thanks for playing ... goodbye!')
|
||||
print()
|
||||
return
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,7 +1,28 @@
|
||||
### Flip Flop
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=63
|
||||
The object of this game is to change a row of ten X’s
|
||||
|
||||
```
|
||||
X X X X X X X X X X
|
||||
```
|
||||
|
||||
to a row of ten 0’s
|
||||
|
||||
```
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
```
|
||||
|
||||
by typing in a number corresponding to the position of an “X” in the line. On some numbers one position will change while on other numbers, two will change. For example, inputting a 3 may reverse the X and 0 in position 3, but it might possibly reverse some of other position too! You ought to be able to change all 10 in 12 or fewer moves. Can you figure out a good winning strategy?
|
||||
|
||||
To reset the line to all X’s (same game), type 0 (zero). To start a new game at any point, type 11.
|
||||
|
||||
The original author of this game was Micheal Kass of New Hyde Park, New York.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=63)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=78)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
129
36_Flip_Flop/python/flipflop.py
Normal file
129
36_Flip_Flop/python/flipflop.py
Normal file
@@ -0,0 +1,129 @@
|
||||
# Flip Flop
|
||||
#
|
||||
# The object of this game is to change a row of ten X's
|
||||
# X X X X X X X X X X
|
||||
# to a row of ten O's:
|
||||
# O O O O O O O O O O
|
||||
# by typing in a number corresponding
|
||||
# to the position of an "X" in the line. On
|
||||
# some numbers one position will
|
||||
# change while on other numbers, two
|
||||
# will change. For example, inputting a 3
|
||||
# may reverse the X and O in position 3,
|
||||
# but it might possibly reverse some
|
||||
# other position too! You ought to be able
|
||||
# to change all 10 in 12 or fewer
|
||||
# moves. Can you figure out a good win-
|
||||
# ning strategy?
|
||||
# To reset the line to all X's (same
|
||||
# game), type 0 (zero). To start a new
|
||||
# game at any point, type 11.
|
||||
# The original author of this game was
|
||||
# Michael Kass of New Hyde Park, New
|
||||
# York.
|
||||
import random
|
||||
import math
|
||||
from typing import Callable, List, Tuple
|
||||
|
||||
flip_dict = {"X": "O", "O": "X"}
|
||||
|
||||
|
||||
def flip_bits(
|
||||
row: List[str], m: int, n: int, r_function: Callable[[int], float]
|
||||
) -> Tuple[List[str], int]:
|
||||
"""
|
||||
Function that flips the positions at the computed steps
|
||||
"""
|
||||
while m == n:
|
||||
r = r_function(n)
|
||||
n = r - int(math.floor(r))
|
||||
n = int(10 * n)
|
||||
if row[n] == "X":
|
||||
row[n] = "O"
|
||||
break
|
||||
elif row[n] == "O":
|
||||
row[n] = "X"
|
||||
return row, n
|
||||
|
||||
|
||||
def print_instructions():
|
||||
print(" " * 32 + "FLIPFLOP")
|
||||
print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
||||
print("\n" * 2)
|
||||
print("THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:\n")
|
||||
print("X X X X X X X X X X\n")
|
||||
print("TO THIS:\n")
|
||||
print("O O O O O O O O O O\n")
|
||||
print("BY TYPING TH NUMBER CORRESPONDING TO THE POSITION OF THE")
|
||||
print("LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON")
|
||||
print("OTHERS, TWO WILL CHANGE. TO RESET LINE TO ALL X'S, TYPE 0")
|
||||
print("(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE ")
|
||||
print("11 (ELEVEN).\n")
|
||||
|
||||
|
||||
def main():
|
||||
q = random.random()
|
||||
|
||||
print("HERE IS THE STARTING LINE OF X'S.\n")
|
||||
# We add an extra 0-th item because this sometimes is set to something
|
||||
# but we never check what it is for completion of the puzzle
|
||||
row = [""] + ["X"] * 10
|
||||
counter_turns = 0
|
||||
n = -1
|
||||
legal_move = True
|
||||
while row[1:] != ["O"] * 10:
|
||||
if legal_move:
|
||||
print(" ".join([str(i) for i in range(1, 11)]))
|
||||
print(" ".join(row[1:]) + "\n")
|
||||
m = input("INPUT THE NUMBER\n")
|
||||
try:
|
||||
m = int(m)
|
||||
if m > 11 or m < 0:
|
||||
raise ValueError()
|
||||
except ValueError:
|
||||
print("ILLEGAL ENTRY--TRY AGAIN")
|
||||
legal_move = False
|
||||
continue
|
||||
legal_move = True
|
||||
if m == 11:
|
||||
# completely reset the puzzle
|
||||
counter_turns = 0
|
||||
row = [""] + ["X"] * 10
|
||||
q = random.random()
|
||||
continue
|
||||
elif m == 0:
|
||||
# reset the board, but not the counter or the random number
|
||||
row = [""] + ["X"] * 10
|
||||
elif m == n:
|
||||
row[n] = flip_dict[row[n]]
|
||||
r_function = lambda n_t: 0.592 * (1 / math.tan(q / n_t + q)) / math.sin(
|
||||
n_t * 2 + q
|
||||
) - math.cos(n_t)
|
||||
row, n = flip_bits(row, m, n, r_function)
|
||||
else:
|
||||
n = m
|
||||
row[n] = flip_dict[row[n]]
|
||||
r_function = lambda n_t: (
|
||||
math.tan(q + n_t / q - n_t)
|
||||
- math.sin(n_t * 2 + q)
|
||||
+ 336 * math.sin(8 * n_t)
|
||||
)
|
||||
row, n = flip_bits(row, m, n, r_function)
|
||||
|
||||
counter_turns += 1
|
||||
print()
|
||||
|
||||
if counter_turns <= 12:
|
||||
print(f"VERY GOOD. YOU GUESSED IT IN ONLY {counter_turns} GUESSES.")
|
||||
else:
|
||||
print(f"TRY HARDER NEXT TIME. IT TOOK YOU {counter_turns} GUESSES.")
|
||||
return
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print_instructions()
|
||||
|
||||
another = ""
|
||||
while another != "NO":
|
||||
main()
|
||||
another = input("DO YOU WANT TO TRY ANOTHER PUZZLE\n")
|
||||
@@ -1,7 +1,18 @@
|
||||
### Football
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=64
|
||||
Football is probably the most popular simulated sports game. I have seen some people play to elect to play computerized football in preference to watching a football game on television.
|
||||
|
||||
Two versions of football are presented. The first is somewhat “traditional” in that you, the player, are playing against the computer. You have a choice of seven offensive plays. On defense the computer seems to play a zone defence, but you have no choice of plays. The computer program presents the necessary rules as you play, and it is also the referee and determines penalties when an infraction is committed. FTBALL was written by John Kemeny at Dartmouth.
|
||||
|
||||
IN the second version of football, the computer referees a game played between two human players. Each player gets a list of twenty plays with a code value for each one. This list should be kept confidential from your opponent. The codes can be changes in data. All twenty plays are offensive; a defensive play is specified by defending against a type of offensive play. A defense is good for other similar types of plays, for example, a defense against a flare pass is very good against a screen pass but much less good against a half-back option.
|
||||
|
||||
This game was originally written by Raymond Miseyka of Butler, Pennsylvania.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=64)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=79)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
### Fur Trader
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=69
|
||||
You are the leader of a French fur trading expedition in 1776 leaving the Ontario area to sell furs and get supplies for the next year. You have a choice of three forts at which you may trade. The cost of supplies and the amount you recieve for your furs will depend upon the fort you choose. You also specify what types of furs that you have to trade.
|
||||
|
||||
The game goes on and on until you elect to trade no longer.
|
||||
|
||||
Author of the program is Dan Bachor, University of Calgary, Alberta, Canada.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=69)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=84)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
### Golf
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=71
|
||||
This is a single player golf game. In other words it’s you against the golf course (the computer). The program asks for your handicap (maximum of 30) and your area of difficulty. You have a bag of 29 clubs plus a putter. On the course you have to contend with rough, trees, on and off fairway, sand traps, and water hazards. In addition, you can hook, slice, go out of bounds, or hit too far. On putting, you determine the potency factor (or percent of swing). Until you get the swing of the game (no pun intended), you’ll probably was to use a fairly high handicap.
|
||||
|
||||
Steve North of Creative Computing modified the original version of this game, the author of which is unknown.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=71)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=86)
|
||||
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
### Gomoko
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=74
|
||||
GOMOKO or GOMOKU is a traditional game of the Orient. It is played by two people on a board of intersecting lines (19 left-to-right lines, 19 top-to-bottom lines, 361 intersections in all). Players take turns. During his turn, a player may cover one intersection with a marker; (one player uses white markers; the other player uses black markers). The object of the game is to get five adjacent markers in a row, horizontally, vertically or along either diagonal.
|
||||
|
||||
Unfortunately, this program does not make the computer a very good player. It does not know when you are about to win or even who has won. But some of its moves may surprise you.
|
||||
|
||||
The original author of this program is Peter Sessions of People’s Computer Company.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=74)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=89)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
### Guess
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=75
|
||||
In Program GUESS, the computer chooses a random integer between 0 and any limit you set. You must then try to guess the number the computer has chosen using the clues provided by the computer.
|
||||
|
||||
You should be able to guess the number in one less than the number of digits needed to represent the number in binary notation — i.e., in base 2. This ought to give you a clue as to the optimum search technique.
|
||||
|
||||
GUESS converted from the original program in FOCAL which appeared in the book “Computers in the Classroom” by Walt Koetke of Lexington High School, Lexington, Massachusetts.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=75)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=90)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
### Gunner
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=77
|
||||
GUNNER allows you to adjust the fire of a field artillery weapon to hit a stationary target. You specify the number of degrees of elevation of your weapon; 45 degrees provides maximum range with values under or over 45 degrees providing less range.
|
||||
|
||||
You get up to five shots to destroy the enemy before he destroys you. Gun range varies between 20,000 and 60,000 yards and burst radius is 100 yards. You must specify elevation within approximately 0.2 degrees to get a hit.
|
||||
|
||||
Tom Kloos of the Oregon Museum of Science and Industry in Portland, Oregon originally wrote GUNNER. Extensive modifications were added by David Ahl.
|
||||
|
||||
---
|
||||
|
||||
As published in Basic Computer Games (1978):
|
||||
- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=77)
|
||||
- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=92)
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
124
42_Gunner/csharp/Program.cs
Normal file
124
42_Gunner/csharp/Program.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
namespace Gunner
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
PrintIntro();
|
||||
|
||||
string keepPlaying = "Y";
|
||||
|
||||
while (keepPlaying == "Y") {
|
||||
PlayGame();
|
||||
Console.WriteLine("TRY AGAIN (Y OR N)");
|
||||
keepPlaying = Console.ReadLine();
|
||||
}
|
||||
}
|
||||
|
||||
static void PlayGame()
|
||||
{
|
||||
int totalAttempts = 0;
|
||||
int amountOfGames = 0;
|
||||
|
||||
while (amountOfGames < 4) {
|
||||
|
||||
int maximumRange = new Random().Next(0, 40000) + 20000;
|
||||
Console.WriteLine($"MAXIMUM RANGE OF YOUR GUN IS {maximumRange} YARDS." + Environment.NewLine + Environment.NewLine + Environment.NewLine);
|
||||
|
||||
int distanceToTarget = (int) (maximumRange * (0.1 + 0.8 * new Random().NextDouble()));
|
||||
Console.WriteLine($"DISTANCE TO THE TARGET IS {distanceToTarget} YARDS.");
|
||||
|
||||
(bool gameWon, int attempts) = HitTheTarget(maximumRange, distanceToTarget);
|
||||
|
||||
if(!gameWon) {
|
||||
Console.WriteLine(Environment.NewLine + "BOOM !!!! YOU HAVE JUST BEEN DESTROYED" + Environment.NewLine +
|
||||
"BY THE ENEMY." + Environment.NewLine + Environment.NewLine + Environment.NewLine
|
||||
);
|
||||
PrintReturnToBase();
|
||||
break;
|
||||
} else {
|
||||
amountOfGames += 1;
|
||||
totalAttempts += attempts;
|
||||
|
||||
Console.WriteLine($"TOTAL ROUNDS EXPENDED WERE:{totalAttempts}");
|
||||
|
||||
if (amountOfGames < 4) {
|
||||
Console.WriteLine("THE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY...");
|
||||
} else {
|
||||
if (totalAttempts > 18) {
|
||||
PrintReturnToBase();
|
||||
} else {
|
||||
Console.WriteLine($"NICE SHOOTING !!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static (bool, int) HitTheTarget(int maximumRange, int distanceToTarget)
|
||||
{
|
||||
int attempts = 0;
|
||||
|
||||
while (attempts < 6)
|
||||
{
|
||||
int elevation = GetElevation();
|
||||
|
||||
int differenceBetweenTargetAndImpact = CalculateDifferenceBetweenTargetAndImpact(maximumRange, distanceToTarget, elevation);
|
||||
|
||||
if (Math.Abs(differenceBetweenTargetAndImpact) < 100)
|
||||
{
|
||||
Console.WriteLine($"*** TARGET DESTROYED *** {attempts} ROUNDS OF AMMUNITION EXPENDED.");
|
||||
return (true, attempts);
|
||||
}
|
||||
else if (differenceBetweenTargetAndImpact > 100)
|
||||
{
|
||||
Console.WriteLine($"OVER TARGET BY {Math.Abs(differenceBetweenTargetAndImpact)} YARDS.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"SHORT OF TARGET BY {Math.Abs(differenceBetweenTargetAndImpact)} YARDS.");
|
||||
}
|
||||
|
||||
attempts += 1;
|
||||
}
|
||||
return (false, attempts);
|
||||
}
|
||||
|
||||
static int CalculateDifferenceBetweenTargetAndImpact(int maximumRange, int distanceToTarget, int elevation)
|
||||
{
|
||||
double weirdNumber = 2 * elevation / 57.3;
|
||||
double distanceShot = maximumRange * Math.Sin(weirdNumber);
|
||||
return (int)distanceShot - distanceToTarget;
|
||||
}
|
||||
|
||||
static void PrintReturnToBase()
|
||||
{
|
||||
Console.WriteLine("BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!");
|
||||
}
|
||||
|
||||
static int GetElevation()
|
||||
{
|
||||
Console.WriteLine("ELEVATION");
|
||||
int elevation = int.Parse(Console.ReadLine());
|
||||
if (elevation > 89) {
|
||||
Console.WriteLine("MAXIMUM ELEVATION IS 89 DEGREES");
|
||||
return GetElevation();
|
||||
}
|
||||
if (elevation < 1) {
|
||||
Console.WriteLine("MINIMUM ELEVATION IS 1 DEGREE");
|
||||
return GetElevation();
|
||||
}
|
||||
return elevation;
|
||||
}
|
||||
|
||||
static void PrintIntro()
|
||||
{
|
||||
Console.WriteLine(new String(' ', 30) + "GUNNER");
|
||||
Console.WriteLine(new String(' ', 15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + Environment.NewLine + Environment.NewLine + Environment.NewLine);
|
||||
Console.WriteLine("YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN");
|
||||
Console.WriteLine("CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE");
|
||||
Console.WriteLine("WILL PLACE A PROJECTILE ON TARGET. A HIT WITHIN 100 YARDS");
|
||||
Console.WriteLine("OF THE TARGET WILL DESTROY IT." + Environment.NewLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user