mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-04-28 19:59:02 -07:00
Merge branch 'coding-horror:main' into 48_High_IQ_Python
This commit is contained in:
19
.gitignore
vendored
19
.gitignore
vendored
@@ -1,3 +1,19 @@
|
||||
.local/
|
||||
.vscode/
|
||||
.gradle/
|
||||
node_modules/
|
||||
buildJvm/
|
||||
|
||||
build.gradle
|
||||
|
||||
.classpath
|
||||
.project
|
||||
.settings
|
||||
.metadata
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
*.class
|
||||
*/.vs
|
||||
*.suo
|
||||
|
||||
@@ -11,6 +27,9 @@ obj/
|
||||
out/
|
||||
|
||||
*.py[co]
|
||||
|
||||
Pipfile
|
||||
|
||||
.DS_Store
|
||||
/.vs/basic-computer-games/v16
|
||||
/.vs
|
||||
|
||||
84
00_Utilities/find-missing-implementations.js
Normal file
84
00_Utilities/find-missing-implementations.js
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Program to find games that are missing solutions in a given language
|
||||
*
|
||||
* Scan each game folder, check for a folder for each language, and also make
|
||||
* sure there's at least one file of the expected extension and not just a
|
||||
* readme or something
|
||||
*/
|
||||
|
||||
const fs = require("fs");
|
||||
const glob = require("glob");
|
||||
|
||||
// relative path to the repository root
|
||||
const ROOT_PATH = "../.";
|
||||
|
||||
const languages = [
|
||||
{ name: "csharp", extension: "cs" },
|
||||
{ name: "java", extension: "java" },
|
||||
{ name: "javascript", extension: "html" },
|
||||
{ name: "pascal", extension: "pas" },
|
||||
{ name: "perl", extension: "pl" },
|
||||
{ name: "python", extension: "py" },
|
||||
{ name: "ruby", extension: "rb" },
|
||||
{ name: "vbnet", extension: "vb" },
|
||||
];
|
||||
|
||||
const getFilesRecursive = async (path, extension) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
glob(`${path}/**/*.${extension}`, (err, matches) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve(matches);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const getPuzzleFolders = () => {
|
||||
return fs
|
||||
.readdirSync(ROOT_PATH, { withFileTypes: true })
|
||||
.filter((dirEntry) => dirEntry.isDirectory())
|
||||
.filter(
|
||||
(dirEntry) =>
|
||||
![".git", "node_modules", "00_Utilities"].includes(dirEntry.name)
|
||||
)
|
||||
.map((dirEntry) => dirEntry.name);
|
||||
};
|
||||
|
||||
(async () => {
|
||||
let missingGames = {};
|
||||
let missingLanguageCounts = {};
|
||||
languages.forEach((l) => (missingLanguageCounts[l.name] = 0));
|
||||
const puzzles = getPuzzleFolders();
|
||||
for (const puzzle of puzzles) {
|
||||
for (const { name: language, extension } of languages) {
|
||||
const files = await getFilesRecursive(
|
||||
`${ROOT_PATH}/${puzzle}/${language}`,
|
||||
extension
|
||||
);
|
||||
if (files.length === 0) {
|
||||
if (!missingGames[puzzle]) missingGames[puzzle] = [];
|
||||
|
||||
missingGames[puzzle].push(language);
|
||||
missingLanguageCounts[language]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
const missingCount = Object.values(missingGames).flat().length;
|
||||
if (missingCount === 0) {
|
||||
console.log("All games have solutions for all languages");
|
||||
} else {
|
||||
console.log(`Missing ${missingCount} implementations:`);
|
||||
|
||||
Object.entries(missingGames).forEach(
|
||||
([p, ls]) => (missingGames[p] = ls.join(", "))
|
||||
);
|
||||
|
||||
console.log(`\nMissing languages by game:`);
|
||||
console.table(missingGames);
|
||||
console.log(`\nBy language:`);
|
||||
console.table(missingLanguageCounts);
|
||||
}
|
||||
})();
|
||||
|
||||
return;
|
||||
50
00_Utilities/markdown_todo.py
Normal file
50
00_Utilities/markdown_todo.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import os
|
||||
|
||||
|
||||
lang_pos = {
|
||||
"csharp": 1, "java": 2, "javascript": 3,
|
||||
"pascal": 4, "perl": 5, "python": 6, "ruby": 7, "vbnet": 8
|
||||
}
|
||||
|
||||
write_string = "# TODO list \n game | csharp | java | javascript | pascal | perl | python | ruby | vbnet \n --- | --- | --- | --- | --- | --- | --- | --- | --- \n"
|
||||
# Set the directory you want to start from
|
||||
rootDir = '..'
|
||||
|
||||
strings_done = []
|
||||
|
||||
checklist = ["game", "csharp", "java", "javascript",
|
||||
"pascal", "perl", "python", "ruby", "vbnet"]
|
||||
|
||||
prev_game = ""
|
||||
|
||||
for dirName, subdirList, fileList in os.walk(rootDir):
|
||||
split_dir = dirName.split("/")
|
||||
|
||||
if len(split_dir) == 2 and not split_dir[1] in ['.git', '00_Utilities']:
|
||||
if prev_game == "":
|
||||
prev_game = split_dir[1]
|
||||
checklist[0] = split_dir[1]
|
||||
|
||||
if prev_game != split_dir[1]:
|
||||
# it's a new dir
|
||||
strings_done.append(checklist)
|
||||
checklist = [split_dir[1], "csharp", "java", "javascript",
|
||||
"pascal", "perl", "python", "ruby", "vbnet"]
|
||||
prev_game = split_dir[1]
|
||||
|
||||
elif len(split_dir) == 3 and split_dir[1] != '.git':
|
||||
if split_dir[2] in lang_pos.keys():
|
||||
if len(fileList) > 1 or len(subdirList) > 0:
|
||||
# there is more files than the readme
|
||||
checklist[lang_pos[split_dir[2]]] = "✅"
|
||||
else:
|
||||
checklist[lang_pos[split_dir[2]]] = "⬜️"
|
||||
|
||||
|
||||
sorted_strings = list(map(lambda l: " | ".join(l) + "\n",
|
||||
sorted(strings_done, key=lambda x: x[0])))
|
||||
write_string += ''.join(sorted_strings)
|
||||
|
||||
|
||||
with open("README.md", "w") as f:
|
||||
f.write(write_string)
|
||||
@@ -17,3 +17,4 @@ http://www.vintage-basic.net/games.html
|
||||
|
||||
#### External Links
|
||||
- Common Lisp: https://github.com/koalahedron/lisp-computer-games/blob/master/01%20Acey%20Ducey/common-lisp/acey-deucy.lisp
|
||||
- PowerShell: https://github.com/eweilnau/basic-computer-games-powershell/blob/main/AceyDucey.ps1
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Oracle Java](https://openjdk.java.net/)
|
||||
|
||||
Two versions of Acey Ducey have been contributed.
|
||||
|
||||
The original upload supported JDK 8/JDK 11 and uses multiple files and the second uses features in JDK 17 and is implemented in a single file AceyDucey17.java.
|
||||
|
||||
Both are in the src folder.
|
||||
|
||||
201
01_Acey_Ducey/java/src/AceyDucey17.java
Normal file
201
01_Acey_Ducey/java/src/AceyDucey17.java
Normal file
@@ -0,0 +1,201 @@
|
||||
import java.util.Random;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* A modern version (JDK17) of ACEY DUCEY using post Java 8 features. Notes
|
||||
* regarding new java features or differences in the original basic
|
||||
* implementation are numbered and at the bottom of this code.
|
||||
* The goal is to recreate the exact look and feel of the original program
|
||||
* minus a large glaring bug in the original code that lets you cheat.
|
||||
*/
|
||||
public class AceyDucey17 {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// notes [1]
|
||||
System.out.println("""
|
||||
ACEY DUCEY CARD GAME
|
||||
CREATIVE COMPUTING MORRISTOWN, NEW JERSEY
|
||||
|
||||
|
||||
ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER
|
||||
THE DEALER (COMPUTER) DEALS TWO CARDS FACE 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""");
|
||||
|
||||
do {
|
||||
playGame();
|
||||
} while (stillInterested());
|
||||
System.out.println("O.K., HOPE YOU HAD FUN!");
|
||||
}
|
||||
|
||||
public static void playGame() {
|
||||
int cashOnHand = 100; // our only mutable variable note [11]
|
||||
System.out.println("YOU NOW HAVE "+ cashOnHand +" DOLLARS.");// note [6]
|
||||
while (cashOnHand > 0) {
|
||||
System.out.println();
|
||||
System.out.println("HERE ARE YOUR NEXT TWO CARDS:");
|
||||
|
||||
final Card lowCard = Card.getRandomCard(2, Card.KING); //note [3]
|
||||
System.out.println(lowCard);
|
||||
final Card highCard = Card.getRandomCard(lowCard.rank() + 1, Card.ACE);
|
||||
System.out.println(highCard);
|
||||
|
||||
final int bet = getBet(cashOnHand);
|
||||
final int winnings = determineWinnings(lowCard,highCard,bet);
|
||||
cashOnHand += winnings;
|
||||
if(winnings != 0 || cashOnHand != 0){ //note [2]
|
||||
System.out.println("YOU NOW HAVE "+ cashOnHand +" DOLLARS.");//note [6]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int determineWinnings(Card lowCard, Card highCard, int bet){
|
||||
if (bet <= 0) { // note [5]
|
||||
System.out.println("CHICKEN!!");
|
||||
return 0;
|
||||
}
|
||||
Card nextCard = Card.getRandomCard(2, Card.ACE);
|
||||
System.out.println(nextCard);
|
||||
if(nextCard.between(lowCard,highCard)){
|
||||
System.out.println("YOU WIN!!!");
|
||||
return bet;
|
||||
}
|
||||
System.out.println("SORRY, YOU LOSE");
|
||||
return -bet;
|
||||
}
|
||||
|
||||
public static boolean stillInterested(){
|
||||
System.out.println();
|
||||
System.out.println();
|
||||
System.out.println("SORRY, FRIEND, BUT YOU BLEW YOUR WAD.");
|
||||
System.out.println();
|
||||
System.out.println();
|
||||
System.out.print("TRY AGAIN (YES OR NO)? ");
|
||||
Scanner input = new Scanner(System.in);
|
||||
boolean playAgain = input.nextLine()
|
||||
.toUpperCase()
|
||||
.startsWith("Y"); // note [9]
|
||||
System.out.println();
|
||||
System.out.println();
|
||||
return playAgain;
|
||||
}
|
||||
|
||||
public static int getBet(int cashOnHand){
|
||||
int bet;
|
||||
do{
|
||||
System.out.println();
|
||||
System.out.print("WHAT IS YOUR BET? ");
|
||||
bet = inputNumber();
|
||||
if (bet > cashOnHand) {
|
||||
System.out.println("SORRY, MY FRIEND, BUT YOU BET TOO MUCH.");
|
||||
System.out.println("YOU HAVE ONLY "+cashOnHand+" DOLLARS TO BET.");
|
||||
}
|
||||
}while(bet > cashOnHand);
|
||||
return bet;
|
||||
}
|
||||
|
||||
public static int inputNumber() {
|
||||
final Scanner input = new Scanner(System.in);
|
||||
// set to negative to mark as not entered yet in case of input error.
|
||||
int number = -1;
|
||||
while (number < 0) {
|
||||
try {
|
||||
number = input.nextInt();
|
||||
} catch(Exception ex) { // note [7]
|
||||
System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE");
|
||||
System.out.print("? ");
|
||||
try{
|
||||
input.nextLine();
|
||||
}
|
||||
catch(Exception ns_ex){ // received EOF (ctrl-d or ctrl-z if windows)
|
||||
System.out.println("END OF INPUT, STOPPING PROGRAM.");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
record Card(int rank){
|
||||
// Some constants to describe face cards.
|
||||
public static final int JACK = 11, QUEEN = 12, KING = 13, ACE = 14;
|
||||
private static final Random random = new Random();
|
||||
|
||||
public static Card getRandomCard(int from, int to){
|
||||
return new Card(random.nextInt(from, to+1)); // note [4]
|
||||
}
|
||||
|
||||
public boolean between(Card lower, Card higher){
|
||||
return lower.rank() < this.rank() && this.rank() < higher.rank();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() { // note [13]
|
||||
return switch (rank) {
|
||||
case JACK -> "JACK";
|
||||
case QUEEN -> "QUEEN";
|
||||
case KING -> "KING";
|
||||
case ACE -> "ACE\n"; // note [10]
|
||||
default -> " "+rank+" "; // note [6]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Notes:
|
||||
1. Multiline strings, a.k.a. text blocks, were added in JDK15.
|
||||
2. The original game only displays the players balance if it changed,
|
||||
which it does not when the player chickens out and bets zero.
|
||||
It also doesn't display the balance when it becomes zero because it has
|
||||
a more appropriate message: Sorry, You Lose.
|
||||
3. To pick two cards to show, the original BASIC implementation has a
|
||||
bug that could cause a race condition if the RND function never chose
|
||||
a lower number first and higher number second. It loops infinitely
|
||||
re-choosing random numbers until the condition is met of the first
|
||||
one being lower. The logic is changed a bit here so that the first
|
||||
card picked is anything but an ACE, the highest possible card,
|
||||
and then the second card is between the just picked first card upto
|
||||
and including the ACE.
|
||||
4. Random.nextInt(origin, bound) was added in JDK17, and allows to
|
||||
directly pick a range for a random integer to be generated. The second
|
||||
parameter is exclusive of the range and thus why they are stated with
|
||||
+1's to the face card.
|
||||
5. The original BASIC implementation has a bug that allows negative value
|
||||
bets. Since you can't bet MORE cash than you have you can always bet
|
||||
less including a very, very large negative value. You would do this when
|
||||
the chances of winning are slim or zero since losing a hand SUBTRACTS
|
||||
your bet from your cash; subtracting a negative number actually ADDS
|
||||
to your cash, potentially making you an instant billionaire.
|
||||
This loophole is now closed.
|
||||
6. The subtle behavior of the BASIC PRINT command causes a space to be
|
||||
printed before all positive numbers as well as a trailing space. Any
|
||||
place a non-face card or the players balance is printed has extra space
|
||||
to mimic this behavior.
|
||||
7. Errors on input were probably specific to the interpreter. This program
|
||||
tries to match the Vintage Basic interpreter's error messages. The final
|
||||
input.nextLine() command exists to clear the blockage of whatever
|
||||
non-number input was entered. But even that could fail if the user
|
||||
types Ctrl-D (windows Ctrl-Z), signifying an EOF (end of file) and thus
|
||||
the closing of STDIN channel. The original program on an EOF signal prints
|
||||
"END OF INPUT IN LINE 660" and thus we cover it roughly the same way.
|
||||
All of this is necessary to avoid a messy stack trace from being
|
||||
printed as the program crashes.
|
||||
9. The original game only accepted a full upper case "YES" to continue
|
||||
playing if bankrupted. This program is more lenient and will accept
|
||||
any input that starts with the letter 'y', uppercase or not.
|
||||
10. The original game prints an extra blank line if the card is an ACE. There
|
||||
is seemingly no rationale for this.
|
||||
11. Modern java best practices are edging toward a more functional paradigm
|
||||
and as such, mutating state is discouraged. All other variables besides
|
||||
the cashOnHand are final and initialized only once.
|
||||
12. Refactoring of the concept of a card is done with a record. Records were
|
||||
introduced in JDK14. Card functionality is encapsulated in this example
|
||||
of a record. An enum could be a better alternative since there are
|
||||
technically only 13 cards possible.
|
||||
13. Switch expressions were introduced as far back as JDK12 but continue to
|
||||
be refined for clarity, exhaustiveness. As of JDK17 pattern matching
|
||||
for switch expressions can be accessed by enabling preview features.
|
||||
*/
|
||||
}
|
||||
@@ -90,19 +90,23 @@ async function main() {
|
||||
print('\nWHAT IS YOUR BET? ');
|
||||
bet = parseInt(await input(), 10);
|
||||
let minimumRequiredBet = 0;
|
||||
if (bet > minimumRequiredBet) {
|
||||
if (bet >= minimumRequiredBet) {
|
||||
if (bet > availableDollars) {
|
||||
print('SORRY, MY FRIEND, BUT YOU BET TOO MUCH.');
|
||||
print(`YOU HAVE ONLY ${availableDollars} DOLLARS TO BET.`);
|
||||
} else {
|
||||
validBet = true;
|
||||
}
|
||||
} else {
|
||||
// Does not meet minimum required bet
|
||||
print('CHICKEN!!');
|
||||
print('');
|
||||
}
|
||||
}
|
||||
if (bet == 0)
|
||||
{
|
||||
// User chose not to bet.
|
||||
print('CHICKEN!!');
|
||||
print('');
|
||||
// Don't draw a third card, draw a new set of 2 cards.
|
||||
continue;
|
||||
}
|
||||
|
||||
print('\n\nHERE IS THE CARD WE DREW: ');
|
||||
print(getCardValue(cardThree));
|
||||
@@ -127,7 +131,7 @@ async function main() {
|
||||
print('');
|
||||
print('');
|
||||
|
||||
if (isValidYesNoString(tryAgainInput)) {
|
||||
if (isValidYesString(tryAgainInput)) {
|
||||
availableDollars = 100;
|
||||
} else {
|
||||
print('O.K., HOPE YOU HAD FUN!');
|
||||
|
||||
@@ -36,7 +36,7 @@ class Deck:
|
||||
|
||||
def build(self):
|
||||
for suit in ['\u2665', '\u2666', '\u2663', '\u2660']:
|
||||
for rank in range(1, 14):
|
||||
for rank in range(2, 15):
|
||||
self.cards.append(Card(suit, rank))
|
||||
|
||||
def shuffle(self):
|
||||
|
||||
295
02_Amazing/vbnet/program.vb
Normal file
295
02_Amazing/vbnet/program.vb
Normal file
@@ -0,0 +1,295 @@
|
||||
Imports System
|
||||
|
||||
Module Program
|
||||
|
||||
Enum Directions
|
||||
SolveAndReset = 0
|
||||
Left = 1
|
||||
Up = 2
|
||||
Right = 3
|
||||
Down = 4
|
||||
End Enum
|
||||
|
||||
'Program State
|
||||
Dim Width As Integer = 0, Height As Integer = 0, Q As Integer = 0, CellsVisited As Integer = 2, curCol As Integer, curRow As Integer = 1
|
||||
Dim SolutionCompleted As Boolean = False
|
||||
Dim CellVisitHistory(,) As Integer
|
||||
Dim CellState(,) As Integer
|
||||
|
||||
Dim rnd As New Random()
|
||||
|
||||
Public ReadOnly Property BlockedLeft As Boolean
|
||||
Get
|
||||
Return curCol - 1 = 0 OrElse CellVisitHistory(curCol - 1, curRow) <> 0
|
||||
End Get
|
||||
End Property
|
||||
Public ReadOnly Property BlockedAbove As Boolean
|
||||
Get
|
||||
Return curRow - 1 = 0 OrElse CellVisitHistory(curCol, curRow - 1) <> 0
|
||||
End Get
|
||||
End Property
|
||||
Public ReadOnly Property BlockedRight As Boolean
|
||||
Get
|
||||
Return curCol = Width OrElse CellVisitHistory(curCol + 1, curRow) <> 0
|
||||
End Get
|
||||
End Property
|
||||
'Note: "BlockedBelow" does NOT include checking if we have a solution!
|
||||
Public ReadOnly Property BlockedBelow As Boolean
|
||||
Get
|
||||
Return curRow = Height OrElse CellVisitHistory(curCol, curRow + 1) <> 0
|
||||
End Get
|
||||
End Property
|
||||
Public ReadOnly Property OnBottomRow As Boolean
|
||||
Get
|
||||
Return curRow.Equals(Height)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
Sub Main(args As String())
|
||||
Const header As String =
|
||||
" AMAZING PROGRAM
|
||||
CREATIVE COMPUTING MORRISTOWN, NEW JERSEY
|
||||
|
||||
|
||||
|
||||
"
|
||||
Console.WriteLine(header)
|
||||
|
||||
While Width <= 1 OrElse Height <= 1
|
||||
Console.Write("WHAT ARE YOUR WIDTH AND LENGTH? ")
|
||||
|
||||
'We no longer have the old convenient INPUT command, so need to parse out the inputs
|
||||
Dim parts = Console.ReadLine().Split(","c).Select(Function(s) Convert.ToInt32(s.Trim())).ToList()
|
||||
Width = parts(0)
|
||||
Height = parts(1)
|
||||
|
||||
If Width <= 1 OrElse Height <= 1 Then Console.WriteLine($"MEANINGLESS DIMENSIONS. TRY AGAIN.{vbCrLf}")
|
||||
End While
|
||||
|
||||
ReDim CellVisitHistory(Width, Height), CellState(Width, Height)
|
||||
|
||||
Console.WriteLine("
|
||||
|
||||
")
|
||||
|
||||
curCol = rnd.Next(1, Width + 1) 'Starting X position
|
||||
CellVisitHistory(curCol, 1) = 1
|
||||
Dim startXPos As Integer = curCol 'we need to know this at the end to print opening line
|
||||
|
||||
Dim keepGoing As Boolean = True
|
||||
While keepGoing
|
||||
If BlockedLeft Then
|
||||
keepGoing = ChoosePath_BlockedToTheLeft()
|
||||
ElseIf BlockedAbove Then
|
||||
keepGoing = ChoosePath_BlockedAbove()
|
||||
ElseIf BlockedRight Then
|
||||
keepGoing = ChoosePath_BlockedToTheRight()
|
||||
Else
|
||||
keepGoing = SelectRandomDirection(Directions.Left, Directions.Up, Directions.Right) 'Go anywhere but down
|
||||
End If
|
||||
End While
|
||||
|
||||
PrintFinalResults(startXPos)
|
||||
End Sub
|
||||
|
||||
Public Sub ResetCurrentPosition()
|
||||
Do
|
||||
If curCol <> Width Then 'not at the right edge
|
||||
curCol += 1
|
||||
ElseIf curRow <> Height Then 'not at the bottom
|
||||
curCol = 1
|
||||
curRow += 1
|
||||
Else
|
||||
curCol = 1
|
||||
curRow = 1
|
||||
End If
|
||||
Loop While CellVisitHistory(curCol, curRow) = 0
|
||||
End Sub
|
||||
|
||||
Dim methods() As Func(Of Boolean) = {AddressOf MarkSolvedAndResetPosition, AddressOf GoLeft, AddressOf GoUp, AddressOf GoRight, AddressOf GoDown}
|
||||
Public Function SelectRandomDirection(ParamArray possibles() As Directions) As Boolean
|
||||
Dim x As Integer = rnd.Next(0, possibles.Length)
|
||||
Return methods(possibles(x))()
|
||||
End Function
|
||||
|
||||
Public Function ChoosePath_BlockedToTheLeft() As Boolean
|
||||
If BlockedAbove Then
|
||||
If BlockedRight Then
|
||||
If curRow <> Height Then
|
||||
If CellVisitHistory(curCol, curRow + 1) <> 0 Then ' Can't go down, but not at the edge...blocked. Reset and try again
|
||||
ResetCurrentPosition()
|
||||
Return True
|
||||
Else
|
||||
Return GoDown()
|
||||
End If
|
||||
ElseIf SolutionCompleted Then 'Can't go Down (there's already another solution)
|
||||
ResetCurrentPosition()
|
||||
Return True
|
||||
Else 'Can't go LEFT, UP, RIGHT, or DOWN, but we're on the bottom and there's no solution yet
|
||||
Return MarkSolvedAndResetPosition()
|
||||
End If
|
||||
ElseIf BlockedBelow Then
|
||||
Return GoRight()
|
||||
ElseIf Not OnBottomRow Then
|
||||
Return SelectRandomDirection(Directions.Right, Directions.Down)
|
||||
ElseIf SolutionCompleted Then 'Can only go right, and we're at the bottom
|
||||
Return GoRight()
|
||||
Else 'Can only go right, we're at the bottom, and there's not a solution yet
|
||||
Return SelectRandomDirection(Directions.Right, Directions.SolveAndReset)
|
||||
End If
|
||||
'== Definitely can go Up ==
|
||||
ElseIf BlockedRight Then
|
||||
If BlockedBelow Then
|
||||
Return GoUp()
|
||||
ElseIf Not OnBottomRow Then
|
||||
Return SelectRandomDirection(Directions.Up, Directions.Down)
|
||||
ElseIf SolutionCompleted Then 'We're on the bottom row, can only go up
|
||||
Return GoUp()
|
||||
Else 'We're on the bottom row, can only go up, but there's no solution
|
||||
Return SelectRandomDirection(Directions.Up, Directions.SolveAndReset)
|
||||
End If
|
||||
'== Definitely can go Up and Right ==
|
||||
ElseIf BlockedBelow Then
|
||||
Return SelectRandomDirection(Directions.Up, Directions.Right)
|
||||
ElseIf Not OnBottomRow Then
|
||||
Return SelectRandomDirection(Directions.Up, Directions.Right, Directions.Down)
|
||||
ElseIf SolutionCompleted Then 'at the bottom, but already have a solution
|
||||
Return SelectRandomDirection(Directions.Up, Directions.Right)
|
||||
Else
|
||||
Return SelectRandomDirection(Directions.Up, Directions.Right, Directions.SolveAndReset)
|
||||
End If
|
||||
End Function
|
||||
|
||||
Public Function ChoosePath_BlockedAbove() As Boolean
|
||||
'No need to check the left side, only called from the "keepGoing" loop where LEFT is already cleared
|
||||
If BlockedRight Then
|
||||
If BlockedBelow Then
|
||||
Return GoLeft()
|
||||
ElseIf Not OnBottomRow Then
|
||||
Return SelectRandomDirection(Directions.Left, Directions.Down)
|
||||
ElseIf SolutionCompleted Then 'Can't go down because there's already a solution
|
||||
Return GoLeft()
|
||||
Else 'At the bottom, no solution yet...
|
||||
Return SelectRandomDirection(Directions.Left, Directions.SolveAndReset)
|
||||
End If
|
||||
ElseIf BlockedBelow Then
|
||||
Return SelectRandomDirection(Directions.Left, Directions.Right)
|
||||
ElseIf Not OnBottomRow Then
|
||||
Return SelectRandomDirection(Directions.Left, Directions.Right, Directions.Down)
|
||||
ElseIf SolutionCompleted Then
|
||||
Return SelectRandomDirection(Directions.Left, Directions.Right)
|
||||
Else
|
||||
Return SelectRandomDirection(Directions.Left, Directions.Right, Directions.SolveAndReset)
|
||||
End If
|
||||
End Function
|
||||
|
||||
Public Function ChoosePath_BlockedToTheRight() As Boolean
|
||||
'No need to check Left or Up, only called from the "keepGoing" loop where LEFT and UP are already cleared
|
||||
If BlockedRight Then 'Can't go Right -- why? we knew this when calling the function
|
||||
If BlockedBelow Then
|
||||
Return SelectRandomDirection(Directions.Left, Directions.Up)
|
||||
ElseIf Not OnBottomRow Then
|
||||
Return SelectRandomDirection(Directions.Left, Directions.Up, Directions.Down)
|
||||
ElseIf SolutionCompleted Then
|
||||
Return SelectRandomDirection(Directions.Left, Directions.Up)
|
||||
Else
|
||||
Return SelectRandomDirection(Directions.Left, Directions.Up, Directions.SolveAndReset)
|
||||
End If
|
||||
Else 'Should never get here
|
||||
Return SelectRandomDirection(Directions.Left, Directions.Up, Directions.Right) 'Go Left, Up, or Right (but path is blocked?)
|
||||
End If
|
||||
End Function
|
||||
|
||||
Public Sub PrintFinalResults(startPos As Integer)
|
||||
For i As Integer = 0 To Width - 1
|
||||
If i = startPos Then Console.Write(". ") Else Console.Write(".--")
|
||||
Next
|
||||
Console.WriteLine(".")
|
||||
|
||||
If Not SolutionCompleted Then 'Pick a random exit
|
||||
Dim X As Integer = rnd.Next(1, Width + 1)
|
||||
If CellState(X, Height) = 0 Then
|
||||
CellState(X, Height) = 1
|
||||
Else
|
||||
CellState(X, Height) = 3
|
||||
End If
|
||||
End If
|
||||
|
||||
For j As Integer = 1 To Height
|
||||
Console.Write("I")
|
||||
For i As Integer = 1 To Width
|
||||
If CellState(i, j) < 2 Then
|
||||
Console.Write(" I")
|
||||
Else
|
||||
Console.Write(" ")
|
||||
End If
|
||||
Next
|
||||
Console.WriteLine()
|
||||
|
||||
For i As Integer = 1 To Width
|
||||
If CellState(i, j) = 0 OrElse CellState(i, j) = 2 Then
|
||||
Console.Write(":--")
|
||||
Else
|
||||
Console.Write(": ")
|
||||
End If
|
||||
Next
|
||||
Console.WriteLine(".")
|
||||
Next
|
||||
End Sub
|
||||
|
||||
Public Function GoLeft() As Boolean
|
||||
curCol -= 1
|
||||
CellVisitHistory(curCol, curRow) = CellsVisited
|
||||
CellsVisited += 1
|
||||
CellState(curCol, curRow) = 2
|
||||
If CellsVisited > Width * Height Then Return False
|
||||
Q = 0
|
||||
Return True
|
||||
End Function
|
||||
|
||||
Public Function GoUp() As Boolean
|
||||
curRow -= 1
|
||||
CellVisitHistory(curCol, curRow) = CellsVisited
|
||||
CellsVisited += 1
|
||||
CellState(curCol, curRow) = 1
|
||||
If CellsVisited > Width * Height Then Return False
|
||||
Q = 0
|
||||
Return True
|
||||
End Function
|
||||
|
||||
Public Function GoRight() As Boolean
|
||||
CellVisitHistory(curCol + 1, curRow) = CellsVisited
|
||||
CellsVisited += 1
|
||||
If CellState(curCol, curRow) = 0 Then CellState(curCol, curRow) = 2 Else CellState(curCol, curRow) = 3
|
||||
curCol += 1
|
||||
If CellsVisited > Width * Height Then Return False
|
||||
Return ChoosePath_BlockedToTheLeft()
|
||||
End Function
|
||||
|
||||
Public Function GoDown() As Boolean
|
||||
If Q = 1 Then Return MarkSolvedAndResetPosition()
|
||||
|
||||
CellVisitHistory(curCol, curRow + 1) = CellsVisited
|
||||
CellsVisited += 1
|
||||
If CellState(curCol, curRow) = 0 Then CellState(curCol, curRow) = 1 Else CellState(curCol, curRow) = 3
|
||||
curRow += 1
|
||||
If CellsVisited > Width * Height Then Return False
|
||||
Return True
|
||||
End Function
|
||||
|
||||
Public Function MarkSolvedAndResetPosition() As Boolean
|
||||
' AlWAYS returns true
|
||||
SolutionCompleted = True
|
||||
Q = 1
|
||||
If CellState(curCol, curRow) = 0 Then
|
||||
CellState(curCol, curRow) = 1
|
||||
curCol = 1
|
||||
curRow = 1
|
||||
If CellVisitHistory(curCol, curRow) = 0 Then ResetCurrentPosition()
|
||||
Else
|
||||
CellState(curCol, curRow) = 3
|
||||
ResetCurrentPosition()
|
||||
End If
|
||||
Return True
|
||||
End Function
|
||||
End Module
|
||||
@@ -37,14 +37,14 @@ fun main() {
|
||||
// an answer or a blank string
|
||||
fun ask(question: String): String {
|
||||
print("$question? ")
|
||||
return readLine()?.uppercase() ?: ""
|
||||
return readln().uppercase() ?: ""
|
||||
}
|
||||
|
||||
// Special case for a "yes or no" question, returns true of yes
|
||||
fun askYesOrNo(question: String): Boolean {
|
||||
return generateSequence {
|
||||
print("$question? ")
|
||||
readLine()
|
||||
readln()
|
||||
}.firstNotNullOf { yesOrNo(it) }
|
||||
}
|
||||
|
||||
|
||||
268
04_Awari/perl/awari.pl
Normal file
268
04_Awari/perl/awari.pl
Normal file
@@ -0,0 +1,268 @@
|
||||
#!/usr/bin/env perl
|
||||
use v5.24;
|
||||
use warnings;
|
||||
use experimental 'signatures';
|
||||
no warnings 'experimental::signatures';
|
||||
use List::Util 'none';
|
||||
|
||||
# our board will be represented with an array of 14 slots, from 0 to 13.
|
||||
# Positions 6 and 13 represent the "home pit" for the human and the
|
||||
# computer, respectively.
|
||||
use constant PLAYER_HOME => 6;
|
||||
use constant COMPUTER_HOME => 13;
|
||||
|
||||
use constant FIRST => 0;
|
||||
use constant AGAIN => 1;
|
||||
|
||||
exit main(@ARGV);
|
||||
|
||||
sub main {
|
||||
$|++; # disable buffering on standard output, every print will be
|
||||
# done immediately
|
||||
|
||||
welcome(); # startup message
|
||||
|
||||
# this array will keep track of computer-side failures, defined as
|
||||
# "the computer did not win". Whenever the computer loses or draws, the
|
||||
# specific sequence of moves will be saved and then used to drive
|
||||
# the search for a (hopefully) optimal move.
|
||||
my $failures = [];
|
||||
while ('enjoying') {
|
||||
|
||||
# a new game starts, let's reset the board to the initial condition
|
||||
my $board = [ (3) x 6, 0, (3) x 6, 0 ];
|
||||
|
||||
# this string will keep track of all moves performed
|
||||
my $moves = '/';
|
||||
|
||||
# the human player starts
|
||||
my $turn = 'player';
|
||||
|
||||
say "\n";
|
||||
print_board($board);
|
||||
|
||||
while (not is_game_over($board)) {
|
||||
|
||||
my $move; # this will collect the move in this turn
|
||||
|
||||
if ($turn eq 'player') { # "first" move for player
|
||||
|
||||
# player_move(...) does the move selected by the player,
|
||||
# returning both the selected move as well as the pit id
|
||||
# where the last seed landed
|
||||
($move, my $landing) = player_move($board);
|
||||
|
||||
# if we landed on the Player's Home Pit we get another move
|
||||
$turn = $landing == PLAYER_HOME ? 'player-again' : 'computer';
|
||||
}
|
||||
elsif ($turn eq 'player-again') { # "second" move for player
|
||||
|
||||
# here we call player_move making it clear that it's the
|
||||
# second move, to get the right prompt eventually. We only
|
||||
# care for the $move as the result, so we ignore the other.
|
||||
($move) = player_move($board, AGAIN);
|
||||
$turn = 'computer';
|
||||
}
|
||||
else {
|
||||
|
||||
# the computer_move(...) function analyzes the $board as well
|
||||
# as adapting the strategy based on past "failures" (i.e.
|
||||
# matches where the computer did not win). For this it's
|
||||
# important to pass the log of these failures, as well as the
|
||||
# full record of moves in this specific match.
|
||||
($move, my $landing) = computer_move($board, $failures, $moves);
|
||||
print "\nMY MOVE IS ", $move - 6;
|
||||
|
||||
# do the second move in the turn if conditions apply
|
||||
if ($landing == COMPUTER_HOME && ! is_game_over($board)) {
|
||||
|
||||
# save the first move before doing the second one!
|
||||
$moves .= "$move/";
|
||||
|
||||
my ($move) = computer_move($board, $failures, $moves);
|
||||
print ',', $move - 6;
|
||||
}
|
||||
$turn = 'player';
|
||||
}
|
||||
|
||||
# append the last selected move by either party, to track this
|
||||
# specific match (useful for computer's AI and ML)
|
||||
$moves .= "$move/";
|
||||
print_board($board);
|
||||
}
|
||||
|
||||
# assess_victory() returns the difference between player's and
|
||||
# computer's seeds, so a negative value is a win for the computer.
|
||||
my $computer_won = assess_victory($board) < 0;
|
||||
|
||||
# if this last match was a "failure" (read: not a win for the
|
||||
# computer), then record it for future memory.
|
||||
push $failures->@*, $moves unless $computer_won;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
# calculate the difference between the two home pits. Negative values mean
|
||||
# that the computer won, 0 is a draw, positive values is a player's win.
|
||||
# The difference is also returned back, in case of need.
|
||||
sub assess_victory ($board) {
|
||||
say "\nGAME OVER";
|
||||
my $difference = $board->[PLAYER_HOME] - $board->[COMPUTER_HOME];
|
||||
if ($difference < 0) {
|
||||
say 'I WIN BY ', -$difference, ' POINTS';
|
||||
}
|
||||
else {
|
||||
say $difference ? "YOU WIN BY $difference POINTS" : 'DRAWN GAME';
|
||||
}
|
||||
return $difference;
|
||||
}
|
||||
|
||||
# move the seeds from $pit and take into account possible bonuses
|
||||
sub move_seeds ($board, $pit) {
|
||||
|
||||
# get the seeds from the selected pit $pit
|
||||
my $seeds = $board->[$pit];
|
||||
$board->[$pit] = 0;
|
||||
|
||||
# $landing will be our "moving cursor" to place seeds around
|
||||
my $landing = $pit;
|
||||
while ($seeds > 0) {
|
||||
$landing = ($landing + 1) % 14; # 12 --> 13 -[wrap]-> 0 --> 1
|
||||
--$seeds;
|
||||
++$board->[$landing];
|
||||
}
|
||||
|
||||
# check for "stealing seeds" condition. This cannot happen in home pits
|
||||
if ($landing != PLAYER_HOME && $landing != COMPUTER_HOME
|
||||
&& $board->[$landing] == 1 && $board->[12 - $landing] > 0) {
|
||||
my $home = $pit < 7 ? PLAYER_HOME : COMPUTER_HOME;
|
||||
$board->[$home] += 1 + $board->[12 - $landing];
|
||||
$board->@[$landing, 12 - $landing] = (0, 0);
|
||||
}
|
||||
|
||||
return ($pit, $landing);
|
||||
}
|
||||
|
||||
sub get_player_move ($board, $prompt) {
|
||||
print "\n$prompt? ";
|
||||
while (defined(my $move = <STDIN>)) {
|
||||
chomp($move); # remove newline
|
||||
return $move - 1 if $move =~ m{\A[1-6]\z}mxs && $board->[$move - 1];
|
||||
print 'ILLEGAL MOVE\nAGAIN? ';
|
||||
}
|
||||
die "goodbye\n";
|
||||
}
|
||||
|
||||
sub player_move ($board, $stage = FIRST) {
|
||||
my $prompt = $stage == FIRST ? 'YOUR MOVE' : 'AGAIN';
|
||||
my $selected_move = get_player_move($board, $prompt);
|
||||
return move_seeds($board, $selected_move);
|
||||
}
|
||||
|
||||
sub computer_move ($board, $failures, $moves) {
|
||||
|
||||
# we will go through all possible moves for the computer and all
|
||||
# possible responses by the player, collecting the "best" move in terms
|
||||
# of reasonable outcome (assuming that each side wants to maximize their
|
||||
# outcome. $best_move will eventually contain the best move for the
|
||||
# computer, and $best_difference the best difference in scoring (as
|
||||
# seen from the computer).
|
||||
my ($best_move, $best_difference);
|
||||
for my $c_move (7 .. 12) {
|
||||
next unless $board->[$c_move]; # only consider pits with seeds inside
|
||||
|
||||
# we work on a copy of the board to do all our trial-and-errors
|
||||
my $copy = [ $board->@* ];
|
||||
move_seeds($copy, $c_move);
|
||||
|
||||
# it's time to "think like a player" and see what's the "best" move
|
||||
# for the player in this situation. This heuristic is "not perfect"
|
||||
# but it seems OK anyway.
|
||||
my $best_player_score = 0;
|
||||
for my $p_move (0 .. 5) {
|
||||
next unless $copy->[$p_move]; # only pits with seeds inside
|
||||
my $landing = $copy->[$p_move] + $p_move;
|
||||
|
||||
# the player's score for this move, calculated as additional seeds
|
||||
# placed in the player's pit. The original algorithm sets this to
|
||||
# 1 only if the $landing position is greater than 13, which can
|
||||
# be obtained by setting the ORIGINAL environment variable to a
|
||||
# "true" value (in Perl terms). Otherwise it is calculated
|
||||
# according to the real rules for the game.
|
||||
my $p_score = $ENV{ORIGINAL} ? $landing > 13
|
||||
: ($landing + 1) % 14 > 6;
|
||||
|
||||
# whatever, the landing position must be within the bounds
|
||||
$landing %= 14;
|
||||
|
||||
# if the conditions apply, the player's move might win additional
|
||||
# seeds, which we have to to take into account.
|
||||
$p_score += $copy->[12 - $landing]
|
||||
if $copy->[$landing] == 0
|
||||
&& $landing != PLAYER_HOME && $landing != COMPUTER_HOME;
|
||||
|
||||
# let's compare this move's score against the best collected
|
||||
# so far (as a response to a specific computer's move).
|
||||
$best_player_score = $p_score if $p_score > $best_player_score;
|
||||
}
|
||||
|
||||
# the overall score for the player is the additional seeds we just
|
||||
# calculated into $best_player_score plus the seeds that were already
|
||||
# in the player's pit
|
||||
$best_player_score += $copy->[PLAYER_HOME];
|
||||
|
||||
# the best difference we can aim for with this computer's move must
|
||||
# assume that the player will try its best
|
||||
my $difference = $copy->[COMPUTER_HOME] - $best_player_score;
|
||||
|
||||
# now it's time to check this computer's move against the history
|
||||
# of failed matches. $candidate_moves will be the "candidate" list
|
||||
# of moves if we accept this one.
|
||||
my $candidate_moves = $moves . $c_move . '/';
|
||||
for my $failure ($failures->@*) {
|
||||
|
||||
# index(.) returns 0 if and only if $candidate_moves appears at
|
||||
# the very beginning of $failure, i.e. it matches a previous
|
||||
# behaviour.
|
||||
next if index($failure, $candidate_moves) != 0;
|
||||
|
||||
# same sequence of moves as before... assign a penalty
|
||||
$difference -= 2;
|
||||
}
|
||||
|
||||
# update $best_move and $best_difference if they need to
|
||||
($best_move, $best_difference) = ($c_move, $difference)
|
||||
if (! defined $best_move) || ($best_difference < $difference);
|
||||
}
|
||||
|
||||
# apply the selected move and return
|
||||
return move_seeds($board, $best_move);
|
||||
}
|
||||
|
||||
sub welcome {
|
||||
say ' ' x 34, 'AWARI';
|
||||
say ' ' x 15, 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY';
|
||||
}
|
||||
|
||||
sub print_board ($board) {
|
||||
my $template = '
|
||||
%2d %2d %2d %2d %2d %2d
|
||||
%2d %d
|
||||
%2d %2d %2d %2d %2d %2d
|
||||
';
|
||||
printf $template, $board->@[12, 11, 10, 9, 8 , 7, 13, 6, 0 .. 5];
|
||||
return;
|
||||
}
|
||||
|
||||
sub is_game_over ($board) {
|
||||
|
||||
# game over if the player's side is empty
|
||||
return 1 if none { $_ } $board->@[0 .. 5];
|
||||
|
||||
# game over if the computers' side is empty
|
||||
return 1 if none { $_ } $board->@[7 .. 12];
|
||||
|
||||
# not game over
|
||||
return 0;
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Ruby](https://www.ruby-lang.org/en/)
|
||||
Conversion to [Ruby](https://www.ruby-lang.org/en/) by [Alex Scown](https://github.com/TheScown)
|
||||
|
||||
311
04_Awari/ruby/awari.rb
Normal file
311
04_Awari/ruby/awari.rb
Normal file
@@ -0,0 +1,311 @@
|
||||
require 'strscan'
|
||||
|
||||
# Prints a number according to Vintage Basic's PRINT statement
|
||||
# @param n The number to print
|
||||
def print_number(n)
|
||||
# PRINT adds padding after a number and before a positive number
|
||||
print ' ' if n >= 0
|
||||
print n.to_s
|
||||
print ' '
|
||||
end
|
||||
|
||||
# Mimic the INPUT statement using Vintage Basic as a reference
|
||||
# @param prompt The prompt to show to the user
|
||||
# @return An array of strings representing the inputted values
|
||||
def input(prompt)
|
||||
prompt_suffix = '? '
|
||||
print "#{prompt}#{prompt_suffix}"
|
||||
|
||||
input = gets.chomp.strip
|
||||
scanner = StringScanner.new(input)
|
||||
input_values = []
|
||||
|
||||
until scanner.eos?
|
||||
scanner.scan(/\s+/)
|
||||
|
||||
if scanner.check(/"/)
|
||||
scanner.scan(/"/)
|
||||
next_string = scanner.scan_until(/"/)
|
||||
|
||||
if next_string
|
||||
# Remove the trailing close quote
|
||||
next_string.chomp!('"')
|
||||
else
|
||||
# No close quote – Vintage Basic crashes in this case
|
||||
raise 'Unmatched quotes in input'
|
||||
end
|
||||
elsif scanner.exist?(/,/)
|
||||
next_string = scanner.scan_until(/,/).chomp(',')
|
||||
else
|
||||
next_string = scanner.scan_until(/\s+|$/).rstrip
|
||||
end
|
||||
|
||||
input_values << next_string
|
||||
end
|
||||
|
||||
input_values << '' if input_values.empty?
|
||||
|
||||
input_values
|
||||
end
|
||||
|
||||
class Game
|
||||
def initialize(history, non_win_count)
|
||||
@beans = Array.new(13, 3)
|
||||
@beans[6] = 0
|
||||
@beans[13] = 0
|
||||
|
||||
@turn_counter = 0
|
||||
|
||||
@history = history
|
||||
@non_win_count = non_win_count
|
||||
end
|
||||
|
||||
# @return [Boolean] True if the computer did not win the game
|
||||
def play
|
||||
while true
|
||||
print_beans
|
||||
|
||||
move = get_move("YOUR MOVE")
|
||||
home_pit = 6
|
||||
computer_home_pit = 13
|
||||
|
||||
last_pit = perform_move(move, home_pit)
|
||||
|
||||
print_beans
|
||||
|
||||
break if game_over
|
||||
|
||||
if home_pit == last_pit
|
||||
second_move = get_move("AGAIN")
|
||||
|
||||
perform_move(second_move, home_pit)
|
||||
|
||||
print_beans
|
||||
|
||||
break if game_over
|
||||
end
|
||||
|
||||
computer_move, computer_last_pit = get_computer_move
|
||||
print "MY MOVE IS #{computer_move - 6}"
|
||||
|
||||
break if game_over
|
||||
|
||||
if computer_last_pit == computer_home_pit
|
||||
second_computer_move, _ = get_computer_move
|
||||
print ",#{second_computer_move - 6}"
|
||||
|
||||
break if game_over
|
||||
end
|
||||
end
|
||||
|
||||
end_game
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def game_over
|
||||
@beans[0...6].all? { |b| b == 0 } || @beans[7...13].all? { |b| b == 0 }
|
||||
end
|
||||
|
||||
# @return [Boolean] True if the computer did not win
|
||||
def end_game
|
||||
puts
|
||||
puts "GAME OVER"
|
||||
|
||||
difference = @beans[6] - @beans[13]
|
||||
|
||||
if difference < 0
|
||||
puts "I WIN BY #{-difference} POINTS"
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
puts "YOU WIN BY #{difference} POINTS" if difference > 0
|
||||
puts "DRAWN GAME" if difference == 0
|
||||
|
||||
difference >= 0
|
||||
end
|
||||
|
||||
# @param [Integer] move
|
||||
# @param [Integer] home_pit
|
||||
def perform_move(move, home_pit)
|
||||
last_pit = distribute_beans(move, home_pit)
|
||||
|
||||
update_history(move)
|
||||
|
||||
last_pit
|
||||
end
|
||||
|
||||
def update_history(current_move)
|
||||
k = current_move % 7
|
||||
@turn_counter += 1
|
||||
|
||||
# Add the move to the history
|
||||
@history[@non_win_count] = @history[@non_win_count] * 6 + k if @turn_counter < 9
|
||||
end
|
||||
|
||||
def print_beans
|
||||
puts
|
||||
|
||||
# Print computer beans
|
||||
print ' ' * 3
|
||||
@beans[7...13].reverse.each { |bean_count| print_bean(bean_count) }
|
||||
puts
|
||||
|
||||
# Print home beans
|
||||
print_bean(@beans[13])
|
||||
print ' ' * 23
|
||||
print_number(@beans[6]) # This is not print_bean in line with the original version
|
||||
puts
|
||||
|
||||
# Print player beans
|
||||
print ' ' * 3
|
||||
@beans[0...6].each { |bean_count| print_bean(bean_count) }
|
||||
puts
|
||||
|
||||
puts
|
||||
end
|
||||
|
||||
def get_move(prompt)
|
||||
move = get_integer_input(prompt)
|
||||
|
||||
while move < 1 || move > 6 || @beans[move - 1] == 0
|
||||
puts "ILLEGAL MOVE"
|
||||
move = get_integer_input("AGAIN")
|
||||
end
|
||||
|
||||
move - 1
|
||||
end
|
||||
|
||||
def distribute_beans(start_pit, home_pit, beans = @beans)
|
||||
beans_to_distribute = beans[start_pit]
|
||||
beans[start_pit] = 0
|
||||
|
||||
current_pit = start_pit
|
||||
|
||||
(0...beans_to_distribute).each do
|
||||
current_pit = (current_pit + 1) % beans.size
|
||||
beans[current_pit] += 1
|
||||
end
|
||||
|
||||
# If the last pit was empty before we put a bean in it (and it's not a scoring pit), add beans to score
|
||||
if beans[current_pit] == 1 && current_pit != 6 && current_pit != 13 && beans[12 - current_pit] != 0
|
||||
beans[home_pit] = beans[home_pit] + beans[12 - current_pit] + 1
|
||||
beans[current_pit] = 0
|
||||
beans[12 - current_pit] = 0
|
||||
end
|
||||
|
||||
current_pit
|
||||
end
|
||||
|
||||
def print_bean(bean_count)
|
||||
print ' ' if bean_count < 10
|
||||
print_number(bean_count)
|
||||
end
|
||||
|
||||
def get_integer_input(prompt)
|
||||
integer_value = nil
|
||||
|
||||
input_values = input(prompt)
|
||||
|
||||
while integer_value.nil?
|
||||
print '!EXTRA INPUT IGNORED' if (input_values.size > 1)
|
||||
|
||||
value = input_values.first
|
||||
|
||||
begin
|
||||
integer_value = Integer(value)
|
||||
rescue
|
||||
puts '!NUMBER EXPECTED - RETRY INPUT LINE'
|
||||
input_values = input('')
|
||||
end
|
||||
end
|
||||
|
||||
integer_value
|
||||
end
|
||||
|
||||
def get_computer_move
|
||||
d = -99
|
||||
home_pit = 13
|
||||
|
||||
chosen_move = 7
|
||||
|
||||
# Test all possible moves
|
||||
(7...13).each do |move_under_test|
|
||||
# Create a copy of the beans to test against
|
||||
beans_copy = @beans.dup
|
||||
|
||||
# If the move is not legal, skip it
|
||||
next if beans_copy[move_under_test] == 0
|
||||
|
||||
# Determine the best response the player may make to this move
|
||||
player_max_score = 0
|
||||
|
||||
# Make the move under test against the copy
|
||||
distribute_beans(move_under_test, home_pit, beans_copy)
|
||||
|
||||
# Test every player response
|
||||
(0...6).each do |i|
|
||||
# Skip the move if it would be illegal
|
||||
next if beans_copy[i] == 0
|
||||
|
||||
# Determine the last
|
||||
landing_with_overflow = beans_copy[i] + i
|
||||
# If landing > 13 the player has put a bean in both home pits
|
||||
player_move_score = (landing_with_overflow > 14) ? 1 : 0
|
||||
# Find the actual pit
|
||||
landing = landing_with_overflow % 14
|
||||
|
||||
# If the landing pit is empty, the player will steal beans
|
||||
if beans_copy[landing] == 0 && landing != 6 && landing != 13
|
||||
player_move_score = beans_copy[12 - landing] + player_move_score
|
||||
end
|
||||
|
||||
# Update the max score if this move is the best player move
|
||||
player_max_score = player_move_score if player_move_score > player_max_score
|
||||
end
|
||||
|
||||
# Final score for move is computer score, minus the player's score and any player gains from their best move
|
||||
final_score = beans_copy[13] - beans_copy[6] - player_max_score
|
||||
|
||||
if @turn_counter < 9
|
||||
k = move_under_test % 7
|
||||
|
||||
(0...@non_win_count).each do |i|
|
||||
# Penalise move if it was used in a losing game
|
||||
final_score = final_score - 2 if @history[@non_win_count] * 6 + k == ((Float(@history[i]) / 6 ** (7 - @turn_counter)) + 0.1).floor
|
||||
end
|
||||
end
|
||||
|
||||
# Choose the move if it is the best move found so far
|
||||
if final_score >= d
|
||||
chosen_move = move_under_test
|
||||
d = final_score
|
||||
end
|
||||
end
|
||||
|
||||
last_pit = perform_move(chosen_move, home_pit)
|
||||
|
||||
[chosen_move, last_pit]
|
||||
end
|
||||
end
|
||||
|
||||
puts 'AWARI'.center(80)
|
||||
puts 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY'.center(80)
|
||||
|
||||
# Initialise stable variables
|
||||
history = Array.new(50)
|
||||
non_win_count = 0
|
||||
|
||||
# APPLICATION LOOP
|
||||
while true
|
||||
puts
|
||||
puts
|
||||
|
||||
history[non_win_count] = 0
|
||||
|
||||
game = Game.new(history, non_win_count)
|
||||
|
||||
computer_didnt_win = game.play
|
||||
non_win_count += 1 if computer_didnt_win
|
||||
end
|
||||
343
07_Basketball/python/basketball.py
Normal file
343
07_Basketball/python/basketball.py
Normal file
@@ -0,0 +1,343 @@
|
||||
import random
|
||||
|
||||
# The basketball class is a computer game that allows you to play as
|
||||
# Dartmouth College's captain and playmaker
|
||||
# The game uses set probabilites to simulate outcomes of each posession
|
||||
# You are able to choose your shot types as well as defensive formations
|
||||
|
||||
|
||||
class Basketball():
|
||||
def __init__(self):
|
||||
self.time = 0
|
||||
self.score = [0, 0] # first value is opponents score, second is home
|
||||
self.defense = None
|
||||
self.defense_choices = [6, 6.5, 7, 7.5]
|
||||
self.shot = None
|
||||
self.shot_choices = [1, 2, 3, 4]
|
||||
self.z1 = None
|
||||
|
||||
# Explains the keyboard inputs
|
||||
print("\t\t\t Basketball")
|
||||
print("\t Creative Computing Morristown, New Jersey\n\n\n")
|
||||
print("This is Dartmouth College basketball. ")
|
||||
print("Υou will be Dartmouth captain and playmaker.")
|
||||
print("Call shots as follows:")
|
||||
print("1. Long (30ft.) Jump Shot; 2. Short (15 ft.) Jump Shot; "
|
||||
+ "3. Lay up; 4. Set Shot")
|
||||
print("Both teams will use the same defense. Call Defense as follows:")
|
||||
print("6. Press; 6.5 Man-to-Man; 7. Zone; 7.5 None.")
|
||||
print("To change defense, just type 0 as your next shot.")
|
||||
print("Your starting defense will be? ", end='')
|
||||
|
||||
# takes input for a defense
|
||||
try:
|
||||
self.defense = float(input())
|
||||
|
||||
except ValueError:
|
||||
self.defense = None
|
||||
|
||||
# if the input wasn't a valid defense, takes input again
|
||||
while self.defense not in self.defense_choices:
|
||||
print("Your new defensive allignment is? ", end='')
|
||||
try:
|
||||
self.defense = float(input())
|
||||
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
# takes input for opponent's name
|
||||
print("\nChoose your opponent? ", end='')
|
||||
|
||||
self.opponent = input()
|
||||
self.start_of_period()
|
||||
|
||||
# adds points to the score
|
||||
# team can take 0 or 1, for opponent or Dartmouth, respectively
|
||||
def add_points(self, team, points):
|
||||
self.score[team] += points
|
||||
self.print_score()
|
||||
|
||||
def ball_passed_back(self):
|
||||
print("Ball passed back to you. ", end='')
|
||||
self.dartmouth_ball()
|
||||
|
||||
# change defense, called when the user enters 0 for their shot
|
||||
def change_defense(self):
|
||||
self.defense = None
|
||||
|
||||
while self.defense not in self.defense_choices:
|
||||
print("Your new defensive allignment is? ")
|
||||
try:
|
||||
self.defense = float(input())
|
||||
|
||||
except ValueError:
|
||||
continue
|
||||
self.dartmouth_ball()
|
||||
|
||||
# simulates two foul shots for a player and adds the points
|
||||
def foul_shots(self, team):
|
||||
print("Shooter fouled. Two shots.")
|
||||
if random.random() > .49:
|
||||
if random.random() > .75:
|
||||
print("Both shots missed.")
|
||||
else:
|
||||
print("Shooter makes one shot and misses one.")
|
||||
self.score[team] += 1
|
||||
else:
|
||||
print("Shooter makes both shots.")
|
||||
self.score[team] += 2
|
||||
|
||||
self.print_score()
|
||||
|
||||
# called when t = 50, starts a new period
|
||||
def halftime(self):
|
||||
print("\n ***** End of first half *****\n")
|
||||
self.print_score()
|
||||
self.start_of_period()
|
||||
|
||||
# prints the current score
|
||||
def print_score(self):
|
||||
print("Score: " + str(self.score[1])
|
||||
+ " to " + str(self.score[0]) + "\n")
|
||||
|
||||
# simulates a center jump for posession at the beginning of a period
|
||||
def start_of_period(self):
|
||||
print("Center jump")
|
||||
if random.random() > .6:
|
||||
print("Dartmouth controls the tap.\n")
|
||||
self.dartmouth_ball()
|
||||
else:
|
||||
print(self.opponent + " controls the tap.\n")
|
||||
self.opponent_ball()
|
||||
|
||||
# called when t = 92
|
||||
def two_minute_warning(self):
|
||||
print(" *** Two minutes left in the game ***")
|
||||
|
||||
# called when the user enters 1 or 2 for their shot
|
||||
def dartmouth_jump_shot(self):
|
||||
self.time += 1
|
||||
if self.time == 50:
|
||||
self.halftime()
|
||||
elif self.time == 92:
|
||||
self.two_minute_warning()
|
||||
print("Jump Shot.")
|
||||
# simulates chances of different possible outcomes
|
||||
if random.random() > .341 * self.defense / 8:
|
||||
if random.random() > .682 * self.defense / 8:
|
||||
if random.random() > .782 * self.defense / 8:
|
||||
if random.random() > .843 * self.defense / 8:
|
||||
print("Charging foul. Dartmouth loses ball.\n")
|
||||
self.opponent_ball()
|
||||
else:
|
||||
# player is fouled
|
||||
self.foul_shots(1)
|
||||
self.opponent_ball()
|
||||
else:
|
||||
if random.random() > .5:
|
||||
print("Shot is blocked. Ball controlled by " +
|
||||
self.opponent + ".\n")
|
||||
self.opponent_ball()
|
||||
else:
|
||||
print("Shot is blocked. Ball controlled by Dartmouth.")
|
||||
self.dartmouth_ball()
|
||||
else:
|
||||
print("Shot is off target.")
|
||||
if self.defense / 6 * random.random() > .45:
|
||||
print("Rebound to " + self.opponent + "\n")
|
||||
self.opponent_ball()
|
||||
else:
|
||||
print("Dartmouth controls the rebound.")
|
||||
if random.random() > .4:
|
||||
if self.defense == 6 and random.random() > .6:
|
||||
print("Pass stolen by " + self.opponent
|
||||
+ ", easy lay up")
|
||||
self.add_points(0, 2)
|
||||
self.dartmouth_ball()
|
||||
else:
|
||||
# ball is passed back to you
|
||||
self.ball_passed_back()
|
||||
else:
|
||||
print("")
|
||||
self.dartmouth_non_jump_shot()
|
||||
else:
|
||||
print("Shot is good.")
|
||||
self.add_points(1, 2)
|
||||
self.opponent_ball()
|
||||
|
||||
# called when the user enters 0, 3, or 4
|
||||
# lay up, set shot, or defense change
|
||||
def dartmouth_non_jump_shot(self):
|
||||
self.time += 1
|
||||
if self.time == 50:
|
||||
self.halftime()
|
||||
elif self.time == 92:
|
||||
self.two_minute_warning()
|
||||
|
||||
if self.shot == 4:
|
||||
print("Set shot.")
|
||||
elif self.shot == 3:
|
||||
print("Lay up.")
|
||||
elif self.shot == 0:
|
||||
self.change_defense()
|
||||
|
||||
# simulates different outcomes after a lay up or set shot
|
||||
if 7/self.defense*random.random() > .4:
|
||||
if 7/self.defense*random.random() > .7:
|
||||
if 7/self.defense*random.random() > .875:
|
||||
if 7/self.defense*random.random() > .925:
|
||||
print("Charging foul. Dartmouth loses the ball.\n")
|
||||
self.opponent_ball()
|
||||
else:
|
||||
print("Shot blocked. " + self.opponent + "'s ball.\n")
|
||||
self.opponent_ball()
|
||||
else:
|
||||
self.foul_shots(1)
|
||||
self.opponent_ball()
|
||||
else:
|
||||
print("Shot is off the rim.")
|
||||
if random.random() > 2/3:
|
||||
print("Dartmouth controls the rebound.")
|
||||
if random.random() > .4:
|
||||
print("Ball passed back to you.\n")
|
||||
self.dartmouth_ball()
|
||||
else:
|
||||
self.dartmouth_non_jump_shot()
|
||||
else:
|
||||
print(self.opponent + " controls the rebound.\n")
|
||||
self.opponent_ball()
|
||||
else:
|
||||
print("Shot is good. Two points.")
|
||||
self.add_points(1, 2)
|
||||
self.opponent_ball()
|
||||
|
||||
# plays out a Dartmouth posession, starting with your choice of shot
|
||||
def dartmouth_ball(self):
|
||||
print("Your shot? ", end='')
|
||||
self.shot = None
|
||||
try:
|
||||
self.shot = int(input())
|
||||
except ValueError:
|
||||
self.shot = None
|
||||
|
||||
while self.shot not in self.shot_choices:
|
||||
print("Incorrect answer. Retype it. Your shot? ", end='')
|
||||
try:
|
||||
self.shot = int(input())
|
||||
except:
|
||||
continue
|
||||
|
||||
if self.time < 100 or random.random() < .5:
|
||||
if self.shot == 1 or self.shot == 2:
|
||||
self.dartmouth_jump_shot()
|
||||
else:
|
||||
self.dartmouth_non_jump_shot()
|
||||
else:
|
||||
if self.score[0] != self.score[1]:
|
||||
print("\n ***** End Of Game *****")
|
||||
print("Final Score: Dartmouth: " + str(self.score[1]) + " "
|
||||
+ self.opponent + ": " + str(self.score[0]))
|
||||
else:
|
||||
print("\n ***** End Of Second Half *****")
|
||||
print("Score at end of regulation time:")
|
||||
print(" Dartmouth: " + str(self.score[1]) + " " +
|
||||
self.opponent + ": " + str(self.score[0]))
|
||||
print("Begin two minute overtime period")
|
||||
self.time = 93
|
||||
self.start_of_period()
|
||||
|
||||
# simulates the opponents jumpshot
|
||||
def opponent_jumpshot(self):
|
||||
print("Jump Shot.")
|
||||
if 8/self.defense*random.random() > .35:
|
||||
if 8/self.defense*random.random() > .75:
|
||||
if 8/self.defense*random.random() > .9:
|
||||
print("Offensive foul. Dartmouth's ball.\n")
|
||||
self.dartmouth_ball()
|
||||
else:
|
||||
self.foul_shots(0)
|
||||
self.dartmouth_ball()
|
||||
else:
|
||||
print("Shot is off the rim.")
|
||||
if self.defense/6*random.random() > .5:
|
||||
print(self.opponent + " controls the rebound.")
|
||||
if self.defense == 6:
|
||||
if random.random() > .75:
|
||||
print("Ball stolen. Easy lay up for Dartmouth.")
|
||||
self.add_points(1, 2)
|
||||
self.opponent_ball()
|
||||
else:
|
||||
if random.random() > .5:
|
||||
print("")
|
||||
self.opponent_non_jumpshot()
|
||||
else:
|
||||
print("Pass back to " + self.opponent +
|
||||
" guard.\n")
|
||||
self.opponent_ball()
|
||||
else:
|
||||
if random.random() > .5:
|
||||
self.opponent_non_jumpshot()
|
||||
else:
|
||||
print("Pass back to " + self.opponent +
|
||||
" guard.\n")
|
||||
self.opponent_ball()
|
||||
else:
|
||||
print("Dartmouth controls the rebound.\n")
|
||||
self.dartmouth_ball()
|
||||
else:
|
||||
print("Shot is good.")
|
||||
self.add_points(0, 2)
|
||||
self.dartmouth_ball()
|
||||
|
||||
# simulates opponents lay up or set shot
|
||||
def opponent_non_jumpshot(self):
|
||||
if self.z1 > 3:
|
||||
print("Set shot.")
|
||||
else:
|
||||
print("Lay up")
|
||||
if 7/self.defense*random.random() > .413:
|
||||
print("Shot is missed.")
|
||||
if self.defense/6*random.random() > .5:
|
||||
print(self.opponent + " controls the rebound.")
|
||||
if self.defense == 6:
|
||||
if random.random() > .75:
|
||||
print("Ball stolen. Easy lay up for Dartmouth.")
|
||||
self.add_points(1, 2)
|
||||
self.opponent_ball()
|
||||
else:
|
||||
if random.random() > .5:
|
||||
print("")
|
||||
self.opponent_non_jumpshot()
|
||||
else:
|
||||
print("Pass back to " + self.opponent +
|
||||
" guard.\n")
|
||||
self.opponent_ball()
|
||||
else:
|
||||
if random.random() > .5:
|
||||
print("")
|
||||
self.opponent_non_jumpshot()
|
||||
else:
|
||||
print("Pass back to " + self.opponent + " guard\n")
|
||||
self.opponent_ball()
|
||||
else:
|
||||
print("Dartmouth controls the rebound.\n")
|
||||
self.dartmouth_ball()
|
||||
else:
|
||||
print("Shot is good.")
|
||||
self.add_points(0, 2)
|
||||
self.dartmouth_ball()
|
||||
|
||||
# simulates an opponents possesion
|
||||
# #randomly picks jump shot or lay up / set shot.
|
||||
def opponent_ball(self):
|
||||
self.time += 1
|
||||
if self.time == 50:
|
||||
self.halftime()
|
||||
self.z1 = 10/4*random.random()+1
|
||||
if self.z1 > 2:
|
||||
self.opponent_non_jumpshot()
|
||||
else:
|
||||
self.opponent_jumpshot()
|
||||
|
||||
|
||||
new_game = Basketball()
|
||||
1
09_Battle/java/.gitignore
vendored
Normal file
1
09_Battle/java/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*~
|
||||
168
09_Battle/java/Battle.java
Normal file
168
09_Battle/java/Battle.java
Normal file
@@ -0,0 +1,168 @@
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Random;
|
||||
import java.util.function.Predicate;
|
||||
import java.text.NumberFormat;
|
||||
|
||||
|
||||
/* This class holds the game state and the game logic */
|
||||
public class Battle {
|
||||
|
||||
/* parameters of the game */
|
||||
private int seaSize;
|
||||
private int[] sizes;
|
||||
private int[] counts;
|
||||
|
||||
/* The game setup - the ships and the sea */
|
||||
private ArrayList<Ship> ships;
|
||||
private Sea sea;
|
||||
|
||||
/* game state counts */
|
||||
private int[] losses; // how many of each type of ship have been sunk
|
||||
private int hits; // how many hits the player has made
|
||||
private int misses; // how many misses the player has made
|
||||
|
||||
// Names of ships of each size. The game as written has ships of size 3, 4 and 5 but
|
||||
// can easily be modified. It makes no sense to have a ship of size zero though.
|
||||
private static String NAMES_BY_SIZE[] = {
|
||||
"error",
|
||||
"size1",
|
||||
"destroyer",
|
||||
"cruiser",
|
||||
"aircraft carrier",
|
||||
"size5" };
|
||||
|
||||
// Entrypoint
|
||||
public static void main(String args[]) {
|
||||
Battle game = new Battle(6, // Sea is 6 x 6 tiles
|
||||
new int[] { 2, 3, 4 }, // Ships are of sizes 2, 3, and 4
|
||||
new int[] { 2, 2, 2 }); // there are two ships of each size
|
||||
game.play();
|
||||
}
|
||||
|
||||
public Battle(int scale, int[] shipSizes, int[] shipCounts) {
|
||||
seaSize = scale;
|
||||
sizes = shipSizes;
|
||||
counts = shipCounts;
|
||||
|
||||
// validate parameters
|
||||
if (seaSize < 4) throw new RuntimeException("Sea Size " + seaSize + " invalid, must be at least 4");
|
||||
|
||||
for (int sz : sizes) {
|
||||
if ((sz < 1) || (sz > seaSize))
|
||||
throw new RuntimeException("Ship has invalid size " + sz);
|
||||
}
|
||||
|
||||
if (counts.length != sizes.length) {
|
||||
throw new RuntimeException("Ship counts must match");
|
||||
}
|
||||
|
||||
// Initialize game state
|
||||
sea = new Sea(seaSize); // holds what ship if any occupies each tile
|
||||
ships = new ArrayList<Ship>(); // positions and states of all the ships
|
||||
losses = new int[counts.length]; // how many ships of each type have been sunk
|
||||
|
||||
// Build up the list of all the ships
|
||||
int shipNumber = 1;
|
||||
for (int type = 0; type < counts.length; ++type) {
|
||||
for (int i = 0; i < counts[i]; ++i) {
|
||||
ships.add(new Ship(shipNumber++, sizes[type]));
|
||||
}
|
||||
}
|
||||
|
||||
// When we put the ships in the sea, we put the biggest ones in first, or they might
|
||||
// not fit
|
||||
ArrayList<Ship> largestFirst = new ArrayList<>(ships);
|
||||
Collections.sort(largestFirst, Comparator.comparingInt((Ship ship) -> ship.size()).reversed());
|
||||
|
||||
// place each ship into the sea
|
||||
for (Ship ship : largestFirst) {
|
||||
ship.placeRandom(sea);
|
||||
}
|
||||
}
|
||||
|
||||
public void play() {
|
||||
System.out.println("The following code of the bad guys' fleet disposition\nhas been captured but not decoded:\n");
|
||||
System.out.println(sea.encodedDump());
|
||||
System.out.println("De-code it and use it if you can\nbut keep the de-coding method a secret.\n");
|
||||
|
||||
int lost = 0;
|
||||
System.out.println("Start game");
|
||||
Input input = new Input(seaSize);
|
||||
try {
|
||||
while (lost < ships.size()) { // the game continues while some ships remain unsunk
|
||||
if (! input.readCoordinates()) { // ... unless there is no more input from the user
|
||||
return;
|
||||
}
|
||||
|
||||
// The computer thinks of the sea as a grid of rows, from top to bottom.
|
||||
// However, the user will use X and Y coordinates, with Y going bottom to top
|
||||
int row = seaSize - input.y();
|
||||
int col = input.x() - 1;
|
||||
|
||||
if (sea.isEmpty(col, row)) {
|
||||
++misses;
|
||||
System.out.println("Splash! Try again.");
|
||||
} else {
|
||||
Ship ship = ships.get(sea.get(col, row) - 1);
|
||||
if (ship.isSunk()) {
|
||||
++misses;
|
||||
System.out.println("There used to be a ship at that point, but you sunk it.");
|
||||
System.out.println("Splash! Try again.");
|
||||
} else if (ship.wasHit(col, row)) {
|
||||
++misses;
|
||||
System.out.println("You already put a hole in ship number " + ship.id());
|
||||
System.out.println("Splash! Try again.");
|
||||
} else {
|
||||
ship.hit(col, row);
|
||||
++hits;
|
||||
System.out.println("A direct hit on ship number " + ship.id());
|
||||
|
||||
// If a ship was hit, we need to know whether it was sunk.
|
||||
// If so, tell the player and update our counts
|
||||
if (ship.isSunk()) {
|
||||
++lost;
|
||||
System.out.println("And you sunk it. Hurrah for the good guys.");
|
||||
System.out.print("So far, the bad guys have lost ");
|
||||
ArrayList<String> typeDescription = new ArrayList<>();
|
||||
for (int i = 0 ; i < sizes.length; ++i) {
|
||||
if (sizes[i] == ship.size()) {
|
||||
++losses[i];
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(losses[i]);
|
||||
sb.append(" ");
|
||||
sb.append(NAMES_BY_SIZE[sizes[i]]);
|
||||
if (losses[i] != 1)
|
||||
sb.append("s");
|
||||
typeDescription.add(sb.toString());
|
||||
}
|
||||
System.out.println(String.join(", ", typeDescription));
|
||||
double ratioNum = ((double)misses)/hits;
|
||||
String ratio = NumberFormat.getInstance().format(ratioNum);
|
||||
System.out.println("Your current splash/hit ratio is " + ratio);
|
||||
|
||||
if (lost == ships.size()) {
|
||||
System.out.println("You have totally wiped out the bad guys' fleet");
|
||||
System.out.println("With a final splash/hit ratio of " + ratio);
|
||||
|
||||
if (misses == 0) {
|
||||
System.out.println("Congratulations - A direct hit every time.");
|
||||
}
|
||||
|
||||
System.out.println("\n****************************\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
// This should not happen running from console, but java requires us to check for it
|
||||
System.err.println("System error.\n" + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
67
09_Battle/java/Input.java
Normal file
67
09_Battle/java/Input.java
Normal file
@@ -0,0 +1,67 @@
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.text.NumberFormat;
|
||||
|
||||
// This class handles reading input from the player
|
||||
// Each input is an x and y coordinate
|
||||
// e.g. 5,3
|
||||
public class Input {
|
||||
private BufferedReader reader;
|
||||
private NumberFormat parser;
|
||||
private int scale; // size of the sea, needed to validate input
|
||||
private boolean isQuit; // whether the input has ended
|
||||
private int[] coords; // the last coordinates read
|
||||
|
||||
public Input(int seaSize) {
|
||||
scale = seaSize;
|
||||
reader = new BufferedReader(new InputStreamReader(System.in));
|
||||
parser = NumberFormat.getIntegerInstance();
|
||||
}
|
||||
|
||||
public boolean readCoordinates() throws IOException {
|
||||
while (true) {
|
||||
// Write a prompt
|
||||
System.out.print("\nTarget x,y\n> ");
|
||||
String inputLine = reader.readLine();
|
||||
if (inputLine == null) {
|
||||
// If the input stream is ended, there is no way to continue the game
|
||||
System.out.println("\nGame quit\n");
|
||||
isQuit = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// split the input into two fields
|
||||
String[] fields = inputLine.split(",");
|
||||
if (fields.length != 2) {
|
||||
// has to be exactly two
|
||||
System.out.println("Need two coordinates separated by ','");
|
||||
continue;
|
||||
}
|
||||
|
||||
coords = new int[2];
|
||||
boolean error = false;
|
||||
// each field should contain an integer from 1 to the size of the sea
|
||||
try {
|
||||
for (int c = 0 ; c < 2; ++c ) {
|
||||
int val = Integer.parseInt(fields[c].strip());
|
||||
if ((val < 1) || (val > scale)) {
|
||||
System.out.println("Coordinates must be from 1 to " + scale);
|
||||
error = true;
|
||||
} else {
|
||||
coords[c] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException ne) {
|
||||
// this happens if the field is not a valid number
|
||||
System.out.println("Coordinates must be numbers");
|
||||
error = true;
|
||||
}
|
||||
if (!error) return true;
|
||||
}
|
||||
}
|
||||
|
||||
public int x() { return coords[0]; }
|
||||
public int y() { return coords[1]; }
|
||||
}
|
||||
60
09_Battle/java/Sea.java
Normal file
60
09_Battle/java/Sea.java
Normal file
@@ -0,0 +1,60 @@
|
||||
// Track the content of the sea
|
||||
class Sea {
|
||||
// the sea is a square grid of tiles. It is a one-dimensional array, and this
|
||||
// class maps x and y coordinates to an array index
|
||||
// Each tile is either empty (value of tiles at index is 0)
|
||||
// or contains a ship (value of tiles at index is the ship number)
|
||||
private int tiles[];
|
||||
|
||||
private int size;
|
||||
|
||||
public Sea(int make_size) {
|
||||
size = make_size;
|
||||
tiles = new int[size*size];
|
||||
}
|
||||
|
||||
public int size() { return size; }
|
||||
|
||||
// This writes out a representation of the sea, but in a funny order
|
||||
// The idea is to give the player the job of working it out
|
||||
public String encodedDump() {
|
||||
StringBuilder out = new StringBuilder();
|
||||
for (int x = 0; x < size; ++x) {
|
||||
for (int y = 0; y < size; ++y)
|
||||
out.append(Integer.toString(get(x, y)));
|
||||
out.append('\n');
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
/* return true if x,y is in the sea and empty
|
||||
* return false if x,y is occupied or is out of range
|
||||
* Doing this in one method makes placing ships much easier
|
||||
*/
|
||||
public boolean isEmpty(int x, int y) {
|
||||
if ((x<0)||(x>=size)||(y<0)||(y>=size)) return false;
|
||||
return (get(x,y) == 0);
|
||||
}
|
||||
|
||||
/* return the ship number, or zero if no ship.
|
||||
* Unlike isEmpty(x,y), these other methods require that the
|
||||
* coordinates passed be valid
|
||||
*/
|
||||
public int get(int x, int y) {
|
||||
return tiles[index(x,y)];
|
||||
}
|
||||
|
||||
public void set(int x, int y, int value) {
|
||||
tiles[index(x, y)] = value;
|
||||
}
|
||||
|
||||
// map the coordinates to the array index
|
||||
private int index(int x, int y) {
|
||||
if ((x < 0) || (x >= size))
|
||||
throw new ArrayIndexOutOfBoundsException("Program error: x cannot be " + x);
|
||||
if ((y < 0) || (y >= size))
|
||||
throw new ArrayIndexOutOfBoundsException("Program error: y cannot be " + y);
|
||||
|
||||
return y*size + x;
|
||||
}
|
||||
}
|
||||
170
09_Battle/java/Ship.java
Normal file
170
09_Battle/java/Ship.java
Normal file
@@ -0,0 +1,170 @@
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Random;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/** A single ship, with its position and where it has been hit */
|
||||
class Ship {
|
||||
// These are the four directions that ships can be in
|
||||
public static final int ORIENT_E=0; // goes East from starting position
|
||||
public static final int ORIENT_SE=1; // goes SouthEast from starting position
|
||||
public static final int ORIENT_S=2; // goes South from starting position
|
||||
public static final int ORIENT_SW=3; // goes SouthWest from starting position
|
||||
|
||||
private int id; // ship number
|
||||
private int size; // how many tiles it occupies
|
||||
private boolean placed; // whether this ship is in the sea yet
|
||||
private boolean sunk; // whether this ship has been sunk
|
||||
private ArrayList<Boolean> hits; // which tiles of the ship have been hit
|
||||
|
||||
private int startX; // starting position coordinates
|
||||
private int startY;
|
||||
private int orientX; // x and y deltas from each tile occupied to the next
|
||||
private int orientY;
|
||||
|
||||
public Ship(int i, int sz) {
|
||||
id = i; size = sz;
|
||||
sunk = false; placed = false;
|
||||
hits = new ArrayList<>(Collections.nCopies(size, false));
|
||||
}
|
||||
|
||||
/** @returns the ship number */
|
||||
public int id() { return id; }
|
||||
/** @returns the ship size */
|
||||
public int size() { return size; }
|
||||
|
||||
/* record the ship as having been hit at the given coordinates */
|
||||
public void hit(int x, int y) {
|
||||
// need to work out how many tiles from the ship's starting position the hit is at
|
||||
// that can be worked out from the difference between the starting X coord and this one
|
||||
// unless the ship runs N-S, in which case use the Y coord instead
|
||||
int offset;
|
||||
if (orientX != 0) {
|
||||
offset = (x - startX) / orientX;
|
||||
} else {
|
||||
offset = (y - startY) / orientY;
|
||||
}
|
||||
hits.set(offset, true);
|
||||
|
||||
// if every tile of the ship has been hit, the ship is sunk
|
||||
sunk = hits.stream().allMatch(Predicate.isEqual(true));
|
||||
}
|
||||
|
||||
public boolean isSunk() { return sunk; }
|
||||
|
||||
// whether the ship has already been hit at the given coordinates
|
||||
public boolean wasHit(int x, int y) {
|
||||
int offset;
|
||||
if (orientX != 0) {
|
||||
offset = (x - startX) / orientX;
|
||||
} else {
|
||||
offset = (y - startY) / orientY;
|
||||
}
|
||||
return hits.get(offset);
|
||||
};
|
||||
|
||||
// Place the ship in the sea.
|
||||
// choose a random starting position, and a random direction
|
||||
// if that doesn't fit, keep picking different positions and directions
|
||||
public void placeRandom(Sea s) {
|
||||
Random random = new Random();
|
||||
for (int tries = 0 ; tries < 1000 ; ++tries) {
|
||||
int x = random.nextInt(s.size());
|
||||
int y = random.nextInt(s.size());
|
||||
int orient = random.nextInt(4);
|
||||
|
||||
if (place(s, x, y, orient)) return;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Could not place any more ships");
|
||||
}
|
||||
|
||||
// Attempt to fit the ship into the sea, starting from a given position and
|
||||
// in a given direction
|
||||
// This is by far the most complicated part of the program.
|
||||
// It will start at the position provided, and attempt to occupy tiles in the
|
||||
// requested direction. If it does not fit, either because of the edge of the
|
||||
// sea, or because of ships already in place, it will try to extend the ship
|
||||
// in the opposite direction instead. If that is not possible, it fails.
|
||||
public boolean place(Sea s, int x, int y, int orient) {
|
||||
if (placed) {
|
||||
throw new RuntimeException("Program error - placed ship " + id + " twice");
|
||||
}
|
||||
switch(orient) {
|
||||
case ORIENT_E: // east is increasing X coordinate
|
||||
orientX = 1; orientY = 0;
|
||||
break;
|
||||
case ORIENT_SE: // southeast is increasing X and Y
|
||||
orientX = 1; orientY = 1;
|
||||
break;
|
||||
case ORIENT_S: // south is increasing Y
|
||||
orientX = 0; orientY = 1;
|
||||
break;
|
||||
case ORIENT_SW: // southwest is increasing Y but decreasing X
|
||||
orientX = -1; orientY = 1;
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Invalid orientation " + orient);
|
||||
}
|
||||
|
||||
if (!s.isEmpty(x, y)) return false; // starting position is occupied - placing fails
|
||||
|
||||
startX = x; startY = y;
|
||||
int tilesPlaced = 1;
|
||||
int nextX = startX;
|
||||
int nextY = startY;
|
||||
while (tilesPlaced < size) {
|
||||
if (extendShip(s, nextX, nextY, nextX + orientX, nextY + orientY)) {
|
||||
// It is clear to extend the ship forwards
|
||||
tilesPlaced += 1;
|
||||
nextX = nextX + orientX;
|
||||
nextY = nextY + orientY;
|
||||
} else {
|
||||
int backX = startX - orientX;
|
||||
int backY = startY - orientY;
|
||||
|
||||
if (extendShip(s, startX, startY, backX, backY)) {
|
||||
// We can move the ship backwards, so it can be one tile longer
|
||||
tilesPlaced +=1;
|
||||
startX = backX;
|
||||
startY = backY;
|
||||
} else {
|
||||
// Could not make it longer or move it backwards
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mark in the sea which tiles this ship occupies
|
||||
for (int i = 0; i < size; ++i) {
|
||||
int sx = startX + i * orientX;
|
||||
int sy = startY + i * orientY;
|
||||
s.set(sx, sy, id);
|
||||
}
|
||||
|
||||
placed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check whether a ship which already occupies the "from" coordinates,
|
||||
// can also occupy the "to" coordinates.
|
||||
// They must be within the sea area, empty, and not cause the ship to cross
|
||||
// over another ship
|
||||
private boolean extendShip(Sea s, int fromX, int fromY, int toX, int toY) {
|
||||
if (!s.isEmpty(toX, toY)) return false; // no space
|
||||
if ((fromX == toX)||(fromY == toY)) return true; // horizontal or vertical
|
||||
|
||||
// we can extend the ship without colliding, but we are going diagonally
|
||||
// and it should not be possible for two ships to cross each other on
|
||||
// opposite diagonals.
|
||||
|
||||
// check the two tiles that would cross us here - if either is empty, we are OK
|
||||
// if they both contain different ships, we are OK
|
||||
// but if they both contain the same ship, we are crossing!
|
||||
int corner1 = s.get(fromX, toY);
|
||||
int corner2 = s.get(toX, fromY);
|
||||
if ((corner1 == 0) || (corner1 != corner2)) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
129
11_Bombardment/perl/bombardment.pl
Normal file
129
11_Bombardment/perl/bombardment.pl
Normal file
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
|
||||
#GLOBAL
|
||||
my %player_bases;
|
||||
my %computer_bases;
|
||||
my %player_choices;
|
||||
my %computer_choices;
|
||||
|
||||
&main;
|
||||
|
||||
sub main {
|
||||
&print_intro;
|
||||
&display_field;
|
||||
&populate_computer_bases;
|
||||
&populate_player_bases;
|
||||
&game_play;
|
||||
}
|
||||
|
||||
sub game_play {
|
||||
until (keys %computer_bases == 0 || keys %player_bases == 0) {
|
||||
&player_turn;
|
||||
if (keys %computer_bases == 0) {
|
||||
exit;
|
||||
}
|
||||
&computer_turn;
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
sub computer_turn {
|
||||
# There is logic in here to ensure that the computer doesn't try to pick a target it has already picked
|
||||
my $valid_choice = 0;
|
||||
until ($valid_choice == 1) {
|
||||
my $target = int(rand(25)+1);
|
||||
if (exists $computer_choices{$target}) {
|
||||
$valid_choice = 0;
|
||||
}
|
||||
else {
|
||||
$valid_choice = 1;
|
||||
$computer_choices{$target}=1;
|
||||
if (exists $player_bases{$target}) {
|
||||
delete($player_bases{$target});
|
||||
my $size = keys %player_bases;
|
||||
if ($size > 0) {
|
||||
print "I GOT YOU. IT WON'T BE LONG NOW. POST $target WAS HIT.\n";
|
||||
if ($size == 3) { print "YOU HAVE ONLY THREE OUTPOSTS LEFT.\n"};
|
||||
if ($size == 2) { print "YOU HAVE ONLY TWO OUTPOSTS LEFT.\n"};
|
||||
if ($size == 1) { print "YOU HAVE ONLY ONE OUTPOSTS LEFT.\n"};
|
||||
}
|
||||
else {
|
||||
print "YOU'RE DEAD. YOUR LAST OUTPOST WAS AT $target. HA, HA, HA.\nBETTER LUCK NEXT TIME\n";
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
print "I MISSED YOU, YOU DIRTY RAT. I PICKED $target. YOUR TURN:\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub player_turn {
|
||||
print "WHERE DO YOU WISH TO FIRE YOUR MISSILE\n";
|
||||
chomp(my $target=<STDIN>);
|
||||
if (exists $computer_bases{$target}) {
|
||||
print "YOU GOT ONE OF MY OUTPOSTS!\n";
|
||||
delete($computer_bases{$target});
|
||||
my $size = keys %computer_bases;
|
||||
if ($size == 3) { print "ONE DOWN, THREE TO GO.\n"};
|
||||
if ($size == 2) { print "TWO DOWN, TWO TO GO.\n"};
|
||||
if ($size == 1) { print "THREE DOWN, ONE TO GO.\n"};
|
||||
if ($size == 0) { print "YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN\nMY TRANSISTO&S RECUP%RA*E!\n"};
|
||||
}
|
||||
else {
|
||||
print "HA, HA YOU MISSED. MY TURN NOW:\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub populate_player_bases {
|
||||
print "WHAT ARE YOUR FOUR POSITIONS\n";
|
||||
my $positions=<STDIN>;
|
||||
chomp($positions);
|
||||
my @positions = split/ /,$positions;
|
||||
foreach my $base (@positions) {
|
||||
$player_bases{$base}=0;
|
||||
}
|
||||
}
|
||||
|
||||
sub display_field {
|
||||
for my $num (1..25) {
|
||||
if (length($num) < 2) {
|
||||
$num = " $num";
|
||||
}
|
||||
print "$num ";
|
||||
if ($num % 5 == 0) {
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub populate_computer_bases {
|
||||
my $size = 0;
|
||||
until ($size == 4) {
|
||||
my $base = int(rand(25)+1);
|
||||
$computer_bases{$base}=0;
|
||||
$size = keys %computer_bases;
|
||||
}
|
||||
}
|
||||
|
||||
sub print_intro {
|
||||
print " " x 33, "BOMBARDMENT\n";
|
||||
print " " x 15, " CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
|
||||
print "\n\n";
|
||||
print "YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU\n";
|
||||
print "HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.\n";
|
||||
print "YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.\n";
|
||||
print "THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.\n\n";
|
||||
print "THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE\n";
|
||||
print "OUTPOSTS OF THE COMPUTER. IT WILL DO THE SAME TO YOU.\n";
|
||||
print "THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS\n";
|
||||
print "FIRST IS THE WINNER.\n\n";
|
||||
print "GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!\n\n";
|
||||
print "TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.\n";
|
||||
print "\n\n\n\n";
|
||||
}
|
||||
@@ -4,10 +4,16 @@ import java.util.Scanner;
|
||||
* Game of Bombs Away
|
||||
*
|
||||
* Based on the Basic game of Bombs Away here
|
||||
* https://github.com/coding-horror/basic-computer-games/blob/main/12%20Bombs%20Away/bombsaway.bas
|
||||
* https://github.com/coding-horror/basic-computer-games/blob/main/12_Bombs_Away/bombsaway.bas
|
||||
*
|
||||
* Note: The idea was to create a version of the 1970's Basic game in Java, without adding new features.
|
||||
* Obvious bugs where found have been fixed, but the playability and overlook and feel
|
||||
* of the game have been faithfully reproduced.
|
||||
*
|
||||
* Modern Java coding conventions have been employed and JDK 11 used for maximum compatibility.
|
||||
*
|
||||
* Java port by https://github.com/journich
|
||||
*
|
||||
* Note: The idea was to create a version of the 1970's Basic game in Java, without introducing
|
||||
* new features - no additional text, error checking, etc has been added.
|
||||
*/
|
||||
public class BombsAway {
|
||||
|
||||
@@ -116,8 +122,9 @@ public class BombsAway {
|
||||
|
||||
private int missions;
|
||||
|
||||
private int chanceToHit;
|
||||
private int chanceToBeHit;
|
||||
private int percentageHitRateOfGunners;
|
||||
private boolean liar;
|
||||
|
||||
public BombsAway() {
|
||||
|
||||
@@ -139,8 +146,9 @@ public class BombsAway {
|
||||
// Show an introduction the first time the game is played.
|
||||
case START:
|
||||
intro();
|
||||
chanceToHit = 0;
|
||||
chanceToBeHit = 0;
|
||||
percentageHitRateOfGunners = 0;
|
||||
liar = false;
|
||||
|
||||
gameState = GAME_STATE.CHOOSE_SIDE;
|
||||
break;
|
||||
@@ -267,39 +275,48 @@ public class BombsAway {
|
||||
break;
|
||||
|
||||
case CHOOSE_ENEMY_DEFENCES:
|
||||
boolean bothWeapons = true;
|
||||
percentageHitRateOfGunners = 0;
|
||||
|
||||
ENEMY_DEFENCES enemyDefences = getEnemyDefences("DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3) ? ");
|
||||
if(enemyDefences == null) {
|
||||
System.out.println("TRY AGAIN...");
|
||||
} else {
|
||||
chanceToBeHit = 35;
|
||||
switch(enemyDefences) {
|
||||
case MISSILES:
|
||||
case GUNS:
|
||||
bothWeapons = false;
|
||||
// MISSILES... An extra 35 but cannot specify percentage hit rate for gunners
|
||||
break;
|
||||
|
||||
// fall through on purpose to BOTH since its pretty much identical code other than the chance to hit
|
||||
// increasing if both weapons are part of the defence.
|
||||
case GUNS:
|
||||
// GUNS... No extra 35 but can specify percentage hit rate for gunners
|
||||
chanceToBeHit = 0;
|
||||
// fall through (no break) on purpose because remaining code is applicable
|
||||
// for both GUNS and BOTH options.
|
||||
|
||||
case BOTH:
|
||||
// BOTH... An extra 35 and percentage hit rate for gunners can be specified.
|
||||
percentageHitRateOfGunners = getNumberFromKeyboard("WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? ");
|
||||
if(percentageHitRateOfGunners < 10) {
|
||||
System.out.println("YOU LIE, BUT YOU'LL PAY...");
|
||||
}
|
||||
if(bothWeapons) {
|
||||
chanceToHit = 35;
|
||||
|
||||
liar = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
gameState = GAME_STATE.PROCESS_FLAK;
|
||||
// If player didn't lie when entering percentage hit rate of gunners continue with game
|
||||
// Otherwise shoot down the player.
|
||||
if(!liar) {
|
||||
gameState = GAME_STATE.PROCESS_FLAK;
|
||||
} else {
|
||||
gameState = GAME_STATE.SHOT_DOWN;
|
||||
}
|
||||
break;
|
||||
|
||||
// Determine if the players airplan makes it through the Flak.
|
||||
// Determine if the player's airplane makes it through the Flak.
|
||||
case PROCESS_FLAK:
|
||||
double calc = (CHANCE_OF_BEING_SHOT_DOWN_BASE * randomNumber(1));
|
||||
|
||||
if ((chanceToHit + percentageHitRateOfGunners) > calc) {
|
||||
if ((chanceToBeHit + percentageHitRateOfGunners) > calc) {
|
||||
gameState = GAME_STATE.SHOT_DOWN;
|
||||
} else {
|
||||
gameState = GAME_STATE.MADE_IT_THROUGH_FLAK;
|
||||
@@ -462,7 +479,7 @@ public class BombsAway {
|
||||
/**
|
||||
* Check whether a string equals one of a variable number of values
|
||||
* Useful to check for Y or YES for example
|
||||
* Comparison is case insensitive.
|
||||
* Comparison is case-insensitive.
|
||||
*
|
||||
* @param text source string
|
||||
* @param values a range of values to compare against the source string
|
||||
|
||||
@@ -45,6 +45,8 @@ function tab(space)
|
||||
// Main program
|
||||
async function main()
|
||||
{
|
||||
s = 0;
|
||||
t = 0;
|
||||
while (1) {
|
||||
print("YOU ARE A PILOT IN A WORLD WAR II BOMBER.\n");
|
||||
while (1) {
|
||||
|
||||
229
12_Bombs_Away/perl/bombsaway.pl
Normal file
229
12_Bombs_Away/perl/bombsaway.pl
Normal file
@@ -0,0 +1,229 @@
|
||||
#!/usr/bin/env perl
|
||||
use v5.24;
|
||||
use warnings;
|
||||
use experimental 'signatures';
|
||||
no warnings 'experimental::signatures';
|
||||
|
||||
exit main(@ARGV);
|
||||
|
||||
sub main {
|
||||
$|++;
|
||||
my $mission = 'y';
|
||||
|
||||
# first-level choices will allow us to select the "right" callback
|
||||
# function to start each mission
|
||||
my @choices = (\&italy, \&allies, \&japan, \&germany);
|
||||
|
||||
# to support being case-insensitive "the right way" we apply the fc()
|
||||
# function (i.e. "fold case"). This is slightly overkill in this case
|
||||
# but it's better to stick to good habits.
|
||||
while (fc($mission // 'n') eq fc('y')) {
|
||||
say 'YOU ARE A PILOT IN A WORLD WAR II BOMBER.';
|
||||
|
||||
my $side = choose(
|
||||
'WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4)', 4);
|
||||
|
||||
# arrays start from 0 in Perl, so our starting-from-1 side value
|
||||
# has to be offset by 1.
|
||||
$choices[$side - 1]->();
|
||||
|
||||
$mission = get_input("\n\n\nANOTHER MISSION (Y OR N)");
|
||||
}
|
||||
__exit();
|
||||
}
|
||||
|
||||
# unified exit function, make sure to shame the desertor!
|
||||
sub __exit ($prefix = '') {
|
||||
say $prefix, "CHICKEN !!!\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# unified input gathering. Checks if the input is closed (e.g. because the
|
||||
# player hit CTRL-D) and __exit()s in case. Gets a prompt for asking a
|
||||
# question, returns whatever is input (except spaces).
|
||||
sub get_input ($prompt) {
|
||||
print "$prompt? ";
|
||||
defined(my $input = <STDIN>) or __exit("\n");
|
||||
|
||||
# remove spaces from the input (including newlines), they are not used
|
||||
|
||||
$input =~ s{\s+}{}gmxs;
|
||||
return $input;
|
||||
}
|
||||
|
||||
# structured choosing function, gets a $prompt for asking a question and
|
||||
# will iterate asking until the input is a number between 1 and $n_max.
|
||||
sub choose ($prompt, $n_max) {
|
||||
while ('necessary') {
|
||||
my $side = get_input($prompt);
|
||||
return $side if $side =~ m{\A [1-9]\d* \z}mxs && $side <= $n_max;
|
||||
say 'TRY AGAIN...';
|
||||
}
|
||||
}
|
||||
|
||||
# Italy mission has the same structure as Allies and Germany, so it's been
|
||||
# refactored into a single "multiple()" (pun intended) function, providing
|
||||
# the right messaging.
|
||||
sub italy {
|
||||
return multiple(
|
||||
'YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)',
|
||||
q{SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.},
|
||||
'BE CAREFUL!!!',
|
||||
q{YOU'RE GOING FOR THE OIL, EH?},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
# Allies mission has the same structure as Italy and Germany, so it's been
|
||||
# refactored into a single "multiple()" (pun intended) function, providing
|
||||
# the right messaging.
|
||||
sub allies {
|
||||
return multiple(
|
||||
'AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4)',
|
||||
q{YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.},
|
||||
q{YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.},
|
||||
q{YOU'RE CHASING THE BISMARK IN THE NORTH SEA.},
|
||||
q{YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.},
|
||||
);
|
||||
}
|
||||
|
||||
# Japan mission is different from the other three and is coded...
|
||||
# differently. The end game phases are the same as other missions though,
|
||||
# hence the calls to "direct_hit()" and "endgame()" functions.
|
||||
sub japan {
|
||||
say q{YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.};
|
||||
my $is_first_kamikaze = get_input(q{YOUR FIRST KAMIKAZE MISSION(Y OR N)});
|
||||
if (fc($is_first_kamikaze) eq fc('n')) {
|
||||
our $guns_hit_rate = 0;
|
||||
say '';
|
||||
return endgame();
|
||||
}
|
||||
return direct_hit() if rand(1) > 0.65;
|
||||
return endgame('fail');
|
||||
}
|
||||
|
||||
# Germany mission has the same structure as Italy and Allies, so it's been
|
||||
# refactored into a single "multiple()" (pun intended) function, providing
|
||||
# the right messaging.
|
||||
sub germany {
|
||||
return multiple(
|
||||
"A NAZI, EH? OH WELL. ARE YOU GOING FOR RUSSIA(1),\n"
|
||||
. 'ENGLAND(2), OR FRANCE(3)',
|
||||
q{YOU'RE NEARING STALINGRAD.},
|
||||
q{NEARING LONDON. BE CAREFUL, THEY'VE GOT RADAR.},
|
||||
q{NEARING VERSAILLES. DUCK SOUP. THEY'RE NEARLY DEFENSELESS.}
|
||||
);
|
||||
}
|
||||
|
||||
# This function implements the workhorse for Italy, Allies and Germany
|
||||
# missions, which all have the same structure. It starts with a $question
|
||||
# and a few @comments, each commenting every different answer to the
|
||||
# $question.
|
||||
sub multiple ($question, @comments) {
|
||||
my $target = choose($question, scalar @comments);
|
||||
say "\n", $comments[$target - 1], "\n";
|
||||
|
||||
# we gather the number of missions flown so far so that we can
|
||||
# use it to figure out if *this* mission will be successful. The more
|
||||
# the missions flown, the higher the probability of success.
|
||||
my $missions;
|
||||
while ('necessary') {
|
||||
$missions = get_input('HOW MANY MISSIONS HAVE YOU FLOWN');
|
||||
last if $missions < 160;
|
||||
print 'MISSIONS, NOT MILES...
|
||||
150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS.
|
||||
NOW THEN, ';
|
||||
}
|
||||
say '';
|
||||
|
||||
# a little intermediate comment based on the value of $missions
|
||||
if ($missions < 25) { say "FRESH OUT OF TRANING, EH?\n" }
|
||||
elsif ($missions >= 100) { say "THAT'S PUSHING THE ODDS!\n" }
|
||||
|
||||
# let's roll a 160-faced die and compare to the missions flown so far,
|
||||
# player might not even have to engage in combat!
|
||||
return direct_hit() if $missions >= rand(160);
|
||||
|
||||
# player didn't get a direct hit on the target, so we provide a
|
||||
# feedback about how much it was apart. This is part of the story.
|
||||
my $miss = 2 + int rand(30);
|
||||
say "MISSED TARGET BY $miss MILES!";
|
||||
say "NOW YOU'RE REALLY IN FOR IT !!\n";
|
||||
|
||||
# here is where the game shows a little "weakness", although it might
|
||||
# have been done on purpose. We use "our" variables $missiles_hit_rate
|
||||
# and $guns_hit_rate here because the original BASIC code did not reset
|
||||
# the associated variables (respectively T and S) at every mission, thus
|
||||
# leaking state from one mission to the following ones.
|
||||
#
|
||||
# In particular, both are leaked to the Japan mission(s), and
|
||||
# $guns_hit_rate is leaked to future "multiple()" missions that have
|
||||
# missiles only.
|
||||
#
|
||||
# This is what you get when your language only has global variables.
|
||||
#
|
||||
# Of course, this might have been done on purpose, and we'll replicate
|
||||
# this behaviour here because it adds some randomness to the game.
|
||||
our $missiles_hit_rate = 0;
|
||||
my $response = choose(
|
||||
'DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)', 3);
|
||||
|
||||
# Apply Gun damage for responses 1 and 3
|
||||
if ($response != 2) { # there's some guns involved, ask more
|
||||
say '';
|
||||
|
||||
# see comment above as to why we have a "our" variable here
|
||||
our $guns_hit_rate =
|
||||
get_input(q{WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)});
|
||||
|
||||
# let's normalize the input a bit
|
||||
$guns_hit_rate = 0 unless $guns_hit_rate =~ m{\A [1-9]\d* \z}mxs;
|
||||
|
||||
# a hit rate this low is not reasonable and is immediately punished!
|
||||
if ($guns_hit_rate < 10) {
|
||||
say q{YOU LIE, BUT YOU'LL PAY...};
|
||||
|
||||
# function endgame() provides the... end game messaging, which is
|
||||
# also used by the Japan mission, so it's been factored out.
|
||||
# Passing 'fail' (or any true value) makes sure that is' a
|
||||
# failure.
|
||||
return endgame('fail'); # sure failure
|
||||
}
|
||||
say '';
|
||||
}
|
||||
# Apply missile damage for responses 2 and 3
|
||||
if ($response > 1 ) {
|
||||
$missiles_hit_rate = 35; # remember... this is a global variable
|
||||
}
|
||||
|
||||
# hand control over to the "endgame()" refactored function (also shared
|
||||
# by the Japan mission).
|
||||
return endgame();
|
||||
}
|
||||
|
||||
sub direct_hit {
|
||||
my $killed = int rand(100);
|
||||
say "DIRECT HIT!!!! $killed KILLED.\nMISSION SUCCESSFUL";
|
||||
return;
|
||||
}
|
||||
|
||||
# This function provides the end game randomization and messages, shared
|
||||
# across all missions. If passed a true value $fail, it will make sure that
|
||||
# the outcome is... a failure. This allows coping with a few ad-hoc
|
||||
# GOTO:s in the original BASIC code, while still preserving a refactored
|
||||
# code.
|
||||
sub endgame ($fail = 0) {
|
||||
our $missiles_hit_rate //= 0;
|
||||
our $guns_hit_rate //= 0;
|
||||
$fail ||= ($missiles_hit_rate + $guns_hit_rate) > rand(100);
|
||||
if ($fail) {
|
||||
say '* * * * BOOM * * * *
|
||||
YOU HAVE BEEN SHOT DOWN.....
|
||||
DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR
|
||||
LAST TRIBUTE...';
|
||||
}
|
||||
else {
|
||||
say 'YOU MADE IT THROUGH TREMENDOUS FLAK!!';
|
||||
}
|
||||
return;
|
||||
}
|
||||
48
15_Boxing/csharp/AttackStrategy.cs
Normal file
48
15_Boxing/csharp/AttackStrategy.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
namespace Boxing;
|
||||
|
||||
public abstract class AttackStrategy
|
||||
{
|
||||
protected const int KnockoutDamageThreshold = 35;
|
||||
protected readonly Boxer Other;
|
||||
protected readonly Stack<Action> Work;
|
||||
private readonly Action _notifyGameEnded;
|
||||
|
||||
public AttackStrategy(Boxer other, Stack<Action> work, Action notifyGameEnded)
|
||||
{
|
||||
Other = other;
|
||||
Work = work;
|
||||
_notifyGameEnded = notifyGameEnded;
|
||||
}
|
||||
|
||||
public void Attack()
|
||||
{
|
||||
var punch = GetPunch();
|
||||
if (punch.IsBestPunch)
|
||||
{
|
||||
Other.DamageTaken += 2;
|
||||
}
|
||||
|
||||
Work.Push(punch.Punch switch
|
||||
{
|
||||
Punch.FullSwing => FullSwing,
|
||||
Punch.Hook => Hook,
|
||||
Punch.Uppercut => Uppercut,
|
||||
_ => Jab
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract AttackPunch GetPunch();
|
||||
protected abstract void FullSwing();
|
||||
protected abstract void Hook();
|
||||
protected abstract void Uppercut();
|
||||
protected abstract void Jab();
|
||||
|
||||
protected void RegisterKnockout(string knockoutMessage)
|
||||
{
|
||||
Work.Clear();
|
||||
_notifyGameEnded();
|
||||
Console.WriteLine(knockoutMessage);
|
||||
}
|
||||
|
||||
protected record AttackPunch(Punch Punch, bool IsBestPunch);
|
||||
}
|
||||
45
15_Boxing/csharp/Boxer.cs
Normal file
45
15_Boxing/csharp/Boxer.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
namespace Boxing;
|
||||
|
||||
public class Boxer
|
||||
{
|
||||
private int _wins;
|
||||
|
||||
private string Name { get; set; } = string.Empty;
|
||||
|
||||
public Punch BestPunch { get; set; }
|
||||
|
||||
public Punch Vulnerability { get; set; }
|
||||
|
||||
public void SetName(string prompt)
|
||||
{
|
||||
Console.WriteLine(prompt);
|
||||
string? name;
|
||||
do
|
||||
{
|
||||
name = Console.ReadLine();
|
||||
} while (string.IsNullOrWhiteSpace(name));
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public int DamageTaken { get; set; }
|
||||
|
||||
public void ResetForNewRound() => DamageTaken = 0;
|
||||
|
||||
public void RecordWin() => _wins += 1;
|
||||
|
||||
public bool IsWinner => _wins >= 2;
|
||||
|
||||
public override string ToString() => Name;
|
||||
}
|
||||
|
||||
public class Opponent : Boxer
|
||||
{
|
||||
public void SetRandomPunches()
|
||||
{
|
||||
do
|
||||
{
|
||||
BestPunch = (Punch) GameUtils.Roll(4); // B1
|
||||
Vulnerability = (Punch) GameUtils.Roll(4); // D1
|
||||
} while (BestPunch == Vulnerability);
|
||||
}
|
||||
}
|
||||
10
15_Boxing/csharp/Boxing.csproj
Normal file
10
15_Boxing/csharp/Boxing.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
15_Boxing/csharp/Boxing.sln
Normal file
22
15_Boxing/csharp/Boxing.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}") = "Boxing", "Boxing.csproj", "{52A7BDE5-3085-4F58-AC57-2BA4E65212D8}"
|
||||
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
|
||||
{52A7BDE5-3085-4F58-AC57-2BA4E65212D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{52A7BDE5-3085-4F58-AC57-2BA4E65212D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{52A7BDE5-3085-4F58-AC57-2BA4E65212D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{52A7BDE5-3085-4F58-AC57-2BA4E65212D8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
115
15_Boxing/csharp/OpponentAttackStrategy.cs
Normal file
115
15_Boxing/csharp/OpponentAttackStrategy.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using static Boxing.GameUtils;
|
||||
using static System.Console;
|
||||
|
||||
namespace Boxing;
|
||||
|
||||
public class OpponentAttackStrategy : AttackStrategy
|
||||
{
|
||||
private readonly Opponent _opponent;
|
||||
|
||||
public OpponentAttackStrategy(Opponent opponent, Boxer player, Action notifyGameEnded, Stack<Action> work) : base(player, work, notifyGameEnded)
|
||||
{
|
||||
_opponent = opponent;
|
||||
}
|
||||
|
||||
protected override AttackPunch GetPunch()
|
||||
{
|
||||
var punch = (Punch)Roll(4);
|
||||
return new AttackPunch(punch, punch == _opponent.BestPunch);
|
||||
}
|
||||
|
||||
protected override void FullSwing() // 720
|
||||
{
|
||||
Write($"{_opponent} TAKES A FULL SWING AND");
|
||||
if (Other.Vulnerability == Punch.FullSwing)
|
||||
{
|
||||
ScoreFullSwing();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RollSatisfies(60, x => x < 30))
|
||||
{
|
||||
WriteLine(" IT'S BLOCKED!");
|
||||
}
|
||||
else
|
||||
{
|
||||
ScoreFullSwing();
|
||||
}
|
||||
}
|
||||
|
||||
void ScoreFullSwing()
|
||||
{
|
||||
WriteLine(" POW!!!!! HE HITS HIM RIGHT IN THE FACE!");
|
||||
if (Other.DamageTaken > KnockoutDamageThreshold)
|
||||
{
|
||||
Work.Push(RegisterOtherKnockedOut);
|
||||
}
|
||||
Other.DamageTaken += 15;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Hook() // 810
|
||||
{
|
||||
Write($"{_opponent} GETS {Other} IN THE JAW (OUCH!)");
|
||||
Other.DamageTaken += 7;
|
||||
WriteLine("....AND AGAIN!");
|
||||
Other.DamageTaken += 5;
|
||||
if (Other.DamageTaken > KnockoutDamageThreshold)
|
||||
{
|
||||
Work.Push(RegisterOtherKnockedOut);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Uppercut() // 860
|
||||
{
|
||||
Write($"{Other} IS ATTACKED BY AN UPPERCUT (OH,OH)...");
|
||||
if (Other.Vulnerability == Punch.Uppercut)
|
||||
{
|
||||
ScoreUppercut();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RollSatisfies(200, x => x > 75))
|
||||
{
|
||||
WriteLine($" BLOCKS AND HITS {_opponent} WITH A HOOK.");
|
||||
_opponent.DamageTaken += 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScoreUppercut();
|
||||
}
|
||||
}
|
||||
|
||||
void ScoreUppercut()
|
||||
{
|
||||
WriteLine($"AND {_opponent} CONNECTS...");
|
||||
Other.DamageTaken += 8;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Jab() // 640
|
||||
{
|
||||
Write($"{_opponent} JABS AND ");
|
||||
if (Other.Vulnerability == Punch.Jab)
|
||||
{
|
||||
ScoreJab();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RollSatisfies(7, x => x > 4))
|
||||
{
|
||||
WriteLine("BLOOD SPILLS !!!");
|
||||
ScoreJab();
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLine("IT'S BLOCKED!");
|
||||
}
|
||||
}
|
||||
|
||||
void ScoreJab() => Other.DamageTaken += 5;
|
||||
}
|
||||
|
||||
private void RegisterOtherKnockedOut()
|
||||
=> RegisterKnockout($"{Other} IS KNOCKED COLD AND {_opponent} IS THE WINNER AND CHAMP!");
|
||||
}
|
||||
121
15_Boxing/csharp/PlayerAttackStrategy.cs
Normal file
121
15_Boxing/csharp/PlayerAttackStrategy.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using static Boxing.GameUtils;
|
||||
using static System.Console;
|
||||
namespace Boxing;
|
||||
|
||||
public class PlayerAttackStrategy : AttackStrategy
|
||||
{
|
||||
private readonly Boxer _player;
|
||||
|
||||
public PlayerAttackStrategy(Boxer player, Opponent opponent, Action notifyGameEnded, Stack<Action> work)
|
||||
: base(opponent, work, notifyGameEnded) => _player = player;
|
||||
|
||||
protected override AttackPunch GetPunch()
|
||||
{
|
||||
var punch = GameUtils.GetPunch($"{_player}'S PUNCH");
|
||||
return new AttackPunch(punch, punch == _player.BestPunch);
|
||||
}
|
||||
|
||||
protected override void FullSwing() // 340
|
||||
{
|
||||
Write($"{_player} SWINGS AND ");
|
||||
if (Other.Vulnerability == Punch.FullSwing)
|
||||
{
|
||||
ScoreFullSwing();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RollSatisfies(30, x => x < 10))
|
||||
{
|
||||
ScoreFullSwing();
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLine("HE MISSES");
|
||||
}
|
||||
}
|
||||
|
||||
void ScoreFullSwing()
|
||||
{
|
||||
WriteLine("HE CONNECTS!");
|
||||
if (Other.DamageTaken > KnockoutDamageThreshold)
|
||||
{
|
||||
Work.Push(() => RegisterKnockout($"{Other} IS KNOCKED COLD AND {_player} IS THE WINNER AND CHAMP!"));
|
||||
}
|
||||
Other.DamageTaken += 15;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Uppercut() // 520
|
||||
{
|
||||
Write($"{_player} TRIES AN UPPERCUT ");
|
||||
if (Other.Vulnerability == Punch.Uppercut)
|
||||
{
|
||||
ScoreUpperCut();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RollSatisfies(100, x => x < 51))
|
||||
{
|
||||
ScoreUpperCut();
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLine("AND IT'S BLOCKED (LUCKY BLOCK!)");
|
||||
}
|
||||
}
|
||||
|
||||
void ScoreUpperCut()
|
||||
{
|
||||
WriteLine("AND HE CONNECTS!");
|
||||
Other.DamageTaken += 4;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Hook() // 450
|
||||
{
|
||||
Write($"{_player} GIVES THE HOOK... ");
|
||||
if (Other.Vulnerability == Punch.Hook)
|
||||
{
|
||||
ScoreHookOnOpponent();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RollSatisfies(2, x => x == 1))
|
||||
{
|
||||
WriteLine("BUT IT'S BLOCKED!!!!!!!!!!!!!");
|
||||
}
|
||||
else
|
||||
{
|
||||
ScoreHookOnOpponent();
|
||||
}
|
||||
}
|
||||
|
||||
void ScoreHookOnOpponent()
|
||||
{
|
||||
WriteLine("CONNECTS...");
|
||||
Other.DamageTaken += 7;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Jab()
|
||||
{
|
||||
WriteLine($"{_player} JABS AT {Other}'S HEAD");
|
||||
if (Other.Vulnerability == Punch.Jab)
|
||||
{
|
||||
ScoreJabOnOpponent();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RollSatisfies(8, x => x < 4))
|
||||
{
|
||||
WriteLine("IT'S BLOCKED.");
|
||||
}
|
||||
else
|
||||
{
|
||||
ScoreJabOnOpponent();
|
||||
}
|
||||
}
|
||||
|
||||
void ScoreJabOnOpponent() => Other.DamageTaken += 3;
|
||||
}
|
||||
}
|
||||
29
15_Boxing/csharp/Program.cs
Normal file
29
15_Boxing/csharp/Program.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using Boxing;
|
||||
using static Boxing.GameUtils;
|
||||
using static System.Console;
|
||||
|
||||
WriteLine(new string('\t', 33) + "BOXING");
|
||||
WriteLine(new string('\t', 15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
|
||||
WriteLine("{0}{0}{0}BOXING OLYMPIC STYLE (3 ROUNDS -- 2 OUT OF 3 WINS){0}", Environment.NewLine);
|
||||
|
||||
var opponent = new Opponent();
|
||||
opponent.SetName("WHAT IS YOUR OPPONENT'S NAME"); // J$
|
||||
var player = new Boxer();
|
||||
player.SetName("INPUT YOUR MAN'S NAME"); // L$
|
||||
|
||||
PrintPunchDescription();
|
||||
player.BestPunch = GetPunch("WHAT IS YOUR MANS BEST"); // B
|
||||
player.Vulnerability = GetPunch("WHAT IS HIS VULNERABILITY"); // D
|
||||
opponent.SetRandomPunches();
|
||||
WriteLine($"{opponent}'S ADVANTAGE IS {opponent.BestPunch.ToFriendlyString()} AND VULNERABILITY IS SECRET.");
|
||||
|
||||
|
||||
for (var i = 1; i <= 3; i ++) // R
|
||||
{
|
||||
var round = new Round(player, opponent, i);
|
||||
round.Start();
|
||||
round.CheckOpponentWin();
|
||||
round.CheckPlayerWin();
|
||||
if (round.GameEnded) break;
|
||||
}
|
||||
WriteLine("{0}{0}AND NOW GOODBYE FROM THE OLYMPIC ARENA.{0}", Environment.NewLine);
|
||||
9
15_Boxing/csharp/Punch.cs
Normal file
9
15_Boxing/csharp/Punch.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Boxing;
|
||||
|
||||
public enum Punch
|
||||
{
|
||||
FullSwing = 1,
|
||||
Hook = 2,
|
||||
Uppercut = 3,
|
||||
Jab = 4
|
||||
}
|
||||
96
15_Boxing/csharp/Round.cs
Normal file
96
15_Boxing/csharp/Round.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
namespace Boxing;
|
||||
|
||||
class Round
|
||||
{
|
||||
|
||||
private readonly Boxer _player;
|
||||
private readonly Boxer _opponent;
|
||||
private readonly int _round;
|
||||
private Stack<Action> _work = new();
|
||||
private readonly PlayerAttackStrategy _playerAttackStrategy;
|
||||
private readonly OpponentAttackStrategy _opponentAttackStrategy;
|
||||
|
||||
public bool GameEnded { get; private set; }
|
||||
|
||||
public Round(Boxer player, Opponent opponent, int round)
|
||||
{
|
||||
_player = player;
|
||||
_opponent = opponent;
|
||||
_round = round;
|
||||
_work.Push(ResetPlayers);
|
||||
_work.Push(CheckOpponentWin);
|
||||
_work.Push(CheckPlayerWin);
|
||||
|
||||
void NotifyGameEnded() => GameEnded = true;
|
||||
_playerAttackStrategy = new PlayerAttackStrategy(player, opponent, NotifyGameEnded, _work);
|
||||
_opponentAttackStrategy = new OpponentAttackStrategy(opponent, player, NotifyGameEnded, _work);
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
while (_work.Count > 0)
|
||||
{
|
||||
var action = _work.Pop();
|
||||
// This delay does not exist in the VB code but it makes a bit easier to follow the game.
|
||||
// I assume the computers at the time were slow enough
|
||||
// so that they did not need this delay...
|
||||
Thread.Sleep(300);
|
||||
action();
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckOpponentWin()
|
||||
{
|
||||
if (_opponent.IsWinner)
|
||||
{
|
||||
Console.WriteLine($"{_opponent} WINS (NICE GOING, {_opponent}).");
|
||||
GameEnded = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckPlayerWin()
|
||||
{
|
||||
if (_player.IsWinner)
|
||||
{
|
||||
Console.WriteLine($"{_player} AMAZINGLY WINS!!");
|
||||
GameEnded = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetPlayers()
|
||||
{
|
||||
_player.ResetForNewRound();
|
||||
_opponent.ResetForNewRound();
|
||||
_work.Push(RoundBegins);
|
||||
}
|
||||
|
||||
private void RoundBegins()
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"ROUND {_round} BEGINS...");
|
||||
_work.Push(CheckRoundWinner);
|
||||
for (var i = 0; i < 7; i++)
|
||||
{
|
||||
_work.Push(DecideWhoAttacks);
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckRoundWinner()
|
||||
{
|
||||
if (_opponent.DamageTaken > _player.DamageTaken)
|
||||
{
|
||||
Console.WriteLine($"{_player} WINS ROUND {_round}");
|
||||
_player.RecordWin();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"{_opponent} WINS ROUND {_round}");
|
||||
_opponent.RecordWin();
|
||||
}
|
||||
}
|
||||
|
||||
private void DecideWhoAttacks()
|
||||
{
|
||||
_work.Push( GameUtils.RollSatisfies(10, x => x > 5) ? _opponentAttackStrategy.Attack : _playerAttackStrategy.Attack );
|
||||
}
|
||||
}
|
||||
35
15_Boxing/csharp/Utils.cs
Normal file
35
15_Boxing/csharp/Utils.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace Boxing;
|
||||
public static class GameUtils
|
||||
{
|
||||
private static readonly Random Rnd = new((int) DateTime.UtcNow.Ticks);
|
||||
public static void PrintPunchDescription() =>
|
||||
Console.WriteLine($"DIFFERENT PUNCHES ARE: {PunchDesc(Punch.FullSwing)}; {PunchDesc(Punch.Hook)}; {PunchDesc(Punch.Uppercut)}; {PunchDesc(Punch.Jab)}.");
|
||||
|
||||
private static string PunchDesc(Punch punch) => $"({(int)punch}) {punch.ToFriendlyString()}";
|
||||
|
||||
public static Punch GetPunch(string prompt)
|
||||
{
|
||||
Console.WriteLine(prompt);
|
||||
Punch result;
|
||||
while (!Enum.TryParse(Console.ReadLine(), out result) || !Enum.IsDefined(typeof(Punch), result))
|
||||
{
|
||||
PrintPunchDescription();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Func<int, int> Roll { get; } = upperLimit => (int) (upperLimit * Rnd.NextSingle()) + 1;
|
||||
|
||||
public static bool RollSatisfies(int upperLimit, Predicate<int> predicate) => predicate(Roll(upperLimit));
|
||||
|
||||
public static string ToFriendlyString(this Punch punch)
|
||||
=> punch switch
|
||||
{
|
||||
Punch.FullSwing => "FULL SWING",
|
||||
Punch.Hook => "HOOK",
|
||||
Punch.Uppercut => "UPPERCUT",
|
||||
Punch.Jab => "JAB",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(punch), punch, null)
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,3 +1,13 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Perl](https://www.perl.org/)
|
||||
|
||||
Actually, this is not so much a port as a complete rewrite, making use of
|
||||
Perl's Posix time functionality. The calendar is for the current year (not
|
||||
1979), but you can get another year by specifying it on the command line, e.g.
|
||||
|
||||
`perl 21_Calendar/perl/calendar.pl 2001`
|
||||
|
||||
It *may* even produce output in languages other than English. But the
|
||||
leftmost column will still be Sunday, even in locales where it is
|
||||
typically Monday.
|
||||
|
||||
130
21_Calendar/perl/calendar.pl
Executable file
130
21_Calendar/perl/calendar.pl
Executable file
@@ -0,0 +1,130 @@
|
||||
#!/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 POSIX qw{ strftime };
|
||||
use Term::ReadLine; # Prompt and return user input
|
||||
use Time::Local ();
|
||||
|
||||
BEGIN {
|
||||
*time_gm =
|
||||
Time::Local->can( 'timegm_modern' ) ||
|
||||
Time::Local->can( 'timegm' );
|
||||
}
|
||||
|
||||
our $VERSION = '0.000_01';
|
||||
|
||||
use constant COLUMN_WIDTH => 6;
|
||||
use constant SECONDS_PER_DAY => 86400;
|
||||
|
||||
binmode STDOUT, ':encoding(utf-8)';
|
||||
|
||||
my $year = @ARGV ? $ARGV[0] : ( localtime )[5] + 1900;
|
||||
my $is_leap_year = is_leap_year( $year );
|
||||
my $year_len = 365 + $is_leap_year;
|
||||
print <<'EOD';
|
||||
CALENDAR
|
||||
Creative Computing Morristown, New Jersey
|
||||
|
||||
|
||||
EOD
|
||||
|
||||
my @mon_len = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
|
||||
$mon_len[1] += $is_leap_year;
|
||||
|
||||
foreach my $month ( 0 .. 11 ) {
|
||||
my $epoch = time_gm( 0, 0, 0, 1, $month, $year );
|
||||
my @start_time = gmtime( $epoch );
|
||||
my ( $week_day, $year_day ) = @start_time[ 6, 7 ];
|
||||
my $label = strftime( '%B %Y', @start_time );
|
||||
$label .= ' ' x ( ( 14 - length $label ) / 2 );
|
||||
printf "\n** %3d ****** %14s ****** %3d **\n",
|
||||
$year_day, $label, $year_len - $year_day;
|
||||
{
|
||||
my $day = 1 + ( 7 - $week_day ) % 7;
|
||||
foreach my $wd ( 0 .. 6 ) {
|
||||
my $ep = time_gm( 0, 0, 0, $day + $wd, $month, $year );
|
||||
printf '%*s', COLUMN_WIDTH, strftime( '%a', gmtime $ep );
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
say '*' x ( COLUMN_WIDTH * 7 );
|
||||
print ' ' x ( COLUMN_WIDTH * $week_day );
|
||||
my $month_day = 1;
|
||||
while ( $week_day < 7 ) {
|
||||
printf '%*d', COLUMN_WIDTH, $month_day++;
|
||||
$week_day++;
|
||||
}
|
||||
print "\n";
|
||||
$week_day = 0;
|
||||
while ( $month_day <= $mon_len[$month] ) {
|
||||
printf '%*d', COLUMN_WIDTH, $month_day++;
|
||||
$week_day++;
|
||||
unless ( $week_day % 7 ) {
|
||||
print "\n";
|
||||
$week_day = 0;
|
||||
}
|
||||
}
|
||||
print "\n" if $week_day;
|
||||
|
||||
}
|
||||
|
||||
sub is_leap_year {
|
||||
my ( $year ) = 1;
|
||||
return 0 if $year % 4;
|
||||
return 1 if $year % 100;
|
||||
return 0 if $year % 400;
|
||||
return 1;
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 TITLE
|
||||
|
||||
calendar - Play the game 'Calendar' from Basic Computer Games
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
calendar.pl
|
||||
|
||||
=head1 DETAILS
|
||||
|
||||
This Perl script is a port of calendar, which is the 21st
|
||||
entry in Basic Computer Games.
|
||||
|
||||
Actually, it is not so much a port as a complete rewrite, making use of
|
||||
Perl's Posix time functionality. The calendar is for the current year
|
||||
(not 1979), but you can get another year by specifying it on the command
|
||||
line, e.g.
|
||||
|
||||
perl 21_Calendar/perl/calendar.pl 2001
|
||||
|
||||
It B<may> even produce output in languages other than English. But the
|
||||
leftmost column will still be Sunday, even in locales where it is
|
||||
typically Monday.
|
||||
|
||||
=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 :
|
||||
77
25_Chief/python/Chief.py
Normal file
77
25_Chief/python/Chief.py
Normal file
@@ -0,0 +1,77 @@
|
||||
def print_lightning_bolt():
|
||||
|
||||
print('*'*36)
|
||||
n = 24
|
||||
while n > 16:
|
||||
print(' '*n + 'x x')
|
||||
n -=1
|
||||
print(' '*16 + 'x xxx')
|
||||
print(' '*15 + 'x x')
|
||||
print(' '*14+ 'xxx x')
|
||||
n -=1
|
||||
while n > 8:
|
||||
print(' '*n + 'x x')
|
||||
n -=1
|
||||
print(' '*8 + 'xx')
|
||||
print(' '*7 +'x')
|
||||
print('*'*36)
|
||||
|
||||
|
||||
def print_solution(n):
|
||||
|
||||
print('\n{} plus 3 gives {}. This Divided by 5 equals {}'.format(n, n+3, (n+3)/5))
|
||||
print('This times 8 gives {}. If we divide 5 and add 5.'.format(( (n+3)/5 )*8 ))
|
||||
print('We get {}, which, minus 1 equals {}'.format(( ((n+3)/5)*8)/5+5, ((((n+3)/5)*8)/5+5)-1 ))
|
||||
|
||||
def Game():
|
||||
print('\nTake a Number and ADD 3. Now, Divide this number by 5 and')
|
||||
print('multiply by 8. Now, Divide by 5 and add the same. Subtract 1')
|
||||
|
||||
resp = float(input('\nWhat do you have? '))
|
||||
comp_guess = (((resp - 4)*5)/8)*5 -3
|
||||
resp2 = input('\nI bet your number was {} was i right(Yes or No)? '.format(comp_guess))
|
||||
|
||||
if resp2 == 'Yes' or resp2 == 'YES' or resp2 == 'yes':
|
||||
print('\nHuh, I Knew I was unbeatable')
|
||||
print('And here is how i did it')
|
||||
print_solution(comp_guess)
|
||||
input('')
|
||||
|
||||
else:
|
||||
resp3 = float(input('\nHUH!! what was you original number? '))
|
||||
|
||||
if resp3 == comp_guess:
|
||||
print('\nThat was my guess, AHA i was right')
|
||||
print("Shamed to accept defeat i guess, don't worry you can master mathematics too")
|
||||
print('Here is how i did it')
|
||||
print_solution(comp_guess)
|
||||
input('')
|
||||
|
||||
else:
|
||||
print('\nSo you think you\'re so smart, EH?')
|
||||
print('Now, Watch')
|
||||
print_solution(resp3)
|
||||
|
||||
resp4 = input('\nNow do you believe me? ')
|
||||
|
||||
if resp4 == 'Yes' or resp4 == 'YES' or resp4 == 'yes':
|
||||
print('\nOk, Lets play again sometime bye!!!!')
|
||||
input('')
|
||||
|
||||
else:
|
||||
print('\nYOU HAVE MADE ME VERY MAD!!!!!')
|
||||
print("BY THE WRATH OF THE MATHEMATICS AND THE RAGE OF THE GODS")
|
||||
print("THERE SHALL BE LIGHTNING!!!!!!!")
|
||||
print_lightning_bolt()
|
||||
print('\nI Hope you believe me now, for your own sake')
|
||||
input('')
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
print('I am CHIEF NUMBERS FREEK, The GREAT INDIAN MATH GOD.')
|
||||
play = input('\nAre you ready to take the test you called me out for(Yes or No)? ')
|
||||
if play == 'Yes' or play == 'YES' or play == 'yes':
|
||||
Game()
|
||||
else:
|
||||
print('Ok, Nevermind. Let me go back to my great slumber, Bye')
|
||||
input('')
|
||||
226
30_Cube/java/src/Cube.java
Normal file
226
30_Cube/java/src/Cube.java
Normal file
@@ -0,0 +1,226 @@
|
||||
import java.io.PrintStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Scanner;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Game of Cube
|
||||
* <p>
|
||||
* Based on game of Cube at:
|
||||
* https://github.com/coding-horror/basic-computer-games/blob/main/30_Cube/cube.bas
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class Cube {
|
||||
|
||||
//Current player location
|
||||
private Location playerLocation;
|
||||
|
||||
//Current list of mines
|
||||
private Set<Location> mines;
|
||||
|
||||
//System input / output objects
|
||||
private PrintStream out;
|
||||
private Scanner scanner;
|
||||
|
||||
//Player's current money
|
||||
private int money;
|
||||
|
||||
/**
|
||||
* Entry point, creates a new Cube object and calls the play method
|
||||
* @param args Java execution arguments, not used in application
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
new Cube().play();
|
||||
}
|
||||
|
||||
public Cube() {
|
||||
out = System.out;
|
||||
scanner = new Scanner(System.in);
|
||||
money = 500;
|
||||
mines = new HashSet<>(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears mines and places 5 new mines on the board
|
||||
*/
|
||||
private void placeMines() {
|
||||
mines.clear();
|
||||
Random random = new Random();
|
||||
for(int i = 0; i < 5; i++) {
|
||||
int x = random.nextInt(1,4);
|
||||
int y = random.nextInt(1,4);
|
||||
int z = random.nextInt(1,4);
|
||||
mines.add(new Location(x,y,z));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the entire game until the player runs out of money or chooses to stop
|
||||
*/
|
||||
public void play() {
|
||||
out.println("DO YOU WANT TO SEE INSTRUCTIONS? (YES--1,NO--0)");
|
||||
if(readParsedBoolean()) {
|
||||
printInstructions();
|
||||
}
|
||||
do {
|
||||
placeMines();
|
||||
out.println("WANT TO MAKE A WAGER?");
|
||||
int wager = 0 ;
|
||||
|
||||
if(readParsedBoolean()) {
|
||||
out.println("HOW MUCH?");
|
||||
do {
|
||||
wager = Integer.parseInt(scanner.nextLine());
|
||||
if(wager > money) {
|
||||
out.println("TRIED TO FOOL ME; BET AGAIN");
|
||||
}
|
||||
} while(wager > money);
|
||||
}
|
||||
|
||||
playerLocation = new Location(1,1,1);
|
||||
while(playerLocation.x + playerLocation.y + playerLocation.z != 9) {
|
||||
out.println("\nNEXT MOVE");
|
||||
String input = scanner.nextLine();
|
||||
|
||||
String[] stringValues = input.split(",");
|
||||
|
||||
if(stringValues.length < 3) {
|
||||
out.println("ILLEGAL MOVE, YOU LOSE.");
|
||||
return;
|
||||
}
|
||||
|
||||
int x = Integer.parseInt(stringValues[0]);
|
||||
int y = Integer.parseInt(stringValues[1]);
|
||||
int z = Integer.parseInt(stringValues[2]);
|
||||
|
||||
Location location = new Location(x,y,z);
|
||||
|
||||
if(x < 1 || x > 3 || y < 1 || y > 3 || z < 1 || z > 3 || !isMoveValid(playerLocation,location)) {
|
||||
out.println("ILLEGAL MOVE, YOU LOSE.");
|
||||
return;
|
||||
}
|
||||
|
||||
playerLocation = location;
|
||||
|
||||
if(mines.contains(location)) {
|
||||
out.println("******BANG******");
|
||||
out.println("YOU LOSE!\n\n");
|
||||
money -= wager;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(wager > 0) {
|
||||
out.printf("YOU NOW HAVE %d DOLLARS\n",money);
|
||||
}
|
||||
|
||||
} while(money > 0 && doAnotherRound());
|
||||
|
||||
out.println("TOUGH LUCK!");
|
||||
out.println("\nGOODBYE.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the user whether they want to play another round
|
||||
* @return True if the player decides to play another round,
|
||||
* False if the player would not like to play again
|
||||
*/
|
||||
private boolean doAnotherRound() {
|
||||
if(money > 0) {
|
||||
out.println("DO YOU WANT TO TRY AGAIN?");
|
||||
return readParsedBoolean();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the instructions to the game, copied from the original code.
|
||||
*/
|
||||
public void printInstructions() {
|
||||
out.println("THIS IS A GAME IN WHICH YOU WILL BE PLAYING AGAINST THE");
|
||||
out.println("RANDOM DECISION OF THE COMPUTER. THE FIELD OF PLAY IS A");
|
||||
out.println("CUBE OF SIDE 3. ANY OF THE 27 LOCATIONS CAN BE DESIGNATED");
|
||||
out.println("BY INPUTTING THREE NUMBERS SUCH AS 2,3,1. AT THE START");
|
||||
out.println("YOU ARE AUTOMATICALLY AT LOCATION 1,1,1. THE OBJECT OF");
|
||||
out.println("THE GAME IS TO GET TO LOCATION 3,3,3. ONE MINOR DETAIL:");
|
||||
out.println("THE COMPUTER WILL PICK, AT RANDOM, 5 LOCATIONS AT WHICH");
|
||||
out.println("IT WILL PLANT LAND MINES. IF YOU HIT ONE OF THESE LOCATIONS");
|
||||
out.println("YOU LOSE. ONE OTHER DETAIL: YOU MAY MOVE ONLY ONE SPACE");
|
||||
out.println("IN ONE DIRECTION EACH MOVE. FOR EXAMPLE: FROM 1,1,2 YOU");
|
||||
out.println("MAY MOVE TO 2,1,2 OR 1,1,3. YOU MAY NOT CHANGE");
|
||||
out.println("TWO OF THE NUMBERS ON THE SAME MOVE. IF YOU MAKE AN ILLEGAL");
|
||||
out.println("MOVE, YOU LOSE AND THE COMPUTER TAKES THE MONEY YOU MAY");
|
||||
out.println("\n");
|
||||
out.println("ALL YES OR NO QUESTIONS WILL BE ANSWERED BY A 1 FOR YES");
|
||||
out.println("OR A 0 (ZERO) FOR NO.");
|
||||
out.println();
|
||||
out.println("WHEN STATING THE AMOUNT OF A WAGER, PRINT ONLY THE NUMBER");
|
||||
out.println("OF DOLLARS (EXAMPLE: 250) YOU ARE AUTOMATICALLY STARTED WITH");
|
||||
out.println("500 DOLLARS IN YOUR ACCOUNT.");
|
||||
out.println();
|
||||
out.println("GOOD LUCK!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the user to input a boolean value. This could either be (true,false), (1,0), (y,n), (yes,no), etc.
|
||||
* By default, it will return false
|
||||
* @return Parsed boolean value of the user input
|
||||
*/
|
||||
private boolean readParsedBoolean() {
|
||||
String in = scanner.nextLine();
|
||||
try {
|
||||
return in.toLowerCase().charAt(0) == 'y' || Boolean.parseBoolean(in) || Integer.parseInt(in) == 1;
|
||||
} catch(NumberFormatException exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a move is valid
|
||||
* @param from The point that the player is at
|
||||
* @param to The point that the player wishes to move to
|
||||
* @return True if the player is only moving, at most, 1 location in any direction, False if the move is invalid
|
||||
*/
|
||||
private boolean isMoveValid(Location from, Location to) {
|
||||
return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) + Math.abs(from.z - to.z) <= 1;
|
||||
}
|
||||
|
||||
public class Location {
|
||||
int x,y,z;
|
||||
|
||||
public Location(int x, int y, int z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/*
|
||||
For use in HashSet and checking if two Locations are the same
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Location location = (Location) o;
|
||||
|
||||
if (x != location.x) return false;
|
||||
if (y != location.y) return false;
|
||||
return z == location.z;
|
||||
}
|
||||
|
||||
/*
|
||||
For use in the HashSet to accordingly index the set
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = x;
|
||||
result = 31 * result + y;
|
||||
result = 31 * result + z;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +1,60 @@
|
||||
#!/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()
|
||||
output_title
|
||||
|
||||
loop do
|
||||
puts "----------"
|
||||
print_instructions
|
||||
setup_game
|
||||
puts
|
||||
game_loop
|
||||
break unless get_input_another_game
|
||||
end
|
||||
|
||||
printf("OK. HOPE YOU ENJOYED YOURSELF.\n")
|
||||
puts "OK. HOPE YOU ENJOYED YOURSELF."
|
||||
end
|
||||
|
||||
def output_title
|
||||
printf("--- DEPTH CHARGE ---\n")
|
||||
printf("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n")
|
||||
printf("\n")
|
||||
puts "--- DEPTH CHARGE ---"
|
||||
puts "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"
|
||||
puts
|
||||
end
|
||||
|
||||
def get_input_y_or_n(message)
|
||||
while true
|
||||
print(message)
|
||||
loop do
|
||||
print message
|
||||
|
||||
value = gets.chomp
|
||||
|
||||
if (value == 'Y' || value == 'y')
|
||||
if value.downcase == "y"
|
||||
return true
|
||||
elsif value == 'N' || value == 'n'
|
||||
elsif value.downcase == "n"
|
||||
return false
|
||||
end
|
||||
|
||||
printf("PLEASE ENTER Y/y OR N/n...\n\n")
|
||||
puts "PLEASE ENTER Y/y OR N/n..."
|
||||
puts
|
||||
end
|
||||
end
|
||||
|
||||
def get_input_positive_integer(message)
|
||||
|
||||
while true
|
||||
print(message)
|
||||
loop do
|
||||
print message
|
||||
value = gets.chomp
|
||||
if (value == 'd')
|
||||
debug_game()
|
||||
|
||||
if value == "d"
|
||||
debug_game
|
||||
next
|
||||
end
|
||||
|
||||
the_input = Integer(value) rescue nil
|
||||
the_input = Integer(value) rescue 0
|
||||
|
||||
if the_input == nil || the_input < 1
|
||||
printf("PLEASE ENTER A POSITIVE NUMBER\n\n")
|
||||
if the_input < 1
|
||||
puts "PLEASE ENTER A POSITIVE NUMBER"
|
||||
puts
|
||||
next
|
||||
|
||||
end
|
||||
|
||||
return the_input
|
||||
@@ -61,42 +62,39 @@ class DepthCharge
|
||||
end
|
||||
|
||||
def print_instructions
|
||||
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.
|
||||
puts <<~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
|
||||
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
|
||||
THE THIRD IS THE DEPTH (Z):
|
||||
SHALLOW < Z < DEEP
|
||||
|
||||
GOOD LUCK !
|
||||
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")
|
||||
puts "@enemy_x: %d" % @enemy_x
|
||||
puts "@enemy_y: %d" % @enemy_y
|
||||
puts "@enemy_z: %d" % @enemy_z
|
||||
puts "@num_tries: %d" % @num_tries
|
||||
puts "@trial: %d" % @trial
|
||||
puts
|
||||
end
|
||||
|
||||
def setup_game
|
||||
@search_area_dimension = get_input_positive_integer("DIMENSION OF SEARCH AREA: ")
|
||||
|
||||
@num_tries = Integer(
|
||||
Math.log(@search_area_dimension)/Math.log(2) + 1
|
||||
)
|
||||
setup_enemy()
|
||||
@num_tries = Integer(Math.log(@search_area_dimension) / Math.log(2) + 1)
|
||||
setup_enemy
|
||||
end
|
||||
|
||||
def setup_enemy
|
||||
@@ -113,32 +111,34 @@ GOOD LUCK !
|
||||
@shot_y = get_input_positive_integer("Y: ")
|
||||
@shot_z = get_input_positive_integer("Z: ")
|
||||
|
||||
if (
|
||||
(@enemy_x - @shot_x).abs \
|
||||
+ (@enemy_y - @shot_y).abs \
|
||||
+ (@enemy_z - @shot_z).abs \
|
||||
== 0
|
||||
)
|
||||
you_win()
|
||||
|
||||
distance = (@enemy_x - @shot_x).abs +
|
||||
(@enemy_y - @shot_y).abs +
|
||||
(@enemy_z - @shot_z).abs
|
||||
|
||||
if distance == 0
|
||||
you_win
|
||||
return
|
||||
else
|
||||
missed_shot()
|
||||
missed_shot
|
||||
end
|
||||
end
|
||||
|
||||
printf("\n")
|
||||
|
||||
you_lose()
|
||||
puts
|
||||
|
||||
you_lose
|
||||
end
|
||||
|
||||
def output_game_status
|
||||
printf("YOU HAVE %d SHOTS REMAINING.\n", @num_tries - @trial + 1)
|
||||
printf("TRIAL \#%d\n", @trial)
|
||||
puts "YOU HAVE %d SHOTS REMAINING." % @num_tries - @trial + 1
|
||||
puts "TRIAL \#%d" % @trial
|
||||
end
|
||||
|
||||
def you_win
|
||||
printf("\nB O O M ! ! YOU FOUND IT IN %d TRIES!\n\n", @trial )
|
||||
puts "\nB O O M ! ! YOU FOUND IT IN %d TRIES!" % @trial
|
||||
puts
|
||||
end
|
||||
|
||||
def missed_shot
|
||||
missed_directions = []
|
||||
|
||||
@@ -160,14 +160,13 @@ GOOD LUCK !
|
||||
missed_directions.push('TOO SHALLOW')
|
||||
end
|
||||
|
||||
printf("SONAR REPORTS SHOT WAS: \n")
|
||||
printf("%s\n", "\t" + missed_directions.join("\n\t"))
|
||||
puts "SONAR REPORTS SHOT WAS: "
|
||||
puts "\t#{missed_directions.join("\n\t")}"
|
||||
end
|
||||
|
||||
def you_lose
|
||||
printf("YOU HAVE BEEN TORPEDOED! ABANDON SHIP!\n")
|
||||
printf("THE SUBMARINE WAS AT %d %d %d\n", @enemy_x, @enemy_y, @enemy_z)
|
||||
|
||||
puts "YOU HAVE BEEN TORPEDOED! ABANDON SHIP!"
|
||||
puts "THE SUBMARINE WAS AT %d %d %d" % [@enemy_x, @enemy_y, @enemy_z]
|
||||
end
|
||||
|
||||
def get_input_another_game
|
||||
@@ -176,4 +175,4 @@ GOOD LUCK !
|
||||
end
|
||||
|
||||
game = DepthCharge.new
|
||||
game.run_game()
|
||||
game.run_game
|
||||
|
||||
38
33_Dice/vbnet/program.vb
Normal file
38
33_Dice/vbnet/program.vb
Normal file
@@ -0,0 +1,38 @@
|
||||
Imports System
|
||||
|
||||
Module Program
|
||||
Sub Main(args As String())
|
||||
Const header As String =
|
||||
" DICE
|
||||
CREATIVE COMPUTING MORRISTOWN, NEW JERSEY
|
||||
|
||||
|
||||
|
||||
THIS PROGRAM SIMULATES THE ROLLING OF A
|
||||
PAIR OF DICE.
|
||||
YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO
|
||||
/ROLL/ THE DICE. WATCH OUT, VERY LARGE NUMBERS TAKE
|
||||
A LONG TIME. IN PARTICULAR, NUMBERS OVER 5000."
|
||||
|
||||
Console.WriteLine(header)
|
||||
|
||||
Dim D6 As New Random()
|
||||
Dim continuePrompt As String = "YES"
|
||||
While continuePrompt = "YES"
|
||||
Console.Write($"{vbCrLf}HOW MANY ROLLS? ")
|
||||
Dim x As Integer = Convert.ToInt32(Console.ReadLine())
|
||||
Dim F = Enumerable.Repeat(0, 11).ToList()
|
||||
For s As Integer = 0 To x - 1
|
||||
F(D6.Next(6) + D6.Next(6)) += 1
|
||||
Next
|
||||
|
||||
Console.WriteLine($"{vbCrLf}TOTAL SPOTS NUMBER OF TIMES")
|
||||
For V As Integer = 0 To 10
|
||||
Console.WriteLine($" {V + 2}{vbTab,-8}{F(V)}")
|
||||
Next
|
||||
|
||||
Console.Write($"{vbCrLf}TRY AGAIN ")
|
||||
continuePrompt = Console.ReadLine().ToUpper()
|
||||
End While
|
||||
End Sub
|
||||
End Module
|
||||
197
36_Flip_Flop/csharp/FlipFlop.cs
Normal file
197
36_Flip_Flop/csharp/FlipFlop.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
// Flip Flop Game
|
||||
|
||||
PrintGameInfo();
|
||||
|
||||
bool startNewGame = true;
|
||||
|
||||
string[] board = new string[] { "X", "X", "X", "X", "X", "X", "X", "X", "X", "X" };
|
||||
|
||||
do
|
||||
{
|
||||
int stepsCount = 0;
|
||||
int lastMove = -1;
|
||||
int moveIndex;
|
||||
int gameSum;
|
||||
double gameEntropyRate = Rnd();
|
||||
bool toPlay = false;
|
||||
bool setNewBoard = true;
|
||||
|
||||
Print();
|
||||
Print("HERE IS THE STARTING LINE OF X'S.");
|
||||
Print();
|
||||
|
||||
do
|
||||
{
|
||||
bool illegalEntry;
|
||||
bool equalToLastMove;
|
||||
|
||||
if (setNewBoard)
|
||||
{
|
||||
PrintNewBoard();
|
||||
board = new string[] { "X", "X", "X", "X", "X", "X", "X", "X", "X", "X" };
|
||||
setNewBoard = false;
|
||||
toPlay = true;
|
||||
}
|
||||
|
||||
stepsCount++;
|
||||
gameSum = 0;
|
||||
|
||||
// Read User's move
|
||||
do
|
||||
{
|
||||
Write("INPUT THE NUMBER? ");
|
||||
var input = Console.ReadLine();
|
||||
illegalEntry = !int.TryParse(input, out moveIndex);
|
||||
|
||||
if (illegalEntry || moveIndex > 11)
|
||||
{
|
||||
illegalEntry = true;
|
||||
Print("ILLEGAL ENTRY--TRY AGAIN.");
|
||||
}
|
||||
}
|
||||
while (illegalEntry);
|
||||
|
||||
if (moveIndex == 11)
|
||||
{
|
||||
// Run new game, To start a new game at any point
|
||||
toPlay = false;
|
||||
stepsCount = 12;
|
||||
startNewGame = true;
|
||||
}
|
||||
|
||||
|
||||
if (moveIndex == 0)
|
||||
{
|
||||
// To reset the line to all X, same game
|
||||
setNewBoard = true;
|
||||
toPlay = false;
|
||||
}
|
||||
|
||||
if (toPlay)
|
||||
{
|
||||
board[moveIndex - 1] = board[moveIndex - 1] == "O" ? "X" : "O";
|
||||
|
||||
if (lastMove == moveIndex)
|
||||
{
|
||||
equalToLastMove = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
equalToLastMove = false;
|
||||
lastMove = moveIndex;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
moveIndex = equalToLastMove
|
||||
? GetMoveIndexWhenEqualeLastMove(moveIndex, gameEntropyRate)
|
||||
: GetMoveIndex(moveIndex, gameEntropyRate);
|
||||
|
||||
board[moveIndex] = board[moveIndex] == "O" ? "X" : "O";
|
||||
}
|
||||
while (lastMove == moveIndex && board[moveIndex] == "X");
|
||||
|
||||
PrintGameBoard(board);
|
||||
|
||||
foreach (var item in board)
|
||||
{
|
||||
if (item == "O")
|
||||
{
|
||||
gameSum++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (stepsCount < 12 && gameSum < 10);
|
||||
|
||||
if (toPlay)
|
||||
{
|
||||
PrintGameResult(gameSum, stepsCount);
|
||||
|
||||
Write("DO YOU WANT TO TRY ANOTHER PUZZLE ");
|
||||
|
||||
var toContinue = Console.ReadLine();
|
||||
|
||||
if (!string.IsNullOrEmpty(toContinue) && toContinue?.ToUpper()[0] == 'N')
|
||||
{
|
||||
startNewGame = false;
|
||||
}
|
||||
|
||||
Print();
|
||||
}
|
||||
}
|
||||
while (startNewGame);
|
||||
|
||||
void Print(string str = "") => Console.WriteLine(str);
|
||||
|
||||
void Write(string value) => Console.Write(value);
|
||||
|
||||
string Tab(int pos) => new(' ', pos);
|
||||
|
||||
double Rnd() => new Random().NextDouble();
|
||||
|
||||
int GetMoveIndex(int moveIndex, double gameEntropyRate)
|
||||
{
|
||||
double rate = Math.Tan(gameEntropyRate + moveIndex / gameEntropyRate - moveIndex) - Math.Sin(gameEntropyRate / moveIndex) + 336 * Math.Sin(8 * moveIndex);
|
||||
return Convert.ToInt32(Math.Floor(10 * (rate - Math.Floor(rate))));
|
||||
}
|
||||
|
||||
int GetMoveIndexWhenEqualeLastMove(int moveIndex, double gameEntropyRate)
|
||||
{
|
||||
double rate = 0.592 * (1 / Math.Tan(gameEntropyRate / moveIndex + gameEntropyRate)) / Math.Sin(moveIndex * 2 + gameEntropyRate) - Math.Cos(moveIndex);
|
||||
return Convert.ToInt32(Math.Floor(10 * (rate - Math.Floor(rate))));
|
||||
}
|
||||
|
||||
void PrintNewBoard()
|
||||
{
|
||||
Print("1 2 3 4 5 6 7 8 9 10");
|
||||
Print("X X X X X X X X X X");
|
||||
Print();
|
||||
}
|
||||
|
||||
void PrintGameBoard(string[] board)
|
||||
{
|
||||
Print("1 2 3 4 5 6 7 8 9 10");
|
||||
|
||||
foreach (var item in board)
|
||||
{
|
||||
Write($"{item} ");
|
||||
}
|
||||
|
||||
Print();
|
||||
Print();
|
||||
}
|
||||
|
||||
void PrintGameResult(int gameSum, int stepsCount)
|
||||
{
|
||||
if (gameSum == 10)
|
||||
{
|
||||
Print($"VERY GOOD. YOU GUESSED IT IN ONLY {stepsCount} GUESSES.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Print($"TRY HARDER NEXT TIME. IT TOOK YOU {stepsCount} GUESSES.");
|
||||
}
|
||||
}
|
||||
|
||||
void PrintGameInfo()
|
||||
{
|
||||
Print(Tab(32) + "FLIPFLOP");
|
||||
Print(Tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
|
||||
Print();
|
||||
Print("THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:");
|
||||
Print();
|
||||
|
||||
Print("X X X X X X X X X X");
|
||||
Print();
|
||||
Print("TO THIS:");
|
||||
Print();
|
||||
Print("O O O O O O O O O O");
|
||||
Print();
|
||||
|
||||
Print("BY TYPING THE 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).");
|
||||
}
|
||||
10
36_Flip_Flop/csharp/FlipFlop.csproj
Normal file
10
36_Flip_Flop/csharp/FlipFlop.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>
|
||||
25
36_Flip_Flop/csharp/FlipFlop.sln
Normal file
25
36_Flip_Flop/csharp/FlipFlop.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
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}") = "FlipFlop", "FlipFlop.csproj", "{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {108E5099-D7AA-4260-B587-1B1FE1AF6B54}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
162
36_Flip_Flop/ruby/flipflop.rb
Normal file
162
36_Flip_Flop/ruby/flipflop.rb
Normal file
@@ -0,0 +1,162 @@
|
||||
#A class representing the internal state of a single game of flip flop
|
||||
# state represents the list of X's (A in the original code)
|
||||
# guesses represents the number of guesses the user has made (C in the original code)
|
||||
# seed represents the random seed for an instance of the game (Q in the original code)
|
||||
Game = Struct.new(:state, :guesses, :seed) do
|
||||
|
||||
#The original BASIC program used 1 indexed arrays while Ruby has 0-indexed arrays.
|
||||
#We can't use 0 indexed arrays for the flip functions or we'll get divide by zero errors.
|
||||
#These convenience functions allow us to modify and access internal game state in a 1-indexed fashion
|
||||
def flip_letter(letter_number)
|
||||
index = letter_number -1
|
||||
if self.state[index] == 'X'
|
||||
self.state[index] = 'O'
|
||||
else
|
||||
self.state[index] = 'X'
|
||||
end
|
||||
end
|
||||
|
||||
def letter_at(letter_number)
|
||||
self.state[letter_number - 1]
|
||||
end
|
||||
end
|
||||
|
||||
def print_welcome
|
||||
puts 'FLIPFLOP'.center(72)
|
||||
puts 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY'.center(72)
|
||||
puts <<~EOS
|
||||
|
||||
THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:
|
||||
|
||||
X X X X X X X X X X
|
||||
|
||||
TO THIS:
|
||||
|
||||
O O O O O O O O O O
|
||||
|
||||
BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE
|
||||
LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON
|
||||
OTHERS, TWO WILL CHANGE. TO RESET LINE TO ALL X'S, TYPE 0
|
||||
(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE
|
||||
11 (ELEVEN).
|
||||
EOS
|
||||
end
|
||||
|
||||
def print_starting_message
|
||||
puts <<~EOS
|
||||
|
||||
HERE IS THE STARTING LINE OF X'S.
|
||||
|
||||
1 2 3 4 5 6 7 8 9 10
|
||||
X X X X X X X X X X
|
||||
|
||||
EOS
|
||||
end
|
||||
|
||||
#Create a new game with [X,X,X,X,X,X,X,X,X,X] as the state
|
||||
#0 as the number of guesses and a random seed between 0 and 1
|
||||
def generate_new_game
|
||||
Game.new(Array.new(10, 'X'), 0, rand())
|
||||
end
|
||||
|
||||
#Given a game, an index, and a shuffle function, flip one or more letters
|
||||
def shuffle_board(game, index, shuffle_function)
|
||||
n = method(shuffle_function).call(game, index)
|
||||
|
||||
if game.letter_at(n) == "O"
|
||||
game.flip_letter(n)
|
||||
if index == n
|
||||
n = shuffle_board(game, index, shuffle_function)
|
||||
end
|
||||
else
|
||||
game.flip_letter(n)
|
||||
end
|
||||
return n
|
||||
end
|
||||
|
||||
#Shuffle logic copied from original BASIC code
|
||||
def shuffle_function1(game, index)
|
||||
r = Math.tan(game.seed + index / game.seed - index) - Math.sin(game.seed / index) + 336 * Math.sin(8 * index)
|
||||
n = r - r.floor
|
||||
(10 * n).floor
|
||||
end
|
||||
|
||||
def shuffle_function2(game, index)
|
||||
r = 0.592 * (1/ Math.tan(game.seed / index + game.seed)) / Math.sin(index * 2 + game.seed) - Math.cos(index)
|
||||
n = r - r.floor
|
||||
(10 * n)
|
||||
end
|
||||
|
||||
def play_game
|
||||
print_starting_message
|
||||
game = generate_new_game
|
||||
working_index = nil
|
||||
|
||||
loop do
|
||||
puts "INPUT THE NUMBER"
|
||||
input = gets.chomp.downcase
|
||||
|
||||
#See if the user input a valid integer, fail otherwise
|
||||
if numeric_input = Integer(input, exception: false)
|
||||
|
||||
#If 11 is entered, we're done with this version of the game
|
||||
if numeric_input == 11
|
||||
return :restart
|
||||
end
|
||||
|
||||
if numeric_input > 11
|
||||
puts 'ILLEGAL ENTRY--TRY AGAIN.'
|
||||
next #illegal entries don't count towards your guesses
|
||||
end
|
||||
|
||||
if working_index == numeric_input
|
||||
game.flip_letter(numeric_input)
|
||||
working_index = shuffle_board(game, numeric_input, :shuffle_function2)
|
||||
#If 0 is entered, we want to reset the state, but not the random seed or number of guesses and keep playing
|
||||
elsif numeric_input == 0
|
||||
game.state = Array.new(10, 'X')
|
||||
elsif game.letter_at(numeric_input) == "O"
|
||||
game.flip_letter(numeric_input)
|
||||
if numeric_input == working_index
|
||||
working_index = shuffle_board(game, numeric_input, :shuffle_function1)
|
||||
end
|
||||
else
|
||||
game.flip_letter(numeric_input)
|
||||
working_index = shuffle_board(game, numeric_input, :shuffle_function1)
|
||||
end
|
||||
else
|
||||
puts 'ILLEGAL ENTRY--TRY AGAIN.'
|
||||
next #illegal entries don't count towards your guesses
|
||||
end
|
||||
|
||||
game.guesses += 1
|
||||
puts '1 2 3 4 5 6 7 8 9 10'
|
||||
puts game.state.join(' ')
|
||||
|
||||
if game.state.all? { |x| x == 'O' }
|
||||
if game.guesses > 12
|
||||
puts "TRY HARDER NEXT TIME. IT TOOK YOU #{game.guesses} GUESSES."
|
||||
else
|
||||
puts "VERY GOOD. YOU GUESSED IT IN ONLY #{game.guesses} GUESSES."
|
||||
end
|
||||
#game is complete
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#Execution starts
|
||||
print_welcome
|
||||
loop do
|
||||
result = play_game
|
||||
if result == :restart
|
||||
next
|
||||
end
|
||||
|
||||
puts 'DO YOU WANT TO TRY ANOTHER PUZZLE'
|
||||
if gets.chomp.downcase[0] == 'n'
|
||||
break
|
||||
end
|
||||
end
|
||||
@@ -1,183 +1,202 @@
|
||||
def GenRandom(C):
|
||||
C=int(random()*5)+1
|
||||
def BadInput850():
|
||||
print ( "\nHAMURABI: I CANNOT DO WHAT YOU WISH.")
|
||||
print ( "GET YOURSELF ANOTHER STEWARD!!!!!")
|
||||
Z=99
|
||||
def BadInput710(S):
|
||||
print ( "HAMURABI: THINK AGAIN. YOU HAVE ONLY")
|
||||
print ( S,"BUSHELS OF GRAIN. NOW THEN,")
|
||||
def BadInput720(A):
|
||||
print ( "HAMURABI: THINK AGAIN. YOU OWN ONLY",A,"ACRES. NOW THEN,")
|
||||
def BadInput710(S):
|
||||
print ( "HAMURABI: THINK AGAIN. YOU HAVE ONLY")
|
||||
print ( S,"BUSHELS OF GRAIN. NOW THEN,")
|
||||
def NationalFink():
|
||||
print ( "DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY")
|
||||
print ( "BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE")
|
||||
print ( "ALSO BEEN DECLARED NATIONAL FINK!!!!")
|
||||
|
||||
def B_input(promptstring): #emulate BASIC input. It rejects non-numeric values
|
||||
x=input(promptstring)
|
||||
while x.isalpha():
|
||||
x=input("?REDO FROM START\n? ")
|
||||
return int(x)
|
||||
|
||||
from random import random
|
||||
from random import seed
|
||||
|
||||
|
||||
def gen_random():
|
||||
return int(random() * 5) + 1
|
||||
|
||||
|
||||
def bad_input_850():
|
||||
print("\nHAMURABI: I CANNOT DO WHAT YOU WISH.")
|
||||
print("GET YOURSELF ANOTHER STEWARD!!!!!")
|
||||
Z = 99
|
||||
|
||||
|
||||
def bad_input_710(S):
|
||||
print("HAMURABI: THINK AGAIN. YOU HAVE ONLY")
|
||||
print(S, "BUSHELS OF GRAIN. NOW THEN,")
|
||||
|
||||
|
||||
def bad_input_720(A):
|
||||
print("HAMURABI: THINK AGAIN. YOU OWN ONLY", A, "ACRES. NOW THEN,")
|
||||
|
||||
|
||||
def national_fink():
|
||||
print("DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY")
|
||||
print("BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE")
|
||||
print("ALSO BEEN DECLARED NATIONAL FINK!!!!")
|
||||
|
||||
|
||||
def b_input(promptstring): # emulate BASIC input. It rejects non-numeric values
|
||||
x = input(promptstring)
|
||||
while x.isalpha():
|
||||
x = input("?REDO FROM START\n? ")
|
||||
return int(x)
|
||||
|
||||
|
||||
seed()
|
||||
title = "HAMURABI"
|
||||
title = title.rjust(32,' ')
|
||||
print (title)
|
||||
title = title.rjust(32, ' ')
|
||||
print(title)
|
||||
attribution = "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"
|
||||
attribution = attribution.rjust(15," ")
|
||||
print (attribution)
|
||||
print ('\n\n\n')
|
||||
print ("TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA")
|
||||
print ("FOR A TEN-YEAR TERM OF OFFICE.\n")
|
||||
D1=0
|
||||
P1=0
|
||||
Z=0 #year
|
||||
P=95 #population
|
||||
S=2800 #grain stores
|
||||
H=3000
|
||||
E=H-S #rats eaten
|
||||
Y=3 #yield (amount of production from land). Reused as price per acre
|
||||
A=H/Y #acres of land
|
||||
I=5 #immigrants
|
||||
Q=1 #boolean for plague, also input for buy/sell land
|
||||
D=0 # people
|
||||
while (Z<11): #line 270. main loop. while the year is less than 11
|
||||
print ("\n\n\nHAMURABI: I BEG TO REPORT TO YOU")
|
||||
Z=Z+1 #year
|
||||
print ( "IN YEAR",Z,",",D,"PEOPLE STARVED,",I,"CAME TO THE CITY,")
|
||||
P=P+I
|
||||
if Q==0:
|
||||
P=int(P/2)
|
||||
print ("A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED.")
|
||||
print ("POPULATION IS NOW",P)
|
||||
print ("THE CITY NOW OWNS",A,"ACRES.")
|
||||
print ("YOU HARVESTED",Y,"BUSHELS PER ACRE.")
|
||||
print ("THE RATS ATE",E,"BUSHELS.")
|
||||
print ("YOU NOW HAVE ",S,"BUSHELS IN STORE.\n")
|
||||
C=int(10*random()) #random number between 1 and 10
|
||||
Y=C+17
|
||||
print ("LAND IS TRADING AT",Y,"BUSHELS PER ACRE.")
|
||||
Q=-99 #dummy value to track status
|
||||
while Q==-99: #always run the loop once
|
||||
Q = B_input("HOW MANY ACRES DO YOU WISH TO BUY? ")
|
||||
if Q<0:
|
||||
Q = -1 #to avoid the corner case of Q=-99
|
||||
BadInput850()
|
||||
Z=99 #jump out of main loop and exit
|
||||
elif Y*Q>S: #can't afford it
|
||||
BadInput710(S)
|
||||
Q=-99 # give'm a second change to get it right
|
||||
elif Y*Q<=S: #normal case, can afford it
|
||||
A=A+Q #increase the number of acres by Q
|
||||
S=S-Y*Q #decrease the amount of grain in store to pay for it
|
||||
C=0 #WTF is C for?
|
||||
if Q ==0 and Z!=99: #maybe you want to sell some land?
|
||||
attribution = attribution.rjust(15, " ")
|
||||
print(attribution)
|
||||
print('\n\n\n')
|
||||
print("TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA")
|
||||
print("FOR A TEN-YEAR TERM OF OFFICE.\n")
|
||||
|
||||
D1 = 0
|
||||
P1 = 0
|
||||
Z = 0 # year
|
||||
P = 95 # population
|
||||
S = 2800 # grain stores
|
||||
H = 3000
|
||||
E = H - S # rats eaten
|
||||
Y = 3 # yield (amount of production from land). Reused as price per acre
|
||||
A = H / Y # acres of land
|
||||
I = 5 # immigrants
|
||||
Q = 1 # boolean for plague, also input for buy/sell land
|
||||
D = 0 # people
|
||||
|
||||
while Z < 11: # line 270. main loop. while the year is less than 11
|
||||
print("\n\n\nHAMURABI: I BEG TO REPORT TO YOU")
|
||||
Z = Z + 1 # year
|
||||
print("IN YEAR", Z, ",", D, "PEOPLE STARVED,", I, "CAME TO THE CITY,")
|
||||
P = P + I
|
||||
|
||||
if Q == 0:
|
||||
P = int(P / 2)
|
||||
print("A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED.")
|
||||
|
||||
print("POPULATION IS NOW", P)
|
||||
print("THE CITY NOW OWNS", A, "ACRES.")
|
||||
print("YOU HARVESTED", Y, "BUSHELS PER ACRE.")
|
||||
print("THE RATS ATE", E, "BUSHELS.")
|
||||
print("YOU NOW HAVE ", S, "BUSHELS IN STORE.\n")
|
||||
C = int(10 * random()) # random number between 1 and 10
|
||||
Y = C + 17
|
||||
print("LAND IS TRADING AT", Y, "BUSHELS PER ACRE.")
|
||||
|
||||
Q = -99 # dummy value to track status
|
||||
while Q == -99: # always run the loop once
|
||||
Q = b_input("HOW MANY ACRES DO YOU WISH TO BUY? ")
|
||||
if Q < 0:
|
||||
Q = -1 # to avoid the corner case of Q=-99
|
||||
bad_input_850()
|
||||
Z = 99 # jump out of main loop and exit
|
||||
elif Y * Q > S: # can't afford it
|
||||
bad_input_710(S)
|
||||
Q = -99 # give'm a second change to get it right
|
||||
elif Y * Q <= S: # normal case, can afford it
|
||||
A = A + Q # increase the number of acres by Q
|
||||
S = S - Y * Q # decrease the amount of grain in store to pay for it
|
||||
C = 0 # WTF is C for?
|
||||
|
||||
if Q == 0 and Z != 99: # maybe you want to sell some land?
|
||||
Q = -99
|
||||
while Q==-99:
|
||||
Q = B_input( "HOW MANY ACRES DO YOU WISH TO SELL? ")
|
||||
if Q<0:
|
||||
BadInput850()
|
||||
Z=99 #jump out of main loop and exit
|
||||
elif Q<=A:#normal case
|
||||
A=A-Q # reduce the acres
|
||||
S=S+Y*Q #add to grain stores
|
||||
C=0 #still don't know what C is for
|
||||
else: #Q>A error!
|
||||
BadInput720()
|
||||
Q=-99 #reloop
|
||||
print ("\n")
|
||||
Q=-99
|
||||
while Q==-99 and Z!=99:
|
||||
Q = B_input("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE? ")
|
||||
if Q<0:
|
||||
BadInput850()
|
||||
#REM *** TRYING TO USE MORE GRAIN THAN IS IN SILOS?
|
||||
elif Q>S:
|
||||
BadInput710
|
||||
Q=-99 #try again!
|
||||
else: #we're good. do the transaction
|
||||
S=S-Q #remove the grain from the stores
|
||||
C=1 #set the speed of light to 1. jk
|
||||
print ("\n")
|
||||
D=-99 #dummy value to force at least one loop
|
||||
while D == -99 and Z!=99:
|
||||
D = B_input("HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED? ")
|
||||
if D<0:
|
||||
BadInput850()
|
||||
Z=99
|
||||
elif D>0:
|
||||
if D>A:
|
||||
#REM *** TRYING TO PLANT MORE ACRES THAN YOU OWN?
|
||||
BadInput720(A)
|
||||
D = -99
|
||||
elif int(D/2)>S:
|
||||
#REM *** ENOUGH GRAIN FOR SEED?
|
||||
BadInput710(S)
|
||||
while Q == -99:
|
||||
Q = b_input("HOW MANY ACRES DO YOU WISH TO SELL? ")
|
||||
if Q < 0:
|
||||
bad_input_850()
|
||||
Z = 99 # jump out of main loop and exit
|
||||
elif Q <= A: # normal case
|
||||
A = A - Q # reduce the acres
|
||||
S = S + Y * Q # add to grain stores
|
||||
C = 0 # still don't know what C is for
|
||||
else: # Q>A error!
|
||||
bad_input_720(A)
|
||||
Q = -99 # reloop
|
||||
print("\n")
|
||||
|
||||
Q = -99
|
||||
while Q == -99 and Z != 99:
|
||||
Q = b_input("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE? ")
|
||||
if Q < 0:
|
||||
bad_input_850()
|
||||
# REM *** TRYING TO USE MORE GRAIN THAN IS IN SILOS?
|
||||
elif Q > S:
|
||||
bad_input_710(S)
|
||||
Q = -99 # try again!
|
||||
else: # we're good. do the transaction
|
||||
S = S - Q # remove the grain from the stores
|
||||
C = 1 # set the speed of light to 1. jk
|
||||
|
||||
print("\n")
|
||||
D = -99 # dummy value to force at least one loop
|
||||
while D == -99 and Z != 99:
|
||||
D = b_input("HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED? ")
|
||||
if D < 0:
|
||||
bad_input_850()
|
||||
Z = 99
|
||||
elif D > 0:
|
||||
if D > A:
|
||||
# REM *** TRYING TO PLANT MORE ACRES THAN YOU OWN?
|
||||
bad_input_720(A)
|
||||
D = -99
|
||||
elif D>=10*P:
|
||||
#REM *** ENOUGH PEOPLE TO TEND THE CROPS?
|
||||
print ("BUT YOU HAVE ONLY",P,"PEOPLE TO TEND THE FIELDS! NOW THEN,")
|
||||
D=-99
|
||||
else: #we're good. decrement the grain store
|
||||
S=S-int(D/2)
|
||||
GenRandom(C)
|
||||
#REM *** A BOUNTIFUL HARVEST!
|
||||
Y=C
|
||||
H=D*Y
|
||||
E=0
|
||||
GenRandom(C)
|
||||
if int(C/2)==C/2: #even number. 50/50 chance
|
||||
#REM *** RATS ARE RUNNING WILD!!
|
||||
E=int(S/C) #calc losses due to rats, based on previous random number
|
||||
S=S-E+H #deduct losses from stores
|
||||
GenRandom(C)
|
||||
#REM *** LET'S HAVE SOME BABIES
|
||||
I=int(C*(20*A+S)/P/100+1)
|
||||
#REM *** HOW MANY PEOPLE HAD FULL TUMMIES?
|
||||
C=int(Q/20)
|
||||
#REM *** HORROS, A 15% CHANCE OF PLAGUE
|
||||
#yeah, should be HORRORS, but left it
|
||||
Q=int(10*(2*random()-.3))
|
||||
if P>=C and Z!=99: #if there are some people without full bellies...
|
||||
#REM *** STARVE ENOUGH FOR IMPEACHMENT?
|
||||
D=P-C
|
||||
if D>.45*P:
|
||||
print ("\nYOU STARVED",D,"PEOPLE IN ONE YEAR!!!")
|
||||
NationalFink()
|
||||
Z=99 #exit the loop
|
||||
P1=((Z-1)*P1+D*100/P)/Z
|
||||
P=C
|
||||
D1=D1+D
|
||||
if Z!=99:
|
||||
print ( "IN YOUR 10-YEAR TERM OF OFFICE,",P1,"PERCENT OF THE")
|
||||
print ( "POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF")
|
||||
print ( D1,"PEOPLE DIED!!")
|
||||
L=A/P
|
||||
print ( "YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH")
|
||||
print ( L,"ACRES PER PERSON.\n")
|
||||
if (P1>33 or L<7):
|
||||
NationalFink()
|
||||
elif (P1>10 or L<9):
|
||||
print ( "YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.")
|
||||
print ( "THE PEOPLE (REMIANING) FIND YOU AN UNPLEASANT RULER, AND,")
|
||||
print ( "FRANKLY, HATE YOUR GUTS!!")
|
||||
elif (P1>3 or L<10):
|
||||
print ( "YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT")
|
||||
print ( "REALLY WASN'T TOO BAD AT ALL. ",int(P*.8*random()),"PEOPLE")
|
||||
print ( "WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR")
|
||||
print ( "TRIVIAL PROBLEMS.")
|
||||
else:
|
||||
print ( "A FANTASTIC PERFORMANCE!!! CHARLEMANGE, DISRAELI, AND")
|
||||
print ( "JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\n")
|
||||
for N in range(1,10):
|
||||
print ( '\a')
|
||||
elif int(D / 2) > S:
|
||||
# REM *** ENOUGH GRAIN FOR SEED?
|
||||
bad_input_710(S)
|
||||
D = -99
|
||||
elif D >= 10 * P:
|
||||
# REM *** ENOUGH PEOPLE TO TEND THE CROPS?
|
||||
print("BUT YOU HAVE ONLY", P, "PEOPLE TO TEND THE FIELDS! NOW THEN,")
|
||||
D = -99
|
||||
else: # we're good. decrement the grain store
|
||||
S = S - int(D / 2)
|
||||
|
||||
C = gen_random()
|
||||
# REM *** A BOUNTIFUL HARVEST!
|
||||
Y = C
|
||||
H = D * Y
|
||||
E = 0
|
||||
|
||||
C = gen_random()
|
||||
if int(C / 2) == C / 2: # even number. 50/50 chance
|
||||
# REM *** RATS ARE RUNNING WILD!!
|
||||
E = int(S / C) # calc losses due to rats, based on previous random number
|
||||
S = S - E + H # deduct losses from stores
|
||||
|
||||
C = gen_random()
|
||||
# REM *** LET'S HAVE SOME BABIES
|
||||
I = int(C * (20 * A + S) / P / 100 + 1)
|
||||
# REM *** HOW MANY PEOPLE HAD FULL TUMMIES?
|
||||
C = int(Q / 20)
|
||||
# REM *** HORROS, A 15% CHANCE OF PLAGUE
|
||||
# yeah, should be HORRORS, but left it
|
||||
Q = int(10 * (2 * random() - .3))
|
||||
if P >= C and Z != 99: # if there are some people without full bellies...
|
||||
# REM *** STARVE ENOUGH FOR IMPEACHMENT?
|
||||
D = P - C
|
||||
if D > .45 * P:
|
||||
print("\nYOU STARVED", D, "PEOPLE IN ONE YEAR!!!")
|
||||
national_fink()
|
||||
Z = 99 # exit the loop
|
||||
P1 = ((Z - 1) * P1 + D * 100 / P) / Z
|
||||
P = C
|
||||
D1 = D1 + D
|
||||
|
||||
if Z != 99:
|
||||
print("IN YOUR 10-YEAR TERM OF OFFICE,", P1, "PERCENT OF THE")
|
||||
print("POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF")
|
||||
print(D1, "PEOPLE DIED!!")
|
||||
L = A / P
|
||||
print("YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH")
|
||||
print(L, "ACRES PER PERSON.\n")
|
||||
if P1 > 33 or L < 7:
|
||||
national_fink()
|
||||
elif P1 > 10 or L < 9:
|
||||
print("YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.")
|
||||
print("THE PEOPLE (REMIANING) FIND YOU AN UNPLEASANT RULER, AND,")
|
||||
print("FRANKLY, HATE YOUR GUTS!!")
|
||||
elif P1 > 3 or L < 10:
|
||||
print("YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT")
|
||||
print("REALLY WASN'T TOO BAD AT ALL. ", int(P * .8 * random()), "PEOPLE")
|
||||
print("WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR")
|
||||
print("TRIVIAL PROBLEMS.")
|
||||
else:
|
||||
print("A FANTASTIC PERFORMANCE!!! CHARLEMANGE, DISRAELI, AND")
|
||||
print("JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\n")
|
||||
for N in range(1, 10):
|
||||
print('\a')
|
||||
|
||||
print("\nSO LONG FOR NOW.\n")
|
||||
|
||||
|
||||
|
||||
|
||||
2
48_High_IQ/d/.gitignore
vendored
Normal file
2
48_High_IQ/d/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.exe
|
||||
*.obj
|
||||
214
48_High_IQ/d/README.md
Normal file
214
48_High_IQ/d/README.md
Normal file
@@ -0,0 +1,214 @@
|
||||
Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Converted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).
|
||||
|
||||
## Running the code
|
||||
|
||||
Assuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:
|
||||
```shell
|
||||
dmd -dip1000 -run highiq.d
|
||||
```
|
||||
|
||||
[Other compilers](https://dlang.org/download.html) also exist.
|
||||
|
||||
|
||||
## Discussion
|
||||
|
||||
The original BASIC game code made use of calculus and clever choises of field IDs to determine the validity of moves.
|
||||
This is the original layout of IDs over the board:
|
||||
|
||||
```
|
||||
13 14 15
|
||||
|
||||
22 23 24
|
||||
|
||||
29 30 31 32 33 34 35
|
||||
|
||||
38 39 40 41 42 43 44
|
||||
|
||||
47 48 49 50 51 52 53
|
||||
|
||||
58 59 60
|
||||
|
||||
67 68 69
|
||||
```
|
||||
|
||||
This seems not very logical, because, wouldn't it make much more sense to let columns increase with 1 and rows increase
|
||||
with 10, so you'd get a consistent coordinate system? It seems that the original author's first step in validating
|
||||
moves was to check that moves jumped from one field over another one onto the next. He did this by making sure that
|
||||
adjacent IDs alter between even and odd horizontally *and* vertically. So a valid move was always from an even ID to an
|
||||
even ID *or* from an odd ID to an odd ID. So one of the checks that the BASIC code made was that the sum of both IDs
|
||||
was even. This is of course not a sufficient test, because moves that jump over three fields are illegal. Therefore the
|
||||
IDs seem to have been carefully laid oud so that the IDs increase with 1 horizontally, and 9 vertically, everywhere. So
|
||||
the only valid difference between IDs for a horizontal move was always 2, and the only valid difference for a vertical
|
||||
move was always 18.
|
||||
|
||||
Fact of the matter is, however, that checking for difference is sufficient and the even sum rule is superfluous, so
|
||||
there is no need for the peculiar distribution of field IDs. Therefore I have chosen the following more logical
|
||||
distribution:
|
||||
|
||||
```
|
||||
13 14 15
|
||||
|
||||
23 24 25
|
||||
|
||||
31 32 33 34 35 36 37
|
||||
|
||||
41 42 43 44 45 46 47
|
||||
|
||||
51 52 53 54 55 56 57
|
||||
|
||||
63 64 65
|
||||
|
||||
73 74 75
|
||||
```
|
||||
|
||||
As a consequence, the implementation of the game code has become much simpler; Not alone due to one less check, but due
|
||||
to the fact that conversions between IDs and board coordinates have become unnecessary and thus we can work with a single
|
||||
representation of the board state.
|
||||
|
||||
This version makes a prettier print of the board than the BASIC original, with coordinates for every move, and explains
|
||||
illegal moves.
|
||||
|
||||
|
||||
## Demo
|
||||
|
||||
```
|
||||
H-I-Q
|
||||
(After Creative Computing Morristown, New Jersey)
|
||||
|
||||
|
||||
Fields are identified by 2-digit numbers, each
|
||||
between 1 and 7. Example: the middle field is 44,
|
||||
the bottom middle is 74.
|
||||
|
||||
_1 _2 _3 _4 _5 _6 _7
|
||||
┌───┬───┬───┐
|
||||
1_ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┤
|
||||
2_ │ ■ │ ■ │ ■ │
|
||||
┌───┬───┼───┼───┼───┼───┬───┐
|
||||
3_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┼───┼───┼───┼───┤
|
||||
4_ │ ■ │ ■ │ ■ │ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┼───┼───┼───┼───┤
|
||||
5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
|
||||
└───┴───┼───┼───┼───┼───┴───┘
|
||||
6_ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┤
|
||||
7_ │ ■ │ ■ │ ■ │
|
||||
└───┴───┴───┘
|
||||
|
||||
Move which peg? 23
|
||||
The peg at 23 has nowhere to go. Try again.
|
||||
|
||||
Move which peg? 24
|
||||
To where? 34
|
||||
Field 34 is occupied. Try again.
|
||||
To where? 54
|
||||
Field 54 is occupied. Try again.
|
||||
To where? 44
|
||||
|
||||
_1 _2 _3 _4 _5 _6 _7
|
||||
┌───┬───┬───┐
|
||||
1_ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┤
|
||||
2_ │ ■ │ │ ■ │
|
||||
┌───┬───┼───┼───┼───┼───┬───┐
|
||||
3_ │ ■ │ ■ │ ■ │ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┼───┼───┼───┼───┤
|
||||
4_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┼───┼───┼───┼───┤
|
||||
5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
|
||||
└───┴───┼───┼───┼───┼───┴───┘
|
||||
6_ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┤
|
||||
7_ │ ■ │ ■ │ ■ │
|
||||
└───┴───┴───┘
|
||||
|
||||
Move which peg? 14
|
||||
The peg at 14 has nowhere to go. Try again.
|
||||
|
||||
Move which peg? 24
|
||||
There is no peg at 24. Try again.
|
||||
|
||||
Move which peg? 44
|
||||
The peg at 44 has nowhere to go. Try again.
|
||||
|
||||
Move which peg? 32
|
||||
To where? 22
|
||||
Field 22 is ouside the board. Try again.
|
||||
To where? 33
|
||||
Field 33 is occupied. Try again.
|
||||
To where? 34
|
||||
|
||||
_1 _2 _3 _4 _5 _6 _7
|
||||
┌───┬───┬───┐
|
||||
1_ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┤
|
||||
2_ │ ■ │ │ ■ │
|
||||
┌───┬───┼───┼───┼───┼───┬───┐
|
||||
3_ │ ■ │ │ │ ■ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┼───┼───┼───┼───┤
|
||||
4_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┼───┼───┼───┼───┤
|
||||
5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
|
||||
└───┴───┼───┼───┼───┼───┴───┘
|
||||
6_ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┤
|
||||
7_ │ ■ │ ■ │ ■ │
|
||||
└───┴───┴───┘
|
||||
|
||||
Move which peg? 44
|
||||
To where? 33
|
||||
You cannot move diagonally. Try again.
|
||||
To where? 24
|
||||
|
||||
_1 _2 _3 _4 _5 _6 _7
|
||||
┌───┬───┬───┐
|
||||
1_ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┤
|
||||
2_ │ ■ │ ■ │ ■ │
|
||||
┌───┬───┼───┼───┼───┼───┬───┐
|
||||
3_ │ ■ │ │ │ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┼───┼───┼───┼───┤
|
||||
4_ │ ■ │ ■ │ ■ │ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┼───┼───┼───┼───┤
|
||||
5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
|
||||
└───┴───┼───┼───┼───┼───┴───┘
|
||||
6_ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┤
|
||||
7_ │ ■ │ ■ │ ■ │
|
||||
└───┴───┴───┘
|
||||
|
||||
Move which peg? 36
|
||||
To where? 33
|
||||
You can't jump that far. Try again.
|
||||
To where? 35
|
||||
Field 35 is occupied. Try again.
|
||||
To where? 34
|
||||
|
||||
_1 _2 _3 _4 _5 _6 _7
|
||||
┌───┬───┬───┐
|
||||
1_ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┤
|
||||
2_ │ ■ │ ■ │ ■ │
|
||||
┌───┬───┼───┼───┼───┼───┬───┐
|
||||
3_ │ ■ │ │ │ ■ │ │ │ ■ │
|
||||
├───┼───┼───┼───┼───┼───┼───┤
|
||||
4_ │ ■ │ ■ │ ■ │ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┼───┼───┼───┼───┤
|
||||
5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
|
||||
└───┴───┼───┼───┼───┼───┴───┘
|
||||
6_ │ ■ │ ■ │ ■ │
|
||||
├───┼───┼───┤
|
||||
7_ │ ■ │ ■ │ ■ │
|
||||
└───┴───┴───┘
|
||||
|
||||
Move which peg? 46
|
||||
To where? 36
|
||||
You need to jump over another peg. Try again.
|
||||
To where? down
|
||||
Field 00 is ouside the board. Try again.
|
||||
To where?
|
||||
```
|
||||
238
48_High_IQ/d/highiq.d
Normal file
238
48_High_IQ/d/highiq.d
Normal file
@@ -0,0 +1,238 @@
|
||||
@safe: // Make @safe the default for this file, enforcing memory-safety.
|
||||
import std;
|
||||
|
||||
void main()
|
||||
{
|
||||
enum width = 50;
|
||||
writeln(center("H-I-Q", width));
|
||||
writeln(center("(After Creative Computing Morristown, New Jersey)\n\n", width));
|
||||
writeln(wrap("Fields are identified by 2-digit numbers, each between 1 and 7. " ~
|
||||
"Example: the middle field is 44, the bottom middle is 74.", width));
|
||||
|
||||
Board board;
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (!board.isGameOver)
|
||||
{
|
||||
writeln(board); // Calls board.toString().
|
||||
board.makeMove;
|
||||
}
|
||||
writeln(board, "\nThe game is over.\nYou had ", board.numPegs, " pieces remaining.");
|
||||
if (board.numPegs == 1)
|
||||
writeln("Bravo! You made a perfect score!\n",
|
||||
"Make a screen dump as a record of your accomplishment!\n");
|
||||
write("Play again? (Yes or No) ");
|
||||
if (readString.toLower != "yes")
|
||||
break;
|
||||
writeln; writeln;
|
||||
board = Board.init;
|
||||
}
|
||||
writeln("\nSo long for now.\n");
|
||||
}
|
||||
|
||||
/// Representation of the game board with pegs.
|
||||
struct Board
|
||||
{
|
||||
enum {outside, taken, empty};
|
||||
int[8][8] state = [
|
||||
1: [ 3: taken, 4: taken, 5: taken],
|
||||
2: [ 3: taken, 4: taken, 5: taken],
|
||||
3: [1: taken, 2: taken, 3: taken, 4: taken, 5: taken, 6: taken, 7: taken],
|
||||
4: [1: taken, 2: taken, 3: taken, 4: empty, 5: taken, 6: taken, 7: taken],
|
||||
5: [1: taken, 2: taken, 3: taken, 4: taken, 5: taken, 6: taken, 7: taken],
|
||||
6: [ 3: taken, 4: taken, 5: taken],
|
||||
7: [ 3: taken, 4: taken, 5: taken]
|
||||
]; // Row 0 and column 0 are unused. Default is 0 (outside).
|
||||
|
||||
/// Returns a string representing the board and its current state.
|
||||
string toString() const
|
||||
{
|
||||
dchar[][] lines = [(" _1 _2 _3 _4 _5 _6 _7 ").to!(dchar[]),
|
||||
(" ┌───┬───┬───┐ ").to!(dchar[]),
|
||||
(" 1_ │ │ │ │ ").to!(dchar[]),
|
||||
(" ├───┼───┼───┤ ").to!(dchar[]),
|
||||
(" 2_ │ │ │ │ ").to!(dchar[]),
|
||||
(" ┌───┬───┼───┼───┼───┼───┬───┐").to!(dchar[]),
|
||||
(" 3_ │ │ │ │ │ │ │ │").to!(dchar[]),
|
||||
(" ├───┼───┼───┼───┼───┼───┼───┤").to!(dchar[]),
|
||||
(" 4_ │ │ │ │ │ │ │ │").to!(dchar[]),
|
||||
(" ├───┼───┼───┼───┼───┼───┼───┤").to!(dchar[]),
|
||||
(" 5_ │ │ │ │ │ │ │ │").to!(dchar[]),
|
||||
(" └───┴───┼───┼───┼───┼───┴───┘").to!(dchar[]),
|
||||
(" 6_ │ │ │ │ ").to!(dchar[]),
|
||||
(" ├───┼───┼───┤ ").to!(dchar[]),
|
||||
(" 7_ │ │ │ │ ").to!(dchar[]),
|
||||
(" └───┴───┴───┘ ").to!(dchar[])];
|
||||
foreach (y, row; state)
|
||||
foreach (x, field; row)
|
||||
if (field == taken)
|
||||
lines[y * 2][x * 4 + 2] = '■';
|
||||
return lines.join("\n").to!string;
|
||||
}
|
||||
|
||||
/// Tests for possible moves.
|
||||
bool isGameOver() const
|
||||
{
|
||||
foreach (r, row; state)
|
||||
foreach (c, field; row)
|
||||
if (field == taken && canMoveFrom(r, c))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool canMoveFrom(int row, int col) const
|
||||
{
|
||||
if (row >= 3 && state[row - 2][col] == empty) // Up
|
||||
return state[row - 1][col] == taken;
|
||||
if (row <= 5 && state[row + 2][col] == empty) // Down
|
||||
return state[row + 1][col] == taken;
|
||||
if (col >= 3 && state[row][col - 2] == empty) // Left
|
||||
return state[row][col - 1] == taken;
|
||||
if (col <= 5 && state[row][col + 2] == empty) // Right
|
||||
return state[row][col + 1] == taken;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Asks for input, validates the move and updates the board.
|
||||
void makeMove()
|
||||
{
|
||||
bool isOutside(int row, int col)
|
||||
{
|
||||
if (row < 1 || row > 7 ||
|
||||
col < 1 || col > 7 ||
|
||||
state[row][col] == outside)
|
||||
{
|
||||
writeln("Field ", row, col, " is ouside the board. Try again.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
auto from = (){
|
||||
while (true)
|
||||
{
|
||||
write("\nMove which peg? ");
|
||||
int field = readInt;
|
||||
int row = field / 10, col = field % 10;
|
||||
if (isOutside(row, col))
|
||||
continue;
|
||||
if (state[row][col] != taken)
|
||||
{
|
||||
writeln("There is no peg at ", field, ". Try again.");
|
||||
continue;
|
||||
}
|
||||
if (!canMoveFrom(row, col))
|
||||
{
|
||||
writeln("The peg at ", field, " has nowhere to go. Try again.");
|
||||
continue;
|
||||
}
|
||||
return tuple!("row", "col")(row, col);
|
||||
}
|
||||
}();
|
||||
auto to = (){
|
||||
while (true)
|
||||
{
|
||||
write("To where? ");
|
||||
int field = readInt;
|
||||
int row = field / 10, col = field % 10;
|
||||
if (isOutside(row, col))
|
||||
continue;
|
||||
if (state[row][col] == taken)
|
||||
{
|
||||
writeln("Field ", field, " is occupied. Try again.");
|
||||
continue;
|
||||
}
|
||||
if (row != from.row && col != from.col)
|
||||
{
|
||||
writeln("You cannot move diagonally. Try again.");
|
||||
continue;
|
||||
}
|
||||
if (row == from.row && col == from.col)
|
||||
{
|
||||
writeln("You aren't going anywhere. Try again.");
|
||||
continue;
|
||||
}
|
||||
if (abs(row - from.row) + abs(col - from.col) > 2)
|
||||
{
|
||||
writeln("You can't jump that far. Try again.");
|
||||
continue;
|
||||
}
|
||||
if (abs(row - from.row) + abs(col - from.col) < 2 ||
|
||||
state[(row + from.row) / 2][(col + from.col) / 2] != taken)
|
||||
{
|
||||
writeln("You need to jump over another peg. Try again.");
|
||||
continue;
|
||||
}
|
||||
return tuple!("row", "col")(row, col);
|
||||
}
|
||||
}();
|
||||
// The move is legal. Update the board state.
|
||||
state[from.row][from.col] = empty;
|
||||
state[ to.row][ to.col] = taken;
|
||||
state[(from.row + to.row) / 2][(from.col + to.col) / 2] = empty;
|
||||
writeln;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of remaining pegs on the board.
|
||||
int numPegs() const
|
||||
{
|
||||
int num = 0;
|
||||
foreach (row; state)
|
||||
foreach (field; row)
|
||||
if (field == taken)
|
||||
num++;
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads an integer from standard input.
|
||||
int readInt() nothrow
|
||||
{
|
||||
try
|
||||
return readString.to!int;
|
||||
catch (Exception) // Not an integer.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Reads a string from standard input.
|
||||
string readString() nothrow
|
||||
{
|
||||
try
|
||||
return trustedReadln.strip;
|
||||
catch (Exception) // readln throws on I/O and Unicode errors, which we handle here.
|
||||
return "";
|
||||
}
|
||||
|
||||
/** An @trusted wrapper around readln.
|
||||
*
|
||||
* This is the only function that formally requires manual review for memory-safety.
|
||||
* [Arguably readln should be safe already](https://forum.dlang.org/post/rab398$1up$1@digitalmars.com)
|
||||
* which would remove the need to have any @trusted code in this program.
|
||||
*/
|
||||
string trustedReadln() @trusted
|
||||
{
|
||||
return readln;
|
||||
}
|
||||
|
||||
version (Windows)
|
||||
{
|
||||
// Make the Windows console do a better job at printing UTF-8 strings,
|
||||
// and restore the default upon termination.
|
||||
|
||||
import core.sys.windows.windows;
|
||||
|
||||
shared static this() @trusted
|
||||
{
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
}
|
||||
|
||||
shared static ~this() @trusted
|
||||
{
|
||||
SetConsoleOutputCP(GetACP);
|
||||
}
|
||||
}
|
||||
153
48_High_IQ/java/src/HighIQ.java
Normal file
153
48_High_IQ/java/src/HighIQ.java
Normal file
@@ -0,0 +1,153 @@
|
||||
import java.io.PrintStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* Game of HighIQ
|
||||
* <p>
|
||||
* Based on the Basic Game of HighIQ Here:
|
||||
* https://github.com/coding-horror/basic-computer-games/blob/main/48_High_IQ/highiq.bas
|
||||
*
|
||||
* No additional functionality has been added
|
||||
*/
|
||||
public class HighIQ {
|
||||
|
||||
//Game board, as a map of position numbers to their values
|
||||
private final Map<Integer, Boolean> board;
|
||||
|
||||
//Output stream
|
||||
private final PrintStream out;
|
||||
|
||||
//Input scanner to use
|
||||
private final Scanner scanner;
|
||||
|
||||
|
||||
public HighIQ(Scanner scanner) {
|
||||
out = System.out;
|
||||
this.scanner = scanner;
|
||||
board = new HashMap<>();
|
||||
|
||||
//Set of all locations to put initial pegs on
|
||||
int[] locations = new int[]{
|
||||
13, 14, 15, 22, 23, 24, 29, 30, 31, 32, 33, 34, 35, 38, 39, 40, 42, 43, 44, 47, 48, 49, 50, 51, 52, 53, 58, 59, 60, 67, 68, 69
|
||||
};
|
||||
|
||||
for (int i : locations) {
|
||||
board.put(i, true);
|
||||
}
|
||||
|
||||
board.put(41, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the actual game, from start to finish.
|
||||
*/
|
||||
public void play() {
|
||||
do {
|
||||
printBoard();
|
||||
while (!move()) {
|
||||
out.println("ILLEGAL MOVE, TRY AGAIN...");
|
||||
}
|
||||
} while (!isGameFinished());
|
||||
|
||||
int pegCount = 0;
|
||||
for (Integer key : board.keySet()) {
|
||||
if (board.getOrDefault(key, false)) {
|
||||
pegCount++;
|
||||
}
|
||||
}
|
||||
|
||||
out.println("YOU HAD " + pegCount + " PEGS REMAINING");
|
||||
|
||||
if (pegCount == 1) {
|
||||
out.println("BRAVO! YOU MADE A PERFECT SCORE!");
|
||||
out.println("SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an individual move
|
||||
* @return True if the move was valid, false if the user made an error and the move is invalid
|
||||
*/
|
||||
public boolean move() {
|
||||
out.println("MOVE WHICH PIECE");
|
||||
int from = scanner.nextInt();
|
||||
|
||||
//using the getOrDefault, which will make the statement false if it is an invalid position
|
||||
if (!board.getOrDefault(from, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
out.println("TO WHERE");
|
||||
int to = scanner.nextInt();
|
||||
|
||||
if (board.getOrDefault(to, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Do nothing if they are the same
|
||||
if (from == to) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//using the difference to check if the relative locations are valid
|
||||
int difference = Math.abs(to - from);
|
||||
if (difference != 2 && difference != 18) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//check if there is a peg between from and to
|
||||
if (!board.getOrDefault((to + from) / 2, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Actually move
|
||||
board.put(from,false);
|
||||
board.put(to,true);
|
||||
board.put((from + to) / 2, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the game is finished
|
||||
* @return True if there are no more moves, False otherwise
|
||||
*/
|
||||
public boolean isGameFinished() {
|
||||
for (Integer key : board.keySet()) {
|
||||
if (board.get(key)) {
|
||||
//Spacing is either 1 or 9
|
||||
//Looking to the right and down from every point, checking for both directions of movement
|
||||
for (int space : new int[]{1, 9}) {
|
||||
Boolean nextToPeg = board.getOrDefault(key + space, false);
|
||||
Boolean hasMovableSpace = !board.getOrDefault(key - space, true) || !board.getOrDefault(key + space * 2, true);
|
||||
if (nextToPeg && hasMovableSpace) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void printBoard() {
|
||||
for (int i = 0; i < 7; i++) {
|
||||
for (int j = 11; j < 18; j++) {
|
||||
out.print(getChar(j + 9 * i));
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
|
||||
private char getChar(int position) {
|
||||
Boolean value = board.get(position);
|
||||
if (value == null) {
|
||||
return ' ';
|
||||
} else if (value) {
|
||||
return '!';
|
||||
} else {
|
||||
return 'O';
|
||||
}
|
||||
}
|
||||
}
|
||||
37
48_High_IQ/java/src/HighIQGame.java
Normal file
37
48_High_IQ/java/src/HighIQGame.java
Normal file
@@ -0,0 +1,37 @@
|
||||
import java.util.Scanner;
|
||||
|
||||
public class HighIQGame {
|
||||
public static void main(String[] args) {
|
||||
|
||||
printInstructions();
|
||||
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
do {
|
||||
new HighIQ(scanner).play();
|
||||
System.out.println("PLAY AGAIN (YES OR NO)");
|
||||
} while(scanner.nextLine().equalsIgnoreCase("yes"));
|
||||
}
|
||||
|
||||
public static void printInstructions() {
|
||||
System.out.println("\t\t\t H-I-Q");
|
||||
System.out.println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
|
||||
System.out.println("HERE IS THE BOARD:");
|
||||
System.out.println(" ! ! !");
|
||||
System.out.println(" 13 14 15\n");
|
||||
System.out.println(" ! ! !");
|
||||
System.out.println(" 22 23 24\n");
|
||||
System.out.println("! ! ! ! ! ! !");
|
||||
System.out.println("29 30 31 32 33 34 35\n");
|
||||
System.out.println("! ! ! ! ! ! !");
|
||||
System.out.println("38 39 40 41 42 43 44\n");
|
||||
System.out.println("! ! ! ! ! ! !");
|
||||
System.out.println("47 48 49 50 51 52 53\n");
|
||||
System.out.println(" ! ! !");
|
||||
System.out.println(" 58 59 60\n");
|
||||
System.out.println(" ! ! !");
|
||||
System.out.println(" 67 68 69");
|
||||
System.out.println("TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD");
|
||||
System.out.println("WILL BE USED DURING PLAY. REFER TO THE ABOVE ONE FOR PEG");
|
||||
System.out.println("NUMBERS. OK, LET'S BEGIN.");
|
||||
}
|
||||
}
|
||||
84
51_Hurkle/perl/hurkle.pl
Executable file
84
51_Hurkle/perl/hurkle.pl
Executable file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# global variables
|
||||
|
||||
my($GRID) = 10;
|
||||
my($TRIES) = 5;
|
||||
|
||||
|
||||
# main program starts here
|
||||
|
||||
# print instructions
|
||||
print <<HERE;
|
||||
Hurkle
|
||||
Creative Computing Morristown, New Jersey
|
||||
|
||||
A Hurkle is hiding on a ${GRID} by ${GRID} grid. Homebase
|
||||
on the grid is point 0,0 in the southwest corner,
|
||||
and any point on the grid is designated by a
|
||||
pair of whole numbers seperated by a comma. The first
|
||||
number is the horizontal position and the second number
|
||||
is the vertical position. You must try to
|
||||
guess the Hurkle's gridpoint. You get ${TRIES} tries.
|
||||
After each try, I will tell you the approximate
|
||||
direction to go to look for the Hurkle.
|
||||
|
||||
HERE
|
||||
|
||||
# The PLAY block is a complete game from start
|
||||
# to finish. The continue block prints the
|
||||
# "let's play again" message and then a new
|
||||
# game is started.
|
||||
PLAY: while (1) {
|
||||
my($H1) = int(rand $GRID);
|
||||
my($H2) = int(rand $GRID);
|
||||
|
||||
for my $i (1 .. $TRIES) {
|
||||
printf(" Guess # %D ? ", $i);
|
||||
|
||||
my($G1,$G2);
|
||||
# The CHECK loop will execute while we
|
||||
# attempt to collect valid input from
|
||||
# the player
|
||||
CHECK: while (1) {
|
||||
|
||||
chomp(my $in = <STDIN>);
|
||||
# Use a regex to attempt to parse out
|
||||
# two integers separated by a comma.
|
||||
if ($in =~ m{(\d+)\s*,\s*(\d+)}) {
|
||||
$G1 = $1; $G2 = $2;
|
||||
last CHECK;
|
||||
}
|
||||
# Input not accepted, please try again
|
||||
print "Please enter two numbers separated by a comma ? ";
|
||||
}
|
||||
|
||||
if (abs($H1 - $G1) + abs($H2 - $G2) != 0) {
|
||||
|
||||
# print directional info
|
||||
printf("Go %s%s\n\n",
|
||||
($G2 == $H2 ? '' : $G2 < $H2 ? 'north' : 'south'),
|
||||
($G1 == $H1 ? '' : $G1 < $H1 ? 'east' : 'west' ),
|
||||
);
|
||||
} else {
|
||||
# win!
|
||||
printf("\nYou found him in %d tries!\n", $i);
|
||||
# move to the continue block
|
||||
next PLAY;
|
||||
}
|
||||
} # tries loop
|
||||
|
||||
# No more guesses
|
||||
printf("Sorry, that's %d guesses.\n", $TRIES);
|
||||
printf("The Hurkle is at %d, %d\n", $H1, $H2);
|
||||
}
|
||||
|
||||
# Execution comes here either from the "next PLAY"
|
||||
# statement, or by the PLAY block naturally ending
|
||||
# after the player has lost.
|
||||
continue {
|
||||
print "\nLet's play again. Hurkle is hiding.\n\n";
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
package king53
|
||||
|
||||
import kotlin.math.abs
|
||||
import kotlin.random.Random
|
||||
import kotlin.system.exitProcess
|
||||
@@ -22,6 +24,7 @@ fun main() {
|
||||
|
||||
with(gameState) {
|
||||
do {
|
||||
|
||||
recalculateLandCost()
|
||||
displayStatus()
|
||||
inputLandSale()
|
||||
@@ -84,6 +87,7 @@ fun loadOldGame(): GameState = GameState().apply {
|
||||
println(" COME ON, YOUR TERM IN OFFICE IS ONLY $yearsRequired YEARS.")
|
||||
retry = true
|
||||
}
|
||||
|
||||
} while (retry)
|
||||
|
||||
print("HOW MUCH DID YOU HAVE IN THE TREASURY? ")
|
||||
@@ -115,6 +119,10 @@ fun loadOldGame(): GameState = GameState().apply {
|
||||
*/
|
||||
sealed class YearOutcome {
|
||||
|
||||
/**
|
||||
* Display output for the end of the year, for each different possible
|
||||
* year outcome.
|
||||
*/
|
||||
open fun displayConsequences() {
|
||||
// Default display nothing
|
||||
}
|
||||
@@ -132,7 +140,7 @@ sealed class YearOutcome {
|
||||
|
||||
object ContinueNextYear : YearOutcome()
|
||||
|
||||
class Win(val yearsRequired: Int) : YearOutcome() {
|
||||
class Win(private val yearsRequired: Int) : YearOutcome() {
|
||||
override fun displayConsequences() {
|
||||
// The misspelling of "successfully" is in the original code.
|
||||
println(
|
||||
@@ -229,12 +237,18 @@ sealed class YearOutcome {
|
||||
* Record data, allow data input, and process the simulation for the game.
|
||||
*/
|
||||
class GameState(val yearsRequired: Int = 8) {
|
||||
|
||||
/**
|
||||
* The current year. Years start with zero, but we never
|
||||
* output the current year.
|
||||
*/
|
||||
var currentYear = 0
|
||||
|
||||
/**
|
||||
* Keep track of each year's crop loss, so we can report increases.
|
||||
*/
|
||||
private var lastYearsCropLoss: Int = 0
|
||||
|
||||
/**
|
||||
* Number of countrymen who have died of either pollution
|
||||
* or starvation this year.
|
||||
@@ -535,11 +549,12 @@ class GameState(val yearsRequired: Int = 8) {
|
||||
the population, but does not affect crop losses.
|
||||
*/
|
||||
var cropLoss = ((2000 - landArea) * (rnd + 1.5) / 2.0).toInt()
|
||||
val cropLossWorse = false
|
||||
if (foreignWorkers > 0)
|
||||
print("OF $plantingArea SQ. MILES PLANTED,")
|
||||
if (plantingArea <= cropLoss)
|
||||
cropLoss = plantingArea
|
||||
val cropLossWorse = cropLoss > lastYearsCropLoss
|
||||
lastYearsCropLoss = cropLoss
|
||||
println(" YOU HARVESTED ${plantingArea - cropLoss} SQ. MILES OF CROPS.")
|
||||
|
||||
if (cropLoss > 0) {
|
||||
|
||||
@@ -5,40 +5,37 @@ print ' 'x33 . "LETTER\n";
|
||||
print ' 'x15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
|
||||
print "\n\n\n";
|
||||
|
||||
print "LETTER GUESSING GAME\n"; print "\n";
|
||||
print "LETTER GUESSING GAME\n\n";
|
||||
print "I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z.\n";
|
||||
print "TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES\n";
|
||||
print "AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER.\n";
|
||||
|
||||
my $A;
|
||||
while (1) {
|
||||
my $L= 65+int(rand(1)*26);
|
||||
my $G= 0;
|
||||
print "\n"; print "O.K., I HAVE A LETTER. START GUESSING.\n";
|
||||
my $letter = 65 + int(rand(26));
|
||||
my $guesses = 0;
|
||||
print "\nO.K., I HAVE A LETTER. START GUESSING.\n";
|
||||
|
||||
my $answer;
|
||||
do {
|
||||
print "\n"; print "WHAT IS YOUR GUESS? ";
|
||||
$G=$G+1;
|
||||
chomp($A= <STDIN>);
|
||||
$A= ord($A);
|
||||
print "\nWHAT IS YOUR GUESS? ";
|
||||
$guesses++;
|
||||
chomp($answer = <STDIN>);
|
||||
$answer = ord($answer);
|
||||
print "\n";
|
||||
if ($A<$L) { print "TOO LOW. TRY A HIGHER LETTER.\n"; }
|
||||
if ($A>$L) { print "TOO HIGH. TRY A LOWER LETTER.\n"; }
|
||||
} until($A eq $L);
|
||||
print "TOO LOW. TRY A HIGHER LETTER.\n" if $answer < $letter;
|
||||
print "TOO HIGH. TRY A LOWER LETTER.\n" if $answer > $letter;
|
||||
} until($answer eq $letter);
|
||||
|
||||
print "\n"; print "YOU GOT IT IN $G GUESSES!!\n";
|
||||
print "\nYOU GOT IT IN $guesses GUESSES!!\n";
|
||||
|
||||
if ($G<=5) {
|
||||
if ($guesses <= 5) {
|
||||
print "GOOD JOB !!!!!\n";
|
||||
for (my $N=1; $N<=15; $N++) { print chr(7); } #ASCII Bell.
|
||||
} else {
|
||||
print chr(7) x 15; # ASCII Bell
|
||||
} else {
|
||||
print "BUT IT SHOULDN'T TAKE MORE THAN 5 GUESSES!\n";
|
||||
}
|
||||
|
||||
print "\n";
|
||||
print "LET'S PLAN AGAIN.....\n";
|
||||
}
|
||||
|
||||
print "\nLET'S PLAY AGAIN.....\n";
|
||||
}
|
||||
|
||||
exit;
|
||||
|
||||
|
||||
|
||||
509
55_Life/csharp/.gitignore
vendored
Normal file
509
55_Life/csharp/.gitignore
vendored
Normal file
@@ -0,0 +1,509 @@
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/dotnetcore,rider,visualstudio,visualstudiocode
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=dotnetcore,rider,visualstudio,visualstudiocode
|
||||
|
||||
### DotnetCore ###
|
||||
# .NET Core build folders
|
||||
bin/
|
||||
obj/
|
||||
|
||||
# Common node modules locations
|
||||
/node_modules
|
||||
/wwwroot/node_modules
|
||||
|
||||
### Rider ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
### VisualStudioCode Patch ###
|
||||
# Ignore all local history of files
|
||||
.history
|
||||
.ionide
|
||||
|
||||
# Support for Project snippet scope
|
||||
|
||||
### VisualStudio ###
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.tlog
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||
*.vbp
|
||||
|
||||
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||
*.dsw
|
||||
*.dsp
|
||||
|
||||
# Visual Studio 6 technical files
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# Visual Studio History (VSHistory) files
|
||||
.vshistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
# VS Code files for those working on multiple tools
|
||||
*.code-workspace
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
|
||||
# Windows Installer files from build outputs
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# JetBrains Rider
|
||||
*.sln.iml
|
||||
|
||||
### VisualStudio Patch ###
|
||||
# Additional files built by Visual Studio
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/dotnetcore,rider,visualstudio,visualstudiocode
|
||||
9
55_Life/csharp/Life.csproj
Normal file
9
55_Life/csharp/Life.csproj
Normal file
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
16
55_Life/csharp/Life.sln
Normal file
16
55_Life/csharp/Life.sln
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Life", "Life.csproj", "{28B02688-78D1-4B3E-B998-BCC78C292D03}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{28B02688-78D1-4B3E-B998-BCC78C292D03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{28B02688-78D1-4B3E-B998-BCC78C292D03}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{28B02688-78D1-4B3E-B998-BCC78C292D03}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{28B02688-78D1-4B3E-B998-BCC78C292D03}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
326
55_Life/csharp/Program.cs
Normal file
326
55_Life/csharp/Program.cs
Normal file
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* LIFE
|
||||
* An implementation of John Conway's popular cellular automaton
|
||||
* Ported by Dyego Alekssander Maas
|
||||
*
|
||||
* An example pattern would be:
|
||||
* " * "
|
||||
* "***"
|
||||
* "DONE" (indicates that the simulation can start)
|
||||
*
|
||||
* You can find patterns to play with here: http://pi.math.cornell.edu/~lipa/mec/lesson6.html
|
||||
*
|
||||
* Optionally, you can run this program with the "--wait 1000" argument, the number being the time in milliseconds
|
||||
* that the application will pause between each iteration. This is enables you to watch the simulation unfolding.
|
||||
* By default, there is no pause between iterations.
|
||||
*/
|
||||
using System.Text;
|
||||
|
||||
const int maxWidth = 70;
|
||||
const int maxHeight = 24;
|
||||
|
||||
Console.WriteLine("ENTER YOUR PATTERN:");
|
||||
var pattern = ReadPattern(limitHeight: maxHeight).ToArray();
|
||||
|
||||
var (minX, minY) = FindTopLeftCorner(pattern);
|
||||
var maxX = maxHeight;
|
||||
var maxY = maxWidth;
|
||||
|
||||
var matrix = new Matrix(height: maxHeight, width: maxWidth);
|
||||
var simulation = InitializeSimulation(pattern, matrix);
|
||||
|
||||
PrintHeader();
|
||||
ProcessSimulation();
|
||||
|
||||
IEnumerable<string> ReadPattern(int limitHeight)
|
||||
{
|
||||
for (var i = 0; i < limitHeight; i++)
|
||||
{
|
||||
var input = Console.ReadLine();
|
||||
if (input.ToUpper() == "DONE")
|
||||
{
|
||||
yield return string.Empty;
|
||||
break;
|
||||
}
|
||||
|
||||
// In the original version, BASIC would trim the spaces in the beginning of an input, so the original
|
||||
// game allowed you to input an '.' before the spaces to circumvent this limitation. This behavior was
|
||||
// kept for compatibility.
|
||||
if (input.StartsWith('.'))
|
||||
yield return input.Substring(1, input.Length - 2);
|
||||
|
||||
yield return input;
|
||||
}
|
||||
}
|
||||
|
||||
(int minX, int minY) FindTopLeftCorner(IEnumerable<string> patternLines)
|
||||
{
|
||||
var longestInput = patternLines
|
||||
.Select((value, index) => (index, value))
|
||||
.OrderByDescending(input => input.value.Length)
|
||||
.First();
|
||||
var centerX = (11 - longestInput.index / 2) - 1;
|
||||
var centerY = (33 - longestInput.value.Length / 2) - 1;
|
||||
return (centerX, centerY);
|
||||
}
|
||||
|
||||
void PrintHeader()
|
||||
{
|
||||
void PrintCentered(string text)
|
||||
{
|
||||
const int pageWidth = 64;
|
||||
|
||||
var spaceCount = (pageWidth - text.Length) / 2;
|
||||
Console.Write(new string(' ', spaceCount));
|
||||
Console.WriteLine(text);
|
||||
}
|
||||
|
||||
PrintCentered("LIFE");
|
||||
PrintCentered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
Simulation InitializeSimulation(IReadOnlyList<string> inputPattern, Matrix matrixToInitialize) {
|
||||
var newSimulation = new Simulation();
|
||||
|
||||
// translates the pattern to the middle of the simulation and counts initial population
|
||||
for (var x = 0; x < inputPattern.Count; x++)
|
||||
{
|
||||
for (var y = 0; y < inputPattern[x].Length; y++)
|
||||
{
|
||||
if (inputPattern[x][y] == ' ') continue;
|
||||
|
||||
matrixToInitialize[minX + x, minY + y] = CellState.Stable;
|
||||
newSimulation.IncreasePopulation();
|
||||
}
|
||||
}
|
||||
|
||||
return newSimulation;
|
||||
}
|
||||
|
||||
TimeSpan GetPauseBetweenIterations()
|
||||
{
|
||||
if (args.Length == 2)
|
||||
{
|
||||
var parameter = args[0].ToLower();
|
||||
if (parameter.Contains("wait"))
|
||||
{
|
||||
var value = args[1];
|
||||
if (int.TryParse(value, out var sleepMilliseconds))
|
||||
return TimeSpan.FromMilliseconds(sleepMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
return TimeSpan.Zero;
|
||||
}
|
||||
|
||||
void ProcessSimulation()
|
||||
{
|
||||
var pauseBetweenIterations = GetPauseBetweenIterations();
|
||||
var isInvalid = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
Console.WriteLine($"GENERATION: {simulation.Generation}\tPOPULATION: {simulation.Population}");
|
||||
if (isInvalid)
|
||||
Console.WriteLine("INVALID!");
|
||||
|
||||
simulation.StartNewGeneration();
|
||||
|
||||
var nextMinX = maxHeight - 1;
|
||||
var nextMinY = maxWidth - 1;
|
||||
var nextMaxX = 0;
|
||||
var nextMaxY = 0;
|
||||
|
||||
// prints the empty lines before search area
|
||||
for (var x = 0; x < minX; x++)
|
||||
{
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
// refreshes the matrix and updates search area
|
||||
for (var x = minX; x < maxX; x++)
|
||||
{
|
||||
var printedLine = Enumerable.Repeat(' ', maxWidth).ToList();
|
||||
for (var y = minY; y < maxY; y++)
|
||||
{
|
||||
if (matrix[x, y] == CellState.Dying)
|
||||
{
|
||||
matrix[x, y] = CellState.Empty;
|
||||
continue;
|
||||
}
|
||||
if (matrix[x, y] == CellState.New)
|
||||
{
|
||||
matrix[x, y] = CellState.Stable;
|
||||
}
|
||||
else if (matrix[x, y] != CellState.Stable)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
printedLine[y] = '*';
|
||||
|
||||
nextMinX = Math.Min(x, nextMinX);
|
||||
nextMaxX = Math.Max(x + 1, nextMaxX);
|
||||
nextMinY = Math.Min(y, nextMinY);
|
||||
nextMaxY = Math.Max(y + 1, nextMaxY);
|
||||
}
|
||||
|
||||
Console.WriteLine(string.Join(separator: null, values: printedLine));
|
||||
}
|
||||
|
||||
// prints empty lines after search area
|
||||
for (var x = maxX + 1; x < maxHeight; x++)
|
||||
{
|
||||
Console.WriteLine();
|
||||
}
|
||||
Console.WriteLine();
|
||||
|
||||
void UpdateSearchArea()
|
||||
{
|
||||
minX = nextMinX;
|
||||
maxX = nextMaxX;
|
||||
minY = nextMinY;
|
||||
maxY = nextMaxY;
|
||||
|
||||
if (minX < 3)
|
||||
{
|
||||
minX = 3;
|
||||
isInvalid = true;
|
||||
}
|
||||
|
||||
if (maxX > 22)
|
||||
{
|
||||
maxX = 22;
|
||||
isInvalid = true;
|
||||
}
|
||||
|
||||
if (minY < 3)
|
||||
{
|
||||
minY = 3;
|
||||
isInvalid = true;
|
||||
}
|
||||
|
||||
if (maxY > 68)
|
||||
{
|
||||
maxY = 68;
|
||||
isInvalid = true;
|
||||
}
|
||||
}
|
||||
UpdateSearchArea();
|
||||
|
||||
for (var x = minX - 1; x < maxX + 2; x++)
|
||||
{
|
||||
for (var y = minY - 1; y < maxY + 2; y++)
|
||||
{
|
||||
int CountNeighbors()
|
||||
{
|
||||
var neighbors = 0;
|
||||
for (var i = x - 1; i < x + 2; i++)
|
||||
{
|
||||
for (var j = y - 1; j < y + 2; j++)
|
||||
{
|
||||
if (matrix[i, j] == CellState.Stable || matrix[i, j] == CellState.Dying)
|
||||
neighbors++;
|
||||
}
|
||||
}
|
||||
|
||||
return neighbors;
|
||||
}
|
||||
|
||||
var neighbors = CountNeighbors();
|
||||
if (matrix[x, y] == 0)
|
||||
{
|
||||
if (neighbors == 3)
|
||||
{
|
||||
matrix[x, y] = CellState.New;
|
||||
simulation.IncreasePopulation();
|
||||
}
|
||||
}
|
||||
else if (neighbors is < 3 or > 4)
|
||||
{
|
||||
matrix[x, y] = CellState.Dying;
|
||||
}
|
||||
else
|
||||
{
|
||||
simulation.IncreasePopulation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// expands search area to accommodate new cells
|
||||
minX--;
|
||||
minY--;
|
||||
maxX++;
|
||||
maxY++;
|
||||
|
||||
if (pauseBetweenIterations > TimeSpan.Zero)
|
||||
Thread.Sleep(pauseBetweenIterations);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the state of a given cell in the simulation.
|
||||
/// </summary>
|
||||
internal enum CellState
|
||||
{
|
||||
Empty = 0,
|
||||
Stable = 1,
|
||||
Dying = 2,
|
||||
New = 3
|
||||
}
|
||||
|
||||
public class Simulation
|
||||
{
|
||||
public int Generation { get; private set; }
|
||||
|
||||
public int Population { get; private set; }
|
||||
|
||||
public void StartNewGeneration()
|
||||
{
|
||||
Generation++;
|
||||
Population = 0;
|
||||
}
|
||||
|
||||
public void IncreasePopulation()
|
||||
{
|
||||
Population++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class was created to aid debugging, through the implementation of the ToString() method.
|
||||
/// </summary>
|
||||
class Matrix
|
||||
{
|
||||
private readonly CellState[,] _matrix;
|
||||
|
||||
public Matrix(int height, int width)
|
||||
{
|
||||
_matrix = new CellState[height, width];
|
||||
}
|
||||
|
||||
public CellState this[int x, int y]
|
||||
{
|
||||
get => _matrix[x, y];
|
||||
set => _matrix[x, y] = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
for (var x = 0; x < _matrix.GetLength(0); x++)
|
||||
{
|
||||
for (var y = 0; y < _matrix.GetLength(1); y++)
|
||||
{
|
||||
var character = _matrix[x, y] == 0 ? " ": ((int)_matrix[x, y]).ToString();
|
||||
stringBuilder.Append(character);
|
||||
}
|
||||
|
||||
stringBuilder.AppendLine();
|
||||
}
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
96
62_Mugwump/perl/mugwump.pl
Executable file
96
62_Mugwump/perl/mugwump.pl
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# global variables defined here
|
||||
my(@MUGWUMP) = ();
|
||||
|
||||
# subroutines defined here
|
||||
|
||||
# init_mugwump: pick the random places for the Mugwumps
|
||||
sub init_mugwump() {
|
||||
@MUGWUMP = ();
|
||||
for (1 .. 4) {
|
||||
push @MUGWUMP, [ int(rand 10), int(rand 10) ];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# main code starts here
|
||||
|
||||
# print introductory text
|
||||
print <<HERE;
|
||||
Mugwump
|
||||
Creative Computing Morristown, New Jersey
|
||||
|
||||
|
||||
|
||||
The object of this game is to find four Mugwumps
|
||||
hidden on a 10 by 10 grid. Homebase is position 0,0.
|
||||
Any guess you make must be two numbers with each
|
||||
number between 0 and 9, inclusive. First number
|
||||
is distance to right of homebase and second number
|
||||
is distance above homebase.
|
||||
|
||||
You get 10 tries. After each try, I will tell
|
||||
you how far you are from each Mugwump.
|
||||
|
||||
HERE
|
||||
|
||||
|
||||
# PLAY block implements a complete game, and the
|
||||
# continue block prints the "let's play again" msg
|
||||
PLAY: while (1) {
|
||||
|
||||
init_mugwump();
|
||||
TURN: for my $turn (1 .. 10) {
|
||||
|
||||
printf("\nTurn no %d -- what is your guess ? ", $turn);
|
||||
|
||||
# Note that parsing of input is rudimentary, in keeping with the
|
||||
# spirit of the original BASIC program. Increased input checks
|
||||
# would be a good place to start working on this program!
|
||||
chomp(my $in = <STDIN>);
|
||||
my($M,$N) = split(/,/,$in);
|
||||
$M = int($M);
|
||||
$N = int($N);
|
||||
|
||||
for my $i (0 .. $#MUGWUMP) {
|
||||
# -1 indicates a Mugwump that was already found
|
||||
next if $MUGWUMP[$i]->[0] == -1;
|
||||
|
||||
if ($MUGWUMP[$i]->[0] == $M && $MUGWUMP[$i]->[1] == $N) {
|
||||
$MUGWUMP[$i]->[0] = -1;
|
||||
printf("You have found Mugwump %d\n", $i+1);
|
||||
} else {
|
||||
my $d = sqrt(($MUGWUMP[$i]->[0] - $M) ** 2 + ($MUGWUMP[$i]->[1] - $N) ** 2);
|
||||
printf("You are %.1f units away from Mugwump %d\n", $d, $i+1);
|
||||
}
|
||||
}
|
||||
|
||||
# If a Mugwump still has not been found,
|
||||
# go to the next turn
|
||||
for my $j (0 .. $#MUGWUMP) {
|
||||
if ($MUGWUMP[$j]->[0] != -1) {
|
||||
next TURN;
|
||||
}
|
||||
}
|
||||
# You win!
|
||||
printf("You got all of them in %d %s!\n\n", $turn, ($turn == 1 ? 'turn' : 'turns'));
|
||||
# Pass execution down to the continue block
|
||||
next PLAY;
|
||||
|
||||
} # end of TURN loop
|
||||
|
||||
print "\nSorry, that's 10 tries. Here's where they're hiding:\n";
|
||||
for my $i (0 .. $#MUGWUMP) {
|
||||
printf("Mugwump %d is at (%d, %d)\n", $i+1, $MUGWUMP[$i]->[0], $MUGWUMP[$i]->[1])
|
||||
if $MUGWUMP[$i]->[0] != -1;
|
||||
}
|
||||
}
|
||||
continue {
|
||||
print "\nThat was fun! Let's play again.......\n";
|
||||
print "Four more Mugwumps are now in hiding.\n\n";
|
||||
}
|
||||
|
||||
126
65_Nim/python/Traditional_NIM.py
Normal file
126
65_Nim/python/Traditional_NIM.py
Normal file
@@ -0,0 +1,126 @@
|
||||
import random
|
||||
|
||||
#Class of the Game
|
||||
class NIM:
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.Piles = {
|
||||
1 : 7,
|
||||
2 : 5,
|
||||
3 : 3,
|
||||
4 : 1
|
||||
}
|
||||
|
||||
def Remove_pegs(self, command):
|
||||
|
||||
try:
|
||||
|
||||
pile, num = command.split(',')
|
||||
num = int(num)
|
||||
pile = int(pile)
|
||||
|
||||
except Exception as e:
|
||||
|
||||
if 'not enough values' in str(e):
|
||||
print('\nNot a valid command. Your command should be in the form of "1,3", Try Again\n')
|
||||
|
||||
else:
|
||||
print('\nError, Try again\n')
|
||||
return None
|
||||
|
||||
if self._command_integrity(num, pile) == True:
|
||||
self.Piles[pile] -= num
|
||||
else:
|
||||
print('\nInvalid value of either Peg or Pile\n')
|
||||
|
||||
def get_AI_move(self):
|
||||
|
||||
possible_pile = []
|
||||
for k,v in self.Piles.items():
|
||||
if v != 0:
|
||||
possible_pile.append(k)
|
||||
|
||||
pile = random.choice(possible_pile)
|
||||
|
||||
num = random.randint(1,self.Piles[pile])
|
||||
|
||||
return pile, num
|
||||
|
||||
def _command_integrity(self, num, pile):
|
||||
|
||||
if pile <= 4 and pile >= 1:
|
||||
if num <= self.Piles[pile]:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def print_pegs(self):
|
||||
|
||||
for pile, peg in self.Piles.items():
|
||||
print('Pile {} : {}'.format(pile, 'O '*peg))
|
||||
|
||||
def Help(self):
|
||||
|
||||
print('-'*10)
|
||||
print('\nThe Game is player with a number of Piles of Objects("O" == one peg)')
|
||||
print('\nThe Piles are arranged as given below(Tradional NIM)\n')
|
||||
self.print_pegs()
|
||||
print('\nAny Number of of Objects are removed one pile by "YOU" and the machine alternatively')
|
||||
print('\nOn your turn, you may take all the objects that remain in any pile')
|
||||
print('but you must take ATLEAST one object')
|
||||
print('\nAnd you may take objects from only one pile on a single turn.')
|
||||
print('\nThe winner is defined as the one that picks the last remaning object')
|
||||
print('-'*10)
|
||||
|
||||
def Checkforwin(self):
|
||||
|
||||
sum = 0
|
||||
for k,v in self.Piles.items():
|
||||
sum += v
|
||||
|
||||
if sum == 0:
|
||||
return True
|
||||
|
||||
else:
|
||||
return False
|
||||
|
||||
#main program
|
||||
if __name__ == "__main__":
|
||||
|
||||
#Game initialization
|
||||
game = NIM()
|
||||
|
||||
print('Hello, This is a game of NIM')
|
||||
help = input('Do You Need Instruction (YES or NO): ')
|
||||
|
||||
if help == 'yes' or help == 'YES' or help == 'Yes':
|
||||
|
||||
#Printing Game Instruction
|
||||
game.Help()
|
||||
|
||||
#Start game loop
|
||||
input('\nPress Enter to start the Game:\n')
|
||||
End = False
|
||||
while True:
|
||||
|
||||
game.print_pegs()
|
||||
|
||||
#Players Move
|
||||
command = input('\nYOUR MOVE - Number of PILE, Number of Object? ')
|
||||
game.Remove_pegs(command)
|
||||
End = game.Checkforwin()
|
||||
if End == True:
|
||||
print('\nPlayer Wins the Game, Congratulations!!')
|
||||
input('\nPress any key to exit')
|
||||
break
|
||||
|
||||
#Computers Move
|
||||
command = game.get_AI_move()
|
||||
print('\nA.I MOVE - A.I Removed {} pegs from Pile {}'.format(command[1],command[0]))
|
||||
game.Remove_pegs(str(command[0]) +',' + str(command[1]))
|
||||
End = game.Checkforwin()
|
||||
if End == True:
|
||||
print('\nComputer Wins the Game, Better Luck Next Time\n')
|
||||
input('Press any key to exit')
|
||||
break
|
||||
282
65_Nim/ruby/nim.rb
Normal file
282
65_Nim/ruby/nim.rb
Normal file
@@ -0,0 +1,282 @@
|
||||
puts "NIM".center(80)
|
||||
puts"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY".center(80)
|
||||
puts "\n\n\n"
|
||||
|
||||
#210 DIM A(100),B(100,10),D(2)
|
||||
$pileArray = Array.new[100]
|
||||
$bArray = Array.new
|
||||
$dArray = Array.new[2]
|
||||
$winOption = 0 # take-last option
|
||||
$numberOfPiles = 1
|
||||
$c = 0
|
||||
$e = 0
|
||||
$f = 0
|
||||
$g = 0
|
||||
$h = 0
|
||||
|
||||
def displayTheRules
|
||||
puts "THE GAME IS PLAYED WITH A NUMBER OF PILES OF OBJECTS."
|
||||
puts "ANY NUMBER OF OBJECTS ARE REMOVED FROM ONE PILE BY YOU AND"
|
||||
puts "THE MACHINE ALTERNATELY. ON YOUR TURN, YOU MAY TAKE"
|
||||
puts "ALL THE OBJECTS THAT REMAIN IN ANY PILE, BUT YOU MUST"
|
||||
puts "TAKE AT LEAST ONE OBJECT, AND YOU MAY TAKE OBJECTS FROM"
|
||||
puts "ONLY ONE PILE ON A SINGLE TURN. YOU MUST SPECIFY WHETHER"
|
||||
puts "WINNING IS DEFINED AS TAKING OR NOT TAKING THE LAST OBJECT,"
|
||||
puts "THE NUMBER OF PILES IN THE GAME, AND HOW MANY OBJECTS ARE"
|
||||
puts "ORIGINALLY IN EACH PILE. EACH PILE MAY CONTAIN A"
|
||||
puts "DIFFERENT NUMBER OF OBJECTS."
|
||||
puts "THE MACHINE WILL SHOW ITS MOVE BY LISTING EACH PILE AND THE"
|
||||
puts "NUMBER OF OBJECTS REMAINING IN THE PILES AFTER EACH OF ITS"
|
||||
puts "MOVES."
|
||||
end
|
||||
|
||||
def sub1570
|
||||
$z=0
|
||||
for i in 1..$numberOfPiles do
|
||||
if $pileArray[i] != 0 then
|
||||
return
|
||||
end
|
||||
$z=1
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
def playAnother
|
||||
put "do you want to play another game";
|
||||
return gets.strip.ucase == "YES"
|
||||
end
|
||||
puts "THIS IS THE GAME OF NIM."
|
||||
print "DO YOU WANT INSTRUCTIONS?"
|
||||
240
|
||||
wantInstructions = gets.strip.upcase
|
||||
if wantInstructions == "YES" then
|
||||
displayTheRules
|
||||
end
|
||||
#250 IF Z$="NO" THEN 440
|
||||
#260 IF Z$="no" THEN 440
|
||||
#270 IF Z$="YES" THEN displayTheRules
|
||||
#280 IF Z$="yes" THEN displayTheRules
|
||||
#290 PRINT "PLEASE ANSWER YES OR NO"
|
||||
#300 GOTO 240
|
||||
|
||||
def sub490 # get number of piles
|
||||
print "ENTER NUMBER OF PILES:"
|
||||
while $numberOfPiles < 0 && $numberOfPiles <= 100 do
|
||||
$numberOfPiles = gets.strip.to_i
|
||||
end
|
||||
end
|
||||
|
||||
def getPileSizes
|
||||
puts "ENTER PILE SIZES:"
|
||||
for i in 1..$numberOfPiles do
|
||||
print i
|
||||
while true do
|
||||
$pileArray[i] = gets.strip.to_i
|
||||
if $pileArray[i] < 2000 && $pileArray[i] > 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def sub440 # get win option
|
||||
puts ""
|
||||
$winOption = 0
|
||||
while $winOption != 1 && q != 2 do
|
||||
puts "ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST"
|
||||
$winOption = gets.strip.to_i
|
||||
end
|
||||
end
|
||||
|
||||
puts "DO YOU WANT TO MOVE FIRST?";
|
||||
#630 INPUT Q9$
|
||||
moveFirst = ""
|
||||
while moveFirst != "YES" && moveFirst != "NO" do
|
||||
moveFirst = gets.strip.upcase
|
||||
case moveFirst
|
||||
when "YES"
|
||||
yourMove
|
||||
when "NO"
|
||||
machineMove
|
||||
end
|
||||
end
|
||||
|
||||
#640 IF Q9$="YES" THEN 1450
|
||||
#650 IF Q9$="yes" THEN 1450
|
||||
#660 IF Q9$="NO" THEN 700
|
||||
#670 IF Q9$="no" THEN 700
|
||||
#680 PRINT "PLEASE ANSWER YES OR NO."
|
||||
#690 GOTO 630
|
||||
|
||||
def machineMove
|
||||
if $winOption == 1 then
|
||||
sub940 # take last
|
||||
end
|
||||
$c=0
|
||||
for i in 1..$numberOfPiles do
|
||||
if $pileArray[i] != 0 then 770
|
||||
$c=$c+1
|
||||
if $c == 3 then
|
||||
sub840
|
||||
end
|
||||
$dArray[$c-1]=i
|
||||
end
|
||||
end
|
||||
|
||||
if $c == 2 then
|
||||
sub920
|
||||
end
|
||||
if $pileArray[$dArray[0]] > 1 then
|
||||
machineWins
|
||||
end
|
||||
machineLoses
|
||||
end
|
||||
|
||||
def machineLoses
|
||||
puts "MACHINE LOSES"
|
||||
# 810 GOTO playAnother
|
||||
if playAnother then
|
||||
sub440 # loop for another
|
||||
end
|
||||
end
|
||||
|
||||
def machineWins
|
||||
puts "MACHINE WINS"
|
||||
# 830 GOTO playAnother
|
||||
if playAnother then
|
||||
sub440 # loop for another
|
||||
end
|
||||
end
|
||||
|
||||
def sub840
|
||||
$c=0
|
||||
for i in 1..$numberOfPiles do
|
||||
if $pileArray[i] > 1 then
|
||||
sub940
|
||||
end
|
||||
if $pileArray[i] == 0 then 890
|
||||
$c=$c+1
|
||||
end
|
||||
if $c/2 != ($c/2).to_i then
|
||||
machineLoses
|
||||
end
|
||||
sub940 # goto
|
||||
end
|
||||
end
|
||||
|
||||
def sub920
|
||||
if $pileArray[$dArray[0]] == 1 then
|
||||
machineWins
|
||||
end
|
||||
if $pileArray[$dArray[1]] == 1 then
|
||||
machineWins
|
||||
end
|
||||
end
|
||||
|
||||
def sub940
|
||||
for i in 1..$numberOfPiles do
|
||||
e=$pileArray[i]
|
||||
for j in 0..10 do
|
||||
$f = $e/2
|
||||
$bArray[i][j] = 2*($f-($f.to_i))
|
||||
$e = $f.to_i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#for j in 10..0 STEP -1 do
|
||||
10..0.step(-1).each do|index|
|
||||
$c=0
|
||||
$h=0
|
||||
for i in 1..$numberOfPiles do
|
||||
if $bArray[i][index] != 0 then
|
||||
$c=$c+1
|
||||
if $pileArray[i] > $h then
|
||||
$h = $pileArray[i]
|
||||
$g = i
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if $c/2 != ($c/2).to_i then 1190
|
||||
end
|
||||
$e = rand($numberOfPiles).to_i
|
||||
#if $pileArray[$e] == 0 then 1140
|
||||
|
||||
$f = rand($pileArray[$e]).to_i
|
||||
$pileArray[$e] = $pileArray[$e]-$f
|
||||
sub1380
|
||||
$pileArray[$g]=0
|
||||
for j in 0..10 do
|
||||
$bArray[$g][index]=0
|
||||
$c=0
|
||||
for i in 1..$numberOfPiles do
|
||||
if $bArray[i][index] != 0 then
|
||||
$c=$c+1
|
||||
end
|
||||
end
|
||||
$pileArray[$g]=$pileArray[$g]+2*($c/2-($c/2)).to_i*2^j
|
||||
end
|
||||
if $winOption == 1 then
|
||||
sub1380
|
||||
end
|
||||
$c=0
|
||||
for i in 1..$numberOfPiles do
|
||||
if $pileArray[i]>1 then
|
||||
sub1380
|
||||
end
|
||||
if $pileArray[i] != 0 then
|
||||
$c=$c+1
|
||||
end
|
||||
if $c/2 == ($c/2).to_i then
|
||||
sub1380
|
||||
end
|
||||
$pileArray[$g] == 1 -$pileArray[$g]
|
||||
|
||||
def sub1380
|
||||
puts "PILE SIZE"
|
||||
for i in 1..$numberOfPiles do
|
||||
put i
|
||||
put $pileArray[i]
|
||||
end
|
||||
if $winOption == 2 then # avoid take-last option
|
||||
yourMove
|
||||
end
|
||||
sub1570
|
||||
if $z == 1 then
|
||||
machineWins
|
||||
end
|
||||
end
|
||||
|
||||
def yourMove
|
||||
put "YOUR MOVE - PILE, NUMBER TO BE REMOVED"
|
||||
# 1460 INPUT x,y
|
||||
x = gets.strip.to_i
|
||||
y = gets.strip.to_i
|
||||
if x > $numberOfPiles then yourMove
|
||||
if x < 1 then yourMove
|
||||
if x != INT(x) then yourMove
|
||||
if y > $pileArray[x] then yourMove
|
||||
if y < 1 then
|
||||
yourMove
|
||||
end
|
||||
if y != INT(y) then
|
||||
yourMove
|
||||
end
|
||||
|
||||
$pileArray[x] = $pileArray[x]-y
|
||||
sub1570 # gosub
|
||||
if $z == 1 then
|
||||
machineLoses
|
||||
end
|
||||
# 1560 GOTO 700
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
252
67_One_Check/perl/onecheck.pl
Executable file
252
67_One_Check/perl/onecheck.pl
Executable file
@@ -0,0 +1,252 @@
|
||||
#!/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 List::Util qw{ sum }; # Add all its arguments
|
||||
use Term::ReadLine; # Prompt and return user input
|
||||
|
||||
our $VERSION = '0.000_01';
|
||||
|
||||
print <<'EOD';
|
||||
ONE CHECK
|
||||
Creative Computing Morristown, New Jersey
|
||||
|
||||
|
||||
|
||||
Solitaire checker puzzle by David Ahl
|
||||
|
||||
48 checkers are placed on the 2 outside spaces of a
|
||||
standard 64-square checkerboard. The object is to
|
||||
remove as many checkers as possible by diagonal jumps
|
||||
(as in standard checkers). Use the numbered board to
|
||||
indicate the square you wish to jump from and to. On
|
||||
the board printed out on each turn '1' indicates a
|
||||
checker and '0' an empty square. When you have no
|
||||
possible jumps remaining, input a '0' in response to
|
||||
question 'Jump from?'
|
||||
EOD
|
||||
|
||||
while ( 1 ) { # Iterate indefinitely
|
||||
|
||||
board_num(); # Display the numerical board.
|
||||
|
||||
# Initialize the board, which is a two-dimensional array.
|
||||
my @board = map { [ ( 1 ) x 8 ] } 0 .. 7; # Initialize to all 1.
|
||||
for my $row ( 2 .. 5 ) { # Set the center section to 0
|
||||
for my $col ( 2 .. 5 ) {
|
||||
$board[$row][$col] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
print <<'EOD';
|
||||
And here is the opening position of the checkers.
|
||||
|
||||
EOD
|
||||
board_pos( \@board );
|
||||
|
||||
my $moves = 0; # Number of moves made.
|
||||
|
||||
# A game proceeds while 'Jump from' is a true value. We make use of
|
||||
# the fact that of the possible returns, only 0 evaluates false.
|
||||
while ( my $jump_from = get_input(
|
||||
'Jump from? ',
|
||||
sub {
|
||||
$ARG = lc; # The caller sees this.
|
||||
return 1 if $ARG eq 'b';
|
||||
return unless m/ \A [0-9]+ \z /smx;
|
||||
$ARG += 0; # Numify, because string '00' is true.
|
||||
return $ARG < 65;
|
||||
},
|
||||
"Please enter a number from 0 to 64, or 'b' to re-display the numeric board\n"
|
||||
)
|
||||
) {
|
||||
if ( $jump_from eq 'b' ) {
|
||||
board_num();
|
||||
board_pos( \@board );
|
||||
next;
|
||||
}
|
||||
|
||||
my $jump_to = get_input(
|
||||
' to? ',
|
||||
sub { m/ \A [0-9]+ \z /smx },
|
||||
"Please enter a number from 1 to 64\n",
|
||||
);
|
||||
|
||||
if ( make_move( \@board, $jump_from, $jump_to ) ) {
|
||||
$moves++;
|
||||
board_pos( \@board );
|
||||
} else {
|
||||
say 'Illegal move. Try again.';
|
||||
}
|
||||
}
|
||||
|
||||
my $checkers_left = sum( map { sum( @{ $board[$_] } ) } 0 .. 7 );
|
||||
print <<"EOD";
|
||||
|
||||
You made $moves jumps and had $checkers_left pieces
|
||||
remaining on the board.
|
||||
|
||||
EOD
|
||||
|
||||
last unless get_yes_no( 'Try again' );
|
||||
|
||||
}
|
||||
|
||||
print <<'EOD';
|
||||
|
||||
O.K. Hope you had fun!!
|
||||
EOD
|
||||
|
||||
# Print the numerical board
|
||||
sub board_num {
|
||||
print <<'EOD';
|
||||
|
||||
Here is the numerical board:
|
||||
|
||||
EOD
|
||||
foreach my $row ( 0 .. 7 ) {
|
||||
state $tplt = ( '%3d' x 8 ) . "\n";
|
||||
my $inx = $row * 8;
|
||||
printf $tplt, map { $inx + $_ } 1 .. 8;
|
||||
}
|
||||
say '';
|
||||
return;
|
||||
}
|
||||
|
||||
# Print the board position
|
||||
sub board_pos {
|
||||
my ( $board ) = @_;
|
||||
for my $row ( 0 .. 7 ) {
|
||||
state $tplt = ( '%2d' x 8 ) . "\n";
|
||||
printf $tplt, @{ $board->[$row] };
|
||||
}
|
||||
say '';
|
||||
return;
|
||||
}
|
||||
|
||||
# Make the move. This is a subroutine for convenience in control flow.
|
||||
# We return a true value for success, and false for failure.
|
||||
sub make_move {
|
||||
my ( $board, $jump_from, $jump_to ) = @_;
|
||||
$jump_from -= 1;
|
||||
$jump_to -= 1;
|
||||
my $from_row = int( $jump_from / 8 ); # Truncates toward 0
|
||||
my $from_col = $jump_from % 8;
|
||||
my $to_row = int( $jump_to / 8 ); # Truncates toward 0
|
||||
my $to_col = $jump_to % 8;
|
||||
return unless $board->[$from_row][$from_col]; # From must be occupied
|
||||
return if $board->[$to_row][$to_col]; # To must be vacant
|
||||
return unless abs( $from_row - $to_row ) == 2; # Must cross two rows
|
||||
return unless abs( $from_col - $to_col ) == 2; # Must cross two cols
|
||||
my $over_row = ( $from_row + $to_row ) / 2; # The row jumped over
|
||||
my $over_col = ( $from_col + $to_col ) / 2; # The col jumped over
|
||||
$board->[$from_row][$from_col] = # Clear the from cell
|
||||
$board->[$over_row][$over_col] = 0; # and the jumped cell
|
||||
$board->[$to_row][$to_col] = 1; # Occupy the to cell
|
||||
return 1;
|
||||
}
|
||||
|
||||
# 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( 'reverse' );
|
||||
$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 };
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 TITLE
|
||||
|
||||
one check - Play the game 'One Check' from Basic Computer Games
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
one check.pl
|
||||
|
||||
=head1 DETAILS
|
||||
|
||||
This Perl script is a port of onecheck.
|
||||
|
||||
This is a solitaire game played on a checker board, where the object is
|
||||
to eliminate as many checkers as possible by making diagonal jumps and
|
||||
removing the jumped checkers.
|
||||
|
||||
It is pretty much a straight port of the BASIC original.
|
||||
|
||||
=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,3 +1,11 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Perl](https://www.perl.org/)
|
||||
|
||||
This Perl script is a port of orbit, which is the 68th entry in Basic
|
||||
Computer Games.
|
||||
|
||||
In this game you are a planetary defense gunner trying to shoot down a
|
||||
cloaked Romulan ship before it can escape.
|
||||
|
||||
This is pretty much a straight port of the BASIC into idiomatic Perl.
|
||||
|
||||
239
68_Orbit/perl/orbit.pl
Executable file
239
68_Orbit/perl/orbit.pl
Executable file
@@ -0,0 +1,239 @@
|
||||
#!/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';
|
||||
|
||||
use constant PI => atan2( 0, -1 );
|
||||
use constant DEG_TO_RAD => atan2( 0, -1 ) / 180;
|
||||
|
||||
print <<'EOD';
|
||||
ORBIT
|
||||
Creative Computing Morristown, New Jersey
|
||||
|
||||
|
||||
|
||||
Somewhere above your planet is a Romulan ship.
|
||||
|
||||
The ship is in a constant polar orbit. Its
|
||||
distance from the center of your planet is from
|
||||
10,000 to 30,000 miles and at its present velocity can
|
||||
circle your planet once every 12 to 36 hours.
|
||||
|
||||
Unfortunately, they are using a cloaking device so
|
||||
you are unable to see them, but with a special
|
||||
instrument you can tell how near their ship your
|
||||
photon bomb exploded. You have seven hours until they
|
||||
have built up sufficient power in order to escape
|
||||
your planet's gravity.
|
||||
|
||||
Your planet has enough power to fire one bomb an hour.
|
||||
|
||||
At the beginning of each hour you will be asked to give an
|
||||
angle (between 0 and 360) and a distance in units of
|
||||
100 miles (between 100 and 300), after which your bomb's
|
||||
distance from the enemy ship will be given.
|
||||
|
||||
An explosion within 5,000 miles of the Romulan ship
|
||||
will destroy it.
|
||||
|
||||
Below is a diagram to help you visualize your plight.
|
||||
|
||||
|
||||
90
|
||||
0000000000000
|
||||
0000000000000000000
|
||||
000000 000000
|
||||
00000 00000
|
||||
00000 XXXXXXXXXXX 00000
|
||||
00000 XXXXXXXXXXXXX 00000
|
||||
0000 XXXXXXXXXXXXXXX 0000
|
||||
0000 XXXXXXXXXXXXXXXXX 0000
|
||||
0000 XXXXXXXXXXXXXXXXXXX 0000
|
||||
180<== 00000 XXXXXXXXXXXXXXXXXXX 00000 ==>0
|
||||
0000 XXXXXXXXXXXXXXXXXXX 0000
|
||||
0000 XXXXXXXXXXXXXXXXX 0000
|
||||
0000 XXXXXXXXXXXXXXX 0000
|
||||
00000 XXXXXXXXXXXXX 00000
|
||||
00000 XXXXXXXXXXX 00000
|
||||
00000 00000
|
||||
000000 000000
|
||||
0000000000000000000
|
||||
0000000000000
|
||||
270
|
||||
|
||||
X - Your planet
|
||||
O - The orbit of the Romulan ship
|
||||
|
||||
On the above diagram, the Romulan ship is circling
|
||||
counterclockwise around your planet. Don't forget that
|
||||
without sufficient power the Romulan ship's altitude
|
||||
and orbital rate will remain constant.
|
||||
|
||||
Good luck. The Federation is counting on you.
|
||||
EOD
|
||||
|
||||
while ( 1 ) { # Iterate indefinitely
|
||||
|
||||
my $romulan_angle = int( 360 * rand() );
|
||||
my $romulan_distance = int( 200 * rand() + 200 );
|
||||
my $romulan_velocity = int( 20 * rand() + 10 );
|
||||
|
||||
my $hour = 0;
|
||||
while ( 1 ) { # Iterate indefinitely
|
||||
$hour++;
|
||||
|
||||
print <<"EOD";
|
||||
|
||||
|
||||
This is hour $hour, at what angle do you wish to send
|
||||
EOD
|
||||
my $bomb_angle = get_input(
|
||||
'do you wish to send your photon bomb? ',
|
||||
sub { m/ \A [0-9]+ \z /smx },
|
||||
"Please enter an integer angle in degrees\n",
|
||||
);
|
||||
say '';
|
||||
my $bomb_distance = get_input(
|
||||
'How far out do you wish to detonate it? ',
|
||||
sub { m/ \A [0-9]+ \z /smx },
|
||||
"Please enter an integer distance in hundreds of miles\n",
|
||||
);
|
||||
|
||||
$romulan_angle = ( $romulan_angle + $romulan_velocity ) % 360;
|
||||
my $miss_angle = abs( $romulan_angle - $bomb_angle );
|
||||
$miss_angle = 360 - $miss_angle if $miss_angle >= 180;
|
||||
my $miss_distance = int sqrt(
|
||||
$romulan_distance * $romulan_distance +
|
||||
$bomb_distance * $bomb_distance -
|
||||
2 * $romulan_distance * $bomb_distance *
|
||||
cos( $miss_angle * DEG_TO_RAD ) );
|
||||
print <<"EOD";
|
||||
|
||||
Your photon bomb exploded $miss_distance*10^2 miles from the
|
||||
Romulan ship.
|
||||
EOD
|
||||
if ( $miss_distance <= 50 ) {
|
||||
say "\nYou have successfully completed your mission.";
|
||||
last;
|
||||
} elsif ( $hour > 6 ) {
|
||||
say "\nYou have allowed the Romulans to escape.";
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
say "\nAnother Romulan ship has gone into orbit.";
|
||||
last unless get_yes_no( 'Do you wish to try to destroy it' );
|
||||
}
|
||||
|
||||
print <<'EOD';
|
||||
|
||||
Good bye.
|
||||
EOD
|
||||
|
||||
# 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( 'reverse' );
|
||||
$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 };
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 TITLE
|
||||
|
||||
orbit - Play the game 'Orbit' from Basic Computer Games
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
orbit.pl
|
||||
|
||||
=head1 DETAILS
|
||||
|
||||
This Perl script is a port of orbit, which is the 68th entry in Basic
|
||||
Computer Games.
|
||||
|
||||
In this game you are a planetary defense gunner trying to shoot down a
|
||||
cloaked Romulan ship before it can escape.
|
||||
|
||||
This is pretty much a straight port of the BASIC into idiomatic Perl.
|
||||
|
||||
=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 :
|
||||
131
69_Pizza/csharp/Pizza/CustomerMap.cs
Normal file
131
69_Pizza/csharp/Pizza/CustomerMap.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Pizza
|
||||
{
|
||||
internal class CustomerMap
|
||||
{
|
||||
private readonly int _mapSize;
|
||||
private readonly string[,] _customerMap;
|
||||
|
||||
public CustomerMap(int mapSize)
|
||||
{
|
||||
_mapSize = mapSize;
|
||||
_customerMap = GenerateCustomerMap();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets customer on position X, Y.
|
||||
/// </summary>
|
||||
/// <param name="x">Represents X position.</param>
|
||||
/// <param name="y">Represents Y position.</param>
|
||||
/// <returns>If positions is valid then returns customer name otherwise returns empty string.</returns>
|
||||
public string GetCustomerOnPosition(int x, int y)
|
||||
{
|
||||
if(IsPositionOutOfRange(x, y))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return _customerMap[y, x];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridden ToString for getting text representation of customers map.
|
||||
/// </summary>
|
||||
/// <returns>Text representation of customers map.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
int verticalSpace = 4;
|
||||
int horizontalSpace = 5;
|
||||
|
||||
var mapToDisplay = new StringBuilder();
|
||||
|
||||
AppendXLine(mapToDisplay, horizontalSpace);
|
||||
|
||||
for (int i = _customerMap.GetLength(0) - 1; i >= 0; i--)
|
||||
{
|
||||
mapToDisplay.AppendLine("-", verticalSpace);
|
||||
mapToDisplay.Append($"{i + 1}");
|
||||
mapToDisplay.Append(' ', horizontalSpace);
|
||||
|
||||
for (var j = 0; j < _customerMap.GetLength(1); j++)
|
||||
{
|
||||
mapToDisplay.Append($"{_customerMap[i, j]}");
|
||||
mapToDisplay.Append(' ', horizontalSpace);
|
||||
}
|
||||
|
||||
mapToDisplay.Append($"{i + 1}");
|
||||
mapToDisplay.Append(' ', horizontalSpace);
|
||||
mapToDisplay.Append(Environment.NewLine);
|
||||
}
|
||||
|
||||
mapToDisplay.AppendLine("-", verticalSpace);
|
||||
|
||||
AppendXLine(mapToDisplay, horizontalSpace);
|
||||
|
||||
return mapToDisplay.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if position is out of range or not.
|
||||
/// </summary>
|
||||
/// <param name="x">Represents X position.</param>
|
||||
/// <param name="y">Represents Y position.</param>
|
||||
/// <returns>True if position is out of range otherwise false.</returns>
|
||||
private bool IsPositionOutOfRange(int x, int y)
|
||||
{
|
||||
return
|
||||
x < 0 || x > _mapSize - 1 ||
|
||||
y < 0 || y > _mapSize - 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates array which represents customers map.
|
||||
/// </summary>
|
||||
/// <returns>Returns customers map.</returns>
|
||||
private string[,] GenerateCustomerMap()
|
||||
{
|
||||
string[,] customerMap = new string[_mapSize, _mapSize];
|
||||
string[] customerNames = GetCustomerNames(_mapSize * _mapSize);
|
||||
int currentCustomerNameIndex = 0;
|
||||
|
||||
for (int i = 0; i < customerMap.GetLength(0); i++)
|
||||
{
|
||||
for (int j = 0; j < customerMap.GetLength(1); j++)
|
||||
{
|
||||
customerMap[i, j] = customerNames[currentCustomerNameIndex++].ToString();
|
||||
}
|
||||
}
|
||||
|
||||
return customerMap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates customer names. Names are represented by alphanumerics from 'A'. Name of last customer depends on passed parameter.
|
||||
/// </summary>
|
||||
/// <param name="numberOfCustomers">How many customers need to be generated.</param>
|
||||
/// <returns>List of customer names.</returns>
|
||||
private static string[] GetCustomerNames(int numberOfCustomers)
|
||||
{
|
||||
// returns ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P"];
|
||||
return Enumerable.Range(65, numberOfCustomers).Select(c => ((Char)c).ToString()).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends line with X coordinates.
|
||||
/// </summary>
|
||||
/// <param name="mapToDisplay">Current map where a new line will be appended.</param>
|
||||
/// <param name="horizontalSpace">Number of horizontal delimiters which will be added between each coordination.</param>
|
||||
private void AppendXLine(StringBuilder mapToDisplay, int horizontalSpace)
|
||||
{
|
||||
mapToDisplay.Append(' ');
|
||||
mapToDisplay.Append('-', horizontalSpace);
|
||||
for (var i = 0; i < _customerMap.GetLength(0); i++)
|
||||
{
|
||||
mapToDisplay.Append($"{i + 1}");
|
||||
mapToDisplay.Append('-', horizontalSpace);
|
||||
}
|
||||
mapToDisplay.Append(Environment.NewLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
10
69_Pizza/csharp/Pizza/Pizza.csproj
Normal file
10
69_Pizza/csharp/Pizza/Pizza.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>
|
||||
25
69_Pizza/csharp/Pizza/Pizza.sln
Normal file
25
69_Pizza/csharp/Pizza/Pizza.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31912.275
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pizza", "Pizza.csproj", "{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {8F7E9FAD-38C5-47A2-B5CA-2B6E5947B982}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
296
69_Pizza/csharp/Pizza/PizzaGame.cs
Normal file
296
69_Pizza/csharp/Pizza/PizzaGame.cs
Normal file
@@ -0,0 +1,296 @@
|
||||
namespace Pizza
|
||||
{
|
||||
internal class PizzaGame
|
||||
{
|
||||
private const int CustomerMapSize = 4;
|
||||
private readonly CustomerMap _customerMap = new CustomerMap(CustomerMapSize);
|
||||
|
||||
/// <summary>
|
||||
/// Starts game. Main coordinator for pizza game.
|
||||
/// It is responsible for showing information, getting data from user and starting to delivery pizza.
|
||||
/// </summary>
|
||||
public void Play()
|
||||
{
|
||||
ShowHeader();
|
||||
|
||||
string playerName = GetPlayerName();
|
||||
|
||||
ShowIntroduction(playerName);
|
||||
ShowMap();
|
||||
|
||||
if (AskForMoreDirections())
|
||||
{
|
||||
ShowMoreDirections(playerName);
|
||||
|
||||
var playerUnderstands = AskIfPlayerUnderstand();
|
||||
if (!playerUnderstands)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
StartDelivery(playerName);
|
||||
EndDelivery(playerName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts with pizza delivering to customers.
|
||||
/// Every 5 deliveries it is asking user whether want to continue in delivering.
|
||||
/// </summary>
|
||||
/// <param name="playerName">Player name which was filled by user.</param>
|
||||
private void StartDelivery(string playerName)
|
||||
{
|
||||
var numberOfDeliveredPizzas = 0;
|
||||
while (true)
|
||||
{
|
||||
numberOfDeliveredPizzas++;
|
||||
string deliverPizzaToCustomer = GetRandomCustomer();
|
||||
|
||||
WriteEmptyLine();
|
||||
Console.WriteLine($"HELLO {playerName}'S PIZZA. THIS IS {deliverPizzaToCustomer}.");
|
||||
Console.WriteLine("\tPLEASE SEND A PIZZA.");
|
||||
|
||||
DeliverPizzaByPlayer(playerName, deliverPizzaToCustomer);
|
||||
|
||||
if (numberOfDeliveredPizzas % 5 == 0)
|
||||
{
|
||||
bool playerWantToDeliveryMorePizzas = AskQuestionWithYesNoResponse("DO YOU WANT TO DELIVER MORE PIZZAS?");
|
||||
if (!playerWantToDeliveryMorePizzas)
|
||||
{
|
||||
WriteEmptyLine();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets random customer for which pizza should be delivered.
|
||||
/// </summary>
|
||||
/// <returns>Customer name.</returns>
|
||||
private string GetRandomCustomer()
|
||||
{
|
||||
int randomPositionOnX = Random.Shared.Next(0, CustomerMapSize);
|
||||
int randomPositionOnY = Random.Shared.Next(0, CustomerMapSize);
|
||||
|
||||
return _customerMap.GetCustomerOnPosition(randomPositionOnX, randomPositionOnY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delivers pizza to customer by player. It verifies whether player was delivering pizza to correct customer.
|
||||
/// </summary>
|
||||
/// <param name="playerName">Player name which was filled by user.</param>
|
||||
/// <param name="deliverPizzaToCustomer">Customer name which order pizza.</param>
|
||||
private void DeliverPizzaByPlayer(string playerName, string deliverPizzaToCustomer)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
string userInput = GetPlayerInput($"\tDRIVER TO {playerName}: WHERE DOES {deliverPizzaToCustomer} LIVE?");
|
||||
var deliveredToCustomer = GetCustomerFromPlayerInput(userInput);
|
||||
if (string.IsNullOrEmpty(deliveredToCustomer))
|
||||
{
|
||||
deliveredToCustomer = "UNKNOWN CUSTOMER";
|
||||
}
|
||||
|
||||
if (deliveredToCustomer.Equals(deliverPizzaToCustomer))
|
||||
{
|
||||
Console.WriteLine($"HELLO {playerName}. THIS IS {deliverPizzaToCustomer}, THANKS FOR THE PIZZA.");
|
||||
break;
|
||||
}
|
||||
|
||||
Console.WriteLine($"THIS IS {deliveredToCustomer}. I DID NOT ORDER A PIZZA.");
|
||||
Console.WriteLine($"I LIVE AT {userInput}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets customer name by user input with customer coordinations.
|
||||
/// </summary>
|
||||
/// <param name="userInput">Input from users - it should represent customer coordination separated by ','.</param>
|
||||
/// <returns>If coordinations are correct and customer exists then returns true otherwise false.</returns>
|
||||
private string GetCustomerFromPlayerInput(string userInput)
|
||||
{
|
||||
var pizzaIsDeliveredToPosition = userInput?
|
||||
.Split(',')
|
||||
.Select(i => int.TryParse(i, out var customerPosition) ? (customerPosition - 1) : -1)
|
||||
.Where(i => i != -1)
|
||||
.ToArray() ?? Array.Empty<int>();
|
||||
if (pizzaIsDeliveredToPosition.Length != 2)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return _customerMap.GetCustomerOnPosition(pizzaIsDeliveredToPosition[0], pizzaIsDeliveredToPosition[1]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows game header in console.
|
||||
/// </summary>
|
||||
private void ShowHeader()
|
||||
{
|
||||
Console.WriteLine("PIZZA".PadLeft(22));
|
||||
Console.WriteLine("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
|
||||
WriteEmptyLine(3);
|
||||
Console.WriteLine("PIZZA DELIVERY GAME");
|
||||
WriteEmptyLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asks user for name which will be used in game.
|
||||
/// </summary>
|
||||
/// <returns>Player name.</returns>
|
||||
private string GetPlayerName()
|
||||
{
|
||||
return GetPlayerInput("WHAT IS YOUR FIRST NAME:");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows game introduction in console
|
||||
/// </summary>
|
||||
/// <param name="playerName">Player name which was filled by user.</param>
|
||||
private void ShowIntroduction(string playerName)
|
||||
{
|
||||
Console.WriteLine($"HI, {playerName}. IN THIS GAME YOU ARE TO TAKE ORDERS");
|
||||
Console.WriteLine("FOR PIZZAS. THEN YOU ARE TO TELL A DELIVERY BOY");
|
||||
Console.WriteLine("WHERE TO DELIVER THE ORDERED PIZZAS.");
|
||||
WriteEmptyLine(2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows customers map in console. In this method is used overridden method 'ToString' for getting text representation of customers map.
|
||||
/// </summary>
|
||||
private void ShowMap()
|
||||
{
|
||||
Console.WriteLine("MAP OF THE CITY OF HYATTSVILLE");
|
||||
WriteEmptyLine();
|
||||
|
||||
Console.WriteLine(_customerMap.ToString());
|
||||
|
||||
Console.WriteLine("THE OUTPUT IS A MAP OF THE HOMES WHERE");
|
||||
Console.WriteLine("YOU ARE TO SEND PIZZAS.");
|
||||
WriteEmptyLine();
|
||||
Console.WriteLine("YOUR JOB IS TO GIVE A TRUCK DRIVER");
|
||||
Console.WriteLine("THE LOCATION OR COORDINATES OF THE");
|
||||
Console.WriteLine("HOME ORDERING THE PIZZA.");
|
||||
WriteEmptyLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asks user if needs more directions.
|
||||
/// </summary>
|
||||
/// <returns>True if user need more directions otherwise false.</returns>
|
||||
private bool AskForMoreDirections()
|
||||
{
|
||||
var playerNeedsMoreDirections = AskQuestionWithYesNoResponse("DO YOU NEED MORE DIRECTIONS?");
|
||||
WriteEmptyLine();
|
||||
|
||||
return playerNeedsMoreDirections;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows more directions.
|
||||
/// </summary>
|
||||
/// <param name="playerName">Player name which was filled by user.</param>
|
||||
private void ShowMoreDirections(string playerName)
|
||||
{
|
||||
Console.WriteLine("SOMEBODY WILL ASK FOR A PIZZA TO BE");
|
||||
Console.WriteLine("DELIVERED. THEN A DELIVERY BOY WILL");
|
||||
Console.WriteLine("ASK YOU FOR THE LOCATION.");
|
||||
Console.WriteLine("\tEXAMPLE:");
|
||||
Console.WriteLine("THIS IS J. PLEASE SEND A PIZZA.");
|
||||
Console.WriteLine($"DRIVER TO {playerName}. WHERE DOES J LIVE?");
|
||||
Console.WriteLine("YOUR ANSWER WOULD BE 2,3");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asks user if understands to instructions.
|
||||
/// </summary>
|
||||
/// <returns>True if user understand otherwise false.</returns>
|
||||
private bool AskIfPlayerUnderstand()
|
||||
{
|
||||
var playerUnderstands = AskQuestionWithYesNoResponse("UNDERSTAND?");
|
||||
if (!playerUnderstands)
|
||||
{
|
||||
Console.WriteLine("THIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY");
|
||||
return false;
|
||||
}
|
||||
|
||||
WriteEmptyLine();
|
||||
Console.WriteLine("GOOD. YOU ARE NOW READY TO START TAKING ORDERS.");
|
||||
WriteEmptyLine();
|
||||
Console.WriteLine("GOOD LUCK!!");
|
||||
WriteEmptyLine();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows message about ending delivery in console.
|
||||
/// </summary>
|
||||
/// <param name="playerName">Player name which was filled by user.</param>
|
||||
private void EndDelivery(string playerName)
|
||||
{
|
||||
Console.WriteLine($"O.K. {playerName}, SEE YOU LATER!");
|
||||
WriteEmptyLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets input from user.
|
||||
/// </summary>
|
||||
/// <param name="question">Question which is displayed in console.</param>
|
||||
/// <returns>User input.</returns>
|
||||
private string GetPlayerInput(string question)
|
||||
{
|
||||
Console.Write($"{question} ");
|
||||
|
||||
while (true)
|
||||
{
|
||||
var userInput = Console.ReadLine();
|
||||
if (!string.IsNullOrWhiteSpace(userInput))
|
||||
{
|
||||
return userInput;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asks user with required resposne 'YES', 'Y, 'NO', 'N'.
|
||||
/// </summary>
|
||||
/// <param name="question">Question which is displayed in console.</param>
|
||||
/// <returns>True if user write 'YES', 'Y'. False if user write 'NO', 'N'.</returns>
|
||||
private static bool AskQuestionWithYesNoResponse(string question)
|
||||
{
|
||||
var possitiveResponse = new string[] { "Y", "YES" };
|
||||
var negativeResponse = new string[] { "N", "NO" };
|
||||
var validUserInputs = possitiveResponse.Concat(negativeResponse);
|
||||
|
||||
Console.Write($"{question} ");
|
||||
|
||||
string? userInput;
|
||||
while (true)
|
||||
{
|
||||
userInput = Console.ReadLine();
|
||||
if (!string.IsNullOrWhiteSpace(userInput) && validUserInputs.Contains(userInput.ToUpper()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Console.Write($"'YES' OR 'NO' PLEASE, NOW THEN, {question} ");
|
||||
}
|
||||
|
||||
return possitiveResponse.Contains(userInput.ToUpper());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes empty line in console.
|
||||
/// </summary>
|
||||
/// <param name="numberOfEmptyLines">Number of empty lines which will be written in console. Parameter is optional and default value is 1.</param>
|
||||
private void WriteEmptyLine(int numberOfEmptyLines = 1)
|
||||
{
|
||||
for (int i = 0; i < numberOfEmptyLines; i++)
|
||||
{
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
69_Pizza/csharp/Pizza/Program.cs
Normal file
11
69_Pizza/csharp/Pizza/Program.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Pizza
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var pizzaGame = new PizzaGame();
|
||||
pizzaGame.Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
21
69_Pizza/csharp/Pizza/StringBuilderExtensions.cs
Normal file
21
69_Pizza/csharp/Pizza/StringBuilderExtensions.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Pizza
|
||||
{
|
||||
internal static class StringBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for adding new lines of specific value.
|
||||
/// </summary>
|
||||
/// <param name="stringBuilder">Extended class.</param>
|
||||
/// <param name="value">Value which will be repeated.</param>
|
||||
/// <param name="numberOfLines">Number of lines that will be appended.</param>
|
||||
public static void AppendLine(this StringBuilder stringBuilder, string value, int numberOfLines)
|
||||
{
|
||||
for (int i = 0; i < numberOfLines; i++)
|
||||
{
|
||||
stringBuilder.AppendLine(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
851
71_Poker/java/Poker.java
Normal file
851
71_Poker/java/Poker.java
Normal file
@@ -0,0 +1,851 @@
|
||||
import java.util.Random;
|
||||
import java.util.Scanner;
|
||||
|
||||
import static java.lang.System.out;
|
||||
|
||||
/**
|
||||
* Port of CREATIVE COMPUTING Poker written in Commodore 64 Basic to plain Java
|
||||
*
|
||||
* Original source scanned from magazine: https://www.atariarchives.org/basicgames/showpage.php?page=129
|
||||
*
|
||||
* I based my port on the OCR'ed source code here: https://github.com/coding-horror/basic-computer-games/blob/main/71_Poker/poker.bas
|
||||
*
|
||||
* Why? Because I remember typing this into my C64 when I was a tiny little developer and having great fun playing it!
|
||||
*
|
||||
* Goal: Keep the algorithms and UX more or less as-is; Improve the control flow a bit (no goto in Java!) and rename some stuff to be easier to follow.
|
||||
*
|
||||
* Result: There are probably bugs, please let me know.
|
||||
*/
|
||||
public class Poker {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new Poker().run();
|
||||
}
|
||||
|
||||
float[] cards = new float[50]; // Index 1-5 = Human hand, index 6-10 = Computer hand
|
||||
float[] B = new float[15];
|
||||
|
||||
float playerValuables = 1;
|
||||
float computerMoney = 200;
|
||||
float humanMoney = 200;
|
||||
float pot = 0;
|
||||
|
||||
String J$ = "";
|
||||
float computerHandValue = 0;
|
||||
|
||||
int K = 0;
|
||||
float G = 0;
|
||||
float T = 0;
|
||||
int M = 0;
|
||||
int D = 0;
|
||||
|
||||
int U = 0;
|
||||
float N = 1;
|
||||
|
||||
float I = 0;
|
||||
|
||||
float X = 0;
|
||||
|
||||
int Z = 0;
|
||||
|
||||
String handDescription = "";
|
||||
|
||||
float V;
|
||||
|
||||
void run() {
|
||||
printWelcome();
|
||||
playRound();
|
||||
startAgain();
|
||||
}
|
||||
|
||||
void printWelcome() {
|
||||
tab(33);
|
||||
out.println("POKER");
|
||||
tab(15);
|
||||
out.print("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
|
||||
out.println();
|
||||
out.println();
|
||||
out.println();
|
||||
out.println("WELCOME TO THE CASINO. WE EACH HAVE $200.");
|
||||
out.println("I WILL OPEN THE BETTING BEFORE THE DRAW; YOU OPEN AFTER.");
|
||||
out.println("TO FOLD BET 0; TO CHECK BET .5.");
|
||||
out.println("ENOUGH TALK -- LET'S GET DOWN TO BUSINESS.");
|
||||
out.println();
|
||||
}
|
||||
|
||||
void tab(int number) {
|
||||
System.out.print("\t".repeat(number));
|
||||
}
|
||||
|
||||
int random0to10() {
|
||||
return new Random().nextInt(10);
|
||||
}
|
||||
|
||||
int removeHundreds(long x) {
|
||||
return _int(x - (100F * _int(x / 100F)));
|
||||
}
|
||||
|
||||
void startAgain() {
|
||||
pot = 0;
|
||||
playRound();
|
||||
}
|
||||
|
||||
void playRound() {
|
||||
if (computerMoney <= 5) {
|
||||
computerBroke();
|
||||
}
|
||||
|
||||
out.println("THE ANTE IS $5. I WILL DEAL:");
|
||||
out.println();
|
||||
|
||||
if (humanMoney <= 5) {
|
||||
playerBroke();
|
||||
}
|
||||
|
||||
pot = pot + 10;
|
||||
humanMoney = humanMoney - 5;
|
||||
computerMoney = computerMoney - 5;
|
||||
for (int Z = 1; Z < 10; Z++) {
|
||||
generateCards(Z);
|
||||
}
|
||||
out.println("YOUR HAND:");
|
||||
N = 1;
|
||||
showHand();
|
||||
N = 6;
|
||||
I = 2;
|
||||
|
||||
describeHand();
|
||||
|
||||
out.println();
|
||||
|
||||
if (I != 6) {
|
||||
if (U >= 13) {
|
||||
if (U <= 16) {
|
||||
Z = 35;
|
||||
} else {
|
||||
Z = 2;
|
||||
if (random0to10() < 1) {
|
||||
Z = 35;
|
||||
}
|
||||
}
|
||||
computerOpens();
|
||||
playerMoves();
|
||||
} else if (random0to10() >= 2) {
|
||||
computerChecks();
|
||||
} else {
|
||||
I = 7;
|
||||
Z = 23;
|
||||
computerOpens();
|
||||
playerMoves();
|
||||
}
|
||||
} else if (random0to10() <= 7) {
|
||||
if (random0to10() <= 7) {
|
||||
if (random0to10() >= 1) {
|
||||
Z = 1;
|
||||
K = 0;
|
||||
out.print("I CHECK. ");
|
||||
playerMoves();
|
||||
} else {
|
||||
X = 11111;
|
||||
I = 7;
|
||||
Z = 23;
|
||||
computerOpens();
|
||||
playerMoves();
|
||||
}
|
||||
} else {
|
||||
X = 11110;
|
||||
I = 7;
|
||||
Z = 23;
|
||||
computerOpens();
|
||||
playerMoves();
|
||||
}
|
||||
} else {
|
||||
X = 11100;
|
||||
I = 7;
|
||||
Z = 23;
|
||||
computerOpens();
|
||||
playerMoves();
|
||||
}
|
||||
}
|
||||
|
||||
void playerMoves() {
|
||||
playersTurn();
|
||||
checkWinnerAfterFirstBet();
|
||||
promptPlayerDrawCards();
|
||||
}
|
||||
|
||||
void computerOpens() {
|
||||
V = Z + random0to10();
|
||||
computerMoves();
|
||||
out.print("I'LL OPEN WITH $" + V);
|
||||
K = _int(V);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StatementWithEmptyBody")
|
||||
void computerMoves() {
|
||||
if (computerMoney - G - V >= 0) {
|
||||
} else if (G != 0) {
|
||||
if (computerMoney - G >= 0) {
|
||||
computerSees();
|
||||
} else {
|
||||
computerBroke();
|
||||
}
|
||||
} else {
|
||||
V = computerMoney;
|
||||
}
|
||||
}
|
||||
|
||||
void promptPlayerDrawCards() {
|
||||
out.println();
|
||||
out.println("NOW WE DRAW -- HOW MANY CARDS DO YOU WANT");
|
||||
inputPlayerDrawCards();
|
||||
}
|
||||
|
||||
void inputPlayerDrawCards() {
|
||||
T = Integer.parseInt(readString());
|
||||
if (T == 0) {
|
||||
computerDrawing();
|
||||
} else {
|
||||
Z = 10;
|
||||
if (T < 4) {
|
||||
playerDrawsCards();
|
||||
} else {
|
||||
out.println("YOU CAN'T DRAW MORE THAN THREE CARDS.");
|
||||
inputPlayerDrawCards();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// line # 980
|
||||
void computerDrawing() {
|
||||
Z = _int(10 + T);
|
||||
for (U = 6; U <= 10; U++) {
|
||||
if (_int((float) (X / Math.pow(10F, (U - 6F)))) == (10 * (_int((float) (X / Math.pow(10, (U - 5))))))) {
|
||||
drawNextCard();
|
||||
}
|
||||
}
|
||||
out.print("I AM TAKING " + _int(Z - 10 - T) + " CARD");
|
||||
if (Z == 11 + T) {
|
||||
out.println();
|
||||
} else {
|
||||
out.println("S");
|
||||
}
|
||||
|
||||
N = 6;
|
||||
V = I;
|
||||
I = 1;
|
||||
describeHand();
|
||||
startPlayerBettingAndReaction();
|
||||
}
|
||||
|
||||
void drawNextCard() {
|
||||
Z = Z + 1;
|
||||
drawCard();
|
||||
}
|
||||
|
||||
@SuppressWarnings("StatementWithEmptyBody")
|
||||
void drawCard() {
|
||||
cards[Z] = 100 * new Random().nextInt(4) + new Random().nextInt(100);
|
||||
if (_int(cards[Z] / 100) > 3) {
|
||||
drawCard();
|
||||
} else if (cards[Z] - 100 * _int(cards[Z] / 100) > 12) {
|
||||
drawCard();
|
||||
} else if (Z == 1) {
|
||||
} else {
|
||||
for (K = 1; K <= Z - 1; K++) {
|
||||
if (cards[Z] == cards[K]) {
|
||||
drawCard();
|
||||
}
|
||||
}
|
||||
if (Z <= 10) {
|
||||
} else {
|
||||
N = cards[U];
|
||||
cards[U] = cards[Z];
|
||||
cards[Z] = N;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void playerDrawsCards() {
|
||||
out.println("WHAT ARE THEIR NUMBERS:");
|
||||
for (int Q = 1; Q <= T; Q++) {
|
||||
U = Integer.parseInt(readString());
|
||||
drawNextCard();
|
||||
}
|
||||
|
||||
out.println("YOUR NEW HAND:");
|
||||
N = 1;
|
||||
showHand();
|
||||
computerDrawing();
|
||||
}
|
||||
|
||||
void startPlayerBettingAndReaction() {
|
||||
computerHandValue = U;
|
||||
M = D;
|
||||
|
||||
if (V != 7) {
|
||||
if (I != 6) {
|
||||
if (U >= 13) {
|
||||
if (U >= 16) {
|
||||
Z = 2;
|
||||
playerBetsAndComputerReacts();
|
||||
} else {
|
||||
Z = 19;
|
||||
if (random0to10() == 8) {
|
||||
Z = 11;
|
||||
}
|
||||
playerBetsAndComputerReacts();
|
||||
}
|
||||
} else {
|
||||
Z = 2;
|
||||
if (random0to10() == 6) {
|
||||
Z = 19;
|
||||
}
|
||||
playerBetsAndComputerReacts();
|
||||
}
|
||||
} else {
|
||||
Z = 1;
|
||||
playerBetsAndComputerReacts();
|
||||
}
|
||||
} else {
|
||||
Z = 28;
|
||||
playerBetsAndComputerReacts();
|
||||
}
|
||||
}
|
||||
|
||||
void playerBetsAndComputerReacts() {
|
||||
K = 0;
|
||||
playersTurn();
|
||||
if (T != .5) {
|
||||
checkWinnerAfterFirstBetAndCompareHands();
|
||||
} else if (V == 7 || I != 6) {
|
||||
computerOpens();
|
||||
promptAndInputPlayerBet();
|
||||
checkWinnerAfterFirstBetAndCompareHands();
|
||||
} else {
|
||||
out.println("I'LL CHECK");
|
||||
compareHands();
|
||||
}
|
||||
}
|
||||
|
||||
void checkWinnerAfterFirstBetAndCompareHands() {
|
||||
checkWinnerAfterFirstBet();
|
||||
compareHands();
|
||||
}
|
||||
|
||||
void compareHands() {
|
||||
out.println("NOW WE COMPARE HANDS:");
|
||||
J$ = handDescription;
|
||||
out.println("MY HAND:");
|
||||
N = 6;
|
||||
showHand();
|
||||
N = 1;
|
||||
describeHand();
|
||||
out.print("YOU HAVE ");
|
||||
K = D;
|
||||
printHandDescriptionResult();
|
||||
handDescription = J$;
|
||||
K = M;
|
||||
out.print(" AND I HAVE ");
|
||||
printHandDescriptionResult();
|
||||
out.print(". ");
|
||||
if (computerHandValue > U) {
|
||||
computerWins();
|
||||
} else if (U > computerHandValue) {
|
||||
humanWins();
|
||||
} else if (handDescription.contains("A FLUS")) {
|
||||
someoneWinsWithFlush();
|
||||
} else if (removeHundreds(M) < removeHundreds(D)) {
|
||||
humanWins();
|
||||
} else if (removeHundreds(M) > removeHundreds(D)) {
|
||||
computerWins();
|
||||
} else {
|
||||
handIsDrawn();
|
||||
}
|
||||
}
|
||||
|
||||
void printHandDescriptionResult() {
|
||||
out.print(handDescription);
|
||||
if (!handDescription.contains("A FLUS")) {
|
||||
K = removeHundreds(K);
|
||||
printCardValue();
|
||||
if (handDescription.contains("SCHMAL")) {
|
||||
out.print(" HIGH");
|
||||
} else if (!handDescription.contains("STRAIG")) {
|
||||
out.print("'S");
|
||||
} else {
|
||||
out.print(" HIGH");
|
||||
}
|
||||
} else {
|
||||
K = K / 100;
|
||||
printCardColor();
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
|
||||
void handIsDrawn() {
|
||||
out.print("THE HAND IS DRAWN.");
|
||||
out.print("ALL $" + pot + " REMAINS IN THE POT.");
|
||||
playRound();
|
||||
}
|
||||
|
||||
void someoneWinsWithFlush() {
|
||||
if (removeHundreds(M) > removeHundreds(D)) {
|
||||
computerWins();
|
||||
} else if (removeHundreds(D) > removeHundreds(M)) {
|
||||
humanWins();
|
||||
} else {
|
||||
handIsDrawn();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("StatementWithEmptyBody")
|
||||
void checkWinnerAfterFirstBet() {
|
||||
if (I != 3) {
|
||||
if (I != 4) {
|
||||
} else {
|
||||
humanWins();
|
||||
}
|
||||
} else {
|
||||
out.println();
|
||||
computerWins();
|
||||
}
|
||||
}
|
||||
|
||||
void computerWins() {
|
||||
out.print(". I WIN. ");
|
||||
computerMoney = computerMoney + pot;
|
||||
potStatusAndNextRoundPrompt();
|
||||
}
|
||||
|
||||
void potStatusAndNextRoundPrompt() {
|
||||
out.println("NOW I HAVE $" + computerMoney + " AND YOU HAVE $" + humanMoney);
|
||||
out.print("DO YOU WISH TO CONTINUE");
|
||||
|
||||
if (yesFromPrompt()) {
|
||||
startAgain();
|
||||
} else {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean yesFromPrompt() {
|
||||
String h = readString();
|
||||
if (h != null) {
|
||||
if (h.toLowerCase().matches("y|yes|yep|affirmative|yay")) {
|
||||
return true;
|
||||
} else if (h.toLowerCase().matches("n|no|nope|fuck off|nay")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
out.println("ANSWER YES OR NO, PLEASE.");
|
||||
return yesFromPrompt();
|
||||
}
|
||||
|
||||
void computerChecks() {
|
||||
Z = 0;
|
||||
K = 0;
|
||||
out.print("I CHECK. ");
|
||||
playerMoves();
|
||||
}
|
||||
|
||||
void humanWins() {
|
||||
out.println("YOU WIN.");
|
||||
humanMoney = humanMoney + pot;
|
||||
potStatusAndNextRoundPrompt();
|
||||
}
|
||||
|
||||
// line # 1740
|
||||
void generateCards(int Z) {
|
||||
cards[Z] = (100 * new Random().nextInt(4)) + new Random().nextInt(100);
|
||||
if (_int(cards[Z] / 100) > 3) {
|
||||
generateCards(Z);
|
||||
return;
|
||||
}
|
||||
if (cards[Z] - 100 * (_int(cards[Z] / 100)) > 12) {
|
||||
generateCards(Z);
|
||||
return;
|
||||
}
|
||||
if (Z == 1) {return;}
|
||||
for (int K = 1; K <= Z - 1; K++) {// TO Z-1
|
||||
if (cards[Z] == cards[K]) {
|
||||
generateCards(Z);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (Z <= 10) {return;}
|
||||
float N = cards[U];
|
||||
cards[U] = cards[Z];
|
||||
cards[Z] = N;
|
||||
}
|
||||
|
||||
// line # 1850
|
||||
void showHand() {
|
||||
for (int cardNumber = _int(N); cardNumber <= N + 4; cardNumber++) {
|
||||
out.print(cardNumber + "-- ");
|
||||
printCardValueAtIndex(cardNumber);
|
||||
out.print(" OF");
|
||||
printCardColorAtIndex(cardNumber);
|
||||
if (cardNumber / 2 == (cardNumber / 2)) {
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// line # 1950
|
||||
void printCardValueAtIndex(int Z) {
|
||||
K = removeHundreds(_int(cards[Z]));
|
||||
printCardValue();
|
||||
}
|
||||
|
||||
void printCardValue() {
|
||||
if (K == 9) {
|
||||
out.print("JACK");
|
||||
} else if (K == 10) {
|
||||
out.print("QUEEN");
|
||||
} else if (K == 11) {
|
||||
out.print("KING");
|
||||
} else if (K == 12) {
|
||||
out.print("ACE");
|
||||
} else if (K < 9) {
|
||||
out.print(K + 2);
|
||||
}
|
||||
}
|
||||
|
||||
// line # 2070
|
||||
void printCardColorAtIndex(int Z) {
|
||||
K = _int(cards[Z] / 100);
|
||||
printCardColor();
|
||||
}
|
||||
|
||||
void printCardColor() {
|
||||
if (K == 0) {
|
||||
out.print(" CLUBS");
|
||||
} else if (K == 1) {
|
||||
out.print(" DIAMONDS");
|
||||
} else if (K == 2) {
|
||||
out.print(" HEARTS");
|
||||
} else if (K == 3) {
|
||||
out.print(" SPADES");
|
||||
}
|
||||
}
|
||||
|
||||
// line # 2170
|
||||
void describeHand() {
|
||||
U = 0;
|
||||
for (Z = _int(N); Z <= N + 4; Z++) {
|
||||
B[Z] = removeHundreds(_int(cards[Z]));
|
||||
if (Z == N + 4) {continue;}
|
||||
if (_int(cards[Z] / 100) != _int(cards[Z + 1] / 100)) {continue;}
|
||||
U = U + 1;
|
||||
}
|
||||
if (U != 4) {
|
||||
for (Z = _int(N); Z <= N + 3; Z++) {
|
||||
for (K = Z + 1; K <= N + 4; K++) {
|
||||
if (B[Z] <= B[K]) {continue;}
|
||||
X = cards[Z];
|
||||
cards[Z] = cards[K];
|
||||
B[Z] = B[K];
|
||||
cards[K] = X;
|
||||
B[K] = cards[K] - 100 * _int(cards[K] / 100);
|
||||
}
|
||||
}
|
||||
X = 0;
|
||||
for (Z = _int(N); Z <= N + 3; Z++) {
|
||||
if (B[Z] != B[Z + 1]) {continue;}
|
||||
X = (float) (X + 11 * Math.pow(10, (Z - N)));
|
||||
D = _int(cards[Z]);
|
||||
|
||||
if (U >= 11) {
|
||||
if (U != 11) {
|
||||
if (U > 12) {
|
||||
if (B[Z] != B[Z - 1]) {
|
||||
fullHouse();
|
||||
} else {
|
||||
U = 17;
|
||||
handDescription = "FOUR ";
|
||||
}
|
||||
} else {
|
||||
fullHouse();
|
||||
}
|
||||
} else if (B[Z] != B[Z - 1]) {
|
||||
handDescription = "TWO PAIR, ";
|
||||
U = 12;
|
||||
} else {
|
||||
handDescription = "THREE ";
|
||||
U = 13;
|
||||
}
|
||||
} else {
|
||||
U = 11;
|
||||
handDescription = "A PAIR OF ";
|
||||
}
|
||||
}
|
||||
|
||||
if (X != 0) {
|
||||
schmaltzHand();
|
||||
} else {
|
||||
if (B[_int(N)] + 3 == B[_int(N + 3)]) {
|
||||
X = 1111;
|
||||
U = 10;
|
||||
}
|
||||
if (B[_int(N + 1)] + 3 != B[_int(N + 4)]) {
|
||||
schmaltzHand();
|
||||
} else if (U != 10) {
|
||||
U = 10;
|
||||
X = 11110;
|
||||
schmaltzHand();
|
||||
} else {
|
||||
U = 14;
|
||||
handDescription = "STRAIGHT";
|
||||
X = 11111;
|
||||
D = _int(cards[_int(N + 4)]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
X = 11111;
|
||||
D = _int(cards[_int(N)]);
|
||||
handDescription = "A FLUSH IN";
|
||||
U = 15;
|
||||
}
|
||||
}
|
||||
|
||||
void schmaltzHand() {
|
||||
if (U >= 10) {
|
||||
if (U != 10) {
|
||||
if (U > 12) {return;}
|
||||
if (removeHundreds(D) <= 6) {
|
||||
I = 6;
|
||||
}
|
||||
} else {
|
||||
if (I == 1) {
|
||||
I = 6;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
D = _int(cards[_int(N + 4)]);
|
||||
handDescription = "SCHMALTZ, ";
|
||||
U = 9;
|
||||
X = 11000;
|
||||
I = 6;
|
||||
}
|
||||
}
|
||||
|
||||
void fullHouse() {
|
||||
U = 16;
|
||||
handDescription = "FULL HOUSE, ";
|
||||
}
|
||||
|
||||
void playersTurn() {
|
||||
G = 0;
|
||||
promptAndInputPlayerBet();
|
||||
}
|
||||
|
||||
String readString() {
|
||||
Scanner sc = new Scanner(System.in);
|
||||
return sc.nextLine();
|
||||
}
|
||||
|
||||
@SuppressWarnings("StatementWithEmptyBody")
|
||||
void promptAndInputPlayerBet() {
|
||||
out.println("WHAT IS YOUR BET");
|
||||
T = readFloat();
|
||||
if (T - _int(T) == 0) {
|
||||
processPlayerBet();
|
||||
} else if (K != 0) {
|
||||
playerBetInvalidAmount();
|
||||
} else if (G != 0) {
|
||||
playerBetInvalidAmount();
|
||||
} else if (T == .5) {
|
||||
} else {
|
||||
playerBetInvalidAmount();
|
||||
}
|
||||
}
|
||||
|
||||
private float readFloat() {
|
||||
try {
|
||||
return Float.parseFloat(readString());
|
||||
} catch (Exception ex) {
|
||||
System.out.println("INVALID INPUT, PLEASE TYPE A FLOAT. ");
|
||||
return readFloat();
|
||||
}
|
||||
}
|
||||
|
||||
void playerBetInvalidAmount() {
|
||||
out.println("NO SMALL CHANGE, PLEASE.");
|
||||
promptAndInputPlayerBet();
|
||||
}
|
||||
|
||||
void processPlayerBet() {
|
||||
if (humanMoney - G - T >= 0) {
|
||||
humanCanAffordBet();
|
||||
} else {
|
||||
playerBroke();
|
||||
promptAndInputPlayerBet();
|
||||
}
|
||||
}
|
||||
|
||||
void humanCanAffordBet() {
|
||||
if (T != 0) {
|
||||
if (G + T >= K) {
|
||||
processComputerMove();
|
||||
} else {
|
||||
out.println("IF YOU CAN'T SEE MY BET, THEN FOLD.");
|
||||
promptAndInputPlayerBet();
|
||||
}
|
||||
} else {
|
||||
I = 3;
|
||||
moveMoneyToPot();
|
||||
}
|
||||
}
|
||||
|
||||
void processComputerMove() {
|
||||
G = G + T;
|
||||
if (G == K) {
|
||||
moveMoneyToPot();
|
||||
} else if (Z != 1) {
|
||||
if (G > 3 * Z) {
|
||||
computerRaisesOrSees();
|
||||
} else {
|
||||
computerRaises();
|
||||
}
|
||||
} else if (G > 5) {
|
||||
if (T <= 25) {
|
||||
computerRaisesOrSees();
|
||||
} else {
|
||||
computerFolds();
|
||||
}
|
||||
} else {
|
||||
V = 5;
|
||||
if (G > 3 * Z) {
|
||||
computerRaisesOrSees();
|
||||
} else {
|
||||
computerRaises();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void computerRaises() {
|
||||
V = G - K + random0to10();
|
||||
computerMoves();
|
||||
out.println("I'LL SEE YOU, AND RAISE YOU" + V);
|
||||
K = _int(G + V);
|
||||
promptAndInputPlayerBet();
|
||||
}
|
||||
|
||||
void computerFolds() {
|
||||
I = 4;
|
||||
out.println("I FOLD.");
|
||||
}
|
||||
|
||||
void computerRaisesOrSees() {
|
||||
if (Z == 2) {
|
||||
computerRaises();
|
||||
} else {
|
||||
computerSees();
|
||||
}
|
||||
}
|
||||
|
||||
void computerSees() {
|
||||
out.println("I'LL SEE YOU.");
|
||||
K = _int(G);
|
||||
moveMoneyToPot();
|
||||
}
|
||||
|
||||
void moveMoneyToPot() {
|
||||
humanMoney = humanMoney - G;
|
||||
computerMoney = computerMoney - K;
|
||||
pot = pot + G + K;
|
||||
}
|
||||
|
||||
void computerBusted() {
|
||||
out.println("I'M BUSTED. CONGRATULATIONS!");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StatementWithEmptyBody")
|
||||
private void computerBroke() {
|
||||
if ((playerValuables / 2) == _int(playerValuables / 2) && playerBuyBackWatch()) {
|
||||
} else if (playerValuables / 3 == _int(playerValuables / 3) && playerBuyBackTieRack()) {
|
||||
} else {
|
||||
computerBusted();
|
||||
}
|
||||
}
|
||||
|
||||
private int _int(float v) {
|
||||
return (int) Math.floor(v);
|
||||
}
|
||||
|
||||
private boolean playerBuyBackWatch() {
|
||||
out.println("WOULD YOU LIKE TO BUY BACK YOUR WATCH FOR $50");
|
||||
if (yesFromPrompt()) {
|
||||
computerMoney = computerMoney + 50;
|
||||
playerValuables = playerValuables / 2;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean playerBuyBackTieRack() {
|
||||
out.println("WOULD YOU LIKE TO BUY BACK YOUR TIE TACK FOR $50");
|
||||
if (yesFromPrompt()) {
|
||||
computerMoney = computerMoney + 50;
|
||||
playerValuables = playerValuables / 3;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// line # 3830
|
||||
@SuppressWarnings("StatementWithEmptyBody")
|
||||
void playerBroke() {
|
||||
out.println("YOU CAN'T BET WITH WHAT YOU HAVEN'T GOT.");
|
||||
if (playerValuables / 2 != _int(playerValuables / 2) && playerSellWatch()) {
|
||||
} else if (playerValuables / 3 != _int(playerValuables / 3) && playerSellTieTack()) {
|
||||
} else {
|
||||
playerBusted();
|
||||
}
|
||||
}
|
||||
|
||||
private void playerBusted() {
|
||||
out.println("YOUR WAD IS SHOT. SO LONG, SUCKER!");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
private boolean playerSellWatch() {
|
||||
out.println("WOULD YOU LIKE TO SELL YOUR WATCH");
|
||||
if (yesFromPrompt()) {
|
||||
if (random0to10() < 7) {
|
||||
out.println("I'LL GIVE YOU $75 FOR IT.");
|
||||
humanMoney = humanMoney + 75;
|
||||
} else {
|
||||
out.println("THAT'S A PRETTY CRUMMY WATCH - I'LL GIVE YOU $25.");
|
||||
humanMoney = humanMoney + 25;
|
||||
}
|
||||
playerValuables = playerValuables * 2;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean playerSellTieTack() {
|
||||
out.println("WILL YOU PART WITH THAT DIAMOND TIE TACK");
|
||||
|
||||
if (yesFromPrompt()) {
|
||||
if (random0to10() < 6) {
|
||||
out.println("YOU ARE NOW $100 RICHER.");
|
||||
humanMoney = humanMoney + 100;
|
||||
} else {
|
||||
out.println("IT'S PASTE. $25.");
|
||||
humanMoney = humanMoney + 25;
|
||||
}
|
||||
playerValuables = playerValuables * 3;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
209
72_Queen/perl/queen.pl
Normal file
209
72_Queen/perl/queen.pl
Normal file
@@ -0,0 +1,209 @@
|
||||
#!/usr/bin/env perl
|
||||
use v5.24;
|
||||
use warnings;
|
||||
use experimental 'signatures';
|
||||
no warnings 'experimental::signatures';
|
||||
|
||||
use constant TARGET => 158;
|
||||
|
||||
main(@ARGV);
|
||||
|
||||
sub main (@args) {
|
||||
welcome();
|
||||
help() if ask_yes_no('DO YOU WANT INSTRUCTIONS');
|
||||
do { one_match() } while ask_yes_no('ANYONE ELSE CARE TO TRY');
|
||||
__exit();
|
||||
}
|
||||
|
||||
sub one_match {
|
||||
print_board();
|
||||
|
||||
# the player can choose the starting position in the top row or the
|
||||
# right column
|
||||
my $move = ask_first_move() or return forfeit();
|
||||
|
||||
# we alternate moves between computer or player from now on
|
||||
while ('playing') {
|
||||
$move = computer_move($move);
|
||||
say "COMPUTER MOVES TO SQUARE $move";
|
||||
return print_computer_victory() if $move == TARGET;
|
||||
|
||||
$move = ask_player_move($move) or return forfeit();
|
||||
return print_player_victory() if $move == TARGET;
|
||||
}
|
||||
}
|
||||
|
||||
sub is_valid_move ($move, $current, $skip_prevalidation = 0) {
|
||||
|
||||
# pre-validation is needed for moves coming from the user
|
||||
if (! $skip_prevalidation) {
|
||||
state $valid_position = { map { $_ => 1 } board_identifiers() };
|
||||
return 0 unless $move =~ m{\A [1-9]\d+ \z}mxs;
|
||||
return 1 if $move == 0;
|
||||
return 0 unless $valid_position->{$move};
|
||||
return 0 if $move <= $current;
|
||||
}
|
||||
|
||||
# the move might be valid in general, let's check from $current
|
||||
my $delta = $move - $current;
|
||||
|
||||
# a valid move differs from the current position by a multiple of 10,
|
||||
# or 11, or 21. If dividing by all of them yields a remainder, then
|
||||
# the move is not valid
|
||||
return 0 if $delta % 10 && $delta % 11 && $delta % 21;
|
||||
|
||||
# otherwise it is
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub ask_player_move ($current) {
|
||||
while ('necessary') {
|
||||
my $move = ask_input('WHAT IS YOUR MOVE');
|
||||
return $move if is_valid_move($move, $current);
|
||||
say "\nY O U C H E A T . . . TRY AGAIN";
|
||||
}
|
||||
}
|
||||
|
||||
sub computer_move ($current) {
|
||||
|
||||
# this game has some optimal/safe positions from where it's possible
|
||||
# to win with the right strategy. We will aim for them, if possible
|
||||
state $optimals = [ 158, 127, 126, 75, 73 ];
|
||||
for my $optimal ($optimals->@*) {
|
||||
|
||||
# moves can only increase, if we did not find any optimal move so far
|
||||
# then there's no point going on
|
||||
last if $optimal <= $current;
|
||||
|
||||
# computer moves are "syntactically" valid, skip pre-validation
|
||||
return $optimal if is_valid_move($optimal, $current, 'skip');
|
||||
|
||||
}
|
||||
|
||||
# cannot reach an optimal position... resort to randomness
|
||||
my $z = rand();
|
||||
return $current + 11 if $z > 0.6; # move down
|
||||
return $current + 21 if $z > 0.3; # move diagonally
|
||||
return $current + 10; ; # move horizontally
|
||||
}
|
||||
|
||||
sub board_identifiers {
|
||||
return (
|
||||
81, 71, 61, 51, 41, 31, 21, 11,
|
||||
92, 82, 72, 62, 52, 42, 32, 22,
|
||||
103, 93, 83, 73, 63, 53, 43, 33,
|
||||
114, 104, 94, 84, 74, 64, 54, 44,
|
||||
125, 115, 105, 95, 85, 75, 65, 55,
|
||||
136, 126, 116, 106, 96, 86, 76, 66,
|
||||
147, 137, 127, 117, 107, 97, 87, 77,
|
||||
158, 148, 138, 128, 118, 108, 98, 88,
|
||||
);
|
||||
}
|
||||
|
||||
sub print_player_victory {
|
||||
print <<'END';
|
||||
|
||||
C O N G R A T U L A T I O N S . . .
|
||||
|
||||
YOU HAVE WON--VERY WELL PLAYED.
|
||||
IT LOOKS LIKE I HAVE MET MY MATCH.
|
||||
THANKS FOR PLAYING---I CAN'T WIN ALL THE TIME.
|
||||
|
||||
END
|
||||
}
|
||||
|
||||
sub print_computer_victory {
|
||||
print <<'END';
|
||||
|
||||
NICE TRY, BUT IT LOOKS LIKE I HAVE WON.
|
||||
THANKS FOR PLAYING.
|
||||
|
||||
END
|
||||
}
|
||||
|
||||
sub forfeit { say "\nIT LOOKS LIKE I HAVE WON BY FORFEIT.\n" }
|
||||
|
||||
sub ask_input ($prompt) {
|
||||
print "$prompt? ";
|
||||
defined(my $input = <STDIN>) or __exit();
|
||||
|
||||
# remove spaces from the input (including newlines), they are not used
|
||||
$input =~ s{\s+}{}gmxs;
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
sub ask_yes_no ($prompt) {
|
||||
while ('necessary') {
|
||||
my $input = ask_input($prompt);
|
||||
return 1 if $input =~ m{\A (?: yes | y) \z}imxs;
|
||||
return 0 if $input =~ m{\A (?: no | n) \z}imxs;
|
||||
say q{PLEASE ANSWER 'YES' OR 'NO'.};
|
||||
}
|
||||
}
|
||||
|
||||
sub ask_first_move {
|
||||
while ('necessary') {
|
||||
my $input = ask_input('WHERE WOULD YOU LIKE TO START');
|
||||
if ($input =~ m{\A (?: 0 | [1-9]\d+) \z}mxs) {
|
||||
return 0 unless $input;
|
||||
my $diagonal = int($input / 10);
|
||||
my $row = $input % 10;
|
||||
return $input if $row == 1 || $row == $diagonal;
|
||||
}
|
||||
say <<'END'
|
||||
PLEASE READ THE DIRECTIONS AGAIN.
|
||||
YOU HAVE BEGUN ILLEGALLY.
|
||||
|
||||
END
|
||||
}
|
||||
}
|
||||
|
||||
sub __exit {
|
||||
say "\nOK --- THANKS AGAIN.";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub welcome {
|
||||
print <<'END'
|
||||
QUEEN
|
||||
CREATIVE COMPUTING MORRISTOWN, NEW JERSEY
|
||||
|
||||
|
||||
|
||||
END
|
||||
}
|
||||
|
||||
sub help {
|
||||
print <<'END';
|
||||
WE ARE GOING TO PLAY A GAME BASED ON ONE OF THE CHESS
|
||||
MOVES. OUR QUEEN WILL BE ABLE TO MOVE ONLY TO THE LEFT,
|
||||
DOWN, OR DIAGONALLY DOWN AND TO THE LEFT.
|
||||
|
||||
THE OBJECT OF THE GAME IS TO PLACE THE QUEEN IN THE LOWER
|
||||
LEFT HAND SQUARE BY ALTERNATING MOVES BETWEEN YOU AND THE
|
||||
COMPUTER. THE FIRST ONE TO PLACE THE QUEEN THERE WINS.
|
||||
|
||||
YOU GO FIRST AND PLACE THE QUEEN IN ANY ONE OF THE SQUARES
|
||||
ON THE TOP ROW OR RIGHT HAND COLUMN.
|
||||
THAT WILL BE YOUR FIRST MOVE.
|
||||
WE ALTERNATE MOVES.
|
||||
YOU MAY FORFEIT BY TYPING '0' AS YOUR MOVE.
|
||||
BE SURE TO PRESS THE RETURN KEY AFTER EACH RESPONSE.
|
||||
|
||||
|
||||
END
|
||||
}
|
||||
|
||||
sub print_board {
|
||||
say '';
|
||||
my @ids = board_identifiers();
|
||||
my $row_template = join ' ', ($ENV{ORIGINAL} ? '%d' : '%3d') x 8;
|
||||
for my $A (0 .. 7) {
|
||||
my $start = $A * 8;
|
||||
my @range = $start .. $start + 7;
|
||||
say ' ', sprintf $row_template, @ids[@range];
|
||||
say "\n";
|
||||
}
|
||||
say '';
|
||||
}
|
||||
111
73_Reverse/ruby/reverse.rb
Normal file
111
73_Reverse/ruby/reverse.rb
Normal file
@@ -0,0 +1,111 @@
|
||||
ARRAYSIZE = 9
|
||||
$digitArray = Array.new(ARRAYSIZE)
|
||||
$winningArray = Array.new(ARRAYSIZE)
|
||||
|
||||
# Method to print the rules
|
||||
def displayTheRules
|
||||
puts "This is the game of 'Reverse'. to win, all you have"
|
||||
puts "to do is arrange a list of numbers (1 through " + ARRAYSIZE.to_s + ")"
|
||||
puts "in numerical order from left to right. to move, you"
|
||||
puts "tell me how many numbers (counting from the left) to"
|
||||
puts "reverse. For example, if the current list is:"
|
||||
puts "2 3 4 5 1 6 7 8 9"
|
||||
puts "and you reverse 4, the result will be:"
|
||||
puts "5 4 3 2 1 6 7 8 9"
|
||||
puts "Now if you reverse 5, you win!"
|
||||
puts "1 2 3 4 5 6 7 8 9"
|
||||
puts "No doubt you will like this game, but"
|
||||
puts "if you want to quit, reverse 0 (zero)."
|
||||
end
|
||||
|
||||
# Method to print the list
|
||||
def printList
|
||||
puts "\n" + $digitArray.join(" ") + "\n\n"
|
||||
end
|
||||
|
||||
# Zero-based arrays contain digits 1-9
|
||||
# Make a random array and an ordered winning answer array A[0] to A[N]
|
||||
def makeRandomList
|
||||
for kIndex in 0..ARRAYSIZE-1 do
|
||||
$digitArray[kIndex] = kIndex+1
|
||||
$winningArray[kIndex] = kIndex+1
|
||||
end
|
||||
# now randomize the digit array order
|
||||
$digitArray.shuffle!
|
||||
end
|
||||
|
||||
def checkForWin? (triesSoFar)
|
||||
# Check for a win (all array elements in order)
|
||||
if $digitArray == $winningArray then
|
||||
puts "You won it in " + triesSoFar.to_s + " moves!!!\n\n"
|
||||
puts "try again (yes or no)?"
|
||||
tryAgain = gets.strip.upcase
|
||||
if tryAgain == "YES" then
|
||||
return true
|
||||
end
|
||||
puts "\nO.K. Hope you had fun!!"
|
||||
exit
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def reverseIt (howManyToReverse, triesSoFar)
|
||||
# REVERSE R NUMBERS AND PRINT NEW LIST
|
||||
|
||||
# extract and reverse the first howManyToReverse elements of the array
|
||||
subArray = $digitArray.take(howManyToReverse)
|
||||
subArray.reverse!
|
||||
|
||||
# get the remaining elements of the original array
|
||||
endArray = $digitArray.slice(howManyToReverse, ARRAYSIZE)
|
||||
# append those elements to the reversed elements
|
||||
$digitArray = subArray.concat(endArray)
|
||||
|
||||
# if we got all in order, randomize again
|
||||
isWinner = checkForWin?(triesSoFar)
|
||||
if isWinner == true then
|
||||
makeRandomList
|
||||
end
|
||||
printList # always print the newly ordered list
|
||||
return isWinner
|
||||
end
|
||||
|
||||
def askHowManyToReverse
|
||||
puts "How many shall I reverse?";
|
||||
rNumber = gets.to_i
|
||||
if rNumber > 0 then
|
||||
if rNumber > ARRAYSIZE then
|
||||
puts "Oops! Too many! I can reverse at most " + ARRAYSIZE.to_s
|
||||
end
|
||||
else
|
||||
rNumber = 0 # zero or negative values end the game
|
||||
end
|
||||
return rNumber
|
||||
end
|
||||
|
||||
puts "REVERSE"
|
||||
puts "Creative Computing Morristown, New Jersey\n\n\n"
|
||||
puts "REVERSE -- A game of skill\n\n"
|
||||
|
||||
puts "Do you want the rules?"
|
||||
wantRules = gets.strip.upcase
|
||||
if wantRules == "YES" then
|
||||
displayTheRules
|
||||
end
|
||||
|
||||
makeRandomList
|
||||
howManyTries = 0
|
||||
puts "\nHere we go ... the list is:"
|
||||
printList # display the initial list
|
||||
# start the game loop
|
||||
r = askHowManyToReverse
|
||||
while r != 0 do # zero will end the game
|
||||
if r <= ARRAYSIZE then
|
||||
howManyTries = howManyTries+1
|
||||
if reverseIt(r, howManyTries) then
|
||||
howManyTries = 0
|
||||
end
|
||||
end
|
||||
r = askHowManyToReverse
|
||||
end
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Oracle Java](https://openjdk.java.net/)
|
||||
|
||||
Two versions of Roulette has been contributed. They are indicated within given sub-folders
|
||||
|
||||
- [oop](./oop) - Conversion by Andrew McGuinness (andrew@arobeia.co.uk)
|
||||
- [iterative](./iterative) - Conversion by Thomas Kwashnak ([Github](https://github.com/LittleTealeaf)).
|
||||
- Implements features from JDK 17.
|
||||
- Does make use of some object oriented programming, but acts as a more iterative solution.
|
||||
277
75_Roulette/java/iterative/Roulette.java
Normal file
277
75_Roulette/java/iterative/Roulette.java
Normal file
@@ -0,0 +1,277 @@
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Random;
|
||||
import java.util.Scanner;
|
||||
import java.util.Set;
|
||||
|
||||
public class Roulette {
|
||||
|
||||
private static Set<Integer> RED_NUMBERS;
|
||||
|
||||
static {
|
||||
RED_NUMBERS = Set.of(1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36);
|
||||
}
|
||||
|
||||
private PrintStream out;
|
||||
private Scanner scanner;
|
||||
private int houseBalance, playerBalance;
|
||||
private Random random;
|
||||
|
||||
public Roulette(PrintStream out, InputStream in) {
|
||||
this.out = out;
|
||||
this.scanner = new Scanner(in);
|
||||
houseBalance = 100000;
|
||||
playerBalance = 1000;
|
||||
random = new Random();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new Roulette(System.out, System.in).play();
|
||||
}
|
||||
|
||||
public void play() {
|
||||
out.println(" ROULETTE");
|
||||
out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
|
||||
out.println("WELCOME TO THE ROULETTE TABLE\n");
|
||||
out.print("DO YOU WANT INSTRUCTIONS? ");
|
||||
if (scanner.nextLine().toLowerCase().charAt(0) != 'n') {
|
||||
printInstructions();
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
Bet[] bets = queryBets();
|
||||
|
||||
out.print("SPINNING...\n\n");
|
||||
int result = random.nextInt(1, 39);
|
||||
|
||||
/*
|
||||
Equivalent to following line
|
||||
if(result == 37) {
|
||||
out.println("00");
|
||||
} else if(result == 38) {
|
||||
out.println("0");
|
||||
} else if(RED_NUMBERS.contains(result)) {
|
||||
out.println(result + " RED");
|
||||
} else {
|
||||
out.println(result + " BLACK");
|
||||
}
|
||||
*/
|
||||
out.println(switch (result) {
|
||||
case 37 -> "00";
|
||||
case 38 -> "0";
|
||||
default -> result + (RED_NUMBERS.contains(result) ? " RED" : " BLACK");
|
||||
});
|
||||
|
||||
betResults(bets, result);
|
||||
out.println();
|
||||
|
||||
out.println("TOTALS:\tME\t\tYOU");
|
||||
out.format("\t\t%5d\t%d\n", houseBalance, playerBalance);
|
||||
} while (playAgain());
|
||||
if (playerBalance <= 0) {
|
||||
out.println("THANKS FOR YOUR MONEY\nI'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL");
|
||||
} else {
|
||||
printCheck();
|
||||
}
|
||||
out.println("COME BACK SOON!");
|
||||
}
|
||||
|
||||
public void printInstructions() {
|
||||
out.println();
|
||||
out.println("THIS IS THE BETTING LAYOUT");
|
||||
out.println(" (*=RED)");
|
||||
out.println();
|
||||
out.println(" 1* 2 3*");
|
||||
out.println(" 4 5* 6 ");
|
||||
out.println(" 7* 8 9*");
|
||||
out.println("10 11 12*");
|
||||
out.println("---------------");
|
||||
out.println("13 14* 15 ");
|
||||
out.println("16* 17 18*");
|
||||
out.println("19* 20 21*");
|
||||
out.println("22 23* 24 ");
|
||||
out.println("---------------");
|
||||
out.println("25* 26 27*");
|
||||
out.println("28 29 30*");
|
||||
out.println("31 32* 33 ");
|
||||
out.println("34* 35 36*");
|
||||
out.println("---------------");
|
||||
out.println(" 00 0 ");
|
||||
out.println();
|
||||
out.println("TYPES OF BETS");
|
||||
out.println();
|
||||
out.println("THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET");
|
||||
out.println("ON THAT NUMBER.");
|
||||
out.println("THESE PAY OFF 35:1");
|
||||
out.println();
|
||||
out.println("THE 2:1 BETS ARE:");
|
||||
out.println(" 37) 1-12 40) FIRST COLUMN");
|
||||
out.println(" 38) 13-24 41) SECOND COLUMN");
|
||||
out.println(" 39) 25-36 42) THIRD COLUMN");
|
||||
out.println();
|
||||
out.println("THE EVEN MONEY BETS ARE:");
|
||||
out.println(" 43) 1-18 46) ODD");
|
||||
out.println(" 44) 19-36 47) RED");
|
||||
out.println(" 45) EVEN 48) BLACK");
|
||||
out.println();
|
||||
out.println(" 49)0 AND 50)00 PAY OFF 35:1");
|
||||
out.println(" NOTE: 0 AND 00 DO NOT COUNT UNDER ANY");
|
||||
out.println(" BETS EXCEPT THEIR OWN.");
|
||||
out.println();
|
||||
out.println("WHEN I ASK FOR EACH BET, TYPE THE NUMBER");
|
||||
out.println("AND THE AMOUNT, SEPARATED BY A COMMA.");
|
||||
out.println("FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500");
|
||||
out.println("WHEN I ASK FOR A BET.");
|
||||
out.println();
|
||||
out.println("THE MINIMUM BET IS $5, THE MAXIMUM IS $500.");
|
||||
}
|
||||
|
||||
private Bet[] queryBets() {
|
||||
int numBets = -1;
|
||||
while (numBets < 1) {
|
||||
out.print("HOW MANY BETS? ");
|
||||
try {
|
||||
numBets = Integer.parseInt(scanner.nextLine());
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
Bet[] bets = new Bet[numBets];
|
||||
|
||||
for (int i = 0; i < numBets; i++) {
|
||||
while (bets[i] == null) {
|
||||
try {
|
||||
out.print("NUMBER" + (i + 1) + "? ");
|
||||
String[] values = scanner.nextLine().split(",");
|
||||
int betNumber = Integer.parseInt(values[0]);
|
||||
int betValue = Integer.parseInt(values[1]);
|
||||
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (bets[j].num == betNumber) {
|
||||
out.println("YOU MADE THAT BET ONCE ALREADY,DUM-DUM");
|
||||
betNumber = -1; //Since -1 is out of the range, this will throw it out at the end
|
||||
}
|
||||
}
|
||||
|
||||
if (betNumber > 0 && betNumber <= 50 && betValue >= 5 && betValue <= 500) {
|
||||
bets[i] = new Bet(betNumber,betValue);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return bets;
|
||||
}
|
||||
|
||||
private void betResults(Bet[] bets, int num) {
|
||||
for (int i = 0; i < bets.length; i++) {
|
||||
Bet bet = bets[i];
|
||||
/*
|
||||
Using a switch statement of ternary operators that check if a certain condition is met based on the bet value
|
||||
Returns the coefficient that the bet amount should be multiplied by to get the resulting value
|
||||
*/
|
||||
int coefficient = switch (bet.num) {
|
||||
case 37 -> (num <= 12) ? 2 : -1;
|
||||
case 38 -> (num > 12 && num <= 24) ? 2 : -1;
|
||||
case 39 -> (num > 24 && num < 37) ? 2 : -1;
|
||||
case 40 -> (num < 37 && num % 3 == 1) ? 2 : -1;
|
||||
case 41 -> (num < 37 && num % 3 == 2) ? 2 : -1;
|
||||
case 42 -> (num < 37 && num % 3 == 0) ? 2 : -1;
|
||||
case 43 -> (num <= 18) ? 1 : -1;
|
||||
case 44 -> (num > 18 && num <= 36) ? 1 : -1;
|
||||
case 45 -> (num % 2 == 0) ? 1 : -1;
|
||||
case 46 -> (num % 2 == 1) ? 1 : -1;
|
||||
case 47 -> RED_NUMBERS.contains(num) ? 1 : -1;
|
||||
case 48 -> !RED_NUMBERS.contains(num) ? 1 : -1;
|
||||
case 49 -> (num == 37) ? 35 : -1;
|
||||
case 50 -> (num == 38) ? 35 : -1;
|
||||
default -> (bet.num < 49 && bet.num == num) ? 35 : -1;
|
||||
};
|
||||
|
||||
int betResult = bet.amount * coefficient;
|
||||
|
||||
if (betResult < 0) {
|
||||
out.println("YOU LOSE " + -betResult + " DOLLARS ON BET " + (i + 1));
|
||||
} else {
|
||||
out.println("YOU WIN " + betResult + " DOLLARS ON BET " + (i + 1));
|
||||
}
|
||||
|
||||
playerBalance += betResult;
|
||||
houseBalance -= betResult;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean playAgain() {
|
||||
|
||||
if (playerBalance <= 0) {
|
||||
out.println("OOPS! YOU JUST SPENT YOUR LAST DOLLAR!");
|
||||
return false;
|
||||
} else if (houseBalance <= 0) {
|
||||
out.println("YOU BROKE THE HOUSE!");
|
||||
playerBalance = 101000;
|
||||
houseBalance = 0;
|
||||
return false;
|
||||
} else {
|
||||
out.println("PLAY AGAIN?");
|
||||
return scanner.nextLine().toLowerCase().charAt(0) == 'y';
|
||||
}
|
||||
}
|
||||
|
||||
private void printCheck() {
|
||||
out.print("TO WHOM SHALL I MAKE THE CHECK? ");
|
||||
String name = scanner.nextLine();
|
||||
|
||||
out.println();
|
||||
for (int i = 0; i < 72; i++) {
|
||||
out.print("-");
|
||||
}
|
||||
out.println();
|
||||
|
||||
for (int i = 0; i < 50; i++) {
|
||||
out.print(" ");
|
||||
}
|
||||
out.println("CHECK NO. " + random.nextInt(0, 100));
|
||||
|
||||
for (int i = 0; i < 40; i++) {
|
||||
out.print(" ");
|
||||
}
|
||||
out.println(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE));
|
||||
out.println();
|
||||
|
||||
out.println("PAY TO THE ORDER OF -----" + name + "----- $" + (playerBalance));
|
||||
out.println();
|
||||
|
||||
for (int i = 0; i < 40; i++) {
|
||||
out.print(" ");
|
||||
}
|
||||
out.println("THE MEMORY BANK OF NEW YORK");
|
||||
|
||||
for (int i = 0; i < 40; i++) {
|
||||
out.print(" ");
|
||||
}
|
||||
out.println("THE COMPUTER");
|
||||
|
||||
for (int i = 0; i < 40; i++) {
|
||||
out.print(" ");
|
||||
}
|
||||
out.println("----------X-----");
|
||||
|
||||
for (int i = 0; i < 72; i++) {
|
||||
out.print("-");
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
|
||||
public class Bet {
|
||||
|
||||
final int num, amount;
|
||||
|
||||
public Bet(int num, int amount) {
|
||||
this.num = num;
|
||||
this.amount = amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
65
75_Roulette/java/oop/Bet.java
Normal file
65
75_Roulette/java/oop/Bet.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/* A bet has a target (the code entered, which is 1-36, or special values for
|
||||
* the various groups, zero and double-zero), and an amount in dollars
|
||||
*/
|
||||
|
||||
public class Bet {
|
||||
public int target;
|
||||
public int amount;
|
||||
|
||||
/* bet on a target, of an amount */
|
||||
public Bet(int on, int of) {
|
||||
target = on; amount = of;
|
||||
}
|
||||
|
||||
/* check if this is a valid bet - on a real target and of a valid amount */
|
||||
public boolean isValid() {
|
||||
return ((target > 0) && (target <= 50) &&
|
||||
(amount >= 5) && (amount <= 500));
|
||||
}
|
||||
|
||||
/* utility to return either the odds amount in the case of a win, or zero for a loss */
|
||||
private int m(boolean isWon, int odds) {
|
||||
return isWon? odds: 0;
|
||||
}
|
||||
|
||||
/* look at the wheel to see if this bet won.
|
||||
* returns 0 if it didn't, or the odds if it did
|
||||
*/
|
||||
public int winsOn(Wheel w) {
|
||||
if (target < 37) {
|
||||
// A number bet 1-36 wins at odds of 35 if it is the exact number
|
||||
return m(w.isNumber() && (w.number() == target), 35);
|
||||
} else
|
||||
switch (target) {
|
||||
case 37: // 1-12, odds of 2
|
||||
return m(w.isNumber() && (w.number() <= 12), 2);
|
||||
case 38: // 13-24, odds of 2
|
||||
return m(w.isNumber() && (w.number() > 12) && (w.number() <= 24), 2);
|
||||
case 39: // 25-36, odds of 2
|
||||
return m(w.isNumber() && (w.number() > 24), 2);
|
||||
case 40: // Column 1, odds of 2
|
||||
return m(w.isNumber() && ((w.number() % 3) == 1), 2);
|
||||
case 41: // Column 2, odds of 2
|
||||
return m(w.isNumber() && ((w.number() % 3) == 2), 2);
|
||||
case 42: // Column 3, odds of 2
|
||||
return m(w.isNumber() && ((w.number() % 3) == 0), 2);
|
||||
case 43: // 1-18, odds of 1
|
||||
return m(w.isNumber() && (w.number() <= 18), 1);
|
||||
case 44: // 19-36, odds of 1
|
||||
return m(w.isNumber() && (w.number() > 18), 1);
|
||||
case 45: // even, odds of 1
|
||||
return m(w.isNumber() && ((w.number() %2) == 0), 1);
|
||||
case 46: // odd, odds of 1
|
||||
return m(w.isNumber() && ((w.number() %2) == 1), 1);
|
||||
case 47: // red, odds of 1
|
||||
return m(w.isNumber() && (w.color() == Wheel.BLACK), 1);
|
||||
case 48: // black, odds of 1
|
||||
return m(w.isNumber() && (w.color() == Wheel.RED), 1);
|
||||
case 49: // single zero, odds of 35
|
||||
return m(w.value().equals("0"), 35);
|
||||
case 50: // double zero, odds of 35
|
||||
return m(w.value().equals("00"), 35);
|
||||
}
|
||||
throw new RuntimeException("Program Error - invalid bet");
|
||||
}
|
||||
}
|
||||
234
75_Roulette/java/oop/Roulette.java
Normal file
234
75_Roulette/java/oop/Roulette.java
Normal file
@@ -0,0 +1,234 @@
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
|
||||
public class Roulette {
|
||||
public static void main(String args[]) throws Exception {
|
||||
Roulette r = new Roulette();
|
||||
r.play();
|
||||
}
|
||||
|
||||
private BufferedReader reader;
|
||||
private PrintStream writer;
|
||||
|
||||
private int house; // how much money does the house have
|
||||
private int player; // how much money does the player have
|
||||
private Wheel wheel = new Wheel();
|
||||
|
||||
public Roulette() {
|
||||
reader = new BufferedReader(new InputStreamReader(System.in));
|
||||
writer = System.out;
|
||||
house = 100000;
|
||||
player = 1000;
|
||||
}
|
||||
|
||||
// for a test / cheat mode -- set the random number generator to a known value
|
||||
private void setSeed(long l) {
|
||||
wheel.setSeed(l);
|
||||
}
|
||||
|
||||
public void play() {
|
||||
try {
|
||||
intro();
|
||||
writer.println("WELCOME TO THE ROULETTE TABLE\n" +
|
||||
"DO YOU WANT INSTRUCTIONS");
|
||||
String instr = reader.readLine();
|
||||
if (!instr.toUpperCase().startsWith("N"))
|
||||
instructions();
|
||||
|
||||
while (betAndSpin()) { // returns true if the game is to continue
|
||||
}
|
||||
|
||||
if (player <= 0) {
|
||||
// player ran out of money
|
||||
writer.println("THANKS FOR YOUR MONEY.\nI'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL");
|
||||
} else {
|
||||
// player has money -- print them a check
|
||||
writer.println("TO WHOM SHALL I MAKE THE CHECK");
|
||||
|
||||
String payee = reader.readLine();
|
||||
|
||||
writer.println("-".repeat(72));
|
||||
tab(50); writer.println("CHECK NO. " + (new Random().nextInt(100) + 1));
|
||||
writer.println();
|
||||
tab(40); writer.println(LocalDate.now().format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG)));
|
||||
writer.println("\n\nPAY TO THE ORDER OF-----" + payee + "-----$ " + player);
|
||||
writer.print("\n\n");
|
||||
tab(10); writer.println("THE MEMORY BANK OF NEW YORK\n");
|
||||
tab(40); writer.println("THE COMPUTER");
|
||||
tab(40); writer.println("----------X-----\n");
|
||||
writer.println("-".repeat(72));
|
||||
writer.println("COME BACK SOON!\n");
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
// this should not happen
|
||||
System.err.println("System error:\n" + e);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the starting introduction */
|
||||
private void intro() throws IOException {
|
||||
tab(32); writer.println("ROULETTE");
|
||||
tab(15); writer.println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n");
|
||||
}
|
||||
|
||||
/* Display the game instructions */
|
||||
private void instructions() {
|
||||
String[] instLines = new String[] {
|
||||
"THIS IS THE BETTING LAYOUT",
|
||||
" (*=RED)",
|
||||
"" ,
|
||||
" 1* 2 3*",
|
||||
" 4 5* 6 ",
|
||||
" 7* 8 9*",
|
||||
"10 11 12*",
|
||||
"---------------",
|
||||
"13 14* 15 ",
|
||||
"16* 17 18*",
|
||||
"19* 20 21*",
|
||||
"22 23* 24 ",
|
||||
"---------------",
|
||||
"25* 26 27*",
|
||||
"28 29 30*",
|
||||
"31 32* 33 ",
|
||||
"34* 35 36*",
|
||||
"---------------",
|
||||
" 00 0 ",
|
||||
"" ,
|
||||
"TYPES OF BETS",
|
||||
"" ,
|
||||
"THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET",
|
||||
"ON THAT NUMBER.",
|
||||
"THESE PAY OFF 35:1",
|
||||
"" ,
|
||||
"THE 2:1 BETS ARE:",
|
||||
" 37) 1-12 40) FIRST COLUMN",
|
||||
" 38) 13-24 41) SECOND COLUMN",
|
||||
" 39) 25-36 42) THIRD COLUMN",
|
||||
"" ,
|
||||
"THE EVEN MONEY BETS ARE:",
|
||||
" 43) 1-18 46) ODD",
|
||||
" 44) 19-36 47) RED",
|
||||
" 45) EVEN 48) BLACK",
|
||||
"",
|
||||
" 49)0 AND 50)00 PAY OFF 35:1",
|
||||
" NOTE: 0 AND 00 DO NOT COUNT UNDER ANY",
|
||||
" BETS EXCEPT THEIR OWN.",
|
||||
"",
|
||||
"WHEN I ASK FOR EACH BET, TYPE THE NUMBER",
|
||||
"AND THE AMOUNT, SEPARATED BY A COMMA.",
|
||||
"FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500",
|
||||
"WHEN I ASK FOR A BET.",
|
||||
"",
|
||||
"THE MINIMUM BET IS $5, THE MAXIMUM IS $500.",
|
||||
"" };
|
||||
writer.println(String.join("\n", instLines));
|
||||
}
|
||||
|
||||
/* Take a set of bets from the player, then spin the wheel and work out the winnings *
|
||||
* This returns true if the game is to continue afterwards
|
||||
*/
|
||||
private boolean betAndSpin() throws IOException {
|
||||
int betCount = 0;
|
||||
|
||||
while (betCount == 0) { // keep asking how many bets until we get a good answer
|
||||
try {
|
||||
writer.println("HOW MANY BETS");
|
||||
String howMany = reader.readLine();
|
||||
betCount = Integer.parseInt(howMany.strip());
|
||||
|
||||
if ((betCount < 1) || (betCount > 100)) betCount = 0; // bad -- set zero and ask again
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
// this happens if the input is not a number
|
||||
writer.println("INPUT ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
HashSet<Integer> betsMade = new HashSet<>(); // Bet targets already made, so we can spot repeats
|
||||
ArrayList<Bet> bets = new ArrayList<>(); // All the bets for this round
|
||||
|
||||
while (bets.size() < betCount) {
|
||||
Bet bet = new Bet(0, 0); // an invalid bet to hold the place
|
||||
while (!bet.isValid()) { // keep asking until it is valid
|
||||
try {
|
||||
writer.println("NUMBER " + (bets.size() + 1));
|
||||
String fields[] = reader.readLine().split(",");
|
||||
if (fields.length == 2) {
|
||||
bet = new Bet(Integer.parseInt(fields[0].strip()),
|
||||
Integer.parseInt(fields[1].strip()));
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
writer.println("INPUT ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there is already a bet on the same target
|
||||
if (betsMade.contains(bet.target)) {
|
||||
writer.println("YOU MADE THAT BET ONCE ALREADY,DUM-DUM");
|
||||
} else {
|
||||
betsMade.add(bet.target); // note this target has now been bet on
|
||||
bets.add(bet);
|
||||
}
|
||||
}
|
||||
|
||||
writer.println("SPINNING\n\n");
|
||||
|
||||
wheel.spin(); // this deliberately takes some random amount of time
|
||||
|
||||
writer.println(wheel.value());
|
||||
|
||||
// go through the bets, and evaluate each one
|
||||
int betNumber = 1;
|
||||
for (Bet b : bets) {
|
||||
int multiplier = b.winsOn(wheel);
|
||||
if (multiplier == 0) {
|
||||
// lost the amount of the bet
|
||||
writer.println("YOU LOSE " + b.amount + " DOLLARS ON BET " + betNumber);
|
||||
house += b.amount;
|
||||
player -= b.amount;
|
||||
} else {
|
||||
// won the amount of the bet, multiplied by the odds
|
||||
int winnings = b.amount * multiplier;
|
||||
writer.println("YOU WIN " + winnings + " DOLLARS ON BET " + betNumber);
|
||||
house -= winnings;
|
||||
player += winnings;
|
||||
}
|
||||
++betNumber;
|
||||
}
|
||||
|
||||
writer.println("\nTOTALS:\tME\tYOU\n\t" + house + "\t" + player);
|
||||
|
||||
if (player <= 0) {
|
||||
writer.println("OOPS! YOU JUST SPENT YOUR LAST DOLLAR");
|
||||
return false; // do not repeat since the player has no more money
|
||||
}
|
||||
if (house <= 0) {
|
||||
writer.println("YOU BROKE THE HOUSE!");
|
||||
player = 101000; // can't win more than the house started with
|
||||
return false; // do not repeat since the house has no more money
|
||||
}
|
||||
|
||||
// player still has money, and the house still has money, so ask the player
|
||||
// if they want to continue
|
||||
writer.println("AGAIN");
|
||||
String doContinue = reader.readLine();
|
||||
|
||||
// repeat if the answer was not "n" or "no"
|
||||
return (!doContinue.toUpperCase().startsWith("N"));
|
||||
}
|
||||
|
||||
// utility to print n spaces for formatting
|
||||
private void tab(int n) {
|
||||
writer.print(" ".repeat(n));
|
||||
}
|
||||
}
|
||||
69
75_Roulette/java/oop/Wheel.java
Normal file
69
75_Roulette/java/oop/Wheel.java
Normal file
@@ -0,0 +1,69 @@
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
|
||||
// The roulette wheel
|
||||
public class Wheel {
|
||||
// List the numbers which are black
|
||||
private HashSet<Integer> black = new HashSet<>(Arrays.asList(new Integer[] { 1,3,5,7,9,12,14,16,18,19,21,23,25,27,30,32,34,36 }));
|
||||
|
||||
private Random random = new Random();
|
||||
private int pocket = 38;
|
||||
|
||||
public static final int ZERO=0;
|
||||
public static final int BLACK=1;
|
||||
public static final int RED=2;
|
||||
|
||||
// Set up a wheel. You call "spin", and then can check the result.
|
||||
public Wheel() {
|
||||
}
|
||||
|
||||
// Cheat / test mode
|
||||
void setSeed(long l) {
|
||||
random.setSeed(l);
|
||||
}
|
||||
|
||||
// Spin the wheel onto a new random value.
|
||||
public void spin() {
|
||||
// keep spinning for a while
|
||||
do {
|
||||
try {
|
||||
// 1 second delay. Where it stops, nobody knows
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
catch (InterruptedException e) {}
|
||||
|
||||
pocket = random.nextInt(38) + 1;
|
||||
} while (random.nextInt(4) > 0); // keep spinning until it stops
|
||||
}
|
||||
|
||||
// The string representation of the number; 1-36, 0, or 00
|
||||
public String value() {
|
||||
if (pocket == 37) return "0";
|
||||
else if (pocket == 38) return "00";
|
||||
else return String.valueOf(pocket);
|
||||
}
|
||||
|
||||
// True if either 0 or 00 is hit
|
||||
public boolean zero() {
|
||||
return (pocket > 36);
|
||||
}
|
||||
|
||||
// True if anything other than 0 or 00 is hit
|
||||
public boolean isNumber() {
|
||||
return (pocket < 37);
|
||||
}
|
||||
|
||||
// The number rolled
|
||||
public int number() {
|
||||
if (zero()) return 0;
|
||||
else return pocket;
|
||||
}
|
||||
|
||||
// Either ZERO, BLACK, or RED
|
||||
public int color() {
|
||||
if (zero()) return ZERO;
|
||||
else if (black.contains(pocket)) return BLACK;
|
||||
else return RED;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,15 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Perl](https://www.perl.org/)
|
||||
|
||||
This conversion consists of three files in `75_Roulette/perl/`:
|
||||
|
||||
- `roulette.pl` is the port of the BASIC to Perl;
|
||||
- `roulette-test.t` is a Perl test for correctness of display and payout;
|
||||
- `make-roulette-test.pl` generates roulette-test.t from roulette.bas.
|
||||
|
||||
The ported version of the game numbers the slots from 0 rather than 1, and uses a dispatch table to figure out the payout.
|
||||
|
||||
The Perl test loads `roulette.pl` and verifies the Perl slot display and payout logic against the BASIC for all combinations of slots and bets. If any tests fail that fact will be noted at the end of the output.
|
||||
|
||||
The test code is generated by reading the BASIC, retaining only the slot display and payout logic (based on line numbers), and wrapping this in code that generates all combinations of bet and spin result. The result is run, and the result is captured and parsed to produce `roulette-test.t`. `make-roulette-test.pl` has some command-line options that may be of interest. `--help` will display the documentation.
|
||||
|
||||
263
75_Roulette/perl/make-roulette-test.pl
Executable file
263
75_Roulette/perl/make-roulette-test.pl
Executable file
@@ -0,0 +1,263 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use 5.014; # For s///r
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Temp;
|
||||
use Getopt::Long 2.33 qw{ :config auto_version };
|
||||
use IPC::Cmd qw{ can_run }; # Core as of Perl 5.9.5.
|
||||
use Pod::Usage;
|
||||
|
||||
our $VERSION = '0.000_01';
|
||||
|
||||
my %opt = (
|
||||
program => find_basic(),
|
||||
output => make_default_output(),
|
||||
);
|
||||
|
||||
GetOptions( \%opt,
|
||||
qw{ output=s program=s },
|
||||
help => sub { pod2usage( { -verbose => 2 } ) },
|
||||
) or pod2usage( { -verbose => 0 } );
|
||||
|
||||
die "No default BASIC found; you must specify --program\n"
|
||||
unless defined $opt{program};
|
||||
|
||||
my $game_dir = ( File::Spec->splitdir( $0 ) )[0];
|
||||
my $basic_file = File::Spec->catfile( $game_dir, 'roulette.bas' );
|
||||
open my $basic_handle, '<', $basic_file
|
||||
or die "Unable to open $basic_file: $!\n";
|
||||
|
||||
my $munged = File::Temp->new();
|
||||
|
||||
print { $munged } <<'EOD';
|
||||
1000 Y=50
|
||||
1010 DIM B(100),C(100),T(100)
|
||||
1090 FOR S=1 TO 38
|
||||
1095 PRINT "SPIN ";S
|
||||
1100 FOR C=1 TO Y
|
||||
1110 B(C)=1
|
||||
1120 T(C)=C
|
||||
1130 NEXT C
|
||||
EOD
|
||||
|
||||
transcribe( $basic_file, $basic_handle, $munged, 1860, 2810 );
|
||||
transcribe( $basic_file, $basic_handle, $munged, 2950 );
|
||||
|
||||
say { $munged } '4000 NEXT S';
|
||||
|
||||
$munged->flush();
|
||||
|
||||
if ( $opt{output} ne '-' ) {
|
||||
my $dir = ( File::Spec->splitpath( $0 ) )[1];
|
||||
my $fn = File::Spec->rel2abs( $opt{output}, $dir );
|
||||
$fn = File::Spec->abs2rel( $fn );
|
||||
open my $fh, '>', $fn
|
||||
or die "Unable to open $fn: $!\n";
|
||||
warn "Writing $fn\n";
|
||||
select $fh;
|
||||
}
|
||||
|
||||
print <<'EOD';
|
||||
package main;
|
||||
|
||||
use 5.010;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Spec;
|
||||
use Test::More 0.88; # Because of done_testing();
|
||||
|
||||
EOD
|
||||
|
||||
print <<"EOD";
|
||||
# NOTE: This file is generated by $0.
|
||||
# Any edits made to it will be lost the next time it is regenerated.
|
||||
# Caveat coder.
|
||||
|
||||
EOD
|
||||
|
||||
print <<'EOD';
|
||||
my $dir = ( File::Spec->splitpath( $0 ) )[1];
|
||||
my $script = File::Spec->catfile( $dir, 'roulette.pl' );
|
||||
{
|
||||
# Modern Perls do not have . in @INC, but we need it there to load a
|
||||
# relative path.
|
||||
local @INC = ( File::Spec->curdir(), @INC );
|
||||
require $script; # Load game as module
|
||||
}
|
||||
|
||||
EOD
|
||||
|
||||
my $spin;
|
||||
my $name;
|
||||
foreach ( `$opt{program} @{[ $munged->filename() ]}` ) {
|
||||
s/\N{U+1D}/ /smxg; # Artifact of the BASIC I'm using.
|
||||
s/ \s+ \z //smx;
|
||||
s/ \A \s+ //smx;
|
||||
if ( $_ eq '' ) {
|
||||
# Ignore empty lines.
|
||||
} elsif ( m/ \A SPIN \s* ( [0-9]+ ) /smx ) {
|
||||
$spin = $1 - 1; # BASIC is 1-based, but Perl is 0-based
|
||||
} elsif ( m/ \A YOU \s+ WIN \s* ( [0-9]+ ) \s*
|
||||
DOLLARS \s+ ON \s+ BET \s* ( [0-9]+ ) /smx ) {
|
||||
say "is payout( $spin, $2 ), $1, 'Spin $spin ($name), bet $2 pays $1';";
|
||||
} elsif ( m/ \A YOU \s+ LOSE \s* ( [0-9]+ ) \s*
|
||||
DOLLARS \s+ ON \s+ BET \s* ( [0-9]+ ) /smx ) {
|
||||
say "is payout( $spin, $2 ), -$1, 'Spin $spin ($name), bet $2 pays -$1';";
|
||||
} elsif ( m/ \A \s* ( [0-9]+ ) (?: \s* ( [[:alpha:]]+ ) )? \z /smx ) {
|
||||
$name = $2 ? sprintf( '%d %s', $1, ucfirst lc $2 ) : $1;
|
||||
say "is format_spin( $spin ), '$name', 'Spin $spin is $name';";
|
||||
} else {
|
||||
die "Unexpected input $_";
|
||||
}
|
||||
}
|
||||
|
||||
print <<'EOD';
|
||||
|
||||
done_testing;
|
||||
|
||||
1;
|
||||
|
||||
# ex: set textwidth=72 :
|
||||
EOD
|
||||
|
||||
sub find_basic {
|
||||
# yabasic seems not to work
|
||||
foreach my $prog ( qw{ basic cbmbasic } ) {
|
||||
return $prog if can_run( $prog )
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub make_default_output {
|
||||
( my $rslt = $0 ) =~ s/ [.] pl \z /.t/smx;
|
||||
$rslt =~ s/ .* \b make- //smx;
|
||||
return $rslt;
|
||||
}
|
||||
|
||||
sub transcribe {
|
||||
my ( $in_file, $in_handle, $out_handle, $first_line, $last_line ) = @_;
|
||||
$last_line //= $first_line;
|
||||
|
||||
while ( <$in_handle> ) {
|
||||
m/ \A \s* ( [0-9]+ )+ \s /smx
|
||||
or next;
|
||||
$1 < $first_line
|
||||
and next;
|
||||
say { $out_handle } sprintf '%04d REM BEGIN VERBATIM FROM %s',
|
||||
$first_line - 10, $in_file;
|
||||
print { $out_handle } $_;
|
||||
last;
|
||||
}
|
||||
while ( <$in_handle> ) {
|
||||
m/ \A \s* ( [0-9]+ )+ \s /smx
|
||||
and $1 > $last_line
|
||||
and last;
|
||||
print { $out_handle } $_;
|
||||
}
|
||||
say { $out_handle } sprintf '%04d REM END VERBATIM FROM %s',
|
||||
$last_line + 10, $in_file;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 TITLE
|
||||
|
||||
make-roulette-test.pl - Generate the tests for 75_Roulette/perl/roulette.pl
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
perl 75_Roulette/perl/make-roulette-test.pl
|
||||
perl 75_Roulette/perl/make-roulette-test.pl --program mybasic
|
||||
perl 75_Roulette/perl/make-roulette-test.pl --help
|
||||
perl 75_Roulette/perl/make-roulette-test.pl --version
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
<<< replace boiler plate >>>
|
||||
|
||||
=head2 --help
|
||||
|
||||
This option displays the documentation for this script. The script then
|
||||
exits.
|
||||
|
||||
=head2 --output
|
||||
|
||||
--output fubar.t
|
||||
|
||||
This option specifies the output file. This needs to be in the same
|
||||
directory as F<roulette.pl>, and defaults to that directory. A single
|
||||
dash (C<'-'>) is special-cased to send the output to standard out.
|
||||
|
||||
The default is C<--output=test-roulette.t>.
|
||||
|
||||
=head2 --program
|
||||
|
||||
--program my_basic
|
||||
|
||||
This option specifies the name of your BASIC interpreter. This must be
|
||||
the name of an executable file in your PATH (aliases do not work).
|
||||
|
||||
The default is the first-found in the list C<qw{ basic cbmbasic }>.
|
||||
|
||||
=head2 --version
|
||||
|
||||
This option displays the version of this script. The script then exits.
|
||||
|
||||
=head1 DETAILS
|
||||
|
||||
This Perl script generates F<roulette-test.t>, which tests
|
||||
F<roulette.pl>. The latter is expected to be written as a modulino.
|
||||
|
||||
This script assumes that:
|
||||
|
||||
=over
|
||||
|
||||
=item * it is in the same directory as F<roulette.pl>;
|
||||
|
||||
=item * F<roulette.bas> is in the first-level subdirectory under the current directory;
|
||||
|
||||
=back
|
||||
|
||||
The generated test assumes that it is in the same directory as
|
||||
F<roulette.pl>.
|
||||
|
||||
This script works by abstracting the internals of F<roulette.bas> and
|
||||
wrapping them in a loop that generates all possible spins, and places
|
||||
all possible bets on each spin. The generated BASIC is written to a
|
||||
temporary file, and executed by a BASIC interpreter. The output is
|
||||
parsed and used to generate the output.
|
||||
|
||||
Obviously there is some ad-hocery going on, and this script has only
|
||||
been tested under C<cbmbasic>, which was what I had on hand.
|
||||
|
||||
B<Caveat:> the abstraction process is driven by BASIC line numbers. Any
|
||||
change of these puts the ad-hocery at risk.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
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 textwidth=72 :
|
||||
1967
75_Roulette/perl/roulette-test.t
Normal file
1967
75_Roulette/perl/roulette-test.t
Normal file
File diff suppressed because it is too large
Load Diff
319
75_Roulette/perl/roulette.pl
Executable file
319
75_Roulette/perl/roulette.pl
Executable file
@@ -0,0 +1,319 @@
|
||||
#!/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 POSIX qw{ strftime }; # Time formatting
|
||||
use Term::ReadLine; # Prompt and return user input
|
||||
|
||||
our $VERSION = '0.000_01';
|
||||
|
||||
# A main() function is not usual in Perl scripts. I have installed one
|
||||
# here to make the script into a "modulino." The next line executes
|
||||
# main() if and only if caller() returns false. It will do this if we
|
||||
# were loaded by another Perl script but not otherwise. This was done so
|
||||
# I could test the payout and spin formatting logic.
|
||||
main() unless caller;
|
||||
|
||||
sub main {
|
||||
|
||||
print <<'EOD';
|
||||
ROULETTE
|
||||
Creative Computing Morristown, New Jersey
|
||||
|
||||
|
||||
|
||||
|
||||
Welcome to the roulette table.
|
||||
|
||||
EOD
|
||||
|
||||
if ( get_yes_no( 'Do you want instructions' ) ) {
|
||||
print <<'EOD';
|
||||
|
||||
This is the betting layout
|
||||
(*=red)
|
||||
|
||||
1* 2 3*
|
||||
4 5* 6
|
||||
7* 8 9*
|
||||
10 11 12*
|
||||
---------------
|
||||
13 14* 15
|
||||
16* 17 18*
|
||||
19* 20 21*
|
||||
22 23* 24
|
||||
---------------
|
||||
25* 26 27*
|
||||
28 29 30*
|
||||
31 32* 33
|
||||
34* 35 36*
|
||||
---------------
|
||||
00 0
|
||||
|
||||
Types of bets:
|
||||
|
||||
The numbers 1 to 36 signify a straight bet
|
||||
on that number.
|
||||
These pay off 35:1
|
||||
|
||||
The 2:1 bets are:
|
||||
37) 1-12 40) first column
|
||||
38) 13-24 41) second column
|
||||
39) 25-36 42) third column
|
||||
|
||||
The even money bets are:
|
||||
43) 1-18 46) odd
|
||||
44) 19-36 47) red
|
||||
45) even 48) black
|
||||
|
||||
49) 0 and 50) 00 pay off 35:1
|
||||
Note: 0 and 00 do not count under any
|
||||
bets except their own.
|
||||
|
||||
When I ask for each bet, type the number
|
||||
and the amount, separated by a comma.
|
||||
For example: to bet $500 on black, type 48,500
|
||||
when I ask for a bet.
|
||||
|
||||
The minimum bet is $5, the maximum is $500.
|
||||
|
||||
EOD
|
||||
}
|
||||
|
||||
my $P = 1000;
|
||||
my $D = 100000.;
|
||||
|
||||
while ( 1 ) { # Iterate indefinitely
|
||||
|
||||
my $Y = get_input( 'How many bets? ',
|
||||
sub { m/ \A [0-9]+ \z /smx && $ARG > 0 && $ARG <= 50 },
|
||||
"Please enter a positive integer no greater than 50\n",
|
||||
);
|
||||
my @B;
|
||||
my @T;
|
||||
foreach my $C ( 1 .. $Y ) {
|
||||
my ( $X, $Z ) = split qr< , >smx, get_input(
|
||||
"Number $C: ",
|
||||
sub { m/ \A ( [0-9]+ ) , ( [0-9]+ ) \z /smx
|
||||
&& $1 > 0 && $1 <= 50 && $2 >= 5 && $2 <= 500 },
|
||||
"Please enter two comma-separated positive numbers\n",
|
||||
);
|
||||
if ( $B[$X] ) {
|
||||
say 'You made that bet once already, dum-dum.';
|
||||
redo;
|
||||
}
|
||||
$B[$X] = $Z; # BASIC does $B[$C] = $Z
|
||||
$T[$C] = $X;
|
||||
}
|
||||
|
||||
print <<'EOD';
|
||||
|
||||
Spinning ...
|
||||
|
||||
EOD
|
||||
my $S = int rand 38; # Zero-based, versus 1-based in BASIC
|
||||
|
||||
say format_spin( $S );
|
||||
|
||||
say '';
|
||||
|
||||
foreach my $C ( 1 .. $Y ) {
|
||||
my $X = $T[$C];
|
||||
my $payout = payout( $S, $X ) * $B[$X];
|
||||
$D -= $payout;
|
||||
$P += $payout;
|
||||
if ( $payout > 0 ) {
|
||||
say "You win $payout dollars on bet $C";
|
||||
} else {
|
||||
$payout = -$payout;
|
||||
say "You lose $payout dollars on bet $C";
|
||||
}
|
||||
}
|
||||
say "Totals\tMe\tYou";
|
||||
say "\t$D\t$P";
|
||||
say '';
|
||||
|
||||
|
||||
last unless get_yes_no( 'Again' );
|
||||
}
|
||||
|
||||
say '';
|
||||
|
||||
if ( $P > 0 ) {
|
||||
my $B = get_input(
|
||||
'To whom shall I make out the check? ',
|
||||
);
|
||||
my $check_number = 1000 + int rand 9000;
|
||||
my $todays_date = strftime( '%B %d, %Y', localtime );
|
||||
print <<"EOD";
|
||||
|
||||
------------------------------------------------------------ Check number $check_number
|
||||
|
||||
$todays_date
|
||||
|
||||
Pay to the order of ------ $B ----- \$$P
|
||||
|
||||
The Memory Bank of New York
|
||||
|
||||
The Computer
|
||||
---------X-----
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Come back soon!
|
||||
EOD
|
||||
} else {
|
||||
print <<'EOD';
|
||||
Thanks for your money.
|
||||
I'll use it to buy a solid gold roulette wheel
|
||||
EOD
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
# Define the kind of each possible spin. 0 is '0' or '00', 1 is
|
||||
# black, and 2 is red. We assign the values in a BEGIN block because
|
||||
# execution never actually reaches this point in the script.
|
||||
my @kind;
|
||||
BEGIN {
|
||||
@kind = ( 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1,
|
||||
2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 0,
|
||||
0 );
|
||||
}
|
||||
|
||||
# Convert the spin (0-37) to its name on the wheel.
|
||||
sub format_spin {
|
||||
my ( $number ) = @_;
|
||||
state $format = [
|
||||
sub { '0' x ( $_[0] - 35 ) },
|
||||
sub { sprintf '%s Black', $_[0] + 1 },
|
||||
sub { sprintf '%s Red', $_[0] + 1 },
|
||||
];
|
||||
return $format->[$kind[$number]]( $number );
|
||||
}
|
||||
|
||||
# Compute the payout given the spin (0-37) and the bet (1-50).
|
||||
sub payout {
|
||||
my ( $number, $bet ) = @_;
|
||||
# We compute the payout on '0' and '00' directly, since under
|
||||
# our rules they are only eligible for the 35-to-1 bet.
|
||||
$kind[$number]
|
||||
or return $number == $bet - 49 + 36 ? 35 : -1;
|
||||
--$bet; # #bet is 1-based coming in
|
||||
# Dispatch table for computing the payout for spins 0-36.
|
||||
state $payout = [
|
||||
( sub { $_[0] == $_[1] ? 35 : -1 } ) x 36,
|
||||
( sub { int( $_[0] / 12 ) == $_[1] - 36 ? 2 : -1 } ) x 3,
|
||||
( sub { $_[0] % 3 == $_[1] - 39 ? 2 : -1 } ) x 3,
|
||||
( sub { int( $_[0] / 18 ) == $_[1] - 42 ? 1 : -1 } ) x 2,
|
||||
( sub { $_[0] % 2 == 45 - $_[1] ? 1 : -1 } ) x 2,
|
||||
( sub { $kind[$_[0]] == 48 - $_[1] ? 1 : -1 } ) x 2,
|
||||
( sub { -1 } ) x 2, # Bet on '0' or '00' loses
|
||||
];
|
||||
return $payout->[$bet]->( $number, $bet );
|
||||
}
|
||||
}
|
||||
|
||||
# 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( 'reverse' );
|
||||
$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 };
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 TITLE
|
||||
|
||||
roulette - Play the game 'Roulette' from Basic Computer Games
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
roulette.pl
|
||||
|
||||
=head1 DETAILS
|
||||
|
||||
This Perl script is a port of roulette, which is the 75th
|
||||
entry in Basic Computer Games.
|
||||
|
||||
The main internal changes are converting the roulette slot numbering to
|
||||
0-based and replacing most of the payout logic with a dispatch table.
|
||||
These changes were tested for correctness against the original BASIC.
|
||||
|
||||
=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 :
|
||||
213
75_Roulette/python/roulette.py
Normal file
213
75_Roulette/python/roulette.py
Normal file
@@ -0,0 +1,213 @@
|
||||
from datetime import date
|
||||
import random
|
||||
|
||||
global RED_NUMBERS
|
||||
RED_NUMBERS = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36]
|
||||
|
||||
def print_instructions():
|
||||
print("""
|
||||
THIS IS THE BETTING LAYOUT
|
||||
(*=RED)
|
||||
|
||||
1* 2 3*
|
||||
4 5* 6
|
||||
7* 8 9*
|
||||
10 11 12*
|
||||
---------------
|
||||
13 14* 15
|
||||
16* 17 18*
|
||||
19* 20 21*
|
||||
22 23* 24
|
||||
---------------
|
||||
25* 26 27*
|
||||
28 29 30*
|
||||
31 32* 33
|
||||
34* 35 36*
|
||||
---------------
|
||||
00 0
|
||||
|
||||
TYPES OF BETS
|
||||
|
||||
THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET
|
||||
ON THAT NUMBER.
|
||||
THESE PAY OFF 35:1
|
||||
|
||||
THE 2:1 BETS ARE:
|
||||
37) 1-12 40) FIRST COLUMN
|
||||
38) 13-24 41) SECOND COLUMN
|
||||
39) 25-36 42) THIRD COLUMN
|
||||
|
||||
THE EVEN MONEY BETS ARE:
|
||||
43) 1-18 46) ODD
|
||||
44) 19-36 47) RED
|
||||
45) EVEN 48) BLACK
|
||||
|
||||
49)0 AND 50)00 PAY OFF 35:1
|
||||
NOTE: 0 AND 00 DO NOT COUNT UNDER ANY
|
||||
BETS EXCEPT THEIR OWN.
|
||||
|
||||
WHEN I ASK FOR EACH BET, TYPE THE NUMBER
|
||||
AND THE AMOUNT, SEPARATED BY A COMMA.
|
||||
FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500
|
||||
WHEN I ASK FOR A BET.
|
||||
|
||||
THE MINIMUM BET IS $5, THE MAXIMUM IS $500.
|
||||
|
||||
""")
|
||||
|
||||
def query_bets():
|
||||
"""Queries the user to input their bets"""
|
||||
betCount = -1
|
||||
while betCount <= 0:
|
||||
try:
|
||||
betCount = int(input("HOW MANY BETS? "))
|
||||
except:
|
||||
...
|
||||
|
||||
bet_IDs = [-1] * betCount
|
||||
bet_Values = [0] * betCount
|
||||
|
||||
for i in range(betCount):
|
||||
while(bet_IDs[i] == -1):
|
||||
try:
|
||||
inString = input("NUMBER " + str(i + 1) + "? ").split(',')
|
||||
id,val = int(inString[0]),int(inString[1])
|
||||
|
||||
# check other bet_IDs
|
||||
for j in range(i):
|
||||
if id != -1 and bet_IDs[j] == id:
|
||||
id = -1
|
||||
print("YOU ALREADY MADE THAT BET ONCE, DUM-DUM")
|
||||
break
|
||||
|
||||
if id > 0 and id <= 50 and val >= 5 and val <= 500:
|
||||
bet_IDs[i] = id
|
||||
bet_Values[i] = val
|
||||
except:
|
||||
...
|
||||
return bet_IDs,bet_Values
|
||||
|
||||
def bet_results(bet_IDs,bet_Values,result):
|
||||
"""Computes the results, prints them, and returns the total net winnings"""
|
||||
total_winnings = 0
|
||||
def get_modifier(id,num):
|
||||
if id == 37 and num <= 12:
|
||||
return 2
|
||||
elif id == 38 and num > 12 and num <= 24:
|
||||
return 2
|
||||
elif id == 39 and num > 24 and num < 37:
|
||||
return 2
|
||||
elif id == 40 and num < 37 and num % 3 == 1:
|
||||
return 2
|
||||
elif id == 41 and num < 37 and num % 3 == 2:
|
||||
return 2
|
||||
elif id == 42 and num < 37 and num % 3 == 0:
|
||||
return 2
|
||||
elif id == 43 and num <= 18:
|
||||
return 1
|
||||
elif id == 44 and num > 18 and num <= 36:
|
||||
return 1
|
||||
elif id == 45 and num % 2 == 0:
|
||||
return 1
|
||||
elif id == 46 and num % 2 == 1:
|
||||
return 1
|
||||
elif id == 47 and num in RED_NUMBERS:
|
||||
return 1
|
||||
elif id == 48 and num not in RED_NUMBERS:
|
||||
return 1
|
||||
elif id < 37 and id == num:
|
||||
return 35
|
||||
else:
|
||||
return -1
|
||||
|
||||
for i in range(len(bet_IDs)):
|
||||
winnings = bet_Values[i] * get_modifier(bet_IDs[i],result)
|
||||
total_winnings += winnings
|
||||
|
||||
if winnings >= 0:
|
||||
print("YOU WIN " + str(winnings) + " DOLLARS ON BET " + str(i + 1))
|
||||
else:
|
||||
print("YOU LOSE " + str(winnings * -1) + " DOLLARS ON BET " + str(i + 1))
|
||||
|
||||
return winnings
|
||||
|
||||
def print_check(amount):
|
||||
"""Prints a check of a given amount"""
|
||||
name = input("TO WHOM SHALL I MAKE THE CHECK? ")
|
||||
|
||||
print("-" * 72)
|
||||
print()
|
||||
print(" " * 40 + "CHECK NO. " + str(random.randint(0,100)))
|
||||
print(" " * 40 + str(date.today()))
|
||||
print()
|
||||
print("PAY TO THE ORDER OF -----" + name + "----- $" + str(amount))
|
||||
print()
|
||||
print(" " * 40 + "THE MEMORY BANK OF NEW YORK")
|
||||
print(" " * 40 + "THE COMPUTER")
|
||||
print(" " * 40 + "----------X-----")
|
||||
print("-" * 72)
|
||||
|
||||
def main():
|
||||
player_balance = 1000
|
||||
host_balance = 100000
|
||||
|
||||
print(" " * 32 + "ROULETTE")
|
||||
print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
||||
print()
|
||||
print()
|
||||
print()
|
||||
|
||||
if stringtobool(input("DO YOU WANT INSTRUCTIONS? ")):
|
||||
print_instructions()
|
||||
|
||||
while True:
|
||||
bet_IDs,bet_Values = query_bets()
|
||||
|
||||
print("SPINNING")
|
||||
print()
|
||||
print()
|
||||
|
||||
val = random.randint(0,38)
|
||||
if val == 38:
|
||||
print("0")
|
||||
elif val == 37:
|
||||
print("00")
|
||||
elif val in RED_NUMBERS:
|
||||
print(str(val) + " RED")
|
||||
else:
|
||||
print(str(val) + " BLACK")
|
||||
|
||||
print()
|
||||
total_winnings = bet_results(bet_IDs,bet_Values,val)
|
||||
player_balance += total_winnings
|
||||
host_balance -= total_winnings
|
||||
|
||||
print()
|
||||
print("TOTALS:\tME\t\tYOU")
|
||||
print("\t\t" + str(host_balance) + "\t" + str(player_balance))
|
||||
|
||||
if player_balance <= 0:
|
||||
print("OOPS! YOU JUST SPENT YOUR LAST DOLLAR!")
|
||||
break
|
||||
elif host_balance <= 0:
|
||||
print("YOU BROKE THE HOUSE!")
|
||||
player_balance = 101000
|
||||
break
|
||||
if not stringtobool(input("PLAY AGAIN? ")):
|
||||
break
|
||||
|
||||
|
||||
if player_balance <= 0:
|
||||
print("THANKS FOR YOUR MONEY")
|
||||
print("I'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL")
|
||||
else:
|
||||
print_check(player_balance)
|
||||
print("COME BACK SOON!")
|
||||
|
||||
|
||||
def stringtobool(string):
|
||||
"""Converts a string to a bool"""
|
||||
return string.lower() in ("yes","y","true","t","yes")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
73
76_Russian_Roulette/ruby/russianroulette.rb
Normal file
73
76_Russian_Roulette/ruby/russianroulette.rb
Normal file
@@ -0,0 +1,73 @@
|
||||
puts <<~INSTRUCTIONS
|
||||
RUSSIAN ROULETTE
|
||||
CREATIVE COMPUTING MORRISTOWN, NEW JERSEY
|
||||
|
||||
|
||||
|
||||
THIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE.
|
||||
|
||||
HERE IS A REVOLVER.
|
||||
|
||||
INSTRUCTIONS
|
||||
|
||||
NUMBER_OF_ROUNDS = 9
|
||||
|
||||
def parse_input
|
||||
correct_input = false
|
||||
|
||||
while not correct_input
|
||||
puts " ?"
|
||||
inp = gets.chomp
|
||||
if inp == "1" or inp == "2"
|
||||
correct_input = true
|
||||
end
|
||||
end
|
||||
|
||||
inp
|
||||
end
|
||||
|
||||
while true
|
||||
|
||||
dead = false
|
||||
n = 0
|
||||
|
||||
puts "TYPE \'1\' TO SPIN CHAMBER AND PULL TRIGGER"
|
||||
puts "TYPE \'2\' TO GIVE UP"
|
||||
puts "GO"
|
||||
|
||||
while not dead
|
||||
|
||||
inp = parse_input
|
||||
|
||||
if inp == "2"
|
||||
break
|
||||
end
|
||||
|
||||
if rand > 0.8333333333333334
|
||||
dead = true
|
||||
else
|
||||
puts "- CLICK -"
|
||||
n += 1
|
||||
end
|
||||
|
||||
if n > NUMBER_OF_ROUNDS
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if dead
|
||||
puts "BANG!!!!! You're Dead!"
|
||||
puts "Condolences will be sent to your relatives.\n\n\n"
|
||||
puts "...Next victim..."
|
||||
else
|
||||
if n > NUMBER_OF_ROUNDS
|
||||
puts "You win!!!!!"
|
||||
puts "Let someone else blow his brain out.\n"
|
||||
else
|
||||
puts " Chicken!!!!!\n\n\n"
|
||||
puts "...Next victim...."
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,3 +1,23 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Perl](https://www.perl.org/)
|
||||
|
||||
This Perl script is a port of slots, which is the 80th entry in Basic
|
||||
Computer Games.
|
||||
|
||||
I know nothing about slot machines, and my research into them says to me
|
||||
that the payout tables can be fairly arbitrary. But I have taken the
|
||||
liberty of deeming the BASIC program's refusal to pay on LEMON CHERRY
|
||||
LEMON a bug, and made that case a double.
|
||||
|
||||
My justification for this is that at the point where the BASIC has
|
||||
detected the double in the first and third reels it has already detected
|
||||
that there is no double in the first and second reels. After the check
|
||||
for a bar (and therefore a double bar) fails it goes back and checks for
|
||||
a double on the second and third reels. But we know this check will
|
||||
fail, since the check for a double on the first and second reels failed.
|
||||
So if a loss was intended at this point, why not just call it a loss?
|
||||
|
||||
To restore the original behavior, comment out the entire line commented
|
||||
'# Bug fix?' (about line 75) and uncomment the line with the trailing
|
||||
comment '# Bug?' (about line 83).
|
||||
|
||||
242
80_Slots/perl/slots.pl
Executable file
242
80_Slots/perl/slots.pl
Executable file
@@ -0,0 +1,242 @@
|
||||
#!/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 List::Util qw{ shuffle }; # Shuffle an array.
|
||||
use Scalar::Util qw{ looks_like_number };
|
||||
use Term::ReadLine; # Prompt and return user input
|
||||
|
||||
our $VERSION = '0.000_01';
|
||||
|
||||
print <<'EOD';
|
||||
SLOTS
|
||||
Creative Computing Morristown, New Jersey
|
||||
|
||||
|
||||
|
||||
You are in the H&M casino, in front of one of our
|
||||
one-arm bandits. Bet from $1 to $100.
|
||||
To pull the arm, punch the return key after making your bet.
|
||||
EOD
|
||||
|
||||
my $winnings = 0; # Winnings
|
||||
|
||||
while ( 1 ) { # Iterate indefinitely
|
||||
|
||||
say '';
|
||||
|
||||
my $bet = get_input( 'Your bet? ',
|
||||
sub { m/ \A [0-9]+ \z /smx },
|
||||
'Please enter a whole number between 0 and 100',
|
||||
);
|
||||
if ( $bet > 100 ) {
|
||||
say 'The house limit is $100';
|
||||
next;
|
||||
}
|
||||
if ( $bet < 1 ) {
|
||||
say 'The minimum bet is $1';
|
||||
next;
|
||||
}
|
||||
|
||||
say "\a" x 10;
|
||||
my $reel_x = int( 6 * rand() );
|
||||
my $reel_y = int( 6 * rand() );
|
||||
my $reel_z = int( 6 * rand() );
|
||||
foreach my $column ( $reel_x, $reel_y, $reel_z ) {
|
||||
state $symbol = [ qw{ Bar Bell Orange Lemon Plum Cherry } ];
|
||||
print $symbol->[$column], "\a" x 5, ' ';
|
||||
}
|
||||
|
||||
use constant YOU_WON => 'You won!';
|
||||
use constant YOU_LOST => 'You lost.';
|
||||
|
||||
say '';
|
||||
if ( $reel_x == $reel_y ) {
|
||||
if ( $reel_y == $reel_z ) {
|
||||
if ( $reel_z ) {
|
||||
say '** TOP DOLLAR **';
|
||||
$winnings += 11 * $bet;
|
||||
} else {
|
||||
say '*** JACKPOT ***';
|
||||
$winnings += 101 * $bet;
|
||||
}
|
||||
say YOU_WON;
|
||||
} elsif ( $reel_y ) {
|
||||
$winnings += double( $bet );
|
||||
} else {
|
||||
$winnings += double_bar( $bet );
|
||||
}
|
||||
} elsif ( $reel_x == $reel_z ) {
|
||||
if ( $reel_z ) {
|
||||
$winnings += double( $bet ); # Bug fix?
|
||||
# NOTE that the below code is what is actually implemented
|
||||
# in the basic, but it is implemented strangely enough (a
|
||||
# GOTO a line that contains a test that, if I understand the
|
||||
# control flow, must fail) that I wonder if it is an error.
|
||||
# I know nothing about slot machines, but research suggests
|
||||
# the payoff table is fairly arbitrary. The code above makes
|
||||
# code above makes the game orthogonal.
|
||||
# $winnings += you_lost( $bet ); # Bug?
|
||||
} else {
|
||||
$winnings += double_bar( $bet );
|
||||
}
|
||||
} elsif ( $reel_y == $reel_z ) {
|
||||
if ( $reel_z ) {
|
||||
$winnings += double( $bet );
|
||||
} else {
|
||||
$winnings += double_bar( $bet );
|
||||
}
|
||||
} else {
|
||||
$winnings += you_lost( $bet );
|
||||
}
|
||||
|
||||
say 'Your standings are $', $winnings;
|
||||
|
||||
last unless get_yes_no( 'Again' );
|
||||
|
||||
}
|
||||
|
||||
if ( $winnings < 0 ) {
|
||||
say 'Pay up! Please leave your money on the terminal.';
|
||||
} elsif ( $winnings > 0 ) {
|
||||
say 'Collect your winnings from the H&M cashier.';
|
||||
} else {
|
||||
say 'Hey, you broke even.';
|
||||
}
|
||||
|
||||
sub double {
|
||||
my ( $bet ) = @_;
|
||||
say 'DOUBLE!';
|
||||
say YOU_WON;
|
||||
return 3 * $bet;
|
||||
}
|
||||
|
||||
sub double_bar {
|
||||
my ( $bet ) = @_;
|
||||
say '* DOUBLE BAR *';
|
||||
say YOU_WON;
|
||||
return 6 * $bet;
|
||||
}
|
||||
|
||||
sub you_lost {
|
||||
my ( $bet ) = @_;
|
||||
say YOU_LOST;
|
||||
return -$bet;
|
||||
}
|
||||
|
||||
# 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( 'reverse' );
|
||||
$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 };
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 TITLE
|
||||
|
||||
slots - Play the game 'Slots' from Basic Computer Games
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
slots.pl
|
||||
|
||||
=head1 DETAILS
|
||||
|
||||
This Perl script is a port of C<slots>, which is the 80th entry in Basic
|
||||
Computer Games.
|
||||
|
||||
I know nothing about slot machines, and my research into them says to me
|
||||
that the payout tables can be fairly arbitrary. But I have taken the
|
||||
liberty of deeming the BASIC program's refusal to pay on LEMON CHERRY
|
||||
LEMON a bug, and made that case a double.
|
||||
|
||||
My justification for this is that at the point where the BASIC has
|
||||
detected the double in the first and third reels it has already detected
|
||||
that there is no double in the first and second reels. After the check
|
||||
for a bar (and therefore a double bar) fails it goes back and checks for
|
||||
a double on the second and third reels. But we know this check will
|
||||
fail, since the check for a double on the first and second reels failed.
|
||||
So if a loss was intended at this point, why not just call it a loss?
|
||||
|
||||
To restore the original behavior, comment out the entire line commented
|
||||
C<'# Bug fix?'> (about line 75) and uncomment the line with the trailing
|
||||
comment C<'# Bug?'> (about line 83).
|
||||
|
||||
=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 :
|
||||
152
80_Slots/ruby/slots.rb
Normal file
152
80_Slots/ruby/slots.rb
Normal file
@@ -0,0 +1,152 @@
|
||||
$pot = 0
|
||||
|
||||
def greeting
|
||||
puts "SLOTS".center(80)
|
||||
puts "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY".center(80)
|
||||
puts "\n\n"
|
||||
|
||||
# PRODUCED BY FRED MIRABELLE AND BOB HARPER ON JAN 29, 1973
|
||||
# IT SIMULATES THE SLOT MACHINE.
|
||||
|
||||
puts "You are in the H&M Casino, in front of one of our"
|
||||
puts "one-arm bandits. You can bet from $1 to $100."
|
||||
puts "To pull the arm, punch the return key after making your bet."
|
||||
puts "\nBet zero to end the game."
|
||||
end
|
||||
|
||||
def overLimit
|
||||
puts "House Limit is $100"
|
||||
end
|
||||
|
||||
def underMinimum
|
||||
puts "Minimum Bet is $1"
|
||||
end
|
||||
|
||||
# bells don't work on my machine. YMMV
|
||||
# I'm displaying dashes between the reels
|
||||
|
||||
def tenBells
|
||||
10.times do
|
||||
# beep if you can
|
||||
print "-"
|
||||
end
|
||||
end
|
||||
|
||||
def fiveBells
|
||||
"-----"
|
||||
end
|
||||
|
||||
def goodbye
|
||||
puts "\n\n\n"
|
||||
# end the game
|
||||
exit
|
||||
end
|
||||
|
||||
def payUp
|
||||
puts "PAY UP! PLEASE LEAVE YOUR MONEY ON THE TERMINAL."
|
||||
end
|
||||
|
||||
def brokeEven
|
||||
puts "HEY, YOU BROKE EVEN."
|
||||
end
|
||||
|
||||
def collectWinnings
|
||||
puts "COLLECT YOUR WINNINGS FROM THE H&M CASHIER."
|
||||
end
|
||||
|
||||
def win winType, bet
|
||||
case winType
|
||||
when "jackpot"
|
||||
winMessage = "***JACKPOT***"
|
||||
winnings = 101
|
||||
when "topDollar"
|
||||
winMessage = "**TOP DOLLAR**"
|
||||
winnings = 11
|
||||
when "doubleBar"
|
||||
winMessage = "*DOUBLE BAR!!*"
|
||||
winnings = 6
|
||||
when "double"
|
||||
winMessage = "DOUBLE!!"
|
||||
winnings = 3
|
||||
end
|
||||
puts "\nYou won: " + winMessage
|
||||
$pot += (winnings * bet)
|
||||
end
|
||||
|
||||
greeting
|
||||
|
||||
#$pot = 0
|
||||
while true
|
||||
reelArray = ["BAR","BELL","ORANGE","LEMON","PLUM","CHERRY"]
|
||||
print "\nYOUR BET? "
|
||||
# get input, remove leading and trailing whitespace, cast to integer
|
||||
bet = gets.strip.to_i
|
||||
|
||||
if bet == 0 then
|
||||
goodbye
|
||||
elsif bet > 100 then
|
||||
overLimit # error if more than $100
|
||||
elsif bet < 1 then
|
||||
underMinimum # have to bet at least a dollar
|
||||
else
|
||||
# valid bet, continue
|
||||
tenBells # ding
|
||||
|
||||
# assign a random value from the array to each of the three reels
|
||||
reel1 = reelArray[rand(5)]
|
||||
reel2 = reelArray[rand(5)]
|
||||
reel3 = reelArray[rand(5)]
|
||||
|
||||
# print the slot machine reels
|
||||
puts "\n\n" + reel1 + fiveBells + reel2 + fiveBells + reel3
|
||||
|
||||
# see if we have a match in the first two reels
|
||||
if reel1 == reel2 then
|
||||
if reel2 == reel3 then
|
||||
if reel3 == "BAR" then
|
||||
# all three reels are "BAR"
|
||||
win "jackpot", bet
|
||||
else
|
||||
# all three reels match but aren't "BAR"
|
||||
win "topDollar", bet
|
||||
end
|
||||
elsif reel2 == "BAR" then
|
||||
# reels 1 and 2 are both "BAR"
|
||||
win "doubleBar", bet
|
||||
else
|
||||
# reels 1 and 2 match but aren't "BAR"
|
||||
win "double", bet
|
||||
end
|
||||
# otherwise see if there's a match in the remaining reels
|
||||
elsif reel1 == reel3 or reel2 == reel3 then
|
||||
if reel3 == "BAR" then
|
||||
# two reels match, both "BAR"
|
||||
win "doubleBar", bet
|
||||
else
|
||||
# two reels match, but not "BAR"
|
||||
win "double", bet
|
||||
end
|
||||
else
|
||||
# bad news - no matches
|
||||
puts "\nYou lost"
|
||||
# decrement your standings by the bet amount
|
||||
$pot -= bet
|
||||
end
|
||||
|
||||
puts "Your standings are: " + $pot.to_s
|
||||
print "\nAgain? " # YES to continue
|
||||
# get input, remove leading and trailing whitespace, make uppercase
|
||||
again = gets.strip.upcase
|
||||
if again != "Y" && again != "YES" then
|
||||
# that's enough... evaluate the pot and quit
|
||||
if $pot < 0 then
|
||||
payUp
|
||||
elsif $pot == 0 then
|
||||
brokeEven
|
||||
else # yay!
|
||||
collectWinnings
|
||||
end
|
||||
goodbye
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -39,8 +39,7 @@ public class Splat {
|
||||
System.out.printf(" ACCELERATION = %.2f FT/SEC/SEC +/-5%%\n", initial.getOriginalAcceleration());
|
||||
|
||||
System.out.println("SET THE TIMER FOR YOUR FREEFALL.");
|
||||
System.out.print("HOW MANY SECONDS ");
|
||||
float freefallTime = scanner.nextFloat();
|
||||
float freefallTime = promptFloat("HOW MANY SECONDS ");
|
||||
System.out.println("HERE WE GO.\n");
|
||||
System.out.println("TIME (SEC) DIST TO FALL (FT)");
|
||||
System.out.println("========== =================");
|
||||
@@ -73,18 +72,28 @@ public class Splat {
|
||||
|
||||
private float promptTerminalVelocity() {
|
||||
if (askYesNo("SELECT YOUR OWN TERMINAL VELOCITY")) {
|
||||
System.out.print("WHAT TERMINAL VELOCITY (MI/HR) ");
|
||||
return mphToFeetPerSec(scanner.nextFloat());
|
||||
float terminalVelocity = promptFloat("WHAT TERMINAL VELOCITY (MI/HR) ");
|
||||
return mphToFeetPerSec(terminalVelocity);
|
||||
}
|
||||
float terminalVelocity = (int) (1000 * random.nextFloat());
|
||||
System.out.printf("OK. TERMINAL VELOCITY = %.2f MI/HR\n", terminalVelocity);
|
||||
return mphToFeetPerSec(terminalVelocity);
|
||||
}
|
||||
|
||||
private float promptFloat(String prompt){
|
||||
while(true){
|
||||
System.out.print(prompt);
|
||||
try {
|
||||
return scanner.nextFloat();
|
||||
} catch (Exception e) {
|
||||
scanner.next(); // clear current input
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float promptGravitationalAcceleration() {
|
||||
if (askYesNo("WANT TO SELECT ACCELERATION DUE TO GRAVITY")) {
|
||||
System.out.print("WHAT ACCELERATION (FT/SEC/SEC) ");
|
||||
return scanner.nextFloat();
|
||||
return promptFloat("WHAT ACCELERATION (FT/SEC/SEC) ");
|
||||
}
|
||||
return chooseRandomAcceleration();
|
||||
}
|
||||
|
||||
336
81_Splat/perl/splat.pl
Executable file
336
81_Splat/perl/splat.pl
Executable file
@@ -0,0 +1,336 @@
|
||||
#!/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 List::Util qw{ shuffle }; # Shuffle an array.
|
||||
use Scalar::Util qw{ looks_like_number };
|
||||
use Term::ReadLine; # Prompt and return user input
|
||||
|
||||
our $VERSION = '0.000_01';
|
||||
|
||||
use constant ROW_TPLT => ( '%4d' x 8 ) . "\n";
|
||||
|
||||
print <<'EOD';
|
||||
SPLAT
|
||||
Creative Computing Morristown, New Jersey
|
||||
|
||||
|
||||
|
||||
Welcome to 'Splat' -- the game that simulates a parachute
|
||||
jump. Try to open your chute at the last possible
|
||||
moment without going splat.
|
||||
EOD
|
||||
|
||||
while ( 1 ) {
|
||||
say '';
|
||||
my $initial_altitude = int( 9001 * rand() + 1000 );
|
||||
|
||||
my $nominal_terminal_velocity;
|
||||
if ( get_yes_no( 'Select your own terminal velocity' ) ) {
|
||||
$nominal_terminal_velocity = get_input(
|
||||
'What terminal velocity (mi/hr)? ',
|
||||
sub { looks_like_number( $ARG ) && $ARG > 0 },
|
||||
'Please enter a positive number',
|
||||
);
|
||||
# Convert miles per hour to feet per second
|
||||
$nominal_terminal_velocity = $nominal_terminal_velocity * 5280 / 3600;
|
||||
} else {
|
||||
$nominal_terminal_velocity = int( 1000 * rand() );
|
||||
say "OK. Terminal velocity = $nominal_terminal_velocity mi/hr"
|
||||
}
|
||||
my $terminal_velocity = dither( $nominal_terminal_velocity );
|
||||
|
||||
my $nominal_gravity; # Acceleration due to gravity
|
||||
if ( get_yes_no( 'Want to select acceleration due to gravity' ) ) {
|
||||
} else {
|
||||
state $body = [
|
||||
[ q<Fine. You're on Mercury. Acceleration = 12.2 ft/sec/sec.>,
|
||||
12.2 ],
|
||||
[ q<All right. You're on Venus. Acceleration = 28.3 ft/sec/sec.>,
|
||||
28.3 ],
|
||||
[ q<Then you're on Earth. Acceleration = 32.16 ft/sec/sec.>,
|
||||
32.16 ],
|
||||
[ q<Fine. You're on the Moon. Acceleration = 5.15 ft/sec/sec.>,
|
||||
5.15 ],
|
||||
[ q<All right. You're on Mars. Acceleration = 12.5 ft/sec/sec.>,
|
||||
12.5 ],
|
||||
[ q<Then you're on Jupiter. Acceleration = 85.2 ft/sec/sec.>,
|
||||
85.2 ],
|
||||
[ q<Fine. You're on Saturn. Acceleration = 37.6 ft/sec/sec.>,
|
||||
37.6 ],
|
||||
[ q<All right. You're on Uranus. Acceleration = 33.8 ft/sec/sec.>,
|
||||
33.8 ],
|
||||
[ q<Then you're on Neptune. Acceleration = 39.6 ft/sec/sec.>,
|
||||
39.6 ],
|
||||
[ q<Fine. You're on the Sun. Acceleration = 896 ft/sec/sec.>,
|
||||
896 ],
|
||||
];
|
||||
my $pick = $body->[ rand scalar @{ $body } ];
|
||||
say $pick->[0];
|
||||
$nominal_gravity = $pick->[1];
|
||||
}
|
||||
my $gravity = dither( $nominal_gravity );
|
||||
|
||||
print <<"EOD";
|
||||
|
||||
Altitude = $initial_altitude ft
|
||||
Term. velocity = $nominal_terminal_velocity ft/sec +/- 5%
|
||||
Acceleration = $nominal_gravity ft/sec/sec +/- 5%
|
||||
Set the timer for your freefall
|
||||
EOD
|
||||
|
||||
my $drop_time = get_input(
|
||||
'How many seconds? ',
|
||||
sub { m/ \A [0-9]+ \z /smx },
|
||||
"Please enter an unsigned integer\n",
|
||||
);
|
||||
|
||||
print <<'EOD';
|
||||
Here we go.
|
||||
|
||||
Time (sec) Dist to fall (ft)
|
||||
========== =================
|
||||
EOD
|
||||
|
||||
if ( defined( my $altitude = make_jump(
|
||||
$initial_altitude,
|
||||
$gravity,
|
||||
$terminal_velocity,
|
||||
$drop_time ) )
|
||||
) {
|
||||
# Successful jump
|
||||
state $succesful = [];
|
||||
state $ordinal = [ qw{ 1st 2nd 3rd } ];
|
||||
if ( defined( my $ord = $ordinal->[ @{ $succesful } ] ) ) {
|
||||
say "Amazing!!! Not nad for your $ord successful jump!!!";
|
||||
} else {
|
||||
my $jumps = @{ $succesful };
|
||||
my $worse = grep { $_ > $altitude } @{ $succesful };
|
||||
my $fractile = 1 - $worse / $jumps;
|
||||
my $better = $jumps - $worse;
|
||||
if ( $fractile <= 0.1 ) {
|
||||
print <<"EOD";
|
||||
Wow! That's some jumping. Of the $jumps successful jumps
|
||||
before yours, only $better opened their chutes lower than
|
||||
you did.
|
||||
EOD
|
||||
} elsif ( $fractile <= 0.25 ) {
|
||||
print <<"EOD";
|
||||
Pretty good! $jumps successful jumps preceded yours and only
|
||||
$better of them got lower than you did before their chutes
|
||||
opened.
|
||||
EOD
|
||||
} elsif ( $fractile <= 0.5 ) {
|
||||
print <<"EOD";
|
||||
Not bad. There have been $jumps successful jumps before yours.
|
||||
You were beaten out by $better of them.
|
||||
EOD
|
||||
} elsif ( $fractile <= 0.75 ) {
|
||||
print <<"EOD";
|
||||
Conservative, aren't you? You ranked only $better in the
|
||||
$jumps successful jumps before yours.
|
||||
EOD
|
||||
} elsif ( $fractile <= 0.9 ) {
|
||||
print <<"EOD";
|
||||
Humph! Don't you have any sporting blood? There were
|
||||
$jumps successful jumps before yours and you came in $worse jumps
|
||||
better than the worst. Shape up!!!
|
||||
EOD
|
||||
} else {
|
||||
print <<"EOD";
|
||||
Hey! You pulled the rip cord much too soon. $jumps successful
|
||||
jumps before yours and you came in number $better! Get with it!
|
||||
EOD
|
||||
}
|
||||
}
|
||||
push @{ $succesful }, $altitude;
|
||||
} else {
|
||||
# Splat
|
||||
|
||||
say q<I'll give you another chance.>;
|
||||
}
|
||||
|
||||
next if get_yes_no( 'Do you want to play again' );
|
||||
next if get_yes_no( 'Please' );
|
||||
|
||||
print <<'EOD';
|
||||
Ssssssssss.
|
||||
|
||||
EOD
|
||||
last;
|
||||
|
||||
}
|
||||
|
||||
# Return the first argument modified by up to plus or minus some
|
||||
# fraction specified by the second argument (default 0.05)
|
||||
sub dither {
|
||||
my ( $arg, $fract ) = @_;
|
||||
$fract //= 1 / 20;
|
||||
return $arg + ( $arg * rand() * $fract ) - ( $arg * rand() * $fract );
|
||||
}
|
||||
|
||||
use constant FORMAT_FALL => "%10.1f %10d\n";
|
||||
use constant FORMAT_SPLAT => "%10.1f %s\n";
|
||||
sub make_jump {
|
||||
my ( $initial_altitude, $gravity, $terminal_velocity, $drop_time ) = @_;
|
||||
my $altitude;
|
||||
foreach my $step ( 0 .. 8 ) {
|
||||
my $time = $step * $drop_time / 8;
|
||||
if ( $time > $terminal_velocity / $gravity ) {
|
||||
# Terminal velocity reached
|
||||
printf "Terminal velocity reached at T plus %.2f seconds.\n",
|
||||
$terminal_velocity / $gravity;
|
||||
for my $step ( $step .. 8 ) {
|
||||
my $time = $step * $drop_time / 8;
|
||||
$altitude = $initial_altitude - (
|
||||
$terminal_velocity * $terminal_velocity /
|
||||
( 2 * $gravity ) + $terminal_velocity * (
|
||||
$time - $terminal_velocity / $gravity ) );
|
||||
if ( $altitude > 0 ) {
|
||||
printf FORMAT_FALL, $time, $altitude;
|
||||
} else {
|
||||
splat(
|
||||
$terminal_velocity / $gravity + (
|
||||
$initial_altitude -
|
||||
$terminal_velocity * $terminal_velocity /
|
||||
( 2 * $gravity ) ) / $terminal_velocity,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
last;
|
||||
} else {
|
||||
$altitude = $initial_altitude - $gravity / 2 * $time * $time;
|
||||
if ( $altitude > 0 ) {
|
||||
printf FORMAT_FALL, $time, $altitude;
|
||||
} else {
|
||||
splat( sqrt( 2 * $initial_altitude / $gravity ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
say 'Chute open.';
|
||||
return $altitude;
|
||||
}
|
||||
|
||||
sub splat {
|
||||
my ( $time ) = @_;
|
||||
printf FORMAT_SPLAT, $time, 'Splat!';
|
||||
state $rip = [
|
||||
q<Requiescat in pace.>,
|
||||
q<May the angel of heaven lead you into paradise.>,
|
||||
q<Rest in peace.>,
|
||||
q<Son-of-a-gun.>,
|
||||
q<#$%&&%!$>,
|
||||
q<A kick in the pants is a boost if you're headed right.>,
|
||||
q<Hmmm. Should have picked a shorter time.>,
|
||||
q<Mutter. Mutter. Mutter.>,
|
||||
q<Pushing up daisies.>,
|
||||
q<Easy come, easy go.>,
|
||||
];
|
||||
say $rip->[ rand scalar @{ $rip } ];
|
||||
return;
|
||||
}
|
||||
|
||||
# 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( 'reverse' );
|
||||
$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 };
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 TITLE
|
||||
|
||||
splat.pl - Play the game 'splat' from Basic Computer Games
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
splat.pl
|
||||
|
||||
=head1 DETAILS
|
||||
|
||||
This Perl script is a port of C<splat>, which is the 73rd entry in
|
||||
Basic Computer Games.
|
||||
|
||||
This is a very basic port. All I really did was untangle the spaghetti.
|
||||
|
||||
=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 :
|
||||
208
83_Stock_Market/python/Stock_Market.py
Normal file
208
83_Stock_Market/python/Stock_Market.py
Normal file
@@ -0,0 +1,208 @@
|
||||
import random
|
||||
|
||||
#Stock_Market
|
||||
class Stock_Market():
|
||||
|
||||
def __init__(self):
|
||||
|
||||
#Hard Coded Names
|
||||
short_names = ['IBM', 'RCA', 'LBJ', 'ABC', 'CBS']
|
||||
full_names = ['INT. BALLISTIC MISSLES', 'RED CROSS OF AMERICA',
|
||||
'LICHTENSTEIN, BUMRAP & JOKE', 'AMERICAN BANKRUPT CO.',
|
||||
'CENSURED BOOKS STORE']
|
||||
|
||||
#Initializing Dictionary to hold all the information systematically
|
||||
self.data = {}
|
||||
for sn, fn in zip(short_names, full_names):
|
||||
#A dictionary for each stock
|
||||
temp = {'Name' : fn, 'Price' : None, 'Holdings' : 0}
|
||||
#Nested outer dictionary for all stocks
|
||||
self.data[sn] = temp
|
||||
|
||||
#Initializing Randomly generated initial prices
|
||||
for stock in self.data.values():
|
||||
stock['Price'] = round(random.uniform(80,120),2) #Price b/w 60 and 120
|
||||
|
||||
#Initialize Assets
|
||||
self.cash_assets = 10000
|
||||
self.stock_assets = 0
|
||||
|
||||
def total_assets(self):
|
||||
|
||||
return self.cash_assets + self.stock_assets
|
||||
|
||||
def _generate_day_change(self):
|
||||
|
||||
self.changes = []
|
||||
for _ in range(len(self.data)):
|
||||
self.changes.append(round(random.uniform(-5,5),2)) #Random % Change b/w -5 and 5
|
||||
|
||||
def update_prices(self):
|
||||
|
||||
self._generate_day_change()
|
||||
for stock, change in zip(self.data.values(), self.changes):
|
||||
stock['Price'] = round(stock['Price'] + (change/100)*stock['Price'], 2)
|
||||
|
||||
def print_exchange_average(self):
|
||||
|
||||
sum = 0
|
||||
for stock in self.data.values():
|
||||
sum += stock['Price']
|
||||
|
||||
print('\nNEW YORK STOCK EXCHANGE AVERAGE: ${:.2f}'.format(sum/5))
|
||||
|
||||
def get_average_change(self):
|
||||
|
||||
sum = 0
|
||||
for change in self.changes:
|
||||
sum += change
|
||||
|
||||
return round(sum/5,2)
|
||||
|
||||
def print_first_day(self):
|
||||
|
||||
print('\nSTOCK\t\t\t\t\tINITIALS\tPRICE/SHARE($)')
|
||||
for stock, data in self.data.items():
|
||||
if stock != 'LBJ':
|
||||
print('{}\t\t\t{}\t\t{}'.format(data['Name'], stock, data['Price']))
|
||||
else:
|
||||
print('{}\t\t{}\t\t{}'.format(data['Name'], stock, data['Price']))
|
||||
|
||||
self.print_exchange_average()
|
||||
self.print_assets()
|
||||
|
||||
def take_inputs(self):
|
||||
|
||||
print('\nWHAT IS YOUR TRANSACTION IN')
|
||||
flag = False
|
||||
while flag != True:
|
||||
new_holdings = []
|
||||
for stock in self.data.keys():
|
||||
try:
|
||||
new_holdings.append(int(input('{}? '.format(stock))))
|
||||
except:
|
||||
print('\nINVALID ENTRY, TRY AGAIN\n')
|
||||
break
|
||||
if len(new_holdings) == 5:
|
||||
flag = self._check_transaction(new_holdings)
|
||||
|
||||
return new_holdings
|
||||
|
||||
def print_trading_day(self):
|
||||
|
||||
print("STOCK\tPRICE/SHARE\tHOLDINGS\tNET. Value\tPRICE CHANGE")
|
||||
for stock, data, change in zip(self.data.keys(), self.data.values(),self.changes):
|
||||
value = data['Price'] * data['Holdings']
|
||||
print('{}\t{}\t\t{}\t\t{:.2f}\t\t{}'.format(stock, data['Price'], data['Holdings'], value, change))
|
||||
|
||||
def update_cash_assets(self, new_holdings):
|
||||
|
||||
sell=0
|
||||
buy=0
|
||||
for stock, holding in zip(self.data.values(), new_holdings):
|
||||
if holding > 0:
|
||||
buy += stock['Price']*holding
|
||||
|
||||
elif holding < 0:
|
||||
sell += stock['Price']*abs(holding)
|
||||
|
||||
self.cash_assets = self.cash_assets + sell - buy
|
||||
|
||||
def update_stock_assets(self):
|
||||
|
||||
sum=0
|
||||
for data in self.data.values():
|
||||
sum += data['Price']*data['Holdings']
|
||||
|
||||
self.stock_assets = round(sum,2)
|
||||
|
||||
def print_assets(self):
|
||||
|
||||
print('\nTOTAL STOCK ASSETS ARE: ${:.2f}'.format(self.stock_assets))
|
||||
print('TOTAL CASH ASSETS ARE: ${:.2f}'.format(self.cash_assets))
|
||||
print('TOTAL ASSETS ARE: ${:.2f}'.format(self.total_assets()))
|
||||
|
||||
def _check_transaction(self, new_holdings):
|
||||
|
||||
sum = 0
|
||||
for stock, holding in zip(self.data.values(), new_holdings):
|
||||
if holding > 0:
|
||||
sum += stock['Price']*holding
|
||||
|
||||
elif holding < 0:
|
||||
if abs(holding) > stock['Holdings']:
|
||||
print('\nYOU HAVE OVERSOLD SOME STOCKS, TRY AGAIN\n')
|
||||
return False
|
||||
|
||||
if sum > self.cash_assets:
|
||||
print('\nYOU HAVE USED ${:.2f} MORE THAN YOU HAVE, TRY AGAIN\n'.format(sum - self.cash_assets))
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def update_holdings(self, new_holdings):
|
||||
|
||||
for stock, new_holding in zip(self.data.values(), new_holdings):
|
||||
stock['Holdings'] += new_holding
|
||||
|
||||
def print_instruction():
|
||||
|
||||
print('''
|
||||
THIS PROGRAM PLAYS THE STOCK MARKET. YOU WILL BE GIVEN
|
||||
$10,000 AND MAY BUY OR SELL STOCKS. THE STOCK PRICES WILL
|
||||
BE GENERATED RANDOMLY AND THEREFORE THIS MODEL DOES NOT
|
||||
REPRESENT EXACTLY WHAT HAPPENS ON THE EXCHANGE. A TABLE
|
||||
OF AVAILABLE STOCKS, THEIR PRICES, AND THE NUMBER OF SHARES
|
||||
IN YOUR PORTFOLIO WILL BE PRINTED. FOLLOWING THIS, THE
|
||||
INITIALS OF EACH STOCK WILL BE PRINTED WITH A QUESTION
|
||||
MARK. HERE YOU INDICATE A TRANSACTION. TO BUY A STOCK
|
||||
TYPE +NNN, TO SELL A STOCK TYPE -NNN, WHERE NNN IS THE
|
||||
NUMBER OF SHARES. A BROKERAGE FEE OF 1% WILL BE CHARGED
|
||||
ON ALL TRANSACTIONS. NOTE THAT IF A STOCK'S VALUE DROPS
|
||||
TO ZERO IT MAY REBOUND TO A POSITIVE VALUE AGAIN. YOU
|
||||
HAVE $10,000 TO INVEST. USE INTEGERS FOR ALL YOUR INPUTS.
|
||||
(NOTE: TO GET A 'FEEL' FOR THE MARKET RUN FOR AT LEAST
|
||||
10 DAYS)
|
||||
------------GOOD LUCK!------------\n
|
||||
''')
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
print('\t\t STOCK MARKET')
|
||||
help = input('\nDO YOU WANT INSTRUCTIONS(YES OR NO)? ')
|
||||
|
||||
#Printing Instruction
|
||||
if help == 'YES' or help == 'yes' or help == 'Yes':
|
||||
print_instruction()
|
||||
|
||||
#Initialize Game
|
||||
Game = Stock_Market()
|
||||
|
||||
#Do first day
|
||||
Game.print_first_day()
|
||||
new_holdings = Game.take_inputs()
|
||||
Game.update_holdings(new_holdings)
|
||||
Game.update_cash_assets(new_holdings)
|
||||
print('\n------------END OF TRADING DAY--------------\n')
|
||||
|
||||
response = 1
|
||||
while response == 1:
|
||||
|
||||
#Simulate a DAY
|
||||
Game.update_prices()
|
||||
Game.print_trading_day()
|
||||
Game.print_exchange_average()
|
||||
Game.update_stock_assets()
|
||||
Game.print_assets()
|
||||
|
||||
response = int(input('\nDO YOU WISH TO CONTINUE (YES-TYPE 1, NO-TYPE 0)? '))
|
||||
if response == 0:
|
||||
break
|
||||
|
||||
new_holdings = Game.take_inputs()
|
||||
Game.update_holdings(new_holdings)
|
||||
Game.update_cash_assets(new_holdings)
|
||||
print('\n------------END OF TRADING DAY--------------\n')
|
||||
|
||||
print('\nHOPE YOU HAD FUN!!!!')
|
||||
input('')
|
||||
94
85_Synonym/ruby/synonim.rb
Normal file
94
85_Synonym/ruby/synonim.rb
Normal file
@@ -0,0 +1,94 @@
|
||||
########################################################
|
||||
#
|
||||
# Synonym
|
||||
#
|
||||
# From Basic Computer Games (1978)
|
||||
#
|
||||
# A synonym of a word is another word (in the English language) which has the same,
|
||||
# or very nearly the same, meaning. This program tests your knowledge of synonyms
|
||||
# of a few common words.
|
||||
#
|
||||
# The computer chooses a word and asks you for a synonym. The computer then tells
|
||||
# you whether you’re right or wrong. If you can’t think of a synonym, type “HELP”
|
||||
# which causes a synonym to be printed.
|
||||
# You may put in words of your choice in the data statements.
|
||||
# The number following DATA in Statement 500 is the total number of data statements.
|
||||
# In each data statement, the first number is the number of words in that statement.
|
||||
#
|
||||
# Can you think of a way to make this into a more general kind of CAI program for any subject?
|
||||
# Walt Koetke of Lexington High School, Massachusetts created this program.
|
||||
#
|
||||
#
|
||||
########################################################
|
||||
|
||||
puts <<~INSTRUCTIONS
|
||||
SYNONYM
|
||||
CREATIVE COMPUTING MORRISTOWN, NEW JERSEY
|
||||
|
||||
A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH
|
||||
LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME MEANING.
|
||||
I CHOOSE A WORD -- YOU TYPE A SYNONYM.
|
||||
IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'
|
||||
AND I WILL TELL YOU A SYNONYM.
|
||||
|
||||
|
||||
INSTRUCTIONS
|
||||
|
||||
right_words = ["RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK"]
|
||||
|
||||
synonym_words = [
|
||||
["FIRST", "START", "BEGINNING", "ONSET", "INITIAL"],
|
||||
["SIMILAR", "ALIKE", "SAME", "LIKE", "RESEMBLING"],
|
||||
["MODEL", "PATTERN", "PROTOTYPE", "STANDARD", "CRITERION"],
|
||||
["SMALL", "INSIGNIFICANT", "LITTLE", "TINY", "MINUTE"],
|
||||
["STOP", "HALT", "STAY", "ARREST", "CHECK", "STANDSTILL"],
|
||||
["HOUSE", "DWELLING", "RESIDENCE", "DOMICILE", "LODGING", "HABITATION"],
|
||||
["PIT", "HOLE", "HOLLOW", "WELL", "GULF", "CHASM", "ABYSS"],
|
||||
["PUSH", "SHOVE", "THRUST", "PROD", "POKE", "BUTT", "PRESS"],
|
||||
["RED", "ROUGE", "SCARLET", "CRIMSON", "FLAME", "RUBY"],
|
||||
["PAIN", "SUFFERING", "HURT", "MISERY", "DISTRESS", "ACHE", "DISCOMFORT"],
|
||||
]
|
||||
|
||||
synonym_words.shuffle.each {|words_ar|
|
||||
|
||||
}
|
||||
|
||||
|
||||
synonym_words.each {|words_ar|
|
||||
answer = false
|
||||
keyword = words_ar.shift
|
||||
|
||||
while not answer and words_ar.length != 0
|
||||
puts " WHAT IS A SYNONYM OF #{keyword}? "
|
||||
inp = gets.chomp.upcase
|
||||
|
||||
if inp == "HELP"
|
||||
clue = words_ar.sample
|
||||
puts "**** A SYNONYM OF #{keyword} IS #{clue}."
|
||||
words_ar.delete(clue)
|
||||
elsif words_ar.include? inp
|
||||
puts right_words.sample
|
||||
answer = true
|
||||
else
|
||||
puts "TRY AGAIN."
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
}
|
||||
|
||||
puts "SYNONYM DRILL COMPLETED"
|
||||
|
||||
|
||||
######################################################################
|
||||
#
|
||||
# Porting notes
|
||||
#
|
||||
# There is a bug in the original program where if you keep asking for
|
||||
# synoyms of a given word it ends up running out of synonyms
|
||||
# in the array and the program crashes.
|
||||
# The bug has been fixed in this version and now when
|
||||
# it runs out of words it continues with the next
|
||||
# array.
|
||||
#
|
||||
######################################################################
|
||||
2
87_3-D_Plot/d/.gitignore
vendored
Normal file
2
87_3-D_Plot/d/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.exe
|
||||
*.obj
|
||||
182
87_3-D_Plot/d/README.md
Normal file
182
87_3-D_Plot/d/README.md
Normal file
@@ -0,0 +1,182 @@
|
||||
Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Converted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).
|
||||
|
||||
## Running the code
|
||||
|
||||
Assuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:
|
||||
```shell
|
||||
dmd -dip1000 -run threedeeplot.d
|
||||
```
|
||||
|
||||
[Other compilers](https://dlang.org/download.html) also exist.
|
||||
|
||||
## On rounding floating point values to integer values
|
||||
|
||||
The D equivalent of Basic `INT` is [`floor`](https://dlang.org/phobos/std_math_rounding.html#.floor),
|
||||
which rounds towards negative infinity. If you change occurrences of `floor` to
|
||||
[`lrint`](https://dlang.org/phobos/std_math_rounding.html#.lrint), you'll see that the plots show a bit more detail,
|
||||
as is done in the bonus below.
|
||||
|
||||
## Bonus: Self-writing programs
|
||||
|
||||
With a small modification to the source, the program can be extended to **plot a random function**, and **print its formula**.
|
||||
|
||||
```shell
|
||||
rdmd -dip1000 threedeeplot_random.d
|
||||
```
|
||||
(`rdmd` caches the executable, which results in speedy execution when the source does not change.)
|
||||
|
||||
### Example output
|
||||
```
|
||||
3D Plot
|
||||
(After Creative Computing Morristown, New Jersey)
|
||||
|
||||
|
||||
f(z) = 30 * sin(z / 10.0)
|
||||
|
||||
*
|
||||
* * * *
|
||||
* * * * *
|
||||
* * * * *
|
||||
* * * * * *
|
||||
* * * * * *
|
||||
* * * * * **
|
||||
* * * * * * *
|
||||
* * * * * * **
|
||||
* * * * * * * *
|
||||
* * * * * * * *
|
||||
* * * * * * * **
|
||||
* * * * * * * * *
|
||||
* * * * ** * * * *
|
||||
* * * * ** * * *
|
||||
* * * * * * * *
|
||||
* * * * * * * *
|
||||
* * * ** * * **
|
||||
* * * ** * **
|
||||
* * * * * **
|
||||
* * * * * **
|
||||
* * * * * **
|
||||
* * * ** * **
|
||||
* * * ** * * **
|
||||
* * * * * * * *
|
||||
* * * * * * * *
|
||||
* * * * ** * * *
|
||||
* * * * ** * * * *
|
||||
* * * * * * * * *
|
||||
* * * * * * * **
|
||||
* * * * * * * *
|
||||
* * * * * * * *
|
||||
* * * * * * **
|
||||
* * * * * * *
|
||||
* * * * * **
|
||||
* * * * * *
|
||||
* * * * * *
|
||||
* * * * *
|
||||
* * * * *
|
||||
* * * *
|
||||
*
|
||||
```
|
||||
|
||||
### Breakdown of differences
|
||||
|
||||
Have a look at the relevant differences between `threedeeplot.d` and `threedeeplot_random.d`.
|
||||
This is the original function with the single expression that is evaluated for the plot:
|
||||
```d
|
||||
static float fna(float z)
|
||||
{
|
||||
return 30.0 * exp(-z * z / 100.0);
|
||||
}
|
||||
```
|
||||
Here `static` means that the nested function does not need acces to its enclosing scope.
|
||||
|
||||
Now, by inserting the following:
|
||||
```d
|
||||
enum functions = ["30.0 * exp(-z * z / 100.0)",
|
||||
"sqrt(900.01 - z * z) * .9 - 2",
|
||||
"30 * (cos(z / 16.0) + .5)",
|
||||
"30 - 30 * sin(z / 18.0)",
|
||||
"30 * exp(-cos(z / 16.0)) - 30",
|
||||
"30 * sin(z / 10.0)"];
|
||||
|
||||
size_t index = uniform(0, functions.length);
|
||||
writeln(center("f(z) = " ~ functions[index], width), "\n");
|
||||
```
|
||||
and changing the implementation of `fna` to
|
||||
```d
|
||||
float fna(float z)
|
||||
{
|
||||
final switch (index)
|
||||
{
|
||||
static foreach (i, f; functions)
|
||||
case i:
|
||||
mixin("return " ~ f ~ ";");
|
||||
}
|
||||
}
|
||||
```
|
||||
we unlock some very special abilities of D. Let's break it down:
|
||||
|
||||
```d
|
||||
enum functions = ["30.0 * exp(-z * z / 100.0)", /*...*/];
|
||||
```
|
||||
This defines an array of strings, each containing a mathematical expression. Due to the `enum` keyword, this is an
|
||||
array that really only exists at compile-time.
|
||||
|
||||
```d
|
||||
size_t index = uniform(0, functions.length);
|
||||
```
|
||||
This defines a random index into the array. `functions.length` is evaluated at compile-time, due to D's compile-time
|
||||
function evaluation (CTFE).
|
||||
|
||||
```d
|
||||
writeln(center("f(z) = " ~ functions[index], width), "\n");
|
||||
```
|
||||
Unmistakenly, this prints the formula centered on a line. What happens behind the scenes is that `functions` (which
|
||||
only existed at compile-time before now) is pasted in, so that an instance of that array actually exists at run-time
|
||||
at this spot, and is instantly indexed.
|
||||
|
||||
```d
|
||||
float fna(float z)
|
||||
{
|
||||
final switch (index)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
`static` has been dropped from the nested function because we want to evaluate `index` inside it. The function contains
|
||||
an ordinary `switch`, with `final` providing some extra robustness. It disallows a `default` case and produces an error
|
||||
when the switch doesn't handle all cases. The `switch` body is where the magic happens and consists of these three
|
||||
lines:
|
||||
```d
|
||||
static foreach (i, f; functions)
|
||||
case i:
|
||||
mixin("return " ~ f ~ ";");
|
||||
```
|
||||
The `static foreach` iterates over `functions` at compile-time, producing one `case` for every element in `functions`.
|
||||
`mixin` takes a string, which is constructed at compile-time, and pastes it right into the source.
|
||||
|
||||
In effect, the implementation of `float fna(float z)` unrolls itself into
|
||||
```d
|
||||
float fna(float z)
|
||||
{
|
||||
final switch (index)
|
||||
{
|
||||
case 0:
|
||||
return 30.0 * exp(-z * z / 100.0);
|
||||
case 1:
|
||||
return sqrt(900.01 - z * z) * .9 - 2;
|
||||
case 2:
|
||||
return 30 * (cos(z / 16.0) + .5);
|
||||
case 3:
|
||||
return 30 - 30 * sin(z / 18.0);
|
||||
case 4:
|
||||
return 30 * exp(-cos(z / 16.0)) - 30;
|
||||
case 5:
|
||||
return 30 * sin(z / 10.0)";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
So if you feel like adding another function, all you need to do is append it to the `functions` array, and the rest of
|
||||
the program *rewrites itself...*
|
||||
35
87_3-D_Plot/d/threedeeplot.d
Normal file
35
87_3-D_Plot/d/threedeeplot.d
Normal file
@@ -0,0 +1,35 @@
|
||||
@safe: // Make @safe the default for this file, enforcing memory-safety.
|
||||
import std.stdio, std.string, std.math, std.range, std.conv, std.algorithm;
|
||||
|
||||
void main()
|
||||
{
|
||||
enum width = 80;
|
||||
writeln(center("3D Plot", width));
|
||||
writeln(center("(After Creative Computing Morristown, New Jersey)\n\n\n", width));
|
||||
|
||||
static float fna(float z)
|
||||
{
|
||||
return 30.0 * exp(-z * z / 100.0);
|
||||
}
|
||||
|
||||
char[] row;
|
||||
|
||||
for (float x = -30.0; x <= 30.0; x += 1.5)
|
||||
{
|
||||
size_t max_z = 0L;
|
||||
auto y1 = 5 * floor((sqrt(900 - x * x)) / 5.0);
|
||||
for (float y = y1; y >= -y1; y -= 5)
|
||||
{
|
||||
auto z = to!size_t(max(0, floor(25 + fna(sqrt(x * x + y * y)) - .7 * y)));
|
||||
if (z > max_z) // Visible
|
||||
{
|
||||
max_z = z;
|
||||
if (z + 1 > row.length) // row needs to grow
|
||||
row ~= ' '.repeat(z + 1 - row.length).array;
|
||||
row[z] = '*';
|
||||
}
|
||||
}
|
||||
writeln(row);
|
||||
row = null;
|
||||
}
|
||||
}
|
||||
50
87_3-D_Plot/d/threedeeplot_random.d
Normal file
50
87_3-D_Plot/d/threedeeplot_random.d
Normal file
@@ -0,0 +1,50 @@
|
||||
@safe: // Make @safe the default for this file, enforcing memory-safety.
|
||||
import std.stdio, std.string, std.math, std.range, std.conv, std.random, std.algorithm;
|
||||
|
||||
void main()
|
||||
{
|
||||
enum width = 80;
|
||||
writeln(center("3D Plot", width));
|
||||
writeln(center("(After Creative Computing Morristown, New Jersey)\n\n", width));
|
||||
|
||||
enum functions = ["30.0 * exp(-z * z / 100.0)",
|
||||
"sqrt(900.01 - z * z) * .9 - 2",
|
||||
"30 * (cos(z / 16.0) + .5)",
|
||||
"30 - 30 * sin(z / 18.0)",
|
||||
"30 * exp(-cos(z / 16.0)) - 30",
|
||||
"30 * sin(z / 10.0)"];
|
||||
|
||||
size_t index = uniform(0, functions.length);
|
||||
writeln(center("f(z) = " ~ functions[index], width), "\n");
|
||||
|
||||
float fna(float z)
|
||||
{
|
||||
final switch (index)
|
||||
{
|
||||
static foreach (i, f; functions)
|
||||
case i:
|
||||
mixin("return " ~ f ~ ";");
|
||||
}
|
||||
}
|
||||
|
||||
char[] row;
|
||||
|
||||
for (float x = -30.0; x <= 30.0; x += 1.5)
|
||||
{
|
||||
size_t max_z = 0L;
|
||||
auto y1 = 5 * lrint((sqrt(900 - x * x)) / 5.0);
|
||||
for (float y = y1; y >= -y1; y -= 5)
|
||||
{
|
||||
auto z = to!size_t(max(0, lrint(25 + fna(sqrt(x * x + y * y)) - .7 * y)));
|
||||
if (z > max_z) // Visible
|
||||
{
|
||||
max_z = z;
|
||||
if (z + 1 > row.length) // row needs to grow
|
||||
row ~= ' '.repeat(z + 1 - row.length).array;
|
||||
row[z] = '*';
|
||||
}
|
||||
}
|
||||
writeln(row);
|
||||
row = null;
|
||||
}
|
||||
}
|
||||
75
89_Tic-Tac-Toe/csharp/tictactoe1/Program.cs
Normal file
75
89_Tic-Tac-Toe/csharp/tictactoe1/Program.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
Console.WriteLine("Hello, World!");
|
||||
// Print text on the screen with 30 spaces before text
|
||||
Console.WriteLine("TIC TAC TOE".PadLeft(30));
|
||||
// Print text on screen with 15 spaces before text
|
||||
Console.WriteLine("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY".PadLeft(15));
|
||||
// Print three blank lines on screen
|
||||
Console.WriteLine("\n\n\n");
|
||||
// THIS PROGRAM PLAYS TIC TAC TOE
|
||||
// THE MACHINE GOES FIRST
|
||||
Console.WriteLine("THE GAME BOARD IS NUMBERED:\n");
|
||||
Console.WriteLine("1 2 3");
|
||||
Console.WriteLine("8 9 4");
|
||||
Console.WriteLine("7 6 5");
|
||||
|
||||
// Main program
|
||||
while(true) {
|
||||
int a, b, c, d, e;
|
||||
int p, q, r, s;
|
||||
a = 9;
|
||||
Console.WriteLine("\n\n");
|
||||
computerMoves(a);
|
||||
p = readYourMove();
|
||||
b = move(p + 1);
|
||||
computerMoves(b);
|
||||
q = readYourMove();
|
||||
if (q == move(b + 4)) {
|
||||
c = move(b + 2);
|
||||
computerMoves(c);
|
||||
r = readYourMove();
|
||||
if (r == move(c + 4)) {
|
||||
if (p % 2 != 0) {
|
||||
d = move(c + 3);
|
||||
computerMoves(d);
|
||||
s = readYourMove();
|
||||
if (s != move(d + 4)) {
|
||||
e = move(d + 4);
|
||||
computerMoves(e);
|
||||
}
|
||||
e = move(d + 6);
|
||||
computerMoves(e);
|
||||
Console.WriteLine("THE GAME IS A DRAW.");
|
||||
} else {
|
||||
d = move(c + 7);
|
||||
computerMoves(d);
|
||||
Console.WriteLine("AND WINS ********");
|
||||
}
|
||||
} else {
|
||||
d = move(c + 4);
|
||||
computerMoves(d);
|
||||
Console.WriteLine("AND WINS ********");
|
||||
}
|
||||
} else {
|
||||
c = move(b + 4);
|
||||
computerMoves(c);
|
||||
Console.WriteLine("AND WINS ********");
|
||||
}
|
||||
}
|
||||
|
||||
void computerMoves(int move) {
|
||||
Console.WriteLine("COMPUTER MOVES " + move);
|
||||
}
|
||||
int readYourMove() {
|
||||
while(true) {
|
||||
Console.Write("YOUR MOVE?");
|
||||
string input = Console.ReadLine();
|
||||
if (int.TryParse(input, out int number)) {
|
||||
return number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int move(int number) {
|
||||
return number - 8 * (int)((number - 1) / 8);
|
||||
}
|
||||
10
89_Tic-Tac-Toe/csharp/tictactoe1/tictactoe1.csproj
Normal file
10
89_Tic-Tac-Toe/csharp/tictactoe1/tictactoe1.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>
|
||||
205
89_Tic-Tac-Toe/perl/tictactoe2.pl
Normal file
205
89_Tic-Tac-Toe/perl/tictactoe2.pl
Normal file
@@ -0,0 +1,205 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
#GLOBALs
|
||||
my %board = (
|
||||
1 => 0,
|
||||
2 => 0,
|
||||
3 => 0,
|
||||
4 => 0,
|
||||
5 => 0,
|
||||
6 => 0,
|
||||
7 => 0,
|
||||
8 => 0,
|
||||
9 => 0,
|
||||
);
|
||||
|
||||
my %winning_combos = (
|
||||
1 => [1,2,3],
|
||||
2 => [4,5,6],
|
||||
3 => [7,8,9],
|
||||
4 => [1,4,7],
|
||||
5 => [2,5,8],
|
||||
6 => [3,6,9],
|
||||
7 => [1,5,9],
|
||||
8 => [7,5,3],
|
||||
);
|
||||
|
||||
my $player=100;
|
||||
my $player_goal=0;
|
||||
my $computer=100;
|
||||
my $computer_goal=0;
|
||||
my $count=0;
|
||||
|
||||
&main;
|
||||
|
||||
sub main {
|
||||
&print_intro;
|
||||
print "DO YOU WANT 'X' OR 'O'\n";
|
||||
chomp(my $ans = <STDIN>);
|
||||
&assign_X_and_O($ans);
|
||||
if ($ans eq "X") {
|
||||
until ($count >= 9) {
|
||||
&player_choice;
|
||||
$count++;
|
||||
&print_board;
|
||||
&check_for_winners;
|
||||
&computer_choice;
|
||||
$count++;
|
||||
&print_board;
|
||||
&check_for_winners;
|
||||
}
|
||||
}
|
||||
else {
|
||||
until ($count >= 9) {
|
||||
&computer_choice;
|
||||
$count++;
|
||||
&print_board;
|
||||
&check_for_winners;
|
||||
if ($count >= 9) {
|
||||
print "IT'S A DRAW. THANK YOU.\n";
|
||||
exit;
|
||||
}
|
||||
&player_choice;
|
||||
$count++;
|
||||
&print_board;
|
||||
&check_for_winners;
|
||||
}
|
||||
}
|
||||
print "IT'S A DRAW. THANK YOU.\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
# This will check to see if anyone has won by adding up the various 3-in-a-row lines.
|
||||
sub check_for_winners {
|
||||
my %tally;
|
||||
foreach my $key (keys %winning_combos) {
|
||||
foreach my $val (@{$winning_combos{$key}}) {
|
||||
$tally{$key}+=$board{$val};
|
||||
}
|
||||
}
|
||||
foreach my $key (keys %tally) {
|
||||
if ($tally{$key} == $player_goal) {
|
||||
print "YOU BEAT ME!! GOOD GAME.\n";
|
||||
exit;
|
||||
}
|
||||
if ($tally{$key} == $computer_goal) {
|
||||
print "I WIN, TURKEY!!!\n";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#On the computer's turn it will first check to see if it should block the player. If it finds it isn't going to win or need to block a player, the it will choose a spot to place it's X or O.
|
||||
|
||||
sub computer_choice {
|
||||
my $move;
|
||||
$move=&check_for_blocks_or_wins;;
|
||||
if ($move > 9) {
|
||||
$move=&check_for_corners;
|
||||
}
|
||||
print "THE COMPUTER MOVES TO...\n";
|
||||
$board{$move}=$computer;
|
||||
}
|
||||
|
||||
sub check_for_corners {
|
||||
my @precedence;
|
||||
if ($count == 0) {
|
||||
@precedence=(1,9,7,3,5,2,4,6,8);
|
||||
}
|
||||
else {
|
||||
@precedence=(5,1,9,7,3,2,4,6,8);
|
||||
}
|
||||
foreach my $move (@precedence) {
|
||||
my $validity=&check_occupation($move);
|
||||
if ($validity eq "valid") {
|
||||
return $move;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub check_for_blocks_or_wins {
|
||||
my %tally;
|
||||
my $validity = "invalid";
|
||||
my $move = 10;
|
||||
foreach my $key (keys %winning_combos) {
|
||||
foreach my $val (@{$winning_combos{$key}}) {
|
||||
$tally{$key}+=$board{$val};
|
||||
}
|
||||
}
|
||||
foreach my $key (keys %tally) {
|
||||
if (abs($tally{$key}) == 2) {
|
||||
until ($validity eq "valid") {
|
||||
foreach my $val (@{$winning_combos{$key}}) {
|
||||
$validity=&check_occupation($val);
|
||||
if ($validity eq "valid") {
|
||||
$move = $val;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $move;
|
||||
}
|
||||
}
|
||||
return $move;
|
||||
}
|
||||
|
||||
sub player_choice {
|
||||
my $validity = "invalid";
|
||||
my $ans = "";
|
||||
until ($validity eq "valid") {
|
||||
print "WHERE DO YOU MOVE? ";
|
||||
chomp($ans = <STDIN>);
|
||||
$validity=&check_occupation($ans);
|
||||
if ($validity eq "invalid") {print "THAT SQUARE IS OCCUPIED.\n\n"}
|
||||
}
|
||||
$board{$ans}=$player;
|
||||
}
|
||||
|
||||
sub check_occupation {
|
||||
my $space = shift;
|
||||
if ($board{$space}==0) { return "valid" }
|
||||
else {return "invalid"};
|
||||
}
|
||||
|
||||
sub print_board {
|
||||
foreach my $num (1..9) {
|
||||
my $char = &which_char($board{$num});
|
||||
if ($num == 4 || $num == 7) { print "\n---+---+---\n";}
|
||||
print "$char";
|
||||
if ($num % 3 > 0) { print "!" }
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
|
||||
sub which_char {
|
||||
my $val=shift;
|
||||
if ($val == 0) {return " ";}
|
||||
elsif ($val == 1) {return " X ";}
|
||||
else {return " O ";}
|
||||
}
|
||||
|
||||
sub assign_X_and_O {
|
||||
my $ans = shift;
|
||||
if ($ans eq "X") {
|
||||
$player = 1;
|
||||
$computer = -1;
|
||||
$player_goal=3;
|
||||
$computer_goal=-3;
|
||||
}
|
||||
else {
|
||||
$player = -1;
|
||||
$computer = 1;
|
||||
$player_goal=-3;
|
||||
$computer_goal=3;
|
||||
}
|
||||
}
|
||||
|
||||
sub print_intro {
|
||||
print ' ' x 30 . "TIC-TAC-TOE\n";
|
||||
print ' ' x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n";
|
||||
print "THE BOARD IS NUMBERED:\n";
|
||||
print "1 2 3\n4 5 6\n7 8 9\n\n\n";
|
||||
}
|
||||
119
92_Trap/csharp/Program.cs
Normal file
119
92_Trap/csharp/Program.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using System;
|
||||
|
||||
namespace trap_cs
|
||||
{
|
||||
class Program
|
||||
{
|
||||
const int maxGuesses = 6;
|
||||
const int maxNumber = 100;
|
||||
static void Main(string[] args)
|
||||
{
|
||||
int lowGuess = 0;
|
||||
int highGuess = 0;
|
||||
|
||||
Random randomNumberGenerator = new ();
|
||||
|
||||
Print("TRAP");
|
||||
Print("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
|
||||
Print();
|
||||
Print();
|
||||
Print();
|
||||
|
||||
PrintInstructions();
|
||||
|
||||
int numberToGuess = randomNumberGenerator.Next(1, maxNumber);
|
||||
|
||||
for (int nGuess = 1; nGuess <= maxGuesses + 1; nGuess++)
|
||||
{
|
||||
if (nGuess > maxGuesses)
|
||||
{
|
||||
Print(string.Format("SORRY, THAT'S {0} GUESSES. THE NUMBER WAS {1}", maxGuesses, numberToGuess));
|
||||
Print();
|
||||
break;
|
||||
}
|
||||
|
||||
GetGuesses(nGuess, ref lowGuess, ref highGuess);
|
||||
|
||||
if(lowGuess == highGuess && lowGuess == numberToGuess)
|
||||
{
|
||||
Print("YOU GOT IT!!!");
|
||||
Print();
|
||||
Print("TRY AGAIN.");
|
||||
Print();
|
||||
break;
|
||||
}
|
||||
if (highGuess < numberToGuess)
|
||||
{
|
||||
Print("MY NUMBER IS LARGER THAN YOUR TRAP NUMBERS.");
|
||||
}
|
||||
else if (lowGuess > numberToGuess)
|
||||
{
|
||||
Print("MY NUMBER IS SMALLER THAN YOUR TRAP NUMBERS.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("YOU HAVE TRAPPED MY NUMBER.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TRAP
|
||||
// REM - STEVE ULLMAN, 8 - 1 - 72
|
||||
static void PrintInstructions()
|
||||
{
|
||||
Print("INSTRUCTIONS ?");
|
||||
|
||||
char response = Console.ReadKey().KeyChar;
|
||||
if (response == 'Y')
|
||||
{
|
||||
Print(string.Format("I AM THINKING OF A NUMBER BETWEEN 1 AND {0}", maxNumber));
|
||||
Print("TRY TO GUESS MY NUMBER. ON EACH GUESS,");
|
||||
Print("YOU ARE TO ENTER 2 NUMBERS, TRYING TO TRAP");
|
||||
Print("MY NUMBER BETWEEN THE TWO NUMBERS. I WILL");
|
||||
Print("TELL YOU IF YOU HAVE TRAPPED MY NUMBER, IF MY");
|
||||
Print("NUMBER IS LARGER THAN YOUR TWO NUMBERS, OR IF");
|
||||
Print("MY NUMBER IS SMALLER THAN YOUR TWO NUMBERS.");
|
||||
Print("IF YOU WANT TO GUESS ONE SINGLE NUMBER, TYPE");
|
||||
Print("YOUR GUESS FOR BOTH YOUR TRAP NUMBERS.");
|
||||
Print(string.Format("YOU GET {0} GUESSES TO GET MY NUMBER.", maxGuesses));
|
||||
}
|
||||
}
|
||||
static void Print(string stringToPrint)
|
||||
{
|
||||
Console.WriteLine(stringToPrint);
|
||||
}
|
||||
static void Print()
|
||||
{
|
||||
Console.WriteLine();
|
||||
}
|
||||
static void GetGuesses(int nGuess, ref int lowGuess, ref int highGuess)
|
||||
{
|
||||
Print();
|
||||
Print(string.Format("GUESS #{0}", nGuess));
|
||||
|
||||
lowGuess = GetIntFromConsole("Type low guess");
|
||||
highGuess = GetIntFromConsole("Type high guess");
|
||||
|
||||
if(lowGuess > highGuess)
|
||||
{
|
||||
int tempGuess = lowGuess;
|
||||
|
||||
lowGuess = highGuess;
|
||||
highGuess = tempGuess;
|
||||
}
|
||||
}
|
||||
static int GetIntFromConsole(string prompt)
|
||||
{
|
||||
|
||||
Console.Write( prompt + " > ");
|
||||
string intAsString = Console.ReadLine();
|
||||
|
||||
if(int.TryParse(intAsString, out int intValue) ==false)
|
||||
{
|
||||
intValue = 1;
|
||||
}
|
||||
|
||||
return intValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
93_23_Matches/csharp/23matches.csproj
Normal file
9
93_23_Matches/csharp/23matches.csproj
Normal file
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<RootNamespace>_23matches</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
25
93_23_Matches/csharp/23matches.sln
Normal file
25
93_23_Matches/csharp/23matches.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.32002.261
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "23matches", "23matches.csproj", "{9DBE7354-0749-4750-9224-5F9F95C64905}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{9DBE7354-0749-4750-9224-5F9F95C64905}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9DBE7354-0749-4750-9224-5F9F95C64905}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9DBE7354-0749-4750-9224-5F9F95C64905}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9DBE7354-0749-4750-9224-5F9F95C64905}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0A87AE2F-68AC-4354-9C8D-578209D41174}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
129
93_23_Matches/csharp/Goto.Program.cs
Normal file
129
93_23_Matches/csharp/Goto.Program.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace _23matches
|
||||
{
|
||||
class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// Mimics the "goto" version of the original program
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Random random = new Random();
|
||||
StartNewGame:
|
||||
Console.WriteLine("23 MATCHES".PadLeft(31));
|
||||
Console.WriteLine("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY".PadLeft(15));
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("THIS IS A GAME CALLED '23 MATCHES'.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE");
|
||||
Console.WriteLine("MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE");
|
||||
Console.WriteLine("THE LAST MATCH.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Input exit to close the program.");
|
||||
Console.WriteLine("Input cls Screen Clear.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("LET'S FLIP A COIN TO SEE WHO GOES FIRST.");
|
||||
Console.WriteLine("IF IT COMES UP HEADS, I WILL WIN THE TOSS.");
|
||||
Console.WriteLine();
|
||||
StartTheGame:
|
||||
string command;
|
||||
int N = 23;
|
||||
int K = 0;
|
||||
int Q = random.Next(2);
|
||||
if (Q == 1)
|
||||
goto ComputerFirst;
|
||||
else
|
||||
goto PlayerFirst;
|
||||
|
||||
ComputerFirst:
|
||||
Console.WriteLine("HEADS! I WIN! HA! HA!");
|
||||
Console.WriteLine("PREPARE TO LOSE, MEATBALL-NOSE!!");
|
||||
Console.WriteLine();
|
||||
int ain = random.Next(1, 3);
|
||||
Console.WriteLine($"I TAKE {ain} MATCHES");
|
||||
N = N - ain;
|
||||
goto PlayersProceed;
|
||||
|
||||
PlayerFirst:
|
||||
Console.WriteLine("TAILS! YOU GO FIRST. ");
|
||||
Console.WriteLine();
|
||||
goto PlayersSpeak;
|
||||
|
||||
PlayersProceed:
|
||||
Console.WriteLine($"THE NUMBER OF MATCHES IS NOW {N}");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.");
|
||||
Console.WriteLine("HOW MANY DO YOU WISH TO REMOVE ");
|
||||
goto PlayersSpeak;
|
||||
|
||||
PlayersSpeak:
|
||||
command = Console.ReadLine().ToLower();
|
||||
if (command.Equals("exit"))
|
||||
{
|
||||
System.Diagnostics.Process tt = System.Diagnostics.Process.GetProcessById(System.Diagnostics.Process.GetCurrentProcess().Id);
|
||||
tt.Kill();
|
||||
}
|
||||
if (command.Equals("cls"))
|
||||
{
|
||||
Console.Clear();
|
||||
goto PlayersProceed;
|
||||
}
|
||||
try
|
||||
{
|
||||
K = Convert.ToInt32(command);
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
goto PlayerInputError;
|
||||
}
|
||||
if (K > 3 || K <= 0)
|
||||
goto PlayerInputError;
|
||||
N = N - K;
|
||||
Console.WriteLine($"THERE ARE NOW {N} MATCHES REMAINING.");
|
||||
if (N == 4 || N == 3 || N == 2)
|
||||
goto TheComputerSpeaks;
|
||||
else if (N <= 1)
|
||||
goto ThePlayerWins;
|
||||
else
|
||||
goto TheComputerSpeaks;
|
||||
|
||||
TheComputerSpeaks:
|
||||
int Z = 4 - K;
|
||||
Console.WriteLine($"MY TURN ! I REMOVE {Z} MATCHES");
|
||||
N = N - Z;
|
||||
if (N <= 1)
|
||||
goto TheComputerWins;
|
||||
else
|
||||
goto PlayersProceed;
|
||||
|
||||
PlayerInputError:
|
||||
Console.WriteLine("VERY FUNNY! DUMMY!");
|
||||
Console.WriteLine("DO YOU WANT TO PLAY OR GOOF AROUND?");
|
||||
Console.WriteLine("NOW, HOW MANY MATCHES DO YOU WANT ");
|
||||
goto PlayersSpeak;
|
||||
ThePlayerWins:
|
||||
Console.WriteLine("YOU WON, FLOPPY EARS !");
|
||||
Console.WriteLine("THINK YOU'RE PRETTY SMART !");
|
||||
Console.WriteLine("LETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
goto StartTheGame;
|
||||
TheComputerWins:
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("YOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!");
|
||||
Console.WriteLine("HA ! HA ! I BEAT YOU !!!");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("GOOD BYE LOSER!");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
goto StartNewGame;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user