diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/README.md b/00_Alternate_Languages/01_Acey_Ducey/c++/README.md new file mode 100644 index 00000000..119825ff --- /dev/null +++ b/00_Alternate_Languages/01_Acey_Ducey/c++/README.md @@ -0,0 +1,5 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [C++14](https://en.wikipedia.org/wiki/C%2B%2B14) + +The build folder are executables for x86 and x64 systems. Compiled and built using Visual Studio. \ No newline at end of file diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Debug/aceyducey.exe b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Debug/aceyducey.exe new file mode 100644 index 00000000..a68757af Binary files /dev/null and b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Debug/aceyducey.exe differ diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Debug/aceyducey.pdb b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Debug/aceyducey.pdb new file mode 100644 index 00000000..d33fbd15 Binary files /dev/null and b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Debug/aceyducey.pdb differ diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Release/aceyducey.exe b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Release/aceyducey.exe new file mode 100644 index 00000000..6314b08f Binary files /dev/null and b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Release/aceyducey.exe differ diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Release/aceyducey.pdb b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Release/aceyducey.pdb new file mode 100644 index 00000000..569e5818 Binary files /dev/null and b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Release/aceyducey.pdb differ diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Debug/aceyducey.exe b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Debug/aceyducey.exe new file mode 100644 index 00000000..34d54faf Binary files /dev/null and b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Debug/aceyducey.exe differ diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Debug/aceyducey.pdb b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Debug/aceyducey.pdb new file mode 100644 index 00000000..100d8fbc Binary files /dev/null and b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Debug/aceyducey.pdb differ diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Release/aceyducey.exe b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Release/aceyducey.exe new file mode 100644 index 00000000..56571175 Binary files /dev/null and b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Release/aceyducey.exe differ diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Release/aceyducey.pdb b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Release/aceyducey.pdb new file mode 100644 index 00000000..bba54022 Binary files /dev/null and b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Release/aceyducey.pdb differ diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/source/Aceyducey.cpp b/00_Alternate_Languages/01_Acey_Ducey/c++/source/Aceyducey.cpp new file mode 100644 index 00000000..c8cb08d6 --- /dev/null +++ b/00_Alternate_Languages/01_Acey_Ducey/c++/source/Aceyducey.cpp @@ -0,0 +1,123 @@ +#include +#include +#include "Aceyducey.h" + + +int main() +{ + //Setting Seed for the Random Generator + srand((unsigned int)time(NULL)); + bool isPlaying(true); + Money = 100; + WelcomeMessage(); + while (isPlaying) + { + Play(isPlaying); + } + printf("O.K., HOPE YOU HAD FUN!\n"); +} + +void WelcomeMessage() +{ + for (int i = 0; i < 25; i++) + { + printf(" "); + } + printf("ACEY DUCEY CARD GAME\n"); + for (int i = 0; i < 14; i++) + { + printf(" "); + } + printf("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\nACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER \n"); + printf("THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP\nYOU HAVE AN OPTION TO BET OR NOT BET DEPENDING\n"); + printf("ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE\nA VALUE BETWEEN THE FIRST TWO.\n"); + printf("IF YOU DO NOT WANT TO BET, INPUT A 0\n"); +} + +void Play(bool& isPlaying) +{ + short int DealerCards[2]; + int Bet; + short int CurrentCard; + printf("YOU NOW HAVE %d DOLLARS.\n\n", Money); + printf("HERE ARE YOUR NEXT TWO CARDS: \n"); + + //Draw Dealers Cards + DrawCard(DealerCards[0]); + printf("\n"); + DrawCard(DealerCards[1]); + printf("\n\n\n"); + + //Check if Bet is Valid + do { + printf("WHAT IS YOUR BET: "); + std::cin >> Bet; + if (Bet == 0) + { + printf("CHICKEN!!\n\n"); + } + } while (Bet > Money || Bet < 0); + + //Draw Players Card + DrawCard(CurrentCard); + printf("\n"); + if (CurrentCard > DealerCards[0] && CurrentCard < DealerCards[1]) + { + printf("YOU WIN!!!\n"); + Money += Bet; + return; + } + else + { + printf("SORRY, YOU LOSE\n"); + Money -= Bet; + } + if (isGameOver()) + { + printf("TRY AGAIN (YES OR NO)\n\n"); + std::string response; + std::cin >> response; + if (response != "YES") + { + isPlaying = false; + } + Money = 100; + } +} + +bool isGameOver() +{ + if (Money <= 0) + { + printf("\n\n"); + printf("SORRY, FRIEND, BUT YOU BLEW YOUR WAD.\n\n"); + return true; + } + return false; +} + +void DrawCard(short int& Card) +{ + //Basically generate 2 numbers first one is between 2-11 and second one 0-3 + short int RandomNum1 = (rand() % 10) + 2; + short int RandomNum2 = rand() % 4; + Card = RandomNum1 + RandomNum2; + + switch (Card) + { + case 11: + printf("JACK"); + break; + case 12: + printf("QUEEN"); + break; + case 13: + printf("KING"); + break; + case 14: + printf("ACE"); + break; + default: + printf("%d", Card); + } +} \ No newline at end of file diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/source/Aceyducey.h b/00_Alternate_Languages/01_Acey_Ducey/c++/source/Aceyducey.h new file mode 100644 index 00000000..67c56d7e --- /dev/null +++ b/00_Alternate_Languages/01_Acey_Ducey/c++/source/Aceyducey.h @@ -0,0 +1,7 @@ +#pragma once + +void WelcomeMessage(); +void DrawCard(short int& Card); +void Play(bool& isPlaying); +bool isGameOver(); +int Money; \ No newline at end of file diff --git a/00_Alternate_Languages/25_Chief/C/chief.c b/00_Alternate_Languages/25_Chief/C/chief.c new file mode 100644 index 00000000..83cdd8cf --- /dev/null +++ b/00_Alternate_Languages/25_Chief/C/chief.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include + +//check if windows or linux for the clear screen +#ifdef _WIN32 +#define CLEAR "cls" +#else +#define CLEAR "clear" +#endif + +void show_solution(float guess); +float guess_number(float number); +void game(); + +float guess_number(float number){ + float guess; + guess = ((((number - 4) * 5) / 8) * 5 - 3); + return guess; +} + +void game(){ + float number,guess; + char answer[4]; + printf("Think a number\n"); + printf("Then add to it 3 and divide it by 5\n"); + printf("Now multiply by 8, divide by 5 and then add 5\n"); + printf("Finally substract 1\n"); + printf("What is the number you got?(if you got decimals put them ex: 23.6): "); + scanf("%f",&number); + guess = guess_number(number); + printf("The number you thought was %f am I right(Yes or No)?\n",guess); + scanf("%s",answer); + for(int i = 0; i < strlen(answer); i++){ + answer[i] = tolower(answer[i]); + } + if(strcmp(answer,"yes") == 0){ + printf("\nHuh, I Knew I was unbeatable"); + printf("And here is how i did it:\n"); + show_solution(guess); + } + else if (strcmp(answer,"no") == 0){ + printf("HUH!! what was you original number?: "); + scanf("%f",&number); + if(number == guess){ + printf("Huh, I Knew I was unbeatable"); + printf("And here is how i did it:\n"); + show_solution(guess); + } + else{ + printf("If I got it wrong I guess you are smarter than me"); + } + } + else{ + system(CLEAR); + printf("I don't understand what you said\n"); + printf("Please answer with Yes or No\n"); + game(); + } + +} + +void show_solution(float guess){ + printf("%f plus 3 is %f\n",guess,guess + 3); + printf("%f divided by 5 is %f\n",guess + 3,(guess + 3) / 5); + printf("%f multiplied by 8 is %f\n",(guess + 3) / 5,(guess + 3) / 5 * 8); + printf("%f divided by 5 is %f\n",(guess + 3) / 5 * 8,(guess + 3) / 5 * 8 / 5); + printf("%f plus 5 is %f\n",(guess + 3) / 5 * 8 / 5,(guess + 3) / 5 * 8 / 5 + 5); + printf("%f minus 1 is %f\n",(guess + 3) / 5 * 8 / 5 + 5,(guess + 3) / 5 * 8 / 5 + 5 - 1); +} + +void main(){ + char answer[4]; + printf("I am CHIEF NUMBERS FREEK, The GREAT INDIAN MATH GOD.\n"); + printf("Are you ready to take the test you called me out for(Yes or No)? "); + scanf("%s",answer); + for(int i = 0; i < strlen(answer); i++){ + answer[i] = tolower(answer[i]); + } + if(strcmp(answer,"yes") == 0){ + game(); + }else if (strcmp(answer,"no") == 0){ + printf("You are a coward, I will not play with you.%d %s\n",strcmp(answer,"yes"),answer); + } + else{ + system(CLEAR); + printf("I don't understand what you said\n"); + printf("Please answer with Yes or No\n"); + main(); + } +} \ No newline at end of file diff --git a/00_Alternate_Languages/30_Cube/C/cube.c b/00_Alternate_Languages/30_Cube/C/cube.c new file mode 100644 index 00000000..a42b3bca --- /dev/null +++ b/00_Alternate_Languages/30_Cube/C/cube.c @@ -0,0 +1,142 @@ +#include +#include +#include + +//check if windows or linux for the clear screen +#ifdef _WIN32 +#define CLEAR "cls" +#else +#define CLEAR "clear" +#endif + +typedef struct{ + int x; + int y; + int z; +}coords; + +void instuctions(){ + printf("\nThis is a game in which you will be playing against the\n"); + printf("random decisions of the computer. The field of play is a\n"); + printf("cube of side 3. Any of the 27 locations can be designated\n"); + printf("by inputing three numbers such as 2,3,1. At the start,\n"); + printf("you are automatically at location 1,1,1. The object of\n"); + printf("the game is to get to location 3,3,3. One minor detail:\n"); + printf("the computer will pick, at random, 5 locations at which\n"); + printf("it will plant land mines. If you hit one of these locations\n"); + printf("you lose. One other detail: You may move only one space\n"); + printf("in one direction each move. For example: From 1,1,2 you\n"); + printf("may move to 2,1,2 or 1,1,3. You may not change\n"); + printf("two of the numbers on the same move. If you make an illegal\n"); + printf("move, you lose and the computer takes the money you may\n"); + printf("have bet on that round.\n\n"); + printf("When stating the amount of a wager, printf only the number\n"); + printf("of dollars (example: 250) you are automatically started with\n"); + printf("500 dollars in your account.\n\n"); + printf("Good luck!\n"); +} + +void game(int money){ + coords player,playerold,mines[5]; + int wager,account = money; + char choice; + if(money == 0){ + printf("You have no money left. See ya next time.\n"); + exit(0); + } + player.x = 1; + player.y = 1; + player.z = 1; + + printf("You have $%d in your account.\n",account); + printf("How much do you want to wager? "); + scanf("%d",&wager); + while(wager > account){ + system(CLEAR); + printf("You do not have that much money in your account.\n"); + printf("How much do you want to wager? "); + scanf("%d",&wager); + } + srand(time(NULL)); + for(int i=0;i<5;i++){ + mines[i].x = rand()%3+1; + mines[i].y = rand()%3+1; + mines[i].z = rand()%3+1; + if(mines[i].x == 3 && mines[i].y == 3 && mines[i].z == 3){ + i--; + } + } + while(player.x != 3 || player.y != 3 || player.z != 3){ + printf("You are at location %d.%d.%d\n",player.x,player.y,player.z); + if(player.x == 1 && player.y == 1 && player.z == 1) + printf("Enter new location(use commas like 1,1,2 or else the program will break...): "); + else printf("Enter new location: "); + playerold.x = player.x; + playerold.y = player.y; + playerold.z = player.z; + scanf("%d,%d,%d",&player.x,&player.y,&player.z); + if(((player.x + player.y + player.z) > (playerold.x + playerold.y + playerold.z + 1)) || ((player.x + player.y + player.z) < (playerold.x + playerold.y + playerold.z -1))){ + system(CLEAR); + printf("Illegal move!\n"); + printf("You lose $%d.\n",wager); + game(account -= wager); + break; + } + if(player.x < 1 || player.x > 3 || player.y < 1 || player.y > 3 || player.z < 1 || player.z > 3){ + system(CLEAR); + printf("Illegal move. You lose!\n"); + game(account -= wager); + break; + } + for(int i=0;i<5;i++){ + if(player.x == mines[i].x && player.y == mines[i].y && player.z == mines[i].z){ + system(CLEAR); + printf("You hit a mine!\n"); + printf("You lose $%d.\n",wager); + game(account -= wager); + exit(0); + } + } + if(account == 0){ + system(CLEAR); + printf("You have no money left!\n"); + printf("Game over!\n"); + exit(0); + } + } + if(player.x == 3 && player.y == 3 && player.z == 3){ + system(CLEAR); + printf("You made it to the end. You win!\n"); + game(account += wager); + exit(0); + } +} + +void init(){ + int account = 500; + char choice; + + printf("Welcome to the game of Cube!\n"); + printf("wanna see the instructions? (y/n): "); + scanf("%c",&choice); + if(choice == 'y'){ + system(CLEAR); + instuctions(); + } + else if (choice == 'n'){ + system(CLEAR); + printf("Ok, let's play!\n"); + } + else{ + system(CLEAR); + printf("Invalid choice. Try again...\n"); + init(); + exit(0); + } + game(account); + exit(0); +} + +void main(){ + init(); +} \ No newline at end of file diff --git a/00_Alternate_Languages/33_Dice/C/dice.c b/00_Alternate_Languages/33_Dice/C/dice.c new file mode 100644 index 00000000..1ab77fca --- /dev/null +++ b/00_Alternate_Languages/33_Dice/C/dice.c @@ -0,0 +1,26 @@ +#include +#include +#include + +float percent(int number, int total){ + float percent; + percent = (float)number / (float)total * 100; + return percent; +} + +int main(){ + int dice1,dice2,times,rolls[13] = {0}; + srand(time(NULL)); + printf("This program simulates the rolling of a pair of dice\n"); + printf("How many times do you want to roll the dice?(Higher the number longer the waiting time): "); + scanf("%d",×); + for(int i = 0; i < times; i++){ + dice1 = rand() % 6 + 1; + dice2 = rand() % 6 + 1; + rolls[dice1 + dice2]+=1; + } + printf("The number of times each sum was rolled is:\n"); + for(int i = 2; i <= 12; i++){ + printf("%d: rolled %d times, or %f%c of the times\n",i,rolls[i],percent(rolls[i],times),(char)37); + } +} \ No newline at end of file diff --git a/00_Alternate_Languages/44_Hangman/C/dictionary.txt b/00_Alternate_Languages/44_Hangman/C/dictionary.txt new file mode 100644 index 00000000..ddf7a59f --- /dev/null +++ b/00_Alternate_Languages/44_Hangman/C/dictionary.txt @@ -0,0 +1,100 @@ +harm +retire +principle +tile +biology +show +reporter +profound +prestige +hardship +supplementary +abundant +firm +preparation +mother +welfare +broadcast +virgin +bloody +shaft +bird +buy +passion +south +slant +hesitate +leak +ride +contempt +banner +hurt +disaster +ranch +damage +conceive +environmental +outside +apathy +temple +arrange +hour +tone +intelligence +soup +bishop +fool +chase +snub +develop +domination +cry +distant +poem +implication +rally +assertive +anxiety +home +bear +execute +century +solo +cathedral +terminal +integration +mastermind +pen +X-ray +match +ceremony +stop +linger +slow +desert +superior +tender +debt +criticism +rehabilitation +finish +jest +scream +piece +mask +approach +sequence +negotiation +to +traffic +midnight +aspect +dull +concession +citizen +conception +instrument +compartment +responsibility +resist +withdraw \ No newline at end of file diff --git a/00_Alternate_Languages/44_Hangman/C/main.c b/00_Alternate_Languages/44_Hangman/C/main.c new file mode 100644 index 00000000..5ad8e43d --- /dev/null +++ b/00_Alternate_Languages/44_Hangman/C/main.c @@ -0,0 +1,137 @@ +#include +#include +#include +#include +#define MAX_WORDS 100 + +//check if windows or linux for the clear screen +#ifdef _WIN32 +#define CLEAR "cls" +#else +#define CLEAR "clear" +#endif + +/** + * @brief Prints the stage of the hangman based on the number of wrong guesses. + * + * @param stage Hangman stage. + */ +void print_hangman(int stage){ + switch (stage){ + case 0: + printf("----------\n"); + printf("| |\n"); + printf("|\n"); + printf("|\n"); + printf("|\n"); + printf("|\n"); + break; + case 1: + printf("----------\n"); + printf("| |\n"); + printf("| O\n"); + printf("| |\n"); + printf("|\n"); + printf("|\n"); + break; + case 2: + printf("----------\n"); + printf("| |\n"); + printf("| o\n"); + printf("| /|\n"); + printf("|\n"); + printf("|\n"); + break; + case 3: + printf("----------\n"); + printf("| |\n"); + printf("| o\n"); + printf("| /|\\\n"); + printf("|\n"); + printf("|\n"); + break; + case 4: + printf("----------\n"); + printf("| |\n"); + printf("| o\n"); + printf("| /|\\\n"); + printf("| /\n"); + printf("|\n"); + break; + case 5: + printf("----------\n"); + printf("| |\n"); + printf("| o\n"); + printf("| /|\\\n"); + printf("| / \\\n"); + printf("|\n"); + break; + default: + break; + } +} + +/** + * @brief Picks and return a random word from the dictionary. + * + * @return Random word + */ +char* random_word_picker(){ + //generate a random english word + char* word = malloc(sizeof(char) * 100); + FILE* fp = fopen("dictionary.txt", "r"); + srand(time(NULL)); + if (fp == NULL){ + printf("Error opening dictionary.txt\n"); + exit(1); + } + int random_number = rand() % MAX_WORDS; + for (int j = 0; j < random_number; j++){ + fscanf(fp, "%s", word); + } + fclose(fp); + return word; +} + + + + +void main(void){ + char* word = malloc(sizeof(char) * 100); + word = random_word_picker(); + char* hidden_word = malloc(sizeof(char) * 100); + for (int i = 0; i < strlen(word); i++){ + hidden_word[i] = '_'; + } + hidden_word[strlen(word)] = '\0'; + int stage = 0; + int wrong_guesses = 0; + int correct_guesses = 0; + char* guess = malloc(sizeof(char) * 100); + while (wrong_guesses < 6 && correct_guesses < strlen(word)){ + CLEAR; + print_hangman(stage); + printf("%s\n", hidden_word); + printf("Enter a guess: "); + scanf("%s", guess); + for (int i = 0; i < strlen(word); i++){ + if (strcmp(guess,word) == 0){ + correct_guesses = strlen(word); + } + else if (guess[0] == word[i]){ + hidden_word[i] = guess[0]; + correct_guesses++; + } + } + if (strchr(word, guess[0]) == NULL){ + wrong_guesses++; + } + stage = wrong_guesses; + } + if (wrong_guesses == 6){ + printf("You lose! The word was %s\n", word); + } + else { + printf("You win!\n"); + } +} \ No newline at end of file diff --git a/00_Alternate_Languages/README.md b/00_Alternate_Languages/README.md index f7c55f95..0cbe947e 100644 --- a/00_Alternate_Languages/README.md +++ b/00_Alternate_Languages/README.md @@ -1,9 +1,15 @@ #### Alternate Languages -This folder contains implementations of each program in alternate languages which are _not_ one of the agreed upon 10 languages, intended to meet these three criteria: +This folder contains implementations of each program in alternate languages which are _not_ one of the agreed upon 10 languages. + +Implementations here are NOT bound to these three criteria: 1. Popular (by TIOBE index) 2. Memory safe 3. Generally considered a 'scripting' language -We welcome additional ports in whatever language you prefer, but these additional ports are for educational purposes only, and do not count towards the donation total at the end of the project. \ No newline at end of file +So for example, (here only) C or PASCAL are allowed. Please still remain faithful to original look-and-feel (console applications). +Try to keep your code portable (unless it is not possible, and then be very explicit about this limitation in your +README and your folder naming). + +We welcome additional ports in whatever language you prefer, but these additional ports are for educational purposes only, and do not count towards the donation total at the end of the project. diff --git a/30_Cube/README.md b/30_Cube/README.md index f99366a2..c220c8d4 100644 --- a/30_Cube/README.md +++ b/30_Cube/README.md @@ -16,3 +16,27 @@ http://www.vintage-basic.net/games.html #### Porting Notes (please note any difficulties or challenges in porting here) + +##### Randomization Logic + +The BASIC code uses an interesting technique for choosing the random coordinates for the mines. The first coordinate is +chosen like this: + +```basic +380 LET A=INT(3*(RND(X))) +390 IF A<>0 THEN 410 +400 LET A=3 +``` + +where line 410 is the start of a similar block of code for the next coordinate. The behaviour of `RND(X)` depends on the +value of `X`. If `X` is greater than zero then it returns a random value between 0 and 1. If `X` is zero it returns the +last random value generated, or 0 if no value has yet been generated. + +If `X` is 1, therefore, the first line above set `A` to 0, 1, or 2. The next 2 lines replace a 0 with a 3. The +replacement values varies for the different coordinates with the result that the random selection is biased towards a +specific set of points. If `X` is 0, the `RND` calls all return 0, so the coordinates are the known. It appears that +this technique was probably used to allow testing the game with a well-known set of locations for the mines. However, in +the code as it comes to us, the value of `X` is never set and is thus 0, so the mine locations are never randomized. + +The C# port implements the biased randomized mine locations, as seems to be the original intent, but includes a +command-line switch to enable the deterministic execution as well. diff --git a/30_Cube/csharp/Cube.csproj b/30_Cube/csharp/Cube.csproj index d3fe4757..3870320c 100644 --- a/30_Cube/csharp/Cube.csproj +++ b/30_Cube/csharp/Cube.csproj @@ -6,4 +6,12 @@ enable enable + + + + + + + + diff --git a/30_Cube/csharp/Game.cs b/30_Cube/csharp/Game.cs new file mode 100644 index 00000000..a06ec565 --- /dev/null +++ b/30_Cube/csharp/Game.cs @@ -0,0 +1,104 @@ +namespace Cube; + +internal class Game +{ + private const int _initialBalance = 500; + private readonly IEnumerable<(int, int, int)> _seeds = new List<(int, int, int)> + { + (3, 2, 3), (1, 3, 3), (3, 3, 2), (3, 2, 3), (3, 1, 3) + }; + private readonly (float, float, float) _startLocation = (1, 1, 1); + private readonly (float, float, float) _goalLocation = (3, 3, 3); + + private readonly IReadWrite _io; + private readonly IRandom _random; + + public Game(IReadWrite io, IRandom random) + { + _io = io; + _random = random; + } + + public void Play() + { + _io.Write(Streams.Introduction); + + if (_io.ReadNumber("") != 0) + { + _io.Write(Streams.Instructions); + } + + PlaySeries(_initialBalance); + + _io.Write(Streams.Goodbye); + } + + private void PlaySeries(float balance) + { + while (true) + { + var wager = _io.ReadWager(balance); + + var gameWon = PlayGame(); + + if (wager.HasValue) + { + balance = gameWon ? (balance + wager.Value) : (balance - wager.Value); + if (balance <= 0) + { + _io.Write(Streams.Bust); + return; + } + _io.WriteLine(Formats.Balance, balance); + } + + if (_io.ReadNumber(Prompts.TryAgain) != 1) { return; } + } + } + + private bool PlayGame() + { + var mineLocations = _seeds.Select(seed => _random.NextLocation(seed)).ToHashSet(); + var currentLocation = _startLocation; + var prompt = Prompts.YourMove; + + while (true) + { + var newLocation = _io.Read3Numbers(prompt); + + if (!MoveIsLegal(currentLocation, newLocation)) { return Lose(Streams.IllegalMove); } + + currentLocation = newLocation; + + if (currentLocation == _goalLocation) { return Win(Streams.Congratulations); } + + if (mineLocations.Contains(currentLocation)) { return Lose(Streams.Bang); } + + prompt = Prompts.NextMove; + } + } + + private bool Lose(Stream text) + { + _io.Write(text); + return false; + } + + private bool Win(Stream text) + { + _io.Write(text); + return true; + } + + private bool MoveIsLegal((float, float, float) from, (float, float, float) to) + => (to.Item1 - from.Item1, to.Item2 - from.Item2, to.Item3 - from.Item3) switch + { + ( > 1, _, _) => false, + (_, > 1, _) => false, + (_, _, > 1) => false, + (1, 1, _) => false, + (1, _, 1) => false, + (_, 1, 1) => false, + _ => true + }; +} diff --git a/30_Cube/csharp/IOExtensions.cs b/30_Cube/csharp/IOExtensions.cs new file mode 100644 index 00000000..14f2a85e --- /dev/null +++ b/30_Cube/csharp/IOExtensions.cs @@ -0,0 +1,20 @@ +namespace Cube; + +internal static class IOExtensions +{ + internal static float? ReadWager(this IReadWrite io, float balance) + { + io.Write(Streams.Wager); + if (io.ReadNumber("") == 0) { return null; } + + var prompt = Prompts.HowMuch; + + while(true) + { + var wager = io.ReadNumber(prompt); + if (wager <= balance) { return wager; } + + prompt = Prompts.BetAgain; + } + } +} diff --git a/30_Cube/csharp/Program.cs b/30_Cube/csharp/Program.cs new file mode 100644 index 00000000..803a569a --- /dev/null +++ b/30_Cube/csharp/Program.cs @@ -0,0 +1,10 @@ +global using Games.Common.IO; +global using Games.Common.Randomness; + +global using static Cube.Resources.Resource; + +using Cube; + +IRandom random = args.Contains("--non-random") ? new ZerosGenerator() : new RandomNumberGenerator(); + +new Game(new ConsoleIO(), random).Play(); diff --git a/30_Cube/csharp/README.md b/30_Cube/csharp/README.md index 4daabb5c..7bea3d88 100644 --- a/30_Cube/csharp/README.md +++ b/30_Cube/csharp/README.md @@ -1,3 +1,12 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/) + +#### Execution + +As noted in the main Readme file, the randomization code in the BASIC program has a switch (the variable `X`) that +allows the game to be run in a deterministic (non-random) mode. + +Running the C# port without command-line parameters will play the game with random mine locations. + +Running the port with a `--non-random` command-line switch will run the game with non-random mine locations. diff --git a/30_Cube/csharp/RandomExtensions.cs b/30_Cube/csharp/RandomExtensions.cs new file mode 100644 index 00000000..ac05108e --- /dev/null +++ b/30_Cube/csharp/RandomExtensions.cs @@ -0,0 +1,14 @@ +namespace Cube; + +internal static class RandomExtensions +{ + internal static (float, float, float) NextLocation(this IRandom random, (int, int, int) bias) + => (random.NextCoordinate(bias.Item1), random.NextCoordinate(bias.Item2), random.NextCoordinate(bias.Item3)); + + private static float NextCoordinate(this IRandom random, int bias) + { + var value = random.Next(3); + if (value == 0) { value = bias; } + return value; + } +} \ No newline at end of file diff --git a/30_Cube/csharp/Resources/Balance.txt b/30_Cube/csharp/Resources/Balance.txt new file mode 100644 index 00000000..1f6adffd --- /dev/null +++ b/30_Cube/csharp/Resources/Balance.txt @@ -0,0 +1 @@ +You now have {0} dollars. \ No newline at end of file diff --git a/30_Cube/csharp/Resources/Bang.txt b/30_Cube/csharp/Resources/Bang.txt new file mode 100644 index 00000000..1d924788 --- /dev/null +++ b/30_Cube/csharp/Resources/Bang.txt @@ -0,0 +1,4 @@ +******BANG****** +You lose! + + diff --git a/30_Cube/csharp/Resources/BetAgain.txt b/30_Cube/csharp/Resources/BetAgain.txt new file mode 100644 index 00000000..47c9fb8c --- /dev/null +++ b/30_Cube/csharp/Resources/BetAgain.txt @@ -0,0 +1 @@ +Tried to fool me; bet again \ No newline at end of file diff --git a/30_Cube/csharp/Resources/Bust.txt b/30_Cube/csharp/Resources/Bust.txt new file mode 100644 index 00000000..cd753d98 --- /dev/null +++ b/30_Cube/csharp/Resources/Bust.txt @@ -0,0 +1 @@ +You bust. diff --git a/30_Cube/csharp/Resources/Congratulations.txt b/30_Cube/csharp/Resources/Congratulations.txt new file mode 100644 index 00000000..3319c833 --- /dev/null +++ b/30_Cube/csharp/Resources/Congratulations.txt @@ -0,0 +1 @@ +Congratulations! diff --git a/30_Cube/csharp/Resources/Goodbye.txt b/30_Cube/csharp/Resources/Goodbye.txt new file mode 100644 index 00000000..0aa64192 --- /dev/null +++ b/30_Cube/csharp/Resources/Goodbye.txt @@ -0,0 +1,3 @@ +Tough luck! + +Goodbye. diff --git a/30_Cube/csharp/Resources/HowMuch.txt b/30_Cube/csharp/Resources/HowMuch.txt new file mode 100644 index 00000000..ff2bea20 --- /dev/null +++ b/30_Cube/csharp/Resources/HowMuch.txt @@ -0,0 +1 @@ +How much \ No newline at end of file diff --git a/30_Cube/csharp/Resources/IllegalMove.txt b/30_Cube/csharp/Resources/IllegalMove.txt new file mode 100644 index 00000000..ca8f96ba --- /dev/null +++ b/30_Cube/csharp/Resources/IllegalMove.txt @@ -0,0 +1,2 @@ + +Illegal move. You lose. diff --git a/30_Cube/csharp/Resources/Instructions.txt b/30_Cube/csharp/Resources/Instructions.txt new file mode 100644 index 00000000..e82ae51e --- /dev/null +++ b/30_Cube/csharp/Resources/Instructions.txt @@ -0,0 +1,24 @@ +This is a game in which you will be playing against the +random decision od the computer. The field of play is a +cube of side 3. Any of the 27 locations can be designated +by inputing three numbers such as 2,3,1. At the start, +you are automatically at location 1,1,1. The object of +the game is to get to location 3,3,3. One minor detail: +the computer will pick, at random, 5 locations at which +it will play land mines. If you hit one of these locations +you lose. One other details: you may move only one space +in one direction each move. For example: from 1,1,2 you +may move to 2,1,2 or 1,1,3. You may not change +two of the numbers on the same move. If you make an illegal +move, you lose and the computer takes the money you may +have bet on that round. + + +All Yes or No questions will be answered by a 1 for Yes +or a 0 (zero) for no. + +When stating the amount of a wager, print only the number +of dollars (example: 250) You are automatically started with +500 dollars in your account. + +Good luck! diff --git a/30_Cube/csharp/Resources/Introduction.txt b/30_Cube/csharp/Resources/Introduction.txt new file mode 100644 index 00000000..6299d19b --- /dev/null +++ b/30_Cube/csharp/Resources/Introduction.txt @@ -0,0 +1,6 @@ + Cube + Creative Computing Morristown, New Jersey + + + +Do you want to see the instructions? (Yes--1,No--0) diff --git a/30_Cube/csharp/Resources/NextMove.txt b/30_Cube/csharp/Resources/NextMove.txt new file mode 100644 index 00000000..4cbe5496 --- /dev/null +++ b/30_Cube/csharp/Resources/NextMove.txt @@ -0,0 +1 @@ +Next move: \ No newline at end of file diff --git a/30_Cube/csharp/Resources/Resource.cs b/30_Cube/csharp/Resources/Resource.cs new file mode 100644 index 00000000..c3ed10c7 --- /dev/null +++ b/30_Cube/csharp/Resources/Resource.cs @@ -0,0 +1,44 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace Cube.Resources; + +internal static class Resource +{ + internal static class Streams + { + public static Stream Introduction => GetStream(); + public static Stream Instructions => GetStream(); + public static Stream Wager => GetStream(); + public static Stream IllegalMove => GetStream(); + public static Stream Bang => GetStream(); + public static Stream Bust => GetStream(); + public static Stream Congratulations => GetStream(); + public static Stream Goodbye => GetStream(); + } + + internal static class Prompts + { + public static string HowMuch => GetString(); + public static string BetAgain => GetString(); + public static string YourMove => GetString(); + public static string NextMove => GetString(); + public static string TryAgain => GetString(); + } + + internal static class Formats + { + public static string Balance => GetString(); + } + + private static string GetString([CallerMemberName] string? name = null) + { + using var stream = GetStream(name); + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + private static Stream GetStream([CallerMemberName] string? name = null) => + Assembly.GetExecutingAssembly().GetManifestResourceStream($"{typeof(Resource).Namespace}.{name}.txt") + ?? throw new Exception($"Could not find embedded resource stream '{name}'."); +} \ No newline at end of file diff --git a/30_Cube/csharp/Resources/TryAgain.txt b/30_Cube/csharp/Resources/TryAgain.txt new file mode 100644 index 00000000..9ccf358a --- /dev/null +++ b/30_Cube/csharp/Resources/TryAgain.txt @@ -0,0 +1 @@ +Do you want to try again \ No newline at end of file diff --git a/30_Cube/csharp/Resources/Wager.txt b/30_Cube/csharp/Resources/Wager.txt new file mode 100644 index 00000000..04720a7a --- /dev/null +++ b/30_Cube/csharp/Resources/Wager.txt @@ -0,0 +1 @@ +Want to make a wager diff --git a/30_Cube/csharp/Resources/YourMove.txt b/30_Cube/csharp/Resources/YourMove.txt new file mode 100644 index 00000000..5ea0c544 --- /dev/null +++ b/30_Cube/csharp/Resources/YourMove.txt @@ -0,0 +1,2 @@ + +It's your move: \ No newline at end of file diff --git a/30_Cube/csharp/ZerosGenerator.cs b/30_Cube/csharp/ZerosGenerator.cs new file mode 100644 index 00000000..4490f606 --- /dev/null +++ b/30_Cube/csharp/ZerosGenerator.cs @@ -0,0 +1,10 @@ +namespace Cube; + +internal class ZerosGenerator : IRandom +{ + public float NextFloat() => 0; + + public float PreviousFloat() => 0; + + public void Reseed(int seed) { } +} \ No newline at end of file diff --git a/32_Diamond/csharp/Diamond.csproj b/32_Diamond/csharp/Diamond.csproj index d3fe4757..3870320c 100644 --- a/32_Diamond/csharp/Diamond.csproj +++ b/32_Diamond/csharp/Diamond.csproj @@ -6,4 +6,12 @@ enable enable + + + + + + + + diff --git a/32_Diamond/csharp/Pattern.cs b/32_Diamond/csharp/Pattern.cs new file mode 100644 index 00000000..ce6d493a --- /dev/null +++ b/32_Diamond/csharp/Pattern.cs @@ -0,0 +1,57 @@ +using System.Text; +using static Diamond.Resources.Resource; + +namespace Diamond; + +internal class Pattern +{ + private readonly IReadWrite _io; + + public Pattern(IReadWrite io) + { + _io = io; + io.Write(Streams.Introduction); + } + + public void Draw() + { + var diamondSize = _io.ReadNumber(Prompts.TypeNumber); + _io.WriteLine(); + + var diamondCount = (int)(60 / diamondSize); + + var diamondLines = new List(GetDiamondLines(diamondSize)).AsReadOnly(); + + for (int patternRow = 0; patternRow < diamondCount; patternRow++) + { + for (int diamondRow = 0; diamondRow < diamondLines.Count; diamondRow++) + { + var line = new StringBuilder(); + for (int patternColumn = 0; patternColumn < diamondCount; patternColumn++) + { + line.PadToLength((int)(patternColumn * diamondSize)).Append(diamondLines[diamondRow]); + } + _io.WriteLine(line); + } + } + } + + public static IEnumerable GetDiamondLines(float size) + { + for (var i = 1; i <= size; i += 2) + { + yield return GetLine(i); + } + + for (var i = size - 2; i >= 1; i -= 2) + { + yield return GetLine(i); + } + + string GetLine(float i) => + string.Concat( + new string(' ', (int)(size - i) / 2), + new string('C', Math.Min((int)i, 2)), + new string('!', Math.Max(0, (int)i - 2))); + } +} diff --git a/32_Diamond/csharp/Program.cs b/32_Diamond/csharp/Program.cs new file mode 100644 index 00000000..46dd67c5 --- /dev/null +++ b/32_Diamond/csharp/Program.cs @@ -0,0 +1,4 @@ +global using Games.Common.IO; +using Diamond; + +new Pattern(new ConsoleIO()).Draw(); diff --git a/32_Diamond/csharp/Resources/Introduction.txt b/32_Diamond/csharp/Resources/Introduction.txt new file mode 100644 index 00000000..e983fc9f --- /dev/null +++ b/32_Diamond/csharp/Resources/Introduction.txt @@ -0,0 +1,5 @@ + Diamond + Creative Computing Morristown, New Jersey + + + diff --git a/32_Diamond/csharp/Resources/Resource.cs b/32_Diamond/csharp/Resources/Resource.cs new file mode 100644 index 00000000..d7051f5c --- /dev/null +++ b/32_Diamond/csharp/Resources/Resource.cs @@ -0,0 +1,29 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace Diamond.Resources; + +internal static class Resource +{ + internal static class Streams + { + public static Stream Introduction => GetStream(); + } + + internal static class Prompts + { + public static string TypeNumber => GetString(); + } + + private static string GetString([CallerMemberName] string? name = null) + { + using var stream = GetStream(name); + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + + private static Stream GetStream([CallerMemberName] string? name = null) => + Assembly.GetExecutingAssembly().GetManifestResourceStream($"{typeof(Resource).Namespace}.{name}.txt") + ?? throw new Exception($"Could not find embedded resource stream '{name}'."); +} \ No newline at end of file diff --git a/32_Diamond/csharp/Resources/Rules.txt b/32_Diamond/csharp/Resources/Rules.txt new file mode 100644 index 00000000..2fd9177f --- /dev/null +++ b/32_Diamond/csharp/Resources/Rules.txt @@ -0,0 +1,22 @@ +Chomp is for 1 or more players (humans only). + +Here's how a board looks (this one is 5 by 7): + + 1 2 3 4 5 6 7 8 9 + 1 P * * * * * * + 2 * * * * * * * + 3 * * * * * * * + 4 * * * * * * * + 5 * * * * * * * + + +The board is a big cookie - R rows high and C columns +wide. You input R and C at the start. In the upper left +corner of the cookie is a poison square (P). The one who +chomps the poison square loses. To take a chomp, type the +row and column of one of the squares on the cookie. +All of the squares below and to the right of that square +(including that square, too) disappear -- Chomp!! +No fair chomping on squares that have already been chomped, +or that are outside the original dimensions of the cookie. + diff --git a/32_Diamond/csharp/Resources/TypeNumber.txt b/32_Diamond/csharp/Resources/TypeNumber.txt new file mode 100644 index 00000000..d74d21fd --- /dev/null +++ b/32_Diamond/csharp/Resources/TypeNumber.txt @@ -0,0 +1,2 @@ +For a pretty diamond pattern, +type in an odd number between 5 and 21 \ No newline at end of file diff --git a/32_Diamond/csharp/StringBuilderExtensions.cs b/32_Diamond/csharp/StringBuilderExtensions.cs new file mode 100644 index 00000000..3ada4146 --- /dev/null +++ b/32_Diamond/csharp/StringBuilderExtensions.cs @@ -0,0 +1,9 @@ +using System.Text; + +namespace Diamond; + +internal static class StringBuilderExtensions +{ + internal static StringBuilder PadToLength(this StringBuilder builder, int length) => + builder.Append(' ', length - builder.Length); +} \ No newline at end of file diff --git a/34_Digits/csharp/Digits.csproj b/34_Digits/csharp/Digits.csproj index d3fe4757..3870320c 100644 --- a/34_Digits/csharp/Digits.csproj +++ b/34_Digits/csharp/Digits.csproj @@ -6,4 +6,12 @@ enable enable + + + + + + + + diff --git a/34_Digits/csharp/Game.cs b/34_Digits/csharp/Game.cs new file mode 100644 index 00000000..19f225b3 --- /dev/null +++ b/34_Digits/csharp/Game.cs @@ -0,0 +1,80 @@ +namespace Digits; + +internal class GameSeries +{ + private readonly IReadOnlyList _weights = new List { 0, 1, 3 }.AsReadOnly(); + + private readonly IReadWrite _io; + private readonly IRandom _random; + + public GameSeries(IReadWrite io, IRandom random) + { + _io = io; + _random = random; + } + + internal void Play() + { + _io.Write(Streams.Introduction); + + if (_io.ReadNumber(Prompts.ForInstructions) != 0) + { + _io.Write(Streams.Instructions); + } + + do + { + new Game(_io, _random).Play(); + } while (_io.ReadNumber(Prompts.WantToTryAgain) == 1); + + _io.Write(Streams.Thanks); + } +} + +internal class Game +{ + private readonly IReadWrite _io; + private readonly Guesser _guesser; + + public Game(IReadWrite io, IRandom random) + { + _io = io; + _guesser = new Guesser(random); + } + + public void Play() + { + var correctGuesses = 0; + + for (int round = 0; round < 3; round++) + { + var digits = _io.Read10Digits(Prompts.TenNumbers, Streams.TryAgain); + + correctGuesses = GuessDigits(digits, correctGuesses); + } + + _io.Write(correctGuesses switch + { + < 10 => Streams.YouWin, + 10 => Streams.ItsATie, + > 10 => Streams.IWin + }); + } + + private int GuessDigits(IEnumerable digits, int correctGuesses) + { + _io.Write(Streams.Headings); + + foreach (var digit in digits) + { + var guess = _guesser.GuessNextDigit(); + if (guess == digit) { correctGuesses++; } + + _io.WriteLine(Formats.GuessResult, guess, digit, guess == digit ? "Right" : "Wrong", correctGuesses); + + _guesser.ObserveActualDigit(digit); + } + + return correctGuesses; + } +} diff --git a/34_Digits/csharp/Guesser.cs b/34_Digits/csharp/Guesser.cs new file mode 100644 index 00000000..9cda59e9 --- /dev/null +++ b/34_Digits/csharp/Guesser.cs @@ -0,0 +1,32 @@ +namespace Digits; + +internal class Guesser +{ + private readonly Memory _matrices = new(); + private readonly IRandom _random; + + public Guesser(IRandom random) + { + _random = random; + } + + public int GuessNextDigit() + { + var currentSum = 0; + var guess = 0; + + for (int i = 0; i < 3; i++) + { + var sum = _matrices.GetWeightedSum(i); + if (sum > currentSum || _random.NextFloat() >= 0.5) + { + currentSum = sum; + guess = i; + } + } + + return guess; + } + + public void ObserveActualDigit(int digit) => _matrices.ObserveDigit(digit); +} diff --git a/34_Digits/csharp/IOExtensions.cs b/34_Digits/csharp/IOExtensions.cs new file mode 100644 index 00000000..cd6af7ad --- /dev/null +++ b/34_Digits/csharp/IOExtensions.cs @@ -0,0 +1,20 @@ +namespace Digits; + +internal static class IOExtensions +{ + internal static IEnumerable Read10Digits(this IReadWrite io, string prompt, Stream retryText) + { + while (true) + { + var numbers = new float[10]; + io.ReadNumbers(prompt, numbers); + + if (numbers.All(n => n == 0 || n == 1 || n == 2)) + { + return numbers.Select(n => (int)n); + } + + io.Write(retryText); + } + } +} \ No newline at end of file diff --git a/34_Digits/csharp/Matrix.cs b/34_Digits/csharp/Matrix.cs new file mode 100644 index 00000000..c07b4553 --- /dev/null +++ b/34_Digits/csharp/Matrix.cs @@ -0,0 +1,27 @@ +namespace Digits; + +internal class Matrix +{ + private readonly int _weight; + private readonly int[,] _values; + + public Matrix(int width, int weight, Func seedFactory) + { + _weight = weight; + _values = new int[width, 3]; + + for (int i = 0; i < width; i++) + for (int j = 0; j < 3; j++) + { + _values[i, j] = seedFactory.Invoke(i, j); + } + + Index = width - 1; + } + + public int Index { get; set; } + + public int GetWeightedValue(int row) => _weight * _values[Index, row]; + + public int IncrementValue(int row) => _values[Index, row]++; +} \ No newline at end of file diff --git a/34_Digits/csharp/Memory.cs b/34_Digits/csharp/Memory.cs new file mode 100644 index 00000000..a3023351 --- /dev/null +++ b/34_Digits/csharp/Memory.cs @@ -0,0 +1,30 @@ +namespace Digits; + +public class Memory +{ + private readonly Matrix[] _matrices; + + public Memory() + { + _matrices = new[] + { + new Matrix(27, 3, (_, _) => 1), + new Matrix(9, 1, (i, j) => i == 4 * j ? 2 : 3), + new Matrix(3, 0, (_, _) => 9) + }; + } + + public int GetWeightedSum(int row) => _matrices.Select(m => m.GetWeightedValue(row)).Sum(); + + public void ObserveDigit(int digit) + { + for (int i = 0; i < 3; i++) + { + _matrices[i].IncrementValue(digit); + } + + _matrices[0].Index = _matrices[0].Index % 9 * 3 + digit; + _matrices[1].Index = _matrices[0].Index % 9; + _matrices[2].Index = digit; + } +} \ No newline at end of file diff --git a/34_Digits/csharp/Program.cs b/34_Digits/csharp/Program.cs new file mode 100644 index 00000000..1b5dd2e0 --- /dev/null +++ b/34_Digits/csharp/Program.cs @@ -0,0 +1,6 @@ +global using Digits; +global using Games.Common.IO; +global using Games.Common.Randomness; +global using static Digits.Resources.Resource; + +new GameSeries(new ConsoleIO(), new RandomNumberGenerator()).Play(); \ No newline at end of file diff --git a/34_Digits/csharp/Resources/ForInstructions.txt b/34_Digits/csharp/Resources/ForInstructions.txt new file mode 100644 index 00000000..1c16d5f4 --- /dev/null +++ b/34_Digits/csharp/Resources/ForInstructions.txt @@ -0,0 +1 @@ +For instructions, type '1', else type '0' \ No newline at end of file diff --git a/34_Digits/csharp/Resources/GuessResult.txt b/34_Digits/csharp/Resources/GuessResult.txt new file mode 100644 index 00000000..4e233e03 --- /dev/null +++ b/34_Digits/csharp/Resources/GuessResult.txt @@ -0,0 +1 @@ + {0} {1} {2} {3} \ No newline at end of file diff --git a/34_Digits/csharp/Resources/Headings.txt b/34_Digits/csharp/Resources/Headings.txt new file mode 100644 index 00000000..8289cdf6 --- /dev/null +++ b/34_Digits/csharp/Resources/Headings.txt @@ -0,0 +1,3 @@ + +My guess Your no. Result No. right + diff --git a/34_Digits/csharp/Resources/IWin.txt b/34_Digits/csharp/Resources/IWin.txt new file mode 100644 index 00000000..491f69cf --- /dev/null +++ b/34_Digits/csharp/Resources/IWin.txt @@ -0,0 +1,4 @@ + +I guessed more than 1/3 of your numbers. +I win. + diff --git a/34_Digits/csharp/Resources/Instructions.txt b/34_Digits/csharp/Resources/Instructions.txt new file mode 100644 index 00000000..f9ff2a16 --- /dev/null +++ b/34_Digits/csharp/Resources/Instructions.txt @@ -0,0 +1,11 @@ + +Please take a piece of paper and write down +the digits '0', '1', or '2' thirty times at random. +Arrange them in three lines of ten digits each. +I will ask for then ten at a time. +I will always guess them first and then look at your +next number to see if I was right. By pure luck, +I ought to be right ten times. But I hope to do better +than that ***** + + diff --git a/34_Digits/csharp/Resources/Introduction.txt b/34_Digits/csharp/Resources/Introduction.txt new file mode 100644 index 00000000..e4d2d93e --- /dev/null +++ b/34_Digits/csharp/Resources/Introduction.txt @@ -0,0 +1,6 @@ + Digits + Creative Computing Morristown, New Jersey + + + +This is a game of guessing. diff --git a/34_Digits/csharp/Resources/ItsATie.txt b/34_Digits/csharp/Resources/ItsATie.txt new file mode 100644 index 00000000..0e92fbf6 --- /dev/null +++ b/34_Digits/csharp/Resources/ItsATie.txt @@ -0,0 +1,4 @@ + +I guessed exactly 1/3 of your numbers. +It's a tie game. + diff --git a/34_Digits/csharp/Resources/Resource.cs b/34_Digits/csharp/Resources/Resource.cs new file mode 100644 index 00000000..2e935955 --- /dev/null +++ b/34_Digits/csharp/Resources/Resource.cs @@ -0,0 +1,43 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace Digits.Resources; + +internal static class Resource +{ + internal static class Streams + { + public static Stream Introduction => GetStream(); + public static Stream Instructions => GetStream(); + public static Stream TryAgain => GetStream(); + public static Stream ItsATie => GetStream(); + public static Stream IWin => GetStream(); + public static Stream YouWin => GetStream(); + public static Stream Thanks => GetStream(); + public static Stream Headings => GetStream(); + } + + internal static class Prompts + { + public static string ForInstructions => GetString(); + public static string TenNumbers => GetString(); + public static string WantToTryAgain => GetString(); + } + + internal static class Formats + { + public static string GuessResult => GetString(); + } + + private static string GetString([CallerMemberName] string? name = null) + { + using var stream = GetStream(name); + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + + private static Stream GetStream([CallerMemberName] string? name = null) => + Assembly.GetExecutingAssembly().GetManifestResourceStream($"{typeof(Resource).Namespace}.{name}.txt") + ?? throw new Exception($"Could not find embedded resource stream '{name}'."); +} \ No newline at end of file diff --git a/34_Digits/csharp/Resources/TenNumbers.txt b/34_Digits/csharp/Resources/TenNumbers.txt new file mode 100644 index 00000000..ad03893a --- /dev/null +++ b/34_Digits/csharp/Resources/TenNumbers.txt @@ -0,0 +1,2 @@ + +Ten numbers, please \ No newline at end of file diff --git a/34_Digits/csharp/Resources/Thanks.txt b/34_Digits/csharp/Resources/Thanks.txt new file mode 100644 index 00000000..15d42e1b --- /dev/null +++ b/34_Digits/csharp/Resources/Thanks.txt @@ -0,0 +1,2 @@ + +Thanks for the game diff --git a/34_Digits/csharp/Resources/TryAgain.txt b/34_Digits/csharp/Resources/TryAgain.txt new file mode 100644 index 00000000..74bdca68 --- /dev/null +++ b/34_Digits/csharp/Resources/TryAgain.txt @@ -0,0 +1,2 @@ +Only use the digits '0', '1', or '2'. +Let's try again. diff --git a/34_Digits/csharp/Resources/WantToTryAgain.txt b/34_Digits/csharp/Resources/WantToTryAgain.txt new file mode 100644 index 00000000..38f4509d --- /dev/null +++ b/34_Digits/csharp/Resources/WantToTryAgain.txt @@ -0,0 +1 @@ +Do you want to try again (1 for yes, 0 for no) \ No newline at end of file diff --git a/34_Digits/csharp/Resources/YouWin.txt b/34_Digits/csharp/Resources/YouWin.txt new file mode 100644 index 00000000..87b26b38 --- /dev/null +++ b/34_Digits/csharp/Resources/YouWin.txt @@ -0,0 +1,4 @@ + +I guessed less than 1/3 of your numbers. +You beat me. Congratulations ***** + diff --git a/41_Guess/csharp/Game.cs b/41_Guess/csharp/Game.cs new file mode 100644 index 00000000..57ae071a --- /dev/null +++ b/41_Guess/csharp/Game.cs @@ -0,0 +1,78 @@ +namespace Guess; + +internal class Game +{ + private readonly IReadWrite _io; + private readonly IRandom _random; + + public Game(IReadWrite io, IRandom random) + { + _io = io; + _random = random; + } + + public void Play() + { + while (true) + { + _io.Write(Streams.Introduction); + + var limit = _io.ReadNumber(Prompts.Limit); + _io.WriteLine(); + + // There's a bug here that exists in the original code. + // If the limit entered is <= 0 then the program will crash. + var targetGuessCount = checked((int)Math.Log2(limit) + 1); + + PlayGuessingRounds(limit, targetGuessCount); + + _io.Write(Streams.BlankLines); + } + } + + private void PlayGuessingRounds(float limit, int targetGuessCount) + { + while (true) + { + _io.WriteLine(Formats.Thinking, limit); + + // There's a bug here that exists in the original code. If a non-integer is entered as the limit + // then it's possible for the secret number to be the next integer greater than the limit. + var secretNumber = (int)_random.NextFloat(limit) + 1; + + var guessCount = 0; + + while (true) + { + var guess = _io.ReadNumber(""); + if (guess <= 0) { return; } + guessCount++; + if (IsGuessCorrect(guess, secretNumber)) { break; } + } + + ReportResult(guessCount, targetGuessCount); + + _io.Write(Streams.BlankLines); + } + } + + private bool IsGuessCorrect(float guess, int secretNumber) + { + if (guess < secretNumber) { _io.Write(Streams.TooLow); } + if (guess > secretNumber) { _io.Write(Streams.TooHigh); } + + return guess == secretNumber; + } + + private void ReportResult(int guessCount, int targetGuessCount) + { + _io.WriteLine(Formats.ThatsIt, guessCount); + _io.WriteLine( + (guessCount - targetGuessCount) switch + { + < 0 => Strings.VeryGood, + 0 => Strings.Good, + > 0 => string.Format(Formats.ShouldHave, targetGuessCount) + }); + } +} \ No newline at end of file diff --git a/41_Guess/csharp/Guess.csproj b/41_Guess/csharp/Guess.csproj index d3fe4757..3870320c 100644 --- a/41_Guess/csharp/Guess.csproj +++ b/41_Guess/csharp/Guess.csproj @@ -6,4 +6,12 @@ enable enable + + + + + + + + diff --git a/41_Guess/csharp/Program.cs b/41_Guess/csharp/Program.cs new file mode 100644 index 00000000..73ab09dd --- /dev/null +++ b/41_Guess/csharp/Program.cs @@ -0,0 +1,7 @@ +global using Games.Common.IO; +global using Games.Common.Randomness; +global using static Guess.Resources.Resource; + +using Guess; + +new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); diff --git a/41_Guess/csharp/Resources/BlankLines.txt b/41_Guess/csharp/Resources/BlankLines.txt new file mode 100644 index 00000000..3f2ff2d6 --- /dev/null +++ b/41_Guess/csharp/Resources/BlankLines.txt @@ -0,0 +1,5 @@ + + + + + diff --git a/41_Guess/csharp/Resources/Good.txt b/41_Guess/csharp/Resources/Good.txt new file mode 100644 index 00000000..989dfa38 --- /dev/null +++ b/41_Guess/csharp/Resources/Good.txt @@ -0,0 +1 @@ +Good. \ No newline at end of file diff --git a/41_Guess/csharp/Resources/Introduction.txt b/41_Guess/csharp/Resources/Introduction.txt new file mode 100644 index 00000000..ed679492 --- /dev/null +++ b/41_Guess/csharp/Resources/Introduction.txt @@ -0,0 +1,9 @@ + Guess + Creative Computing Morristown, New Jersey + + + +This is a number guessing game. I'll think +of a number between 1 and any limit you want. +The you have to guess what it is. + diff --git a/41_Guess/csharp/Resources/Limit.txt b/41_Guess/csharp/Resources/Limit.txt new file mode 100644 index 00000000..62e698a6 --- /dev/null +++ b/41_Guess/csharp/Resources/Limit.txt @@ -0,0 +1 @@ +What limit do you want \ No newline at end of file diff --git a/41_Guess/csharp/Resources/Resource.cs b/41_Guess/csharp/Resources/Resource.cs new file mode 100644 index 00000000..d42477e2 --- /dev/null +++ b/41_Guess/csharp/Resources/Resource.cs @@ -0,0 +1,44 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace Guess.Resources; + +internal static class Resource +{ + internal static class Streams + { + public static Stream Introduction => GetStream(); + public static Stream TooLow => GetStream(); + public static Stream TooHigh => GetStream(); + public static Stream BlankLines => GetStream(); + } + + internal static class Formats + { + public static string Thinking => GetString(); + public static string ThatsIt => GetString(); + public static string ShouldHave => GetString(); + } + + internal static class Prompts + { + public static string Limit => GetString(); + } + + internal static class Strings + { + public static string Good => GetString(); + public static string VeryGood => GetString(); + } + + private static string GetString([CallerMemberName] string? name = null) + { + using var stream = GetStream(name); + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + private static Stream GetStream([CallerMemberName] string? name = null) => + Assembly.GetExecutingAssembly().GetManifestResourceStream($"{typeof(Resource).Namespace}.{name}.txt") + ?? throw new Exception($"Could not find embedded resource stream '{name}'."); +} \ No newline at end of file diff --git a/41_Guess/csharp/Resources/ShouldHave.txt b/41_Guess/csharp/Resources/ShouldHave.txt new file mode 100644 index 00000000..84803588 --- /dev/null +++ b/41_Guess/csharp/Resources/ShouldHave.txt @@ -0,0 +1 @@ +You should have been able to get it in only {0} \ No newline at end of file diff --git a/41_Guess/csharp/Resources/ThatsIt.txt b/41_Guess/csharp/Resources/ThatsIt.txt new file mode 100644 index 00000000..61f78c43 --- /dev/null +++ b/41_Guess/csharp/Resources/ThatsIt.txt @@ -0,0 +1 @@ +That's it! You got it in {0} tries. \ No newline at end of file diff --git a/41_Guess/csharp/Resources/Thinking.txt b/41_Guess/csharp/Resources/Thinking.txt new file mode 100644 index 00000000..8f1bbac7 --- /dev/null +++ b/41_Guess/csharp/Resources/Thinking.txt @@ -0,0 +1,2 @@ +I'm thinking of a number between 1 and {0} +Now you try to guess what it is. \ No newline at end of file diff --git a/41_Guess/csharp/Resources/TooHigh.txt b/41_Guess/csharp/Resources/TooHigh.txt new file mode 100644 index 00000000..bb4ee4ed --- /dev/null +++ b/41_Guess/csharp/Resources/TooHigh.txt @@ -0,0 +1 @@ +Too high. Try a smaller answer. \ No newline at end of file diff --git a/41_Guess/csharp/Resources/TooLow.txt b/41_Guess/csharp/Resources/TooLow.txt new file mode 100644 index 00000000..4bc1776f --- /dev/null +++ b/41_Guess/csharp/Resources/TooLow.txt @@ -0,0 +1 @@ +Too low. Try a bigger answer. \ No newline at end of file diff --git a/41_Guess/csharp/Resources/VeryGood.txt b/41_Guess/csharp/Resources/VeryGood.txt new file mode 100644 index 00000000..606150c7 --- /dev/null +++ b/41_Guess/csharp/Resources/VeryGood.txt @@ -0,0 +1 @@ +Very good. \ No newline at end of file diff --git a/56_Life_for_Two/README.md b/56_Life_for_Two/README.md index 3cc22c9e..3d906342 100644 --- a/56_Life_for_Two/README.md +++ b/56_Life_for_Two/README.md @@ -6,6 +6,7 @@ There are two players; the game is played on a 5x5 board and each player has a s The # and * are regarded as the same except when deciding whether to generate a live cell. An empty cell having two `#` and one `*` for neighbors will generate a `#`, i.e. the live cell generated belongs to the player who has the majority of the 3 live cells surrounding the empty cell where life is to be generated, for example: +``` | | 1 | 2 | 3 | 4 | 5 | |:-:|:-:|:-:|:-:|:-:|:-:| | 1 | | | | | | @@ -13,9 +14,10 @@ The # and * are regarded as the same except when deciding whether to generate a | 3 | | | | # | | | 4 | | | # | | | | 5 | | | | | | +``` A new cell will be generated at (3,3) which will be a `#` since there are two `#` and one `*` surrounding. The board will then become: - +``` | | 1 | 2 | 3 | 4 | 5 | |:-:|:-:|:-:|:-:|:-:|:-:| | 1 | | | | | | @@ -23,7 +25,7 @@ A new cell will be generated at (3,3) which will be a `#` since there are two `# | 3 | | | # | # | | | 4 | | | | | | | 5 | | | | | | - +``` On the first most each player positions 3 pieces of life on the board by typing in the co-ordinates of the pieces. (In the event of the same cell being chosen by both players that cell is left empty.) The board is then adjusted to the next generation and printed out. diff --git a/56_Life_for_Two/java/LifeForTwo.java b/56_Life_for_Two/java/LifeForTwo.java new file mode 100644 index 00000000..1f68e794 --- /dev/null +++ b/56_Life_for_Two/java/LifeForTwo.java @@ -0,0 +1,305 @@ +import java.util.*; +import java.util.stream.IntStream; + +/** + * Life for Two + *

+ * The original BASIC program uses a grid with an extras border of cells all around, + * probably to simplify calculations and manipulations. This java program has the exact + * grid size and instead uses boundary check conditions in the logic. + *

+ * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm) + */ +public class LifeForTwo { + + final static int GRID_SIZE = 5; + + //Pair of offset which when added to the current cell's coordinates, + // give the coordinates of the neighbours + final static int[] neighbourCellOffsets = { + -1, 0, + 1, 0, + 0, -1, + 0, 1, + -1, -1, + 1, -1, + -1, 1, + 1, 1 + }; + + //The best term that I could come with to describe these numbers was 'masks' + //They act like indicators to decide which player won the cell. The value is the score of the cell after all the + // generation calculations. + final static List maskPlayer1 = List.of(3, 102, 103, 120, 130, 121, 112, 111, 12); + final static List maskPlayer2 = List.of(21, 30, 1020, 1030, 1011, 1021, 1003, 1002, 1012); + + public static void main(String[] args) { + printIntro(); + Scanner scan = new Scanner(System.in); + scan.useDelimiter("\\D"); + + int[][] grid = new int[GRID_SIZE][GRID_SIZE]; + + initializeGrid(grid); + + //Read the initial 3 moves for each player + for (int b = 1; b <= 2; b++) { + System.out.printf("\nPLAYER %d - 3 LIVE PIECES.%n", b); + for (int k1 = 1; k1 <= 3; k1++) { + var player1Coordinates = readUntilValidCoordinates(scan, grid); + grid[player1Coordinates.x - 1][player1Coordinates.y - 1] = (b == 1 ? 3 : 30); + } + } + + printGrid(grid); + + calculatePlayersScore(grid); //Convert 3, 30 to 100, 1000 + + resetGridForNextGen(grid); + computeCellScoresForOneGen(grid); + + var playerScores = calculatePlayersScore(grid); + resetGridForNextGen(grid); + + boolean gameOver = false; + while (!gameOver) { + printGrid(grid); + if (playerScores.getPlayer1Score() == 0 && playerScores.getPlayer2Score() == 0) { + System.out.println("\nA DRAW"); + gameOver = true; + } else if (playerScores.getPlayer2Score() == 0) { + System.out.println("\nPLAYER 1 IS THE WINNER"); + gameOver = true; + } else if (playerScores.getPlayer1Score() == 0) { + System.out.println("\nPLAYER 2 IS THE WINNER"); + gameOver = true; + } else { + System.out.print("PLAYER 1 "); + Coordinate player1Move = readCoordinate(scan); + System.out.print("PLAYER 2 "); + Coordinate player2Move = readCoordinate(scan); + if (!player1Move.equals(player2Move)) { + grid[player1Move.x - 1][player1Move.y - 1] = 100; + grid[player2Move.x - 1][player2Move.y - 1] = 1000; + } + //In the original, B is assigned 99 when both players choose the same cell + //and that is used to control the flow + computeCellScoresForOneGen(grid); + playerScores = calculatePlayersScore(grid); + resetGridForNextGen(grid); + } + } + + } + + private static void initializeGrid(int[][] grid) { + for (int[] row : grid) { + Arrays.fill(row, 0); + } + } + + private static void computeCellScoresForOneGen(int[][] grid) { + for (int i = 0; i < GRID_SIZE; i++) { + for (int j = 0; j < GRID_SIZE; j++) { + if (grid[i][j] >= 100) { + calculateScoreForOccupiedCell(grid, i, j); + } + } + } + } + + private static Scores calculatePlayersScore(int[][] grid) { + int m2 = 0; + int m3 = 0; + for (int i = 0; i < GRID_SIZE; i++) { + for (int j = 0; j < GRID_SIZE; j++) { + if (grid[i][j] < 3) { + grid[i][j] = 0; + } else { + if (maskPlayer1.contains(grid[i][j])) { + m2++; + } else if (maskPlayer2.contains(grid[i][j])) { + m3++; + } + } + } + } + return new Scores(m2, m3); + } + + private static void resetGridForNextGen(int[][] grid) { + for (int i = 0; i < GRID_SIZE; i++) { + for (int j = 0; j < GRID_SIZE; j++) { + if (grid[i][j] < 3) { + grid[i][j] = 0; + } else { + if (maskPlayer1.contains(grid[i][j])) { + grid[i][j] = 100; + } else if (maskPlayer2.contains(grid[i][j])) { + grid[i][j] = 1000; + } else { + grid[i][j] = 0; + } + } + } + } + } + + private static void calculateScoreForOccupiedCell(int[][] grid, int i, int j) { + var b = 1; + if (grid[i][j] > 999) { + b = 10; + } + for (int k = 0; k < 15; k += 2) { + //check bounds + var neighbourX = i + neighbourCellOffsets[k]; + var neighbourY = j + neighbourCellOffsets[k + 1]; + if (neighbourX >= 0 && neighbourX < GRID_SIZE && + neighbourY >= 0 && neighbourY < GRID_SIZE) { + grid[neighbourX][neighbourY] = grid[neighbourX][neighbourY] + b; + } + + } + } + + private static void printGrid(int[][] grid) { + System.out.println(); + printRowEdge(); + System.out.println(); + for (int i = 0; i < grid.length; i++) { + System.out.printf("%d ", i + 1); + for (int j = 0; j < grid[i].length; j++) { + System.out.printf(" %c ", mapChar(grid[i][j])); + } + System.out.printf(" %d", i + 1); + System.out.println(); + } + printRowEdge(); + System.out.println(); + } + + private static void printRowEdge() { + System.out.print("0 "); + IntStream.range(1, GRID_SIZE + 1).forEach(i -> System.out.printf(" %s ", i)); + System.out.print(" 0"); + } + + private static char mapChar(int i) { + if (i == 3 || i == 100) { + return '*'; + } + if (i == 30 || i == 1000) { + return '#'; + } + return ' '; + } + + private static Coordinate readUntilValidCoordinates(Scanner scanner, int[][] grid) { + boolean coordinateInRange = false; + Coordinate coordinate = null; + while (!coordinateInRange) { + coordinate = readCoordinate(scanner); + if (coordinate.x <= 0 || coordinate.x > GRID_SIZE + || coordinate.y <= 0 || coordinate.y > GRID_SIZE + || grid[coordinate.x - 1][coordinate.y - 1] != 0) { + System.out.println("ILLEGAL COORDS. RETYPE"); + } else { + coordinateInRange = true; + } + } + return coordinate; + } + + private static Coordinate readCoordinate(Scanner scanner) { + Coordinate coordinate = null; + int x, y; + boolean valid = false; + + System.out.println("X,Y"); + System.out.print("XXXXXX\r"); + System.out.print("$$$$$$\r"); + System.out.print("&&&&&&\r"); + + while (!valid) { + try { + System.out.print("? "); + y = scanner.nextInt(); + x = scanner.nextInt(); + valid = true; + coordinate = new Coordinate(x, y); + } catch (InputMismatchException e) { + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE"); + valid = false; + } finally { + scanner.nextLine(); + } + } + return coordinate; + } + + private static void printIntro() { + System.out.println(" LIFE2"); + System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + + System.out.println("\tU.B. LIFE GAME"); + } + + private static class Coordinate { + private final int x, y; + + public Coordinate(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + @Override + public String toString() { + return "Coordinate{" + + "x=" + x + + ", y=" + y + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Coordinate that = (Coordinate) o; + return x == that.x && y == that.y; + } + + @Override + public int hashCode() { + return Objects.hash(x, y); + } + } + + private static class Scores { + private final int player1Score; + private final int player2Score; + + public Scores(int player1Score, int player2Score) { + this.player1Score = player1Score; + this.player2Score = player2Score; + } + + public int getPlayer1Score() { + return player1Score; + } + + public int getPlayer2Score() { + return player2Score; + } + } + + +} diff --git a/56_Life_for_Two/python/life_for_two.py b/56_Life_for_Two/python/life_for_two.py new file mode 100644 index 00000000..a79be546 --- /dev/null +++ b/56_Life_for_Two/python/life_for_two.py @@ -0,0 +1,155 @@ +''' +LIFE FOR TWO + +Competitive Game of Life (two or more players). + +Ported by Sajid Sarker (2022). +''' +# Global Variable Initialisation +gn = [] +gx = [] +gy = [] +gk = [0, 3, 102, 103, 120, 130, 121, 112, 111, 12, 21, 30, 1020, 1030, 1011, 1021, 1003, 1002, 1012] +ga = [0, -1, 0, 1, 0, 0, -1, 0, 1, -1, -1, 1, -1, -1, 1, 1, 1] +m2 = 0 +m3 = 0 + +# Initialise the board +for j in range(6): + gn.append([]) + for k in range(6): + gn[j].append(0) + +for i in range(3): + gx.append(0) + gy.append(0) + +# Helper Functions +def tab(number) -> str: + t = "" + while len(t) < number: + t += " " + return t + +def display_header() -> None: + print("{}LIFE2".format(tab(33))) + print("{}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n".format(tab(15))) + print("{}U.B. LIFE GAME".format(tab(10))) + +# Board Functions +def setup_board() -> None: + # Players add symbols to initially setup the board + for b in range(1, 3): + p1 = 3 if b != 2 else 30 + print("\nPLAYER {} - 3 LIVE PIECES.".format(b)) + for k1 in range(1, 4): + query_player(b) + gn[gx[b]][gy[b]] = p1 + +def modify_board() -> None: + # Players take turns to add symbols and modify the board + for b in range(1, 3): + print("PLAYER {} ".format(b)) + query_player(b) + if b == 99: + break + if b <= 2: + gn[gx[1]][gy[1]] = 100 + gn[gx[2]][gy[2]] = 1000 + +def simulate_board() -> None: + # Simulate the board for one step + for j in range(1, 6): + for k in range(1, 6): + if gn[j][k] > 99: + b = 1 if gn[j][k] <= 999 else 10 + for o1 in range(1, 16, 2): + gn[j + ga[o1] - 1][k + ga[o1 + 1] - 1] = gn[j + ga[o1] - 1][k + ga[o1 + 1] - 1] + b + #gn[j + ga[o1]][k + ga[o1 + 1]] = gn[j + ga[o1]][k + ga[o1 + 1]] + b + +def display_board() -> None: + # Draws the board with all symbols + m2, m3 = 0, 0 + for j in range(7): + print("") + for k in range(7): + if j == 0 or j == 6: + if k != 6: + print(" " + str(k) + " ", end="") + else: + print(" 0 ", end="") + elif k == 0 or k == 6: + if j != 6: + print(" " + str(j) + " ", end="") + else: + print(" 0\n") + else: + if gn[j][k] < 3: + gn[j][k] = 0 + print(" ", end="") + else: + for o1 in range(1, 19): + if gn[j][k] == gk[o1]: + break + if o1 <= 18: + if o1 > 9: + gn[j][k] = 1000 + m3 += 1 + print(" # ", end="") + else: + gn[j][k] = 100 + m2 += 1 + print(" * ", end="") + else: + gn[j][k] = 0 + print(" ", end="") + +# Player Functions +def query_player(b) -> None: + # Query player for symbol placement coordinates + while True: + print("X,Y\nXXXXXX\n$$$$$$\n&&&&&&") + a_ = input("??") + b_ = input("???") + x_ = [int(num) for num in a_.split() if num.isdigit()] + y_ = [int(num) for num in b_.split() if num.isdigit()] + x_ = [0] if len(x_) == 0 else x_ + y_ = [0] if len(y_) == 0 else y_ + gx[b] = y_[0] + gy[b] = x_[0] + if gx[b] in range(1, 6) and gy[b] in range(1, 6) and gn[gx[b]][gy[b]] == 0: + break + print("ILLEGAL COORDS. RETYPE") + if b != 1: + if gx[1] == gx[2] and gy[1] == gy[2]: + print("SAME COORD. SET TO 0") + gn[gx[b] + 1][gy[b] + 1] = 0 + b = 99 + +# Game Functions +def check_winner(m2, m3) -> None: + # Check if the game has been won + if m2 == 0 and m3 == 0: + print("\nA DRAW\n") + return + if m3 == 0: + print("\nPLAYER 1 IS THE WINNER\n") + return + if m2 == 0: + print("\nPLAYER 2 IS THE WINNER\n") + return + +# Program Flow +def main() -> None: + display_header() + setup_board() + display_board() + while True: + print("\n") + simulate_board() + display_board() + check_winner(m2, m3) + modify_board() + +if __name__ == "__main__": + main() diff --git a/67_One_Check/csharp/Board.cs b/67_One_Check/csharp/Board.cs new file mode 100644 index 00000000..2e68072d --- /dev/null +++ b/67_One_Check/csharp/Board.cs @@ -0,0 +1,64 @@ +namespace OneCheck; + +internal class Board +{ + private readonly bool[][] _checkers; + private int _pieceCount; + private int _moveCount; + + public Board() + { + _checkers = + Enumerable.Range(0, 8) + .Select(r => Enumerable.Range(0, 8) + .Select(c => r <= 1 || r >= 6 || c <= 1 || c >= 6).ToArray()) + .ToArray(); + _pieceCount = 48; + } + + private bool this[int index] + { + get => _checkers[index / 8][index % 8]; + set => _checkers[index / 8][index % 8] = value; + } + + public bool PlayMove(IReadWrite io) + { + while (true) + { + var from = (int)io.ReadNumber(Prompts.From); + if (from == 0) { return false; } + + var move = new Move { From = from - 1, To = (int)io.ReadNumber(Prompts.To) - 1 }; + + if (TryMove(move)) + { + _moveCount++; + return true; + } + + io.Write(Streams.IllegalMove); + } + } + + public bool TryMove(Move move) + { + if (move.IsInRange && move.IsTwoSpacesDiagonally && IsPieceJumpingPieceToEmptySpace(move)) + { + this[move.From] = false; + this[move.Jumped] = false; + this[move.To] = true; + _pieceCount--; + return true; + } + + return false; + } + + private bool IsPieceJumpingPieceToEmptySpace(Move move) => this[move.From] && this[move.Jumped] && !this[move.To]; + + public string GetReport() => string.Format(Formats.Results, _moveCount, _pieceCount); + + public override string ToString() => + string.Join(Environment.NewLine, _checkers.Select(r => string.Join(" ", r.Select(c => c ? " 1" : " 0")))); +} diff --git a/67_One_Check/csharp/Game.cs b/67_One_Check/csharp/Game.cs new file mode 100644 index 00000000..d9e64e26 --- /dev/null +++ b/67_One_Check/csharp/Game.cs @@ -0,0 +1,45 @@ +namespace OneCheck; + +internal class Game +{ + private readonly IReadWrite _io; + + public Game(IReadWrite io) + { + _io = io; + } + + public void Play() + { + _io.Write(Streams.Introduction); + + do + { + var board = new Board(); + do + { + _io.WriteLine(board); + _io.WriteLine(); + } while (board.PlayMove(_io)); + + _io.WriteLine(board.GetReport()); + } while (_io.ReadYesNo(Prompts.TryAgain) == "yes"); + + _io.Write(Streams.Bye); + } +} + +internal static class IOExtensions +{ + internal static string ReadYesNo(this IReadWrite io, string prompt) + { + while (true) + { + var response = io.ReadString(prompt).ToLower(); + + if (response == "yes" || response == "no") { return response; } + + io.Write(Streams.YesOrNo); + } + } +} diff --git a/67_One_Check/csharp/Move.cs b/67_One_Check/csharp/Move.cs new file mode 100644 index 00000000..0b48659e --- /dev/null +++ b/67_One_Check/csharp/Move.cs @@ -0,0 +1,13 @@ +namespace OneCheck; + +internal class Move +{ + public int From { get; init; } + public int To { get; init; } + public int Jumped => (From + To) / 2; + + public bool IsInRange => From >= 0 && From <= 63 && To >= 0 && To <= 63; + public bool IsTwoSpacesDiagonally => RowDelta == 2 && ColumnDelta == 2; + private int RowDelta => Math.Abs(From / 8 - To / 8); + private int ColumnDelta => Math.Abs(From % 8 - To % 8); +} \ No newline at end of file diff --git a/67_One_Check/csharp/OneCheck.csproj b/67_One_Check/csharp/OneCheck.csproj index d3fe4757..3870320c 100644 --- a/67_One_Check/csharp/OneCheck.csproj +++ b/67_One_Check/csharp/OneCheck.csproj @@ -6,4 +6,12 @@ enable enable + + + + + + + + diff --git a/67_One_Check/csharp/Program.cs b/67_One_Check/csharp/Program.cs new file mode 100644 index 00000000..4a3ab83b --- /dev/null +++ b/67_One_Check/csharp/Program.cs @@ -0,0 +1,5 @@ +global using Games.Common.IO; +global using static OneCheck.Resources.Resource; +using OneCheck; + +new Game(new ConsoleIO()).Play(); diff --git a/67_One_Check/csharp/Resources/Bye.txt b/67_One_Check/csharp/Resources/Bye.txt new file mode 100644 index 00000000..ee4ddab1 --- /dev/null +++ b/67_One_Check/csharp/Resources/Bye.txt @@ -0,0 +1,2 @@ + +O.K. Hope you had fun!! \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/From.txt b/67_One_Check/csharp/Resources/From.txt new file mode 100644 index 00000000..bb4c7a2d --- /dev/null +++ b/67_One_Check/csharp/Resources/From.txt @@ -0,0 +1 @@ +Jump from \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/IllegalMove.txt b/67_One_Check/csharp/Resources/IllegalMove.txt new file mode 100644 index 00000000..a96b6e81 --- /dev/null +++ b/67_One_Check/csharp/Resources/IllegalMove.txt @@ -0,0 +1 @@ +Illegal move. Try again... \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/Introduction.txt b/67_One_Check/csharp/Resources/Introduction.txt new file mode 100644 index 00000000..409f6b37 --- /dev/null +++ b/67_One_Check/csharp/Resources/Introduction.txt @@ -0,0 +1,30 @@ + One Check + Creative Computing Morristown, New Jersey + + + +Solitaire checker puzzle by David Ahl + +48 checkers and 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 ?' + +Here is the numerical board: + + 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 37 38 39 40 + 41 42 43 44 45 46 47 48 + 49 50 51 52 53 54 55 56 + 57 58 59 60 61 62 63 64 + +And here is the opening position of the checkers. + diff --git a/67_One_Check/csharp/Resources/Resource.cs b/67_One_Check/csharp/Resources/Resource.cs new file mode 100644 index 00000000..7095d7ec --- /dev/null +++ b/67_One_Check/csharp/Resources/Resource.cs @@ -0,0 +1,45 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace OneCheck.Resources; + +internal static class Resource +{ + internal static class Streams + { + public static Stream Introduction => GetStream(); + public static Stream IllegalMove => GetStream(); + public static Stream YesOrNo => GetStream(); + public static Stream Bye => GetStream(); + } + + internal static class Formats + { + public static string Results => GetString(); + } + + internal static class Prompts + { + public static string From => GetString(); + public static string To => GetString(); + public static string TryAgain => GetString(); + } + + internal static class Strings + { + public static string TooManyColumns => GetString(); + public static string TooManyRows => GetString(); + } + + private static string GetString([CallerMemberName] string? name = null) + { + using var stream = GetStream(name); + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + + private static Stream GetStream([CallerMemberName] string? name = null) => + Assembly.GetExecutingAssembly().GetManifestResourceStream($"{typeof(Resource).Namespace}.{name}.txt") + ?? throw new Exception($"Could not find embedded resource stream '{name}'."); +} \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/Results.txt b/67_One_Check/csharp/Resources/Results.txt new file mode 100644 index 00000000..a8771b6b --- /dev/null +++ b/67_One_Check/csharp/Resources/Results.txt @@ -0,0 +1,3 @@ + +You made {0} jumps and had {1} pieces +remaining on the board. diff --git a/67_One_Check/csharp/Resources/To.txt b/67_One_Check/csharp/Resources/To.txt new file mode 100644 index 00000000..788636ff --- /dev/null +++ b/67_One_Check/csharp/Resources/To.txt @@ -0,0 +1 @@ +to \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/TryAgain.txt b/67_One_Check/csharp/Resources/TryAgain.txt new file mode 100644 index 00000000..c65e51fc --- /dev/null +++ b/67_One_Check/csharp/Resources/TryAgain.txt @@ -0,0 +1 @@ +Try again \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/YesOrNo.txt b/67_One_Check/csharp/Resources/YesOrNo.txt new file mode 100644 index 00000000..703d4ad6 --- /dev/null +++ b/67_One_Check/csharp/Resources/YesOrNo.txt @@ -0,0 +1 @@ +Please answer 'Yes' or 'No'. \ No newline at end of file diff --git a/76_Russian_Roulette/lua/russianroulette.lua b/76_Russian_Roulette/lua/russianroulette.lua new file mode 100644 index 00000000..546ec6c4 --- /dev/null +++ b/76_Russian_Roulette/lua/russianroulette.lua @@ -0,0 +1,58 @@ +print [[ + RUSSIAN ROULETTE + CREATIVE COMPUTING MORRISTOWN, NEW JERSY +This is a game of >>>>>>>>>>Russian Roulette +Here is a Revolver + +]] + +local function parse_input() + local incorrect_input = true + local input = nil + while incorrect_input do + input = io.read(1) + if input == "1" or input == "2" then incorrect_input = false end + end + return input +end + +local function russian_roulette() + local NUMBER_OF_ROUNDS = 9 + + while true do + local dead = false + local n = 0 + print("Type '1' to Spin chamber and pull trigger") + print("Type '2' to Give up") + print("Go") + + while not dead do + local choice = parse_input() + if choice == "2" then break end + + if math.random() > 0.833333333333334 then + dead = true + else + print("CLICK") + n = n + 1 + end + + if n > NUMBER_OF_ROUNDS then break end + end + + if dead then + print("BANG!!!!! You're Dead!") + print("Condolences will be sent to your relatives.\n\n\n") + print("...Next victim...") + elseif n > NUMBER_OF_ROUNDS then + print("You win!!!!!") + print("Let someone else blow his brain out.\n") + else + print(" Chicken!!!!!\n\n\n") + print("...Next victim....") + end + end +end + +russian_roulette() + diff --git a/84_Super_Star_Trek/python/superstartrek.py b/84_Super_Star_Trek/python/superstartrek.py index 40ccb9f6..21e03e45 100644 --- a/84_Super_Star_Trek/python/superstartrek.py +++ b/84_Super_Star_Trek/python/superstartrek.py @@ -902,7 +902,10 @@ class Game: if len(command) == 0: com = 6 else: - com = int(command) + try: + com = int(command) + except ValueError: + com = 6 if com < 0: return diff --git a/91_Train/rust/Cargo.toml b/91_Train/rust/Cargo.toml new file mode 100644 index 00000000..f2fa11b7 --- /dev/null +++ b/91_Train/rust/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rust" +version = "0.1.0" +authors = ["AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com>"] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.5" diff --git a/91_Train/rust/README.md b/91_Train/rust/README.md new file mode 100644 index 00000000..7e85f9a1 --- /dev/null +++ b/91_Train/rust/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM) diff --git a/91_Train/rust/src/lib.rs b/91_Train/rust/src/lib.rs new file mode 100644 index 00000000..d796a20a --- /dev/null +++ b/91_Train/rust/src/lib.rs @@ -0,0 +1,155 @@ +/* + lib.rs contains all the logic of the program +*/ +use rand::{Rng, prelude::thread_rng}; //rng +use std::error::Error; //better errors +use std::io::{self, Write}; //io interactions +use std::{str::FromStr, fmt::Display}; //traits + +//DATA + +/// handles setup for the game +pub struct Config { +} +impl Config { + /// creates and returns a new Config from user input + pub fn new() -> Result> { + //DATA + let config: Config = Config { + }; + + //return new config + return Ok(config); + } +} + +/// run the program +pub fn run(_config: &Config) -> Result<(), Box> { + //DATA + let mut rng = thread_rng(); + + let mut speed_train_1; + let mut time_difference; + let mut speed_train_2; + + let mut guess; + let mut answer; + + let mut error:f32; + + //Game loop + loop { + //initialize variables + speed_train_1 = rng.gen_range(40..65); + time_difference = rng.gen_range(5..20); + speed_train_2 = rng.gen_range(20..39); + + //print starting message / conditions + println!("A CAR TRAVELING {} MPH CAN MAKE A CERTAIN TRIP IN\n{} HOURS LESS THAN A TRAIN TRAVELING AT {} MPH",speed_train_1,time_difference,speed_train_2); + println!(); + + //get guess + guess = loop { + match get_number_from_input("HOW LONG DOES THE TRIP TAKE BY CAR?",0,-1) { + Ok(num) => break num, + Err(err) => { + eprintln!("{}",err); + continue; + }, + } + }; + + //calculate answer and error + answer = time_difference * speed_train_2 / (speed_train_1 - speed_train_2); + error = ((answer - guess) as isize).abs() as f32 * 100.0/(guess as f32) + 0.5; + + //check guess against answer + if error > 5.0 { + println!("SORRY, YOU WERE OFF BY {} PERCENT.", error); + println!("CORRECT ANSWER IS {} HOURS.",answer); + } else { + println!("GOOD! ANSWER WITHIN {} PERCENT.", error); + } + + //ask user if they want to go again + match get_string_from_user_input("ANOTHER PROBLEM (Y/N)") { + Ok(s) => if !s.to_uppercase().eq("Y") {break;} else {continue;}, + _ => break, + } + } + + //return to main + Ok(()) +} + +/// gets a string from user input +fn get_string_from_user_input(prompt: &str) -> Result> { + //DATA + let mut raw_input = String::new(); + + //print prompt + print!("{}", prompt); + //make sure it's printed before getting input + io::stdout().flush().expect("couldn't flush stdout"); + + //read user input from standard input, and store it to raw_input, then return it or an error as needed + raw_input.clear(); //clear input + match io::stdin().read_line(&mut raw_input) { + Ok(_num_bytes_read) => return Ok(String::from(raw_input.trim())), + Err(err) => return Err(format!("ERROR: CANNOT READ INPUT!: {}", err).into()), + } +} +/// generic function to get a number from the passed string (user input) +/// pass a min lower than the max to have minimum and maximum bounds +/// pass a min higher than the max to only have a minimum bound +/// pass a min equal to the max to only have a maximum bound +/// +/// Errors: +/// no number on user input +fn get_number_from_input(prompt: &str, min:T, max:T) -> Result> { + //DATA + let raw_input: String; + let processed_input: String; + + + //input loop + raw_input = loop { + match get_string_from_user_input(prompt) { + Ok(input) => break input, + Err(e) => { + eprintln!("{}",e); + continue; + }, + } + }; + + //filter out non-numeric characters from user input + processed_input = raw_input.chars().filter(|c| c.is_numeric()).collect(); + + //from input, try to read a number + match processed_input.trim().parse() { + Ok(i) => { + //what bounds must the input fall into + if min < max { //have a min and max bound: [min,max] + if i >= min && i <= max {//is input valid, within bounds + return Ok(i); //exit the loop with the value i, returning it + } else { //print error message specific to this case + return Err(format!("ONLY BETWEEN {} AND {}, PLEASE!", min, max).into()); + } + } else if min > max { //only a min bound: [min, infinity) + if i >= min { + return Ok(i); + } else { + return Err(format!("NO LESS THAN {}, PLEASE!", min).into()); + } + } else { //only a max bound: (-infinity, max] + if i <= max { + return Ok(i); + } else { + return Err(format!("NO MORE THAN {}, PLEASE!", max).into()); + } + } + }, + Err(_e) => return Err(format!("Error: couldn't find a valid number in {}",raw_input).into()), + } +} diff --git a/91_Train/rust/src/main.rs b/91_Train/rust/src/main.rs new file mode 100644 index 00000000..438f69be --- /dev/null +++ b/91_Train/rust/src/main.rs @@ -0,0 +1,41 @@ +use std::process;//allows for some better error handling + +mod lib; //allows access to lib.rs +use lib::Config; + +/// main function +/// responsibilities: +/// - Calling the command line logic with the argument values +/// - Setting up any other configuration +/// - Calling a run function in lib.rs +/// - Handling the error if run returns an error +fn main() { + //greet user + welcome(); + + // set up other configuration + let mut config = Config::new().unwrap_or_else(|err| { + eprintln!("Problem configuring program: {}", err); + process::exit(1); + }); + + // run the program + if let Err(e) = lib::run(&mut config) { + eprintln!("Application Error: {}", e); //use the eprintln! macro to output to standard error + process::exit(1); //exit the program with an error code + } + + //end of program + println!("THANKS FOR PLAYING!"); +} + +/// print the welcome message +fn welcome() { + println!(" + Train + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + + +TIME - SPEED DISTANCE EXERCISE + "); +}