mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-12 15:50:20 -08:00
MAINT: Apply 'pre-commit run --all' and fix issues
This commit is contained in:
@@ -2,4 +2,3 @@
|
||||
20 PRINT "You entered: ";A;B;C
|
||||
30 PRINT "--------------------------"
|
||||
40 GOTO 10
|
||||
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
10 A=1: B=-2: C=0.7: D=123456789: E=-0.0000000001
|
||||
20 PRINT "|";A;"|";B;"|";C;"|";D;"|";E;"|"
|
||||
|
||||
|
||||
|
||||
@@ -2,5 +2,3 @@
|
||||
20 PRINT "2: ";RND(-2);RND(1);RND(1);RND(1)
|
||||
30 PRINT "3: ";RND(-5);RND(1);RND(1);RND(1)
|
||||
40 PRINT "4: ";RND(-2);RND(1);RND(1);RND(1)
|
||||
|
||||
|
||||
|
||||
@@ -88,4 +88,4 @@ public static class IRandomExtensions
|
||||
}
|
||||
|
||||
private static int ToInt(float value) => (int)Math.Floor(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly:InternalsVisibleTo("Games.Common.Test")]
|
||||
[assembly:InternalsVisibleTo("Games.Common.Test")]
|
||||
|
||||
@@ -4,8 +4,8 @@ use std::fs::metadata;
|
||||
use std::path::{Path, PathBuf};
|
||||
/**
|
||||
* todo list generator for this repository, coded in rust
|
||||
*
|
||||
* @author Anthony Rubick
|
||||
*
|
||||
* @author Anthony Rubick
|
||||
*/
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ fn main() {
|
||||
|
||||
");
|
||||
|
||||
|
||||
|
||||
//ask user how they want the todo list formatted
|
||||
format_game_first = get_yn_from_user("\n\t---====FORMATS====---\ngame first:\n\tGame\n\t\tLanguage ✅/⬜️\n\nlang first:\n\tLanguage\n\t\tGame ✅/⬜️\n\nmake todo list using the game first format? (y/n | default No) ");
|
||||
|
||||
@@ -214,7 +214,7 @@ fn get_yn_from_user(prompt:&str) -> bool {
|
||||
|
||||
//default in case of error
|
||||
if input.is_empty() {return false;}
|
||||
|
||||
|
||||
//get and parse input
|
||||
match &input[0..1] { //get first character
|
||||
"y" | "Y" => return true,
|
||||
@@ -243,4 +243,3 @@ fn _list_files(vec: &mut Vec<PathBuf>, path: &Path) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,4 +4,3 @@ As published in Basic Computer Games (1978), as found at Annarchive:
|
||||
|
||||
Conversion to Lua
|
||||
- [Lua.org](https://www.lua.org)
|
||||
|
||||
|
||||
@@ -6,4 +6,4 @@ edition = "2018"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rand = "0.8.5"
|
||||
rand = "0.8.5"
|
||||
|
||||
@@ -1,3 +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)
|
||||
Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)
|
||||
|
||||
@@ -25,15 +25,15 @@ fn main() {
|
||||
/*
|
||||
vector of:
|
||||
vectors of:
|
||||
integers
|
||||
Initially set to 0, unprocessed cells.
|
||||
integers
|
||||
Initially set to 0, unprocessed cells.
|
||||
Filled in with consecutive non-zero numbers as cells are processed
|
||||
*/
|
||||
let mut used; //2d vector
|
||||
/*
|
||||
vector of:
|
||||
vectors of:
|
||||
integers
|
||||
integers
|
||||
Remains 0 if there is no exit down or right
|
||||
Set to 1 if there is an exit down
|
||||
Set to 2 if there is an exit right
|
||||
@@ -43,11 +43,11 @@ fn main() {
|
||||
let width;
|
||||
let height;
|
||||
let entrance_column; //rng, column of entrance
|
||||
let mut row;
|
||||
let mut row;
|
||||
let mut col;
|
||||
let mut count;
|
||||
|
||||
|
||||
|
||||
|
||||
//print welcome message
|
||||
println!("
|
||||
@@ -171,13 +171,13 @@ fn main() {
|
||||
fn get_user_input(prompt: &str) -> usize {
|
||||
//DATA
|
||||
let mut raw_input = String::new(); // temporary variable for user input that can be parsed later
|
||||
|
||||
|
||||
//input loop
|
||||
return loop {
|
||||
|
||||
|
||||
//print prompt
|
||||
println!("{}", prompt);
|
||||
|
||||
|
||||
//read user input from standard input, and store it to raw_input
|
||||
raw_input.clear(); //clear input
|
||||
io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!");
|
||||
@@ -186,7 +186,7 @@ fn get_user_input(prompt: &str) -> usize {
|
||||
match raw_input.trim().parse::<usize>() {
|
||||
Ok(i) => {
|
||||
if i>1 { //min size 1
|
||||
break i; // this escapes the loop, returning i
|
||||
break i; // this escapes the loop, returning i
|
||||
}
|
||||
else {
|
||||
println!("INPUT OUT OF RANGE. TRY AGAIN.");
|
||||
|
||||
@@ -6,85 +6,69 @@ An ancient African game (see also Kalah, Mancala).
|
||||
Ported by Dave LeCompte
|
||||
"""
|
||||
|
||||
"""
|
||||
|
||||
PORTING NOTES
|
||||
|
||||
This game started out as 70 lines of BASIC, and I have ported it
|
||||
before. I find it somewhat amazing how efficient (densely packed) the
|
||||
original code is. Of course, the original code has fairly cryptic
|
||||
variable names (as was forced by BASIC's limitation on long (2+
|
||||
character) variable names). I have done my best here to interpret what
|
||||
each variable is doing in context, and rename them appropriately.
|
||||
|
||||
I have endeavored to leave the logic of the code in place, as it's
|
||||
interesting to see a 2-ply game tree evaluation written in BASIC,
|
||||
along with what a reader in 2021 would call "machine learning".
|
||||
|
||||
As each game is played, the move history is stored as base-6
|
||||
digits stored losing_book[game_number]. If the human player wins or
|
||||
draws, the computer increments game_number, effectively "recording"
|
||||
that loss to be referred to later. As the computer evaluates moves, it
|
||||
checks the potential game state against these losing game records, and
|
||||
if the potential move matches with the losing game (up to the current
|
||||
number of moves), that move is evaluated at a two point penalty.
|
||||
|
||||
Compare this, for example with MENACE, a mechanical device for
|
||||
"learning" tic-tac-toe:
|
||||
https://en.wikipedia.org/wiki/Matchbox_Educable_Noughts_and_Crosses_Engine
|
||||
|
||||
The base-6 representation allows game history to be VERY efficiently
|
||||
represented. I considered whether to rewrite this representation to be
|
||||
easier to read, but I elected to TRY to document it, instead.
|
||||
|
||||
Another place where I have made a difficult decision between accuracy
|
||||
and correctness is inside the "wrapping" code where it considers
|
||||
"while human_move_end > 13". The original BASIC code reads:
|
||||
|
||||
830 IF L>13 THEN L=L-14:R=1:GOTO 830
|
||||
|
||||
I suspect that the intention is not to assign 1 to R, but to increment
|
||||
R. I discuss this more in a porting note comment next to the
|
||||
translated code. If you wish to play a more accurate version of the
|
||||
game as written in the book, you can convert the increment back to an
|
||||
assignment.
|
||||
|
||||
|
||||
I continue to be impressed with this jewel of a game; as soon as I had
|
||||
the AI playing against me, it was beating me. I've been able to score
|
||||
a few wins against the computer, but even at its 2-ply lookahead, it
|
||||
beats me nearly always. I would like to become better at this game to
|
||||
explore the effectiveness of the "losing book" machine learning.
|
||||
|
||||
|
||||
EXERCISES FOR THE READER
|
||||
One could go many directions with this game:
|
||||
|
||||
- change the initial number of stones in each pit
|
||||
|
||||
- change the number of pits
|
||||
|
||||
- only allow capturing if you end on your side of the board
|
||||
|
||||
- don't allow capturing at all
|
||||
|
||||
- don't drop a stone into the enemy "home"
|
||||
|
||||
- go clockwise, instead
|
||||
|
||||
- allow the player to choose to go clockwise or counterclockwise
|
||||
|
||||
- instead of a maximum of two moves, allow each move that ends on the
|
||||
"home" to be followed by a free move.
|
||||
|
||||
- increase the AI lookahead
|
||||
|
||||
- make the scoring heuristic a little more nuanced
|
||||
|
||||
- store history to a file on disk (or in the cloud!) to allow the AI
|
||||
to learn over more than a single session
|
||||
|
||||
"""
|
||||
# PORTING NOTES
|
||||
#
|
||||
# This game started out as 70 lines of BASIC, and I have ported it
|
||||
# before. I find it somewhat amazing how efficient (densely packed) the
|
||||
# original code is. Of course, the original code has fairly cryptic
|
||||
# variable names (as was forced by BASIC's limitation on long (2+
|
||||
# character) variable names). I have done my best here to interpret what
|
||||
# each variable is doing in context, and rename them appropriately.
|
||||
#
|
||||
# I have endeavored to leave the logic of the code in place, as it's
|
||||
# interesting to see a 2-ply game tree evaluation written in BASIC,
|
||||
# along with what a reader in 2021 would call "machine learning".
|
||||
#
|
||||
# As each game is played, the move history is stored as base-6
|
||||
# digits stored losing_book[game_number]. If the human player wins or
|
||||
# draws, the computer increments game_number, effectively "recording"
|
||||
# that loss to be referred to later. As the computer evaluates moves, it
|
||||
# checks the potential game state against these losing game records, and
|
||||
# if the potential move matches with the losing game (up to the current
|
||||
# number of moves), that move is evaluated at a two point penalty.
|
||||
#
|
||||
# Compare this, for example with MENACE, a mechanical device for
|
||||
# "learning" tic-tac-toe:
|
||||
# https://en.wikipedia.org/wiki/Matchbox_Educable_Noughts_and_Crosses_Engine
|
||||
#
|
||||
# The base-6 representation allows game history to be VERY efficiently
|
||||
# represented. I considered whether to rewrite this representation to be
|
||||
# easier to read, but I elected to TRY to document it, instead.
|
||||
#
|
||||
# Another place where I have made a difficult decision between accuracy
|
||||
# and correctness is inside the "wrapping" code where it considers
|
||||
# "while human_move_end > 13". The original BASIC code reads:
|
||||
#
|
||||
# 830 IF L>13 THEN L=L-14:R=1:GOTO 830
|
||||
#
|
||||
# I suspect that the intention is not to assign 1 to R, but to increment
|
||||
# R. I discuss this more in a porting note comment next to the
|
||||
# translated code. If you wish to play a more accurate version of the
|
||||
# game as written in the book, you can convert the increment back to an
|
||||
# assignment.
|
||||
#
|
||||
# I continue to be impressed with this jewel of a game; as soon as I had
|
||||
# the AI playing against me, it was beating me. I've been able to score
|
||||
# a few wins against the computer, but even at its 2-ply lookahead, it
|
||||
# beats me nearly always. I would like to become better at this game to
|
||||
# explore the effectiveness of the "losing book" machine learning.
|
||||
#
|
||||
#
|
||||
# EXERCISES FOR THE READER
|
||||
# One could go many directions with this game:
|
||||
# - change the initial number of stones in each pit
|
||||
# - change the number of pits
|
||||
# - only allow capturing if you end on your side of the board
|
||||
# - don't allow capturing at all
|
||||
# - don't drop a stone into the enemy "home"
|
||||
# - go clockwise, instead
|
||||
# - allow the player to choose to go clockwise or counterclockwise
|
||||
# - instead of a maximum of two moves, allow each move that ends on the
|
||||
# "home" to be followed by a free move.
|
||||
# - increase the AI lookahead
|
||||
# - make the scoring heuristic a little more nuanced
|
||||
# - store history to a file on disk (or in the cloud!) to allow the AI
|
||||
# to learn over more than a single session
|
||||
|
||||
|
||||
game_number = 0
|
||||
|
||||
@@ -16,9 +16,9 @@ my %START_OPTIONS = (
|
||||
|
||||
sub run {
|
||||
# input: no input perameters
|
||||
#
|
||||
#
|
||||
# output: nothing returned
|
||||
#
|
||||
#
|
||||
# description: This is the primary game loop. Once a game is concluded
|
||||
# another will begin right away until the exeecution
|
||||
# is terminated.
|
||||
@@ -32,7 +32,7 @@ sub run {
|
||||
while (1) {
|
||||
write_intro();
|
||||
|
||||
($pile_size, $min_select, $max_select, $win_option, $start_option)
|
||||
($pile_size, $min_select, $max_select, $win_option, $start_option)
|
||||
= &get_user_input();
|
||||
|
||||
if ($pile_size < 0) {
|
||||
@@ -48,9 +48,9 @@ sub run {
|
||||
|
||||
sub write_intro {
|
||||
# input: no input perameters
|
||||
#
|
||||
#
|
||||
# output: nothing returned
|
||||
#
|
||||
#
|
||||
# description: This subroutine prints the intro and rules.
|
||||
|
||||
printf "%33s", "BATNUM\n";
|
||||
@@ -73,15 +73,15 @@ sub write_intro {
|
||||
|
||||
sub get_user_input {
|
||||
# input: no input perameters
|
||||
#
|
||||
#
|
||||
# output: (int) pile_size
|
||||
# (int) min_select
|
||||
# (int) max_select
|
||||
# (int) win_option
|
||||
# (int) start_option
|
||||
#
|
||||
#
|
||||
# description: This subroutine gets the necessary perametes from the player.
|
||||
#
|
||||
#
|
||||
# pile_size (int > 0)
|
||||
# min_select (int > 0) max_select (int > 0)
|
||||
# -> min/max, space delimated
|
||||
@@ -128,9 +128,9 @@ sub play {
|
||||
# (int) max_select
|
||||
# (int) win_option
|
||||
# (int) start_option
|
||||
#
|
||||
#
|
||||
# output: nothing returned
|
||||
#
|
||||
#
|
||||
# description: This is where the game logic lives. The player and computer
|
||||
# both take turns until the current game is over.
|
||||
|
||||
@@ -147,7 +147,7 @@ sub play {
|
||||
if ($players_turn) {
|
||||
($game_over, $pile_size) = players_move(
|
||||
$pile_size, $min_select, $max_select, $win_option);
|
||||
|
||||
|
||||
$players_turn = 0;
|
||||
|
||||
if ($game_over) {
|
||||
@@ -156,7 +156,7 @@ sub play {
|
||||
} else {
|
||||
($game_over, $pile_size) = computers_move(
|
||||
$pile_size, $min_select, $max_select, $win_option);
|
||||
|
||||
|
||||
$players_turn = 1;
|
||||
}
|
||||
}
|
||||
@@ -170,10 +170,10 @@ sub players_move {
|
||||
# (int) min_select
|
||||
# (int) max_select
|
||||
# (int) win_option
|
||||
#
|
||||
#
|
||||
# output: (boolean) game is over
|
||||
# (int) new pile_size
|
||||
#
|
||||
#
|
||||
# description: This subroutine handles the players move.
|
||||
|
||||
my $pile_size = shift;
|
||||
@@ -209,7 +209,7 @@ sub players_move {
|
||||
return (1, $pile_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (0, $pile_size);
|
||||
}
|
||||
|
||||
@@ -219,10 +219,10 @@ sub computers_move {
|
||||
# (int) min_select
|
||||
# (int) max_select
|
||||
# (int) win_option
|
||||
#
|
||||
#
|
||||
# output: (boolean) game is over
|
||||
# (int) new pile_size
|
||||
#
|
||||
#
|
||||
# description: This subroutine handles the computers move.
|
||||
|
||||
my $pile_size = shift;
|
||||
@@ -258,10 +258,10 @@ sub computers_move {
|
||||
sub get_computer_remove_amount {
|
||||
# input: (int) min_select
|
||||
# (int) max_select
|
||||
#
|
||||
# output: (int) random number (x) where,
|
||||
#
|
||||
# output: (int) random number (x) where,
|
||||
# min_select <= x <= max_select
|
||||
#
|
||||
#
|
||||
# description: This subroutine generates the amount of items the computer
|
||||
# will remove.
|
||||
|
||||
|
||||
0
20_Buzzword/java/src/Buzzword.java
Executable file → Normal file
0
20_Buzzword/java/src/Buzzword.java
Executable file → Normal file
@@ -1,24 +1,24 @@
|
||||
/*********************************************************************************
|
||||
* CHECKERS
|
||||
* ported from BASIC https://www.atariarchives.org/basicgames/showpage.php?page=41
|
||||
*
|
||||
*
|
||||
* Porting philosophy
|
||||
* 1) Adhere to the original as much as possible
|
||||
* 2) Attempt to be understandable by Novice progammers
|
||||
*
|
||||
*
|
||||
* There are no classes or Object Oriented design patterns used in this implementation.
|
||||
* Everything is written procedurally, using only top-level functions. Hopefully, this
|
||||
* will be approachable for someone who wants to learn C# syntax without experience with
|
||||
* Object Oriented concepts. Similarly, basic data structures have been chosen over more
|
||||
* powerful collection types. Linq/lambda syntax is also excluded.
|
||||
*
|
||||
*
|
||||
* C# Concepts contained in this example:
|
||||
* Loops (for, foreach, while, and do)
|
||||
* Multidimensional arrays
|
||||
* Tuples
|
||||
* Nullables
|
||||
* IEnumerable (yield return / yield break)
|
||||
*
|
||||
* IEnumerable (yield return / yield break)
|
||||
*
|
||||
* The original had multiple implementations of logic, like determining valid jump locations.
|
||||
* This has been refactored to reduce unnecessary code duplication.
|
||||
*********************************************************************************/
|
||||
@@ -259,7 +259,7 @@ int[,] CrownKingPieces(int[,] state)
|
||||
if (state[to.x, to.y] != 0)
|
||||
// space already occupied by another piece
|
||||
return null;
|
||||
|
||||
|
||||
return to;
|
||||
}
|
||||
/// <summary>
|
||||
@@ -290,7 +290,7 @@ int RankMove(int[,] state, (int x, int y) from, (int x, int y) to)
|
||||
// move to edge of board
|
||||
rank += 1;
|
||||
}
|
||||
// look to the row in front of the potential destination for
|
||||
// look to the row in front of the potential destination for
|
||||
for (int c = -1; c <=1; c+=2)
|
||||
{
|
||||
var inFront = GetLocation(to, (c, -1));
|
||||
@@ -307,7 +307,7 @@ int RankMove(int[,] state, (int x, int y) from, (int x, int y) to)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ((state[inFront.x, inFront.y] > 0) &&
|
||||
if ((state[inFront.x, inFront.y] > 0) &&
|
||||
(state[inBack.x, inBack.y] == 0) || (inBack == from))
|
||||
{
|
||||
// the player can jump us
|
||||
@@ -388,7 +388,7 @@ IEnumerable<(int x, int y)> GetPossibleMoves(int[,] state, (int x, int y) from)
|
||||
/// </summary>
|
||||
((int x, int y) from, (int x, int y) to)? CalculateMove(int[,] state)
|
||||
{
|
||||
var possibleMoves = new List<((int x, int y) from, (int x, int y) to)>();
|
||||
var possibleMoves = new List<((int x, int y) from, (int x, int y) to)>();
|
||||
for (int x = 0; x < 8; x++)
|
||||
{
|
||||
for (int y = 0; y < 8; y++)
|
||||
@@ -477,7 +477,7 @@ IEnumerable<(int x, int y)> GetPossibleMoves(int[,] state, (int x, int y) from)
|
||||
/// <summary>
|
||||
/// Get the move from the player.
|
||||
/// return a tuple of "from" and "to" representing a valid move
|
||||
///
|
||||
///
|
||||
/// </summary>
|
||||
((int x, int y) from, (int x,int y) to) GetPlayerMove(int[,] state)
|
||||
{
|
||||
@@ -498,8 +498,8 @@ IEnumerable<(int x, int y)> GetPossibleMoves(int[,] state, (int x, int y) from)
|
||||
// 3) Select a TO location
|
||||
// 4) If TO is invalid or the implied move is invalid,
|
||||
// return to step 1
|
||||
|
||||
|
||||
|
||||
|
||||
// There is still currently no way for the player to indicate that no move can be made
|
||||
// This matches the original logic, but is a candidate for a refactor
|
||||
|
||||
@@ -585,9 +585,9 @@ int [,] PlayerTurn(int[,] state)
|
||||
#endregion
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
*
|
||||
* Main program starts here
|
||||
*
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
WriteIntroduction();
|
||||
@@ -596,14 +596,14 @@ WriteIntroduction();
|
||||
// set player pieces to 1, computer pieces to -1
|
||||
// turn your head to the right to visualize the board.
|
||||
// kings will be represented by -2 (for computer) and 2 (for player)
|
||||
int[,] state = new int[8, 8] {
|
||||
int[,] state = new int[8, 8] {
|
||||
{ 1, 0, 1, 0, 0, 0,-1, 0 },
|
||||
{ 0, 1, 0, 0, 0,-1, 0,-1 },
|
||||
{ 1, 0, 1, 0, 0, 0,-1, 0 },
|
||||
{ 0, 1, 0, 0, 0,-1, 0,-1 },
|
||||
{ 1, 0, 1, 0, 0, 0,-1, 0 },
|
||||
{ 0, 1, 0, 0, 0,-1, 0,-1 },
|
||||
{ 1, 0, 1, 0, 0, 0,-1, 0 },
|
||||
{ 1, 0, 1, 0, 0, 0,-1, 0 },
|
||||
{ 0, 1, 0, 0, 0,-1, 0,-1 },
|
||||
{ 1, 0, 1, 0, 0, 0,-1, 0 },
|
||||
{ 0, 1, 0, 0, 0,-1, 0,-1 },
|
||||
};
|
||||
|
||||
|
||||
27
38_Fur_Trader/c/furtrader.c
Executable file → Normal file
27
38_Fur_Trader/c/furtrader.c
Executable file → Normal file
@@ -110,10 +110,10 @@ char getYesOrNo()
|
||||
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* Show the player the choices of Fort, get their input, if the
|
||||
* input is a valid choice (1,2,3) return it, otherwise keep
|
||||
* prompting the user.
|
||||
* prompting the user.
|
||||
*/
|
||||
int getFortChoice()
|
||||
{
|
||||
@@ -140,7 +140,7 @@ int getFortChoice()
|
||||
|
||||
|
||||
/*
|
||||
* Print the description for the fort
|
||||
* Print the description for the fort
|
||||
*/
|
||||
void showFortComment( int which_fort )
|
||||
{
|
||||
@@ -172,10 +172,10 @@ void showFortComment( int which_fort )
|
||||
exit( 1 ); /* you have a bug */
|
||||
}
|
||||
print( "" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* Prompt the player for how many of each fur type they want.
|
||||
* Accept numeric inputs, re-prompting on incorrect input values
|
||||
*/
|
||||
@@ -193,7 +193,7 @@ void getFursPurchase( int *furs )
|
||||
furs[i] = getNumericInput();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* (Re)Set the player's inventory to zero
|
||||
@@ -209,7 +209,7 @@ void zeroInventory( int *player_fur_count )
|
||||
|
||||
|
||||
/*
|
||||
* Tally the player's inventory
|
||||
* Tally the player's inventory
|
||||
*/
|
||||
int sumInventory( int *player_fur_count )
|
||||
{
|
||||
@@ -225,7 +225,7 @@ int sumInventory( int *player_fur_count )
|
||||
|
||||
|
||||
/*
|
||||
* Return a random number between a & b
|
||||
* Return a random number between a & b
|
||||
* Ref: https://stackoverflow.com/a/686376/1730895
|
||||
*/
|
||||
float randomAB(float a, float b)
|
||||
@@ -255,7 +255,7 @@ int main( void )
|
||||
char yes_or_no;
|
||||
int event_picker;
|
||||
int which_fort;
|
||||
|
||||
|
||||
/* what part of the game is in play */
|
||||
int game_state = STATE_STARTING;
|
||||
|
||||
@@ -294,12 +294,12 @@ int main( void )
|
||||
exit( 0 ); /* STOP */
|
||||
game_state = STATE_TRADING;
|
||||
}
|
||||
|
||||
|
||||
else if ( game_state == STATE_TRADING )
|
||||
{
|
||||
print( "" );
|
||||
printf( "YOU HAVE $ %1.2f IN SAVINGS\n", player_funds );
|
||||
printf( "AND %d FURS TO BEGIN THE EXPEDITION\n", MAX_FURS );
|
||||
printf( "AND %d FURS TO BEGIN THE EXPEDITION\n", MAX_FURS );
|
||||
getFursPurchase( player_furs );
|
||||
|
||||
if ( sumInventory( player_furs ) > MAX_FURS )
|
||||
@@ -392,7 +392,7 @@ int main( void )
|
||||
beaver_price = ( ( 0.25 * randFloat() + 1.00 ) * 100 + 0.5 ) / 100;
|
||||
if ( fox_price < 0 )
|
||||
{
|
||||
/* Original Bug? There is no Fox price generated for New York,
|
||||
/* Original Bug? There is no Fox price generated for New York,
|
||||
it will use any previous "D1" price.
|
||||
So if there was no previous value, make one up */
|
||||
fox_price = ( ( 0.25 * randFloat() + 1.05 ) * 100 + 0.5 ) / 100; /* not in orginal code */
|
||||
@@ -447,7 +447,7 @@ int main( void )
|
||||
fox_value = fox_price * player_furs[ FUR_FOX ];
|
||||
ermine_value = ermine_price * player_furs[ FUR_ERMINE ];
|
||||
mink_value = mink_price * player_furs[ FUR_MINK ];
|
||||
|
||||
|
||||
print( "" );
|
||||
printf( "YOUR BEAVER SOLD FOR $%6.2f\n", beaver_value );
|
||||
printf( "YOUR FOX SOLD FOR $%6.2f\n", fox_value );
|
||||
@@ -472,4 +472,3 @@ int main( void )
|
||||
|
||||
return 0; /* exit OK */
|
||||
}
|
||||
|
||||
|
||||
@@ -4,47 +4,45 @@ HEXAPAWN
|
||||
A machine learning game, an interpretation of HEXAPAWN game as
|
||||
presented in Martin Gardner's "The Unexpected Hanging and Other
|
||||
Mathematical Diversions", Chapter Eight: A Matchbox Game-Learning
|
||||
Machine.
|
||||
Machine.
|
||||
|
||||
Original version for H-P timeshare system by R.A. Kaapke 5/5/76
|
||||
Instructions by Jeff Dalton
|
||||
Original version for H-P timeshare system by R.A. Kaapke 5/5/76
|
||||
Instructions by Jeff Dalton
|
||||
Conversion to MITS BASIC by Steve North
|
||||
|
||||
|
||||
Port to Python by Dave LeCompte
|
||||
"""
|
||||
|
||||
"""
|
||||
PORTING NOTES:
|
||||
|
||||
I printed out the BASIC code and hand-annotated what each little block
|
||||
of code did, which feels amazingly retro.
|
||||
|
||||
I encourage other porters that have a complex knot of GOTOs and
|
||||
semi-nested subroutines to do hard-copy hacking, it might be a
|
||||
different perspective that helps.
|
||||
|
||||
A spoiler - the objective of the game is not documented, ostensibly to
|
||||
give the human player a challenge. If a player (human or computer)
|
||||
advances a pawn across the board to the far row, that player wins. If
|
||||
a player has no legal moves (either by being blocked, or all their
|
||||
pieces having been captured), that player loses.
|
||||
|
||||
The original BASIC had 2 2-dimensional tables stored in DATA at the
|
||||
end of the program. This encoded all 19 different board configurations
|
||||
(Hexapawn is a small game), with reflections in one table, and then in
|
||||
a parallel table, for each of the 19 rows, a list of legal moves was
|
||||
encoded by turning them into 2-digit decimal numbers. As gameplay
|
||||
continued, the AI would overwrite losing moves with 0 in the second
|
||||
array.
|
||||
|
||||
My port takes this "parallel array" structure and turns that
|
||||
information into a small Python class, BoardLayout. BoardLayout stores
|
||||
the board description and legal moves, but stores the moves as (row,
|
||||
column) 2-tuples, which is easier to read. The logic for checking if a
|
||||
BoardLayout matches the current board, as well as removing losing move
|
||||
have been moved into methods of this class.
|
||||
"""
|
||||
# PORTING NOTES:
|
||||
#
|
||||
# I printed out the BASIC code and hand-annotated what each little block
|
||||
# of code did, which feels amazingly retro.
|
||||
#
|
||||
# I encourage other porters that have a complex knot of GOTOs and
|
||||
# semi-nested subroutines to do hard-copy hacking, it might be a
|
||||
# different perspective that helps.
|
||||
#
|
||||
# A spoiler - the objective of the game is not documented, ostensibly to
|
||||
# give the human player a challenge. If a player (human or computer)
|
||||
# advances a pawn across the board to the far row, that player wins. If
|
||||
# a player has no legal moves (either by being blocked, or all their
|
||||
# pieces having been captured), that player loses.
|
||||
#
|
||||
# The original BASIC had 2 2-dimensional tables stored in DATA at the
|
||||
# end of the program. This encoded all 19 different board configurations
|
||||
# (Hexapawn is a small game), with reflections in one table, and then in
|
||||
# a parallel table, for each of the 19 rows, a list of legal moves was
|
||||
# encoded by turning them into 2-digit decimal numbers. As gameplay
|
||||
# continued, the AI would overwrite losing moves with 0 in the second
|
||||
# array.
|
||||
#
|
||||
# My port takes this "parallel array" structure and turns that
|
||||
# information into a small Python class, BoardLayout. BoardLayout stores
|
||||
# the board description and legal moves, but stores the moves as (row,
|
||||
# column) 2-tuples, which is easier to read. The logic for checking if a
|
||||
# BoardLayout matches the current board, as well as removing losing move
|
||||
# have been moved into methods of this class.
|
||||
|
||||
import collections
|
||||
import random
|
||||
@@ -84,7 +82,7 @@ HEXAPAWN IS PLAYED WITH CHESS PAWNS ON A 3 BY 3 BOARD.
|
||||
THE PAWNS ARE MOVED AS IN CHESS - ONE SPACE FORWARD TO
|
||||
AN EMPTY SPACE OR ONE SPACE FORWARD AND DIAGONALLY TO
|
||||
CAPTURE AN OPPOSING MAN. ON THE BOARD, YOUR PAWNS
|
||||
ARE 'O', THE COMPUTER'S PAWNS ARE 'X', AND EMPTY
|
||||
ARE 'O', THE COMPUTER'S PAWNS ARE 'X', AND EMPTY
|
||||
SQUARES ARE '.'. TO ENTER A MOVE, TYPE THE NUMBER OF
|
||||
THE SQUARE YOU ARE MOVING FROM, FOLLOWED BY THE NUMBER
|
||||
OF THE SQUARE YOU WILL MOVE TO. THE NUMBERS MUST BE
|
||||
@@ -238,7 +236,7 @@ def get_coordinates():
|
||||
try:
|
||||
print("YOUR MOVE?")
|
||||
response = input()
|
||||
m1, m2 = [int(c) for c in response.split(",")]
|
||||
m1, m2 = (int(c) for c in response.split(","))
|
||||
return m1, m2
|
||||
except ValueError as ve:
|
||||
print_illegal()
|
||||
|
||||
@@ -6,4 +6,4 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rand = "0.8.5"
|
||||
rand = "0.8.5"
|
||||
|
||||
@@ -1,3 +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)
|
||||
Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)
|
||||
|
||||
@@ -25,7 +25,7 @@ impl CODE {
|
||||
//generate random combination of colors
|
||||
for _i in 0..num_positions {
|
||||
code.code.push(rng.gen_range(0..num_colors));
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
/**
|
||||
@@ -55,7 +55,7 @@ impl CODE {
|
||||
let valid_chars = &LETTERS[0..num_colors];
|
||||
//DATA
|
||||
let new_code = CODE{
|
||||
code:
|
||||
code:
|
||||
input_string.to_ascii_uppercase().chars() //get an iterator with all the chars in input string converted to uppercase
|
||||
.filter( |c| { valid_chars.contains(*c)}) //remove chars that aren't in LETTERS
|
||||
.map( |x| -> usize {valid_chars.find(x).expect("invalid character")})//convert all the chars into usizes representing their index in LETTERS
|
||||
@@ -153,7 +153,7 @@ fn main() {
|
||||
|
||||
//game loop
|
||||
for round_num in 1..=num_rounds {
|
||||
//data
|
||||
//data
|
||||
let mut num_moves: usize = 1;
|
||||
let mut answer: CODE;
|
||||
let mut guess: GUESS;
|
||||
@@ -189,16 +189,16 @@ fn main() {
|
||||
io::stdin().read_line(&mut raw_input).expect("CANNOT READ INPUT!"); //read user input from standard input and store it to raw_input
|
||||
|
||||
//attempt to parse input
|
||||
if raw_input.trim().eq_ignore_ascii_case("board") {
|
||||
if raw_input.trim().eq_ignore_ascii_case("board") {
|
||||
//print the board state
|
||||
print_board(&guesses);
|
||||
continue; //run loop again
|
||||
}
|
||||
else if raw_input.trim().eq_ignore_ascii_case("quit") {
|
||||
else if raw_input.trim().eq_ignore_ascii_case("quit") {
|
||||
//quit the game
|
||||
println!("QUITTER! MY COMBINATION WAS: {}\nGOOD BYE", answer._as_human_readible_words());
|
||||
return; //exit the game
|
||||
}
|
||||
}
|
||||
else {
|
||||
//parse input for a code
|
||||
match CODE::new_from_string(raw_input, num_colors) {
|
||||
@@ -244,14 +244,14 @@ fn main() {
|
||||
io::stdin().read_line(&mut raw_input).expect("CANNOT READ INPUT!"); //read user input from standard input and store it to raw_input
|
||||
|
||||
//attempt to create a code from the user input, if successful break the loop returning the code
|
||||
if let Some(code) = CODE::new_from_string(raw_input, num_colors) {
|
||||
if let Some(code) = CODE::new_from_string(raw_input, num_colors) {
|
||||
if code.code.len() == num_positions {break code;} //exit loop with code
|
||||
else {println!("CODE MUST HAVE {} POSITIONS", num_positions);continue;} //tell them to try again
|
||||
}
|
||||
}
|
||||
|
||||
println!("INVALID CODE. TRY AGAIN"); //if unsuccessful, this is printed and the loop runs again
|
||||
};
|
||||
|
||||
|
||||
//reset some things in preparation for computer play
|
||||
guesses.clear();
|
||||
num_moves = 0;
|
||||
@@ -276,28 +276,28 @@ fn main() {
|
||||
if all_possibilities[guess_int] {
|
||||
guess = GUESS::new(CODE::new_from_int(guess_int, num_colors, num_positions)); //create guess
|
||||
}
|
||||
else {//if it's not possible:
|
||||
else {//if it's not possible:
|
||||
// search all possibilities after guess, use first valid one //790
|
||||
for g in guess_int..total_posibilities {
|
||||
if all_possibilities[g] {
|
||||
if all_possibilities[g] {
|
||||
guess_int=g;
|
||||
guess = GUESS::new(CODE::new_from_int(guess_int, num_colors, num_positions)); //create guess
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//if none was found
|
||||
// search all possibilities before guess, use first valid one //820
|
||||
if guess.code.code.is_empty() {
|
||||
if guess.code.code.is_empty() {
|
||||
for g in (0..guess_int).rev() {
|
||||
if all_possibilities[g] {
|
||||
if all_possibilities[g] {
|
||||
guess_int=g;
|
||||
guess = GUESS::new(CODE::new_from_int(guess_int, num_colors, num_positions)); //create guess
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if none where found, tell the user and start over #850
|
||||
if guess.code.code.is_empty() {
|
||||
if guess.code.code.is_empty() {
|
||||
println!("YOU HAVE GIVEN ME INCONSISTENT INFORMATION.");
|
||||
println!("PLAY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.");
|
||||
return; //exit game
|
||||
@@ -348,8 +348,8 @@ fn welcome() {
|
||||
println!("
|
||||
MASTERMIND
|
||||
CREATIVE COMPUTING MORRISTOWN, NEW JERSEY
|
||||
|
||||
|
||||
|
||||
|
||||
");
|
||||
}
|
||||
|
||||
@@ -418,4 +418,4 @@ fn get_number_from_user_input<T: Display + PartialOrd + FromStr>(prompt: &str, e
|
||||
//this is only reached if a number couldn't be parsed from the input
|
||||
if !error_message.is_empty() {println!("{}",error_message);} //if they gave an error message to use, print it
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,11 @@ Math exercise/demonstration
|
||||
Ported by Dave LeCompte
|
||||
"""
|
||||
|
||||
"""
|
||||
PORTING NOTE
|
||||
|
||||
The title, as printed ingame, is "NICOMA", hinting at a time when
|
||||
filesystems weren't even 8.3, but could only support 6 character
|
||||
filenames.
|
||||
"""
|
||||
# PORTING NOTE
|
||||
#
|
||||
# The title, as printed ingame, is "NICOMA", hinting at a time when
|
||||
# filesystems weren't even 8.3, but could only support 6 character
|
||||
# filenames.
|
||||
|
||||
import time
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::io;
|
||||
fn main() {
|
||||
//DATA
|
||||
let mut points: usize = 100;
|
||||
let mut rng = thread_rng();
|
||||
let mut rng = thread_rng();
|
||||
let mut number:u8;
|
||||
|
||||
//print welcome message
|
||||
@@ -39,7 +39,7 @@ fn main() {
|
||||
println!("YOU HAVE {} POINTS.", points);
|
||||
}
|
||||
|
||||
//print
|
||||
//print
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,7 +57,6 @@ fn welcome() {
|
||||
|
||||
YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)
|
||||
YOUR POINT COUNT. YOU WIN WHEN YOU GET 500 POINTS
|
||||
|
||||
|
||||
");
|
||||
}
|
||||
|
||||
|
||||
@@ -6,14 +6,12 @@ A poetry generator
|
||||
Ported by Dave LeCompte
|
||||
"""
|
||||
|
||||
"""
|
||||
PORTING EDITORIAL NOTE:
|
||||
|
||||
The original code is a pretty convoluted mesh of GOTOs and global
|
||||
state. This adaptation pulls things apart into phrases, but I have
|
||||
left the variables as globals, which makes goes against decades of
|
||||
wisdom that global state is bad.
|
||||
"""
|
||||
# PORTING EDITORIAL NOTE:
|
||||
#
|
||||
# The original code is a pretty convoluted mesh of GOTOs and global
|
||||
# state. This adaptation pulls things apart into phrases, but I have
|
||||
# left the variables as globals, which makes goes against decades of
|
||||
# wisdom that global state is bad.
|
||||
|
||||
PAGE_WIDTH = 64
|
||||
|
||||
|
||||
Reference in New Issue
Block a user