mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-12 15:50:20 -08:00
Merge pull request #716 from coding-horror/py-football
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)
|
||||
|
||||
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