mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-05 20:40:25 -08:00
Added MiniScript version of 27_Civil_War.
This commit is contained in:
16
00_Alternate_Languages/27_Civil_War/MiniScript/README.md
Normal file
16
00_Alternate_Languages/27_Civil_War/MiniScript/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html).
|
||||
|
||||
Conversion to [MiniScript](https://miniscript.org).
|
||||
|
||||
Ways to play:
|
||||
|
||||
1. Command-Line MiniScript:
|
||||
Download for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as:
|
||||
|
||||
miniscript civilwar.ms
|
||||
|
||||
2. Mini Micro:
|
||||
Download Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose "Mount Folder..." Select the folder containing the BASIC program. Then, at the Mini Micro command prompt, enter:
|
||||
|
||||
load "civilwar"
|
||||
run
|
||||
437
00_Alternate_Languages/27_Civil_War/MiniScript/civilwar.ms
Normal file
437
00_Alternate_Languages/27_Civil_War/MiniScript/civilwar.ms
Normal file
@@ -0,0 +1,437 @@
|
||||
print " "*26 + "Civil War"
|
||||
print " "*15 + "Creative Computing Morristown, New Jersey"
|
||||
print; print; print
|
||||
// ORIGINAL GAME DESIGN: CRAM, GOODIE, HIBBARD LEXINGTON H.S.
|
||||
// MODIFICATIONS: G. PAUL, R. HESS (TIES), 1973
|
||||
// Conversion to MiniScript: J. Strout, 2023
|
||||
|
||||
sides = ["Confederate", "Union"]
|
||||
|
||||
getYesNo = function(prompt)
|
||||
while true
|
||||
yn = input(prompt + "? ").lower
|
||||
if yn and yn[0] == "y" then return "YES"
|
||||
if yn and yn[0] == "n" then return "NO"
|
||||
print "Yes or no -- "
|
||||
end while
|
||||
end function
|
||||
|
||||
instructions = function
|
||||
print; print; print; print
|
||||
print "This is a civil war simulation."
|
||||
print "To play type a response when the computer asks."
|
||||
print "Remember that all factors are interrelated and that your"
|
||||
print "responses could change history. Facts and figures used are"
|
||||
print "based on the actual occurrence. Most battles tend to result"
|
||||
print "as they did in the civil war, but it all depends on you!!"
|
||||
print
|
||||
print "The object of the game is to win as many battles as ";
|
||||
print "possible."
|
||||
print
|
||||
print "Your choices for defensive strategy are:"
|
||||
print " (1) artillery attack"
|
||||
print " (2) fortification against frontal attack"
|
||||
print " (3) fortification against flanking maneuvers"
|
||||
print " (4) falling back"
|
||||
print " Your choices for offensive strategy are:"
|
||||
print " (1) artillery attack"
|
||||
print " (2) frontal attack"
|
||||
print " (3) flanking maneuvers"
|
||||
print " (4) encirclement"
|
||||
print "You may surrender by typing a '5' for your strategy."
|
||||
end function
|
||||
|
||||
historicalBattles = []
|
||||
addBattle = function(name, men0, men1, cas0, cas1, offDef, desc)
|
||||
battle = {}
|
||||
battle.name = name
|
||||
battle.men = [men0, men1]
|
||||
battle.casualties = [cas0, cas1]
|
||||
battle.offDef = offDef // 1=Confederate Defense, 2=both Offense, 3=Confederate Offense
|
||||
battle.description = desc
|
||||
historicalBattles.push battle
|
||||
end function
|
||||
|
||||
loadData = function
|
||||
// Historical data
|
||||
addBattle "Bull Run",18000,18500,1967,2708,1, [
|
||||
"July 21, 1861. Gen. Beauregard, commanding the South, met",
|
||||
"Union forces with Gen. Mcdowell in a premature battle at",
|
||||
"Bull Run. Gen. Jackson helped push back the Union attack."]
|
||||
|
||||
addBattle "Shiloh",40000.,44894.,10699,13047,3, [
|
||||
"April 6-7, 1862. The Confederate surprise attack at",
|
||||
"Shiloh failed due to poor organization."]
|
||||
|
||||
addBattle "Seven Days",95000.,115000.,20614,15849,3, [
|
||||
"June 25-july 1, 1862. General Lee (CSA) upheld the",
|
||||
"offensive throughout the battle and forced Gen. McClellan",
|
||||
"and the Union forces away from Richmond."]
|
||||
|
||||
addBattle "Second Bull Run",54000.,63000.,10000,14000,2, [
|
||||
"Aug 29-30, 1862. The combined Confederate forces under Lee",
|
||||
"and Jackson drove the Union forces back into washington."]
|
||||
|
||||
addBattle "Antietam",40000.,50000.,10000,12000,3, [
|
||||
"Sept 17, 1862. The South failed to incorporate Maryland",
|
||||
"into the Confederacy."]
|
||||
|
||||
addBattle "Fredericksburg",75000.,120000.,5377,12653,1, [
|
||||
"Dec 13, 1862. The Confederacy under Lee successfully",
|
||||
"repulsed an attack by the Union under Gen. Burnside."]
|
||||
|
||||
addBattle "Murfreesboro",38000.,45000.,11000,12000,1, [
|
||||
"Dec 31, 1862. The South under Gen. Bragg won a close battle."]
|
||||
|
||||
addBattle "Chancellorsville",32000,90000.,13000,17197,2, [
|
||||
"May 1-6, 1863. The South had a costly victory and lost",
|
||||
"one of their outstanding generals, 'Stonewall' Jackson."]
|
||||
|
||||
addBattle "Vicksburg",50000.,70000.,12000,19000,1, [
|
||||
"July 4, 1863. Vicksburg was a costly defeat for the South",
|
||||
"because it gave the Union access to the Mississippi."]
|
||||
|
||||
addBattle "Gettysburg",72500.,85000.,20000,23000,3, [
|
||||
"July 1-3, 1863. A Southern mistake by Gen. Lee at Gettysburg",
|
||||
"cost them one of the most crucial battles of the war."]
|
||||
|
||||
addBattle "Chickamauga",66000.,60000.,18000,16000,2, [
|
||||
"Sept. 15, 1863. Confusion in a forest near Chickamauga led",
|
||||
"to a costly Southern victory."]
|
||||
|
||||
addBattle "Chattanooga",37000.,60000.,36700.,5800,2, [
|
||||
"Nov. 25, 1863. After the South had sieged Gen. Rosencrans'",
|
||||
"army for three months, Gen. Grant broke the siege."]
|
||||
|
||||
addBattle "Spotsylvania",62000.,110000.,17723,18000,2, [
|
||||
"May 5, 1864. Grant's plan to keep Lee isolated began to",
|
||||
"fail here, and continued at Cold Harbor and Petersburg."]
|
||||
|
||||
addBattle "Atlanta",65000.,100000.,8500,3700,1, [
|
||||
"August, 1864. Sherman and three veteran armies converged",
|
||||
"on Atlanta and dealt the death blow to the Confederacy."]
|
||||
|
||||
end function
|
||||
|
||||
setup = function
|
||||
print; print; print
|
||||
if getYesNo("Are there two generals present") == "YES" then
|
||||
globals.numPlayers = 2
|
||||
else
|
||||
globals.numPlayers = 1
|
||||
print; print "You are the Confederacy. Good luck!"
|
||||
print
|
||||
end if
|
||||
print "Select a battle by typing a number from 1 to 14 on"
|
||||
print "request. Type any other number to end the simulation."
|
||||
print "But '0' brings back exact previous battle situation"
|
||||
print "allowing you to replay it."
|
||||
print
|
||||
print "Note: a negative food$ entry causes the program to "
|
||||
print "use the entries from the previous battle."
|
||||
print
|
||||
yn = getYesNo("After requesting a battle, do you wish battle descriptions")
|
||||
globals.battleDesc = (yn == "YES")
|
||||
end function
|
||||
|
||||
// Game variables -- the 2-element arrays below represent the stats for
|
||||
// player 0 (Confederacy) and 1 (Union)
|
||||
D = [0,0] // money
|
||||
F = [0,0] // food budget
|
||||
H = [0,0] // salary budget
|
||||
B = [0,0] // ammo budget
|
||||
men = [0,0] // men at start of battle? (M1, M2)
|
||||
menAdded = [0,0] // men added (M3, M4)
|
||||
menAvail = [0,0] // men available (M5, M6)
|
||||
P = [0,0] // casualties?
|
||||
T = [0,0] // total losses?
|
||||
resources = [0,0] // total resources (money) available to each side (R1, R2)
|
||||
spending = [0,0] // total expenditures for each side (Q1, Q2)
|
||||
morale = [0,0] // troop morale (O)
|
||||
strategy = [0,0] // strategy choice (Y1, Y2)
|
||||
inflation = [0,0] // inflation (I1, I2)
|
||||
|
||||
R = 0 // previous battle
|
||||
losses = 0 // Confederate losses
|
||||
wins = 0 // Confederate wins
|
||||
unresolved = 0 // battles where neither side clearly won
|
||||
|
||||
printInColumns = function(a, b, c)
|
||||
print (a + " "*20)[:20] + (b + " "*16)[:16] + c
|
||||
end function
|
||||
|
||||
pickBattle = function
|
||||
print; print; print
|
||||
globals.replay = false
|
||||
while true
|
||||
num = input("Which battle do you wish to simulate? ").val
|
||||
if num == 0 and R > 0 then
|
||||
num = R
|
||||
globals.replay = true
|
||||
end if
|
||||
if 0 < num <= historicalBattles.len then break
|
||||
end while
|
||||
globals.bat = historicalBattles[num - 1]
|
||||
if not replay then
|
||||
men[0] = bat.men[0]
|
||||
men[1] = bat.men[1]
|
||||
|
||||
// inflation calc
|
||||
inflation[0] = 10 + (losses - wins) * 2
|
||||
inflation[1] = 10 + (wins - losses) * 2
|
||||
|
||||
// money available
|
||||
D[0] = 100 * floor((men[0]*(100-inflation[0])/2000) * (1+(resources[0]-spending[0])/(resources[0]+1))+0.5)
|
||||
D[1] = 100 * floor(men[1]*(100-inflation[1])/2000 + 0.5)
|
||||
if numPlayers == 2 then
|
||||
D[1] = 100 * floor((men[1]*(100-inflation[1])/2000) * (1+(resources[1]-spending[1])/(resources[1]+1))+0.5)
|
||||
end if
|
||||
|
||||
// men available
|
||||
menAvail[0] = floor(men[0]*(1 + (P[0]-T[0])/(menAdded[0]+1)))
|
||||
menAvail[1] = floor(men[1]*(1 + (P[1]-T[1])/(menAdded[1]+1)))
|
||||
globals.F1 = 5/6 * men[0] // ?!?
|
||||
print; print; print; print; print
|
||||
print "P:" + P + "; T:" + T + "; menAdded:" + menAdded
|
||||
print "men[0]:" + men[0] + " ...F1:" + F1
|
||||
|
||||
print "This is the battle of " + bat.name
|
||||
if battleDesc then
|
||||
for line in bat.description
|
||||
print line
|
||||
end for
|
||||
end if
|
||||
else
|
||||
print bat.name + " Instant Replay"
|
||||
end if
|
||||
print
|
||||
printInColumns " ", "CONFEDERACY", " UNION"
|
||||
printInColumns "MEN", " "+menAvail[0], " "+menAvail[1]
|
||||
printInColumns "MONEY", "$ "+D[0], "$ "+D[1]
|
||||
printInColumns "INFLATION", " "+(inflation[0]+15)+" %", " " +inflation[1]+" %"
|
||||
// (Note: printout lies and shows confederate inflation 15% higher than actual)
|
||||
print
|
||||
end function
|
||||
|
||||
getBudget = function(player)
|
||||
print sides[player] + " General---How much do you wish to spend for"
|
||||
getNum = function(prompt, allowNegative)
|
||||
while true
|
||||
n = input(prompt)
|
||||
if not n then continue
|
||||
if n[-1] == "k" then n = n[:-1] + "000" // (allow entries like "60k")
|
||||
if n.val >= 0 or allowNegative then return n.val
|
||||
print "Negative values are not allowed."
|
||||
end while
|
||||
end function
|
||||
|
||||
while true
|
||||
f = getNum(" - Food......? ", true)
|
||||
if f < 0 then
|
||||
if resources[player] == 0 then
|
||||
print "No previous entries."
|
||||
print "How much do you wish to spend for"
|
||||
continue
|
||||
end if
|
||||
break // keep all previous entries
|
||||
end if
|
||||
F[player] = f
|
||||
H[player] = getNum(" - Salaries..? ", false)
|
||||
B[player] = getNum(" - Ammunition? ", false)
|
||||
if F[player] + H[player] + B[player] <= D[player] then break
|
||||
print "Think again! You have only $" + D[player]
|
||||
end while
|
||||
end function
|
||||
|
||||
calcMorale = function(player)
|
||||
m = ((2*F[player]^2 + H[player]^2) / F1^2 + 1)
|
||||
print (" "*11 + sides[player])[-11:], " "
|
||||
if m >= 10 then
|
||||
print "morale is high"
|
||||
else if m >= 5 then
|
||||
print "morale is fair"
|
||||
else
|
||||
print "morale is poor"
|
||||
end if
|
||||
morale[player] = m
|
||||
end function
|
||||
|
||||
getStrategy = function(player)
|
||||
if numPlayers == 1 then prompt = "Your strategy" else prompt = sides[player] + " strategy"
|
||||
while true
|
||||
strat = input(prompt + "? ").val
|
||||
if 0 < strat < 6 then break
|
||||
print "Strategy " + strat + " not allowed."
|
||||
end while
|
||||
strategy[player] = strat
|
||||
if strat == 5 then
|
||||
print "The " + ["Confederacy", "Union"][player] + " has surrendered."
|
||||
globals.gameOver = true
|
||||
end if
|
||||
end function
|
||||
|
||||
calcComputerStrategy = function
|
||||
// Union strategy is computer chosen
|
||||
print "Union strategy is ", ""
|
||||
s0 = 0
|
||||
r = 100 * rnd
|
||||
for i in range(0, 3)
|
||||
s0 += unionStrats[i]
|
||||
if r < s0 then
|
||||
strategy[1] = i+1
|
||||
break
|
||||
end if
|
||||
end for
|
||||
print strategy[1]
|
||||
end function
|
||||
|
||||
learnStrategy = function
|
||||
// Learn present strategy, start forgetting old ones.
|
||||
// - Present strategy of south gains 3*s, others lose s
|
||||
// probability points, unless a strategy falls below 5%.
|
||||
s = 3; s0 = 0
|
||||
for i in range(0,3)
|
||||
if unionStrats[i] < 5 then continue
|
||||
unionStrats[i] -= s
|
||||
s0 += s
|
||||
end for
|
||||
unionStrats[strategy[1]-1] += s0
|
||||
end function
|
||||
|
||||
doBattle = function
|
||||
U = 0; U2 = 0
|
||||
// simulated losses -- North
|
||||
C6 = (2 * bat.casualties[1]/5) * (1+1/(2*(abs(strategy[1]-strategy[0])+1)))
|
||||
C6 = C6 * (1.28 + (5*men[1]/6) / (B[1]+1))
|
||||
C6 = floor(C6 * (1+1/morale[1]) + .5)
|
||||
// - IF LOSS > MEN PRESENT, RESCALE LOSSES
|
||||
E2 = 100/morale[1] // desertions (Union)
|
||||
if floor(C6 + E2) >= menAvail[1] then
|
||||
C6 = floor(13*menAvail[1]/20)
|
||||
E2 = 7 * C6/13
|
||||
U2=1 // Union loss
|
||||
end if
|
||||
// simulated losses -- South
|
||||
C5 = (2 * bat.casualties[0]/5) * (1+1/(2*(abs(strategy[1]-strategy[0])+1)))
|
||||
print "step A:" + C5
|
||||
C5 = floor(C5 * (1+1/morale[0])*(1.28+F1/(B[0]+1))+.5)
|
||||
print "step B:" + C5
|
||||
print "based on morale[0]:"+morale[0]+", F1:"+F1+", B[0]:"+B[0]
|
||||
E=100/morale[0]
|
||||
if C5+100/morale[0] >= men[0]*(1+(P1-T1)/(menAdded[0]+1)) then
|
||||
C5 = floor(13*men[0]/20 * (1+(P1-T1)/(menAdded[0]+1)))
|
||||
print "step C:" + C5
|
||||
print "men: " + men; print "menAdded: " + menAdded; print "P1,T1:" + P1 + "," + T1
|
||||
E=7*C5/13 // desertions (Confed)
|
||||
U=1 // Confederate loss
|
||||
end if
|
||||
print
|
||||
print; print; printInColumns "", "CONFEDERACY", "UNION"
|
||||
if numPlayers == 1 then
|
||||
C6 = floor(17 * bat.casualties[1] * bat.casualties[0] / (C5*20))
|
||||
E2 = 5 * morale[0]
|
||||
end if
|
||||
printInColumns "CASUALTIES", C5, C6
|
||||
printInColumns "DESERTIONS", floor(E), floor(E2)
|
||||
print
|
||||
if numPlayers == 2 then
|
||||
print "Compared to the actual casualties at " + bat.name
|
||||
print "Confederate: " + round(100*C5/bat.casualties[0]) + "% of the original"
|
||||
print "Union: " + round(100*C6/bat.casualties[1]) + "% of the original"
|
||||
print
|
||||
// Who won?
|
||||
print "U:"+U+ " U2:"+U2
|
||||
if (U == 1 and U2 != 1) or (U == U2 and C5+E > C6+E2) then
|
||||
print "The Union wins " + bat.name
|
||||
globals.losses += 1
|
||||
else if (U2 == 1 and U != 1) or (U == U2 and C5+E < C6+E2) then
|
||||
print "The confederacy wins " + bat.name
|
||||
globals.wins += 1
|
||||
else
|
||||
print "Battle outcome unresolved"
|
||||
globals.unresolved += 1
|
||||
end if
|
||||
else
|
||||
print "Your casualties were " + round(100*C5/bat.casualties[0]) + "% of"
|
||||
print "the actual casualties at " + bat.name
|
||||
print
|
||||
if U == 1 or C5+E >= 17*bat.casualties[1]*bat.casualties[0]/(C5*20)+5*morale[0] then
|
||||
print "You lose " + bat.name
|
||||
if not replay then globals.losses += 1
|
||||
else
|
||||
print "You win " + bat.name
|
||||
if not replay then globals.wins += 1
|
||||
end if
|
||||
end if
|
||||
if not replay then
|
||||
// Cumulative battle factors which alter historical
|
||||
// resources availeble. (If a replay, don't update.)
|
||||
T[0] += C5 + E
|
||||
T[1] += C6 + E2
|
||||
P[0] += bat.casualties[0]
|
||||
P[1] += bat.casualties[1]
|
||||
spending[0] += F[0] + H[0] + B[0]
|
||||
spending[1] += F[1] + H[1] + B[1]
|
||||
resources[0] += men[0]*(100-inflation[0])/20
|
||||
resources[1] += men[1]*(100-inflation[1])/20
|
||||
menAdded[0] += men[0]
|
||||
menAdded[1] += men[1]
|
||||
|
||||
learnStrategy
|
||||
end if
|
||||
print "---------------"
|
||||
end function
|
||||
|
||||
// Main Program
|
||||
loadData
|
||||
unionStrats = [25, 25, 25, 25]
|
||||
P1=0; P2=0; T1=0; T2=0 // cumulative stat thingies
|
||||
print
|
||||
if getYesNo("Do you want instructions") == "YES" then instructions
|
||||
setup
|
||||
gameOver = false
|
||||
while not gameOver
|
||||
pickBattle
|
||||
if gameOver then break
|
||||
for i in range(0, numPlayers-1)
|
||||
getBudget i
|
||||
end for
|
||||
for i in range(0, numPlayers-1)
|
||||
calcMorale i
|
||||
end for
|
||||
print "Confederate General---", ""
|
||||
if bat.offDef == 3 then
|
||||
print "you are on the offensive"
|
||||
else if bat.offDef == 1 then
|
||||
print "you are on the defensive"
|
||||
else
|
||||
print "both sides are on the offensive "
|
||||
end if
|
||||
print
|
||||
getStrategy 0
|
||||
if numPlayers == 2 then getStrategy 1 else calcComputerStrategy
|
||||
if gameOver then break
|
||||
doBattle
|
||||
end while
|
||||
|
||||
// Finish off
|
||||
print; print; print; print; print; print
|
||||
print "The Confederacy has won " + wins + " battles and lost " + losses
|
||||
if strategy[0] == 5 or (strategy[1] != 5 and losses > wins) then
|
||||
print "The Union has won the war"
|
||||
else
|
||||
print "The Confederacy has won the war"
|
||||
end if
|
||||
print "For the " + (wins + losses + unresolved) + " battles fought (excluding reruns)"
|
||||
print
|
||||
printInColumns "", "Confederacy", "Union"
|
||||
printInColumns "Historical Losses", round(P[0]), round(P[1])
|
||||
printInColumns "Simulated Losses", round(T[0]), round(T[1])
|
||||
print
|
||||
printInColumns " % of Original", round(100*T[0]/P[0]), round(100*T[1]/P[1])
|
||||
if numPlayers == 1 then
|
||||
print
|
||||
print "Union intelligence suggsets that the South used "
|
||||
print "strategies 1, 2, 3, 4 in the following percentages"
|
||||
print unionStrats.join
|
||||
end if
|
||||
@@ -17,6 +17,10 @@ As published in Basic Computer Games (1978):
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
#### Known Bugs
|
||||
|
||||
- At the end of a single-player game, the program reports strategies used by "THE SOUTH", but these are in fact strategies used by the North (the computer player) -- the South is always a human player.
|
||||
|
||||
#### Porting Notes
|
||||
|
||||
(please note any difficulties or challenges in porting here)
|
||||
|
||||
Reference in New Issue
Block a user