mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 23:26:40 -08:00
Football (Python): Added
This commit is contained in:
@@ -1,3 +1,30 @@
|
|||||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||||
|
|
||||||
Conversion to [Python](https://www.python.org/about/)
|
Conversion to [Python](https://www.python.org/about/)
|
||||||
|
|
||||||
|
|
||||||
|
## Porting notes
|
||||||
|
|
||||||
|
Variables:
|
||||||
|
|
||||||
|
* E: score_limit
|
||||||
|
* H(2): Scores
|
||||||
|
* T(2): Team toggle
|
||||||
|
* T: team who currently possesses the ball
|
||||||
|
* L: Offset
|
||||||
|
* P: Who has the ball
|
||||||
|
* K: yards
|
||||||
|
* R: Runback current team in yards
|
||||||
|
* P$(20): Actions (see data.json)
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
* `P$(I)`: Access index `I` of the `P` array
|
||||||
|
* ABS: abs (absolute value)
|
||||||
|
* RND(1): random()
|
||||||
|
* GOSUB: Execute a function - will jump back to this
|
||||||
|
* GOTO: Just jump
|
||||||
|
|
||||||
|
Patterns:
|
||||||
|
|
||||||
|
* `T=T(T)`: Toggle the team who currently has the ball
|
||||||
|
|||||||
9
37_Football/python/data.json
Normal file
9
37_Football/python/data.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"players": [17,8,4,14,19,3,10,1,7,11,15,9,5,20,13,18,16,2,12,6,
|
||||||
|
20,2,17,5,8,18,12,11,1,4,19,14,10,7,9,15,6,13,16,3],
|
||||||
|
"actions": ["PITCHOUT","TRIPLE REVERSE","DRAW","QB SNEAK","END AROUND",
|
||||||
|
"DOUBLE REVERSE","LEFT SWEEP","RIGHT SWEEP","OFF TACKLE",
|
||||||
|
"WISHBONE OPTION","FLARE PASS","SCREEN PASS",
|
||||||
|
"ROLL OUT OPTION","RIGHT CURL","LEFT CURL","WISHBONE OPTION",
|
||||||
|
"SIDELINE PASS","HALF-BACK OPTION","RAZZLE-DAZZLE","BOMB!!!!"]
|
||||||
|
}
|
||||||
453
37_Football/python/football.py
Normal file
453
37_Football/python/football.py
Normal file
@@ -0,0 +1,453 @@
|
|||||||
|
"""
|
||||||
|
FOOTBALL
|
||||||
|
|
||||||
|
A game.
|
||||||
|
|
||||||
|
Ported to Python by Martin Thoma in 2022.
|
||||||
|
The JavaScript version by Oscar Toledo G. (nanochess) was used
|
||||||
|
"""
|
||||||
|
# NOTE: The newlines might be wrong
|
||||||
|
|
||||||
|
import json
|
||||||
|
from math import floor
|
||||||
|
from pathlib import Path
|
||||||
|
from random import randint, random
|
||||||
|
from typing import List, Tuple
|
||||||
|
|
||||||
|
with open(Path(__file__).parent / "data.json") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
player_data = [num - 1 for num in data["players"]]
|
||||||
|
actions = data["actions"]
|
||||||
|
|
||||||
|
|
||||||
|
aa: List[int] = [-100 for _ in range(20)]
|
||||||
|
ba: List[int] = [-100 for _ in range(20)]
|
||||||
|
ca: List[int] = [-100 for _ in range(40)]
|
||||||
|
score: List[int] = [0, 0]
|
||||||
|
ta: Tuple[int, int] = (1, 0)
|
||||||
|
wa: Tuple[int, int] = (-1, 1)
|
||||||
|
xa: Tuple[int, int] = (100, 0)
|
||||||
|
ya: Tuple[int, int] = (1, -1)
|
||||||
|
za: Tuple[int, int] = (0, 100)
|
||||||
|
marker: Tuple[str, str] = ("--->", "<---")
|
||||||
|
t: int = 0
|
||||||
|
p: int = 0
|
||||||
|
winning_score: int
|
||||||
|
|
||||||
|
|
||||||
|
def ask_bool(prompt: str) -> bool:
|
||||||
|
while True:
|
||||||
|
answer = input(prompt).lower()
|
||||||
|
if answer in ["yes", "y"]:
|
||||||
|
return True
|
||||||
|
elif answer in ["no", "n"]:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def ask_int(prompt: str) -> int:
|
||||||
|
while True:
|
||||||
|
answer = input(prompt)
|
||||||
|
try:
|
||||||
|
int_answer = int(answer)
|
||||||
|
return int_answer
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def get_offense_defense() -> Tuple[int, int]:
|
||||||
|
while True:
|
||||||
|
input_str = input("INPUT OFFENSIVE PLAY, DEFENSIVE PLAY: ")
|
||||||
|
try:
|
||||||
|
p1, p2 = (int(n) for n in input_str.split(","))
|
||||||
|
return p1, p2
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def field_headers() -> None:
|
||||||
|
print("TEAM 1 [0 10 20 30 40 50 60 70 80 90 100] TEAM 2")
|
||||||
|
print("\n\n")
|
||||||
|
|
||||||
|
|
||||||
|
def separator() -> None:
|
||||||
|
print("+" * 72 + "\n")
|
||||||
|
|
||||||
|
|
||||||
|
def show_ball() -> None:
|
||||||
|
da: Tuple[int, int] = (0, 3)
|
||||||
|
print(" " * (da[t] + 5 + int(p / 2)) + marker[t] + "\n")
|
||||||
|
field_headers()
|
||||||
|
|
||||||
|
|
||||||
|
def show_scores() -> bool:
|
||||||
|
print()
|
||||||
|
print(f"TEAM 1 SCORE IS {score[0]}")
|
||||||
|
print(f"TEAM 2 SCORE IS {score[1]}")
|
||||||
|
print()
|
||||||
|
if score[t] >= winning_score:
|
||||||
|
print(f"TEAM {t+1} WINS*******************")
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def loss_posession() -> None:
|
||||||
|
global t
|
||||||
|
print()
|
||||||
|
print(f"** LOSS OF POSSESSION FROM TEAM {t+1} TO TEAM {ta[t]+1}")
|
||||||
|
print()
|
||||||
|
separator()
|
||||||
|
print()
|
||||||
|
t = ta[t]
|
||||||
|
|
||||||
|
|
||||||
|
def touchdown() -> None:
|
||||||
|
print()
|
||||||
|
print(f"TOUCHDOWN BY TEAM {t+1} *********************YEA TEAM")
|
||||||
|
q = 7
|
||||||
|
g = random()
|
||||||
|
if g <= 0.1:
|
||||||
|
q = 6
|
||||||
|
print("EXTRA POINT NO GOOD")
|
||||||
|
else:
|
||||||
|
print("EXTRA POINT GOOD")
|
||||||
|
score[t] = score[t] + q
|
||||||
|
|
||||||
|
|
||||||
|
def print_header() -> None:
|
||||||
|
print(" " * 32 + "FOOTBALL")
|
||||||
|
print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n")
|
||||||
|
print("PRESENTING N.F.U. FOOTBALL (NO FORTRAN USED)\n\n")
|
||||||
|
|
||||||
|
|
||||||
|
def print_instructions() -> None:
|
||||||
|
print(
|
||||||
|
"""THIS IS A FOOTBALL GAME FOR TWO TEAMS IN WHICH PLAYERS MUST
|
||||||
|
PREPARE A TAPE WITH A DATA STATEMENT (1770 FOR TEAM 1,
|
||||||
|
1780 FOR TEAM 2) IN WHICH EACH TEAM SCRAMBLES NOS. 1-20
|
||||||
|
THESE NUMBERS ARE THEN ASSIGNED TO TWENTY GIVEN PLAYS.
|
||||||
|
A LIST OF NOS. AND THEIR PLAYS IS PROVIDED WITH
|
||||||
|
BOTH TEAMS HAVING THE SAME PLAYS. THE MORE SIMILAR THE
|
||||||
|
PLAYS THE LESS YARDAGE GAINED. SCORES ARE GIVEN
|
||||||
|
WHENEVER SCORES ARE MADE. SCORES MAY ALSO BE OBTAINED
|
||||||
|
BY INPUTTING 99,99 FOR PLAY NOS. TO PUNT OR ATTEMPT A
|
||||||
|
FIELD GOAL, INPUT 77,77 FOR PLAY NUMBERS. QUESTIONS WILL BE
|
||||||
|
ASKED THEN. ON 4TH DOWN, YOU WILL ALSO BE ASKED WHETHER
|
||||||
|
YOU WANT TO PUNT OR ATTEMPT A FIELD GOAL. IF THE ANSWER TO
|
||||||
|
BOTH QUESTIONS IS NO IT WILL BE ASSUMED YOU WANT TO
|
||||||
|
TRY AND GAIN YARDAGE. ANSWER ALL QUESTIONS YES OR NO.
|
||||||
|
THE GAME IS PLAYED UNTIL PLAYERS TERMINATE (CONTROL-C).
|
||||||
|
PLEASE PREPARE A TAPE AND RUN.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
global winning_score
|
||||||
|
print_header()
|
||||||
|
want_instructions = ask_bool("DO YOU WANT INSTRUCTIONS? ")
|
||||||
|
if want_instructions:
|
||||||
|
print_instructions()
|
||||||
|
print()
|
||||||
|
winning_score = ask_int("PLEASE INPUT SCORE LIMIT ON GAME: ")
|
||||||
|
for i in range(40):
|
||||||
|
index = player_data[i - 1]
|
||||||
|
if i < 20:
|
||||||
|
aa[index] = i
|
||||||
|
else:
|
||||||
|
ba[index] = i - 20
|
||||||
|
ca[i] = index
|
||||||
|
offset = 0
|
||||||
|
for t in [0, 1]:
|
||||||
|
print(f"TEAM {t+1} PLAY CHART")
|
||||||
|
print("NO. PLAY")
|
||||||
|
for i in range(20):
|
||||||
|
input_str = f"{ca[i + offset]}"
|
||||||
|
while len(input_str) < 6:
|
||||||
|
input_str += " "
|
||||||
|
input_str += actions[i]
|
||||||
|
print(input_str)
|
||||||
|
offset += 20
|
||||||
|
t = 1
|
||||||
|
print()
|
||||||
|
print("TEAR OFF HERE----------------------------------------------")
|
||||||
|
print("\n" * 10)
|
||||||
|
|
||||||
|
field_headers()
|
||||||
|
print("TEAM 1 DEFEND 0 YD GOAL -- TEAM 2 DEFENDS 100 YD GOAL.")
|
||||||
|
t = randint(0, 1)
|
||||||
|
print()
|
||||||
|
print("THE COIN IS FLIPPED")
|
||||||
|
routine = 1
|
||||||
|
while True:
|
||||||
|
if routine <= 1:
|
||||||
|
p = xa[t] - ya[t] * 40
|
||||||
|
separator()
|
||||||
|
print(f"TEAM {t+1} RECEIVES KICK-OFF")
|
||||||
|
k = floor(26 * random() + 40)
|
||||||
|
if routine <= 2:
|
||||||
|
p = p - ya[t] * k
|
||||||
|
if routine <= 3:
|
||||||
|
if wa[t] * p >= za[t] + 10:
|
||||||
|
print("BALL WENT OUT OF ENDZONE --AUTOMATIC TOUCHBACK--")
|
||||||
|
p = za[t] - wa[t] * 20
|
||||||
|
if routine <= 4:
|
||||||
|
routine = 5
|
||||||
|
else:
|
||||||
|
print(f"BALL WENT {k} YARDS. NOW ON {p}")
|
||||||
|
show_ball()
|
||||||
|
|
||||||
|
if routine <= 4:
|
||||||
|
want_runback = ask_bool(f"TEAM {t+1} DO YOU WANT TO RUNBACK? ")
|
||||||
|
|
||||||
|
if want_runback:
|
||||||
|
k = floor(9 * random() + 1)
|
||||||
|
r = floor(((xa[t] - ya[t] * p + 25) * random() - 15) / k)
|
||||||
|
p = p - wa[t] * r
|
||||||
|
print(f"RUNBACK TEAM {t+1} {r} YARDS")
|
||||||
|
g = random()
|
||||||
|
if g < 0.25:
|
||||||
|
loss_posession()
|
||||||
|
routine = 4
|
||||||
|
continue
|
||||||
|
elif ya[t] * p >= xa[t]:
|
||||||
|
touchdown()
|
||||||
|
if show_scores():
|
||||||
|
return
|
||||||
|
t = ta[t]
|
||||||
|
routine = 1
|
||||||
|
continue
|
||||||
|
elif wa[t] * p >= za[t]:
|
||||||
|
print(f"SAFETY AGAINST TEAM {t+1} **********************OH-OH")
|
||||||
|
score[ta[t]] = score[ta[t]] + 2
|
||||||
|
if show_scores():
|
||||||
|
return
|
||||||
|
|
||||||
|
p = za[t] - wa[t] * 20
|
||||||
|
want_punt = ask_bool(
|
||||||
|
f"TEAM {t+1} DO YOU WANT TO PUNT INSTEAD OF A KICKOFF? "
|
||||||
|
)
|
||||||
|
if want_punt:
|
||||||
|
print(f"TEAM {t+1} WILL PUNT")
|
||||||
|
g = random()
|
||||||
|
if g < 0.25:
|
||||||
|
loss_posession()
|
||||||
|
routine = 4
|
||||||
|
continue
|
||||||
|
|
||||||
|
print()
|
||||||
|
separator()
|
||||||
|
k = floor(25 * random() + 35)
|
||||||
|
t = ta[t]
|
||||||
|
routine = 2
|
||||||
|
continue
|
||||||
|
|
||||||
|
touchdown()
|
||||||
|
if show_scores():
|
||||||
|
return
|
||||||
|
t = ta[t]
|
||||||
|
routine = 1
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
routine = 5
|
||||||
|
continue
|
||||||
|
|
||||||
|
else:
|
||||||
|
if wa[t] * p >= za[t]:
|
||||||
|
p = za[t] - wa[t] * 20
|
||||||
|
|
||||||
|
if routine <= 5:
|
||||||
|
d = 1
|
||||||
|
s = p
|
||||||
|
|
||||||
|
if routine <= 6:
|
||||||
|
print("=" * 72 + "\n")
|
||||||
|
print(f"TEAM {t+1} DOWN {d} ON {p}")
|
||||||
|
if d == 1:
|
||||||
|
if ya[t] * (p + ya[t] * 10) >= xa[t]:
|
||||||
|
c = 8
|
||||||
|
else:
|
||||||
|
c = 4
|
||||||
|
|
||||||
|
if c != 8:
|
||||||
|
yards = 10 - (ya[t] * p - ya[t] * s)
|
||||||
|
print(" " * 27 + f"{yards} YARDS TO 1ST DOWN")
|
||||||
|
else:
|
||||||
|
yards = xa[t] - ya[t] * p
|
||||||
|
print(" " * 27 + f"{yards} YARDS")
|
||||||
|
|
||||||
|
show_ball()
|
||||||
|
if d == 4:
|
||||||
|
routine = 8
|
||||||
|
|
||||||
|
if routine <= 7:
|
||||||
|
u = floor(3 * random() - 1)
|
||||||
|
while True:
|
||||||
|
p1, p2 = get_offense_defense()
|
||||||
|
if t != 1:
|
||||||
|
p2, p1 = p1, p2
|
||||||
|
|
||||||
|
if p1 == 99:
|
||||||
|
if show_scores():
|
||||||
|
return
|
||||||
|
if p1 == 99:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if p1 < 1 or p1 > 20 or p2 < 1 or p2 > 20:
|
||||||
|
print("ILLEGAL PLAY NUMBER, CHECK AND ", end="")
|
||||||
|
continue
|
||||||
|
|
||||||
|
break
|
||||||
|
p1 -= 1
|
||||||
|
p2 -= 1
|
||||||
|
|
||||||
|
if d == 4 or p1 == 77:
|
||||||
|
want_punt = ask_bool(f"DOES TEAM {t+1} WANT TO PUNT? ")
|
||||||
|
|
||||||
|
if want_punt:
|
||||||
|
print()
|
||||||
|
print(f"TEAM {t+1} WILL PUNT")
|
||||||
|
g = random()
|
||||||
|
if g < 0.25:
|
||||||
|
loss_posession()
|
||||||
|
routine = 4
|
||||||
|
continue
|
||||||
|
|
||||||
|
print()
|
||||||
|
separator()
|
||||||
|
k = floor(25 * random() + 35)
|
||||||
|
t = ta[t]
|
||||||
|
routine = 2
|
||||||
|
continue
|
||||||
|
|
||||||
|
attempt_field_goal = ask_bool(
|
||||||
|
f"DOES TEAM {t+1} WANT TO ATTEMPT A FIELD GOAL? "
|
||||||
|
)
|
||||||
|
|
||||||
|
if attempt_field_goal:
|
||||||
|
print()
|
||||||
|
print(f"TEAM {t+1} WILL ATTEMPT A FIELD GOAL")
|
||||||
|
g = random()
|
||||||
|
if g < 0.025:
|
||||||
|
loss_posession()
|
||||||
|
routine = 4
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
f = floor(35 * random() + 20)
|
||||||
|
print()
|
||||||
|
print(f"KICK IS {f} YARDS LONG")
|
||||||
|
p = p - wa[t] * f
|
||||||
|
g = random()
|
||||||
|
if g < 0.35:
|
||||||
|
print("BALL WENT WIDE")
|
||||||
|
elif ya[t] * p >= xa[t]:
|
||||||
|
print(
|
||||||
|
f"FIELD GOLD GOOD FOR TEAM {t+1} *********************YEA"
|
||||||
|
)
|
||||||
|
q = 3
|
||||||
|
score[t] = score[t] + q
|
||||||
|
if show_scores():
|
||||||
|
return
|
||||||
|
t = ta[t]
|
||||||
|
routine = 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"FIELD GOAL UNSUCCESFUL TEAM {t+1}-----------------TOO BAD")
|
||||||
|
print()
|
||||||
|
separator()
|
||||||
|
if ya[t] * p < xa[t] + 10:
|
||||||
|
print()
|
||||||
|
print(f"BALL NOW ON {p}")
|
||||||
|
t = ta[t]
|
||||||
|
show_ball()
|
||||||
|
routine = 4
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
t = ta[t]
|
||||||
|
routine = 3
|
||||||
|
continue
|
||||||
|
|
||||||
|
else:
|
||||||
|
routine = 7
|
||||||
|
continue
|
||||||
|
|
||||||
|
y = floor(
|
||||||
|
abs(aa[p1] - ba[p2]) / 19 * ((xa[t] - ya[t] * p + 25) * random() - 15)
|
||||||
|
)
|
||||||
|
print()
|
||||||
|
if t == 1 and aa[p1] < 11 or t == 2 and ba[p2] < 11:
|
||||||
|
print("THE BALL WAS RUN")
|
||||||
|
elif u == 0:
|
||||||
|
print(f"PASS INCOMPLETE TEAM {t+1}")
|
||||||
|
y = 0
|
||||||
|
else:
|
||||||
|
g = random()
|
||||||
|
if g <= 0.025 and y > 2:
|
||||||
|
print("PASS COMPLETED")
|
||||||
|
else:
|
||||||
|
print("QUARTERBACK SCRAMBLED")
|
||||||
|
|
||||||
|
p = p - wa[t] * y
|
||||||
|
print()
|
||||||
|
print(f"NET YARDS GAINED ON DOWN {d} ARE {y}")
|
||||||
|
|
||||||
|
g = random()
|
||||||
|
if g <= 0.025:
|
||||||
|
loss_posession()
|
||||||
|
routine = 4
|
||||||
|
continue
|
||||||
|
elif ya[t] * p >= xa[t]:
|
||||||
|
touchdown()
|
||||||
|
if show_scores():
|
||||||
|
return
|
||||||
|
t = ta[t]
|
||||||
|
routine = 1
|
||||||
|
continue
|
||||||
|
elif wa[t] * p >= za[t]:
|
||||||
|
print()
|
||||||
|
print(f"SAFETY AGAINST TEAM {t+1} **********************OH-OH")
|
||||||
|
score[ta[t]] = score[ta[t]] + 2
|
||||||
|
if show_scores():
|
||||||
|
return
|
||||||
|
p = za[t] - wa[t] * 20
|
||||||
|
want_punt = ask_bool(
|
||||||
|
f"TEAM {t+1} DO YOU WANT TO PUNT INSTEAD OF A KICKOFF? "
|
||||||
|
)
|
||||||
|
if want_punt:
|
||||||
|
print()
|
||||||
|
print(f"TEAM {t+1} WILL PUNT")
|
||||||
|
g = random()
|
||||||
|
if g < 0.25:
|
||||||
|
loss_posession()
|
||||||
|
routine = 4
|
||||||
|
continue
|
||||||
|
|
||||||
|
print()
|
||||||
|
separator()
|
||||||
|
k = floor(25 * random() + 35)
|
||||||
|
t = ta[t]
|
||||||
|
routine = 2
|
||||||
|
continue
|
||||||
|
|
||||||
|
touchdown()
|
||||||
|
if show_scores():
|
||||||
|
return
|
||||||
|
t = ta[t]
|
||||||
|
routine = 1
|
||||||
|
elif ya[t] * p - ya[t] * s >= 10:
|
||||||
|
routine = 5
|
||||||
|
else:
|
||||||
|
d += 1
|
||||||
|
if d != 5:
|
||||||
|
routine = 6
|
||||||
|
else:
|
||||||
|
print()
|
||||||
|
print(f"CONVERSION UNSUCCESSFUL TEAM {t+1}")
|
||||||
|
t = ta[t]
|
||||||
|
print()
|
||||||
|
separator()
|
||||||
|
routine = 5
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user