From 688d55c0bba229fce674d6652f2cd17bd6e5811d Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 19 Dec 2020 06:00:42 -0500 Subject: [PATCH 001/100] Just forked - Want to help? Feel free! --- README.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index d3958ed..7820585 100644 --- a/README.rst +++ b/README.rst @@ -1,3 +1,11 @@ +##Just forked this one - planning on taking it to the next level ... + +###Want to help? Feel free! + +####-- Randall + + + ================ Star Trek 1971 ================ @@ -36,4 +44,4 @@ Here is a list of possible improvements: + crew functions - Easier navigation (using cartesian system maybe) - Make some parts more 'Pythonic' -- ...Plenty more! \ No newline at end of file +- ...Plenty more! From 3db3dee6e87e7736a912d5d41146c77608e9837e Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 19 Dec 2020 06:01:04 -0500 Subject: [PATCH 002/100] Update README.rst --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 7820585..7a01f52 100644 --- a/README.rst +++ b/README.rst @@ -1,8 +1,8 @@ -##Just forked this one - planning on taking it to the next level ... +## Just forked this one - planning on taking it to the next level ... -###Want to help? Feel free! +### Want to help? Feel free! -####-- Randall +#### -- Randall From 43a3a996db891c363b6cc68b06a85d87bb1fe4e0 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 19 Dec 2020 06:02:41 -0500 Subject: [PATCH 003/100] Update README.rst --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 7a01f52..71a2e5f 100644 --- a/README.rst +++ b/README.rst @@ -1,8 +1,8 @@ -## Just forked this one - planning on taking it to the next level ... +** Just forked this one - planning on taking it to the next level ... ** -### Want to help? Feel free! +** Want to help? Feel free! ** -#### -- Randall +** -- _Randall_ ** From cff83d6b9f8117cbae107cda06d137c6c088e2cb Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 19 Dec 2020 06:06:32 -0500 Subject: [PATCH 004/100] Update README.rst --- README.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 71a2e5f..2c3479d 100644 --- a/README.rst +++ b/README.rst @@ -1,8 +1,11 @@ -** Just forked this one - planning on taking it to the next level ... ** +Just forked this one - planning on taking it to the next level ... + +Want to help? Feel free! + +-- _Randall + -** Want to help? Feel free! ** -** -- _Randall_ ** From b26e8cae7fd4c0111067206a13e3f3382ed5ed2c Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Sat, 19 Dec 2020 08:25:05 -0500 Subject: [PATCH 005/100] Integrals --- .gitignore | 8 ++ startrek.py | 384 +++++++++++++++++++++++++++------------------------- strings.py | 2 +- 3 files changed, 209 insertions(+), 185 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84e3373 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +################################################################################ +# This .gitignore file was automatically created by Microsoft(R) Visual Studio. +################################################################################ + +/.vs/slnx.sqlite +/.vs/startrek1971/v16/.suo +/__pycache__/strings.cpython-37.pyc +/.vs/ProjectSettings.json diff --git a/startrek.py b/startrek.py index ca745be..072e989 100644 --- a/startrek.py +++ b/startrek.py @@ -75,30 +75,22 @@ def run(): def print_game_status(): global game if game.destroyed: - print "MISSION FAILED: ENTERPRISE DESTROYED!!!" - print - print - print + print("MISSION FAILED: ENTERPRISE DESTROYED!!!") + print('\n'*2) elif game.energy == 0: - print "MISSION FAILED: ENTERPRISE RAN OUT OF ENERGY." - print - print - print + print("MISSION FAILED: ENTERPRISE RAN OUT OF ENERGY.") + print('\n'*2) elif game.klingons == 0: - print "MISSION ACCOMPLISHED: ALL KLINGON SHIPS DESTROYED. WELL DONE!!!" - print - print - print + print("MISSION ACCOMPLISHED: ALL KLINGON SHIPS DESTROYED. WELL DONE!!!") + print('\n'*2) elif game.time_remaining == 0: - print "MISSION FAILED: ENTERPRISE RAN OUT OF TIME." - print - print - print + print("MISSION FAILED: ENTERPRISE RAN OUT OF TIME.") + print('\n'*2) def command_prompt(): - command = raw_input("Enter command: ").strip().lower() - print + command = input("Enter command: ").strip().lower() + print() if command == "nav": navigation() elif command == "srs": @@ -122,11 +114,11 @@ def command_prompt(): def computer_controls(): global game if game.computer_damage > 0: - print "The main computer is damaged. Repairs are underway." - print + print("The main computer is damaged. Repairs are underway.") + print() return print_strings(strings.computerStrings) - command = raw_input("Enter computer command: ").strip().lower() + command = input("Enter computer command: ").strip().lower() if command == "rec": display_galactic_record() elif command == "sta": @@ -138,9 +130,9 @@ def computer_controls(): elif command == "nav": navigation_calculator() else: - print - print "Invalid computer command." - print + print() + print("Invalid computer command.") + print() induce_damage(4) @@ -174,82 +166,83 @@ def compute_direction(x1, y1, x2, y2): def navigation_calculator(): global game - print - print "Enterprise located in quadrant [%s,%s]." % (game.quadrant_x + 1, game.quadrant_y + 1) - print + print() + print("Enterprise located in quadrant [%s,%s]." % \ + (game.quadrant_x + 1, game.quadrant_y + 1)) + print() quad_x = input_double("Enter destination quadrant X (1--8): ") if quad_x is False or quad_x < 1 or quad_x > 8: - print "Invalid X coordinate." - print + print("Invalid X coordinate.") + print() return quad_y = input_double("Enter destination quadrant Y (1--8): ") if quad_y is False or quad_y < 1 or quad_y > 8: - print "Invalid Y coordinate." - print + print("Invalid Y coordinate.") + print() return - print + print() qx = int(quad_x) - 1 qy = int(quad_y) - 1 if qx == game.quadrant_x and qy == game.quadrant_y: - print "That is the current location of the Enterprise." - print + print("That is the current location of the Enterprise.") + print() return - print "Direction: {0:1.2f}".format(compute_direction(game.quadrant_x, game.quadrant_y, qx, qy)) - print "Distance: {0:2.2f}".format(distance(game.quadrant_x, game.quadrant_y, qx, qy)) - print + print("Direction: {0:1.2f}".format(compute_direction(game.quadrant_x, game.quadrant_y, qx, qy))) + print("Distance: {0:2.2f}".format(distance(game.quadrant_x, game.quadrant_y, qx, qy))) + print() def starbase_calculator(): global game - print + print() if game.quadrants[game.quadrant_y][game.quadrant_x].starbase: - print "Starbase in sector [%s,%s]." % (game.starbase_x + 1, game.starbase_y + 1) - print "Direction: {0:1.2f}".format( + print("Starbase in sector [%s,%s]." % (game.starbase_x + 1, game.starbase_y + 1)) + print("Direction: {0:1.2f}".format( compute_direction(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) - ) - print "Distance: {0:2.2f}".format(distance(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) / 8) + )) + print("Distance: {0:2.2f}".format(distance(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) / 8)) else: - print "There are no starbases in this quadrant." - print + print("There are no starbases in this quadrant.") + print() def photon_torpedo_calculator(): global game - print + print() if len(game.klingon_ships) == 0: - print "There are no Klingon ships in this quadrant." - print + print("There are no Klingon ships in this quadrant.") + print() return for ship in game.klingon_ships: text = "Direction {2:1.2f}: Klingon ship in sector [{0},{1}]." - print text.format( + print(text.format( ship.sector_x + 1, ship.sector_y + 1, - compute_direction(game.sector_x, game.sector_y, ship.sector_x, ship.sector_y)) - print + compute_direction(game.sector_x, game.sector_y, ship.sector_x, ship.sector_y))) + print() def display_status(): global game - print - print " Time Remaining: {0}".format(game.time_remaining) - print " Klingon Ships Remaining: {0}".format(game.klingons) - print " Starbases: {0}".format(game.starbases) - print " Warp Engine Damage: {0}".format(game.navigation_damage) - print " Short Range Scanner Damage: {0}".format(game.short_range_scan_damage) - print " Long Range Scanner Damage: {0}".format(game.long_range_scan_damage) - print " Shield Controls Damage: {0}".format(game.shield_control_damage) - print " Main Computer Damage: {0}".format(game.computer_damage) - print "Photon Torpedo Control Damage: {0}".format(game.photon_damage) - print " Phaser Damage: {0}".format(game.phaser_damage) - print + print() + print(" Time Remaining: {0}".format(game.time_remaining)) + print(" Klingon Ships Remaining: {0}".format(game.klingons)) + print(" Starbases: {0}".format(game.starbases)) + print(" Warp Engine Damage: {0}".format(game.navigation_damage)) + print(" Short Range Scanner Damage: {0}".format(game.short_range_scan_damage)) + print(" Long Range Scanner Damage: {0}".format(game.long_range_scan_damage)) + print(" Shield Controls Damage: {0}".format(game.shield_control_damage)) + print(" Main Computer Damage: {0}".format(game.computer_damage)) + print("Photon Torpedo Control Damage: {0}".format(game.photon_damage)) + print(" Phaser Damage: {0}".format(game.phaser_damage)) + print() def display_galactic_record(): global game - print + print() sb = "" - print "-------------------------------------------------" + print("-------------------------------------------------") for i in range(8): for j in range(8): sb += "| " @@ -264,30 +257,30 @@ def display_galactic_record(): sb = sb + \ "{0}{1}{2} ".format(klingon_count, starbase_count, star_count) sb += "|" - print sb + print(sb) sb = "" - print "-------------------------------------------------" - print + print("-------------------------------------------------") + print() def phaser_controls(): global game if game.phaser_damage > 0: - print "Phasers are damaged. Repairs are underway." - print + print("Phasers are damaged. Repairs are underway.") + print() return if len(game.klingon_ships) == 0: - print "There are no Klingon ships in this quadrant." - print + print("There are no Klingon ships in this quadrant.") + print() return - print "Phasers locked on target." + print("Phasers locked on target.") phaser_energy = input_double("Enter phaser energy (1--{0}): ".format(game.energy)) if not phaser_energy or phaser_energy < 1 or phaser_energy > game.energy: - print "Invalid energy level." - print + print("Invalid energy level.") + print() return - print - print "Firing phasers..." + print() + print("Firing phasers...") destroyed_ships = [] for ship in game.klingon_ships: game.energy -= int(phaser_energy) @@ -298,32 +291,32 @@ def phaser_controls(): delivered_energy = phaser_energy * (1.0 - dist / 11.3) ship.shield_level -= int(delivered_energy) if ship.shield_level <= 0: - print "Klingon ship destroyed at sector [{0},{1}].".format(ship.sector_x + 1, ship.sector_y + 1) + print("Klingon ship destroyed at sector [{0},{1}].".format(ship.sector_x + 1, ship.sector_y + 1)) destroyed_ships.append(ship) else: - print "Hit ship at sector [{0},{1}]. Klingon shield strength dropped to {2}.".format( + print("Hit ship at sector [{0},{1}]. Klingon shield strength dropped to {2}.".format( ship.sector_x + 1, ship.sector_y + 1, ship.shield_level - ) + )) for ship in destroyed_ships: game.quadrants[game.quadrant_y][game.quadrant_x].klingons -= 1 game.klingons -= 1 game.sector[ship.sector_y][ship.sector_x] = sector_type.empty game.klingon_ships.remove(ship) if len(game.klingon_ships) > 0: - print + print() klingons_attack() - print + print() def shield_controls(): global game - print "--- Shield Controls ----------------" - print "add = Add energy to shields." - print "sub = Subtract energy from shields." - print - print "Enter shield control command: " - command = raw_input("Enter shield control command: ").strip().lower() - print + print("--- Shield Controls ----------------") + print("add = Add energy to shields.") + print("sub = Subtract energy from shields.") + print() + print("Enter shield control command: ") + command = input("Enter shield control command: ").strip().lower() + print() if command == "add": adding = True max_transfer = game.energy @@ -331,24 +324,24 @@ def shield_controls(): adding = False max_transfer = game.shield_level else: - print "Invalid command." - print + print("Invalid command.") + print() return transfer = input_double( "Enter amount of energy (1--{0}): ".format(max_transfer)) if not transfer or transfer < 1 or transfer > max_transfer: - print "Invalid amount of energy." - print + print("Invalid amount of energy.") + print() return - print + print() if adding: game.energy -= int(transfer) game.shield_level += int(transfer) else: game.energy += int(transfer) game.shield_level -= int(transfer) - print "Shield strength is now {0}. Energy level is now {1}.".format(game.shield_level, game.energy) - print + print("Shield strength is now {0}. Energy level is now {1}.".format(game.shield_level, game.energy)) + print() def klingons_attack(): @@ -356,9 +349,9 @@ def klingons_attack(): if len(game.klingon_ships) > 0: for ship in game.klingon_ships: if game.docked: - print "Enterprise hit by ship at sector [{0},{1}]. No damage due to starbase shields.".format( + print("Enterprise hit by ship at sector [{0},{1}]. No damage due to starbase shields.".format( ship.sector_x + 1, ship.sector_y + 1 - ) + )) else: dist = distance( game.sector_x, game.sector_y, ship.sector_x, ship.sector_y) @@ -368,9 +361,9 @@ def klingons_attack(): if game.shield_level < 0: game.shield_level = 0 game.destroyed = True - print "Enterprise hit by ship at sector [{0},{1}]. Shields dropped to {2}.".format( + print("Enterprise hit by ship at sector [{0},{1}]. Shields dropped to {2}.".format( ship.sector_x + 1, ship.sector_y + 1, game.shield_level - ) + )) if game.shield_level == 0: return True return True @@ -392,26 +385,26 @@ def induce_damage(item): item = random.randint(0, 6) if item == 0: game.navigation_damage = damage - print "Warp engines are malfunctioning." + print("Warp engines are malfunctioning.") elif item == 1: game.short_range_scan_damage = damage - print "Short range scanner is malfunctioning." + print("Short range scanner is malfunctioning.") elif item == 2: game.long_range_scan_damage = damage - print "Long range scanner is malfunctioning." + print("Long range scanner is malfunctioning.") elif item == 3: game.shield_control_damage = damage - print "Shield controls are malfunctioning." + print("Shield controls are malfunctioning.") elif item == 4: game.computer_damage = damage - print "The main computer is malfunctioning." + print("The main computer is malfunctioning.") elif item == 5: game.photon_damage = damage - print "Photon torpedo controls are malfunctioning." + print("Photon torpedo controls are malfunctioning.") elif item == 6: game.phaser_damage = damage - print "Phasers are malfunctioning." - print + print("Phasers are malfunctioning.") + print() def repair_damage(): @@ -419,44 +412,44 @@ def repair_damage(): if game.navigation_damage > 0: game.navigation_damage -= 1 if game.navigation_damage == 0: - print "Warp engines have been repaired." - print + print("Warp engines have been repaired.") + print() return True if game.short_range_scan_damage > 0: game.short_range_scan_damage -= 1 if game.short_range_scan_damage == 0: - print "Short range scanner has been repaired." - print + print("Short range scanner has been repaired.") + print() return True if game.long_range_scan_damage > 0: game.long_range_scan_damage -= 1 if game.long_range_scan_damage == 0: - print "Long range scanner has been repaired." - print + print("Long range scanner has been repaired.") + print() return True if game.shield_control_damage > 0: game.shield_control_damage -= 1 if game.shield_control_damage == 0: - print "Shield controls have been repaired." - print + print("Shield controls have been repaired.") + print() return True if game.computer_damage > 0: game.computer_damage -= 1 if game.computer_damage == 0: - print "The main computer has been repaired." - print + print("The main computer has been repaired.") + print() return True if game.photon_damage > 0: game.photon_damage -= 1 if game.photon_damage == 0: - print "Photon torpedo controls have been repaired." - print + print("Photon torpedo controls have been repaired.") + print() return True if game.phaser_damage > 0: game.phaser_damage -= 1 if game.phaser_damage == 0: - print "Phasers have been repaired." - print + print("Phasers have been repaired.") + print() return True return False @@ -464,11 +457,11 @@ def repair_damage(): def long_range_scan(): global game if game.long_range_scan_damage > 0: - print "Long range scanner is damaged. Repairs are underway." - print + print("Long range scanner is damaged. Repairs are underway.") + print() return sb = "" - print "-------------------" + print("-------------------") for i in range(game.quadrant_y - 1, game.quadrant_y+2): # quadrantY + 1 ? for j in range(game.quadrant_x - 1, game.quadrant_x+2): # quadrantX + 1? sb += "| " @@ -484,33 +477,33 @@ def long_range_scan(): sb = sb + \ "{0}{1}{2} ".format(klingon_count, starbase_count, star_count) sb += "|" - print sb + print(sb) sb = "" - print "-------------------" - print + print("-------------------") + print() def torpedo_control(): global game if game.photon_damage > 0: - print "Photon torpedo control is damaged. Repairs are underway." - print + print("Photon torpedo control is damaged. Repairs are underway.") + print() return if game.photon_torpedoes == 0: - print "Photon torpedoes exhausted." - print + print("Photon torpedoes exhausted.") + print() return if len(game.klingon_ships) == 0: - print "There are no Klingon ships in this quadrant." - print + print("There are no Klingon ships in this quadrant.") + print() return direction = input_double("Enter firing direction (1.0--9.0): ") if not direction or direction < 1.0 or direction > 9.0: - print "Invalid direction." - print + print("Invalid direction.") + print() return - print - print "Photon torpedo fired..." + print() + print("Photon torpedo fired...") game.photon_torpedoes -= 1 angle = -(pi * (direction - 1.0) / 4.0) if random.randint(0, 2) == 0: @@ -527,12 +520,12 @@ def torpedo_control(): new_x = int(round(x)) new_y = int(round(y)) if last_x != new_x or last_y != new_y: - print " [{0},{1}]".format(new_x + 1, new_y + 1) + print(" [{0},{1}]".format(new_x + 1, new_y + 1)) last_x = new_x last_y = new_y for ship in game.klingon_ships: if ship.sector_x == new_x and ship.sector_y == new_y: - print "Klingon ship destroyed at sector [{0},{1}].".format(ship.sector_x + 1, ship.sector_y + 1) + print("Klingon ship destroyed at sector [{0},{1}].".format(ship.sector_x + 1, ship.sector_y + 1)) game.sector[ship.sector_y][ship.sector_x] = sector_type.empty game.klingons -= 1 game.klingon_ships.remove(ship) @@ -545,23 +538,23 @@ def torpedo_control(): game.starbases -= 1 game.quadrants[game.quadrant_y][game.quadrant_x].starbase = False game.sector[new_y][new_x] = sector_type.empty - print "The Enterprise destroyed a Federation starbase at sector [{0},{1}]!".format(new_x + 1, new_y + 1) + print("The Enterprise destroyed a Federation starbase at sector [{0},{1}]!".format(new_x + 1, new_y + 1)) hit = True break elif game.sector[new_y][new_x] == sector_type.star: - print "The torpedo was captured by a star's gravitational field at sector [{0},{1}].".format( + print("The torpedo was captured by a star's gravitational field at sector [{0},{1}].".format( new_x + 1, new_y + 1 - ) + )) hit = True break x += vx y += vy if not hit: - print "Photon torpedo failed to hit anything." + print("Photon torpedo failed to hit anything.") if len(game.klingon_ships) > 0: - print + print() klingons_attack() - print + print() def navigation(): @@ -569,33 +562,33 @@ def navigation(): max_warp_factor = 8.0 if game.navigation_damage > 0: max_warp_factor = 0.2 + random.randint(0, 8) / 10.0 - print "Warp engines damaged. Maximum warp factor: {0}".format(max_warp_factor) - print + print("Warp engines damaged. Maximum warp factor: {0}".format(max_warp_factor)) + print() direction = input_double("Enter course (1.0--8.9): ") if not direction or direction < 1.0 or direction > 9.0: - print "Invalid course." - print + print("Invalid course.") + print() return dist = input_double( "Enter warp factor (0.1--{0}): ".format(max_warp_factor)) if not dist or dist < 0.1 or dist > max_warp_factor: - print "Invalid warp factor." - print + print("Invalid warp factor.") + print() return - print + print() dist *= 8 energy_required = int(dist) if energy_required >= game.energy: - print "Unable to comply. Insufficient energy to travel that speed." - print + print("Unable to comply. Insufficient energy to travel that speed.") + print() return else: - print "Warp engines engaged." - print + print("Warp engines engaged.") + print() game.energy -= energy_required last_quad_x = game.quadrant_x @@ -624,8 +617,8 @@ def navigation(): game.sector_x = last_sect_x game.sector_y = last_sect_y game.sector[game.sector_y][game.sector_x] = sector_type.enterprise - print "Encountered obstacle within quadrant." - print + print("Encountered obstacle within quadrant.") + print() obstacle = True break last_sect_x = sect_x @@ -645,12 +638,12 @@ def navigation(): game.sector_x = int(round(x)) % 8 game.sector_y = int(round(y)) % 8 if quad_x != game.quadrant_x or quad_y != game.quadrant_y: - game.quadrant_x = quad_x - game.quadrant_y = quad_y + game.quadrant_x = int(quad_x) + game.quadrant_y = int(quad_y) generate_sector() else: - game.quadrant_x = quad_x - game.quadrant_y = quad_y + game.quadrant_x = int(quad_x) + game.quadrant_y = int(quad_y) game.sector[game.sector_y][game.sector_x] = sector_type.enterprise if is_docking_location(game.sector_y, game.sector_x): game.energy = 3000 @@ -674,20 +667,20 @@ def navigation(): short_range_scan() if game.docked: - print "Lowering shields as part of docking sequence..." - print "Enterprise successfully docked with starbase." - print + print("Lowering shields as part of docking sequence...") + print("Enterprise successfully docked with starbase.") + print() else: if game.quadrants[game.quadrant_y][game.quadrant_x].klingons > 0 \ and last_quad_x == game.quadrant_x and last_quad_y == game.quadrant_y: klingons_attack() - print + print() elif not repair_damage(): induce_damage(-1) def input_double(prompt): - text = raw_input(prompt) + text = input(prompt) value = float(text) if type(value) == float: return value @@ -753,13 +746,13 @@ def read_sector(i, j): def short_range_scan(): global game if game.short_range_scan_damage > 0: - print "Short range scanner is damaged. Repairs are underway." - print + print("Short range scanner is damaged. Repairs are underway.") + print() else: quadrant = game.quadrants[game.quadrant_y][game.quadrant_x] quadrant.scanned = True print_sector(quadrant) - print + print() def print_sector(quadrant): @@ -771,8 +764,31 @@ def print_sector(quadrant): game.condition = "YELLOW" sb = "" - print "-=--=--=--=--=--=--=--=- Region: {0}".format(quadrant.name) - print_sector_row(sb, 0, " Quadrant: [{0},{1}]".format(game.quadrant_x + 1, game.quadrant_y + 1)) + print("-=--=--=--=--=--=--=--=- Region: {0}".format(quadrant.name)) + print_sector_row(sb, 0, " Quadrant: [{0},{1}]".format( + game.quadrant_x + 1, game.quadrant_y + 1)) + + + + + + + + + + + + + + + + + + + + + + 0 print_sector_row(sb, 1, " Sector: [{0},{1}]".format(game.sector_x + 1, game.sector_y + 1)) print_sector_row(sb, 2, " Stardate: {0}".format(game.star_date)) print_sector_row(sb, 3, " Time remaining: {0}".format(game.time_remaining)) @@ -780,16 +796,16 @@ def print_sector(quadrant): print_sector_row(sb, 5, " Energy: {0}".format(game.energy)) print_sector_row(sb, 6, " Shields: {0}".format(game.shield_level)) print_sector_row(sb, 7, " Photon Torpedoes: {0}".format(game.photon_torpedoes)) - print "-=--=--=--=--=--=--=--=- Docked: {0}".format(game.docked) + print("-=--=--=--=--=--=--=--=- Docked: {0}".format(game.docked)) if quadrant.klingons > 0: - print - print "Condition RED: Klingon ship{0} detected.".format("" if quadrant.klingons == 1 else "s") + print() + print("Condition RED: Klingon ship{0} detected.".format("" if quadrant.klingons == 1 else "s")) if game.shield_level == 0 and not game.docked: - print "Warning: Shields are down." + print("Warning: Shields are down.") elif game.energy < 300: - print - print "Condition YELLOW: Low energy level." + print() + print("Condition YELLOW: Low energy level.") game.condition = "YELLOW" @@ -808,14 +824,14 @@ def print_sector_row(sb, row, suffix): sb += ">S<" if suffix is not None: sb = sb + suffix - print sb + print(sb) def print_mission(): global game - print "Mission: Destroy {0} Klingon ships in {1} stardates with {2} starbases.".format( - game.klingons, game.time_remaining, game.starbases) - print + print("Mission: Destroy {0} Klingon ships in {1} stardates with {2} starbases.".format( + game.klingons, game.time_remaining, game.starbases)) + print() def initialize_game(): @@ -871,8 +887,8 @@ def initialize_game(): def print_strings(string_list): for string in string_list: - print string - print + print(string) + print() if __name__ == '__main__': diff --git a/strings.py b/strings.py index 5781948..1a6f16a 100644 --- a/strings.py +++ b/strings.py @@ -1,4 +1,4 @@ -titleStrings = r""" +titleStrings = r""") ______ _______ ______ ______ _______ ______ ______ __ __ / __ //__ __// __ // __ / /__ __// __ / / ____// / / / / / /_/ / / / /_/ // /_/ / / / / /_/ / / /__ / // / From cab2ab8635172453c2cc53bee2754afa0670b92a Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Sat, 19 Dec 2020 08:43:59 -0500 Subject: [PATCH 006/100] . --- startrek.py | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/startrek.py b/startrek.py index 072e989..a18ca84 100644 --- a/startrek.py +++ b/startrek.py @@ -767,28 +767,6 @@ def print_sector(quadrant): print("-=--=--=--=--=--=--=--=- Region: {0}".format(quadrant.name)) print_sector_row(sb, 0, " Quadrant: [{0},{1}]".format( game.quadrant_x + 1, game.quadrant_y + 1)) - - - - - - - - - - - - - - - - - - - - - - 0 print_sector_row(sb, 1, " Sector: [{0},{1}]".format(game.sector_x + 1, game.sector_y + 1)) print_sector_row(sb, 2, " Stardate: {0}".format(game.star_date)) print_sector_row(sb, 3, " Time remaining: {0}".format(game.time_remaining)) From 3e20d54f58a3caa82988fdda9257eb578e3cc279 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Sat, 19 Dec 2020 08:43:59 -0500 Subject: [PATCH 007/100] . --- startrek.py | 22 ---------------------- strings.py | 2 +- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/startrek.py b/startrek.py index 072e989..a18ca84 100644 --- a/startrek.py +++ b/startrek.py @@ -767,28 +767,6 @@ def print_sector(quadrant): print("-=--=--=--=--=--=--=--=- Region: {0}".format(quadrant.name)) print_sector_row(sb, 0, " Quadrant: [{0},{1}]".format( game.quadrant_x + 1, game.quadrant_y + 1)) - - - - - - - - - - - - - - - - - - - - - - 0 print_sector_row(sb, 1, " Sector: [{0},{1}]".format(game.sector_x + 1, game.sector_y + 1)) print_sector_row(sb, 2, " Stardate: {0}".format(game.star_date)) print_sector_row(sb, 3, " Time remaining: {0}".format(game.time_remaining)) diff --git a/strings.py b/strings.py index 1a6f16a..5781948 100644 --- a/strings.py +++ b/strings.py @@ -1,4 +1,4 @@ -titleStrings = r""") +titleStrings = r""" ______ _______ ______ ______ _______ ______ ______ __ __ / __ //__ __// __ // __ / /__ __// __ / / ____// / / / / / /_/ / / / /_/ // /_/ / / / / /_/ / / /__ / // / From bc8341669fcab473557935159e642fabc701b46b Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 19 Dec 2020 09:12:06 -0500 Subject: [PATCH 008/100] Converted to Python 3 Light tactile testing .... success! --- README.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 2c3479d..d9a2d37 100644 --- a/README.rst +++ b/README.rst @@ -2,8 +2,9 @@ Just forked this one - planning on taking it to the next level ... Want to help? Feel free! --- _Randall +-- Randall +p.s. Converted to Python 3. Lightly tested - okay! From 52c8264f270bbccb7a099b04c5184df136363852 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Sat, 19 Dec 2020 13:11:04 -0500 Subject: [PATCH 009/100] Let it begin ... --- .gitignore | 5 +- AbsDisplay.py | 49 +++++ startrek.py => StarTrek2020.py | 336 +++++++++++++++++---------------- strings.py => TrekStrings.py | 0 4 files changed, 222 insertions(+), 168 deletions(-) create mode 100644 AbsDisplay.py rename startrek.py => StarTrek2020.py (72%) rename strings.py => TrekStrings.py (100%) diff --git a/.gitignore b/.gitignore index 84e3373..c6c77ab 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,8 @@ /.vs/slnx.sqlite /.vs/startrek1971/v16/.suo -/__pycache__/strings.cpython-37.pyc +/__pycache__/TrekStrings.cpython-37.pyc /.vs/ProjectSettings.json +/__pycache__/strings.cpython-37.pyc +/__pycache__/AbsDisplay.cpython-37.pyc +/.vs/VSWorkspaceState.json diff --git a/AbsDisplay.py b/AbsDisplay.py new file mode 100644 index 0000000..5579ea7 --- /dev/null +++ b/AbsDisplay.py @@ -0,0 +1,49 @@ +import abc + +class abs_display(abc.ABC): + ''' + The plan is to have several places to + display information. The goal is to + use only one display, to display a + certain type of message. Networked + screens would also be a great idea. + Logging would be in there somewhere, + as well. + ''' + + ST_DEFAULT = 'd' + ST_CONSOLE = 'c' + ST_NETWORK = 'n' + + def __init__(self, type_ = ST_DEFAULT, width = 80, height = 24): + super().__init__() + self.screen_type = type_ + self.width = width + self.height = height + self.xpos = self.ypos = -1 + + @abc.abstractmethod + def display(self, message): + pass + + +class console(abs_display): + ''' + The best place to start is by encapsulating the default + display. Will add screen metadata for it all, later. + ''' + def __init__(self): + super().__init__(abs_display.ST_CONSOLE) + + def display(self, message = ''): + print(message) + + + +if __name__ == '__main__': + con = console() + con.display("Testing!") + + + + diff --git a/startrek.py b/StarTrek2020.py similarity index 72% rename from startrek.py rename to StarTrek2020.py index a18ca84..9d0fa4a 100644 --- a/startrek.py +++ b/StarTrek2020.py @@ -1,7 +1,9 @@ from math import atan2, pi, sqrt, cos, sin import random -import strings +import TrekStrings + +from AbsDisplay import console class Quadrant(): @@ -30,7 +32,7 @@ def __init__(self): self.shield_level = 0 -class Game(): +class Game(console): def __init__(self): self.star_date = 0 @@ -61,12 +63,12 @@ def __init__(self): def run(): global game - print_strings(strings.titleStrings) + print_strings(TrekStrings.titleStrings) while True: initialize_game() print_mission() generate_sector() - print_strings(strings.commandStrings) + print_strings(TrekStrings.commandStrings) while game.energy > 0 and not game.destroyed and game.klingons > 0 and game.time_remaining > 0: command_prompt() print_game_status() @@ -75,22 +77,22 @@ def run(): def print_game_status(): global game if game.destroyed: - print("MISSION FAILED: ENTERPRISE DESTROYED!!!") - print('\n'*2) + game.display("MISSION FAILED: ENTERPRISE DESTROYED!!!") + game.display('\n'*2) elif game.energy == 0: - print("MISSION FAILED: ENTERPRISE RAN OUT OF ENERGY.") - print('\n'*2) + game.display("MISSION FAILED: ENTERPRISE RAN OUT OF ENERGY.") + game.display('\n'*2) elif game.klingons == 0: - print("MISSION ACCOMPLISHED: ALL KLINGON SHIPS DESTROYED. WELL DONE!!!") - print('\n'*2) + game.display("MISSION ACCOMPLISHED: ALL KLINGON SHIPS DESTROYED. WELL DONE!!!") + game.display('\n'*2) elif game.time_remaining == 0: - print("MISSION FAILED: ENTERPRISE RAN OUT OF TIME.") - print('\n'*2) + game.display("MISSION FAILED: ENTERPRISE RAN OUT OF TIME.") + game.display('\n'*2) def command_prompt(): command = input("Enter command: ").strip().lower() - print() + game.display() if command == "nav": navigation() elif command == "srs": @@ -108,16 +110,16 @@ def command_prompt(): elif command.startswith('qui') or command.startswith('exi'): exit() else: - print_strings(strings.commandStrings) + print_strings(TrekStrings.commandStrings) def computer_controls(): global game if game.computer_damage > 0: - print("The main computer is damaged. Repairs are underway.") - print() + game.display("The main computer is damaged. Repairs are underway.") + game.display() return - print_strings(strings.computerStrings) + print_strings(TrekStrings.computerStrings) command = input("Enter computer command: ").strip().lower() if command == "rec": display_galactic_record() @@ -130,9 +132,9 @@ def computer_controls(): elif command == "nav": navigation_calculator() else: - print() - print("Invalid computer command.") - print() + game.display() + game.display("Invalid computer command.") + game.display() induce_damage(4) @@ -166,83 +168,83 @@ def compute_direction(x1, y1, x2, y2): def navigation_calculator(): global game - print() - print("Enterprise located in quadrant [%s,%s]." % \ + game.display() + game.display("Enterprise located in quadrant [%s,%s]." % \ (game.quadrant_x + 1, game.quadrant_y + 1)) - print() + game.display() quad_x = input_double("Enter destination quadrant X (1--8): ") if quad_x is False or quad_x < 1 or quad_x > 8: - print("Invalid X coordinate.") - print() + game.display("Invalid X coordinate.") + game.display() return quad_y = input_double("Enter destination quadrant Y (1--8): ") if quad_y is False or quad_y < 1 or quad_y > 8: - print("Invalid Y coordinate.") - print() + game.display("Invalid Y coordinate.") + game.display() return - print() + game.display() qx = int(quad_x) - 1 qy = int(quad_y) - 1 if qx == game.quadrant_x and qy == game.quadrant_y: - print("That is the current location of the Enterprise.") - print() + game.display("That is the current location of the Enterprise.") + game.display() return - print("Direction: {0:1.2f}".format(compute_direction(game.quadrant_x, game.quadrant_y, qx, qy))) - print("Distance: {0:2.2f}".format(distance(game.quadrant_x, game.quadrant_y, qx, qy))) - print() + game.display("Direction: {0:1.2f}".format(compute_direction(game.quadrant_x, game.quadrant_y, qx, qy))) + game.display("Distance: {0:2.2f}".format(distance(game.quadrant_x, game.quadrant_y, qx, qy))) + game.display() def starbase_calculator(): global game - print() + game.display() if game.quadrants[game.quadrant_y][game.quadrant_x].starbase: - print("Starbase in sector [%s,%s]." % (game.starbase_x + 1, game.starbase_y + 1)) - print("Direction: {0:1.2f}".format( + game.display("Starbase in sector [%s,%s]." % (game.starbase_x + 1, game.starbase_y + 1)) + game.display("Direction: {0:1.2f}".format( compute_direction(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) )) - print("Distance: {0:2.2f}".format(distance(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) / 8)) + game.display("Distance: {0:2.2f}".format(distance(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) / 8)) else: - print("There are no starbases in this quadrant.") - print() + game.display("There are no starbases in this quadrant.") + game.display() def photon_torpedo_calculator(): global game - print() + game.display() if len(game.klingon_ships) == 0: - print("There are no Klingon ships in this quadrant.") - print() + game.display("There are no Klingon ships in this quadrant.") + game.display() return for ship in game.klingon_ships: text = "Direction {2:1.2f}: Klingon ship in sector [{0},{1}]." - print(text.format( + game.display(text.format( ship.sector_x + 1, ship.sector_y + 1, compute_direction(game.sector_x, game.sector_y, ship.sector_x, ship.sector_y))) - print() + game.display() def display_status(): global game - print() - print(" Time Remaining: {0}".format(game.time_remaining)) - print(" Klingon Ships Remaining: {0}".format(game.klingons)) - print(" Starbases: {0}".format(game.starbases)) - print(" Warp Engine Damage: {0}".format(game.navigation_damage)) - print(" Short Range Scanner Damage: {0}".format(game.short_range_scan_damage)) - print(" Long Range Scanner Damage: {0}".format(game.long_range_scan_damage)) - print(" Shield Controls Damage: {0}".format(game.shield_control_damage)) - print(" Main Computer Damage: {0}".format(game.computer_damage)) - print("Photon Torpedo Control Damage: {0}".format(game.photon_damage)) - print(" Phaser Damage: {0}".format(game.phaser_damage)) - print() + game.display() + game.display(" Time Remaining: {0}".format(game.time_remaining)) + game.display(" Klingon Ships Remaining: {0}".format(game.klingons)) + game.display(" Starbases: {0}".format(game.starbases)) + game.display(" Warp Engine Damage: {0}".format(game.navigation_damage)) + game.display(" Short Range Scanner Damage: {0}".format(game.short_range_scan_damage)) + game.display(" Long Range Scanner Damage: {0}".format(game.long_range_scan_damage)) + game.display(" Shield Controls Damage: {0}".format(game.shield_control_damage)) + game.display(" Main Computer Damage: {0}".format(game.computer_damage)) + game.display("Photon Torpedo Control Damage: {0}".format(game.photon_damage)) + game.display(" Phaser Damage: {0}".format(game.phaser_damage)) + game.display() def display_galactic_record(): global game - print() + game.display() sb = "" - print("-------------------------------------------------") + game.display("-------------------------------------------------") for i in range(8): for j in range(8): sb += "| " @@ -257,30 +259,30 @@ def display_galactic_record(): sb = sb + \ "{0}{1}{2} ".format(klingon_count, starbase_count, star_count) sb += "|" - print(sb) + game.display(sb) sb = "" - print("-------------------------------------------------") - print() + game.display("-------------------------------------------------") + game.display() def phaser_controls(): global game if game.phaser_damage > 0: - print("Phasers are damaged. Repairs are underway.") - print() + game.display("Phasers are damaged. Repairs are underway.") + game.display() return if len(game.klingon_ships) == 0: - print("There are no Klingon ships in this quadrant.") - print() + game.display("There are no Klingon ships in this quadrant.") + game.display() return - print("Phasers locked on target.") + game.display("Phasers locked on target.") phaser_energy = input_double("Enter phaser energy (1--{0}): ".format(game.energy)) if not phaser_energy or phaser_energy < 1 or phaser_energy > game.energy: - print("Invalid energy level.") - print() + game.display("Invalid energy level.") + game.display() return - print() - print("Firing phasers...") + game.display() + game.display("Firing phasers...") destroyed_ships = [] for ship in game.klingon_ships: game.energy -= int(phaser_energy) @@ -291,10 +293,10 @@ def phaser_controls(): delivered_energy = phaser_energy * (1.0 - dist / 11.3) ship.shield_level -= int(delivered_energy) if ship.shield_level <= 0: - print("Klingon ship destroyed at sector [{0},{1}].".format(ship.sector_x + 1, ship.sector_y + 1)) + game.display("Klingon ship destroyed at sector [{0},{1}].".format(ship.sector_x + 1, ship.sector_y + 1)) destroyed_ships.append(ship) else: - print("Hit ship at sector [{0},{1}]. Klingon shield strength dropped to {2}.".format( + game.display("Hit ship at sector [{0},{1}]. Klingon shield strength dropped to {2}.".format( ship.sector_x + 1, ship.sector_y + 1, ship.shield_level )) for ship in destroyed_ships: @@ -303,20 +305,20 @@ def phaser_controls(): game.sector[ship.sector_y][ship.sector_x] = sector_type.empty game.klingon_ships.remove(ship) if len(game.klingon_ships) > 0: - print() + game.display() klingons_attack() - print() + game.display() def shield_controls(): global game - print("--- Shield Controls ----------------") - print("add = Add energy to shields.") - print("sub = Subtract energy from shields.") - print() - print("Enter shield control command: ") + game.display("--- Shield Controls ----------------") + game.display("add = Add energy to shields.") + game.display("sub = Subtract energy from shields.") + game.display() + game.display("Enter shield control command: ") command = input("Enter shield control command: ").strip().lower() - print() + game.display() if command == "add": adding = True max_transfer = game.energy @@ -324,24 +326,24 @@ def shield_controls(): adding = False max_transfer = game.shield_level else: - print("Invalid command.") - print() + game.display("Invalid command.") + game.display() return transfer = input_double( "Enter amount of energy (1--{0}): ".format(max_transfer)) if not transfer or transfer < 1 or transfer > max_transfer: - print("Invalid amount of energy.") - print() + game.display("Invalid amount of energy.") + game.display() return - print() + game.display() if adding: game.energy -= int(transfer) game.shield_level += int(transfer) else: game.energy += int(transfer) game.shield_level -= int(transfer) - print("Shield strength is now {0}. Energy level is now {1}.".format(game.shield_level, game.energy)) - print() + game.display("Shield strength is now {0}. Energy level is now {1}.".format(game.shield_level, game.energy)) + game.display() def klingons_attack(): @@ -349,7 +351,7 @@ def klingons_attack(): if len(game.klingon_ships) > 0: for ship in game.klingon_ships: if game.docked: - print("Enterprise hit by ship at sector [{0},{1}]. No damage due to starbase shields.".format( + game.display("Enterprise hit by ship at sector [{0},{1}]. No damage due to starbase shields.".format( ship.sector_x + 1, ship.sector_y + 1 )) else: @@ -361,7 +363,7 @@ def klingons_attack(): if game.shield_level < 0: game.shield_level = 0 game.destroyed = True - print("Enterprise hit by ship at sector [{0},{1}]. Shields dropped to {2}.".format( + game.display("Enterprise hit by ship at sector [{0},{1}]. Shields dropped to {2}.".format( ship.sector_x + 1, ship.sector_y + 1, game.shield_level )) if game.shield_level == 0: @@ -385,26 +387,26 @@ def induce_damage(item): item = random.randint(0, 6) if item == 0: game.navigation_damage = damage - print("Warp engines are malfunctioning.") + game.display("Warp engines are malfunctioning.") elif item == 1: game.short_range_scan_damage = damage - print("Short range scanner is malfunctioning.") + game.display("Short range scanner is malfunctioning.") elif item == 2: game.long_range_scan_damage = damage - print("Long range scanner is malfunctioning.") + game.display("Long range scanner is malfunctioning.") elif item == 3: game.shield_control_damage = damage - print("Shield controls are malfunctioning.") + game.display("Shield controls are malfunctioning.") elif item == 4: game.computer_damage = damage - print("The main computer is malfunctioning.") + game.display("The main computer is malfunctioning.") elif item == 5: game.photon_damage = damage - print("Photon torpedo controls are malfunctioning.") + game.display("Photon torpedo controls are malfunctioning.") elif item == 6: game.phaser_damage = damage - print("Phasers are malfunctioning.") - print() + game.display("Phasers are malfunctioning.") + game.display() def repair_damage(): @@ -412,44 +414,44 @@ def repair_damage(): if game.navigation_damage > 0: game.navigation_damage -= 1 if game.navigation_damage == 0: - print("Warp engines have been repaired.") - print() + game.display("Warp engines have been repaired.") + game.display() return True if game.short_range_scan_damage > 0: game.short_range_scan_damage -= 1 if game.short_range_scan_damage == 0: - print("Short range scanner has been repaired.") - print() + game.display("Short range scanner has been repaired.") + game.display() return True if game.long_range_scan_damage > 0: game.long_range_scan_damage -= 1 if game.long_range_scan_damage == 0: - print("Long range scanner has been repaired.") - print() + game.display("Long range scanner has been repaired.") + game.display() return True if game.shield_control_damage > 0: game.shield_control_damage -= 1 if game.shield_control_damage == 0: - print("Shield controls have been repaired.") - print() + game.display("Shield controls have been repaired.") + game.display() return True if game.computer_damage > 0: game.computer_damage -= 1 if game.computer_damage == 0: - print("The main computer has been repaired.") - print() + game.display("The main computer has been repaired.") + game.display() return True if game.photon_damage > 0: game.photon_damage -= 1 if game.photon_damage == 0: - print("Photon torpedo controls have been repaired.") - print() + game.display("Photon torpedo controls have been repaired.") + game.display() return True if game.phaser_damage > 0: game.phaser_damage -= 1 if game.phaser_damage == 0: - print("Phasers have been repaired.") - print() + game.display("Phasers have been repaired.") + game.display() return True return False @@ -457,11 +459,11 @@ def repair_damage(): def long_range_scan(): global game if game.long_range_scan_damage > 0: - print("Long range scanner is damaged. Repairs are underway.") - print() + game.display("Long range scanner is damaged. Repairs are underway.") + game.display() return sb = "" - print("-------------------") + game.display("-------------------") for i in range(game.quadrant_y - 1, game.quadrant_y+2): # quadrantY + 1 ? for j in range(game.quadrant_x - 1, game.quadrant_x+2): # quadrantX + 1? sb += "| " @@ -477,33 +479,33 @@ def long_range_scan(): sb = sb + \ "{0}{1}{2} ".format(klingon_count, starbase_count, star_count) sb += "|" - print(sb) + game.display(sb) sb = "" - print("-------------------") - print() + game.display("-------------------") + game.display() def torpedo_control(): global game if game.photon_damage > 0: - print("Photon torpedo control is damaged. Repairs are underway.") - print() + game.display("Photon torpedo control is damaged. Repairs are underway.") + game.display() return if game.photon_torpedoes == 0: - print("Photon torpedoes exhausted.") - print() + game.display("Photon torpedoes exhausted.") + game.display() return if len(game.klingon_ships) == 0: - print("There are no Klingon ships in this quadrant.") - print() + game.display("There are no Klingon ships in this quadrant.") + game.display() return direction = input_double("Enter firing direction (1.0--9.0): ") if not direction or direction < 1.0 or direction > 9.0: - print("Invalid direction.") - print() + game.display("Invalid direction.") + game.display() return - print() - print("Photon torpedo fired...") + game.display() + game.display("Photon torpedo fired...") game.photon_torpedoes -= 1 angle = -(pi * (direction - 1.0) / 4.0) if random.randint(0, 2) == 0: @@ -520,12 +522,12 @@ def torpedo_control(): new_x = int(round(x)) new_y = int(round(y)) if last_x != new_x or last_y != new_y: - print(" [{0},{1}]".format(new_x + 1, new_y + 1)) + game.display(" [{0},{1}]".format(new_x + 1, new_y + 1)) last_x = new_x last_y = new_y for ship in game.klingon_ships: if ship.sector_x == new_x and ship.sector_y == new_y: - print("Klingon ship destroyed at sector [{0},{1}].".format(ship.sector_x + 1, ship.sector_y + 1)) + game.display("Klingon ship destroyed at sector [{0},{1}].".format(ship.sector_x + 1, ship.sector_y + 1)) game.sector[ship.sector_y][ship.sector_x] = sector_type.empty game.klingons -= 1 game.klingon_ships.remove(ship) @@ -538,11 +540,11 @@ def torpedo_control(): game.starbases -= 1 game.quadrants[game.quadrant_y][game.quadrant_x].starbase = False game.sector[new_y][new_x] = sector_type.empty - print("The Enterprise destroyed a Federation starbase at sector [{0},{1}]!".format(new_x + 1, new_y + 1)) + game.display("The Enterprise destroyed a Federation starbase at sector [{0},{1}]!".format(new_x + 1, new_y + 1)) hit = True break elif game.sector[new_y][new_x] == sector_type.star: - print("The torpedo was captured by a star's gravitational field at sector [{0},{1}].".format( + game.display("The torpedo was captured by a star's gravitational field at sector [{0},{1}].".format( new_x + 1, new_y + 1 )) hit = True @@ -550,11 +552,11 @@ def torpedo_control(): x += vx y += vy if not hit: - print("Photon torpedo failed to hit anything.") + game.display("Photon torpedo failed to hit anything.") if len(game.klingon_ships) > 0: - print() + game.display() klingons_attack() - print() + game.display() def navigation(): @@ -562,33 +564,33 @@ def navigation(): max_warp_factor = 8.0 if game.navigation_damage > 0: max_warp_factor = 0.2 + random.randint(0, 8) / 10.0 - print("Warp engines damaged. Maximum warp factor: {0}".format(max_warp_factor)) - print() + game.display("Warp engines damaged. Maximum warp factor: {0}".format(max_warp_factor)) + game.display() direction = input_double("Enter course (1.0--8.9): ") if not direction or direction < 1.0 or direction > 9.0: - print("Invalid course.") - print() + game.display("Invalid course.") + game.display() return dist = input_double( "Enter warp factor (0.1--{0}): ".format(max_warp_factor)) if not dist or dist < 0.1 or dist > max_warp_factor: - print("Invalid warp factor.") - print() + game.display("Invalid warp factor.") + game.display() return - print() + game.display() dist *= 8 energy_required = int(dist) if energy_required >= game.energy: - print("Unable to comply. Insufficient energy to travel that speed.") - print() + game.display("Unable to comply. Insufficient energy to travel that speed.") + game.display() return else: - print("Warp engines engaged.") - print() + game.display("Warp engines engaged.") + game.display() game.energy -= energy_required last_quad_x = game.quadrant_x @@ -617,8 +619,8 @@ def navigation(): game.sector_x = last_sect_x game.sector_y = last_sect_y game.sector[game.sector_y][game.sector_x] = sector_type.enterprise - print("Encountered obstacle within quadrant.") - print() + game.display("Encountered obstacle within quadrant.") + game.display() obstacle = True break last_sect_x = sect_x @@ -667,14 +669,14 @@ def navigation(): short_range_scan() if game.docked: - print("Lowering shields as part of docking sequence...") - print("Enterprise successfully docked with starbase.") - print() + game.display("Lowering shields as part of docking sequence...") + game.display("Enterprise successfully docked with starbase.") + game.display() else: if game.quadrants[game.quadrant_y][game.quadrant_x].klingons > 0 \ and last_quad_x == game.quadrant_x and last_quad_y == game.quadrant_y: klingons_attack() - print() + game.display() elif not repair_damage(): induce_damage(-1) @@ -746,13 +748,13 @@ def read_sector(i, j): def short_range_scan(): global game if game.short_range_scan_damage > 0: - print("Short range scanner is damaged. Repairs are underway.") - print() + game.display("Short range scanner is damaged. Repairs are underway.") + game.display() else: quadrant = game.quadrants[game.quadrant_y][game.quadrant_x] quadrant.scanned = True print_sector(quadrant) - print() + game.display() def print_sector(quadrant): @@ -764,7 +766,7 @@ def print_sector(quadrant): game.condition = "YELLOW" sb = "" - print("-=--=--=--=--=--=--=--=- Region: {0}".format(quadrant.name)) + game.display("-=--=--=--=--=--=--=--=- Region: {0}".format(quadrant.name)) print_sector_row(sb, 0, " Quadrant: [{0},{1}]".format( game.quadrant_x + 1, game.quadrant_y + 1)) print_sector_row(sb, 1, " Sector: [{0},{1}]".format(game.sector_x + 1, game.sector_y + 1)) @@ -774,16 +776,16 @@ def print_sector(quadrant): print_sector_row(sb, 5, " Energy: {0}".format(game.energy)) print_sector_row(sb, 6, " Shields: {0}".format(game.shield_level)) print_sector_row(sb, 7, " Photon Torpedoes: {0}".format(game.photon_torpedoes)) - print("-=--=--=--=--=--=--=--=- Docked: {0}".format(game.docked)) + game.display("-=--=--=--=--=--=--=--=- Docked: {0}".format(game.docked)) if quadrant.klingons > 0: - print() - print("Condition RED: Klingon ship{0} detected.".format("" if quadrant.klingons == 1 else "s")) + game.display() + game.display("Condition RED: Klingon ship{0} detected.".format("" if quadrant.klingons == 1 else "s")) if game.shield_level == 0 and not game.docked: - print("Warning: Shields are down.") + game.display("Warning: Shields are down.") elif game.energy < 300: - print() - print("Condition YELLOW: Low energy level.") + game.display() + game.display("Condition YELLOW: Low energy level.") game.condition = "YELLOW" @@ -802,14 +804,14 @@ def print_sector_row(sb, row, suffix): sb += ">S<" if suffix is not None: sb = sb + suffix - print(sb) + game.display(sb) def print_mission(): global game - print("Mission: Destroy {0} Klingon ships in {1} stardates with {2} starbases.".format( + game.display("Mission: Destroy {0} Klingon ships in {1} stardates with {2} starbases.".format( game.klingons, game.time_remaining, game.starbases)) - print() + game.display() def initialize_game(): @@ -837,7 +839,7 @@ def initialize_game(): game.docked = False names = [] - for name in strings.quadrantNames: + for name in TrekStrings.quadrantNames: names.append(name) for i in range(8): @@ -865,8 +867,8 @@ def initialize_game(): def print_strings(string_list): for string in string_list: - print(string) - print() + game.display(string) + game.display() if __name__ == '__main__': diff --git a/strings.py b/TrekStrings.py similarity index 100% rename from strings.py rename to TrekStrings.py From 80ca38b5b3701dd10d0d15e3115a5dd77edb87d9 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Sat, 19 Dec 2020 13:37:22 -0500 Subject: [PATCH 010/100] Eliminate in-play input execption. --- AbsDisplay.py | 12 ++++++++++++ StarTrek2020.py | 30 ++++++++++-------------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/AbsDisplay.py b/AbsDisplay.py index 5579ea7..909958c 100644 --- a/AbsDisplay.py +++ b/AbsDisplay.py @@ -38,6 +38,18 @@ def __init__(self): def display(self, message = ''): print(message) + def read(self, prompt=''): + return input(prompt) + + def read_double(self, prompt): + text = input(prompt) + try: + value = float(text) + return value + except: + pass + return False + if __name__ == '__main__': diff --git a/StarTrek2020.py b/StarTrek2020.py index 9d0fa4a..e7f9698 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -91,7 +91,7 @@ def print_game_status(): def command_prompt(): - command = input("Enter command: ").strip().lower() + command = game.read("Enter command: ").strip().lower() game.display() if command == "nav": navigation() @@ -120,7 +120,7 @@ def computer_controls(): game.display() return print_strings(TrekStrings.computerStrings) - command = input("Enter computer command: ").strip().lower() + command = game.read("Enter computer command: ").strip().lower() if command == "rec": display_galactic_record() elif command == "sta": @@ -172,12 +172,12 @@ def navigation_calculator(): game.display("Enterprise located in quadrant [%s,%s]." % \ (game.quadrant_x + 1, game.quadrant_y + 1)) game.display() - quad_x = input_double("Enter destination quadrant X (1--8): ") + quad_x = game.read_double("Enter destination quadrant X (1--8): ") if quad_x is False or quad_x < 1 or quad_x > 8: game.display("Invalid X coordinate.") game.display() return - quad_y = input_double("Enter destination quadrant Y (1--8): ") + quad_y = game.read_double("Enter destination quadrant Y (1--8): ") if quad_y is False or quad_y < 1 or quad_y > 8: game.display("Invalid Y coordinate.") game.display() @@ -276,7 +276,7 @@ def phaser_controls(): game.display() return game.display("Phasers locked on target.") - phaser_energy = input_double("Enter phaser energy (1--{0}): ".format(game.energy)) + phaser_energy = game.read_double("Enter phaser energy (1--{0}): ".format(game.energy)) if not phaser_energy or phaser_energy < 1 or phaser_energy > game.energy: game.display("Invalid energy level.") game.display() @@ -317,7 +317,7 @@ def shield_controls(): game.display("sub = Subtract energy from shields.") game.display() game.display("Enter shield control command: ") - command = input("Enter shield control command: ").strip().lower() + command = game.read("Enter shield control command: ").strip().lower() game.display() if command == "add": adding = True @@ -329,7 +329,7 @@ def shield_controls(): game.display("Invalid command.") game.display() return - transfer = input_double( + transfer = game.read_double( "Enter amount of energy (1--{0}): ".format(max_transfer)) if not transfer or transfer < 1 or transfer > max_transfer: game.display("Invalid amount of energy.") @@ -499,7 +499,7 @@ def torpedo_control(): game.display("There are no Klingon ships in this quadrant.") game.display() return - direction = input_double("Enter firing direction (1.0--9.0): ") + direction = game.read_double("Enter firing direction (1.0--9.0): ") if not direction or direction < 1.0 or direction > 9.0: game.display("Invalid direction.") game.display() @@ -567,13 +567,13 @@ def navigation(): game.display("Warp engines damaged. Maximum warp factor: {0}".format(max_warp_factor)) game.display() - direction = input_double("Enter course (1.0--8.9): ") + direction = game.read_double("Enter course (1.0--8.9): ") if not direction or direction < 1.0 or direction > 9.0: game.display("Invalid course.") game.display() return - dist = input_double( + dist = game.read_double( "Enter warp factor (0.1--{0}): ".format(max_warp_factor)) if not dist or dist < 0.1 or dist > max_warp_factor: game.display("Invalid warp factor.") @@ -680,16 +680,6 @@ def navigation(): elif not repair_damage(): induce_damage(-1) - -def input_double(prompt): - text = input(prompt) - value = float(text) - if type(value) == float: - return value - else: - return False - - def generate_sector(): global game quadrant = game.quadrants[game.quadrant_y][game.quadrant_x] From b0c491b87da87c9a8d00cca9f3e6ab688319706f Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Sat, 19 Dec 2020 16:47:12 -0500 Subject: [PATCH 011/100] Major refactoring. Mostly harmless. --- .gitignore | 6 + AbsDisplay.py | 7 + Aliens.py | 36 ++ Assets.py | 87 +++++ Calculators.py | 227 +++++++++++ Controls.py | 192 ++++++++++ Map.py | 5 + Reports.py | 62 +++ Scanners.py | 44 +++ StarTrek2020.py | 999 ++++++++++-------------------------------------- 10 files changed, 863 insertions(+), 802 deletions(-) create mode 100644 Aliens.py create mode 100644 Assets.py create mode 100644 Calculators.py create mode 100644 Controls.py create mode 100644 Map.py create mode 100644 Reports.py create mode 100644 Scanners.py diff --git a/.gitignore b/.gitignore index c6c77ab..f189e89 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,9 @@ /__pycache__/strings.cpython-37.pyc /__pycache__/AbsDisplay.cpython-37.pyc /.vs/VSWorkspaceState.json +/__pycache__/Aliens.cpython-37.pyc +/__pycache__/Scanners.cpython-37.pyc +/__pycache__/Reports.cpython-37.pyc +/__pycache__/Controls.cpython-37.pyc +/__pycache__/Calculators.cpython-37.pyc +/__pycache__/Assets.cpython-37.pyc diff --git a/AbsDisplay.py b/AbsDisplay.py index 909958c..8366387 100644 --- a/AbsDisplay.py +++ b/AbsDisplay.py @@ -27,6 +27,12 @@ def display(self, message): pass + def print_strings(self, string_list): + for string in string_list: + self.display(string) + self.display() + + class console(abs_display): ''' The best place to start is by encapsulating the default @@ -52,6 +58,7 @@ def read_double(self, prompt): + if __name__ == '__main__': con = console() con.display("Testing!") diff --git a/Aliens.py b/Aliens.py new file mode 100644 index 0000000..8c7eacf --- /dev/null +++ b/Aliens.py @@ -0,0 +1,36 @@ +import random + +from Assets import ship + +class attack(object): + + @staticmethod + def klingons_attack(game): + from Calculators import calculator + if len(game.klingon_ships) > 0: + for ship in game.klingon_ships: + if game.docked: + game.display("Enterprise hit by ship at sector [{0},{1}]. No damage due to starbase shields.".format( + ship.sector_x + 1, ship.sector_y + 1 + )) + else: + dist = calculator.distance( + game.sector_x, game.sector_y, ship.sector_x, ship.sector_y) + delivered_energy = 300 * \ + random.uniform(0.0, 1.0) * (1.0 - dist / 11.3) + game.shield_level -= int(delivered_energy) + if game.shield_level < 0: + game.shield_level = 0 + game.destroyed = True + game.display("Enterprise hit by ship at sector [{0},{1}]. Shields dropped to {2}.".format( + ship.sector_x + 1, ship.sector_y + 1, game.shield_level + )) + if game.shield_level == 0: + return True + return True + return False + + + + + diff --git a/Assets.py b/Assets.py new file mode 100644 index 0000000..abf7aea --- /dev/null +++ b/Assets.py @@ -0,0 +1,87 @@ +import random + + +class ship(object): + + @staticmethod + def induce_damage(game, item): + if random.randint(0, 6) > 0: + return + damage = 1 + random.randint(0, 4) + if item < 0: + item = random.randint(0, 6) + if item == 0: + game.navigation_damage = damage + game.display("Warp engines are malfunctioning.") + elif item == 1: + game.short_range_scan_damage = damage + game.display("Short range scanner is malfunctioning.") + elif item == 2: + game.long_range_scan_damage = damage + game.display("Long range scanner is malfunctioning.") + elif item == 3: + game.shield_control_damage = damage + game.display("Shield controls are malfunctioning.") + elif item == 4: + game.computer_damage = damage + game.display("The main computer is malfunctioning.") + elif item == 5: + game.photon_damage = damage + game.display("Photon torpedo controls are malfunctioning.") + elif item == 6: + game.phaser_damage = damage + game.display("Phasers are malfunctioning.") + game.display() + + + @staticmethod + def repair_damage(game): + if game.navigation_damage > 0: + game.navigation_damage -= 1 + if game.navigation_damage == 0: + game.display("Warp engines have been repaired.") + game.display() + return True + if game.short_range_scan_damage > 0: + game.short_range_scan_damage -= 1 + if game.short_range_scan_damage == 0: + game.display("Short range scanner has been repaired.") + game.display() + return True + if game.long_range_scan_damage > 0: + game.long_range_scan_damage -= 1 + if game.long_range_scan_damage == 0: + game.display("Long range scanner has been repaired.") + game.display() + return True + if game.shield_control_damage > 0: + game.shield_control_damage -= 1 + if game.shield_control_damage == 0: + game.display("Shield controls have been repaired.") + game.display() + return True + if game.computer_damage > 0: + game.computer_damage -= 1 + if game.computer_damage == 0: + game.display("The main computer has been repaired.") + game.display() + return True + if game.photon_damage > 0: + game.photon_damage -= 1 + if game.photon_damage == 0: + game.display("Photon torpedo controls have been repaired.") + game.display() + return True + if game.phaser_damage > 0: + game.phaser_damage -= 1 + if game.phaser_damage == 0: + game.display("Phasers have been repaired.") + game.display() + return True + return False + + + + + + diff --git a/Calculators.py b/Calculators.py new file mode 100644 index 0000000..a44e864 --- /dev/null +++ b/Calculators.py @@ -0,0 +1,227 @@ +from math import atan2, pi, sqrt, cos, sin +import random + +from Scanners import scanner +from Assets import ship +from Aliens import attack + +class calculator(object): + + @staticmethod + def distance(x1, y1, x2, y2): + x = x2 - x1 + y = y2 - y1 + return sqrt(x * x + y * y) + + @staticmethod + def navigation(game): + max_warp_factor = 8.0 + if game.navigation_damage > 0: + max_warp_factor = 0.2 + random.randint(0, 8) / 10.0 + game.display("Warp engines damaged. Maximum warp factor: {0}".format(max_warp_factor)) + game.display() + + direction = game.read_double("Enter course (1.0--8.9): ") + if not direction or direction < 1.0 or direction > 9.0: + game.display("Invalid course.") + game.display() + return + + dist = game.read_double( + "Enter warp factor (0.1--{0}): ".format(max_warp_factor)) + if not dist or dist < 0.1 or dist > max_warp_factor: + game.display("Invalid warp factor.") + game.display() + return + + game.display() + + dist *= 8 + energy_required = int(dist) + if energy_required >= game.energy: + game.display("Unable to comply. Insufficient energy to travel that speed.") + game.display() + return + else: + game.display("Warp engines engaged.") + game.display() + game.energy -= energy_required + + last_quad_x = game.quadrant_x + last_quad_y = game.quadrant_y + angle = -(pi * (direction - 1.0) / 4.0) + x = game.quadrant_x * 8 + game.sector_x + y = game.quadrant_y * 8 + game.sector_y + dx = dist * cos(angle) + dy = dist * sin(angle) + vx = dx / 1000 + vy = dy / 1000 + # quad_x = quad_y = sect_x = sect_y = 0 + last_sect_x = game.sector_x + last_sect_y = game.sector_y + game.sector[game.sector_y][game.sector_x] = game.sector_type.empty + obstacle = False + for i in range(999): + x += vx + y += vy + quad_x = int(round(x)) / 8 + quad_y = int(round(y)) / 8 + if quad_x == game.quadrant_x and quad_y == game.quadrant_y: + sect_x = int(round(x)) % 8 + sect_y = int(round(y)) % 8 + if game.sector[sect_y][sect_x] != game.sector_type.empty: + game.sector_x = last_sect_x + game.sector_y = last_sect_y + game.sector[game.sector_y][game.sector_x] = game.sector_type.enterprise + game.display("Encountered obstacle within quadrant.") + game.display() + obstacle = True + break + last_sect_x = sect_x + last_sect_y = sect_y + + if not obstacle: + if x < 0: + x = 0 + elif x > 63: + x = 63 + if y < 0: + y = 0 + elif y > 63: + y = 63 + quad_x = int(round(x)) / 8 + quad_y = int(round(y)) / 8 + game.sector_x = int(round(x)) % 8 + game.sector_y = int(round(y)) % 8 + if quad_x != game.quadrant_x or quad_y != game.quadrant_y: + game.quadrant_x = int(quad_x) + game.quadrant_y = int(quad_y) + game.generate_sector() + else: + game.quadrant_x = int(quad_x) + game.quadrant_y = int(quad_y) + game.sector[game.sector_y][game.sector_x] = game.sector_type.enterprise + if game.is_docking_location(game.sector_y, game.sector_x): + game.energy = 3000 + game.photon_torpedoes = 10 + game.navigation_damage = 0 + game.short_range_scan_damage = 0 + game.long_range_scan_damage = 0 + game.shield_control_damage = 0 + game.computer_damage = 0 + game.photon_damage = 0 + game.phaser_damage = 0 + game.shield_level = 0 + game.docked = True + else: + game.docked = False + + if last_quad_x != game.quadrant_x or last_quad_y != game.quadrant_y: + game.time_remaining -= 1 + game.star_date += 1 + + scanner.short_range_scan(game) + + if game.docked: + game.display("Lowering shields as part of docking sequence...") + game.display("Enterprise successfully docked with starbase.") + game.display() + else: + if game.quadrants[game.quadrant_y][game.quadrant_x].klingons > 0 \ + and last_quad_x == game.quadrant_x and last_quad_y == game.quadrant_y: + attack.klingons_attack(game) + game.display() + elif not ship.repair_damage(game): + ship.induce_damage(game, -1) + + + @staticmethod + def compute_direction(x1, y1, x2, y2): + if x1 == x2: + if y1 < y2: + direction = 7 + else: + direction = 3 + elif y1 == y2: + if x1 < x2: + direction = 1 + else: + direction = 5 + else: + dy = abs(y2 - y1) + dx = abs(x2 - x1) + angle = atan2(dy, dx) + if x1 < x2: + if y1 < y2: + direction = 9.0 - 4.0 * angle / pi + else: + direction = 1.0 + 4.0 * angle / pi + else: + if y1 < y2: + direction = 5.0 + 4.0 * angle / pi + else: + direction = 5.0 - 4.0 * angle / pi + return direction + + + @staticmethod + def navigation_calculator(game): + game.display() + game.display("Enterprise located in quadrant [%s,%s]." % \ + (game.quadrant_x + 1, game.quadrant_y + 1)) + game.display() + quad_x = game.read_double("Enter destination quadrant X (1--8): ") + if quad_x is False or quad_x < 1 or quad_x > 8: + game.display("Invalid X coordinate.") + game.display() + return + quad_y = game.read_double("Enter destination quadrant Y (1--8): ") + if quad_y is False or quad_y < 1 or quad_y > 8: + game.display("Invalid Y coordinate.") + game.display() + return + game.display() + qx = int(quad_x) - 1 + qy = int(quad_y) - 1 + if qx == game.quadrant_x and qy == game.quadrant_y: + game.display("That is the current location of the Enterprise.") + game.display() + return + direction = calculator.compute_direction(game.quadrant_x, game.quadrant_y, qx, qy) + game.display("Direction: {0:1.2f}".format(direction)) + game.display("Distance: {0:2.2f}".format( + calculator.distance(game.quadrant_x, game.quadrant_y, qx, qy))) + game.display() + + @staticmethod + def starbase_calculator(game): + game.display() + if game.quadrants[game.quadrant_y][game.quadrant_x].starbase: + game.display("Starbase in sector [%s,%s]." % (game.starbase_x + 1, game.starbase_y + 1)) + direction = calculator.compute_direction(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) + game.display("Direction: {0:1.2f}".format(direction)) + game.display("Distance: {0:2.2f}".format( + calculator.distance(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) / 8)) + else: + game.display("There are no starbases in this quadrant.") + game.display() + + @staticmethod + def photon_torpedo_calculator(game): + game.display() + if len(game.klingon_ships) == 0: + game.display("There are no Klingon ships in this quadrant.") + game.display() + return + + for ship in game.klingon_ships: + text = "Direction {2:1.2f}: Klingon ship in sector [{0},{1}]." + direction = compute_direction(game.sector_x, game.sector_y, ship.sector_x, ship.sector_y) + game.display(text.format( + ship.sector_x + 1, ship.sector_y + 1, direction)) + game.display() + + + + + diff --git a/Controls.py b/Controls.py new file mode 100644 index 0000000..3d4d965 --- /dev/null +++ b/Controls.py @@ -0,0 +1,192 @@ +from math import pi, sqrt, cos, sin +import random + +import TrekStrings +from Assets import ship +from Aliens import attack +from Calculators import calculator +from Reports import status + + +class control(object): + + @staticmethod + def computer_controls(game): + if game.computer_damage > 0: + game.display("The main computer is damaged. Repairs are underway.") + game.display() + return + game.print_strings(TrekStrings.computerStrings) + command = game.read("Enter computer command: ").strip().lower() + if command == "rec": + status.display_galactic_record(game) + elif command == "sta": + status.display_status(game) + elif command == "tor": + calculator.photon_torpedo_calculator(game) + elif command == "bas": + calculator.starbase_calculator(game) + elif command == "nav": + calculator.navigation_calculator(game) + else: + game.display() + game.display("Invalid computer command.") + game.display() + ship.induce_damage(game, 4) + + + @staticmethod + def phaser_controls(game): + if game.phaser_damage > 0: + game.display("Phasers are damaged. Repairs are underway.") + game.display() + return + if len(game.klingon_ships) == 0: + game.display("There are no Klingon ships in this quadrant.") + game.display() + return + game.display("Phasers locked on target.") + phaser_energy = game.read_double("Enter phaser energy (1--{0}): ".format(game.energy)) + if not phaser_energy or phaser_energy < 1 or phaser_energy > game.energy: + game.display("Invalid energy level.") + game.display() + return + game.display() + game.display("Firing phasers...") + destroyed_ships = [] + for ship in game.klingon_ships: + game.energy -= int(phaser_energy) + if game.energy < 0: + game.energy = 0 + break + dist = calculator.distance(game.sector_x, game.sector_y, ship.sector_x, ship.sector_y) + delivered_energy = phaser_energy * (1.0 - dist / 11.3) + ship.shield_level -= int(delivered_energy) + if ship.shield_level <= 0: + game.display("Klingon ship destroyed at sector [{0},{1}].".format(ship.sector_x + 1, ship.sector_y + 1)) + destroyed_ships.append(ship) + else: + game.display("Hit ship at sector [{0},{1}]. Klingon shield strength dropped to {2}.".format( + ship.sector_x + 1, ship.sector_y + 1, ship.shield_level + )) + for ship in destroyed_ships: + game.quadrants[game.quadrant_y][game.quadrant_x].klingons -= 1 + game.klingons -= 1 + game.sector[ship.sector_y][ship.sector_x] = game.sector_type.empty + game.klingon_ships.remove(ship) + if len(game.klingon_ships) > 0: + game.display() + attack.klingons_attack(game) + game.display() + + + def shield_controls(game): + game.display("--- Shield Controls ----------------") + game.display("add = Add energy to shields.") + game.display("sub = Subtract energy from shields.") + game.display() + command = game.read("Enter shield control command: ").strip().lower() + game.display() + if command == "add": + adding = True + max_transfer = game.energy + elif command == "sub": + adding = False + max_transfer = game.shield_level + else: + game.display("Invalid command.") + game.display() + return + transfer = game.read_double( + "Enter amount of energy (1--{0}): ".format(max_transfer)) + if not transfer or transfer < 1 or transfer > max_transfer: + game.display("Invalid amount of energy.") + game.display() + return + game.display() + if adding: + game.energy -= int(transfer) + game.shield_level += int(transfer) + else: + game.energy += int(transfer) + game.shield_level -= int(transfer) + game.display("Shield strength is now {0}. Energy level is now {1}.".format(game.shield_level, game.energy)) + game.display() + + + def torpedo_control(game): + if game.photon_damage > 0: + game.display("Photon torpedo control is damaged. Repairs are underway.") + game.display() + return + if game.photon_torpedoes == 0: + game.display("Photon torpedoes exhausted.") + game.display() + return + if len(game.klingon_ships) == 0: + game.display("There are no Klingon ships in this quadrant.") + game.display() + return + direction = game.read_double("Enter firing direction (1.0--9.0): ") + if not direction or direction < 1.0 or direction > 9.0: + game.display("Invalid direction.") + game.display() + return + game.display() + game.display("Photon torpedo fired...") + game.photon_torpedoes -= 1 + angle = -(pi * (direction - 1.0) / 4.0) + if random.randint(0, 2) == 0: + angle += (1.0 - 2.0 * random.uniform(0.0, 1.0) * pi * 2.0) * 0.03 + x = game.sector_x + y = game.sector_y + vx = cos(angle) / 20 + vy = sin(angle) / 20 + last_x = last_y = -1 + # new_x = game.sector_x + # new_y = game.sector_y + hit = False + while x >= 0 and y >= 0 and round(x) < 8 and round(y) < 8: + new_x = int(round(x)) + new_y = int(round(y)) + if last_x != new_x or last_y != new_y: + game.display(" [{0},{1}]".format(new_x + 1, new_y + 1)) + last_x = new_x + last_y = new_y + for ship in game.klingon_ships: + if ship.sector_x == new_x and ship.sector_y == new_y: + game.display("Klingon ship destroyed at sector [{0},{1}].".format(ship.sector_x + 1, ship.sector_y + 1)) + game.sector[ship.sector_y][ship.sector_x] = game.sector_type.empty + game.klingons -= 1 + game.klingon_ships.remove(ship) + game.quadrants[game.quadrant_y][game.quadrant_x].klingons -= 1 + hit = True + break # break out of the for loop + if hit: + break # break out of the while loop + if game.sector[new_y][new_x] == game.sector_type.starbase: + game.starbases -= 1 + game.quadrants[game.quadrant_y][game.quadrant_x].starbase = False + game.sector[new_y][new_x] = game.sector_type.empty + game.display("The Enterprise destroyed a Federation starbase at sector [{0},{1}]!".format(new_x + 1, new_y + 1)) + hit = True + break + elif game.sector[new_y][new_x] == game.sector_type.star: + game.display("The torpedo was captured by a star's gravitational field at sector [{0},{1}].".format( + new_x + 1, new_y + 1 + )) + hit = True + break + x += vx + y += vy + if not hit: + game.display("Photon torpedo failed to hit anything.") + if len(game.klingon_ships) > 0: + game.display() + attack.klingons_attack(game) + game.display() + + + + + diff --git a/Map.py b/Map.py new file mode 100644 index 0000000..6440f74 --- /dev/null +++ b/Map.py @@ -0,0 +1,5 @@ +class sector(object): + pass + + + diff --git a/Reports.py b/Reports.py new file mode 100644 index 0000000..49a9663 --- /dev/null +++ b/Reports.py @@ -0,0 +1,62 @@ + +class status(object): + + @staticmethod + def display_status(game): + game.display() + game.display(" Time Remaining: {0}".format(game.time_remaining)) + game.display(" Klingon Ships Remaining: {0}".format(game.klingons)) + game.display(" Starbases: {0}".format(game.starbases)) + game.display(" Warp Engine Damage: {0}".format(game.navigation_damage)) + game.display(" Short Range Scanner Damage: {0}".format(game.short_range_scan_damage)) + game.display(" Long Range Scanner Damage: {0}".format(game.long_range_scan_damage)) + game.display(" Shield Controls Damage: {0}".format(game.shield_control_damage)) + game.display(" Main Computer Damage: {0}".format(game.computer_damage)) + game.display("Photon Torpedo Control Damage: {0}".format(game.photon_damage)) + game.display(" Phaser Damage: {0}".format(game.phaser_damage)) + game.display() + + + @staticmethod + def display_galactic_record(game): + game.display() + sb = "" + game.display("-------------------------------------------------") + for i in range(8): + for j in range(8): + sb += "| " + klingon_count = 0 + starbase_count = 0 + star_count = 0 + quadrant = game.quadrants[i][j] + if quadrant.scanned: + klingon_count = quadrant.klingons + starbase_count = 1 if quadrant.starbase else 0 + star_count = quadrant.stars + sb = sb + \ + "{0}{1}{2} ".format(klingon_count, starbase_count, star_count) + sb += "|" + game.display(sb) + sb = "" + game.display("-------------------------------------------------") + game.display() + + + @staticmethod + def print_game_status(game): + if game.destroyed: + game.display("MISSION FAILED: ENTERPRISE DESTROYED!!!") + game.display('\n'*2) + elif game.energy == 0: + game.display("MISSION FAILED: ENTERPRISE RAN OUT OF ENERGY.") + game.display('\n'*2) + elif game.klingons == 0: + game.display("MISSION ACCOMPLISHED: ALL KLINGON SHIPS DESTROYED. WELL DONE!!!") + game.display('\n'*2) + elif game.time_remaining == 0: + game.display("MISSION FAILED: ENTERPRISE RAN OUT OF TIME.") + game.display('\n'*2) + + + + diff --git a/Scanners.py b/Scanners.py new file mode 100644 index 0000000..eb97c8b --- /dev/null +++ b/Scanners.py @@ -0,0 +1,44 @@ +class scanner(object): + + @staticmethod + def short_range_scan(game): + if game.short_range_scan_damage > 0: + game.display("Short range scanner is damaged. Repairs are underway.") + game.display() + else: + quadrant = game.quadrants[game.quadrant_y][game.quadrant_x] + quadrant.scanned = True + game.print_sector(quadrant) + game.display() + + @staticmethod + def long_range_scan(game): + if game.long_range_scan_damage > 0: + game.display("Long range scanner is damaged. Repairs are underway.") + game.display() + return + sb = "" + game.display("-------------------") + for i in range(game.quadrant_y - 1, game.quadrant_y+2): # quadrantY + 1 ? + for j in range(game.quadrant_x - 1, game.quadrant_x+2): # quadrantX + 1? + sb += "| " + klingon_count = 0 + starbase_count = 0 + star_count = 0 + if 0 <= i < 8 and 0 <= j < 8: + quadrant = game.quadrants[i][j] + quadrant.scanned = True + klingon_count = quadrant.klingons + starbase_count = 1 if quadrant.starbase else 0 + star_count = quadrant.stars + sb = sb + \ + "{0}{1}{2} ".format(klingon_count, starbase_count, star_count) + sb += "|" + game.display(sb) + sb = "" + game.display("-------------------") + game.display() + + + + diff --git a/StarTrek2020.py b/StarTrek2020.py index e7f9698..55223b9 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -1,9 +1,13 @@ -from math import atan2, pi, sqrt, cos, sin +from math import pi, sqrt, cos, sin import random import TrekStrings from AbsDisplay import console +from Calculators import calculator +from Controls import control +from Scanners import scanner +from Reports import status class Quadrant(): @@ -21,8 +25,6 @@ class SectorType(): def __init__(self): self.empty, self.star, self.klingon, self.enterprise, self.starbase = 1, 2, 3, 4, 5 -sector_type = SectorType() - class KlingonShip(): @@ -40,6 +42,7 @@ def __init__(self): self.energy = 0 self.klingons = 0 self.starbases = 0 + self.sector_type = SectorType() self.quadrant_x, self.quadrant_y = 0, 0 self.sector_x, self.sector_y = 0, 0 self.shield_level = 0 @@ -58,808 +61,200 @@ def __init__(self): self.sector = [[SectorType() for _ in range(8)] for _ in range(8)] self.klingon_ships = [] -game = Game() - - -def run(): - global game - print_strings(TrekStrings.titleStrings) - while True: - initialize_game() - print_mission() - generate_sector() - print_strings(TrekStrings.commandStrings) - while game.energy > 0 and not game.destroyed and game.klingons > 0 and game.time_remaining > 0: - command_prompt() - print_game_status() - - -def print_game_status(): - global game - if game.destroyed: - game.display("MISSION FAILED: ENTERPRISE DESTROYED!!!") - game.display('\n'*2) - elif game.energy == 0: - game.display("MISSION FAILED: ENTERPRISE RAN OUT OF ENERGY.") - game.display('\n'*2) - elif game.klingons == 0: - game.display("MISSION ACCOMPLISHED: ALL KLINGON SHIPS DESTROYED. WELL DONE!!!") - game.display('\n'*2) - elif game.time_remaining == 0: - game.display("MISSION FAILED: ENTERPRISE RAN OUT OF TIME.") - game.display('\n'*2) - - -def command_prompt(): - command = game.read("Enter command: ").strip().lower() - game.display() - if command == "nav": - navigation() - elif command == "srs": - short_range_scan() - elif command == "lrs": - long_range_scan() - elif command == "pha": - phaser_controls() - elif command == "tor": - torpedo_control() - elif command == "she": - shield_controls() - elif command == "com": - computer_controls() - elif command.startswith('qui') or command.startswith('exi'): - exit() - else: - print_strings(TrekStrings.commandStrings) - - -def computer_controls(): - global game - if game.computer_damage > 0: - game.display("The main computer is damaged. Repairs are underway.") - game.display() - return - print_strings(TrekStrings.computerStrings) - command = game.read("Enter computer command: ").strip().lower() - if command == "rec": - display_galactic_record() - elif command == "sta": - display_status() - elif command == "tor": - photon_torpedo_calculator() - elif command == "bas": - starbase_calculator() - elif command == "nav": - navigation_calculator() - else: - game.display() - game.display("Invalid computer command.") - game.display() - induce_damage(4) - - -def compute_direction(x1, y1, x2, y2): - if x1 == x2: - if y1 < y2: - direction = 7 - else: - direction = 3 - elif y1 == y2: - if x1 < x2: - direction = 1 - else: - direction = 5 - else: - dy = abs(y2 - y1) - dx = abs(x2 - x1) - angle = atan2(dy, dx) - if x1 < x2: - if y1 < y2: - direction = 9.0 - 4.0 * angle / pi - else: - direction = 1.0 + 4.0 * angle / pi - else: - if y1 < y2: - direction = 5.0 + 4.0 * angle / pi - else: - direction = 5.0 - 4.0 * angle / pi - return direction - - -def navigation_calculator(): - global game - game.display() - game.display("Enterprise located in quadrant [%s,%s]." % \ - (game.quadrant_x + 1, game.quadrant_y + 1)) - game.display() - quad_x = game.read_double("Enter destination quadrant X (1--8): ") - if quad_x is False or quad_x < 1 or quad_x > 8: - game.display("Invalid X coordinate.") - game.display() - return - quad_y = game.read_double("Enter destination quadrant Y (1--8): ") - if quad_y is False or quad_y < 1 or quad_y > 8: - game.display("Invalid Y coordinate.") - game.display() - return - game.display() - qx = int(quad_x) - 1 - qy = int(quad_y) - 1 - if qx == game.quadrant_x and qy == game.quadrant_y: - game.display("That is the current location of the Enterprise.") - game.display() - return - game.display("Direction: {0:1.2f}".format(compute_direction(game.quadrant_x, game.quadrant_y, qx, qy))) - game.display("Distance: {0:2.2f}".format(distance(game.quadrant_x, game.quadrant_y, qx, qy))) - game.display() - - -def starbase_calculator(): - global game - game.display() - if game.quadrants[game.quadrant_y][game.quadrant_x].starbase: - game.display("Starbase in sector [%s,%s]." % (game.starbase_x + 1, game.starbase_y + 1)) - game.display("Direction: {0:1.2f}".format( - compute_direction(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) - )) - game.display("Distance: {0:2.2f}".format(distance(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) / 8)) - else: - game.display("There are no starbases in this quadrant.") - game.display() - - -def photon_torpedo_calculator(): - global game - game.display() - if len(game.klingon_ships) == 0: - game.display("There are no Klingon ships in this quadrant.") - game.display() - return - - for ship in game.klingon_ships: - text = "Direction {2:1.2f}: Klingon ship in sector [{0},{1}]." - game.display(text.format( - ship.sector_x + 1, ship.sector_y + 1, - compute_direction(game.sector_x, game.sector_y, ship.sector_x, ship.sector_y))) - game.display() - - -def display_status(): - global game - game.display() - game.display(" Time Remaining: {0}".format(game.time_remaining)) - game.display(" Klingon Ships Remaining: {0}".format(game.klingons)) - game.display(" Starbases: {0}".format(game.starbases)) - game.display(" Warp Engine Damage: {0}".format(game.navigation_damage)) - game.display(" Short Range Scanner Damage: {0}".format(game.short_range_scan_damage)) - game.display(" Long Range Scanner Damage: {0}".format(game.long_range_scan_damage)) - game.display(" Shield Controls Damage: {0}".format(game.shield_control_damage)) - game.display(" Main Computer Damage: {0}".format(game.computer_damage)) - game.display("Photon Torpedo Control Damage: {0}".format(game.photon_damage)) - game.display(" Phaser Damage: {0}".format(game.phaser_damage)) - game.display() - - -def display_galactic_record(): - global game - game.display() - sb = "" - game.display("-------------------------------------------------") - for i in range(8): - for j in range(8): - sb += "| " - klingon_count = 0 - starbase_count = 0 - star_count = 0 - quadrant = game.quadrants[i][j] - if quadrant.scanned: - klingon_count = quadrant.klingons - starbase_count = 1 if quadrant.starbase else 0 - star_count = quadrant.stars - sb = sb + \ - "{0}{1}{2} ".format(klingon_count, starbase_count, star_count) - sb += "|" - game.display(sb) - sb = "" - game.display("-------------------------------------------------") - game.display() - - -def phaser_controls(): - global game - if game.phaser_damage > 0: - game.display("Phasers are damaged. Repairs are underway.") - game.display() - return - if len(game.klingon_ships) == 0: - game.display("There are no Klingon ships in this quadrant.") - game.display() - return - game.display("Phasers locked on target.") - phaser_energy = game.read_double("Enter phaser energy (1--{0}): ".format(game.energy)) - if not phaser_energy or phaser_energy < 1 or phaser_energy > game.energy: - game.display("Invalid energy level.") - game.display() - return - game.display() - game.display("Firing phasers...") - destroyed_ships = [] - for ship in game.klingon_ships: - game.energy -= int(phaser_energy) - if game.energy < 0: - game.energy = 0 - break - dist = distance(game.sector_x, game.sector_y, ship.sector_x, ship.sector_y) - delivered_energy = phaser_energy * (1.0 - dist / 11.3) - ship.shield_level -= int(delivered_energy) - if ship.shield_level <= 0: - game.display("Klingon ship destroyed at sector [{0},{1}].".format(ship.sector_x + 1, ship.sector_y + 1)) - destroyed_ships.append(ship) + + def run(self): + self.print_strings(TrekStrings.titleStrings) + while True: + self.initialize_game() + self.print_mission() + self.generate_sector() + self.print_strings(TrekStrings.commandStrings) + while self.energy > 0 and not self.destroyed and self.klingons > 0 and self.time_remaining > 0: + self.command_prompt() + status.print_game_status(game) + + def initialize_game(self): + self.quadrant_x = random.randint(0, 7) + self.quadrant_y = random.randint(0, 7) + self.sector_x = random.randint(0, 7) + self.sector_y = random.randint(0, 7) + self.star_date = random.randint(0, 50) + 2250 + self.energy = 3000 + self.photon_torpedoes = 10 + self.time_remaining = 40 + random.randint(0, 9) + self.klingons = 15 + random.randint(0, 5) + self.starbases = 2 + random.randint(0, 2) + self.destroyed = False + self.navigation_damage = 0 + self.short_range_scan_damage = 0 + self.long_range_scan_damage = 0 + self.shield_control_damage = 0 + self.computer_damage = 0 + self.photon_damage = 0 + self.phaser_damage = 0 + self.shield_level = 0 + self.docked = False + + names = [] + for name in TrekStrings.quadrantNames: + names.append(name) + + for i in range(8): + for j in range(8): + index = random.randint(0, len(names) - 1) + quadrant = Quadrant() + quadrant.name = names[index] + quadrant.stars = 1 + random.randint(0, 7) + self.quadrants[i][j] = quadrant + del names[index] + + klingon_count = self.klingons + starbase_count = self.starbases + while klingon_count > 0 or starbase_count > 0: + i = random.randint(0, 7) + j = random.randint(0, 7) + quadrant = self.quadrants[i][j] + if not quadrant.starbase: + quadrant.starbase = True + starbase_count -= 1 + if quadrant.klingons < 3: + quadrant.klingons += 1 + klingon_count -= 1 + + + def command_prompt(self): + command = self.read("Enter command: ").strip().lower() + self.display() + if command == "nav": + calculator.navigation(game) + elif command == "srs": + scanner.short_range_scan(game) + elif command == "lrs": + scanner.long_range_scan(game) + elif command == "pha": + control.phaser_controls(game) + elif command == "tor": + control.torpedo_control(game) + elif command == "she": + control.shield_controls(game) + elif command == "com": + control.computer_controls(game) + elif command.startswith('qui') or command.startswith('exi'): + exit() else: - game.display("Hit ship at sector [{0},{1}]. Klingon shield strength dropped to {2}.".format( - ship.sector_x + 1, ship.sector_y + 1, ship.shield_level - )) - for ship in destroyed_ships: - game.quadrants[game.quadrant_y][game.quadrant_x].klingons -= 1 - game.klingons -= 1 - game.sector[ship.sector_y][ship.sector_x] = sector_type.empty - game.klingon_ships.remove(ship) - if len(game.klingon_ships) > 0: - game.display() - klingons_attack() - game.display() - - -def shield_controls(): - global game - game.display("--- Shield Controls ----------------") - game.display("add = Add energy to shields.") - game.display("sub = Subtract energy from shields.") - game.display() - game.display("Enter shield control command: ") - command = game.read("Enter shield control command: ").strip().lower() - game.display() - if command == "add": - adding = True - max_transfer = game.energy - elif command == "sub": - adding = False - max_transfer = game.shield_level - else: - game.display("Invalid command.") - game.display() - return - transfer = game.read_double( - "Enter amount of energy (1--{0}): ".format(max_transfer)) - if not transfer or transfer < 1 or transfer > max_transfer: - game.display("Invalid amount of energy.") - game.display() - return - game.display() - if adding: - game.energy -= int(transfer) - game.shield_level += int(transfer) - else: - game.energy += int(transfer) - game.shield_level -= int(transfer) - game.display("Shield strength is now {0}. Energy level is now {1}.".format(game.shield_level, game.energy)) - game.display() - - -def klingons_attack(): - global game - if len(game.klingon_ships) > 0: - for ship in game.klingon_ships: - if game.docked: - game.display("Enterprise hit by ship at sector [{0},{1}]. No damage due to starbase shields.".format( - ship.sector_x + 1, ship.sector_y + 1 - )) - else: - dist = distance( - game.sector_x, game.sector_y, ship.sector_x, ship.sector_y) - delivered_energy = 300 * \ - random.uniform(0.0, 1.0) * (1.0 - dist / 11.3) - game.shield_level -= int(delivered_energy) - if game.shield_level < 0: - game.shield_level = 0 - game.destroyed = True - game.display("Enterprise hit by ship at sector [{0},{1}]. Shields dropped to {2}.".format( - ship.sector_x + 1, ship.sector_y + 1, game.shield_level - )) - if game.shield_level == 0: + self.print_strings(TrekStrings.commandStrings) + + + def is_sector_region_empty(self, i, j): + for y in range(i - 1, i+1): # i + 1? + if self.read_sector(y, j - 1) != \ + self.sector_type.empty and \ + self.read_sector(y, j + 1) != \ + self.sector_type.empty: + return False + return self.read_sector(i, j) == self.sector_type.empty + + + def read_sector(self, i, j): + if i < 0 or j < 0 or i > 7 or j > 7: + return self.sector_type.empty + return self.sector[i][j] + + + def is_docking_location(self, i, j): + for y in range(i - 1, i+1): # i + 1? + for x in range(j - 1, j+1): # j + 1? + if self.read_sector(y, x) == self.sector_type.starbase: return True - return True - return False - - -def distance(x1, y1, x2, y2): - x = x2 - x1 - y = y2 - y1 - return sqrt(x * x + y * y) - - -def induce_damage(item): - global game - if random.randint(0, 6) > 0: - return - damage = 1 + random.randint(0, 4) - if item < 0: - item = random.randint(0, 6) - if item == 0: - game.navigation_damage = damage - game.display("Warp engines are malfunctioning.") - elif item == 1: - game.short_range_scan_damage = damage - game.display("Short range scanner is malfunctioning.") - elif item == 2: - game.long_range_scan_damage = damage - game.display("Long range scanner is malfunctioning.") - elif item == 3: - game.shield_control_damage = damage - game.display("Shield controls are malfunctioning.") - elif item == 4: - game.computer_damage = damage - game.display("The main computer is malfunctioning.") - elif item == 5: - game.photon_damage = damage - game.display("Photon torpedo controls are malfunctioning.") - elif item == 6: - game.phaser_damage = damage - game.display("Phasers are malfunctioning.") - game.display() - - -def repair_damage(): - global game - if game.navigation_damage > 0: - game.navigation_damage -= 1 - if game.navigation_damage == 0: - game.display("Warp engines have been repaired.") - game.display() - return True - if game.short_range_scan_damage > 0: - game.short_range_scan_damage -= 1 - if game.short_range_scan_damage == 0: - game.display("Short range scanner has been repaired.") - game.display() - return True - if game.long_range_scan_damage > 0: - game.long_range_scan_damage -= 1 - if game.long_range_scan_damage == 0: - game.display("Long range scanner has been repaired.") - game.display() - return True - if game.shield_control_damage > 0: - game.shield_control_damage -= 1 - if game.shield_control_damage == 0: - game.display("Shield controls have been repaired.") - game.display() - return True - if game.computer_damage > 0: - game.computer_damage -= 1 - if game.computer_damage == 0: - game.display("The main computer has been repaired.") - game.display() - return True - if game.photon_damage > 0: - game.photon_damage -= 1 - if game.photon_damage == 0: - game.display("Photon torpedo controls have been repaired.") - game.display() - return True - if game.phaser_damage > 0: - game.phaser_damage -= 1 - if game.phaser_damage == 0: - game.display("Phasers have been repaired.") - game.display() - return True - return False - - -def long_range_scan(): - global game - if game.long_range_scan_damage > 0: - game.display("Long range scanner is damaged. Repairs are underway.") - game.display() - return - sb = "" - game.display("-------------------") - for i in range(game.quadrant_y - 1, game.quadrant_y+2): # quadrantY + 1 ? - for j in range(game.quadrant_x - 1, game.quadrant_x+2): # quadrantX + 1? - sb += "| " - klingon_count = 0 - starbase_count = 0 - star_count = 0 - if 0 <= i < 8 and 0 <= j < 8: - quadrant = game.quadrants[i][j] - quadrant.scanned = True - klingon_count = quadrant.klingons - starbase_count = 1 if quadrant.starbase else 0 - star_count = quadrant.stars - sb = sb + \ - "{0}{1}{2} ".format(klingon_count, starbase_count, star_count) - sb += "|" - game.display(sb) + return False + + + def generate_sector(self): + quadrant = self.quadrants[self.quadrant_y][self.quadrant_x] + starbase = quadrant.starbase + stars = quadrant.stars + klingons = quadrant.klingons + self.klingon_ships = [] + for i in range(8): + for j in range(8): + self.sector[i][j] = self.sector_type.empty + self.sector[self.sector_y][self.sector_x] = self.sector_type.enterprise + while starbase or stars > 0 or klingons > 0: + i = random.randint(0, 7) + j = random.randint(0, 7) + if self.is_sector_region_empty(i, j): + if starbase: + starbase = False + self.sector[i][j] = self.sector_type.starbase + self.starbase_y = i + self.starbase_x = j + elif stars > 0: + self.sector[i][j] = self.sector_type.star + stars -= 1 + elif klingons > 0: + self.sector[i][j] = self.sector_type.klingon + klingon_ship = KlingonShip() + klingon_ship.shield_level = 300 + random.randint(0, 199) + klingon_ship.sector_y = i + klingon_ship.sector_x = j + self.klingon_ships.append(klingon_ship) + klingons -= 1 + + + def print_sector(self, quadrant): + self.condition = "GREEN" + if quadrant.klingons > 0: + self.condition = "RED" + elif self.energy < 300: + self.condition = "YELLOW" + sb = "" - game.display("-------------------") - game.display() - - -def torpedo_control(): - global game - if game.photon_damage > 0: - game.display("Photon torpedo control is damaged. Repairs are underway.") - game.display() - return - if game.photon_torpedoes == 0: - game.display("Photon torpedoes exhausted.") - game.display() - return - if len(game.klingon_ships) == 0: - game.display("There are no Klingon ships in this quadrant.") - game.display() - return - direction = game.read_double("Enter firing direction (1.0--9.0): ") - if not direction or direction < 1.0 or direction > 9.0: - game.display("Invalid direction.") - game.display() - return - game.display() - game.display("Photon torpedo fired...") - game.photon_torpedoes -= 1 - angle = -(pi * (direction - 1.0) / 4.0) - if random.randint(0, 2) == 0: - angle += (1.0 - 2.0 * random.uniform(0.0, 1.0) * pi * 2.0) * 0.03 - x = game.sector_x - y = game.sector_y - vx = cos(angle) / 20 - vy = sin(angle) / 20 - last_x = last_y = -1 - # new_x = game.sector_x - # new_y = game.sector_y - hit = False - while x >= 0 and y >= 0 and round(x) < 8 and round(y) < 8: - new_x = int(round(x)) - new_y = int(round(y)) - if last_x != new_x or last_y != new_y: - game.display(" [{0},{1}]".format(new_x + 1, new_y + 1)) - last_x = new_x - last_y = new_y - for ship in game.klingon_ships: - if ship.sector_x == new_x and ship.sector_y == new_y: - game.display("Klingon ship destroyed at sector [{0},{1}].".format(ship.sector_x + 1, ship.sector_y + 1)) - game.sector[ship.sector_y][ship.sector_x] = sector_type.empty - game.klingons -= 1 - game.klingon_ships.remove(ship) - game.quadrants[game.quadrant_y][game.quadrant_x].klingons -= 1 - hit = True - break # break out of the for loop - if hit: - break # break out of the while loop - if game.sector[new_y][new_x] == sector_type.starbase: - game.starbases -= 1 - game.quadrants[game.quadrant_y][game.quadrant_x].starbase = False - game.sector[new_y][new_x] = sector_type.empty - game.display("The Enterprise destroyed a Federation starbase at sector [{0},{1}]!".format(new_x + 1, new_y + 1)) - hit = True - break - elif game.sector[new_y][new_x] == sector_type.star: - game.display("The torpedo was captured by a star's gravitational field at sector [{0},{1}].".format( - new_x + 1, new_y + 1 - )) - hit = True - break - x += vx - y += vy - if not hit: - game.display("Photon torpedo failed to hit anything.") - if len(game.klingon_ships) > 0: - game.display() - klingons_attack() - game.display() - - -def navigation(): - global game - max_warp_factor = 8.0 - if game.navigation_damage > 0: - max_warp_factor = 0.2 + random.randint(0, 8) / 10.0 - game.display("Warp engines damaged. Maximum warp factor: {0}".format(max_warp_factor)) - game.display() - - direction = game.read_double("Enter course (1.0--8.9): ") - if not direction or direction < 1.0 or direction > 9.0: - game.display("Invalid course.") - game.display() - return - - dist = game.read_double( - "Enter warp factor (0.1--{0}): ".format(max_warp_factor)) - if not dist or dist < 0.1 or dist > max_warp_factor: - game.display("Invalid warp factor.") - game.display() - return - - game.display() - - dist *= 8 - energy_required = int(dist) - if energy_required >= game.energy: - game.display("Unable to comply. Insufficient energy to travel that speed.") - game.display() - return - else: - game.display("Warp engines engaged.") - game.display() - game.energy -= energy_required - - last_quad_x = game.quadrant_x - last_quad_y = game.quadrant_y - angle = -(pi * (direction - 1.0) / 4.0) - x = game.quadrant_x * 8 + game.sector_x - y = game.quadrant_y * 8 + game.sector_y - dx = dist * cos(angle) - dy = dist * sin(angle) - vx = dx / 1000 - vy = dy / 1000 - # quad_x = quad_y = sect_x = sect_y = 0 - last_sect_x = game.sector_x - last_sect_y = game.sector_y - game.sector[game.sector_y][game.sector_x] = sector_type.empty - obstacle = False - for i in range(999): - x += vx - y += vy - quad_x = int(round(x)) / 8 - quad_y = int(round(y)) / 8 - if quad_x == game.quadrant_x and quad_y == game.quadrant_y: - sect_x = int(round(x)) % 8 - sect_y = int(round(y)) % 8 - if game.sector[sect_y][sect_x] != sector_type.empty: - game.sector_x = last_sect_x - game.sector_y = last_sect_y - game.sector[game.sector_y][game.sector_x] = sector_type.enterprise - game.display("Encountered obstacle within quadrant.") - game.display() - obstacle = True - break - last_sect_x = sect_x - last_sect_y = sect_y - - if not obstacle: - if x < 0: - x = 0 - elif x > 63: - x = 63 - if y < 0: - y = 0 - elif y > 63: - y = 63 - quad_x = int(round(x)) / 8 - quad_y = int(round(y)) / 8 - game.sector_x = int(round(x)) % 8 - game.sector_y = int(round(y)) % 8 - if quad_x != game.quadrant_x or quad_y != game.quadrant_y: - game.quadrant_x = int(quad_x) - game.quadrant_y = int(quad_y) - generate_sector() - else: - game.quadrant_x = int(quad_x) - game.quadrant_y = int(quad_y) - game.sector[game.sector_y][game.sector_x] = sector_type.enterprise - if is_docking_location(game.sector_y, game.sector_x): - game.energy = 3000 - game.photon_torpedoes = 10 - game.navigation_damage = 0 - game.short_range_scan_damage = 0 - game.long_range_scan_damage = 0 - game.shield_control_damage = 0 - game.computer_damage = 0 - game.photon_damage = 0 - game.phaser_damage = 0 - game.shield_level = 0 - game.docked = True - else: - game.docked = False - - if last_quad_x != game.quadrant_x or last_quad_y != game.quadrant_y: - game.time_remaining -= 1 - game.star_date += 1 - - short_range_scan() - - if game.docked: - game.display("Lowering shields as part of docking sequence...") - game.display("Enterprise successfully docked with starbase.") - game.display() - else: - if game.quadrants[game.quadrant_y][game.quadrant_x].klingons > 0 \ - and last_quad_x == game.quadrant_x and last_quad_y == game.quadrant_y: - klingons_attack() - game.display() - elif not repair_damage(): - induce_damage(-1) - -def generate_sector(): - global game - quadrant = game.quadrants[game.quadrant_y][game.quadrant_x] - starbase = quadrant.starbase - stars = quadrant.stars - klingons = quadrant.klingons - game.klingon_ships = [] - for i in range(8): - for j in range(8): - game.sector[i][j] = sector_type.empty - game.sector[game.sector_y][game.sector_x] = sector_type.enterprise - while starbase or stars > 0 or klingons > 0: - i = random.randint(0, 7) - j = random.randint(0, 7) - if is_sector_region_empty(i, j): - if starbase: - starbase = False - game.sector[i][j] = sector_type.starbase - game.starbase_y = i - game.starbase_x = j - elif stars > 0: - game.sector[i][j] = sector_type.star - stars -= 1 - elif klingons > 0: - game.sector[i][j] = sector_type.klingon - klingon_ship = KlingonShip() - klingon_ship.shield_level = 300 + random.randint(0, 199) - klingon_ship.sector_y = i - klingon_ship.sector_x = j - game.klingon_ships.append(klingon_ship) - klingons -= 1 - - -def is_docking_location(i, j): - for y in range(i - 1, i+1): # i + 1? - for x in range(j - 1, j+1): # j + 1? - if read_sector(y, x) == sector_type.starbase: - return True - return False - - -def is_sector_region_empty(i, j): - for y in range(i - 1, i+1): # i + 1? - if read_sector(y, j - 1) != sector_type.empty and read_sector(y, j + 1) != sector_type.empty: - return False - return read_sector(i, j) == sector_type.empty - - -def read_sector(i, j): - global game - if i < 0 or j < 0 or i > 7 or j > 7: - return sector_type.empty - return game.sector[i][j] - - -def short_range_scan(): - global game - if game.short_range_scan_damage > 0: - game.display("Short range scanner is damaged. Repairs are underway.") - game.display() - else: - quadrant = game.quadrants[game.quadrant_y][game.quadrant_x] - quadrant.scanned = True - print_sector(quadrant) - game.display() - - -def print_sector(quadrant): - global game - game.condition = "GREEN" - if quadrant.klingons > 0: - game.condition = "RED" - elif game.energy < 300: - game.condition = "YELLOW" - - sb = "" - game.display("-=--=--=--=--=--=--=--=- Region: {0}".format(quadrant.name)) - print_sector_row(sb, 0, " Quadrant: [{0},{1}]".format( - game.quadrant_x + 1, game.quadrant_y + 1)) - print_sector_row(sb, 1, " Sector: [{0},{1}]".format(game.sector_x + 1, game.sector_y + 1)) - print_sector_row(sb, 2, " Stardate: {0}".format(game.star_date)) - print_sector_row(sb, 3, " Time remaining: {0}".format(game.time_remaining)) - print_sector_row(sb, 4, " Condition: {0}".format(game.condition)) - print_sector_row(sb, 5, " Energy: {0}".format(game.energy)) - print_sector_row(sb, 6, " Shields: {0}".format(game.shield_level)) - print_sector_row(sb, 7, " Photon Torpedoes: {0}".format(game.photon_torpedoes)) - game.display("-=--=--=--=--=--=--=--=- Docked: {0}".format(game.docked)) - - if quadrant.klingons > 0: - game.display() - game.display("Condition RED: Klingon ship{0} detected.".format("" if quadrant.klingons == 1 else "s")) - if game.shield_level == 0 and not game.docked: - game.display("Warning: Shields are down.") - elif game.energy < 300: - game.display() - game.display("Condition YELLOW: Low energy level.") - game.condition = "YELLOW" - - -def print_sector_row(sb, row, suffix): - global game - for column in range(8): - if game.sector[row][column] == sector_type.empty: - sb += " " - elif game.sector[row][column] == sector_type.enterprise: - sb += "" - elif game.sector[row][column] == sector_type.klingon: - sb += "+K+" - elif game.sector[row][column] == sector_type.star: - sb += " * " - elif game.sector[row][column] == sector_type.starbase: - sb += ">S<" - if suffix is not None: - sb = sb + suffix - game.display(sb) - - -def print_mission(): - global game - game.display("Mission: Destroy {0} Klingon ships in {1} stardates with {2} starbases.".format( - game.klingons, game.time_remaining, game.starbases)) - game.display() - - -def initialize_game(): - # gah, globals - global game - game.quadrant_x = random.randint(0, 7) - game.quadrant_y = random.randint(0, 7) - game.sector_x = random.randint(0, 7) - game.sector_y = random.randint(0, 7) - game.star_date = random.randint(0, 50) + 2250 - game.energy = 3000 - game.photon_torpedoes = 10 - game.time_remaining = 40 + random.randint(0, 9) - game.klingons = 15 + random.randint(0, 5) - game.starbases = 2 + random.randint(0, 2) - game.destroyed = False - game.navigation_damage = 0 - game.short_range_scan_damage = 0 - game.long_range_scan_damage = 0 - game.shield_control_damage = 0 - game.computer_damage = 0 - game.photon_damage = 0 - game.phaser_damage = 0 - game.shield_level = 0 - game.docked = False - - names = [] - for name in TrekStrings.quadrantNames: - names.append(name) - - for i in range(8): - for j in range(8): - index = random.randint(0, len(names) - 1) - quadrant = Quadrant() - quadrant.name = names[index] - quadrant.stars = 1 + random.randint(0, 7) - game.quadrants[i][j] = quadrant - del names[index] - - klingon_count = game.klingons - starbase_count = game.starbases - while klingon_count > 0 or starbase_count > 0: - i = random.randint(0, 7) - j = random.randint(0, 7) - quadrant = game.quadrants[i][j] - if not quadrant.starbase: - quadrant.starbase = True - starbase_count -= 1 - if quadrant.klingons < 3: - quadrant.klingons += 1 - klingon_count -= 1 - - -def print_strings(string_list): - for string in string_list: - game.display(string) - game.display() + self.display("-=--=--=--=--=--=--=--=- Region: {0}".format(quadrant.name)) + self.print_sector_row(sb, 0, " Quadrant: [{0},{1}]".format( + self.quadrant_x + 1, self.quadrant_y + 1)) + self.print_sector_row(sb, 1, " Sector: [{0},{1}]".format(self.sector_x + 1, self.sector_y + 1)) + self.print_sector_row(sb, 2, " Stardate: {0}".format(self.star_date)) + self.print_sector_row(sb, 3, " Time remaining: {0}".format(self.time_remaining)) + self.print_sector_row(sb, 4, " Condition: {0}".format(self.condition)) + self.print_sector_row(sb, 5, " Energy: {0}".format(self.energy)) + self.print_sector_row(sb, 6, " Shields: {0}".format(self.shield_level)) + self.print_sector_row(sb, 7, " Photon Torpedoes: {0}".format(self.photon_torpedoes)) + self.display("-=--=--=--=--=--=--=--=- Docked: {0}".format(self.docked)) + + if quadrant.klingons > 0: + self.display() + self.display("Condition RED: Klingon ship{0} detected.".format("" if quadrant.klingons == 1 else "s")) + if self.shield_level == 0 and not self.docked: + self.display("Warning: Shields are down.") + elif self.energy < 300: + self.display() + self.display("Condition YELLOW: Low energy level.") + self.condition = "YELLOW" + + + def print_sector_row(self, sb, row, suffix): + for column in range(8): + if self.sector[row][column] == self.sector_type.empty: + sb += " " + elif self.sector[row][column] == self.sector_type.enterprise: + sb += "" + elif self.sector[row][column] == self.sector_type.klingon: + sb += "+K+" + elif self.sector[row][column] == self.sector_type.star: + sb += " * " + elif self.sector[row][column] == self.sector_type.starbase: + sb += ">S<" + if suffix is not None: + sb = sb + suffix + self.display(sb) + + + def print_mission(self): + self.display("Mission: Destroy {0} Klingon ships in {1} stardates with {2} starbases.".format( + self.klingons, self.time_remaining, self.starbases)) + self.display() if __name__ == '__main__': - run() + game = Game() + game.run() From 2d0f90cd3a1009125e46fab8335ed4b3dca3fcf3 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Sun, 20 Dec 2020 02:46:27 -0500 Subject: [PATCH 012/100] light --- .gitignore | 2 + Aliens.py | 23 +++--- Assets.py | 80 +++++++++++-------- Calculators.py | 45 ++++++----- Controls.py | 40 +++++----- Map.py | 173 +++++++++++++++++++++++++++++++++++++++- Reports.py | 16 ++-- Scanners.py | 8 +- StarTrek2020.py | 207 +++--------------------------------------------- 9 files changed, 302 insertions(+), 292 deletions(-) diff --git a/.gitignore b/.gitignore index f189e89..ac0fe4e 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ /__pycache__/Controls.cpython-37.pyc /__pycache__/Calculators.cpython-37.pyc /__pycache__/Assets.cpython-37.pyc +/.vs/2020_12_20_StarTrek1971/v16/.suo +/__pycache__/Map.cpython-37.pyc diff --git a/Aliens.py b/Aliens.py index 8c7eacf..e5455f0 100644 --- a/Aliens.py +++ b/Aliens.py @@ -1,15 +1,20 @@ import random -from Assets import ship +from Assets import Enterprise -class attack(object): +class KlingonShip(object): + + def __init__(self): + self.sector_x = 0 + self.sector_y = 0 + self.shield_level = 0 @staticmethod - def klingons_attack(game): + def attack(game): from Calculators import calculator if len(game.klingon_ships) > 0: for ship in game.klingon_ships: - if game.docked: + if game.enterprise.docked: game.display("Enterprise hit by ship at sector [{0},{1}]. No damage due to starbase shields.".format( ship.sector_x + 1, ship.sector_y + 1 )) @@ -18,14 +23,14 @@ def klingons_attack(game): game.sector_x, game.sector_y, ship.sector_x, ship.sector_y) delivered_energy = 300 * \ random.uniform(0.0, 1.0) * (1.0 - dist / 11.3) - game.shield_level -= int(delivered_energy) - if game.shield_level < 0: - game.shield_level = 0 + game.enterprise.shield_level -= int(delivered_energy) + if game.enterprise.shield_level < 0: + game.enterprise.shield_level = 0 game.destroyed = True game.display("Enterprise hit by ship at sector [{0},{1}]. Shields dropped to {2}.".format( - ship.sector_x + 1, ship.sector_y + 1, game.shield_level + ship.sector_x + 1, ship.sector_y + 1, game.enterprise.shield_level )) - if game.shield_level == 0: + if game.enterprise.shield_level == 0: return True return True return False diff --git a/Assets.py b/Assets.py index abf7aea..d8d02ff 100644 --- a/Assets.py +++ b/Assets.py @@ -1,80 +1,92 @@ import random -class ship(object): +class Enterprise(object): - @staticmethod - def induce_damage(game, item): + def __init__(self): + self.energy = 0 + self.shield_level = 0 + self.docked = False + self.condition = "GREEN" + self.navigation_damage = 0 + self.short_range_scan_damage = 0 + self.long_range_scan_damage = 0 + self.shield_control_damage = 0 + self.computer_damage = 0 + self.photon_damage = 0 + self.phaser_damage = 0 + + + def damage(self, game, item): if random.randint(0, 6) > 0: return damage = 1 + random.randint(0, 4) if item < 0: item = random.randint(0, 6) if item == 0: - game.navigation_damage = damage + self.navigation_damage = damage game.display("Warp engines are malfunctioning.") elif item == 1: - game.short_range_scan_damage = damage + self.short_range_scan_damage = damage game.display("Short range scanner is malfunctioning.") elif item == 2: - game.long_range_scan_damage = damage + self.long_range_scan_damage = damage game.display("Long range scanner is malfunctioning.") elif item == 3: - game.shield_control_damage = damage + self.shield_control_damage = damage game.display("Shield controls are malfunctioning.") elif item == 4: - game.computer_damage = damage + self.computer_damage = damage game.display("The main computer is malfunctioning.") elif item == 5: - game.photon_damage = damage + self.photon_damage = damage game.display("Photon torpedo controls are malfunctioning.") elif item == 6: - game.phaser_damage = damage + self.phaser_damage = damage game.display("Phasers are malfunctioning.") game.display() - @staticmethod - def repair_damage(game): - if game.navigation_damage > 0: - game.navigation_damage -= 1 - if game.navigation_damage == 0: + def repair(self, game): + if self.navigation_damage > 0: + self.navigation_damage -= 1 + if self.navigation_damage == 0: game.display("Warp engines have been repaired.") game.display() return True - if game.short_range_scan_damage > 0: - game.short_range_scan_damage -= 1 - if game.short_range_scan_damage == 0: + if self.short_range_scan_damage > 0: + self.short_range_scan_damage -= 1 + if self.short_range_scan_damage == 0: game.display("Short range scanner has been repaired.") - game.display() + self.display() return True - if game.long_range_scan_damage > 0: - game.long_range_scan_damage -= 1 - if game.long_range_scan_damage == 0: + if self.long_range_scan_damage > 0: + self.long_range_scan_damage -= 1 + if self.long_range_scan_damage == 0: game.display("Long range scanner has been repaired.") game.display() return True - if game.shield_control_damage > 0: - game.shield_control_damage -= 1 - if game.shield_control_damage == 0: + if self.shield_control_damage > 0: + self.shield_control_damage -= 1 + if self.shield_control_damage == 0: game.display("Shield controls have been repaired.") game.display() return True - if game.computer_damage > 0: - game.computer_damage -= 1 - if game.computer_damage == 0: + if self.computer_damage > 0: + self.computer_damage -= 1 + if self.computer_damage == 0: game.display("The main computer has been repaired.") game.display() return True - if game.photon_damage > 0: - game.photon_damage -= 1 - if game.photon_damage == 0: + if self.photon_damage > 0: + self.photon_damage -= 1 + if self.photon_damage == 0: game.display("Photon torpedo controls have been repaired.") game.display() return True - if game.phaser_damage > 0: - game.phaser_damage -= 1 - if game.phaser_damage == 0: + if self.phaser_damage > 0: + self.phaser_damage -= 1 + if self.phaser_damage == 0: game.display("Phasers have been repaired.") game.display() return True diff --git a/Calculators.py b/Calculators.py index a44e864..caadc10 100644 --- a/Calculators.py +++ b/Calculators.py @@ -1,9 +1,10 @@ from math import atan2, pi, sqrt, cos, sin import random +from Map import * from Scanners import scanner -from Assets import ship -from Aliens import attack +from Assets import Enterprise +from Aliens import KlingonShip class calculator(object): @@ -16,7 +17,7 @@ def distance(x1, y1, x2, y2): @staticmethod def navigation(game): max_warp_factor = 8.0 - if game.navigation_damage > 0: + if game.enterprise.navigation_damage > 0: max_warp_factor = 0.2 + random.randint(0, 8) / 10.0 game.display("Warp engines damaged. Maximum warp factor: {0}".format(max_warp_factor)) game.display() @@ -38,14 +39,14 @@ def navigation(game): dist *= 8 energy_required = int(dist) - if energy_required >= game.energy: + if energy_required >= game.enterprise.energy: game.display("Unable to comply. Insufficient energy to travel that speed.") game.display() return else: game.display("Warp engines engaged.") game.display() - game.energy -= energy_required + game.enterprise.energy -= energy_required last_quad_x = game.quadrant_x last_quad_y = game.quadrant_y @@ -96,25 +97,25 @@ def navigation(game): if quad_x != game.quadrant_x or quad_y != game.quadrant_y: game.quadrant_x = int(quad_x) game.quadrant_y = int(quad_y) - game.generate_sector() + Map.generate_sector(game) else: game.quadrant_x = int(quad_x) game.quadrant_y = int(quad_y) game.sector[game.sector_y][game.sector_x] = game.sector_type.enterprise - if game.is_docking_location(game.sector_y, game.sector_x): - game.energy = 3000 + if Map.is_docking_location(game, game.sector_y, game.sector_x): + game.enterprise.energy = 3000 game.photon_torpedoes = 10 - game.navigation_damage = 0 - game.short_range_scan_damage = 0 - game.long_range_scan_damage = 0 - game.shield_control_damage = 0 - game.computer_damage = 0 - game.photon_damage = 0 - game.phaser_damage = 0 - game.shield_level = 0 - game.docked = True + game.enterprise.navigation_damage = 0 + game.enterprise.short_range_scan_damage = 0 + game.enterprise.long_range_scan_damage = 0 + game.enterprise.shield_control_damage = 0 + game.enterprise.computer_damage = 0 + game.enterprise.photon_damage = 0 + game.enterprise.phaser_damage = 0 + game.enterprise.shield_level = 0 + game.enterprise.docked = True else: - game.docked = False + game.enterprise.docked = False if last_quad_x != game.quadrant_x or last_quad_y != game.quadrant_y: game.time_remaining -= 1 @@ -122,17 +123,17 @@ def navigation(game): scanner.short_range_scan(game) - if game.docked: + if game.enterprise.docked: game.display("Lowering shields as part of docking sequence...") game.display("Enterprise successfully docked with starbase.") game.display() else: if game.quadrants[game.quadrant_y][game.quadrant_x].klingons > 0 \ and last_quad_x == game.quadrant_x and last_quad_y == game.quadrant_y: - attack.klingons_attack(game) + KlingonShip.attack(game) game.display() - elif not ship.repair_damage(game): - ship.induce_damage(game, -1) + elif not game.enterprise.repair(game): + game.enterprise.damage(game, -1) @staticmethod diff --git a/Controls.py b/Controls.py index 3d4d965..363ca3e 100644 --- a/Controls.py +++ b/Controls.py @@ -2,8 +2,8 @@ import random import TrekStrings -from Assets import ship -from Aliens import attack +from Assets import Enterprise +from Aliens import KlingonShip from Calculators import calculator from Reports import status @@ -12,7 +12,7 @@ class control(object): @staticmethod def computer_controls(game): - if game.computer_damage > 0: + if game.enterprise.computer_damage > 0: game.display("The main computer is damaged. Repairs are underway.") game.display() return @@ -32,12 +32,12 @@ def computer_controls(game): game.display() game.display("Invalid computer command.") game.display() - ship.induce_damage(game, 4) + game.enterprise.damage(game, 4) @staticmethod def phaser_controls(game): - if game.phaser_damage > 0: + if game.enterprise.phaser_damage > 0: game.display("Phasers are damaged. Repairs are underway.") game.display() return @@ -46,8 +46,8 @@ def phaser_controls(game): game.display() return game.display("Phasers locked on target.") - phaser_energy = game.read_double("Enter phaser energy (1--{0}): ".format(game.energy)) - if not phaser_energy or phaser_energy < 1 or phaser_energy > game.energy: + phaser_energy = game.read_double("Enter phaser energy (1--{0}): ".format(game.enterprise.energy)) + if not phaser_energy or phaser_energy < 1 or phaser_energy > game.enterprise.energy: game.display("Invalid energy level.") game.display() return @@ -55,9 +55,9 @@ def phaser_controls(game): game.display("Firing phasers...") destroyed_ships = [] for ship in game.klingon_ships: - game.energy -= int(phaser_energy) - if game.energy < 0: - game.energy = 0 + game.enterprise.energy -= int(phaser_energy) + if game.enterprise.energy < 0: + game.enterprise.energy = 0 break dist = calculator.distance(game.sector_x, game.sector_y, ship.sector_x, ship.sector_y) delivered_energy = phaser_energy * (1.0 - dist / 11.3) @@ -76,7 +76,7 @@ def phaser_controls(game): game.klingon_ships.remove(ship) if len(game.klingon_ships) > 0: game.display() - attack.klingons_attack(game) + KlingonShip.attack(game) game.display() @@ -89,10 +89,10 @@ def shield_controls(game): game.display() if command == "add": adding = True - max_transfer = game.energy + max_transfer = game.enterprise.energy elif command == "sub": adding = False - max_transfer = game.shield_level + max_transfer = game.enterprise.shield_level else: game.display("Invalid command.") game.display() @@ -105,17 +105,17 @@ def shield_controls(game): return game.display() if adding: - game.energy -= int(transfer) - game.shield_level += int(transfer) + game.enterprise.energy -= int(transfer) + game.enterprise.shield_level += int(transfer) else: - game.energy += int(transfer) - game.shield_level -= int(transfer) - game.display("Shield strength is now {0}. Energy level is now {1}.".format(game.shield_level, game.energy)) + game.enterprise.energy += int(transfer) + game.enterprise.shield_level -= int(transfer) + game.display("Shield strength is now {0}. Energy level is now {1}.".format(game.enterprise.shield_level, game.enterprise.energy)) game.display() def torpedo_control(game): - if game.photon_damage > 0: + if game.enterprise.photon_damage > 0: game.display("Photon torpedo control is damaged. Repairs are underway.") game.display() return @@ -183,7 +183,7 @@ def torpedo_control(game): game.display("Photon torpedo failed to hit anything.") if len(game.klingon_ships) > 0: game.display() - attack.klingons_attack(game) + KlingonShip.attack(game) game.display() diff --git a/Map.py b/Map.py index 6440f74..9fae9a1 100644 --- a/Map.py +++ b/Map.py @@ -1,5 +1,174 @@ -class sector(object): - pass +import random +import TrekStrings +from Aliens import KlingonShip + + +class Quadrant(): + + def __init__(game): + game.name = "" + game.klingons = 0 + game.stars = 0 + game.starbase = False + game.scanned = False + + +class SectorType(): + + def __init__(game): + game.empty, game.star, game.klingon, game.enterprise, game.starbase = 1, 2, 3, 4, 5 + + +class Map(object): + + @staticmethod + def initialize_game(game): + game.quadrant_x = random.randint(0, 7) + game.quadrant_y = random.randint(0, 7) + game.sector_x = random.randint(0, 7) + game.sector_y = random.randint(0, 7) + game.star_date = random.randint(0, 50) + 2250 + game.enterprise.energy = 3000 + game.photon_torpedoes = 10 + game.time_remaining = 40 + random.randint(0, 9) + game.klingons = 15 + random.randint(0, 5) + game.starbases = 2 + random.randint(0, 2) + game.destroyed = False + + names = [] + for name in TrekStrings.quadrantNames: + names.append(name) + + for i in range(8): + for j in range(8): + index = random.randint(0, len(names) - 1) + quadrant = Quadrant() + quadrant.name = names[index] + quadrant.stars = 1 + random.randint(0, 7) + game.quadrants[i][j] = quadrant + del names[index] + + klingon_count = game.klingons + starbase_count = game.starbases + while klingon_count > 0 or starbase_count > 0: + i = random.randint(0, 7) + j = random.randint(0, 7) + quadrant = game.quadrants[i][j] + if not quadrant.starbase: + quadrant.starbase = True + starbase_count -= 1 + if quadrant.klingons < 3: + quadrant.klingons += 1 + klingon_count -= 1 + + + @staticmethod + def generate_sector(game): + quadrant = game.quadrants[game.quadrant_y][game.quadrant_x] + starbase = quadrant.starbase + stars = quadrant.stars + klingons = quadrant.klingons + game.klingon_ships = [] + for i in range(8): + for j in range(8): + game.sector[i][j] = game.sector_type.empty + game.sector[game.sector_y][game.sector_x] = game.sector_type.enterprise + while starbase or stars > 0 or klingons > 0: + i = random.randint(0, 7) + j = random.randint(0, 7) + if Map.is_sector_region_empty(game, i, j): + if starbase: + starbase = False + game.sector[i][j] = game.sector_type.starbase + game.starbase_y = i + game.starbase_x = j + elif stars > 0: + game.sector[i][j] = game.sector_type.star + stars -= 1 + elif klingons > 0: + game.sector[i][j] = game.sector_type.klingon + klingon_ship = KlingonShip() + klingon_ship.shield_level = 300 + random.randint(0, 199) + klingon_ship.sector_y = i + klingon_ship.sector_x = j + game.klingon_ships.append(klingon_ship) + klingons -= 1 + + @staticmethod + def is_sector_region_empty(game, i, j): + for y in range(i - 1, i+1): # i + 1? + if Map.read_sector(game, y, j - 1) != \ + game.sector_type.empty and \ + Map.read_sector(game, y, j + 1) != \ + game.sector_type.empty: + return False + return Map.read_sector(game, i, j) == game.sector_type.empty + + + @staticmethod + def read_sector(game, i, j): + if i < 0 or j < 0 or i > 7 or j > 7: + return game.sector_type.empty + return game.sector[i][j] + + + @staticmethod + def is_docking_location(game, i, j): + for y in range(i - 1, i+1): # i + 1? + for x in range(j - 1, j+1): # j + 1? + if Map.read_sector(game, y, x) == game.sector_type.starbase: + return True + return False + + + @staticmethod + def print_sector(game, quadrant): + game.enterprise.condition = "GREEN" + if quadrant.klingons > 0: + game.enterprise.condition = "RED" + elif game.enterprise.energy < 300: + game.enterprise.condition = "YELLOW" + + sb = "" + game.display("-=--=--=--=--=--=--=--=- Region: {0}".format(quadrant.name)) + Map.print_sector_row(game, sb, 0, " Quadrant: [{0},{1}]".format( + game.quadrant_x + 1, game.quadrant_y + 1)) + Map.print_sector_row(game, sb, 1, " Sector: [{0},{1}]".format(game.sector_x + 1, game.sector_y + 1)) + Map.print_sector_row(game, sb, 2, " Stardate: {0}".format(game.star_date)) + Map.print_sector_row(game, sb, 3, " Time remaining: {0}".format(game.time_remaining)) + Map.print_sector_row(game, sb, 4, " Condition: {0}".format(game.enterprise.condition)) + Map.print_sector_row(game, sb, 5, " Energy: {0}".format(game.enterprise.energy)) + Map.print_sector_row(game, sb, 6, " Shields: {0}".format(game.enterprise.shield_level)) + Map.print_sector_row(game, sb, 7, " Photon Torpedoes: {0}".format(game.photon_torpedoes)) + game.display("-=--=--=--=--=--=--=--=- Docked: {0}".format(game.enterprise.docked)) + + if quadrant.klingons > 0: + game.display() + game.display("Condition RED: Klingon ship{0} detected.".format("" if quadrant.klingons == 1 else "s")) + if game.enterprise.shield_level == 0 and not game.enterprise.docked: + game.display("Warning: Shields are down.") + elif game.enterprise.energy < 300: + game.display() + game.display("Condition YELLOW: Low energy level.") + game.enterprise.condition = "YELLOW" + + + @staticmethod + def print_sector_row(game, sb, row, suffix): + for column in range(8): + if game.sector[row][column] == game.sector_type.empty: + sb += " " + elif game.sector[row][column] == game.sector_type.enterprise: + sb += "" + elif game.sector[row][column] == game.sector_type.klingon: + sb += "+K+" + elif game.sector[row][column] == game.sector_type.star: + sb += " * " + elif game.sector[row][column] == game.sector_type.starbase: + sb += ">S<" + if suffix is not None: + sb = sb + suffix + game.display(sb) diff --git a/Reports.py b/Reports.py index 49a9663..75a2fcb 100644 --- a/Reports.py +++ b/Reports.py @@ -7,13 +7,13 @@ def display_status(game): game.display(" Time Remaining: {0}".format(game.time_remaining)) game.display(" Klingon Ships Remaining: {0}".format(game.klingons)) game.display(" Starbases: {0}".format(game.starbases)) - game.display(" Warp Engine Damage: {0}".format(game.navigation_damage)) - game.display(" Short Range Scanner Damage: {0}".format(game.short_range_scan_damage)) - game.display(" Long Range Scanner Damage: {0}".format(game.long_range_scan_damage)) - game.display(" Shield Controls Damage: {0}".format(game.shield_control_damage)) - game.display(" Main Computer Damage: {0}".format(game.computer_damage)) - game.display("Photon Torpedo Control Damage: {0}".format(game.photon_damage)) - game.display(" Phaser Damage: {0}".format(game.phaser_damage)) + game.display(" Warp Engine Damage: {0}".format(game.enterprise.navigation_damage)) + game.display(" Short Range Scanner Damage: {0}".format(game.enterprise.short_range_scan_damage)) + game.display(" Long Range Scanner Damage: {0}".format(game.enterprise.long_range_scan_damage)) + game.display(" Shield Controls Damage: {0}".format(game.enterprise.shield_control_damage)) + game.display(" Main Computer Damage: {0}".format(game.enterprise.computer_damage)) + game.display("Photon Torpedo Control Damage: {0}".format(game.enterprise.photon_damage)) + game.display(" Phaser Damage: {0}".format(game.enterprise.phaser_damage)) game.display() @@ -47,7 +47,7 @@ def print_game_status(game): if game.destroyed: game.display("MISSION FAILED: ENTERPRISE DESTROYED!!!") game.display('\n'*2) - elif game.energy == 0: + elif game.enterprise.energy == 0: game.display("MISSION FAILED: ENTERPRISE RAN OUT OF ENERGY.") game.display('\n'*2) elif game.klingons == 0: diff --git a/Scanners.py b/Scanners.py index eb97c8b..c7a831a 100644 --- a/Scanners.py +++ b/Scanners.py @@ -1,19 +1,21 @@ +from Map import * + class scanner(object): @staticmethod def short_range_scan(game): - if game.short_range_scan_damage > 0: + if game.enterprise.short_range_scan_damage > 0: game.display("Short range scanner is damaged. Repairs are underway.") game.display() else: quadrant = game.quadrants[game.quadrant_y][game.quadrant_x] quadrant.scanned = True - game.print_sector(quadrant) + Map.print_sector(game, quadrant) game.display() @staticmethod def long_range_scan(game): - if game.long_range_scan_damage > 0: + if game.enterprise.long_range_scan_damage > 0: game.display("Long range scanner is damaged. Repairs are underway.") game.display() return diff --git a/StarTrek2020.py b/StarTrek2020.py index 55223b9..d124685 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -8,53 +8,23 @@ from Controls import control from Scanners import scanner from Reports import status - - -class Quadrant(): - - def __init__(self): - self.name = "" - self.klingons = 0 - self.stars = 0 - self.starbase = False - self.scanned = False - - -class SectorType(): - - def __init__(self): - self.empty, self.star, self.klingon, self.enterprise, self.starbase = 1, 2, 3, 4, 5 - - -class KlingonShip(): - - def __init__(self): - self.sector_x = 0 - self.sector_y = 0 - self.shield_level = 0 +from Assets import Enterprise +from Aliens import KlingonShip +from Map import * class Game(console): def __init__(self): + self.enterprise = Enterprise() self.star_date = 0 self.time_remaining = 0 - self.energy = 0 self.klingons = 0 self.starbases = 0 self.sector_type = SectorType() self.quadrant_x, self.quadrant_y = 0, 0 self.sector_x, self.sector_y = 0, 0 - self.shield_level = 0 - self.navigation_damage = 0 - self.short_range_scan_damage = 0 - self.long_range_scan_damage = 0 - self.shield_control_damage = 0 - self.computer_damage = 0 - self.photon_damage = 0 - self.phaser_damage = 0 self.photon_torpedoes = 0 - self.docked = False self.destroyed = False self.starbase_x, self.starbase_y = 0, 0 self.quadrants = [[Quadrant() for _ in range(8)] for _ in range(8)] @@ -64,62 +34,15 @@ def __init__(self): def run(self): self.print_strings(TrekStrings.titleStrings) - while True: - self.initialize_game() - self.print_mission() - self.generate_sector() - self.print_strings(TrekStrings.commandStrings) - while self.energy > 0 and not self.destroyed and self.klingons > 0 and self.time_remaining > 0: - self.command_prompt() - status.print_game_status(game) - - def initialize_game(self): - self.quadrant_x = random.randint(0, 7) - self.quadrant_y = random.randint(0, 7) - self.sector_x = random.randint(0, 7) - self.sector_y = random.randint(0, 7) - self.star_date = random.randint(0, 50) + 2250 - self.energy = 3000 - self.photon_torpedoes = 10 - self.time_remaining = 40 + random.randint(0, 9) - self.klingons = 15 + random.randint(0, 5) - self.starbases = 2 + random.randint(0, 2) - self.destroyed = False - self.navigation_damage = 0 - self.short_range_scan_damage = 0 - self.long_range_scan_damage = 0 - self.shield_control_damage = 0 - self.computer_damage = 0 - self.photon_damage = 0 - self.phaser_damage = 0 - self.shield_level = 0 - self.docked = False - - names = [] - for name in TrekStrings.quadrantNames: - names.append(name) - - for i in range(8): - for j in range(8): - index = random.randint(0, len(names) - 1) - quadrant = Quadrant() - quadrant.name = names[index] - quadrant.stars = 1 + random.randint(0, 7) - self.quadrants[i][j] = quadrant - del names[index] - - klingon_count = self.klingons - starbase_count = self.starbases - while klingon_count > 0 or starbase_count > 0: - i = random.randint(0, 7) - j = random.randint(0, 7) - quadrant = self.quadrants[i][j] - if not quadrant.starbase: - quadrant.starbase = True - starbase_count -= 1 - if quadrant.klingons < 3: - quadrant.klingons += 1 - klingon_count -= 1 + Map.initialize_game(game) + self.print_mission() + Map.generate_sector(game) + self.print_strings(TrekStrings.commandStrings) + while self.enterprise.energy > 0 and not \ + self.destroyed and self.klingons > 0 and \ + self.time_remaining > 0: + self.command_prompt() + status.print_game_status(game) def command_prompt(self): @@ -145,110 +68,6 @@ def command_prompt(self): self.print_strings(TrekStrings.commandStrings) - def is_sector_region_empty(self, i, j): - for y in range(i - 1, i+1): # i + 1? - if self.read_sector(y, j - 1) != \ - self.sector_type.empty and \ - self.read_sector(y, j + 1) != \ - self.sector_type.empty: - return False - return self.read_sector(i, j) == self.sector_type.empty - - - def read_sector(self, i, j): - if i < 0 or j < 0 or i > 7 or j > 7: - return self.sector_type.empty - return self.sector[i][j] - - - def is_docking_location(self, i, j): - for y in range(i - 1, i+1): # i + 1? - for x in range(j - 1, j+1): # j + 1? - if self.read_sector(y, x) == self.sector_type.starbase: - return True - return False - - - def generate_sector(self): - quadrant = self.quadrants[self.quadrant_y][self.quadrant_x] - starbase = quadrant.starbase - stars = quadrant.stars - klingons = quadrant.klingons - self.klingon_ships = [] - for i in range(8): - for j in range(8): - self.sector[i][j] = self.sector_type.empty - self.sector[self.sector_y][self.sector_x] = self.sector_type.enterprise - while starbase or stars > 0 or klingons > 0: - i = random.randint(0, 7) - j = random.randint(0, 7) - if self.is_sector_region_empty(i, j): - if starbase: - starbase = False - self.sector[i][j] = self.sector_type.starbase - self.starbase_y = i - self.starbase_x = j - elif stars > 0: - self.sector[i][j] = self.sector_type.star - stars -= 1 - elif klingons > 0: - self.sector[i][j] = self.sector_type.klingon - klingon_ship = KlingonShip() - klingon_ship.shield_level = 300 + random.randint(0, 199) - klingon_ship.sector_y = i - klingon_ship.sector_x = j - self.klingon_ships.append(klingon_ship) - klingons -= 1 - - - def print_sector(self, quadrant): - self.condition = "GREEN" - if quadrant.klingons > 0: - self.condition = "RED" - elif self.energy < 300: - self.condition = "YELLOW" - - sb = "" - self.display("-=--=--=--=--=--=--=--=- Region: {0}".format(quadrant.name)) - self.print_sector_row(sb, 0, " Quadrant: [{0},{1}]".format( - self.quadrant_x + 1, self.quadrant_y + 1)) - self.print_sector_row(sb, 1, " Sector: [{0},{1}]".format(self.sector_x + 1, self.sector_y + 1)) - self.print_sector_row(sb, 2, " Stardate: {0}".format(self.star_date)) - self.print_sector_row(sb, 3, " Time remaining: {0}".format(self.time_remaining)) - self.print_sector_row(sb, 4, " Condition: {0}".format(self.condition)) - self.print_sector_row(sb, 5, " Energy: {0}".format(self.energy)) - self.print_sector_row(sb, 6, " Shields: {0}".format(self.shield_level)) - self.print_sector_row(sb, 7, " Photon Torpedoes: {0}".format(self.photon_torpedoes)) - self.display("-=--=--=--=--=--=--=--=- Docked: {0}".format(self.docked)) - - if quadrant.klingons > 0: - self.display() - self.display("Condition RED: Klingon ship{0} detected.".format("" if quadrant.klingons == 1 else "s")) - if self.shield_level == 0 and not self.docked: - self.display("Warning: Shields are down.") - elif self.energy < 300: - self.display() - self.display("Condition YELLOW: Low energy level.") - self.condition = "YELLOW" - - - def print_sector_row(self, sb, row, suffix): - for column in range(8): - if self.sector[row][column] == self.sector_type.empty: - sb += " " - elif self.sector[row][column] == self.sector_type.enterprise: - sb += "" - elif self.sector[row][column] == self.sector_type.klingon: - sb += "+K+" - elif self.sector[row][column] == self.sector_type.star: - sb += " * " - elif self.sector[row][column] == self.sector_type.starbase: - sb += ">S<" - if suffix is not None: - sb = sb + suffix - self.display(sb) - - def print_mission(self): self.display("Mission: Destroy {0} Klingon ships in {1} stardates with {2} starbases.".format( self.klingons, self.time_remaining, self.starbases)) From aa1cffd39bb82f702beab9c4ac43b7d2c57a17b3 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Sun, 20 Dec 2020 04:46:15 -0500 Subject: [PATCH 013/100] Tighter 'nav. --- .gitignore | 4 + AbsDisplay.py | 4 +- AbsShip.py | 190 ++++++++++++++++++++++++++++++++++++++++++++ Aliens.py | 41 ---------- Assets.py | 99 ----------------------- Calculators.py | 30 ++++--- Map.py => Charts.py | 103 +++++++++++++----------- Controls.py | 29 ++++--- Glyphs.py | 5 ++ Reports.py | 2 +- Scanners.py | 46 ----------- StarTrek2020.py | 27 +++---- 12 files changed, 298 insertions(+), 282 deletions(-) create mode 100644 AbsShip.py delete mode 100644 Aliens.py delete mode 100644 Assets.py rename Map.py => Charts.py (59%) create mode 100644 Glyphs.py delete mode 100644 Scanners.py diff --git a/.gitignore b/.gitignore index ac0fe4e..52d737f 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,7 @@ /__pycache__/Assets.cpython-37.pyc /.vs/2020_12_20_StarTrek1971/v16/.suo /__pycache__/Map.cpython-37.pyc +/__pycache__/Charts.cpython-37.pyc +/__pycache__/AbsShip.cpython-37.pyc +/__pycache__/Glyphs.cpython-37.pyc +/.vs/slnx.sqlite-journal diff --git a/AbsDisplay.py b/AbsDisplay.py index 8366387..beb49d2 100644 --- a/AbsDisplay.py +++ b/AbsDisplay.py @@ -33,7 +33,7 @@ def print_strings(self, string_list): self.display() -class console(abs_display): +class Con(abs_display): ''' The best place to start is by encapsulating the default display. Will add screen metadata for it all, later. @@ -60,7 +60,7 @@ def read_double(self, prompt): if __name__ == '__main__': - con = console() + con = Con() con.display("Testing!") diff --git a/AbsShip.py b/AbsShip.py new file mode 100644 index 0000000..4f8c2ee --- /dev/null +++ b/AbsShip.py @@ -0,0 +1,190 @@ +import abc +import random + +import Glyphs + +class AbsShip(abc.ABC): + ''' The first step, into a much larger universe ... ''' + + def __init__(self): + self.shield_level = 0 + + @abc.abstractmethod + def get_glyph(self): + pass + + +class Enterprise(AbsShip): + + def __init__(self): + super().__init__() + self.energy = 0 + self.docked = False + self.condition = "GREEN" + self.navigation_damage = 0 + self.short_range_scan_damage = 0 + self.long_range_scan_damage = 0 + self.shield_control_damage = 0 + self.computer_damage = 0 + self.photon_damage = 0 + self.phaser_damage = 0 + + + def get_glyph(self): + return Glyphs.ENTERPRISE + + + def damage(self, game, item): + if random.randint(0, 6) > 0: + return + damage = 1 + random.randint(0, 4) + if item < 0: + item = random.randint(0, 6) + if item == 0: + self.navigation_damage = damage + game.display("Warp engines are malfunctioning.") + elif item == 1: + self.short_range_scan_damage = damage + game.display("Short range scanner is malfunctioning.") + elif item == 2: + self.long_range_scan_damage = damage + game.display("Long range scanner is malfunctioning.") + elif item == 3: + self.shield_control_damage = damage + game.display("Shield controls are malfunctioning.") + elif item == 4: + self.computer_damage = damage + game.display("The main computer is malfunctioning.") + elif item == 5: + self.photon_damage = damage + game.display("Photon torpedo controls are malfunctioning.") + elif item == 6: + self.phaser_damage = damage + game.display("Phasers are malfunctioning.") + game.display() + + + def repair(self, game): + if self.navigation_damage > 0: + self.navigation_damage -= 1 + if self.navigation_damage == 0: + game.display("Warp engines have been repaired.") + game.display() + return True + if self.short_range_scan_damage > 0: + self.short_range_scan_damage -= 1 + if self.short_range_scan_damage == 0: + game.display("Short range scanner has been repaired.") + self.display() + return True + if self.long_range_scan_damage > 0: + self.long_range_scan_damage -= 1 + if self.long_range_scan_damage == 0: + game.display("Long range scanner has been repaired.") + game.display() + return True + if self.shield_control_damage > 0: + self.shield_control_damage -= 1 + if self.shield_control_damage == 0: + game.display("Shield controls have been repaired.") + game.display() + return True + if self.computer_damage > 0: + self.computer_damage -= 1 + if self.computer_damage == 0: + game.display("The main computer has been repaired.") + game.display() + return True + if self.photon_damage > 0: + self.photon_damage -= 1 + if self.photon_damage == 0: + game.display("Photon torpedo controls have been repaired.") + game.display() + return True + if self.phaser_damage > 0: + self.phaser_damage -= 1 + if self.phaser_damage == 0: + game.display("Phasers have been repaired.") + game.display() + return True + return False + + + def short_range_scan(self, game): + from Charts import Sectors + + if self.short_range_scan_damage > 0: + game.display("Short range scanner is damaged. Repairs are underway.") + game.display() + else: + quadrant = game.quadrants[game.quadrant_y][game.quadrant_x] + quadrant.scanned = True + Sectors.print_sector(game, quadrant) + game.display() + + + def long_range_scan(self, game): + if self.long_range_scan_damage > 0: + game.display("Long range scanner is damaged. Repairs are underway.") + game.display() + return + sb = "" + game.display("-------------------") + for i in range(game.quadrant_y - 1, game.quadrant_y+2): # quadrantY + 1 ? + for j in range(game.quadrant_x - 1, game.quadrant_x+2): # quadrantX + 1? + sb += "| " + klingon_count = 0 + starbase_count = 0 + star_count = 0 + if 0 <= i < 8 and 0 <= j < 8: + quadrant = game.quadrants[i][j] + quadrant.scanned = True + klingon_count = quadrant.klingons + starbase_count = 1 if quadrant.starbase else 0 + star_count = quadrant.stars + sb = sb + \ + "{0}{1}{2} ".format(klingon_count, starbase_count, star_count) + sb += "|" + game.display(sb) + sb = "" + game.display("-------------------") + game.display() + + +class KlingonShip(AbsShip): + + def __init__(self): + super().__init__() + self.sector_x = 0 + self.sector_y = 0 + + + def get_glyph(self): + return Glyphs.KLINGON + + + @staticmethod + def attack(game): + from Calculators import calculator + if len(game.klingon_ships) > 0: + for ship in game.klingon_ships: + if game.enterprise.docked: + game.display("Enterprise hit by ship at sector [{0},{1}]. No damage due to starbase shields.".format( + ship.sector_x + 1, ship.sector_y + 1 + )) + else: + dist = calculator.distance( + game.sector_x, game.sector_y, ship.sector_x, ship.sector_y) + delivered_energy = 300 * \ + random.uniform(0.0, 1.0) * (1.0 - dist / 11.3) + game.enterprise.shield_level -= int(delivered_energy) + if game.enterprise.shield_level < 0: + game.enterprise.shield_level = 0 + game.destroyed = True + game.display("Enterprise hit by ship at sector [{0},{1}]. Shields dropped to {2}.".format( + ship.sector_x + 1, ship.sector_y + 1, game.enterprise.shield_level + )) + if game.enterprise.shield_level == 0: + return True + return True + return False diff --git a/Aliens.py b/Aliens.py deleted file mode 100644 index e5455f0..0000000 --- a/Aliens.py +++ /dev/null @@ -1,41 +0,0 @@ -import random - -from Assets import Enterprise - -class KlingonShip(object): - - def __init__(self): - self.sector_x = 0 - self.sector_y = 0 - self.shield_level = 0 - - @staticmethod - def attack(game): - from Calculators import calculator - if len(game.klingon_ships) > 0: - for ship in game.klingon_ships: - if game.enterprise.docked: - game.display("Enterprise hit by ship at sector [{0},{1}]. No damage due to starbase shields.".format( - ship.sector_x + 1, ship.sector_y + 1 - )) - else: - dist = calculator.distance( - game.sector_x, game.sector_y, ship.sector_x, ship.sector_y) - delivered_energy = 300 * \ - random.uniform(0.0, 1.0) * (1.0 - dist / 11.3) - game.enterprise.shield_level -= int(delivered_energy) - if game.enterprise.shield_level < 0: - game.enterprise.shield_level = 0 - game.destroyed = True - game.display("Enterprise hit by ship at sector [{0},{1}]. Shields dropped to {2}.".format( - ship.sector_x + 1, ship.sector_y + 1, game.enterprise.shield_level - )) - if game.enterprise.shield_level == 0: - return True - return True - return False - - - - - diff --git a/Assets.py b/Assets.py deleted file mode 100644 index d8d02ff..0000000 --- a/Assets.py +++ /dev/null @@ -1,99 +0,0 @@ -import random - - -class Enterprise(object): - - def __init__(self): - self.energy = 0 - self.shield_level = 0 - self.docked = False - self.condition = "GREEN" - self.navigation_damage = 0 - self.short_range_scan_damage = 0 - self.long_range_scan_damage = 0 - self.shield_control_damage = 0 - self.computer_damage = 0 - self.photon_damage = 0 - self.phaser_damage = 0 - - - def damage(self, game, item): - if random.randint(0, 6) > 0: - return - damage = 1 + random.randint(0, 4) - if item < 0: - item = random.randint(0, 6) - if item == 0: - self.navigation_damage = damage - game.display("Warp engines are malfunctioning.") - elif item == 1: - self.short_range_scan_damage = damage - game.display("Short range scanner is malfunctioning.") - elif item == 2: - self.long_range_scan_damage = damage - game.display("Long range scanner is malfunctioning.") - elif item == 3: - self.shield_control_damage = damage - game.display("Shield controls are malfunctioning.") - elif item == 4: - self.computer_damage = damage - game.display("The main computer is malfunctioning.") - elif item == 5: - self.photon_damage = damage - game.display("Photon torpedo controls are malfunctioning.") - elif item == 6: - self.phaser_damage = damage - game.display("Phasers are malfunctioning.") - game.display() - - - def repair(self, game): - if self.navigation_damage > 0: - self.navigation_damage -= 1 - if self.navigation_damage == 0: - game.display("Warp engines have been repaired.") - game.display() - return True - if self.short_range_scan_damage > 0: - self.short_range_scan_damage -= 1 - if self.short_range_scan_damage == 0: - game.display("Short range scanner has been repaired.") - self.display() - return True - if self.long_range_scan_damage > 0: - self.long_range_scan_damage -= 1 - if self.long_range_scan_damage == 0: - game.display("Long range scanner has been repaired.") - game.display() - return True - if self.shield_control_damage > 0: - self.shield_control_damage -= 1 - if self.shield_control_damage == 0: - game.display("Shield controls have been repaired.") - game.display() - return True - if self.computer_damage > 0: - self.computer_damage -= 1 - if self.computer_damage == 0: - game.display("The main computer has been repaired.") - game.display() - return True - if self.photon_damage > 0: - self.photon_damage -= 1 - if self.photon_damage == 0: - game.display("Photon torpedo controls have been repaired.") - game.display() - return True - if self.phaser_damage > 0: - self.phaser_damage -= 1 - if self.phaser_damage == 0: - game.display("Phasers have been repaired.") - game.display() - return True - return False - - - - - - diff --git a/Calculators.py b/Calculators.py index caadc10..930547a 100644 --- a/Calculators.py +++ b/Calculators.py @@ -1,12 +1,10 @@ from math import atan2, pi, sqrt, cos, sin import random -from Map import * -from Scanners import scanner -from Assets import Enterprise -from Aliens import KlingonShip +from Charts import * +from AbsShip import * -class calculator(object): +class Calc(object): @staticmethod def distance(x1, y1, x2, y2): @@ -60,7 +58,7 @@ def navigation(game): # quad_x = quad_y = sect_x = sect_y = 0 last_sect_x = game.sector_x last_sect_y = game.sector_y - game.sector[game.sector_y][game.sector_x] = game.sector_type.empty + game.sector[game.sector_y][game.sector_x] = Glyphs.SPACE obstacle = False for i in range(999): x += vx @@ -70,10 +68,10 @@ def navigation(game): if quad_x == game.quadrant_x and quad_y == game.quadrant_y: sect_x = int(round(x)) % 8 sect_y = int(round(y)) % 8 - if game.sector[sect_y][sect_x] != game.sector_type.empty: + if game.sector[sect_y][sect_x] != Glyphs.SPACE: game.sector_x = last_sect_x game.sector_y = last_sect_y - game.sector[game.sector_y][game.sector_x] = game.sector_type.enterprise + game.sector[game.sector_y][game.sector_x] = Glyphs.ENTERPRISE game.display("Encountered obstacle within quadrant.") game.display() obstacle = True @@ -97,12 +95,12 @@ def navigation(game): if quad_x != game.quadrant_x or quad_y != game.quadrant_y: game.quadrant_x = int(quad_x) game.quadrant_y = int(quad_y) - Map.generate_sector(game) + Sectors.generate_sector(game) else: game.quadrant_x = int(quad_x) game.quadrant_y = int(quad_y) - game.sector[game.sector_y][game.sector_x] = game.sector_type.enterprise - if Map.is_docking_location(game, game.sector_y, game.sector_x): + game.sector[game.sector_y][game.sector_x] = Glyphs.ENTERPRISE + if Sectors.is_docking_location(game, game.sector_y, game.sector_x): game.enterprise.energy = 3000 game.photon_torpedoes = 10 game.enterprise.navigation_damage = 0 @@ -121,7 +119,7 @@ def navigation(game): game.time_remaining -= 1 game.star_date += 1 - scanner.short_range_scan(game) + game.enterprise.short_range_scan(game) if game.enterprise.docked: game.display("Lowering shields as part of docking sequence...") @@ -188,10 +186,10 @@ def navigation_calculator(game): game.display("That is the current location of the Enterprise.") game.display() return - direction = calculator.compute_direction(game.quadrant_x, game.quadrant_y, qx, qy) + direction = Calc.compute_direction(game.quadrant_x, game.quadrant_y, qx, qy) game.display("Direction: {0:1.2f}".format(direction)) game.display("Distance: {0:2.2f}".format( - calculator.distance(game.quadrant_x, game.quadrant_y, qx, qy))) + Calc.distance(game.quadrant_x, game.quadrant_y, qx, qy))) game.display() @staticmethod @@ -199,10 +197,10 @@ def starbase_calculator(game): game.display() if game.quadrants[game.quadrant_y][game.quadrant_x].starbase: game.display("Starbase in sector [%s,%s]." % (game.starbase_x + 1, game.starbase_y + 1)) - direction = calculator.compute_direction(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) + direction = Calc.compute_direction(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) game.display("Direction: {0:1.2f}".format(direction)) game.display("Distance: {0:2.2f}".format( - calculator.distance(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) / 8)) + Calc.distance(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) / 8)) else: game.display("There are no starbases in this quadrant.") game.display() diff --git a/Map.py b/Charts.py similarity index 59% rename from Map.py rename to Charts.py index 9fae9a1..3fe0e68 100644 --- a/Map.py +++ b/Charts.py @@ -1,26 +1,31 @@ import random import TrekStrings -from Aliens import KlingonShip +import Glyphs +from AbsShip import KlingonShip class Quadrant(): - def __init__(game): - game.name = "" - game.klingons = 0 - game.stars = 0 - game.starbase = False - game.scanned = False + def __init__(self): + self.name = "" + self.klingons = 0 + self.stars = 0 + self.starbase = False + self.scanned = False class SectorType(): - def __init__(game): - game.empty, game.star, game.klingon, game.enterprise, game.starbase = 1, 2, 3, 4, 5 + def __init__(self): + self.empty, self.star, self.klingon, \ + self.enterprise, self.starbase = \ + Glyphs.SPACE, Glyphs.STAR, Glyphs.KLINGON, \ + Glyphs.ENTERPRISE, Glyphs.STARBASE -class Map(object): + +class Sectors(object): @staticmethod def initialize_game(game): @@ -72,22 +77,22 @@ def generate_sector(game): game.klingon_ships = [] for i in range(8): for j in range(8): - game.sector[i][j] = game.sector_type.empty - game.sector[game.sector_y][game.sector_x] = game.sector_type.enterprise + game.sector[i][j] = Glyphs.SPACE + game.sector[game.sector_y][game.sector_x] = Glyphs.ENTERPRISE while starbase or stars > 0 or klingons > 0: i = random.randint(0, 7) j = random.randint(0, 7) - if Map.is_sector_region_empty(game, i, j): + if Sectors.is_sector_region_empty(game, i, j): if starbase: starbase = False - game.sector[i][j] = game.sector_type.starbase + game.sector[i][j] = Glyphs.STARBASE game.starbase_y = i game.starbase_x = j elif stars > 0: - game.sector[i][j] = game.sector_type.star + game.sector[i][j] = Glyphs.STAR stars -= 1 elif klingons > 0: - game.sector[i][j] = game.sector_type.klingon + game.sector[i][j] = Glyphs.KLINGON klingon_ship = KlingonShip() klingon_ship.shield_level = 300 + random.randint(0, 199) klingon_ship.sector_y = i @@ -98,18 +103,18 @@ def generate_sector(game): @staticmethod def is_sector_region_empty(game, i, j): for y in range(i - 1, i+1): # i + 1? - if Map.read_sector(game, y, j - 1) != \ - game.sector_type.empty and \ - Map.read_sector(game, y, j + 1) != \ - game.sector_type.empty: + if Sectors.read_sector(game, y, j - 1) != \ + Glyphs.SPACE and \ + Sectors.read_sector(game, y, j + 1) != \ + Glyphs.SPACE: return False - return Map.read_sector(game, i, j) == game.sector_type.empty + return Sectors.read_sector(game, i, j) == Glyphs.SPACE @staticmethod def read_sector(game, i, j): if i < 0 or j < 0 or i > 7 or j > 7: - return game.sector_type.empty + return Glyphs.SPACE return game.sector[i][j] @@ -117,7 +122,7 @@ def read_sector(game, i, j): def is_docking_location(game, i, j): for y in range(i - 1, i+1): # i + 1? for x in range(j - 1, j+1): # j + 1? - if Map.read_sector(game, y, x) == game.sector_type.starbase: + if Sectors.read_sector(game, y, x) == Glyphs.STARBASE: return True return False @@ -130,18 +135,21 @@ def print_sector(game, quadrant): elif game.enterprise.energy < 300: game.enterprise.condition = "YELLOW" - sb = "" - game.display("-=--=--=--=--=--=--=--=- Region: {0}".format(quadrant.name)) - Map.print_sector_row(game, sb, 0, " Quadrant: [{0},{1}]".format( - game.quadrant_x + 1, game.quadrant_y + 1)) - Map.print_sector_row(game, sb, 1, " Sector: [{0},{1}]".format(game.sector_x + 1, game.sector_y + 1)) - Map.print_sector_row(game, sb, 2, " Stardate: {0}".format(game.star_date)) - Map.print_sector_row(game, sb, 3, " Time remaining: {0}".format(game.time_remaining)) - Map.print_sector_row(game, sb, 4, " Condition: {0}".format(game.enterprise.condition)) - Map.print_sector_row(game, sb, 5, " Energy: {0}".format(game.enterprise.energy)) - Map.print_sector_row(game, sb, 6, " Shields: {0}".format(game.enterprise.shield_level)) - Map.print_sector_row(game, sb, 7, " Photon Torpedoes: {0}".format(game.photon_torpedoes)) - game.display("-=--=--=--=--=--=--=--=- Docked: {0}".format(game.enterprise.docked)) + sb = " a b c d e f g h \n" + sb += f" -=--=--=--=--=--=--=--=- Region: {quadrant.name}\n" + info = list() + info.append(f" Quadrant: [{game.quadrant_x + 1}, {game.quadrant_y + 1}\n") + info.append(f" Sector: [{game.sector_x + 1}, {game.sector_y + 1}\n") + info.append(f" Stardate: {game.star_date}\n") + info.append(f" Time remaining: {game.time_remaining}\n") + info.append(f" Condition: {game.enterprise.condition}\n") + info.append(f" Energy: {game.enterprise.energy}\n") + info.append(f" Shields: {game.enterprise.shield_level}\n") + info.append(f" Photon Torpedoes: {game.photon_torpedoes}\n") + for ss in range(8): + sb = Sectors._get_row(game, sb, ss, info[ss]) + sb += " -=--=--=--=--=--=--=--=- Docked: {game.enterprise.docked}\n" + print(sb, end='') if quadrant.klingons > 0: game.display() @@ -155,20 +163,21 @@ def print_sector(game, quadrant): @staticmethod - def print_sector_row(game, sb, row, suffix): + def _get_row(game, sb, row, suffix): + sb += f" {row} |" for column in range(8): - if game.sector[row][column] == game.sector_type.empty: - sb += " " - elif game.sector[row][column] == game.sector_type.enterprise: - sb += "" - elif game.sector[row][column] == game.sector_type.klingon: - sb += "+K+" - elif game.sector[row][column] == game.sector_type.star: - sb += " * " - elif game.sector[row][column] == game.sector_type.starbase: - sb += ">S<" + if game.sector[row][column] == Glyphs.SPACE: + sb += Glyphs.SPACE + elif game.sector[row][column] == Glyphs.ENTERPRISE: + sb += Glyphs.ENTERPRISE + elif game.sector[row][column] == Glyphs.KLINGON: + sb += Glyphs.KLINGON + elif game.sector[row][column] == Glyphs.STAR: + sb += Glyphs.STAR + elif game.sector[row][column] == Glyphs.STARBASE: + sb += Glyphs.STARBASE if suffix is not None: sb = sb + suffix - game.display(sb) + return sb diff --git a/Controls.py b/Controls.py index 363ca3e..50b9cef 100644 --- a/Controls.py +++ b/Controls.py @@ -2,10 +2,9 @@ import random import TrekStrings -from Assets import Enterprise -from Aliens import KlingonShip -from Calculators import calculator -from Reports import status +from AbsShip import * +from Calculators import Calc +from Reports import Stats class control(object): @@ -19,15 +18,15 @@ def computer_controls(game): game.print_strings(TrekStrings.computerStrings) command = game.read("Enter computer command: ").strip().lower() if command == "rec": - status.display_galactic_record(game) + Stats.display_galactic_record(game) elif command == "sta": - status.display_status(game) + Stats.display_status(game) elif command == "tor": - calculator.photon_torpedo_calculator(game) + Calc.photon_torpedo_calculator(game) elif command == "bas": - calculator.starbase_calculator(game) + Calc.starbase_calculator(game) elif command == "nav": - calculator.navigation_calculator(game) + Calc.navigation_calculator(game) else: game.display() game.display("Invalid computer command.") @@ -59,7 +58,7 @@ def phaser_controls(game): if game.enterprise.energy < 0: game.enterprise.energy = 0 break - dist = calculator.distance(game.sector_x, game.sector_y, ship.sector_x, ship.sector_y) + dist = Calc.distance(game.sector_x, game.sector_y, ship.sector_x, ship.sector_y) delivered_energy = phaser_energy * (1.0 - dist / 11.3) ship.shield_level -= int(delivered_energy) if ship.shield_level <= 0: @@ -72,7 +71,7 @@ def phaser_controls(game): for ship in destroyed_ships: game.quadrants[game.quadrant_y][game.quadrant_x].klingons -= 1 game.klingons -= 1 - game.sector[ship.sector_y][ship.sector_x] = game.sector_type.empty + game.sector[ship.sector_y][ship.sector_x] = Glyphs.SPACE game.klingon_ships.remove(ship) if len(game.klingon_ships) > 0: game.display() @@ -156,7 +155,7 @@ def torpedo_control(game): for ship in game.klingon_ships: if ship.sector_x == new_x and ship.sector_y == new_y: game.display("Klingon ship destroyed at sector [{0},{1}].".format(ship.sector_x + 1, ship.sector_y + 1)) - game.sector[ship.sector_y][ship.sector_x] = game.sector_type.empty + game.sector[ship.sector_y][ship.sector_x] = Glyphs.SPACE game.klingons -= 1 game.klingon_ships.remove(ship) game.quadrants[game.quadrant_y][game.quadrant_x].klingons -= 1 @@ -164,14 +163,14 @@ def torpedo_control(game): break # break out of the for loop if hit: break # break out of the while loop - if game.sector[new_y][new_x] == game.sector_type.starbase: + if game.sector[new_y][new_x] == Glyphs.STARBASE: game.starbases -= 1 game.quadrants[game.quadrant_y][game.quadrant_x].starbase = False - game.sector[new_y][new_x] = game.sector_type.empty + game.sector[new_y][new_x] = Glyphs.SPACE game.display("The Enterprise destroyed a Federation starbase at sector [{0},{1}]!".format(new_x + 1, new_y + 1)) hit = True break - elif game.sector[new_y][new_x] == game.sector_type.star: + elif game.sector[new_y][new_x] == Glyphs.STAR: game.display("The torpedo was captured by a star's gravitational field at sector [{0},{1}].".format( new_x + 1, new_y + 1 )) diff --git a/Glyphs.py b/Glyphs.py new file mode 100644 index 0000000..5d2fe94 --- /dev/null +++ b/Glyphs.py @@ -0,0 +1,5 @@ +SPACE = " " +STAR = " * " +STARBASE = ">S<" +ENTERPRISE = "" +KLINGON = "+K+" diff --git a/Reports.py b/Reports.py index 75a2fcb..1ff7249 100644 --- a/Reports.py +++ b/Reports.py @@ -1,5 +1,5 @@ -class status(object): +class Stats(object): @staticmethod def display_status(game): diff --git a/Scanners.py b/Scanners.py deleted file mode 100644 index c7a831a..0000000 --- a/Scanners.py +++ /dev/null @@ -1,46 +0,0 @@ -from Map import * - -class scanner(object): - - @staticmethod - def short_range_scan(game): - if game.enterprise.short_range_scan_damage > 0: - game.display("Short range scanner is damaged. Repairs are underway.") - game.display() - else: - quadrant = game.quadrants[game.quadrant_y][game.quadrant_x] - quadrant.scanned = True - Map.print_sector(game, quadrant) - game.display() - - @staticmethod - def long_range_scan(game): - if game.enterprise.long_range_scan_damage > 0: - game.display("Long range scanner is damaged. Repairs are underway.") - game.display() - return - sb = "" - game.display("-------------------") - for i in range(game.quadrant_y - 1, game.quadrant_y+2): # quadrantY + 1 ? - for j in range(game.quadrant_x - 1, game.quadrant_x+2): # quadrantX + 1? - sb += "| " - klingon_count = 0 - starbase_count = 0 - star_count = 0 - if 0 <= i < 8 and 0 <= j < 8: - quadrant = game.quadrants[i][j] - quadrant.scanned = True - klingon_count = quadrant.klingons - starbase_count = 1 if quadrant.starbase else 0 - star_count = quadrant.stars - sb = sb + \ - "{0}{1}{2} ".format(klingon_count, starbase_count, star_count) - sb += "|" - game.display(sb) - sb = "" - game.display("-------------------") - game.display() - - - - diff --git a/StarTrek2020.py b/StarTrek2020.py index d124685..b3a9eef 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -3,17 +3,15 @@ import TrekStrings -from AbsDisplay import console -from Calculators import calculator +from AbsDisplay import Con +from Calculators import Calc from Controls import control -from Scanners import scanner -from Reports import status -from Assets import Enterprise -from Aliens import KlingonShip -from Map import * +from Reports import Stats +from AbsShip import * +from Charts import * -class Game(console): +class Game(Con): def __init__(self): self.enterprise = Enterprise() @@ -21,7 +19,6 @@ def __init__(self): self.time_remaining = 0 self.klingons = 0 self.starbases = 0 - self.sector_type = SectorType() self.quadrant_x, self.quadrant_y = 0, 0 self.sector_x, self.sector_y = 0, 0 self.photon_torpedoes = 0 @@ -34,26 +31,26 @@ def __init__(self): def run(self): self.print_strings(TrekStrings.titleStrings) - Map.initialize_game(game) + Sectors.initialize_game(game) self.print_mission() - Map.generate_sector(game) + Sectors.generate_sector(game) self.print_strings(TrekStrings.commandStrings) while self.enterprise.energy > 0 and not \ self.destroyed and self.klingons > 0 and \ self.time_remaining > 0: self.command_prompt() - status.print_game_status(game) + Stats.print_game_status(game) def command_prompt(self): command = self.read("Enter command: ").strip().lower() self.display() if command == "nav": - calculator.navigation(game) + Calc.navigation(game) elif command == "srs": - scanner.short_range_scan(game) + game.enterprise.short_range_scan(game) elif command == "lrs": - scanner.long_range_scan(game) + game.enterprise.long_range_scan(game) elif command == "pha": control.phaser_controls(game) elif command == "tor": From 43b4e01c15e8ea583d82b9bcee14bfeb6b9ca664 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Tue, 22 Dec 2020 12:31:03 -0500 Subject: [PATCH 014/100] Chess-inspired coordinates. --- .gitignore | 12 ++- AbsDisplay.py | 34 ------- AbsShip.py | 104 ++++++++++++-------- Calculators.py | 141 +++++++-------------------- Charts.py | 183 ----------------------------------- Console.py | 49 ++++++++++ Controls.py | 124 +++++++++++------------- Glyphs.py | 2 + MapGame.py | 237 ++++++++++++++++++++++++++++++++++++++++++++++ MapSparse.py | 203 +++++++++++++++++++++++++++++++++++++++ Points.py | 83 ++++++++++++++++ Quadrant.py | 28 ++++++ Quips.py | 67 +++++++++++++ Reports.py | 75 +++++++-------- Sectors.py | 43 +++++++++ StarTrek2020.py | 51 +++++----- TrekStrings.py | 4 +- test_MapSparse.py | 50 ++++++++++ 18 files changed, 991 insertions(+), 499 deletions(-) delete mode 100644 Charts.py create mode 100644 Console.py create mode 100644 MapGame.py create mode 100644 MapSparse.py create mode 100644 Points.py create mode 100644 Quadrant.py create mode 100644 Quips.py create mode 100644 Sectors.py create mode 100644 test_MapSparse.py diff --git a/.gitignore b/.gitignore index 52d737f..0aaa764 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,17 @@ /__pycache__/Assets.cpython-37.pyc /.vs/2020_12_20_StarTrek1971/v16/.suo /__pycache__/Map.cpython-37.pyc -/__pycache__/Charts.cpython-37.pyc +/__pycache__/MapGame.cpython-37.pyc /__pycache__/AbsShip.cpython-37.pyc /__pycache__/Glyphs.cpython-37.pyc /.vs/slnx.sqlite-journal +/__pycache__/Charts.cpython-37.pyc +/.vs/PythonSettings.json +/__pycache__/Calculators.cpython-37.pyc.2654468500952 +/__pycache__/Sectors.cpython-37.pyc +/__pycache__/Quips.cpython-37.pyc +/__pycache__/Quadrant.cpython-37.pyc +/__pycache__/Points.cpython-37.pyc +/__pycache__/MapSparse.cpython-37.pyc +/__pycache__/MapSparce.cpython-37.pyc +/__pycache__/Console.cpython-37.pyc diff --git a/AbsDisplay.py b/AbsDisplay.py index beb49d2..ac6c8ee 100644 --- a/AbsDisplay.py +++ b/AbsDisplay.py @@ -32,37 +32,3 @@ def print_strings(self, string_list): self.display(string) self.display() - -class Con(abs_display): - ''' - The best place to start is by encapsulating the default - display. Will add screen metadata for it all, later. - ''' - def __init__(self): - super().__init__(abs_display.ST_CONSOLE) - - def display(self, message = ''): - print(message) - - def read(self, prompt=''): - return input(prompt) - - def read_double(self, prompt): - text = input(prompt) - try: - value = float(text) - return value - except: - pass - return False - - - - -if __name__ == '__main__': - con = Con() - con.display("Testing!") - - - - diff --git a/AbsShip.py b/AbsShip.py index 4f8c2ee..f92e2f6 100644 --- a/AbsShip.py +++ b/AbsShip.py @@ -2,6 +2,7 @@ import random import Glyphs +from Quips import Quips class AbsShip(abc.ABC): ''' The first step, into a much larger universe ... ''' @@ -13,6 +14,32 @@ def __init__(self): def get_glyph(self): pass +class StarBase(AbsShip): + + def __init__(self): + super().__init__() + + def get_glyph(self): + return Glyphs.STARBASE + + @staticmethod + def dock_enterprise(ship): + ship.energy = 3000 + ship.photon_torpedoes = 10 + ship.navigation_damage = 0 + ship.short_range_scan_damage = 0 + ship.long_range_scan_damage = 0 + ship.shield_control_damage = 0 + ship.computer_damage = 0 + ship.photon_damage = 0 + ship.phaser_damage = 0 + ship.shield_level = 0 + ship.docked = True + + @staticmethod + def launch_enterprise(ship): + ship.docked = False + class Enterprise(AbsShip): @@ -28,13 +55,17 @@ def __init__(self): self.computer_damage = 0 self.photon_damage = 0 self.phaser_damage = 0 - + self.photon_torpedoes = 0 + StarBase.dock_enterprise(self) + StarBase.launch_enterprise(self) def get_glyph(self): return Glyphs.ENTERPRISE def damage(self, game, item): + if game.is_testing: + return if random.randint(0, 6) > 0: return damage = 1 + random.randint(0, 4) @@ -42,25 +73,25 @@ def damage(self, game, item): item = random.randint(0, 6) if item == 0: self.navigation_damage = damage - game.display("Warp engines are malfunctioning.") + game.display(Quips.jibe_damage('Warp Engines')) elif item == 1: self.short_range_scan_damage = damage - game.display("Short range scanner is malfunctioning.") + game.display(Quips.jibe_damage('Short Range Scanners')) elif item == 2: self.long_range_scan_damage = damage - game.display("Long range scanner is malfunctioning.") + game.display(Quips.jibe_damage('Long Range Scanners')) elif item == 3: self.shield_control_damage = damage - game.display("Shield controls are malfunctioning.") + game.display(Quips.jibe_damage('Shield Controls')) elif item == 4: self.computer_damage = damage - game.display("The main computer is malfunctioning.") + game.display(Quips.jibe_damage('Main Computer')) elif item == 5: self.photon_damage = damage - game.display("Photon torpedo controls are malfunctioning.") + game.display(Quips.jibe_damage('Photon Torpedo Controls')) elif item == 6: self.phaser_damage = damage - game.display("Phasers are malfunctioning.") + game.display(Quips.jibe_damage('Phasers')) game.display() @@ -111,39 +142,32 @@ def repair(self, game): def short_range_scan(self, game): - from Charts import Sectors + from MapGame import Sectors if self.short_range_scan_damage > 0: - game.display("Short range scanner is damaged. Repairs are underway.") + game.display(Quips.jibe_damage('Short Ranged Scanners')) game.display() else: - quadrant = game.quadrants[game.quadrant_y][game.quadrant_x] - quadrant.scanned = True - Sectors.print_sector(game, quadrant) + quad = game.game_map.quad() + Sectors.print_sector(game, quad) game.display() def long_range_scan(self, game): if self.long_range_scan_damage > 0: - game.display("Long range scanner is damaged. Repairs are underway.") + game.display(Quips.jibe_damage('Long Ranged Scanners')) game.display() return sb = "" game.display("-------------------") - for i in range(game.quadrant_y - 1, game.quadrant_y+2): # quadrantY + 1 ? - for j in range(game.quadrant_x - 1, game.quadrant_x+2): # quadrantX + 1? - sb += "| " - klingon_count = 0 - starbase_count = 0 - star_count = 0 - if 0 <= i < 8 and 0 <= j < 8: - quadrant = game.quadrants[i][j] - quadrant.scanned = True - klingon_count = quadrant.klingons - starbase_count = 1 if quadrant.starbase else 0 - star_count = quadrant.stars - sb = sb + \ - "{0}{1}{2} ".format(klingon_count, starbase_count, star_count) + pw_sector = game.game_map.sector + if pw_sector < 5: + pw_sector = 5 + elif pw_sector > 59: + pw_sector = 59 + for peek in range(pw_sector-5, pw_sector + 6): + quad = game.game_map.scan_quad(peek) + f"{quad.klingons}{quad.starbases}{quad.stars} " sb += "|" game.display(sb) sb = "" @@ -155,26 +179,32 @@ class KlingonShip(AbsShip): def __init__(self): super().__init__() - self.sector_x = 0 - self.sector_y = 0 + self.xpos = 0 + self.ypos = 0 + self.shield_level = 0 def get_glyph(self): return Glyphs.KLINGON + def from_map(self, xpos, ypos): + self.xpos = xpos + self.ypos = ypos + self.shield_level = 300 + random.randint(0, 199) @staticmethod def attack(game): - from Calculators import calculator - if len(game.klingon_ships) > 0: - for ship in game.klingon_ships: + from Calculators import Calc + kships = game.game_map.get_area_klingons() + if len(kships) > 0: + for ship in kships: if game.enterprise.docked: game.display("Enterprise hit by ship at sector [{0},{1}]. No damage due to starbase shields.".format( - ship.sector_x + 1, ship.sector_y + 1 + ship.xpos + 1, ship.ypos + 1 )) else: - dist = calculator.distance( - game.sector_x, game.sector_y, ship.sector_x, ship.sector_y) + dist = Calc.distance( + game.game_map.xpos, game.game_map.ypos, ship.xpos, ship.ypos) delivered_energy = 300 * \ random.uniform(0.0, 1.0) * (1.0 - dist / 11.3) game.enterprise.shield_level -= int(delivered_energy) @@ -182,7 +212,7 @@ def attack(game): game.enterprise.shield_level = 0 game.destroyed = True game.display("Enterprise hit by ship at sector [{0},{1}]. Shields dropped to {2}.".format( - ship.sector_x + 1, ship.sector_y + 1, game.enterprise.shield_level + ship.xpos + 1, ship.ypos + 1, game.enterprise.shield_level )) if game.enterprise.shield_level == 0: return True diff --git a/Calculators.py b/Calculators.py index 930547a..c897bbf 100644 --- a/Calculators.py +++ b/Calculators.py @@ -1,10 +1,11 @@ from math import atan2, pi, sqrt, cos, sin import random -from Charts import * +from MapGame import * from AbsShip import * +from Points import Destination -class Calc(object): +class Calc(): @staticmethod def distance(x1, y1, x2, y2): @@ -12,30 +13,23 @@ def distance(x1, y1, x2, y2): y = y2 - y1 return sqrt(x * x + y * y) + @staticmethod def navigation(game): - max_warp_factor = 8.0 if game.enterprise.navigation_damage > 0: max_warp_factor = 0.2 + random.randint(0, 8) / 10.0 game.display("Warp engines damaged. Maximum warp factor: {0}".format(max_warp_factor)) game.display() - direction = game.read_double("Enter course (1.0--8.9): ") - if not direction or direction < 1.0 or direction > 9.0: + dest_sys = game.read_sector() + if not dest_sys: game.display("Invalid course.") game.display() return - dist = game.read_double( - "Enter warp factor (0.1--{0}): ".format(max_warp_factor)) - if not dist or dist < 0.1 or dist > max_warp_factor: - game.display("Invalid warp factor.") - game.display() - return - game.display() - dist *= 8 + dist = dest_sys.warp * 8 energy_required = int(dist) if energy_required >= game.enterprise.energy: game.display("Unable to comply. Insufficient energy to travel that speed.") @@ -46,78 +40,10 @@ def navigation(game): game.display() game.enterprise.energy -= energy_required - last_quad_x = game.quadrant_x - last_quad_y = game.quadrant_y - angle = -(pi * (direction - 1.0) / 4.0) - x = game.quadrant_x * 8 + game.sector_x - y = game.quadrant_y * 8 + game.sector_y - dx = dist * cos(angle) - dy = dist * sin(angle) - vx = dx / 1000 - vy = dy / 1000 - # quad_x = quad_y = sect_x = sect_y = 0 - last_sect_x = game.sector_x - last_sect_y = game.sector_y - game.sector[game.sector_y][game.sector_x] = Glyphs.SPACE - obstacle = False - for i in range(999): - x += vx - y += vy - quad_x = int(round(x)) / 8 - quad_y = int(round(y)) / 8 - if quad_x == game.quadrant_x and quad_y == game.quadrant_y: - sect_x = int(round(x)) % 8 - sect_y = int(round(y)) % 8 - if game.sector[sect_y][sect_x] != Glyphs.SPACE: - game.sector_x = last_sect_x - game.sector_y = last_sect_y - game.sector[game.sector_y][game.sector_x] = Glyphs.ENTERPRISE - game.display("Encountered obstacle within quadrant.") - game.display() - obstacle = True - break - last_sect_x = sect_x - last_sect_y = sect_y - - if not obstacle: - if x < 0: - x = 0 - elif x > 63: - x = 63 - if y < 0: - y = 0 - elif y > 63: - y = 63 - quad_x = int(round(x)) / 8 - quad_y = int(round(y)) / 8 - game.sector_x = int(round(x)) % 8 - game.sector_y = int(round(y)) % 8 - if quad_x != game.quadrant_x or quad_y != game.quadrant_y: - game.quadrant_x = int(quad_x) - game.quadrant_y = int(quad_y) - Sectors.generate_sector(game) - else: - game.quadrant_x = int(quad_x) - game.quadrant_y = int(quad_y) - game.sector[game.sector_y][game.sector_x] = Glyphs.ENTERPRISE - if Sectors.is_docking_location(game, game.sector_y, game.sector_x): - game.enterprise.energy = 3000 - game.photon_torpedoes = 10 - game.enterprise.navigation_damage = 0 - game.enterprise.short_range_scan_damage = 0 - game.enterprise.long_range_scan_damage = 0 - game.enterprise.shield_control_damage = 0 - game.enterprise.computer_damage = 0 - game.enterprise.photon_damage = 0 - game.enterprise.phaser_damage = 0 - game.enterprise.shield_level = 0 - game.enterprise.docked = True - else: - game.enterprise.docked = False + game.game_map.go_to(dest_sys) - if last_quad_x != game.quadrant_x or last_quad_y != game.quadrant_y: - game.time_remaining -= 1 - game.star_date += 1 + game.time_remaining -= 1 + game.star_date += 1 game.enterprise.short_range_scan(game) @@ -126,8 +52,7 @@ def navigation(game): game.display("Enterprise successfully docked with starbase.") game.display() else: - if game.quadrants[game.quadrant_y][game.quadrant_x].klingons > 0 \ - and last_quad_x == game.quadrant_x and last_quad_y == game.quadrant_y: + if game.game_map.klingons > 0: KlingonShip.attack(game) game.display() elif not game.enterprise.repair(game): @@ -167,7 +92,7 @@ def compute_direction(x1, y1, x2, y2): def navigation_calculator(game): game.display() game.display("Enterprise located in quadrant [%s,%s]." % \ - (game.quadrant_x + 1, game.quadrant_y + 1)) + (game.game_map.major_x + 1, game.game_map.major_y + 1)) game.display() quad_x = game.read_double("Enter destination quadrant X (1--8): ") if quad_x is False or quad_x < 1 or quad_x > 8: @@ -182,42 +107,46 @@ def navigation_calculator(game): game.display() qx = int(quad_x) - 1 qy = int(quad_y) - 1 - if qx == game.quadrant_x and qy == game.quadrant_y: + if qx == game.game_map.major_x and qy == game.game_map.major_y: game.display("That is the current location of the Enterprise.") game.display() return - direction = Calc.compute_direction(game.quadrant_x, game.quadrant_y, qx, qy) + direction = Calc.compute_direction( + game.game_map.major_x, + game.game_map.major_y, + qx, qy) game.display("Direction: {0:1.2f}".format(direction)) game.display("Distance: {0:2.2f}".format( - Calc.distance(game.quadrant_x, game.quadrant_y, qx, qy))) + Calc.distance(game.game_map.major_x, game.game_map.major_y, qx, qy))) game.display() + @staticmethod - def starbase_calculator(game): + def starbase_inventory(game): + game.display() + bases = game.game_map.get_all(Glyphs.STARBASE) game.display() - if game.quadrants[game.quadrant_y][game.quadrant_x].starbase: - game.display("Starbase in sector [%s,%s]." % (game.starbase_x + 1, game.starbase_y + 1)) - direction = Calc.compute_direction(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) - game.display("Direction: {0:1.2f}".format(direction)) - game.display("Distance: {0:2.2f}".format( - Calc.distance(game.sector_x, game.sector_y, game.starbase_x, game.starbase_y) / 8)) + if bases: + game.display("Starbases:") + for info in bases: + area = info[0]; base = info[1] + game.display(f"\tSector #{area.number} at [{base.xpos},{base.ypos}].") else: - game.display("There are no starbases in this quadrant.") + game.display("There are no Starbases.") game.display() + @staticmethod def photon_torpedo_calculator(game): game.display() - if len(game.klingon_ships) == 0: - game.display("There are no Klingon ships in this quadrant.") - game.display() + kships = game.game_map.get_area_klingons() + if len(kships) == 0: + game.display("There are no enemy ships in this quadrant.") return - for ship in game.klingon_ships: - text = "Direction {2:1.2f}: Klingon ship in sector [{0},{1}]." - direction = compute_direction(game.sector_x, game.sector_y, ship.sector_x, ship.sector_y) - game.display(text.format( - ship.sector_x + 1, ship.sector_y + 1, direction)) + game.display("Enemies:") + for ship in kships: + game.display(f"\tKlingon [{ship.xpos},{ship.ypos}].") game.display() diff --git a/Charts.py b/Charts.py deleted file mode 100644 index 3fe0e68..0000000 --- a/Charts.py +++ /dev/null @@ -1,183 +0,0 @@ -import random -import TrekStrings - -import Glyphs -from AbsShip import KlingonShip - - -class Quadrant(): - - def __init__(self): - self.name = "" - self.klingons = 0 - self.stars = 0 - self.starbase = False - self.scanned = False - - -class SectorType(): - - def __init__(self): - self.empty, self.star, self.klingon, \ - self.enterprise, self.starbase = \ - Glyphs.SPACE, Glyphs.STAR, Glyphs.KLINGON, \ - Glyphs.ENTERPRISE, Glyphs.STARBASE - - - -class Sectors(object): - - @staticmethod - def initialize_game(game): - game.quadrant_x = random.randint(0, 7) - game.quadrant_y = random.randint(0, 7) - game.sector_x = random.randint(0, 7) - game.sector_y = random.randint(0, 7) - game.star_date = random.randint(0, 50) + 2250 - game.enterprise.energy = 3000 - game.photon_torpedoes = 10 - game.time_remaining = 40 + random.randint(0, 9) - game.klingons = 15 + random.randint(0, 5) - game.starbases = 2 + random.randint(0, 2) - game.destroyed = False - - names = [] - for name in TrekStrings.quadrantNames: - names.append(name) - - for i in range(8): - for j in range(8): - index = random.randint(0, len(names) - 1) - quadrant = Quadrant() - quadrant.name = names[index] - quadrant.stars = 1 + random.randint(0, 7) - game.quadrants[i][j] = quadrant - del names[index] - - klingon_count = game.klingons - starbase_count = game.starbases - while klingon_count > 0 or starbase_count > 0: - i = random.randint(0, 7) - j = random.randint(0, 7) - quadrant = game.quadrants[i][j] - if not quadrant.starbase: - quadrant.starbase = True - starbase_count -= 1 - if quadrant.klingons < 3: - quadrant.klingons += 1 - klingon_count -= 1 - - - @staticmethod - def generate_sector(game): - quadrant = game.quadrants[game.quadrant_y][game.quadrant_x] - starbase = quadrant.starbase - stars = quadrant.stars - klingons = quadrant.klingons - game.klingon_ships = [] - for i in range(8): - for j in range(8): - game.sector[i][j] = Glyphs.SPACE - game.sector[game.sector_y][game.sector_x] = Glyphs.ENTERPRISE - while starbase or stars > 0 or klingons > 0: - i = random.randint(0, 7) - j = random.randint(0, 7) - if Sectors.is_sector_region_empty(game, i, j): - if starbase: - starbase = False - game.sector[i][j] = Glyphs.STARBASE - game.starbase_y = i - game.starbase_x = j - elif stars > 0: - game.sector[i][j] = Glyphs.STAR - stars -= 1 - elif klingons > 0: - game.sector[i][j] = Glyphs.KLINGON - klingon_ship = KlingonShip() - klingon_ship.shield_level = 300 + random.randint(0, 199) - klingon_ship.sector_y = i - klingon_ship.sector_x = j - game.klingon_ships.append(klingon_ship) - klingons -= 1 - - @staticmethod - def is_sector_region_empty(game, i, j): - for y in range(i - 1, i+1): # i + 1? - if Sectors.read_sector(game, y, j - 1) != \ - Glyphs.SPACE and \ - Sectors.read_sector(game, y, j + 1) != \ - Glyphs.SPACE: - return False - return Sectors.read_sector(game, i, j) == Glyphs.SPACE - - - @staticmethod - def read_sector(game, i, j): - if i < 0 or j < 0 or i > 7 or j > 7: - return Glyphs.SPACE - return game.sector[i][j] - - - @staticmethod - def is_docking_location(game, i, j): - for y in range(i - 1, i+1): # i + 1? - for x in range(j - 1, j+1): # j + 1? - if Sectors.read_sector(game, y, x) == Glyphs.STARBASE: - return True - return False - - - @staticmethod - def print_sector(game, quadrant): - game.enterprise.condition = "GREEN" - if quadrant.klingons > 0: - game.enterprise.condition = "RED" - elif game.enterprise.energy < 300: - game.enterprise.condition = "YELLOW" - - sb = " a b c d e f g h \n" - sb += f" -=--=--=--=--=--=--=--=- Region: {quadrant.name}\n" - info = list() - info.append(f" Quadrant: [{game.quadrant_x + 1}, {game.quadrant_y + 1}\n") - info.append(f" Sector: [{game.sector_x + 1}, {game.sector_y + 1}\n") - info.append(f" Stardate: {game.star_date}\n") - info.append(f" Time remaining: {game.time_remaining}\n") - info.append(f" Condition: {game.enterprise.condition}\n") - info.append(f" Energy: {game.enterprise.energy}\n") - info.append(f" Shields: {game.enterprise.shield_level}\n") - info.append(f" Photon Torpedoes: {game.photon_torpedoes}\n") - for ss in range(8): - sb = Sectors._get_row(game, sb, ss, info[ss]) - sb += " -=--=--=--=--=--=--=--=- Docked: {game.enterprise.docked}\n" - print(sb, end='') - - if quadrant.klingons > 0: - game.display() - game.display("Condition RED: Klingon ship{0} detected.".format("" if quadrant.klingons == 1 else "s")) - if game.enterprise.shield_level == 0 and not game.enterprise.docked: - game.display("Warning: Shields are down.") - elif game.enterprise.energy < 300: - game.display() - game.display("Condition YELLOW: Low energy level.") - game.enterprise.condition = "YELLOW" - - - @staticmethod - def _get_row(game, sb, row, suffix): - sb += f" {row} |" - for column in range(8): - if game.sector[row][column] == Glyphs.SPACE: - sb += Glyphs.SPACE - elif game.sector[row][column] == Glyphs.ENTERPRISE: - sb += Glyphs.ENTERPRISE - elif game.sector[row][column] == Glyphs.KLINGON: - sb += Glyphs.KLINGON - elif game.sector[row][column] == Glyphs.STAR: - sb += Glyphs.STAR - elif game.sector[row][column] == Glyphs.STARBASE: - sb += Glyphs.STARBASE - if suffix is not None: - sb = sb + suffix - return sb - - diff --git a/Console.py b/Console.py new file mode 100644 index 0000000..6117c9e --- /dev/null +++ b/Console.py @@ -0,0 +1,49 @@ +from AbsDisplay import abs_display +from Points import Destination + +class Con(abs_display): + ''' + The best place to start is by encapsulating the default + display. Will add screen metadata for it all, later. + ''' + def __init__(self): + super().__init__(abs_display.ST_CONSOLE) + + def display(self, message = ''): + print(message) + + def read(self, prompt=''): + return input(prompt) + + def read_double(self, prompt): + text = input(prompt) + try: + value = float(text) + return value + except: + pass + return False + + def read_xypos(self, prompt = "Location (alpha,num)"): + ''' + Parse: [a-h], ypos + or + #,# + Return None on error + Example: b,4 + ''' + text = input(prompt + ': ') + return Destination.parse_xypos(text) + + def read_sector(self, prompt= "Helm: sector 1-64, speed 1.0-9.0?"): + text = input(prompt + ': ') + return Destination.parse_warp(text) + + def read_nav(self, prompt= "Helm: sector 1-64, a-h, 1-8?"): + text = input(prompt + ': ') + return Destination.parse_sector(text) + + +if __name__ == '__main__': + con = Con() + con.display("Testing!") diff --git a/Controls.py b/Controls.py index 50b9cef..32a9183 100644 --- a/Controls.py +++ b/Controls.py @@ -5,14 +5,14 @@ from AbsShip import * from Calculators import Calc from Reports import Stats +from Quips import Quips - -class control(object): +class Control(): @staticmethod def computer_controls(game): if game.enterprise.computer_damage > 0: - game.display("The main computer is damaged. Repairs are underway.") + game.display(Quips.jibe_damage('computer')) game.display() return game.print_strings(TrekStrings.computerStrings) @@ -24,7 +24,7 @@ def computer_controls(game): elif command == "tor": Calc.photon_torpedo_calculator(game) elif command == "bas": - Calc.starbase_calculator(game) + Calc.starbase_inventory(game) elif command == "nav": Calc.navigation_calculator(game) else: @@ -37,10 +37,11 @@ def computer_controls(game): @staticmethod def phaser_controls(game): if game.enterprise.phaser_damage > 0: - game.display("Phasers are damaged. Repairs are underway.") + game.display(Quips.jibe_damage("phasers")) game.display() return - if len(game.klingon_ships) == 0: + kships = game.game_map.get_area_klingons() + if len(kships) == 0: game.display("There are no Klingon ships in this quadrant.") game.display() return @@ -53,27 +54,26 @@ def phaser_controls(game): game.display() game.display("Firing phasers...") destroyed_ships = [] - for ship in game.klingon_ships: + for ss, ship in enumerate(kships): game.enterprise.energy -= int(phaser_energy) if game.enterprise.energy < 0: game.enterprise.energy = 0 break - dist = Calc.distance(game.sector_x, game.sector_y, ship.sector_x, ship.sector_y) + dist = Calc.distance(game.game_map.xpos, + game.game_map.ypos, + ship.xpos, ship.ypos) delivered_energy = phaser_energy * (1.0 - dist / 11.3) ship.shield_level -= int(delivered_energy) if ship.shield_level <= 0: - game.display("Klingon ship destroyed at sector [{0},{1}].".format(ship.sector_x + 1, ship.sector_y + 1)) + game.display(f"Enemy ship destroyed at [{ship.xpos + 1},{ship.ypos + 1}].") + game.display(Quips.jibe_defeat('enemy')) destroyed_ships.append(ship) else: - game.display("Hit ship at sector [{0},{1}]. Klingon shield strength dropped to {2}.".format( - ship.sector_x + 1, ship.sector_y + 1, ship.shield_level - )) - for ship in destroyed_ships: - game.quadrants[game.quadrant_y][game.quadrant_x].klingons -= 1 - game.klingons -= 1 - game.sector[ship.sector_y][ship.sector_x] = Glyphs.SPACE - game.klingon_ships.remove(ship) - if len(game.klingon_ships) > 0: + game.display(f"Hit ship at [{ship.xpos + 1},{ship.ypos + 1}].") + game.display(f"Enemy shield down to {ship.shield_level}.") + game.game_map.klingons -= len(destroyed_ships) + game.game_map.remove_items(destroyed_ships) + if game.game_map.klingons > 0: game.display() KlingonShip.attack(game) game.display() @@ -115,77 +115,59 @@ def shield_controls(game): def torpedo_control(game): if game.enterprise.photon_damage > 0: - game.display("Photon torpedo control is damaged. Repairs are underway.") + game.display(Quips.jibe_damage('photon launcher')) game.display() return - if game.photon_torpedoes == 0: + if game.enterprise.photon_torpedoes == 0: game.display("Photon torpedoes exhausted.") game.display() return - if len(game.klingon_ships) == 0: + if len(game.game_map.get_area_klingons()) == 0: game.display("There are no Klingon ships in this quadrant.") game.display() return - direction = game.read_double("Enter firing direction (1.0--9.0): ") - if not direction or direction < 1.0 or direction > 9.0: - game.display("Invalid direction.") + shot = game.read_xypos() + if not shot: + game.display("Invalid shot.") game.display() return game.display() game.display("Photon torpedo fired...") - game.photon_torpedoes -= 1 - angle = -(pi * (direction - 1.0) / 4.0) - if random.randint(0, 2) == 0: - angle += (1.0 - 2.0 * random.uniform(0.0, 1.0) * pi * 2.0) * 0.03 - x = game.sector_x - y = game.sector_y - vx = cos(angle) / 20 - vy = sin(angle) / 20 - last_x = last_y = -1 - # new_x = game.sector_x - # new_y = game.sector_y + game.enterprise.photon_torpedoes -= 1 hit = False - while x >= 0 and y >= 0 and round(x) < 8 and round(y) < 8: - new_x = int(round(x)) - new_y = int(round(y)) - if last_x != new_x or last_y != new_y: - game.display(" [{0},{1}]".format(new_x + 1, new_y + 1)) - last_x = new_x - last_y = new_y - for ship in game.klingon_ships: - if ship.sector_x == new_x and ship.sector_y == new_y: - game.display("Klingon ship destroyed at sector [{0},{1}].".format(ship.sector_x + 1, ship.sector_y + 1)) - game.sector[ship.sector_y][ship.sector_x] = Glyphs.SPACE - game.klingons -= 1 - game.klingon_ships.remove(ship) - game.quadrants[game.quadrant_y][game.quadrant_x].klingons -= 1 + for ship in game.game_map.get_area_objects(): + if game.is_testing: + print(f'{ship.glyph}({ship.xpos},{ship.ypos}), shot({shot.xpos},{shot.ypos})') + if ship.xpos == shot.xpos and ship.ypos == shot.ypos: + if ship.glyph == Glyphs.KLINGON: + num = game.game_map.game_id(ship) + game.display(f"Klingon ship #{num} destroyed.") + game.display(Quips.jibe_defeat('enemy')) + game.game_map.klingons -= 1 + game.game_map.remove_items([ship]) hit = True - break # break out of the for loop - if hit: - break # break out of the while loop - if game.sector[new_y][new_x] == Glyphs.STARBASE: - game.starbases -= 1 - game.quadrants[game.quadrant_y][game.quadrant_x].starbase = False - game.sector[new_y][new_x] = Glyphs.SPACE - game.display("The Enterprise destroyed a Federation starbase at sector [{0},{1}]!".format(new_x + 1, new_y + 1)) - hit = True - break - elif game.sector[new_y][new_x] == Glyphs.STAR: - game.display("The torpedo was captured by a star's gravitational field at sector [{0},{1}].".format( - new_x + 1, new_y + 1 - )) - hit = True - break - x += vx - y += vy + break + elif ship.glyph == Glyphs.STARBASE: + game.game_map.starbases -= 1 + num = game.game_map.game_id(ship) + game.display("Federation Starbase #{num} destroyed!") + game.display(Quips.jibe_defeat('commander')) + game.game_map.remove_items([ship]) + hit = True + break + elif ship.glyph == Glyphs.STAR: + num = game.game_map.game_id(ship) + game.display(f"Torpedo vaporizes star #{num}!") + game.display(Quips.jibe_defeat('scientist')) + game.game_map.remove_items([ship]) + hit = True + break if not hit: - game.display("Photon torpedo failed to hit anything.") - if len(game.klingon_ships) > 0: + game.display("Torpedo missed.") + if len(game.game_map.get_area_klingons()) > 0: game.display() KlingonShip.attack(game) game.display() - - diff --git a/Glyphs.py b/Glyphs.py index 5d2fe94..ef41a81 100644 --- a/Glyphs.py +++ b/Glyphs.py @@ -3,3 +3,5 @@ STARBASE = ">S<" ENTERPRISE = "" KLINGON = "+K+" + +GLYPHS = SPACE, STARBASE, KLINGON, ENTERPRISE diff --git a/MapGame.py b/MapGame.py new file mode 100644 index 0000000..0cd807b --- /dev/null +++ b/MapGame.py @@ -0,0 +1,237 @@ +import random +import TrekStrings + +import Glyphs +from AbsShip import KlingonShip +from Points import Destination +from Quadrant import Quadrant +from Sectors import Sectors + +import MapSparse + +class GameMap(MapSparse.SparseMap): + + def __init__(self): + super().__init__() + self.sector = -1 + self.major_x = self.major_y = -1 + self.xpos = self.ypos = -1 + self.stars = -1 + self.klingons = -1 + self.starbases = -1 + self.last_nav = None + + def place(self, takers): + ''' + Randomly place game-objects, into the map. + ''' + if not sum(takers): + return None + takers =list(takers) + for which, nelem in enumerate(takers): + if not nelem: + continue + to_take = random.randrange(0, nelem) + if nelem is 1: + to_take = 1 + if not to_take: + continue + taken = 0 + while taken != to_take: + for ss, area in enumerate(self.areas()): + should_take = random.randrange(1, 8) + if should_take % (ss + 2) == 0: + if which is 0: + area.place_glyph(Glyphs.STARBASE) + elif which is 1: + area.place_glyph(Glyphs.STAR) + elif which is 2: + area.place_glyph(Glyphs.KLINGON) + taken += 1 + if taken == to_take: + break; + takers[which] -= taken + return tuple(takers) + + def enterprise_in(self, glyph, dest=None): + ''' Place the ENTERPRISE at the destination, else a + random one. Return the x, y location - else False ''' + area = self.area() + if area: + pos = area.place_glyph(Glyphs.ENTERPRISE, dest) + if pos: + return pos + return False + + def enterprise_location(self): + ''' Get Enterprise location. False if not found. ''' + area = self.area() + if area: + for obj in area.objs: + if obj.glyph == Glyphs.ENTERPRISE: + return obj.xpos, obj.ypos + return False + + def enterprise_out(self): + ''' Remove the ENTERPRISE from the present AREA ''' + pos = self.enterprise_location() + if pos: + self.remove(*pos) + + def place_glyph(self, glyph, dest=None): + ''' Place the glyph as the destination, else a random one ''' + area = self.area() + if area: + pos = area.place_glyph(self, glyph, dest) + if pos: + return True + return False + + def remove(self, xpos, ypos): + ''' Remove ANYTHING from the present AREA ''' + area = self.area() + if area: + area.remove(xpos, ypos) + + def area(self): + ''' + Return the internal / sparsely populated AREA object. + Return an empty / default AREA upon coordinate error. + ''' + if self.sector > 0: + for area in self.areas(): + if area.number == self.sector: + return area + return MapSparse.SparseMap.Area() + + def scan_quad(self, sector): + ''' + Return a scan (LRS?) for a specific quadrant. + Return empty quadrant, on error. + ''' + if sector > 0 and sector < 65: + for area in self.areas(): + if area.number == self.sector: + return Quadrant.from_area(area) + return Quadrant() + + def _count(self, glyph): + ''' Tally the number of glyphs in the AREA ''' + count = 0 + area = self.area() + if area: + for obj in area.objs: + if obj.glyph == glyph: + count += 1 + return count + + def remove_items(self, destroyed_ships): + area = self.area() + for obj in destroyed_ships: + area.remove(obj.xpos, obj.ypos) + + def get_area_klingons(self): + ''' + Return this Area's data for Kingons, in an array. + ''' + results = [] + area = self.area() + for data in area.get_data(Glyphs.KLINGON): + ship = KlingonShip() + ship.from_map(data.xpos, data.ypos) + results.append(ship) + return results + + def num_area_klingons(self): + return self._count(Glyphs.KLINGON) + + def num_area_starbases(self): + return self._count(Glyphs.STARBASE) + + def num_area_stars(self): + return self._count(Glyphs.STAR) + + def get_area_objects(self): + ''' + Return the actual objects, as located in the Area. + NOTE: Changes to this collection will update Area + content. + ''' + area = self.area() + return area.objs + + def game_id(self, piece): + ''' + Uniquely identify a game piece / object. + ''' + area = self.area() + num = (area.number * 100) + (piece.ypos * 8) + piece.xpos + return f"{piece.glyph[0]}x{num}" + + def get_all(self, glyph): + ''' + Return [ [AREA, PIECE], ... ] for every glyph found. + ''' + results = [] + for area in self.areas(): + for piece in area.get_data(glyph): + results.append([area, piece]) + return results + + def quad(self): + area = self.area() + return Quadrant.from_area(area) + + def get_map(self): + ''' + Generate AREA map of the present sector. + ''' + area = self.area() + return area.get_map() + + def random_jump(self): + dest = Destination( + random.randint(1, 65), + random.randint(0, 7), + random.randint(0, 7) + ) + self.go_to(dest) + + def go_to(self, dest): + if self.last_nav: + self.enterprise_out() + assert(isinstance(self.sector, int)) + self.sector = dest.sector + if self.sector > 0: + fop = (self.sector + 8) / 8 + self.major_x = int(fop) - 1 # ZERO BASED REGIONS + if not fop.is_integer(): + self.major_y = \ + ((fop - float(self.major_x)) * 10) - 1 # ZBR + else: + self.major_x = -1 + self.major_y = -1 + + self.xpos = dest.xpos + self.ypos = dest.ypos + self.enterprise_in(dest) + self.last_nav = dest + + def randomize(self, bases=None, stars=None, aliens=None): + if not aliens: + aliens = 15 + random.randint(0, 5) + if not bases: + bases = 2 + random.randint(0, 2) + self.starbases = bases + self.klingons = aliens + self.stars = stars + self.init() + takers = bases, stars, aliens + while takers: + for lrs in self.map: + takers = self.place(takers) + if not takers: + break + + + diff --git a/MapSparse.py b/MapSparse.py new file mode 100644 index 0000000..99d04bb --- /dev/null +++ b/MapSparse.py @@ -0,0 +1,203 @@ +import random +import TrekStrings +import Glyphs + +class SparseMap: + ''' + Minimalist mapping. On-demand Area epansion to full-Area views. + ''' + + class Region(): + ''' + Regional meta for a collection of Area maps. + ''' + def __init__(self): + self.name = "" + + class Area(): + ''' + A minimalist collection of Area-plotted Glyphs. + Area numbers are 1's based. + Area plotting is 0's based. + Names are Trekian. + ''' + class Piece: + ''' + Sparse data management for an increasingly minimalist world. + ''' + def __init__(self, xpos, ypos, glyph=Glyphs.SPACE): + self.xpos = xpos + self.ypos = ypos + self.glyph = glyph + + def __init__(self): + ''' + Create an empty AREA. + ''' + self.name = "" + self.number = -1 + self.scanned = False + self.objs = [] + + def is_null(self): + ''' + See if this AREA has anything important. + ''' + dum = Area() + return dum.name == self.name and \ + dum.number == self.number and \ + dum.scanned == self.scanned and \ + len(dum.objs) == len(self.objs) + + def is_empty(self): + ''' Checks to see if the Area has anything ...''' + return len(self.objs) == True + + def items(self): + ''' Items in the Area ...''' + return len(self.objs) + + def remove(self, xpos, ypos): + ''' Remove an item from the Area. ''' + for ss, obj in enumerate(self.objs): + if obj.xpos == xpos and obj.ypos == ypos: + self.objs.remove(obj) + return + + def get_map(self): + ''' + Generate a map of this sector. Map is full + of Glyphs.SPACE on error. + ''' + results = [[Glyphs.SPACE for _ in range(8)] for _ in range(8)] + for obj in self.objs: + results[obj.ypos][obj.xpos] = obj.glyph # ASSURED + return results + + def __str__(self): + result = '' + for line in get_map(): + result += ''.join(line) + result += '\n' + return result + + def range_ok(self, xpos, ypos): + ''' Verify that coordinates are plottable. ''' + if xpos < 0 or ypos < 0 or \ + xpos > 7 or ypos > 7: + return False + return True + + def get_data(self, glyph): + results = [] + for p in self.objs: + if p.glyph == glyph: + results.append(SparseMap.Area.clone(p)) + return results + + def count_glyphs(self, glyph): + ''' + Tally the number of glyphs that we have in the Area. + ''' + count = 0 + for p in self.objs: + if p.glyph == glyph: + count += 1 + return count + + def plot_glyph(self, xpos, ypos, glyph): + ''' + Sync (update or add) a glyph to the sparse array. + Return coordinate occupied, else None on error. + ''' + if self.range_ok(xpos, ypos) is False: + return None + for p in self.objs: + if p.xpos is xpos and p.ypos is ypos: + p.glyph = glyph + return xpos, ypos + self.objs.append(SparseMap.Area.Piece(xpos, ypos, glyph)) + return xpos, ypos + + def place_glyph(self, glyph, dest=None): + ''' Place / randomly place a glyph into the Map. ''' + area = self.get_map() + if not dest: + while True: + xpos = random.randrange(0,7) + ypos = random.randrange(0,7) + if area[xpos][ypos] == Glyphs.SPACE: + self.plot_glyph(xpos, ypos, glyph) + return xpos, ypos + else: + self.plot_glyph(xpos, ypos, glyph) + return dest.xpos, dest.ypos + + @staticmethod + def clone(piece): + ''' Copy a piece. ''' + ''' Copy a piece. ''' + return SparseMap.Area.Piece(piece.xpos, piece.ypos, piece.glyph) + + def __init__(self): + self.initalized = False + self.map = [[[y,x] for y in range(8)] for x in range(8)] + + def init(self, reset=False): + if not reset and self.initalized: + return + for xx, row in enumerate(self.map): + lrs = SparseMap.Region() + for yy, col in enumerate(row): + self.map[xx][yy] = [lrs, SparseMap.Area()] + self.name_areas() + self.initalized = True + + def data(self): + ''' Enumerate thru every [Region, Area] in the Map ''' + for row in self.map: + for col in row: + yield col + + def areas(self): + ''' Enumerare thru every Area on the Map ''' + for row in self.map: + for col in row: + yield col[1] + + def name_areas(self): + names = list(TrekStrings.quadrantNames) + for num, area in enumerate(self.areas(),1): + index = random.randint(0, len(names) - 1) + area.name = names[index] + area.number = num + del names[index] + + def get_sector_names(self): + results = [] + temp = [] + for ss, col in enumerate(self.areas(),1): + temp.append([col.number,col.name]) + if ss % 8 == 0: + results.append(temp) + temp = [] + results.append(temp) + return results + + def plot(self, ones_based, xpos, ypos, glyph): + ''' + Add an item to a MAP using the 1's based AREA identifier. + Coordinates here are ZERO based. + ''' + for area in self.areas(): + if area.number == ones_based: + area.plot_glyph(xpos, ypos, glyph) + return True + return False + + def plot_ones_based(self, ones_based, xpos, ypos, glyph): + ''' + Add an item to a MAP using the 1's based AREA identifier. + Coordinates here are ONES based. + ''' + return self.plot(ones_based, xpos -1, ypos -1, glyph) \ No newline at end of file diff --git a/Points.py b/Points.py new file mode 100644 index 0000000..3ec4eaa --- /dev/null +++ b/Points.py @@ -0,0 +1,83 @@ + + +class Destination(): + ''' Zero based, Map navigation ''' + def __init__(self, sector=-1, xpos=-1, ypos=-1, warp=0): + self.warp = warp + self.sector = sector + self.xpos = xpos + self.ypos = ypos + + @staticmethod + def parse_sector(dest, sep=','): + ''' + Parse: sector#, alpha-col, row-num + Example: 5,b,1 + ''' + dest = str(dest) + cols = dest.split(sep) + if len(cols) == 3: + try: + sector = int(cols[0]) % 8 + if str(cols[1]).isalpha(): + xpos = ((ord(cols[1]) - ord('a')) % 8) + ypos = int(cols[2]) % 8 + return Destination(sector, xpos, ypos) + except: + pass + return None + + @staticmethod + def parse_xypos(dest, sep=','): + ''' + WARNING: USER 1's -> 0-BASED TRANSLATION HERE + + Parse: [a-h], ypos + or + #,# + Return None on error + Example: b,5 + ''' + dest = str(dest) + cols = dest.split(sep) + if len(cols) == 2: + try: + alph = cols[0].strip().lower()[0] + num = 0 + if alph.isalpha(): + num = ord(alph) - 96 # 'a' == 1 + else: + num = int(alph) + xpos = num + ypos = int(cols[1].strip()[0]) + return Destination(-1, xpos-1, ypos-1, -1) + except: + pass + return None + + @staticmethod + def parse_warp(dest, sep=','): + ''' + Parse: sector-num, speed-float - None on error + Example: 5,1.1 + ''' + dest = str(dest) + cols = dest.split(sep) + if len(cols) == 2: + try: + sector = int(cols[0].strip()) + if sector < 1: + sector = 1 + speed = float(cols[1].strip()) + if speed < 0: speed = 0.1 + if speed > 9: speed = 9.0 + return Destination(sector, -1, -1, speed) + except: + pass + return None + + + + + + diff --git a/Quadrant.py b/Quadrant.py new file mode 100644 index 0000000..b1fadb2 --- /dev/null +++ b/Quadrant.py @@ -0,0 +1,28 @@ +import Glyphs + +class Quadrant(): + def __init__(self, num=-1, name='', lines=[], + aliens=-1, stars=-1, starbases=-1): + self.name = name + self.number = num + self.lines = lines + self.klingons = aliens + self.stars = stars + self.starbases = starbases + self.scanned = True # meh + + def is_null(self): + return self.num == -1 + + @staticmethod + def from_area(area): + if not area: + return Quadrant() + name = area.name + num = area.number + map = area.get_map() + return Quadrant(num, name, map, + area.get_data(Glyphs.KLINGON), + area.count_glyphs(Glyphs.STAR), + area.count_glyphs(Glyphs.STARBASE)) + diff --git a/Quips.py b/Quips.py new file mode 100644 index 0000000..5884b27 --- /dev/null +++ b/Quips.py @@ -0,0 +1,67 @@ +import random + +DAMAGE_PREFIX = [ + "The main ", + "That @#$#@& ", + "Our cheap ", + "Darnit captian, that ", + "Yikes, the ", + ] +DAMAGE_SUFFIX = [ + " has died. We're on it!", + " is out. We're working on it!", + " is almost repaired!", + " is dead.", + " is fried. I'm working as fast as I can!", + " is being replaced.", + " is dead. Please leave a message.", + ] +DEFEAT_PREFIX = [ + "A defeated ", + "The vengefull ", + "An angry ", + "The ejecting ", + "A rescued ", + "Another ", + "Yet another ", + ] +DEFEAT_SUFFIX = [ + " says: I'll be back!", + " cries: ... a lucky shot!", + " sighs bitterly.", + " dies.", + " crew is rescued.", + " crew is spaced.", + " crew is recycled.", + " crew is recovered.", + " yells: Thy mother mates poorly!", + " snarls: Lucky shot.", + " laughs: You'll not do THAT again!", + " says nothing.", + " screams: Thy father was a Targ!", + ] + +class Quips(): + + @staticmethod + def jibe(noun, prefix, suffix): + prand = random.randrange(0, len(prefix) - 1) + srand = random.randrange(0, len(suffix) - 1) + return prefix[prand] + noun + suffix[srand] + + @staticmethod + def jibe_damage(noun): + if random.randrange(0, 100) > 25: + return f"{noun.capitalize()} damaged. Repairs are underway." + return Quips.jibe(noun, DAMAGE_PREFIX, DAMAGE_SUFFIX) + + @staticmethod + def jibe_defeat(noun): + if random.randrange(0, 100) > 25: + return f"Another {noun.lower()} defeated." + return Quips.jibe(noun, DEFEAT_PREFIX, DEFEAT_SUFFIX) + + + + + diff --git a/Reports.py b/Reports.py index 1ff7249..fa88b00 100644 --- a/Reports.py +++ b/Reports.py @@ -1,62 +1,55 @@ +import Glyphs -class Stats(object): +class Stats(): @staticmethod def display_status(game): game.display() - game.display(" Time Remaining: {0}".format(game.time_remaining)) - game.display(" Klingon Ships Remaining: {0}".format(game.klingons)) - game.display(" Starbases: {0}".format(game.starbases)) - game.display(" Warp Engine Damage: {0}".format(game.enterprise.navigation_damage)) - game.display(" Short Range Scanner Damage: {0}".format(game.enterprise.short_range_scan_damage)) - game.display(" Long Range Scanner Damage: {0}".format(game.enterprise.long_range_scan_damage)) - game.display(" Shield Controls Damage: {0}".format(game.enterprise.shield_control_damage)) - game.display(" Main Computer Damage: {0}".format(game.enterprise.computer_damage)) - game.display("Photon Torpedo Control Damage: {0}".format(game.enterprise.photon_damage)) - game.display(" Phaser Damage: {0}".format(game.enterprise.phaser_damage)) + game.display(f" Time Remaining: {game.time_remaining}") + game.display(f" Klingon Ships Remaining: {game.game_map.klingons}") + game.display(f" Starbases: {game.game_map.starbases}") + game.display(f" Warp Engine Damage: {game.enterprise.navigation_damage}") + game.display(f" Short Range Scanner Damage: {game.enterprise.short_range_scan_damage}") + game.display(f" Long Range Scanner Damage: {game.enterprise.long_range_scan_damage}") + game.display(f" Shield Controls Damage: {game.enterprise.shield_control_damage}") + game.display(f" Main Computer Damage: {game.enterprise.computer_damage}") + game.display(f"Photon Torpedo Control Damage: {game.enterprise.photon_damage}") + game.display(f" Phaser Damage: {game.enterprise.phaser_damage}") game.display() @staticmethod def display_galactic_record(game): game.display() - sb = "" game.display("-------------------------------------------------") - for i in range(8): - for j in range(8): - sb += "| " - klingon_count = 0 - starbase_count = 0 - star_count = 0 - quadrant = game.quadrants[i][j] - if quadrant.scanned: - klingon_count = quadrant.klingons - starbase_count = 1 if quadrant.starbase else 0 - star_count = quadrant.stars - sb = sb + \ - "{0}{1}{2} ".format(klingon_count, starbase_count, star_count) - sb += "|" - game.display(sb) - sb = "" - game.display("-------------------------------------------------") + game.display( + f"{Glyphs.KLINGON}{game.game_map.klingons}|" + + f"{Glyphs.STARBASE}|{game.game_map.starbases}|" + + f"{Glyphs.STAR}{game.game_map.stars}") + game.display("-------------------------------------------------") game.display() @staticmethod def print_game_status(game): if game.destroyed: - game.display("MISSION FAILED: ENTERPRISE DESTROYED!!!") - game.display('\n'*2) + msg = "MISSION FAILED: ENTERPRISE DESTROYED!!!" + game.display('!' * len(msg)) + game.display(msg) + game.display('!' * len(msg)) elif game.enterprise.energy == 0: - game.display("MISSION FAILED: ENTERPRISE RAN OUT OF ENERGY.") - game.display('\n'*2) - elif game.klingons == 0: - game.display("MISSION ACCOMPLISHED: ALL KLINGON SHIPS DESTROYED. WELL DONE!!!") - game.display('\n'*2) + msg = "MISSION FAILED: ENTERPRISE RAN OUT OF ENERGY." + game.display('!' * len(msg)) + game.display(msg) + game.display('!' * len(msg)) + elif game.game_map.klingons == 0: + msg = "MISSION ACCOMPLISHED: ALL ENEMY SHIPS DESTROYED. WELL DONE!!!" + game.display('!' * len(msg)) + game.display(msg) + game.display('!' * len(msg)) elif game.time_remaining == 0: - game.display("MISSION FAILED: ENTERPRISE RAN OUT OF TIME.") - game.display('\n'*2) - - - + msg = "MISSION FAILED: ENTERPRISE RAN OUT OF TIME." + game.display('!' * len(msg)) + game.display(msg) + game.display('!' * len(msg)) diff --git a/Sectors.py b/Sectors.py new file mode 100644 index 0000000..227aab6 --- /dev/null +++ b/Sectors.py @@ -0,0 +1,43 @@ + +class Sectors(): + + @staticmethod + def print_sector(game, quad): + game.enterprise.condition = "GREEN" + if game.game_map.num_area_klingons() > 0: + game.enterprise.condition = "RED" + elif game.enterprise.energy < 300: + game.enterprise.condition = "YELLOW" + + sb = " a b c d e f g h \n" + sb += f" -=--=--=--=--=--=--=--=- Region: {quad.name}\n" + info = list() + info.append(f" Sector: [{quad.number}]\n") + info.append(f" Hazzards: [{quad.stars + len(quad.klingons)}]\n") + info.append(f" Stardate: {game.star_date}\n") + info.append(f" Condition: {game.enterprise.condition}\n") + info.append(f" Energy: {game.enterprise.energy}\n") + info.append(f" Shields: {game.enterprise.shield_level}\n") + info.append(f" Photon Torpedoes: {game.enterprise.photon_torpedoes}\n") + info.append(f" Time remaining: {game.time_remaining}\n") + for row, line in enumerate(quad.lines): + sb += f" {row+1} |" + for col in line: + sb += col + sb += info[row] + sb += f" -=--=--=--=--=--=--=--=- Docked: {game.enterprise.docked}\n" + print(sb, end='') + + if len(quad.klingons) > 0: + game.display() + game.display("Condition RED: Klingon ship{0} detected.".format("" if quad.klingons == 1 else "s")) + if game.enterprise.shield_level == 0 and not game.enterprise.docked: + game.display("Warning: Shields are down.") + elif game.enterprise.energy < 300: + game.display() + game.display("Condition YELLOW: Low energy level.") + game.enterprise.condition = "YELLOW" + + + + diff --git a/StarTrek2020.py b/StarTrek2020.py index b3a9eef..7aee2af 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -3,45 +3,43 @@ import TrekStrings -from AbsDisplay import Con +from Console import Con from Calculators import Calc -from Controls import control +from Controls import Control from Reports import Stats from AbsShip import * -from Charts import * +from MapGame import * +from Points import Destination class Game(Con): def __init__(self): + self.is_testing = False + self.game_map = GameMap() self.enterprise = Enterprise() self.star_date = 0 self.time_remaining = 0 - self.klingons = 0 - self.starbases = 0 - self.quadrant_x, self.quadrant_y = 0, 0 - self.sector_x, self.sector_y = 0, 0 - self.photon_torpedoes = 0 self.destroyed = False - self.starbase_x, self.starbase_y = 0, 0 - self.quadrants = [[Quadrant() for _ in range(8)] for _ in range(8)] - self.sector = [[SectorType() for _ in range(8)] for _ in range(8)] - self.klingon_ships = [] - def run(self): self.print_strings(TrekStrings.titleStrings) - Sectors.initialize_game(game) + game.star_date = random.randint(0, 50) + 2250 + game.time_remaining = 40 + random.randint(0, 9) + game.destroyed = False + stars = random.randrange(32, 64) + aliens = random.randrange(12, 16) + starbases = random.randrange(6, 8) + game.game_map.randomize(starbases, stars, aliens) self.print_mission() - Sectors.generate_sector(game) + self.print_strings(TrekStrings.commandStrings) while self.enterprise.energy > 0 and not \ - self.destroyed and self.klingons > 0 and \ + self.destroyed and self.game_map.klingons > 0 and \ self.time_remaining > 0: self.command_prompt() Stats.print_game_status(game) - def command_prompt(self): command = self.read("Enter command: ").strip().lower() self.display() @@ -52,25 +50,30 @@ def command_prompt(self): elif command == "lrs": game.enterprise.long_range_scan(game) elif command == "pha": - control.phaser_controls(game) + Control.phaser_controls(game) elif command == "tor": - control.torpedo_control(game) + Control.torpedo_control(game) elif command == "she": - control.shield_controls(game) + Control.shield_controls(game) elif command == "com": - control.computer_controls(game) + Control.computer_controls(game) elif command.startswith('qui') or command.startswith('exi'): exit() else: self.print_strings(TrekStrings.commandStrings) - def print_mission(self): self.display("Mission: Destroy {0} Klingon ships in {1} stardates with {2} starbases.".format( - self.klingons, self.time_remaining, self.starbases)) + self.game_map.klingons, self.time_remaining, self.game_map.starbases)) self.display() if __name__ == '__main__': + import traceback game = Game() - game.run() + try: + game.run() + except Exception as ex: + print(ex) + # Stack trace: + traceback.print_exc() diff --git a/TrekStrings.py b/TrekStrings.py index 5781948..7df4378 100644 --- a/TrekStrings.py +++ b/TrekStrings.py @@ -112,7 +112,7 @@ "--- Main Computer --------------", "rec = Cumulative Galatic Record", "sta = Status Report", - "tor = Photon Torpedo Calculator", - "bas = Starbase Calculator", + "tor = Photon Torpedo Targets", + "bas = Starbase Locations", "nav = Navigation Calculator", ] \ No newline at end of file diff --git a/test_MapSparse.py b/test_MapSparse.py new file mode 100644 index 0000000..9f48c5c --- /dev/null +++ b/test_MapSparse.py @@ -0,0 +1,50 @@ +import random +import MapGame +import Glyphs +from MapSparse import SparseMap + +def fill_map(): + map = SparseMap() + map.init() + for sector in range(1, 65): + for xpos in range(8): + for ypos in range(8): + assert(map.plot(sector,xpos,ypos,Glyphs.ENTERPRISE)) + return map + +def define_map(): + map = SparseMap() + map.init() + for ypos, area in enumerate(range(8)): + for xpos, area in enumerate(range(8)): + which = random.randrange(0, 14) + glyph = Glyphs.SPACE + if which < 0: + pass + elif which < 8: + glyph = Glyphs.STAR + elif which < 13: + glyph = Glyphs.STARBASE + else: + glyph = Glyphs.KLINGON + + map.plot(area, + random.randrange(0, 7), + random.randrange(0, 7), + glyph) + return map + +if __name__ == '__main__': + map = fill_map() + for sect, area in enumerate(map.areas(),1): + assert(area.number == sect) + + for sector in map.areas(): + for line in sector.get_map(): + print(line, end='') + print() + + + + + From abb2c57d2d1d677b9f0a905288100bce94a70306 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Wed, 23 Dec 2020 03:04:04 -0500 Subject: [PATCH 015/100] WORK IN-PROGRESS. Fixing LRS and MAP DISTRIBUTIONS. --- .gitignore | 2 +- AbsDisplay.py | 2 +- AbsShip.py | 2 +- Calculators.py | 66 +---------------------------- Controls.py | 20 ++++----- MapSparse.py | 2 +- Quadrant.py | 39 +++++++++++++++++ Quips.py | 25 ++++++++--- Reports.py | 6 +-- Sectors.py | 43 ------------------- StarTrek2020.py | 16 +++---- TrekStrings.py | 9 ++-- __pycache__/Sectors.cpython-37.pyc | Bin 0 -> 1745 bytes 13 files changed, 87 insertions(+), 145 deletions(-) delete mode 100644 Sectors.py create mode 100644 __pycache__/Sectors.cpython-37.pyc diff --git a/.gitignore b/.gitignore index 0aaa764..82559a5 100644 --- a/.gitignore +++ b/.gitignore @@ -24,7 +24,7 @@ /__pycache__/Charts.cpython-37.pyc /.vs/PythonSettings.json /__pycache__/Calculators.cpython-37.pyc.2654468500952 -/__pycache__/Sectors.cpython-37.pyc +/__pycache__/Quadrant.cpython-37.pyc /__pycache__/Quips.cpython-37.pyc /__pycache__/Quadrant.cpython-37.pyc /__pycache__/Points.cpython-37.pyc diff --git a/AbsDisplay.py b/AbsDisplay.py index ac6c8ee..030c2b8 100644 --- a/AbsDisplay.py +++ b/AbsDisplay.py @@ -27,7 +27,7 @@ def display(self, message): pass - def print_strings(self, string_list): + def show_strings(self, string_list): for string in string_list: self.display(string) self.display() diff --git a/AbsShip.py b/AbsShip.py index f92e2f6..64470d6 100644 --- a/AbsShip.py +++ b/AbsShip.py @@ -149,7 +149,7 @@ def short_range_scan(self, game): game.display() else: quad = game.game_map.quad() - Sectors.print_sector(game, quad) + Quadrant.display_area(game, quad) game.display() diff --git a/Calculators.py b/Calculators.py index c897bbf..9e39f52 100644 --- a/Calculators.py +++ b/Calculators.py @@ -60,69 +60,7 @@ def navigation(game): @staticmethod - def compute_direction(x1, y1, x2, y2): - if x1 == x2: - if y1 < y2: - direction = 7 - else: - direction = 3 - elif y1 == y2: - if x1 < x2: - direction = 1 - else: - direction = 5 - else: - dy = abs(y2 - y1) - dx = abs(x2 - x1) - angle = atan2(dy, dx) - if x1 < x2: - if y1 < y2: - direction = 9.0 - 4.0 * angle / pi - else: - direction = 1.0 + 4.0 * angle / pi - else: - if y1 < y2: - direction = 5.0 + 4.0 * angle / pi - else: - direction = 5.0 - 4.0 * angle / pi - return direction - - - @staticmethod - def navigation_calculator(game): - game.display() - game.display("Enterprise located in quadrant [%s,%s]." % \ - (game.game_map.major_x + 1, game.game_map.major_y + 1)) - game.display() - quad_x = game.read_double("Enter destination quadrant X (1--8): ") - if quad_x is False or quad_x < 1 or quad_x > 8: - game.display("Invalid X coordinate.") - game.display() - return - quad_y = game.read_double("Enter destination quadrant Y (1--8): ") - if quad_y is False or quad_y < 1 or quad_y > 8: - game.display("Invalid Y coordinate.") - game.display() - return - game.display() - qx = int(quad_x) - 1 - qy = int(quad_y) - 1 - if qx == game.game_map.major_x and qy == game.game_map.major_y: - game.display("That is the current location of the Enterprise.") - game.display() - return - direction = Calc.compute_direction( - game.game_map.major_x, - game.game_map.major_y, - qx, qy) - game.display("Direction: {0:1.2f}".format(direction)) - game.display("Distance: {0:2.2f}".format( - Calc.distance(game.game_map.major_x, game.game_map.major_y, qx, qy))) - game.display() - - - @staticmethod - def starbase_inventory(game): + def show_starbase(game): game.display() bases = game.game_map.get_all(Glyphs.STARBASE) game.display() @@ -137,7 +75,7 @@ def starbase_inventory(game): @staticmethod - def photon_torpedo_calculator(game): + def show_torp_targets(game): game.display() kships = game.game_map.get_area_klingons() if len(kships) == 0: diff --git a/Controls.py b/Controls.py index 32a9183..cbca095 100644 --- a/Controls.py +++ b/Controls.py @@ -10,23 +10,21 @@ class Control(): @staticmethod - def computer_controls(game): + def computer(game): if game.enterprise.computer_damage > 0: game.display(Quips.jibe_damage('computer')) game.display() return - game.print_strings(TrekStrings.computerStrings) + game.show_strings(TrekStrings.CPU_CMDS) command = game.read("Enter computer command: ").strip().lower() if command == "rec": - Stats.display_galactic_record(game) + Stats.show_galactic_status(game) elif command == "sta": - Stats.display_status(game) + Stats.show_ship_status(game) elif command == "tor": - Calc.photon_torpedo_calculator(game) + Calc.show_torp_targets(game) elif command == "bas": - Calc.starbase_inventory(game) - elif command == "nav": - Calc.navigation_calculator(game) + Calc.show_starbase(game) else: game.display() game.display("Invalid computer command.") @@ -35,7 +33,7 @@ def computer_controls(game): @staticmethod - def phaser_controls(game): + def phasers(game): if game.enterprise.phaser_damage > 0: game.display(Quips.jibe_damage("phasers")) game.display() @@ -79,7 +77,7 @@ def phaser_controls(game): game.display() - def shield_controls(game): + def shields(game): game.display("--- Shield Controls ----------------") game.display("add = Add energy to shields.") game.display("sub = Subtract energy from shields.") @@ -113,7 +111,7 @@ def shield_controls(game): game.display() - def torpedo_control(game): + def torpedos(game): if game.enterprise.photon_damage > 0: game.display(Quips.jibe_damage('photon launcher')) game.display() diff --git a/MapSparse.py b/MapSparse.py index 99d04bb..640727f 100644 --- a/MapSparse.py +++ b/MapSparse.py @@ -166,7 +166,7 @@ def areas(self): yield col[1] def name_areas(self): - names = list(TrekStrings.quadrantNames) + names = list(TrekStrings.AREA_NAMES) for num, area in enumerate(self.areas(),1): index = random.randint(0, len(names) - 1) area.name = names[index] diff --git a/Quadrant.py b/Quadrant.py index b1fadb2..22a402c 100644 --- a/Quadrant.py +++ b/Quadrant.py @@ -26,3 +26,42 @@ def from_area(area): area.count_glyphs(Glyphs.STAR), area.count_glyphs(Glyphs.STARBASE)) + + @staticmethod + def display_area(game, quad): + game.enterprise.condition = "GREEN" + if game.game_map.num_area_klingons() > 0: + game.enterprise.condition = "RED" + elif game.enterprise.energy < 300: + game.enterprise.condition = "YELLOW" + + sb = " a b c d e f g h \n" + sb += f" -=--=--=--=--=--=--=--=- Region: {quad.name}\n" + info = list() + info.append(f" Area: [{quad.number}]\n") + info.append(f" Hazzards: [{quad.stars + len(quad.klingons)}]\n") + info.append(f" Stardate: {game.star_date}\n") + info.append(f" Condition: {game.enterprise.condition}\n") + info.append(f" Energy: {game.enterprise.energy}\n") + info.append(f" Shields: {game.enterprise.shield_level}\n") + info.append(f" Photon Torpedoes: {game.enterprise.photon_torpedoes}\n") + info.append(f" Time remaining: {game.time_remaining}\n") + for row, line in enumerate(quad.lines): + sb += f" {row+1} |" + for col in line: + sb += col + sb += info[row] + sb += f" -=--=--=--=--=--=--=--=- Docked: {game.enterprise.docked}\n" + print(sb, end='') + + if len(quad.klingons) > 0: + game.display() + game.display("Condition RED: Klingon ship{0} detected.".format("" if quad.klingons == 1 else "s")) + if game.enterprise.shield_level == 0 and not game.enterprise.docked: + game.display("Warning: Shields are down.") + elif game.enterprise.energy < 300: + game.display() + game.display("Condition YELLOW: Low energy level.") + game.enterprise.condition = "YELLOW" + + diff --git a/Quips.py b/Quips.py index 5884b27..c8cb2ac 100644 --- a/Quips.py +++ b/Quips.py @@ -21,24 +21,35 @@ "The vengefull ", "An angry ", "The ejecting ", - "A rescued ", + "A confused ", "Another ", "Yet another ", ] DEFEAT_SUFFIX = [ - " says: I'll be back!", - " cries: ... a lucky shot!", + " says: `I'll be back!`", + " cries: ... 'a lucky shot!'", " sighs bitterly.", " dies.", + " is rescued.", + " is history.", + " is no more.", + " is recycled.", + " is eliminated.", + " ejects.", " crew is rescued.", " crew is spaced.", " crew is recycled.", " crew is recovered.", - " yells: Thy mother mates poorly!", - " snarls: Lucky shot.", - " laughs: You'll not do THAT again!", + " yells: 'Thy mother mates poorly!'", + " snarls: 'Lucky shot.'", + " laughs: 'You'll not do THAT again!'", " says nothing.", - " screams: Thy father was a Targ!", + " screams: 'Thy father is a Targ!'", + " yells: 'Your parents eat bats!'", + " snarls: 'Thy people eat vermin!'", + " yells: 'May you create social diseases!'", + " curses: 'Thy fathers spread pox!'", + " yells: 'Your mother is progressive!'", ] class Quips(): diff --git a/Reports.py b/Reports.py index fa88b00..5816e53 100644 --- a/Reports.py +++ b/Reports.py @@ -3,7 +3,7 @@ class Stats(): @staticmethod - def display_status(game): + def show_ship_status(game): game.display() game.display(f" Time Remaining: {game.time_remaining}") game.display(f" Klingon Ships Remaining: {game.game_map.klingons}") @@ -19,7 +19,7 @@ def display_status(game): @staticmethod - def display_galactic_record(game): + def show_galactic_status(game): game.display() game.display("-------------------------------------------------") game.display( @@ -31,7 +31,7 @@ def display_galactic_record(game): @staticmethod - def print_game_status(game): + def show_game_status(game): if game.destroyed: msg = "MISSION FAILED: ENTERPRISE DESTROYED!!!" game.display('!' * len(msg)) diff --git a/Sectors.py b/Sectors.py deleted file mode 100644 index 227aab6..0000000 --- a/Sectors.py +++ /dev/null @@ -1,43 +0,0 @@ - -class Sectors(): - - @staticmethod - def print_sector(game, quad): - game.enterprise.condition = "GREEN" - if game.game_map.num_area_klingons() > 0: - game.enterprise.condition = "RED" - elif game.enterprise.energy < 300: - game.enterprise.condition = "YELLOW" - - sb = " a b c d e f g h \n" - sb += f" -=--=--=--=--=--=--=--=- Region: {quad.name}\n" - info = list() - info.append(f" Sector: [{quad.number}]\n") - info.append(f" Hazzards: [{quad.stars + len(quad.klingons)}]\n") - info.append(f" Stardate: {game.star_date}\n") - info.append(f" Condition: {game.enterprise.condition}\n") - info.append(f" Energy: {game.enterprise.energy}\n") - info.append(f" Shields: {game.enterprise.shield_level}\n") - info.append(f" Photon Torpedoes: {game.enterprise.photon_torpedoes}\n") - info.append(f" Time remaining: {game.time_remaining}\n") - for row, line in enumerate(quad.lines): - sb += f" {row+1} |" - for col in line: - sb += col - sb += info[row] - sb += f" -=--=--=--=--=--=--=--=- Docked: {game.enterprise.docked}\n" - print(sb, end='') - - if len(quad.klingons) > 0: - game.display() - game.display("Condition RED: Klingon ship{0} detected.".format("" if quad.klingons == 1 else "s")) - if game.enterprise.shield_level == 0 and not game.enterprise.docked: - game.display("Warning: Shields are down.") - elif game.enterprise.energy < 300: - game.display() - game.display("Condition YELLOW: Low energy level.") - game.enterprise.condition = "YELLOW" - - - - diff --git a/StarTrek2020.py b/StarTrek2020.py index 7aee2af..adde175 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -23,7 +23,7 @@ def __init__(self): self.destroyed = False def run(self): - self.print_strings(TrekStrings.titleStrings) + self.show_strings(TrekStrings.LOGO_TREKER) game.star_date = random.randint(0, 50) + 2250 game.time_remaining = 40 + random.randint(0, 9) game.destroyed = False @@ -33,12 +33,12 @@ def run(self): game.game_map.randomize(starbases, stars, aliens) self.print_mission() - self.print_strings(TrekStrings.commandStrings) + self.show_strings(TrekStrings.HELM_CMDS) while self.enterprise.energy > 0 and not \ self.destroyed and self.game_map.klingons > 0 and \ self.time_remaining > 0: self.command_prompt() - Stats.print_game_status(game) + Stats.show_game_status(game) def command_prompt(self): command = self.read("Enter command: ").strip().lower() @@ -50,17 +50,17 @@ def command_prompt(self): elif command == "lrs": game.enterprise.long_range_scan(game) elif command == "pha": - Control.phaser_controls(game) + Control.phasers(game) elif command == "tor": - Control.torpedo_control(game) + Control.torpedos(game) elif command == "she": - Control.shield_controls(game) + Control.shields(game) elif command == "com": - Control.computer_controls(game) + Control.computer(game) elif command.startswith('qui') or command.startswith('exi'): exit() else: - self.print_strings(TrekStrings.commandStrings) + self.show_strings(TrekStrings.HELM_CMDS) def print_mission(self): self.display("Mission: Destroy {0} Klingon ships in {1} stardates with {2} starbases.".format( diff --git a/TrekStrings.py b/TrekStrings.py index 7df4378..af82870 100644 --- a/TrekStrings.py +++ b/TrekStrings.py @@ -1,4 +1,4 @@ -titleStrings = r""" +LOGO_TREKER = r""" ______ _______ ______ ______ _______ ______ ______ __ __ / __ //__ __// __ // __ / /__ __// __ / / ____// / / / / / /_/ / / / /_/ // /_/ / / / / /_/ / / /__ / // / @@ -13,7 +13,7 @@ '---._____.|]""".split('\n') -quadrantNames = [ +AREA_NAMES = [ "Aaamazzara", "Altair IV", "Aurelia", @@ -96,7 +96,7 @@ "Zytchin III", ] -commandStrings = [ +HELM_CMDS = [ "--- Commands -----------------", "nav = Navigation", "srs = Short Range Scan", @@ -108,11 +108,10 @@ "qui = Quit the game", ] -computerStrings = [ +CPU_CMDS = [ "--- Main Computer --------------", "rec = Cumulative Galatic Record", "sta = Status Report", "tor = Photon Torpedo Targets", "bas = Starbase Locations", - "nav = Navigation Calculator", ] \ No newline at end of file diff --git a/__pycache__/Sectors.cpython-37.pyc b/__pycache__/Sectors.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..678d34f85d80883b43b76d616f02b506d017fe2a GIT binary patch literal 1745 zcmb7FO>f&a7$zlI{;2Kd!*SE@0|a_l46K2Z4J&4BL(#l4 zv1ImucS2tT9b;+=VUZ1U3uf>SMi3%Kr--W6xH7LHSl<$anF;Du)brG0Rv(E^Stdc5 zJvL&4Wn+Ar`4zF;EAt^58=*ZxV>33dvMdjh97qbU%xjF1#%=+Y4-2r~n&3NVPFe)d z#l%-?QPQ#T99m8?nnQ1Ev^0kjO_8!f*ouz4ltj_&ECX6)cYZN2x?w?a zeTl^%F}kW;Bj5?1Z1rkIam1GU;9va4s-D5_USrLQ>O~2xl;rOu!X*x12X^(Mgzo7?Wka4A~$56zvO?~bAmh#C$d$AokU zVT5o(P6+7|(j$dvLrEWe`QSglN|ug&-gSMiK_o6j)f82md0K=AV1((fzlMlCCw#j(<+Lu9^(^b3RzFRb_#D zAr~Xz23+PlH)P3N*BNp;bVhQ~I~!7P>(G9ZN+9jTiL^XWlGeZtLTNjr5#%pzP(S8E zW&&tOAk6{yWG=PLE0n4($s$w)OjDhSTo`GlDZG^ure!$IWx{>V+utATw>v)L?algToo;N>`e$_SBJBCzCn*F1b>$8P?{9qmaHBna zr>>7KWKm~C1O1k@z0o!9)$x(Phsp lYYJ1BSp6#mYRMV;yj#QiIisr>6Usp5zDNRorL6!#{{lk3$~pi5 literal 0 HcmV?d00001 From 66bca88799caf7c7473ca7970aa0f461fd113bc5 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Wed, 23 Dec 2020 03:06:06 -0500 Subject: [PATCH 016/100] Delete Sectors.cpython-37.pyc --- __pycache__/Sectors.cpython-37.pyc | Bin 1745 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/Sectors.cpython-37.pyc diff --git a/__pycache__/Sectors.cpython-37.pyc b/__pycache__/Sectors.cpython-37.pyc deleted file mode 100644 index 678d34f85d80883b43b76d616f02b506d017fe2a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1745 zcmb7FO>f&a7$zlI{;2Kd!*SE@0|a_l46K2Z4J&4BL(#l4 zv1ImucS2tT9b;+=VUZ1U3uf>SMi3%Kr--W6xH7LHSl<$anF;Du)brG0Rv(E^Stdc5 zJvL&4Wn+Ar`4zF;EAt^58=*ZxV>33dvMdjh97qbU%xjF1#%=+Y4-2r~n&3NVPFe)d z#l%-?QPQ#T99m8?nnQ1Ev^0kjO_8!f*ouz4ltj_&ECX6)cYZN2x?w?a zeTl^%F}kW;Bj5?1Z1rkIam1GU;9va4s-D5_USrLQ>O~2xl;rOu!X*x12X^(Mgzo7?Wka4A~$56zvO?~bAmh#C$d$AokU zVT5o(P6+7|(j$dvLrEWe`QSglN|ug&-gSMiK_o6j)f82md0K=AV1((fzlMlCCw#j(<+Lu9^(^b3RzFRb_#D zAr~Xz23+PlH)P3N*BNp;bVhQ~I~!7P>(G9ZN+9jTiL^XWlGeZtLTNjr5#%pzP(S8E zW&&tOAk6{yWG=PLE0n4($s$w)OjDhSTo`GlDZG^ure!$IWx{>V+utATw>v)L?algToo;N>`e$_SBJBCzCn*F1b>$8P?{9qmaHBna zr>>7KWKm~C1O1k@z0o!9)$x(Phsp lYYJ1BSp6#mYRMV;yj#QiIisr>6Usp5zDNRorL6!#{{lk3$~pi5 From c02fe3cb52d4d9d2a3301db3670989b70fb8e9d1 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Wed, 23 Dec 2020 03:17:51 -0500 Subject: [PATCH 017/100] 2020: The 'trek, so far .... This is proving to be waaaayyy too fun - happy holidays! --- README.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index d9a2d37..b2fe993 100644 --- a/README.rst +++ b/README.rst @@ -1,13 +1,15 @@ -Just forked this one - planning on taking it to the next level ... +So far: -Want to help? Feel free! - --- Randall - -p.s. Converted to Python 3. Lightly tested - okay! +o Converted from Python 2, to Python 3. +o Simplifying coordinate calculations - kudos for the idea! +o Added random event Quips – should make the game a tad more ‘NPC’? +o Heavily re-factored for growth, testing, re-use, and maintenance using modern Python. +Original authors did an excellent job here - made the modernization a WHOLE LOT easier! +-- Nagy +Original: ================ From 742eec9caf3093469890f67aaef902d4cd49cc32 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Wed, 23 Dec 2020 03:18:16 -0500 Subject: [PATCH 018/100] Update README.rst --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index b2fe993..3bf0168 100644 --- a/README.rst +++ b/README.rst @@ -1,10 +1,14 @@ So far: o Converted from Python 2, to Python 3. + o Simplifying coordinate calculations - kudos for the idea! + o Added random event Quips – should make the game a tad more ‘NPC’? + o Heavily re-factored for growth, testing, re-use, and maintenance using modern Python. + Original authors did an excellent job here - made the modernization a WHOLE LOT easier! -- Nagy From dbc059ff484908722aa94c4990b68380bd36c116 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Wed, 23 Dec 2020 03:31:08 -0500 Subject: [PATCH 019/100] SRS --- AbsShip.py | 1 - MapGame.py | 1 - Quadrant.py | 2 +- README.rst | 10 ++++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/AbsShip.py b/AbsShip.py index 64470d6..963c489 100644 --- a/AbsShip.py +++ b/AbsShip.py @@ -142,7 +142,6 @@ def repair(self, game): def short_range_scan(self, game): - from MapGame import Sectors if self.short_range_scan_damage > 0: game.display(Quips.jibe_damage('Short Ranged Scanners')) diff --git a/MapGame.py b/MapGame.py index 0cd807b..9746bbd 100644 --- a/MapGame.py +++ b/MapGame.py @@ -5,7 +5,6 @@ from AbsShip import KlingonShip from Points import Destination from Quadrant import Quadrant -from Sectors import Sectors import MapSparse diff --git a/Quadrant.py b/Quadrant.py index 22a402c..8dcee2d 100644 --- a/Quadrant.py +++ b/Quadrant.py @@ -36,7 +36,7 @@ def display_area(game, quad): game.enterprise.condition = "YELLOW" sb = " a b c d e f g h \n" - sb += f" -=--=--=--=--=--=--=--=- Region: {quad.name}\n" + sb += f" -=--=--=--=--=--=--=--=- Quadrant: {quad.name}\n" info = list() info.append(f" Area: [{quad.number}]\n") info.append(f" Hazzards: [{quad.stars + len(quad.klingons)}]\n") diff --git a/README.rst b/README.rst index 3bf0168..d92af2b 100644 --- a/README.rst +++ b/README.rst @@ -1,16 +1,18 @@ So far: -o Converted from Python 2, to Python 3. +* Converted from Python 2, to Python 3. -o Simplifying coordinate calculations - kudos for the idea! +* Simplifying coordinate calculations - kudos for the idea! -o Added random event Quips – should make the game a tad more ‘NPC’? +* Added random event Quips – should make the game a tad more ‘NPC’? -o Heavily re-factored for growth, testing, re-use, and maintenance using modern Python. +* Heavily re-factored for growth, testing, re-use, and maintenance using modern Python. Original authors did an excellent job here - made the modernization a WHOLE LOT easier! +:monocle_face: + -- Nagy Original: From 2b36d4328a76b1e2cf6552c99d0e0d49d0675353 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Wed, 23 Dec 2020 04:25:22 -0500 Subject: [PATCH 020/100] Better in-play inventory. --- Calculators.py | 4 ++-- Controls.py | 4 +--- MapGame.py | 23 +++++++++-------------- MapSparse.py | 3 ++- Quips.py | 12 +++++++----- README.rst | 1 - Reports.py | 2 +- StarTrek2020.py | 2 +- 8 files changed, 23 insertions(+), 28 deletions(-) diff --git a/Calculators.py b/Calculators.py index 9e39f52..d5bf623 100644 --- a/Calculators.py +++ b/Calculators.py @@ -32,7 +32,7 @@ def navigation(game): dist = dest_sys.warp * 8 energy_required = int(dist) if energy_required >= game.enterprise.energy: - game.display("Unable to comply. Insufficient energy to travel that speed.") + game.display("Insufficient energy to travel at that speed.") game.display() return else: @@ -79,7 +79,7 @@ def show_torp_targets(game): game.display() kships = game.game_map.get_area_klingons() if len(kships) == 0: - game.display("There are no enemy ships in this quadrant.") + game.display("There are no enemies in this quadrant.") return game.display("Enemies:") diff --git a/Controls.py b/Controls.py index cbca095..25d6afc 100644 --- a/Controls.py +++ b/Controls.py @@ -69,7 +69,6 @@ def phasers(game): else: game.display(f"Hit ship at [{ship.xpos + 1},{ship.ypos + 1}].") game.display(f"Enemy shield down to {ship.shield_level}.") - game.game_map.klingons -= len(destroyed_ships) game.game_map.remove_items(destroyed_ships) if game.game_map.klingons > 0: game.display() @@ -141,7 +140,6 @@ def torpedos(game): num = game.game_map.game_id(ship) game.display(f"Klingon ship #{num} destroyed.") game.display(Quips.jibe_defeat('enemy')) - game.game_map.klingons -= 1 game.game_map.remove_items([ship]) hit = True break @@ -156,7 +154,7 @@ def torpedos(game): elif ship.glyph == Glyphs.STAR: num = game.game_map.game_id(ship) game.display(f"Torpedo vaporizes star #{num}!") - game.display(Quips.jibe_defeat('scientist')) + game.display(Quips.jibe_defeat('academic')) game.game_map.remove_items([ship]) hit = True break diff --git a/MapGame.py b/MapGame.py index 9746bbd..d896249 100644 --- a/MapGame.py +++ b/MapGame.py @@ -13,8 +13,7 @@ class GameMap(MapSparse.SparseMap): def __init__(self): super().__init__() self.sector = -1 - self.major_x = self.major_y = -1 - self.xpos = self.ypos = -1 + self.xpos = self.ypos = -1 self.stars = -1 self.klingons = -1 self.starbases = -1 @@ -124,10 +123,16 @@ def _count(self, glyph): count += 1 return count - def remove_items(self, destroyed_ships): + def update_counts(self): + self.klingons = self._count(Glyphs.KLINGON) + self.starbases = self._count(Glyphs.STARBASE) + self.stars = self._count(Glyphs.STAR) + + def remove_items(self, removed): area = self.area() - for obj in destroyed_ships: + for obj in removed: area.remove(obj.xpos, obj.ypos) + self.update_counts() def get_area_klingons(self): ''' @@ -201,16 +206,6 @@ def go_to(self, dest): self.enterprise_out() assert(isinstance(self.sector, int)) self.sector = dest.sector - if self.sector > 0: - fop = (self.sector + 8) / 8 - self.major_x = int(fop) - 1 # ZERO BASED REGIONS - if not fop.is_integer(): - self.major_y = \ - ((fop - float(self.major_x)) * 10) - 1 # ZBR - else: - self.major_x = -1 - self.major_y = -1 - self.xpos = dest.xpos self.ypos = dest.ypos self.enterprise_in(dest) diff --git a/MapSparse.py b/MapSparse.py index 640727f..3c12dea 100644 --- a/MapSparse.py +++ b/MapSparse.py @@ -4,7 +4,8 @@ class SparseMap: ''' - Minimalist mapping. On-demand Area epansion to full-Area views. + Minimalist mapping. + On-demand 'sparse-array' expansion to full-Area views. ''' class Region(): diff --git a/Quips.py b/Quips.py index c8cb2ac..99ab47b 100644 --- a/Quips.py +++ b/Quips.py @@ -4,7 +4,7 @@ "The main ", "That @#$#@& ", "Our cheap ", - "Darnit captian, that ", + "Darn-it captain, that ", "Yikes, the ", ] DAMAGE_SUFFIX = [ @@ -12,13 +12,14 @@ " is out. We're working on it!", " is almost repaired!", " is dead.", - " is fried. I'm working as fast as I can!", + " is fried. Working as fast as we can!", + " is toast. Working as fast as I can!", " is being replaced.", " is dead. Please leave a message.", ] DEFEAT_PREFIX = [ "A defeated ", - "The vengefull ", + "The vengeful ", "An angry ", "The ejecting ", "A confused ", @@ -35,6 +36,7 @@ " is no more.", " is recycled.", " is eliminated.", + " was aborted. Few lives, matter?", " ejects.", " crew is rescued.", " crew is spaced.", @@ -47,8 +49,8 @@ " screams: 'Thy father is a Targ!'", " yells: 'Your parents eat bats!'", " snarls: 'Thy people eat vermin!'", - " yells: 'May you create social diseases!'", - " curses: 'Thy fathers spread pox!'", + " yells: 'May you create social disease!'", + " curses: 'Thy fathers spreadeth pox!'", " yells: 'Your mother is progressive!'", ] diff --git a/README.rst b/README.rst index d92af2b..5687f31 100644 --- a/README.rst +++ b/README.rst @@ -11,7 +11,6 @@ So far: Original authors did an excellent job here - made the modernization a WHOLE LOT easier! -:monocle_face: -- Nagy diff --git a/Reports.py b/Reports.py index 5816e53..69faa5e 100644 --- a/Reports.py +++ b/Reports.py @@ -31,7 +31,7 @@ def show_galactic_status(game): @staticmethod - def show_game_status(game): + def show_exit_status(game): if game.destroyed: msg = "MISSION FAILED: ENTERPRISE DESTROYED!!!" game.display('!' * len(msg)) diff --git a/StarTrek2020.py b/StarTrek2020.py index adde175..ae5c328 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -38,7 +38,7 @@ def run(self): self.destroyed and self.game_map.klingons > 0 and \ self.time_remaining > 0: self.command_prompt() - Stats.show_game_status(game) + Stats.show_exit_status(game) def command_prompt(self): command = self.read("Enter command: ").strip().lower() From 186aecd9c2d0aa6fe7f4a04b0d53841889c5d07b Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Wed, 23 Dec 2020 08:02:19 -0500 Subject: [PATCH 021/100] Better randomization. --- AbsShip.py | 38 +++++++++++++++++++++++--------------- Calculators.py | 4 ++-- Controls.py | 5 ++--- MapGame.py | 41 ++++++++++++++++++++++------------------- MapSparse.py | 36 ++++++++++++++++++++++++++++++------ Quadrant.py | 16 +++++++++------- StarTrek2020.py | 7 +++---- 7 files changed, 91 insertions(+), 56 deletions(-) diff --git a/AbsShip.py b/AbsShip.py index 963c489..2505008 100644 --- a/AbsShip.py +++ b/AbsShip.py @@ -3,6 +3,7 @@ import Glyphs from Quips import Quips +from Quadrant import Quadrant class AbsShip(abc.ABC): ''' The first step, into a much larger universe ... ''' @@ -14,7 +15,7 @@ def __init__(self): def get_glyph(self): pass -class StarBase(AbsShip): +class ShipStarbase(AbsShip): def __init__(self): super().__init__() @@ -41,7 +42,7 @@ def launch_enterprise(ship): ship.docked = False -class Enterprise(AbsShip): +class ShipEnterprise(AbsShip): def __init__(self): super().__init__() @@ -56,14 +57,16 @@ def __init__(self): self.photon_damage = 0 self.phaser_damage = 0 self.photon_torpedoes = 0 - StarBase.dock_enterprise(self) - StarBase.launch_enterprise(self) + ShipStarbase.dock_enterprise(self) + ShipStarbase.launch_enterprise(self) def get_glyph(self): return Glyphs.ENTERPRISE - def damage(self, game, item): + ''' + Damage the Enterprise. + ''' if game.is_testing: return if random.randint(0, 6) > 0: @@ -94,8 +97,10 @@ def damage(self, game, item): game.display(Quips.jibe_damage('Phasers')) game.display() - def repair(self, game): + ''' + Rapair damage to the Enterprise. + ''' if self.navigation_damage > 0: self.navigation_damage -= 1 if self.navigation_damage == 0: @@ -140,9 +145,7 @@ def repair(self, game): return True return False - def short_range_scan(self, game): - if self.short_range_scan_damage > 0: game.display(Quips.jibe_damage('Short Ranged Scanners')) game.display() @@ -151,30 +154,36 @@ def short_range_scan(self, game): Quadrant.display_area(game, quad) game.display() - def long_range_scan(self, game): if self.long_range_scan_damage > 0: game.display(Quips.jibe_damage('Long Ranged Scanners')) game.display() return sb = "" - game.display("-------------------") pw_sector = game.game_map.sector if pw_sector < 5: pw_sector = 5 elif pw_sector > 59: pw_sector = 59 + dots = None for peek in range(pw_sector-5, pw_sector + 6): quad = game.game_map.scan_quad(peek) - f"{quad.klingons}{quad.starbases}{quad.stars} " - sb += "|" + lines = \ + (f"Sector: {quad.number:>02}", + f"Enemies:{quad.klingons:>02}", + f"Bases:{quad.starbases:>02}", + f"Stars: {quad.stars:>03}") + str_ = ' | '.join(lines) + dots = '-' * len(str_) + "\n" + sb += dots + sb += str_ game.display(sb) sb = "" - game.display("-------------------") + game.display(dots) game.display() -class KlingonShip(AbsShip): +class ShipKlingon(AbsShip): def __init__(self): super().__init__() @@ -182,7 +191,6 @@ def __init__(self): self.ypos = 0 self.shield_level = 0 - def get_glyph(self): return Glyphs.KLINGON diff --git a/Calculators.py b/Calculators.py index d5bf623..95b9370 100644 --- a/Calculators.py +++ b/Calculators.py @@ -1,4 +1,4 @@ -from math import atan2, pi, sqrt, cos, sin +from math import sqrt import random from MapGame import * @@ -53,7 +53,7 @@ def navigation(game): game.display() else: if game.game_map.klingons > 0: - KlingonShip.attack(game) + ShipKlingon.attack(game) game.display() elif not game.enterprise.repair(game): game.enterprise.damage(game, -1) diff --git a/Controls.py b/Controls.py index 25d6afc..214bbaa 100644 --- a/Controls.py +++ b/Controls.py @@ -1,4 +1,3 @@ -from math import pi, sqrt, cos, sin import random import TrekStrings @@ -72,7 +71,7 @@ def phasers(game): game.game_map.remove_items(destroyed_ships) if game.game_map.klingons > 0: game.display() - KlingonShip.attack(game) + ShipKlingon.attack(game) game.display() @@ -162,7 +161,7 @@ def torpedos(game): game.display("Torpedo missed.") if len(game.game_map.get_area_klingons()) > 0: game.display() - KlingonShip.attack(game) + ShipKlingon.attack(game) game.display() diff --git a/MapGame.py b/MapGame.py index d896249..1472903 100644 --- a/MapGame.py +++ b/MapGame.py @@ -2,7 +2,7 @@ import TrekStrings import Glyphs -from AbsShip import KlingonShip +from AbsShip import ShipKlingon from Points import Destination from Quadrant import Quadrant @@ -36,18 +36,22 @@ def place(self, takers): continue taken = 0 while taken != to_take: - for ss, area in enumerate(self.areas()): - should_take = random.randrange(1, 8) - if should_take % (ss + 2) == 0: - if which is 0: - area.place_glyph(Glyphs.STARBASE) - elif which is 1: - area.place_glyph(Glyphs.STAR) - elif which is 2: - area.place_glyph(Glyphs.KLINGON) - taken += 1 - if taken == to_take: - break; + ss = random.randrange(1, 64) + area = self.get_area(ss) + should_take = random.randrange(1, 8) + if which is 0: + if area.count_glyphs(Glyphs.STARBASE) != 0: + continue + area.place_glyph(Glyphs.STARBASE) + elif which is 1: + area.place_glyph(Glyphs.STAR) + elif which is 2: + if area.count_glyphs(Glyphs.KLINGON) > 3: + continue + area.place_glyph(Glyphs.KLINGON) + taken += 1 + if taken == to_take: + break; takers[which] -= taken return tuple(takers) @@ -107,10 +111,9 @@ def scan_quad(self, sector): Return a scan (LRS?) for a specific quadrant. Return empty quadrant, on error. ''' - if sector > 0 and sector < 65: - for area in self.areas(): - if area.number == self.sector: - return Quadrant.from_area(area) + area = self.get_area(sector) + if area: + return Quadrant.from_area(area) return Quadrant() def _count(self, glyph): @@ -141,7 +144,7 @@ def get_area_klingons(self): results = [] area = self.area() for data in area.get_data(Glyphs.KLINGON): - ship = KlingonShip() + ship = ShipKlingon() ship.from_map(data.xpos, data.ypos) results.append(ship) return results @@ -222,7 +225,7 @@ def randomize(self, bases=None, stars=None, aliens=None): self.init() takers = bases, stars, aliens while takers: - for lrs in self.map: + for lrs in self._map: takers = self.place(takers) if not takers: break diff --git a/MapSparse.py b/MapSparse.py index 3c12dea..ba18253 100644 --- a/MapSparse.py +++ b/MapSparse.py @@ -67,7 +67,7 @@ def remove(self, xpos, ypos): def get_map(self): ''' - Generate a map of this sector. Map is full + Generate a map of this AREA. Map is full of Glyphs.SPACE on error. ''' results = [[Glyphs.SPACE for _ in range(8)] for _ in range(8)] @@ -142,31 +142,52 @@ def clone(piece): def __init__(self): self.initalized = False - self.map = [[[y,x] for y in range(8)] for x in range(8)] + self._map = [[[y,x] for y in range(8)] for x in range(8)] def init(self, reset=False): if not reset and self.initalized: return - for xx, row in enumerate(self.map): + for xx, row in enumerate(self._map): lrs = SparseMap.Region() for yy, col in enumerate(row): - self.map[xx][yy] = [lrs, SparseMap.Area()] + self._map[xx][yy] = [lrs, SparseMap.Area()] self.name_areas() self.initalized = True + def get_area(self, which): + ''' + Get an AREA from the map. + Area identifiers are 1's based. + Returns False on under / over flows. + ''' + if which < 1: + return False + if which >= 65: + return False + which -= 1 # ASSURED + fid = which / 8 + ypos = 0 + xpos = int(fid) + if not fid.is_integer(): + ypos = which %8 + return self._map[xpos][ypos][1] + def data(self): ''' Enumerate thru every [Region, Area] in the Map ''' - for row in self.map: + for row in self._map: for col in row: yield col def areas(self): ''' Enumerare thru every Area on the Map ''' - for row in self.map: + for row in self._map: for col in row: yield col[1] def name_areas(self): + ''' + Assign / re-assign 'Trekian names. + ''' names = list(TrekStrings.AREA_NAMES) for num, area in enumerate(self.areas(),1): index = random.randint(0, len(names) - 1) @@ -175,6 +196,9 @@ def name_areas(self): del names[index] def get_sector_names(self): + ''' + Return a list of [secor numbers, sector_name] pairs. + ''' results = [] temp = [] for ss, col in enumerate(self.areas(),1): diff --git a/Quadrant.py b/Quadrant.py index 8dcee2d..06aed5c 100644 --- a/Quadrant.py +++ b/Quadrant.py @@ -1,8 +1,9 @@ import Glyphs class Quadrant(): - def __init__(self, num=-1, name='', lines=[], - aliens=-1, stars=-1, starbases=-1): + def __init__(self, num=-1, name='', + aliens=-1, stars=-1, + starbases=-1, lines=[]): self.name = name self.number = num self.lines = lines @@ -21,10 +22,11 @@ def from_area(area): name = area.name num = area.number map = area.get_map() - return Quadrant(num, name, map, - area.get_data(Glyphs.KLINGON), + return Quadrant(num, name, + area.count_glyphs(Glyphs.KLINGON), area.count_glyphs(Glyphs.STAR), - area.count_glyphs(Glyphs.STARBASE)) + area.count_glyphs(Glyphs.STARBASE), + map) @staticmethod @@ -39,7 +41,7 @@ def display_area(game, quad): sb += f" -=--=--=--=--=--=--=--=- Quadrant: {quad.name}\n" info = list() info.append(f" Area: [{quad.number}]\n") - info.append(f" Hazzards: [{quad.stars + len(quad.klingons)}]\n") + info.append(f" Hazzards: [{quad.stars + quad.klingons}]\n") info.append(f" Stardate: {game.star_date}\n") info.append(f" Condition: {game.enterprise.condition}\n") info.append(f" Energy: {game.enterprise.energy}\n") @@ -54,7 +56,7 @@ def display_area(game, quad): sb += f" -=--=--=--=--=--=--=--=- Docked: {game.enterprise.docked}\n" print(sb, end='') - if len(quad.klingons) > 0: + if quad.klingons > 0: game.display() game.display("Condition RED: Klingon ship{0} detected.".format("" if quad.klingons == 1 else "s")) if game.enterprise.shield_level == 0 and not game.enterprise.docked: diff --git a/StarTrek2020.py b/StarTrek2020.py index ae5c328..ecfee69 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -1,5 +1,4 @@ -from math import pi, sqrt, cos, sin -import random +import random import TrekStrings @@ -17,7 +16,7 @@ class Game(Con): def __init__(self): self.is_testing = False self.game_map = GameMap() - self.enterprise = Enterprise() + self.enterprise = ShipEnterprise() self.star_date = 0 self.time_remaining = 0 self.destroyed = False @@ -27,7 +26,7 @@ def run(self): game.star_date = random.randint(0, 50) + 2250 game.time_remaining = 40 + random.randint(0, 9) game.destroyed = False - stars = random.randrange(32, 64) + stars = random.randrange(400, 600) # 4096 = ALL aliens = random.randrange(12, 16) starbases = random.randrange(6, 8) game.game_map.randomize(starbases, stars, aliens) From 5a9545dac70e4bd2dbd0ba0918a88e0c63c6d271 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Wed, 23 Dec 2020 09:23:54 -0500 Subject: [PATCH 022/100] LRS tweaks ... --- AbsShip.py | 12 ++++++------ MapGame.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/AbsShip.py b/AbsShip.py index 2505008..bddb225 100644 --- a/AbsShip.py +++ b/AbsShip.py @@ -99,7 +99,7 @@ def damage(self, game, item): def repair(self, game): ''' - Rapair damage to the Enterprise. + Repair damage to the Enterprise. ''' if self.navigation_damage > 0: self.navigation_damage -= 1 @@ -162,17 +162,17 @@ def long_range_scan(self, game): sb = "" pw_sector = game.game_map.sector if pw_sector < 5: - pw_sector = 5 + pw_sector = 6 elif pw_sector > 59: pw_sector = 59 dots = None for peek in range(pw_sector-5, pw_sector + 6): quad = game.game_map.scan_quad(peek) lines = \ - (f"Sector: {quad.number:>02}", - f"Enemies:{quad.klingons:>02}", - f"Bases:{quad.starbases:>02}", - f"Stars: {quad.stars:>03}") + (f"| Sector: {quad.number:>02}", + f"Enemies: {quad.klingons:>02}", + f"Bases: {quad.starbases:>02}", + f"Stars: {quad.stars:>03} |") str_ = ' | '.join(lines) dots = '-' * len(str_) + "\n" sb += dots diff --git a/MapGame.py b/MapGame.py index 1472903..3f0c60d 100644 --- a/MapGame.py +++ b/MapGame.py @@ -173,7 +173,7 @@ def game_id(self, piece): ''' area = self.area() num = (area.number * 100) + (piece.ypos * 8) + piece.xpos - return f"{piece.glyph[0]}x{num}" + return f"{piece.glyph[1]}x{num}" def get_all(self, glyph): ''' From c54e1e9311450335418b7dec147bc49247b4f929 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Wed, 23 Dec 2020 10:49:46 -0500 Subject: [PATCH 023/100] Fixed game object reporting. --- .gitignore | 3 + AbsShip.py | 210 ---------------------------------------------- Controls.py | 6 +- MapGame.py | 18 ++-- Reports.py | 14 ++-- ShipEnterprise.py | 145 ++++++++++++++++++++++++++++++++ ShipKlingon.py | 51 +++++++++++ ShipStarbase.py | 29 +++++++ StarTrek2020.py | 15 ++-- 9 files changed, 260 insertions(+), 231 deletions(-) create mode 100644 ShipEnterprise.py create mode 100644 ShipKlingon.py create mode 100644 ShipStarbase.py diff --git a/.gitignore b/.gitignore index 82559a5..bbb050a 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ /__pycache__/MapSparse.cpython-37.pyc /__pycache__/MapSparce.cpython-37.pyc /__pycache__/Console.cpython-37.pyc +/__pycache__/ShipStarbase.cpython-37.pyc +/__pycache__/ShipKlingon.cpython-37.pyc +/__pycache__/ShipEnterprise.cpython-37.pyc diff --git a/AbsShip.py b/AbsShip.py index bddb225..4b856a3 100644 --- a/AbsShip.py +++ b/AbsShip.py @@ -15,213 +15,3 @@ def __init__(self): def get_glyph(self): pass -class ShipStarbase(AbsShip): - - def __init__(self): - super().__init__() - - def get_glyph(self): - return Glyphs.STARBASE - - @staticmethod - def dock_enterprise(ship): - ship.energy = 3000 - ship.photon_torpedoes = 10 - ship.navigation_damage = 0 - ship.short_range_scan_damage = 0 - ship.long_range_scan_damage = 0 - ship.shield_control_damage = 0 - ship.computer_damage = 0 - ship.photon_damage = 0 - ship.phaser_damage = 0 - ship.shield_level = 0 - ship.docked = True - - @staticmethod - def launch_enterprise(ship): - ship.docked = False - - -class ShipEnterprise(AbsShip): - - def __init__(self): - super().__init__() - self.energy = 0 - self.docked = False - self.condition = "GREEN" - self.navigation_damage = 0 - self.short_range_scan_damage = 0 - self.long_range_scan_damage = 0 - self.shield_control_damage = 0 - self.computer_damage = 0 - self.photon_damage = 0 - self.phaser_damage = 0 - self.photon_torpedoes = 0 - ShipStarbase.dock_enterprise(self) - ShipStarbase.launch_enterprise(self) - - def get_glyph(self): - return Glyphs.ENTERPRISE - - def damage(self, game, item): - ''' - Damage the Enterprise. - ''' - if game.is_testing: - return - if random.randint(0, 6) > 0: - return - damage = 1 + random.randint(0, 4) - if item < 0: - item = random.randint(0, 6) - if item == 0: - self.navigation_damage = damage - game.display(Quips.jibe_damage('Warp Engines')) - elif item == 1: - self.short_range_scan_damage = damage - game.display(Quips.jibe_damage('Short Range Scanners')) - elif item == 2: - self.long_range_scan_damage = damage - game.display(Quips.jibe_damage('Long Range Scanners')) - elif item == 3: - self.shield_control_damage = damage - game.display(Quips.jibe_damage('Shield Controls')) - elif item == 4: - self.computer_damage = damage - game.display(Quips.jibe_damage('Main Computer')) - elif item == 5: - self.photon_damage = damage - game.display(Quips.jibe_damage('Photon Torpedo Controls')) - elif item == 6: - self.phaser_damage = damage - game.display(Quips.jibe_damage('Phasers')) - game.display() - - def repair(self, game): - ''' - Repair damage to the Enterprise. - ''' - if self.navigation_damage > 0: - self.navigation_damage -= 1 - if self.navigation_damage == 0: - game.display("Warp engines have been repaired.") - game.display() - return True - if self.short_range_scan_damage > 0: - self.short_range_scan_damage -= 1 - if self.short_range_scan_damage == 0: - game.display("Short range scanner has been repaired.") - self.display() - return True - if self.long_range_scan_damage > 0: - self.long_range_scan_damage -= 1 - if self.long_range_scan_damage == 0: - game.display("Long range scanner has been repaired.") - game.display() - return True - if self.shield_control_damage > 0: - self.shield_control_damage -= 1 - if self.shield_control_damage == 0: - game.display("Shield controls have been repaired.") - game.display() - return True - if self.computer_damage > 0: - self.computer_damage -= 1 - if self.computer_damage == 0: - game.display("The main computer has been repaired.") - game.display() - return True - if self.photon_damage > 0: - self.photon_damage -= 1 - if self.photon_damage == 0: - game.display("Photon torpedo controls have been repaired.") - game.display() - return True - if self.phaser_damage > 0: - self.phaser_damage -= 1 - if self.phaser_damage == 0: - game.display("Phasers have been repaired.") - game.display() - return True - return False - - def short_range_scan(self, game): - if self.short_range_scan_damage > 0: - game.display(Quips.jibe_damage('Short Ranged Scanners')) - game.display() - else: - quad = game.game_map.quad() - Quadrant.display_area(game, quad) - game.display() - - def long_range_scan(self, game): - if self.long_range_scan_damage > 0: - game.display(Quips.jibe_damage('Long Ranged Scanners')) - game.display() - return - sb = "" - pw_sector = game.game_map.sector - if pw_sector < 5: - pw_sector = 6 - elif pw_sector > 59: - pw_sector = 59 - dots = None - for peek in range(pw_sector-5, pw_sector + 6): - quad = game.game_map.scan_quad(peek) - lines = \ - (f"| Sector: {quad.number:>02}", - f"Enemies: {quad.klingons:>02}", - f"Bases: {quad.starbases:>02}", - f"Stars: {quad.stars:>03} |") - str_ = ' | '.join(lines) - dots = '-' * len(str_) + "\n" - sb += dots - sb += str_ - game.display(sb) - sb = "" - game.display(dots) - game.display() - - -class ShipKlingon(AbsShip): - - def __init__(self): - super().__init__() - self.xpos = 0 - self.ypos = 0 - self.shield_level = 0 - - def get_glyph(self): - return Glyphs.KLINGON - - def from_map(self, xpos, ypos): - self.xpos = xpos - self.ypos = ypos - self.shield_level = 300 + random.randint(0, 199) - - @staticmethod - def attack(game): - from Calculators import Calc - kships = game.game_map.get_area_klingons() - if len(kships) > 0: - for ship in kships: - if game.enterprise.docked: - game.display("Enterprise hit by ship at sector [{0},{1}]. No damage due to starbase shields.".format( - ship.xpos + 1, ship.ypos + 1 - )) - else: - dist = Calc.distance( - game.game_map.xpos, game.game_map.ypos, ship.xpos, ship.ypos) - delivered_energy = 300 * \ - random.uniform(0.0, 1.0) * (1.0 - dist / 11.3) - game.enterprise.shield_level -= int(delivered_energy) - if game.enterprise.shield_level < 0: - game.enterprise.shield_level = 0 - game.destroyed = True - game.display("Enterprise hit by ship at sector [{0},{1}]. Shields dropped to {2}.".format( - ship.xpos + 1, ship.ypos + 1, game.enterprise.shield_level - )) - if game.enterprise.shield_level == 0: - return True - return True - return False diff --git a/Controls.py b/Controls.py index 214bbaa..e13af1e 100644 --- a/Controls.py +++ b/Controls.py @@ -1,7 +1,11 @@ import random import TrekStrings -from AbsShip import * +import Glyphs +from ShipKlingon import ShipKlingon +from ShipKlingon import ShipKlingon +#from ShipStarbase import ShipStarbase +from ShipEnterprise import ShipEnterprise from Calculators import Calc from Reports import Stats from Quips import Quips diff --git a/MapGame.py b/MapGame.py index 3f0c60d..76dab4e 100644 --- a/MapGame.py +++ b/MapGame.py @@ -2,7 +2,7 @@ import TrekStrings import Glyphs -from AbsShip import ShipKlingon +from ShipKlingon import ShipKlingon from Points import Destination from Quadrant import Quadrant @@ -116,7 +116,7 @@ def scan_quad(self, sector): return Quadrant.from_area(area) return Quadrant() - def _count(self, glyph): + def _count_area(self, glyph): ''' Tally the number of glyphs in the AREA ''' count = 0 area = self.area() @@ -127,9 +127,11 @@ def _count(self, glyph): return count def update_counts(self): - self.klingons = self._count(Glyphs.KLINGON) - self.starbases = self._count(Glyphs.STARBASE) - self.stars = self._count(Glyphs.STAR) + self.klingons = self.starbases = self.stars = 0 + for area in self.areas(): + self.klingons += area.count_glyphs(Glyphs.KLINGON) + self.starbases += area.count_glyphs(Glyphs.STARBASE) + self.stars += area.count_glyphs(Glyphs.STAR) def remove_items(self, removed): area = self.area() @@ -150,13 +152,13 @@ def get_area_klingons(self): return results def num_area_klingons(self): - return self._count(Glyphs.KLINGON) + return self._count_area(Glyphs.KLINGON) def num_area_starbases(self): - return self._count(Glyphs.STARBASE) + return self._count_area(Glyphs.STARBASE) def num_area_stars(self): - return self._count(Glyphs.STAR) + return self._count_area(Glyphs.STAR) def get_area_objects(self): ''' diff --git a/Reports.py b/Reports.py index 69faa5e..e079b6e 100644 --- a/Reports.py +++ b/Reports.py @@ -21,13 +21,13 @@ def show_ship_status(game): @staticmethod def show_galactic_status(game): game.display() - game.display("-------------------------------------------------") - game.display( - f"{Glyphs.KLINGON}{game.game_map.klingons}|" + - f"{Glyphs.STARBASE}|{game.game_map.starbases}|" + - f"{Glyphs.STAR}{game.game_map.stars}") - game.display("-------------------------------------------------") - game.display() + str_ = f"| KLINGONS: {game.game_map.klingons:>04} | " + \ + f"STARBASES: {game.game_map.starbases:>04} | " + \ + f"STARS: {game.game_map.stars:>04} |" + dots = len(str_) * '-' + game.display(dots) + game.display(str_) + game.display(dots) @staticmethod diff --git a/ShipEnterprise.py b/ShipEnterprise.py new file mode 100644 index 0000000..5b58ca6 --- /dev/null +++ b/ShipEnterprise.py @@ -0,0 +1,145 @@ +import random +from AbsShip import AbsShip +from ShipStarbase import ShipStarbase +from Quadrant import Quadrant + +class ShipEnterprise(AbsShip): + + def __init__(self): + super().__init__() + self.energy = 0 + self.docked = False + self.condition = "GREEN" + self.navigation_damage = 0 + self.short_range_scan_damage = 0 + self.long_range_scan_damage = 0 + self.shield_control_damage = 0 + self.computer_damage = 0 + self.photon_damage = 0 + self.phaser_damage = 0 + self.photon_torpedoes = 0 + ShipStarbase.dock_enterprise(self) + ShipStarbase.launch_enterprise(self) + + def get_glyph(self): + return Glyphs.ENTERPRISE + + def damage(self, game, item): + ''' + Damage the Enterprise. + ''' + if game.is_testing: + return + if random.randint(0, 6) > 0: + return + damage = 1 + random.randint(0, 4) + if item < 0: + item = random.randint(0, 6) + if item == 0: + self.navigation_damage = damage + game.display(Quips.jibe_damage('Warp Engines')) + elif item == 1: + self.short_range_scan_damage = damage + game.display(Quips.jibe_damage('Short Range Scanners')) + elif item == 2: + self.long_range_scan_damage = damage + game.display(Quips.jibe_damage('Long Range Scanners')) + elif item == 3: + self.shield_control_damage = damage + game.display(Quips.jibe_damage('Shield Controls')) + elif item == 4: + self.computer_damage = damage + game.display(Quips.jibe_damage('Main Computer')) + elif item == 5: + self.photon_damage = damage + game.display(Quips.jibe_damage('Photon Torpedo Controls')) + elif item == 6: + self.phaser_damage = damage + game.display(Quips.jibe_damage('Phasers')) + game.display() + + def repair(self, game): + ''' + Repair damage to the Enterprise. + ''' + if self.navigation_damage > 0: + self.navigation_damage -= 1 + if self.navigation_damage == 0: + game.display("Warp engines have been repaired.") + game.display() + return True + if self.short_range_scan_damage > 0: + self.short_range_scan_damage -= 1 + if self.short_range_scan_damage == 0: + game.display("Short range scanner has been repaired.") + self.display() + return True + if self.long_range_scan_damage > 0: + self.long_range_scan_damage -= 1 + if self.long_range_scan_damage == 0: + game.display("Long range scanner has been repaired.") + game.display() + return True + if self.shield_control_damage > 0: + self.shield_control_damage -= 1 + if self.shield_control_damage == 0: + game.display("Shield controls have been repaired.") + game.display() + return True + if self.computer_damage > 0: + self.computer_damage -= 1 + if self.computer_damage == 0: + game.display("The main computer has been repaired.") + game.display() + return True + if self.photon_damage > 0: + self.photon_damage -= 1 + if self.photon_damage == 0: + game.display("Photon torpedo controls have been repaired.") + game.display() + return True + if self.phaser_damage > 0: + self.phaser_damage -= 1 + if self.phaser_damage == 0: + game.display("Phasers have been repaired.") + game.display() + return True + return False + + def short_range_scan(self, game): + if self.short_range_scan_damage > 0: + game.display(Quips.jibe_damage('Short Ranged Scanners')) + game.display() + else: + quad = game.game_map.quad() + Quadrant.display_area(game, quad) + game.display() + + def long_range_scan(self, game): + if self.long_range_scan_damage > 0: + game.display(Quips.jibe_damage('Long Ranged Scanners')) + game.display() + return + sb = "" + pw_sector = game.game_map.sector + if pw_sector < 5: + pw_sector = 6 + elif pw_sector > 59: + pw_sector = 59 + dots = None + for peek in range(pw_sector-5, pw_sector + 6): + quad = game.game_map.scan_quad(peek) + lines = \ + (f"| Sector: {quad.number:>02}", + f"Enemies: {quad.klingons:>02}", + f"Bases: {quad.starbases:>02}", + f"Stars: {quad.stars:>03} |") + str_ = ' | '.join(lines) + dots = '-' * len(str_) + "\n" + sb += dots + sb += str_ + game.display(sb) + sb = "" + game.display(dots) + game.display() + diff --git a/ShipKlingon.py b/ShipKlingon.py new file mode 100644 index 0000000..253098f --- /dev/null +++ b/ShipKlingon.py @@ -0,0 +1,51 @@ +import random +from AbsShip import AbsShip + +class ShipKlingon(AbsShip): + + def __init__(self): + super().__init__() + self.xpos = 0 + self.ypos = 0 + self.shield_level = 0 + + def get_glyph(self): + return Glyphs.KLINGON + + def from_map(self, xpos, ypos): + self.xpos = xpos + self.ypos = ypos + self.shield_level = 300 + random.randint(0, 199) + + @staticmethod + def attack(game): + if game.is_testing: + return False + from Calculators import Calc + kships = game.game_map.get_area_klingons() + if len(kships) > 0: + for ship in kships: + if game.enterprise.docked: + game.display("Enterprise hit by ship at sector [{0},{1}]. No damage due to starbase shields.".format( + ship.xpos + 1, ship.ypos + 1 + )) + else: + dist = Calc.distance( + game.game_map.xpos, game.game_map.ypos, ship.xpos, ship.ypos) + delivered_energy = 300 * \ + random.uniform(0.0, 1.0) * (1.0 - dist / 11.3) + game.enterprise.shield_level -= int(delivered_energy) + if game.enterprise.shield_level < 0: + game.enterprise.shield_level = 0 + game.destroyed = True + game.display("Enterprise hit by ship at sector [{0},{1}]. Shields dropped to {2}.".format( + ship.xpos + 1, ship.ypos + 1, game.enterprise.shield_level + )) + if game.enterprise.shield_level == 0: + return True + return True + return False + + + + diff --git a/ShipStarbase.py b/ShipStarbase.py new file mode 100644 index 0000000..50a0c10 --- /dev/null +++ b/ShipStarbase.py @@ -0,0 +1,29 @@ +from AbsShip import AbsShip + +class ShipStarbase(AbsShip): + + def __init__(self): + super().__init__() + + def get_glyph(self): + return Glyphs.STARBASE + + @staticmethod + def dock_enterprise(ship): + ship.energy = 3000 + ship.photon_torpedoes = 10 + ship.navigation_damage = 0 + ship.short_range_scan_damage = 0 + ship.long_range_scan_damage = 0 + ship.shield_control_damage = 0 + ship.computer_damage = 0 + ship.photon_damage = 0 + ship.phaser_damage = 0 + ship.shield_level = 0 + ship.docked = True + + @staticmethod + def launch_enterprise(ship): + ship.docked = False + + diff --git a/StarTrek2020.py b/StarTrek2020.py index ecfee69..b2dedfb 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -6,7 +6,9 @@ from Calculators import Calc from Controls import Control from Reports import Stats -from AbsShip import * +from ShipKlingon import ShipKlingon +from ShipStarbase import ShipStarbase +from ShipEnterprise import ShipEnterprise from MapGame import * from Points import Destination @@ -33,11 +35,14 @@ def run(self): self.print_mission() self.show_strings(TrekStrings.HELM_CMDS) - while self.enterprise.energy > 0 and not \ - self.destroyed and self.game_map.klingons > 0 and \ - self.time_remaining > 0: + running = True + while running: self.command_prompt() - Stats.show_exit_status(game) + running = self.enterprise.energy > 0 and not \ + self.destroyed and self.game_map.klingons > 0 and \ + self.time_remaining > 0 + if not running: + Stats.show_exit_status(game) def command_prompt(self): command = self.read("Enter command: ").strip().lower() From fcd7564bec5f8b318f6cd345e9eb82b7ecb6c8ae Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Wed, 23 Dec 2020 12:20:53 -0500 Subject: [PATCH 024/100] Sub-Space Navigation. Hazzard / Docking checking to follow. \o/ --- Calculators.py | 34 +++++++++++++++++++++++++++++++--- Console.py | 4 ++++ Controls.py | 4 ++-- MapGame.py | 14 +++++++++----- MapSparse.py | 2 +- Points.py | 7 +++++++ Quadrant.py | 1 + ShipKlingon.py | 5 ++++- StarTrek2020.py | 11 +++++++++-- TrekStrings.py | 3 ++- 10 files changed, 70 insertions(+), 15 deletions(-) diff --git a/Calculators.py b/Calculators.py index 95b9370..6359fc3 100644 --- a/Calculators.py +++ b/Calculators.py @@ -13,12 +13,40 @@ def distance(x1, y1, x2, y2): y = y2 - y1 return sqrt(x * x + y * y) + @staticmethod + def sublight_navigation(game): + dest_sys = game.read_xypos() + if not dest_sys: + game.display("Invalid course.") + game.display() + return + + game.display() + game.display("Sub-light engines engaged.") + game.display() + game.game_map.go_to(dest_sys) + + game.time_remaining -= 1 + game.star_date += 1 + + game.enterprise.short_range_scan(game) + + if game.enterprise.docked: + game.display("Lowering shields as part of docking sequence...") + game.display("Enterprise successfully docked with starbase.") + game.display() + else: + if game.game_map.klingons > 0: + ShipKlingon.attack_if_you_can(game) + game.display() + elif not game.enterprise.repair(game): + game.enterprise.damage(game, -1) @staticmethod - def navigation(game): + def warp_navigation(game): if game.enterprise.navigation_damage > 0: max_warp_factor = 0.2 + random.randint(0, 8) / 10.0 - game.display("Warp engines damaged. Maximum warp factor: {0}".format(max_warp_factor)) + game.display(f"Warp engines damaged. Maximum warp factor: {max_warp_factor}") game.display() dest_sys = game.read_sector() @@ -53,7 +81,7 @@ def navigation(game): game.display() else: if game.game_map.klingons > 0: - ShipKlingon.attack(game) + ShipKlingon.attack_if_you_can(game) game.display() elif not game.enterprise.repair(game): game.enterprise.damage(game, -1) diff --git a/Console.py b/Console.py index 6117c9e..5558554 100644 --- a/Console.py +++ b/Console.py @@ -43,6 +43,10 @@ def read_nav(self, prompt= "Helm: sector 1-64, a-h, 1-8?"): text = input(prompt + ': ') return Destination.parse_sector(text) + def read_xypos(self, prompt= "Helm: a-h, 1-8?"): + text = input(prompt + ': ') + return Destination.parse_xypos(text) + if __name__ == '__main__': con = Con() diff --git a/Controls.py b/Controls.py index e13af1e..3f07f37 100644 --- a/Controls.py +++ b/Controls.py @@ -75,7 +75,7 @@ def phasers(game): game.game_map.remove_items(destroyed_ships) if game.game_map.klingons > 0: game.display() - ShipKlingon.attack(game) + ShipKlingon.attack_if_you_can(game) game.display() @@ -165,7 +165,7 @@ def torpedos(game): game.display("Torpedo missed.") if len(game.game_map.get_area_klingons()) > 0: game.display() - ShipKlingon.attack(game) + ShipKlingon.attack_if_you_can(game) game.display() diff --git a/MapGame.py b/MapGame.py index 76dab4e..5bcd91d 100644 --- a/MapGame.py +++ b/MapGame.py @@ -55,7 +55,7 @@ def place(self, takers): takers[which] -= taken return tuple(takers) - def enterprise_in(self, glyph, dest=None): + def enterprise_in(self, dest=None): ''' Place the ENTERPRISE at the destination, else a random one. Return the x, y location - else False ''' area = self.area() @@ -209,10 +209,14 @@ def random_jump(self): def go_to(self, dest): if self.last_nav: self.enterprise_out() - assert(isinstance(self.sector, int)) - self.sector = dest.sector - self.xpos = dest.xpos - self.ypos = dest.ypos + if dest.sector > 0: + self.sector = dest.sector + if dest.xpos != -1: + self.xpos = dest.xpos + self.ypos = dest.ypos + dest.sector = self.sector + dest.xpos = self.xpos + dest.ypos = self.ypos self.enterprise_in(dest) self.last_nav = dest diff --git a/MapSparse.py b/MapSparse.py index ba18253..bb10942 100644 --- a/MapSparse.py +++ b/MapSparse.py @@ -131,7 +131,7 @@ def place_glyph(self, glyph, dest=None): self.plot_glyph(xpos, ypos, glyph) return xpos, ypos else: - self.plot_glyph(xpos, ypos, glyph) + self.plot_glyph(dest.xpos, dest.ypos, glyph) return dest.xpos, dest.ypos @staticmethod diff --git a/Points.py b/Points.py index 3ec4eaa..867c52b 100644 --- a/Points.py +++ b/Points.py @@ -3,6 +3,13 @@ class Destination(): ''' Zero based, Map navigation ''' def __init__(self, sector=-1, xpos=-1, ypos=-1, warp=0): + if sector > 64: sector = 64 # zOuter Limits =) + if xpos > 7: xpos = 7 + if ypos > 7: ypos = 7 + if xpos < 0: xpos = 0 + if ypos < 0: ypos = 0 + if warp > 10: warp = 10 + if warp < 0: warp = 0 self.warp = warp self.sector = sector self.xpos = xpos diff --git a/Quadrant.py b/Quadrant.py index 06aed5c..bff5aac 100644 --- a/Quadrant.py +++ b/Quadrant.py @@ -54,6 +54,7 @@ def display_area(game, quad): sb += col sb += info[row] sb += f" -=--=--=--=--=--=--=--=- Docked: {game.enterprise.docked}\n" + sb += " a b c d e f g h \n" print(sb, end='') if quad.klingons > 0: diff --git a/ShipKlingon.py b/ShipKlingon.py index 253098f..d597eda 100644 --- a/ShipKlingon.py +++ b/ShipKlingon.py @@ -18,7 +18,10 @@ def from_map(self, xpos, ypos): self.shield_level = 300 + random.randint(0, 199) @staticmethod - def attack(game): + def attack_if_you_can(game): + ''' + IF you ever find yourself in the AREA, then have at USS? + ''' if game.is_testing: return False from Calculators import Calc diff --git a/StarTrek2020.py b/StarTrek2020.py index b2dedfb..4924bf3 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -32,6 +32,9 @@ def run(self): aliens = random.randrange(12, 16) starbases = random.randrange(6, 8) game.game_map.randomize(starbases, stars, aliens) + dest = Destination(64, 5, 5) + game.game_map.go_to(dest) + game.game_map.get_area(64).name = 'Outer Limits' self.print_mission() self.show_strings(TrekStrings.HELM_CMDS) @@ -47,8 +50,12 @@ def run(self): def command_prompt(self): command = self.read("Enter command: ").strip().lower() self.display() - if command == "nav": - Calc.navigation(game) + if command == "nav": # force of habbit? + Calc.warp_navigation(game) + if command == "wsn": + Calc.warp_navigation(game) + if command == "ssn": + Calc.sublight_navigation(game) elif command == "srs": game.enterprise.short_range_scan(game) elif command == "lrs": diff --git a/TrekStrings.py b/TrekStrings.py index af82870..d469678 100644 --- a/TrekStrings.py +++ b/TrekStrings.py @@ -98,7 +98,8 @@ HELM_CMDS = [ "--- Commands -----------------", - "nav = Navigation", + "wsn = Warp Speed Navigator", + "ssn = Sublight Speed Navigator", "srs = Short Range Scan", "lrs = Long Range Scan", "pha = Phaser Control", From 00ca5188c79245a1d60048157534f738f4130270 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Wed, 23 Dec 2020 15:40:37 -0500 Subject: [PATCH 025/100] Collision & Docking Detection. --- .gitignore | 1 + Calculators.py | 4 ++-- ErrorCollision.py | 11 +++++++++ MapGame.py | 59 +++++++++++++++++++++++++++++++---------------- MapSparse.py | 22 +++++++++--------- Quips.py | 28 ++++++++++++++++++++++ README.rst | 2 ++ StarTrek2020.py | 54 ++++++++++++++++++++++++++++++++----------- TrekStrings.py | 14 ++++------- 9 files changed, 139 insertions(+), 56 deletions(-) create mode 100644 ErrorCollision.py diff --git a/.gitignore b/.gitignore index bbb050a..b922ded 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ /__pycache__/ShipStarbase.cpython-37.pyc /__pycache__/ShipKlingon.cpython-37.pyc /__pycache__/ShipEnterprise.cpython-37.pyc +/__pycache__/ErrorCollision.cpython-37.pyc diff --git a/Calculators.py b/Calculators.py index 6359fc3..7b95802 100644 --- a/Calculators.py +++ b/Calculators.py @@ -24,7 +24,7 @@ def sublight_navigation(game): game.display() game.display("Sub-light engines engaged.") game.display() - game.game_map.go_to(dest_sys) + game.move_to(dest_sys) game.time_remaining -= 1 game.star_date += 1 @@ -68,7 +68,7 @@ def warp_navigation(game): game.display() game.enterprise.energy -= energy_required - game.game_map.go_to(dest_sys) + game.move_to(dest_sys) game.time_remaining -= 1 game.star_date += 1 diff --git a/ErrorCollision.py b/ErrorCollision.py new file mode 100644 index 0000000..b957856 --- /dev/null +++ b/ErrorCollision.py @@ -0,0 +1,11 @@ +class ErrorEnterpriseCollision(Exception): + ''' + ... because some problems simpy have to wait ... =) + ''' + def __init__(self, glyph): + super().__init__() + self.glyph = glyph + + + + diff --git a/MapGame.py b/MapGame.py index 5bcd91d..181bd8c 100644 --- a/MapGame.py +++ b/MapGame.py @@ -5,6 +5,7 @@ from ShipKlingon import ShipKlingon from Points import Destination from Quadrant import Quadrant +from ErrorCollision import ErrorEnterpriseCollision import MapSparse @@ -57,19 +58,30 @@ def place(self, takers): def enterprise_in(self, dest=None): ''' Place the ENTERPRISE at the destination, else a - random one. Return the x, y location - else False ''' - area = self.area() + random one. + + Will raise an ErrorEnterpriseCollision, upon same. + + Returns the final x, y location upon success ''' + area = self.pw_area() + berror = False if area: + for p in area._pieces: + if p.xpos == dest.xpos and p.ypos == dest.ypos: + pos = area.place_glyph(Glyphs.ENTERPRISE) + berror = p.glyph pos = area.place_glyph(Glyphs.ENTERPRISE, dest) + if berror: + raise ErrorEnterpriseCollision(berror) if pos: return pos return False def enterprise_location(self): ''' Get Enterprise location. False if not found. ''' - area = self.area() + area = self.pw_area() if area: - for obj in area.objs: + for obj in area._pieces: if obj.glyph == Glyphs.ENTERPRISE: return obj.xpos, obj.ypos return False @@ -82,7 +94,7 @@ def enterprise_out(self): def place_glyph(self, glyph, dest=None): ''' Place the glyph as the destination, else a random one ''' - area = self.area() + area = self.pw_area() if area: pos = area.place_glyph(self, glyph, dest) if pos: @@ -91,11 +103,11 @@ def place_glyph(self, glyph, dest=None): def remove(self, xpos, ypos): ''' Remove ANYTHING from the present AREA ''' - area = self.area() + area = self.pw_area() if area: area.remove(xpos, ypos) - def area(self): + def pw_area(self): ''' Return the internal / sparsely populated AREA object. Return an empty / default AREA upon coordinate error. @@ -119,9 +131,9 @@ def scan_quad(self, sector): def _count_area(self, glyph): ''' Tally the number of glyphs in the AREA ''' count = 0 - area = self.area() + area = self.pw_area() if area: - for obj in area.objs: + for obj in area._pieces: if obj.glyph == glyph: count += 1 return count @@ -134,7 +146,7 @@ def update_counts(self): self.stars += area.count_glyphs(Glyphs.STAR) def remove_items(self, removed): - area = self.area() + area = self.pw_area() for obj in removed: area.remove(obj.xpos, obj.ypos) self.update_counts() @@ -144,7 +156,7 @@ def get_area_klingons(self): Return this Area's data for Kingons, in an array. ''' results = [] - area = self.area() + area = self.pw_area() for data in area.get_data(Glyphs.KLINGON): ship = ShipKlingon() ship.from_map(data.xpos, data.ypos) @@ -166,14 +178,14 @@ def get_area_objects(self): NOTE: Changes to this collection will update Area content. ''' - area = self.area() - return area.objs + area = self.pw_area() + return area._pieces def game_id(self, piece): ''' Uniquely identify a game piece / object. ''' - area = self.area() + area = self.pw_area() num = (area.number * 100) + (piece.ypos * 8) + piece.xpos return f"{piece.glyph[1]}x{num}" @@ -188,25 +200,29 @@ def get_all(self, glyph): return results def quad(self): - area = self.area() + area = self.pw_area() return Quadrant.from_area(area) def get_map(self): ''' Generate AREA map of the present sector. ''' - area = self.area() + area = self.pw_area() return area.get_map() def random_jump(self): dest = Destination( - random.randint(1, 65), + random.randint(1, 64), random.randint(0, 7), random.randint(0, 7) ) - self.go_to(dest) + self._go_to(dest) - def go_to(self, dest): + def _go_to(self, dest): + ''' + Place the main player (Enterprise, for now) into the Area. + Returns the final, effective, player location. + ''' if self.last_nav: self.enterprise_out() if dest.sector > 0: @@ -217,8 +233,11 @@ def go_to(self, dest): dest.sector = self.sector dest.xpos = self.xpos dest.ypos = self.ypos - self.enterprise_in(dest) + pos = self.enterprise_in(dest) + dest.xpos = pos[0] + dest.ypos = pos[1] self.last_nav = dest + return dest def randomize(self, bases=None, stars=None, aliens=None): if not aliens: diff --git a/MapSparse.py b/MapSparse.py index bb10942..253a6bf 100644 --- a/MapSparse.py +++ b/MapSparse.py @@ -38,7 +38,7 @@ def __init__(self): self.name = "" self.number = -1 self.scanned = False - self.objs = [] + self._pieces = [] def is_null(self): ''' @@ -48,21 +48,21 @@ def is_null(self): return dum.name == self.name and \ dum.number == self.number and \ dum.scanned == self.scanned and \ - len(dum.objs) == len(self.objs) + len(dum.objs) == len(self._pieces) def is_empty(self): ''' Checks to see if the Area has anything ...''' - return len(self.objs) == True + return len(self._pieces) == True def items(self): ''' Items in the Area ...''' - return len(self.objs) + return len(self._pieces) def remove(self, xpos, ypos): ''' Remove an item from the Area. ''' - for ss, obj in enumerate(self.objs): + for ss, obj in enumerate(self._pieces): if obj.xpos == xpos and obj.ypos == ypos: - self.objs.remove(obj) + self._pieces.remove(obj) return def get_map(self): @@ -71,7 +71,7 @@ def get_map(self): of Glyphs.SPACE on error. ''' results = [[Glyphs.SPACE for _ in range(8)] for _ in range(8)] - for obj in self.objs: + for obj in self._pieces: results[obj.ypos][obj.xpos] = obj.glyph # ASSURED return results @@ -91,7 +91,7 @@ def range_ok(self, xpos, ypos): def get_data(self, glyph): results = [] - for p in self.objs: + for p in self._pieces: if p.glyph == glyph: results.append(SparseMap.Area.clone(p)) return results @@ -101,7 +101,7 @@ def count_glyphs(self, glyph): Tally the number of glyphs that we have in the Area. ''' count = 0 - for p in self.objs: + for p in self._pieces: if p.glyph == glyph: count += 1 return count @@ -113,11 +113,11 @@ def plot_glyph(self, xpos, ypos, glyph): ''' if self.range_ok(xpos, ypos) is False: return None - for p in self.objs: + for p in self._pieces: if p.xpos is xpos and p.ypos is ypos: p.glyph = glyph return xpos, ypos - self.objs.append(SparseMap.Area.Piece(xpos, ypos, glyph)) + self._pieces.append(SparseMap.Area.Piece(xpos, ypos, glyph)) return xpos, ypos def place_glyph(self, glyph, dest=None): diff --git a/Quips.py b/Quips.py index 99ab47b..085374d 100644 --- a/Quips.py +++ b/Quips.py @@ -53,6 +53,30 @@ " curses: 'Thy fathers spreadeth pox!'", " yells: 'Your mother is progressive!'", ] +MISTAKES = [ + "... the crew was not impressed ...", + "... that's going to leave a mark ...", + "... next time, remember to 'carry the 1'? ...", + "... math lives matter ...", + "... that's coming out of your paycheck ...", + "... this is not a bumper car ...", + "... life can be tough, that way ...", + "... who ordered THAT take-out ...", + "... random is, what random does ...", + "... you've got their attention ...", + "... next time, just text them ...", + "... how rude!", + "... yes, karma CAN hurt ...", + "... life is but a dream!", + "... game over.", + "... they will talk about this one for years.", + "... who is going to pay for this?", + "... galactic insurance premiums skyrocket ...", + "... captain goes down with the starship ...", + "... we'll notify your next-of-kin.", + "... that was not in the script ...", + "... you never did THAT in the simulator ...", + ] class Quips(): @@ -73,6 +97,10 @@ def jibe_defeat(noun): if random.randrange(0, 100) > 25: return f"Another {noun.lower()} defeated." return Quips.jibe(noun, DEFEAT_PREFIX, DEFEAT_SUFFIX) + + @staticmethod + def jibe_fatal_mistake(): + return MISTAKES[random.randrange(0, len(MISTAKES) - 1)] diff --git a/README.rst b/README.rst index 5687f31..a5a985a 100644 --- a/README.rst +++ b/README.rst @@ -6,6 +6,8 @@ So far: * Added random event Quips – should make the game a tad more ‘NPC’? +* Added that classic sublight / in system propulsion system. Warp speeds engines are now a seperate navigational system. + * Heavily re-factored for growth, testing, re-use, and maintenance using modern Python. diff --git a/StarTrek2020.py b/StarTrek2020.py index 4924bf3..6dc60f7 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -1,16 +1,16 @@ import random import TrekStrings - from Console import Con -from Calculators import Calc -from Controls import Control -from Reports import Stats from ShipKlingon import ShipKlingon from ShipStarbase import ShipStarbase from ShipEnterprise import ShipEnterprise -from MapGame import * +from Calculators import Calc +from Controls import Control +from Reports import Stats from Points import Destination +from Quips import Quips +from MapGame import * class Game(Con): @@ -23,6 +23,17 @@ def __init__(self): self.time_remaining = 0 self.destroyed = False + def move_to(self, dest): + pos = self.game_map._go_to(dest) + area = self.game_map.pw_area() + self.enterprise.docked = False + for p in area._pieces: + if p.glyph == Glyphs.STARBASE: + if p.xpos + 1 == pos.xpos or p.ypos + 1 == pos.ypos or \ + p.xpos - 1 == pos.xpos or p.ypos - 1 == pos.ypos: + self.enterprise.docked = True + return pos + def run(self): self.show_strings(TrekStrings.LOGO_TREKER) game.star_date = random.randint(0, 50) + 2250 @@ -33,24 +44,39 @@ def run(self): starbases = random.randrange(6, 8) game.game_map.randomize(starbases, stars, aliens) dest = Destination(64, 5, 5) - game.game_map.go_to(dest) + game.move_to(dest) game.game_map.get_area(64).name = 'Outer Limits' self.print_mission() self.show_strings(TrekStrings.HELM_CMDS) running = True - while running: - self.command_prompt() - running = self.enterprise.energy > 0 and not \ - self.destroyed and self.game_map.klingons > 0 and \ - self.time_remaining > 0 - if not running: - Stats.show_exit_status(game) + try: + while running: + self.command_prompt() + running = self.enterprise.energy > 0 and not \ + self.destroyed and self.game_map.klingons > 0 and \ + self.time_remaining > 0 + if not running: + Stats.show_exit_status(game) + except ErrorEnterpriseCollision as ex: + Stats.show_exit_status(game) + game.display() + if ex.glyph == Glyphs.KLINGON: + self.display("You flew into a KLINGON!") + if ex.glyph == Glyphs.STARBASE: + self.display("You flew into a STARBASE?") + if ex.glyph == Glyphs.STAR: + self.display("You flew into a STAR?") + self.destroyed = True + game.display() + self.display(Quips.jibe_fatal_mistake()) + game.display(';-)') + return False def command_prompt(self): command = self.read("Enter command: ").strip().lower() self.display() - if command == "nav": # force of habbit? + if command == "nav": # force of habit? Calc.warp_navigation(game) if command == "wsn": Calc.warp_navigation(game) diff --git a/TrekStrings.py b/TrekStrings.py index d469678..cb118c6 100644 --- a/TrekStrings.py +++ b/TrekStrings.py @@ -98,15 +98,11 @@ HELM_CMDS = [ "--- Commands -----------------", - "wsn = Warp Speed Navigator", - "ssn = Sublight Speed Navigator", - "srs = Short Range Scan", - "lrs = Long Range Scan", - "pha = Phaser Control", - "tor = Photon Torpedo Control", - "she = Shield Control", - "com = Access Computer", - "qui = Quit the game", + "nav = Warp Speed srs = Short Range Scan", + "sub = Sublight Speed lrs = Long Range Scan", + "pha = Phasers tor = Photon Torpedos", + "she = Shields com = Access Computer", + "qui = Quit", ] CPU_CMDS = [ From ee009a7b3bae9a95f3bd0ebbf577cdd330c85d98 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Thu, 24 Dec 2020 02:43:30 -0500 Subject: [PATCH 026/100] A more classic - yet improved - LRS --- ErrorCollision.py | 2 +- ShipEnterprise.py | 38 ++++++++++++++++++++------------------ TrekStrings.py | 8 +++----- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ErrorCollision.py b/ErrorCollision.py index b957856..5057978 100644 --- a/ErrorCollision.py +++ b/ErrorCollision.py @@ -1,6 +1,6 @@ class ErrorEnterpriseCollision(Exception): ''' - ... because some problems simpy have to wait ... =) + ... because some problems simply have to wait ... =) ''' def __init__(self, glyph): super().__init__() diff --git a/ShipEnterprise.py b/ShipEnterprise.py index 5b58ca6..281edd0 100644 --- a/ShipEnterprise.py +++ b/ShipEnterprise.py @@ -2,6 +2,7 @@ from AbsShip import AbsShip from ShipStarbase import ShipStarbase from Quadrant import Quadrant +import Glyphs class ShipEnterprise(AbsShip): @@ -120,26 +121,27 @@ def long_range_scan(self, game): game.display(Quips.jibe_damage('Long Ranged Scanners')) game.display() return - sb = "" + pw_sector = game.game_map.sector - if pw_sector < 5: - pw_sector = 6 - elif pw_sector > 59: - pw_sector = 59 - dots = None - for peek in range(pw_sector-5, pw_sector + 6): + if pw_sector < 4: + pw_sector = 5 + elif pw_sector > 60: + pw_sector = 60 + lines = [] + for peek in range(pw_sector-4, pw_sector + 5): quad = game.game_map.scan_quad(peek) - lines = \ - (f"| Sector: {quad.number:>02}", - f"Enemies: {quad.klingons:>02}", - f"Bases: {quad.starbases:>02}", - f"Stars: {quad.stars:>03} |") - str_ = ' | '.join(lines) - dots = '-' * len(str_) + "\n" - sb += dots - sb += str_ - game.display(sb) - sb = "" + lines.append(f"SEC: {quad.number:>03}") + lines.append(f"{Glyphs.KLINGON}: {quad.klingons:>03}") + lines.append(f"{Glyphs.STARBASE}: {quad.starbases:>03}") + lines.append(f"{Glyphs.STAR}: {quad.stars:>03}") + dots = ' +' + ('-' * 35) + '+' + game.display(dots) + game.display(' | LONG RANGE SCAN |') game.display(dots) + for ss in range(0,(len(lines)-1),12): + for offs in range(4): + line = f' | {lines[ss+offs]:<9} | {lines[ss+4+offs]:<9} | {lines[ss+8+offs]:<9} |' + game.display(line) + game.display(dots) game.display() diff --git a/TrekStrings.py b/TrekStrings.py index cb118c6..6f28539 100644 --- a/TrekStrings.py +++ b/TrekStrings.py @@ -98,11 +98,9 @@ HELM_CMDS = [ "--- Commands -----------------", - "nav = Warp Speed srs = Short Range Scan", - "sub = Sublight Speed lrs = Long Range Scan", - "pha = Phasers tor = Photon Torpedos", - "she = Shields com = Access Computer", - "qui = Quit", + "nav = Warp Speed srs = Short Range Scan tor = Photon Torpedos", + "sub = Sublight Speed lrs = Long Range Scan pha = Phasers", + "qui = Quit com = Access Computer she = Shields", ] CPU_CMDS = [ From fe1816b9d4faa40e760782b8a728bc056a1cbfeb Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Thu, 24 Dec 2020 02:43:30 -0500 Subject: [PATCH 027/100] A more classic - yet improved - LRS --- ErrorCollision.py | 2 +- ShipEnterprise.py | 38 ++++++++++++++++++++------------------ StarTrek2020.py | 6 ++---- TrekStrings.py | 8 +++----- 4 files changed, 26 insertions(+), 28 deletions(-) diff --git a/ErrorCollision.py b/ErrorCollision.py index b957856..5057978 100644 --- a/ErrorCollision.py +++ b/ErrorCollision.py @@ -1,6 +1,6 @@ class ErrorEnterpriseCollision(Exception): ''' - ... because some problems simpy have to wait ... =) + ... because some problems simply have to wait ... =) ''' def __init__(self, glyph): super().__init__() diff --git a/ShipEnterprise.py b/ShipEnterprise.py index 5b58ca6..281edd0 100644 --- a/ShipEnterprise.py +++ b/ShipEnterprise.py @@ -2,6 +2,7 @@ from AbsShip import AbsShip from ShipStarbase import ShipStarbase from Quadrant import Quadrant +import Glyphs class ShipEnterprise(AbsShip): @@ -120,26 +121,27 @@ def long_range_scan(self, game): game.display(Quips.jibe_damage('Long Ranged Scanners')) game.display() return - sb = "" + pw_sector = game.game_map.sector - if pw_sector < 5: - pw_sector = 6 - elif pw_sector > 59: - pw_sector = 59 - dots = None - for peek in range(pw_sector-5, pw_sector + 6): + if pw_sector < 4: + pw_sector = 5 + elif pw_sector > 60: + pw_sector = 60 + lines = [] + for peek in range(pw_sector-4, pw_sector + 5): quad = game.game_map.scan_quad(peek) - lines = \ - (f"| Sector: {quad.number:>02}", - f"Enemies: {quad.klingons:>02}", - f"Bases: {quad.starbases:>02}", - f"Stars: {quad.stars:>03} |") - str_ = ' | '.join(lines) - dots = '-' * len(str_) + "\n" - sb += dots - sb += str_ - game.display(sb) - sb = "" + lines.append(f"SEC: {quad.number:>03}") + lines.append(f"{Glyphs.KLINGON}: {quad.klingons:>03}") + lines.append(f"{Glyphs.STARBASE}: {quad.starbases:>03}") + lines.append(f"{Glyphs.STAR}: {quad.stars:>03}") + dots = ' +' + ('-' * 35) + '+' + game.display(dots) + game.display(' | LONG RANGE SCAN |') game.display(dots) + for ss in range(0,(len(lines)-1),12): + for offs in range(4): + line = f' | {lines[ss+offs]:<9} | {lines[ss+4+offs]:<9} | {lines[ss+8+offs]:<9} |' + game.display(line) + game.display(dots) game.display() diff --git a/StarTrek2020.py b/StarTrek2020.py index 6dc60f7..6f79283 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -76,11 +76,9 @@ def run(self): def command_prompt(self): command = self.read("Enter command: ").strip().lower() self.display() - if command == "nav": # force of habit? + if command == "nav": Calc.warp_navigation(game) - if command == "wsn": - Calc.warp_navigation(game) - if command == "ssn": + if command == "sub": Calc.sublight_navigation(game) elif command == "srs": game.enterprise.short_range_scan(game) diff --git a/TrekStrings.py b/TrekStrings.py index cb118c6..6f28539 100644 --- a/TrekStrings.py +++ b/TrekStrings.py @@ -98,11 +98,9 @@ HELM_CMDS = [ "--- Commands -----------------", - "nav = Warp Speed srs = Short Range Scan", - "sub = Sublight Speed lrs = Long Range Scan", - "pha = Phasers tor = Photon Torpedos", - "she = Shields com = Access Computer", - "qui = Quit", + "nav = Warp Speed srs = Short Range Scan tor = Photon Torpedos", + "sub = Sublight Speed lrs = Long Range Scan pha = Phasers", + "qui = Quit com = Access Computer she = Shields", ] CPU_CMDS = [ From fecd7d76a2869a72b71840dc4ffc1800c1dbc5e9 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Thu, 24 Dec 2020 03:58:28 -0500 Subject: [PATCH 028/100] Docking assured. Safe warp-ins enabled. --- Calculators.py | 2 +- Console.py | 12 +++---- ErrorCollision.py | 2 -- MapGame.py | 34 ++++++++++++-------- Points.py | 81 +++++++++++++++++++---------------------------- StarTrek2020.py | 6 ++-- 6 files changed, 63 insertions(+), 74 deletions(-) diff --git a/Calculators.py b/Calculators.py index 7b95802..494e0db 100644 --- a/Calculators.py +++ b/Calculators.py @@ -3,7 +3,7 @@ from MapGame import * from AbsShip import * -from Points import Destination +from Points import * class Calc(): diff --git a/Console.py b/Console.py index 5558554..513ac60 100644 --- a/Console.py +++ b/Console.py @@ -1,5 +1,5 @@ from AbsDisplay import abs_display -from Points import Destination +from Points import * class Con(abs_display): ''' @@ -33,19 +33,15 @@ def read_xypos(self, prompt = "Location (alpha,num)"): Example: b,4 ''' text = input(prompt + ': ') - return Destination.parse_xypos(text) + return SubDest.parse(text) def read_sector(self, prompt= "Helm: sector 1-64, speed 1.0-9.0?"): text = input(prompt + ': ') - return Destination.parse_warp(text) - - def read_nav(self, prompt= "Helm: sector 1-64, a-h, 1-8?"): - text = input(prompt + ': ') - return Destination.parse_sector(text) + return WarpDest.parse(text) def read_xypos(self, prompt= "Helm: a-h, 1-8?"): text = input(prompt + ': ') - return Destination.parse_xypos(text) + return SubDest.parse(text) if __name__ == '__main__': diff --git a/ErrorCollision.py b/ErrorCollision.py index 5057978..bab439b 100644 --- a/ErrorCollision.py +++ b/ErrorCollision.py @@ -7,5 +7,3 @@ def __init__(self, glyph): self.glyph = glyph - - diff --git a/MapGame.py b/MapGame.py index 181bd8c..f278680 100644 --- a/MapGame.py +++ b/MapGame.py @@ -3,7 +3,7 @@ import Glyphs from ShipKlingon import ShipKlingon -from Points import Destination +from Points import * from Quadrant import Quadrant from ErrorCollision import ErrorEnterpriseCollision @@ -58,12 +58,14 @@ def place(self, takers): def enterprise_in(self, dest=None): ''' Place the ENTERPRISE at the destination, else a - random one. + random one. Will raise an ErrorEnterpriseCollision, upon same. Returns the final x, y location upon success ''' area = self.pw_area() + if not dest: + return area.place_glyph(Glyphs.ENTERPRISE) berror = False if area: for p in area._pieces: @@ -211,7 +213,7 @@ def get_map(self): return area.get_map() def random_jump(self): - dest = Destination( + dest = SubDest( random.randint(1, 64), random.randint(0, 7), random.randint(0, 7) @@ -219,21 +221,27 @@ def random_jump(self): self._go_to(dest) def _go_to(self, dest): - ''' + ''' Either a WARP ~or~ a SUBSPACE destination is ok. Place the main player (Enterprise, for now) into the Area. Returns the final, effective, player location. ''' + if not dest: + return if self.last_nav: self.enterprise_out() - if dest.sector > 0: - self.sector = dest.sector - if dest.xpos != -1: - self.xpos = dest.xpos - self.ypos = dest.ypos - dest.sector = self.sector - dest.xpos = self.xpos - dest.ypos = self.ypos - pos = self.enterprise_in(dest) + pos = None + if isinstance(dest, WarpDest): + if dest.sector > 0: + self.sector = dest.sector + dest.sector = self.sector + pos = self.enterprise_in() # SAFE WARP-IN! + else: + if dest.xpos != -1: + self.xpos = dest.xpos + self.ypos = dest.ypos + dest.xpos = self.xpos + dest.ypos = self.ypos + pos = self.enterprise_in(dest) # CAPIN' KNOWS BEST? dest.xpos = pos[0] dest.ypos = pos[1] self.last_nav = dest diff --git a/Points.py b/Points.py index 867c52b..7825906 100644 --- a/Points.py +++ b/Points.py @@ -1,41 +1,52 @@ - - -class Destination(): - ''' Zero based, Map navigation ''' - def __init__(self, sector=-1, xpos=-1, ypos=-1, warp=0): +class WarpDest(): + ''' Warp Speed: + One's based GALAXY navigation. + Guaranteed SAFE placement. + ''' + def __init__(self, sector=-1, warp=0): if sector > 64: sector = 64 # zOuter Limits =) - if xpos > 7: xpos = 7 - if ypos > 7: ypos = 7 - if xpos < 0: xpos = 0 - if ypos < 0: ypos = 0 if warp > 10: warp = 10 if warp < 0: warp = 0 self.warp = warp self.sector = sector - self.xpos = xpos - self.ypos = ypos @staticmethod - def parse_sector(dest, sep=','): + def parse(dest, sep=','): ''' - Parse: sector#, alpha-col, row-num - Example: 5,b,1 + Parse: sector-num, speed-float - None on error + Example: 5,1.1 ''' dest = str(dest) cols = dest.split(sep) - if len(cols) == 3: + if len(cols) == 2: try: - sector = int(cols[0]) % 8 - if str(cols[1]).isalpha(): - xpos = ((ord(cols[1]) - ord('a')) % 8) - ypos = int(cols[2]) % 8 - return Destination(sector, xpos, ypos) + sector = int(cols[0].strip()) + if sector < 1: + sector = 1 + speed = float(cols[1].strip()) + if speed < 0: speed = 0.1 + if speed > 9: speed = 9.0 + return WarpDest(sector, speed) except: pass return None + +class SubDest(): + ''' Sublight Navigation: + Zero based, AREA placement. + Caveat, User! ;-) + ''' + def __init__(self, xpos=-1, ypos=-1): + if xpos > 7: xpos = 7 + if ypos > 7: ypos = 7 + if xpos < 0: xpos = 0 + if ypos < 0: ypos = 0 + self.xpos = xpos + self.ypos = ypos + @staticmethod - def parse_xypos(dest, sep=','): + def parse(dest, sep=','): ''' WARNING: USER 1's -> 0-BASED TRANSLATION HERE @@ -57,34 +68,8 @@ def parse_xypos(dest, sep=','): num = int(alph) xpos = num ypos = int(cols[1].strip()[0]) - return Destination(-1, xpos-1, ypos-1, -1) + return SubDest(xpos-1, ypos-1) except: pass return None - @staticmethod - def parse_warp(dest, sep=','): - ''' - Parse: sector-num, speed-float - None on error - Example: 5,1.1 - ''' - dest = str(dest) - cols = dest.split(sep) - if len(cols) == 2: - try: - sector = int(cols[0].strip()) - if sector < 1: - sector = 1 - speed = float(cols[1].strip()) - if speed < 0: speed = 0.1 - if speed > 9: speed = 9.0 - return Destination(sector, -1, -1, speed) - except: - pass - return None - - - - - - diff --git a/StarTrek2020.py b/StarTrek2020.py index 6f79283..0c06c22 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -8,7 +8,7 @@ from Calculators import Calc from Controls import Control from Reports import Stats -from Points import Destination +from Points import * from Quips import Quips from MapGame import * @@ -32,6 +32,7 @@ def move_to(self, dest): if p.xpos + 1 == pos.xpos or p.ypos + 1 == pos.ypos or \ p.xpos - 1 == pos.xpos or p.ypos - 1 == pos.ypos: self.enterprise.docked = True + ShipStarbase.dock_enterprise(self.enterprise) return pos def run(self): @@ -43,7 +44,7 @@ def run(self): aliens = random.randrange(12, 16) starbases = random.randrange(6, 8) game.game_map.randomize(starbases, stars, aliens) - dest = Destination(64, 5, 5) + dest = WarpDest(64, 0) game.move_to(dest) game.game_map.get_area(64).name = 'Outer Limits' self.print_mission() @@ -70,6 +71,7 @@ def run(self): self.destroyed = True game.display() self.display(Quips.jibe_fatal_mistake()) + game.display() game.display(';-)') return False From 110c8db2e9a52fc1dd4ef17d3f00fb3527e8da85 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Thu, 24 Dec 2020 04:55:00 -0500 Subject: [PATCH 029/100] Game coodrinates assured. --- MapGame.py | 4 ++-- StarTrek2020.py | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/MapGame.py b/MapGame.py index f278680..00a6dd2 100644 --- a/MapGame.py +++ b/MapGame.py @@ -242,8 +242,8 @@ def _go_to(self, dest): dest.xpos = self.xpos dest.ypos = self.ypos pos = self.enterprise_in(dest) # CAPIN' KNOWS BEST? - dest.xpos = pos[0] - dest.ypos = pos[1] + self.xpos = dest.xpos = pos[0] + self.ypos = dest.ypos = pos[1] self.last_nav = dest return dest diff --git a/StarTrek2020.py b/StarTrek2020.py index 0c06c22..5873ebf 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -26,6 +26,7 @@ def __init__(self): def move_to(self, dest): pos = self.game_map._go_to(dest) area = self.game_map.pw_area() + was_docked = self.enterprise.docked self.enterprise.docked = False for p in area._pieces: if p.glyph == Glyphs.STARBASE: @@ -33,6 +34,8 @@ def move_to(self, dest): p.xpos - 1 == pos.xpos or p.ypos - 1 == pos.ypos: self.enterprise.docked = True ShipStarbase.dock_enterprise(self.enterprise) + if was_docked and self.enterprise.docked == False: + ShipStarbase.launch_enterprise(self.enterprise) return pos def run(self): From 1ed13d083f9d55137dbd6226ed798e1141f85591 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Thu, 24 Dec 2020 14:16:19 -0500 Subject: [PATCH 030/100] Title changed + link to introductory video. --- README.rst | 6 +++++- TrekStrings.py | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index a5a985a..0ba3db6 100644 --- a/README.rst +++ b/README.rst @@ -1,8 +1,11 @@ +The original free-and-open StarTrek console game was THE most played game of the day .... back in the 1970's! + + So far: * Converted from Python 2, to Python 3. -* Simplifying coordinate calculations - kudos for the idea! +* Changed in-system coordinates to simple 'chess like' (b,4 (etc)) references. * Added random event Quips – should make the game a tad more ‘NPC’? @@ -10,6 +13,7 @@ So far: * Heavily re-factored for growth, testing, re-use, and maintenance using modern Python. +Video: https://youtu.be/TpmtCLOJ5Uw Original authors did an excellent job here - made the modernization a WHOLE LOT easier! diff --git a/TrekStrings.py b/TrekStrings.py index 6f28539..009f66d 100644 --- a/TrekStrings.py +++ b/TrekStrings.py @@ -5,7 +5,8 @@ _\ \ / / / __ // __/ / / / __/ / __ / / / / /_/ / / / / / / // /\ \ / / / /\ \ / /___ / /\ \ /_____/ /_/ /_/ /_//_/ \_\ /_/ /_/ \_\/_____//_/ \_\ - + + 1971 - 2020 ________________ _ \__(=======/_=_/____.--'-`--.___ \ \ `,--,-.___.----' From e4bd3a45b3ebf6b6928530b8dd8381ac116c1d93 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Fri, 25 Dec 2020 02:17:48 -0500 Subject: [PATCH 031/100] Random damage & probability updates. --- .gitignore | 2 + AbsShip.py | 2 +- Calculators.py | 15 ++-- Controls.py | 32 +++++---- Difficulity.py | 49 +++++++++++++ MapGame.py | 149 +++++++++++++++++++++++---------------- MapSparse.py | 8 +-- Quips.py | 33 ++++----- Reports.py | 18 ++--- Quadrant.py => Sector.py | 28 ++++---- ShipEnterprise.py | 36 +++++----- ShipKlingon.py | 2 +- StarTrek2020.py | 26 ++++--- test_MapSparse.py | 6 +- 14 files changed, 244 insertions(+), 162 deletions(-) create mode 100644 Difficulity.py rename Quadrant.py => Sector.py (76%) diff --git a/.gitignore b/.gitignore index b922ded..e7cf513 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,5 @@ /__pycache__/ShipKlingon.cpython-37.pyc /__pycache__/ShipEnterprise.cpython-37.pyc /__pycache__/ErrorCollision.cpython-37.pyc +/__pycache__/Sector.cpython-37.pyc +/__pycache__/Difficulity.cpython-37.pyc diff --git a/AbsShip.py b/AbsShip.py index 4b856a3..958cf3b 100644 --- a/AbsShip.py +++ b/AbsShip.py @@ -3,7 +3,7 @@ import Glyphs from Quips import Quips -from Quadrant import Quadrant +from Sector import Sector class AbsShip(abc.ABC): ''' The first step, into a much larger universe ... ''' diff --git a/Calculators.py b/Calculators.py index 494e0db..1ffca4a 100644 --- a/Calculators.py +++ b/Calculators.py @@ -4,6 +4,7 @@ from MapGame import * from AbsShip import * from Points import * +from Difficulity import Probabilities class Calc(): @@ -36,11 +37,11 @@ def sublight_navigation(game): game.display("Enterprise successfully docked with starbase.") game.display() else: - if game.game_map.klingons > 0: + if game.game_map.count_area_klingons() > 0: ShipKlingon.attack_if_you_can(game) game.display() elif not game.enterprise.repair(game): - game.enterprise.damage(game, -1) + game.enterprise.damage(game, Probabilities.LRS) @staticmethod def warp_navigation(game): @@ -80,11 +81,11 @@ def warp_navigation(game): game.display("Enterprise successfully docked with starbase.") game.display() else: - if game.game_map.klingons > 0: + if game.game_map.count_area_klingons() > 0: ShipKlingon.attack_if_you_can(game) game.display() elif not game.enterprise.repair(game): - game.enterprise.damage(game, -1) + game.enterprise.damage(game, Probabilities.RANDOM) @staticmethod @@ -107,7 +108,7 @@ def show_torp_targets(game): game.display() kships = game.game_map.get_area_klingons() if len(kships) == 0: - game.display("There are no enemies in this quadrant.") + game.display("There are no enemies in this sector.") return game.display("Enemies:") @@ -115,7 +116,3 @@ def show_torp_targets(game): game.display(f"\tKlingon [{ship.xpos},{ship.ypos}].") game.display() - - - - diff --git a/Controls.py b/Controls.py index 3f07f37..b56f74d 100644 --- a/Controls.py +++ b/Controls.py @@ -9,6 +9,7 @@ from Calculators import Calc from Reports import Stats from Quips import Quips +from Difficulity import Probabilities class Control(): @@ -32,7 +33,7 @@ def computer(game): game.display() game.display("Invalid computer command.") game.display() - game.enterprise.damage(game, 4) + game.enterprise.damage(game, Probabilities.COMPUTER) @staticmethod @@ -43,7 +44,7 @@ def phasers(game): return kships = game.game_map.get_area_klingons() if len(kships) == 0: - game.display("There are no Klingon ships in this quadrant.") + game.display("There are no Klingon ships in this sector.") game.display() return game.display("Phasers locked on target.") @@ -72,11 +73,12 @@ def phasers(game): else: game.display(f"Hit ship at [{ship.xpos + 1},{ship.ypos + 1}].") game.display(f"Enemy shield down to {ship.shield_level}.") - game.game_map.remove_items(destroyed_ships) - if game.game_map.klingons > 0: + game.game_map.remove_area_items(destroyed_ships) + if game.game_map.count_area_klingons() > 0: game.display() ShipKlingon.attack_if_you_can(game) game.display() + game.enterprise.damage(game, Probabilities.PHASERS) def shields(game): @@ -111,6 +113,7 @@ def shields(game): game.enterprise.shield_level -= int(transfer) game.display("Shield strength is now {0}. Energy level is now {1}.".format(game.enterprise.shield_level, game.enterprise.energy)) game.display() + game.enterprise.damage(game, Probabilities.SHIELDS) def torpedos(game): @@ -122,8 +125,8 @@ def torpedos(game): game.display("Photon torpedoes exhausted.") game.display() return - if len(game.game_map.get_area_klingons()) == 0: - game.display("There are no Klingon ships in this quadrant.") + if game.game_map.count_area_klingons() == 0: + game.display("There are no Klingon ships in this sector.") game.display() return shot = game.read_xypos() @@ -140,33 +143,34 @@ def torpedos(game): print(f'{ship.glyph}({ship.xpos},{ship.ypos}), shot({shot.xpos},{shot.ypos})') if ship.xpos == shot.xpos and ship.ypos == shot.ypos: if ship.glyph == Glyphs.KLINGON: - num = game.game_map.game_id(ship) + num = game.game_map.get_game_id(ship) game.display(f"Klingon ship #{num} destroyed.") game.display(Quips.jibe_defeat('enemy')) - game.game_map.remove_items([ship]) + game.game_map.remove_area_items([ship]) hit = True break elif ship.glyph == Glyphs.STARBASE: - game.game_map.starbases -= 1 - num = game.game_map.game_id(ship) + game.game_map.game_starbases -= 1 + num = game.game_map.get_game_id(ship) game.display("Federation Starbase #{num} destroyed!") game.display(Quips.jibe_defeat('commander')) - game.game_map.remove_items([ship]) + game.game_map.remove_area_items([ship]) hit = True break elif ship.glyph == Glyphs.STAR: - num = game.game_map.game_id(ship) + num = game.game_map.get_game_id(ship) game.display(f"Torpedo vaporizes star #{num}!") game.display(Quips.jibe_defeat('academic')) - game.game_map.remove_items([ship]) + game.game_map.remove_area_items([ship]) hit = True break if not hit: game.display("Torpedo missed.") - if len(game.game_map.get_area_klingons()) > 0: + if game.game_map.count_area_klingons() > 0: game.display() ShipKlingon.attack_if_you_can(game) game.display() + game.enterprise.damage(game, Probabilities.PHOTON) diff --git a/Difficulity.py b/Difficulity.py new file mode 100644 index 0000000..53a0410 --- /dev/null +++ b/Difficulity.py @@ -0,0 +1,49 @@ +import random + +class Probabilities: + ''' + Extracting allows for easier customization. + ''' + _LEVEL = 4 + RANDOM = -1 + NAV = 0 + SRS = 1 + LRS = 2 + SHIELDS = 3 + COMPUTER = 4 + PHOTON = 5 + PHASERS = 6 + + @staticmethod + def set_difficulity(game, level): + ''' + The HIGHER the level, the MORE difficult + the game will be. 0 = EASY, 6 = HIGHEST + ''' + if level < 0: level = 0 + if level > 6: level = 6 + Probabilities._LEVEL = level + + @staticmethod + def calc_damage(game, item): + ''' + How mch damage? + ''' + return random.randint(1, 3) + + @staticmethod + def should_damage_enterprise(game, item): + ''' + Should we damage? + Lowest level (above) eliminates damage to ITEM + ''' + if game.is_testing: + return False + if item == Probabilities.SHIELDS: + return False + if random.randint(0, 6) < Probabilities._LEVEL: + return True + return False + + + diff --git a/MapGame.py b/MapGame.py index 00a6dd2..3eb8026 100644 --- a/MapGame.py +++ b/MapGame.py @@ -4,7 +4,7 @@ import Glyphs from ShipKlingon import ShipKlingon from Points import * -from Quadrant import Quadrant +from Sector import Sector from ErrorCollision import ErrorEnterpriseCollision import MapSparse @@ -15,9 +15,9 @@ def __init__(self): super().__init__() self.sector = -1 self.xpos = self.ypos = -1 - self.stars = -1 - self.klingons = -1 - self.starbases = -1 + self.game_stars = -1 + self.game_klingons = -1 + self.game_starbases = -1 self.last_nav = None def place(self, takers): @@ -30,16 +30,16 @@ def place(self, takers): for which, nelem in enumerate(takers): if not nelem: continue - to_take = random.randrange(0, nelem) + to_take = random.randint(0, nelem) if nelem is 1: to_take = 1 if not to_take: continue taken = 0 while taken != to_take: - ss = random.randrange(1, 64) + ss = random.randrange(1, 64) # Ignore "Outer Limits" area = self.get_area(ss) - should_take = random.randrange(1, 8) + should_take = random.randint(1, 8) if which is 0: if area.count_glyphs(Glyphs.STARBASE) != 0: continue @@ -57,12 +57,14 @@ def place(self, takers): return tuple(takers) def enterprise_in(self, dest=None): - ''' Place the ENTERPRISE at the destination, else a + ''' + Place the ENTERPRISE at the destination, else a random one. Will raise an ErrorEnterpriseCollision, upon same. - Returns the final x, y location upon success ''' + Returns the final x, y location upon success + ''' area = self.pw_area() if not dest: return area.place_glyph(Glyphs.ENTERPRISE) @@ -80,7 +82,9 @@ def enterprise_in(self, dest=None): return False def enterprise_location(self): - ''' Get Enterprise location. False if not found. ''' + ''' + Get Enterprise location. False if not found. + ''' area = self.pw_area() if area: for obj in area._pieces: @@ -88,14 +92,18 @@ def enterprise_location(self): return obj.xpos, obj.ypos return False - def enterprise_out(self): - ''' Remove the ENTERPRISE from the present AREA ''' + def enterprise_out(self)->None: + ''' + Remove the ENTERPRISE from the present AREA + ''' pos = self.enterprise_location() if pos: - self.remove(*pos) + self.clear_area(*pos) - def place_glyph(self, glyph, dest=None): - ''' Place the glyph as the destination, else a random one ''' + def place_glyph(self, glyph, dest=None)->bool: + ''' + Place the glyph at the destination, else a random one + ''' area = self.pw_area() if area: pos = area.place_glyph(self, glyph, dest) @@ -103,13 +111,15 @@ def place_glyph(self, glyph, dest=None): return True return False - def remove(self, xpos, ypos): - ''' Remove ANYTHING from the present AREA ''' + def clear_area(self, xpos, ypos)->None: + ''' + Remove ANYTHING from the present AREA + ''' area = self.pw_area() if area: area.remove(xpos, ypos) - def pw_area(self): + def pw_area(self)->MapSparse.SparseMap.Area: ''' Return the internal / sparsely populated AREA object. Return an empty / default AREA upon coordinate error. @@ -120,18 +130,38 @@ def pw_area(self): return area return MapSparse.SparseMap.Area() - def scan_quad(self, sector): + def scan_sector(self, sector)->Sector: ''' - Return a scan (LRS?) for a specific quadrant. - Return empty quadrant, on error. + Return Sector() information (e.g. LRS) for a specific AREA. + Return empty Sector() upon error. ''' area = self.get_area(sector) if area: - return Quadrant.from_area(area) - return Quadrant() + return Sector.from_area(area) + return Sector() + + def count_area_klingons(self)->int: + ''' + How many surround, U.S.S? + ''' + return self._count_area(Glyphs.KLINGON) + + def count_area_starbases(self)->int: + ''' + How many surround, U.S.S? + ''' + return self._count_area(Glyphs.STARBASE) + + def count_area_stars(self)->int: + ''' + How many surround, U.S.S? + ''' + return self._count_area(Glyphs.STAR) - def _count_area(self, glyph): - ''' Tally the number of glyphs in the AREA ''' + def _count_area(self, glyph)->int: + ''' + Tally the number of glyphs in the DEFAULT AREA + ''' count = 0 area = self.pw_area() if area: @@ -140,20 +170,29 @@ def _count_area(self, glyph): count += 1 return count - def update_counts(self): - self.klingons = self.starbases = self.stars = 0 + def update_counts(self)->None: + ''' + Update this map's official game-pieces-in-play tally + ''' + self.game_klingons = self.game_starbases = self.game_stars = 0 for area in self.areas(): - self.klingons += area.count_glyphs(Glyphs.KLINGON) - self.starbases += area.count_glyphs(Glyphs.STARBASE) - self.stars += area.count_glyphs(Glyphs.STAR) + self.game_klingons += area.count_glyphs(Glyphs.KLINGON) + self.game_starbases += area.count_glyphs(Glyphs.STARBASE) + self.game_stars += area.count_glyphs(Glyphs.STAR) + area = self.get_area() + - def remove_items(self, removed): + def remove_area_items(self, piece_array)->None: + ''' + Remove a collection of pieces (e.g. ships), + from the PRESENT / default AREA. + ''' area = self.pw_area() - for obj in removed: + for obj in piece_array: area.remove(obj.xpos, obj.ypos) self.update_counts() - def get_area_klingons(self): + def get_area_klingons(self)->list: ''' Return this Area's data for Kingons, in an array. ''' @@ -165,16 +204,7 @@ def get_area_klingons(self): results.append(ship) return results - def num_area_klingons(self): - return self._count_area(Glyphs.KLINGON) - - def num_area_starbases(self): - return self._count_area(Glyphs.STARBASE) - - def num_area_stars(self): - return self._count_area(Glyphs.STAR) - - def get_area_objects(self): + def get_area_objects(self)->list: ''' Return the actual objects, as located in the Area. NOTE: Changes to this collection will update Area @@ -183,7 +213,7 @@ def get_area_objects(self): area = self.pw_area() return area._pieces - def game_id(self, piece): + def get_game_id(self, piece)->str: ''' Uniquely identify a game piece / object. ''' @@ -191,7 +221,7 @@ def game_id(self, piece): num = (area.number * 100) + (piece.ypos * 8) + piece.xpos return f"{piece.glyph[1]}x{num}" - def get_all(self, glyph): + def get_all(self, glyph)->list: ''' Return [ [AREA, PIECE], ... ] for every glyph found. ''' @@ -201,25 +231,20 @@ def get_all(self, glyph): results.append([area, piece]) return results - def quad(self): + def get_pw_sector(self)->Sector: + ''' + Create a Sector() report for the DEFAULT AREA + ''' area = self.pw_area() - return Quadrant.from_area(area) + return Sector.from_area(area) - def get_map(self): + def get_map(self)->list: ''' Generate AREA map of the present sector. ''' area = self.pw_area() return area.get_map() - def random_jump(self): - dest = SubDest( - random.randint(1, 64), - random.randint(0, 7), - random.randint(0, 7) - ) - self._go_to(dest) - def _go_to(self, dest): ''' Either a WARP ~or~ a SUBSPACE destination is ok. Place the main player (Enterprise, for now) into the Area. @@ -247,14 +272,14 @@ def _go_to(self, dest): self.last_nav = dest return dest - def randomize(self, bases=None, stars=None, aliens=None): + def randomize(self, bases=None, stars=None, aliens=None)->None: if not aliens: - aliens = 15 + random.randint(0, 5) + aliens = random.randint(5, 10) if not bases: - bases = 2 + random.randint(0, 2) - self.starbases = bases - self.klingons = aliens - self.stars = stars + bases = random.randint(2, 4) + self.game_starbases = bases + self.game_klingons = aliens + self.game_stars = stars self.init() takers = bases, stars, aliens while takers: diff --git a/MapSparse.py b/MapSparse.py index 253a6bf..557bc7b 100644 --- a/MapSparse.py +++ b/MapSparse.py @@ -65,7 +65,7 @@ def remove(self, xpos, ypos): self._pieces.remove(obj) return - def get_map(self): + def get_map(self)->list: ''' Generate a map of this AREA. Map is full of Glyphs.SPACE on error. @@ -125,8 +125,8 @@ def place_glyph(self, glyph, dest=None): area = self.get_map() if not dest: while True: - xpos = random.randrange(0,7) - ypos = random.randrange(0,7) + xpos = random.randint(0,7) + ypos = random.randint(0,7) if area[xpos][ypos] == Glyphs.SPACE: self.plot_glyph(xpos, ypos, glyph) return xpos, ypos @@ -190,7 +190,7 @@ def name_areas(self): ''' names = list(TrekStrings.AREA_NAMES) for num, area in enumerate(self.areas(),1): - index = random.randint(0, len(names) - 1) + index = random.randrange(0, len(names)) area.name = names[index] area.number = num del names[index] diff --git a/Quips.py b/Quips.py index 085374d..fa9d6c0 100644 --- a/Quips.py +++ b/Quips.py @@ -28,7 +28,7 @@ ] DEFEAT_SUFFIX = [ " says: `I'll be back!`", - " cries: ... 'a lucky shot!'", + " cries: 'lucky shot!'", " sighs bitterly.", " dies.", " is rescued.", @@ -38,20 +38,16 @@ " is eliminated.", " was aborted. Few lives, matter?", " ejects.", + " was confused.", " crew is rescued.", " crew is spaced.", " crew is recycled.", " crew is recovered.", - " yells: 'Thy mother mates poorly!'", " snarls: 'Lucky shot.'", " laughs: 'You'll not do THAT again!'", " says nothing.", - " screams: 'Thy father is a Targ!'", - " yells: 'Your parents eat bats!'", - " snarls: 'Thy people eat vermin!'", - " yells: 'May you create social disease!'", - " curses: 'Thy fathers spreadeth pox!'", - " yells: 'Your mother is progressive!'", + " screams: 'Thy father was a Targ!'", + " yells: 'Thy mother is progressive!'", ] MISTAKES = [ "... the crew was not impressed ...", @@ -59,18 +55,17 @@ "... next time, remember to 'carry the 1'? ...", "... math lives matter ...", "... that's coming out of your paycheck ...", - "... this is not a bumper car ...", + "... this is not a bumpy car ...", "... life can be tough, that way ...", "... who ordered THAT take-out ...", "... random is, what random does ...", "... you've got their attention ...", - "... next time, just text them ...", "... how rude!", "... yes, karma CAN hurt ...", "... life is but a dream!", "... game over.", - "... they will talk about this one for years.", - "... who is going to pay for this?", + "... they will talk about this for years.", + "... who is going to pay for that?", "... galactic insurance premiums skyrocket ...", "... captain goes down with the starship ...", "... we'll notify your next-of-kin.", @@ -82,25 +77,25 @@ class Quips(): @staticmethod def jibe(noun, prefix, suffix): - prand = random.randrange(0, len(prefix) - 1) - srand = random.randrange(0, len(suffix) - 1) + prand = random.randint(0, len(prefix) - 1) + srand = random.randint(0, len(suffix) - 1) return prefix[prand] + noun + suffix[srand] @staticmethod def jibe_damage(noun): - if random.randrange(0, 100) > 25: + if random.randint(0, 100) > 25: return f"{noun.capitalize()} damaged. Repairs are underway." - return Quips.jibe(noun, DAMAGE_PREFIX, DAMAGE_SUFFIX) + return Quips.jibe(noun.lower(), DAMAGE_PREFIX, DAMAGE_SUFFIX) @staticmethod def jibe_defeat(noun): - if random.randrange(0, 100) > 25: + if random.randint(0, 100) > 25: return f"Another {noun.lower()} defeated." - return Quips.jibe(noun, DEFEAT_PREFIX, DEFEAT_SUFFIX) + return Quips.jibe(noun.lower(), DEFEAT_PREFIX, DEFEAT_SUFFIX) @staticmethod def jibe_fatal_mistake(): - return MISTAKES[random.randrange(0, len(MISTAKES) - 1)] + return MISTAKES[random.randint(0, len(MISTAKES) - 1)] diff --git a/Reports.py b/Reports.py index e079b6e..73e87d2 100644 --- a/Reports.py +++ b/Reports.py @@ -1,13 +1,15 @@ import Glyphs class Stats(): - + ''' + Reports do not generate damage. + ''' @staticmethod def show_ship_status(game): game.display() game.display(f" Time Remaining: {game.time_remaining}") - game.display(f" Klingon Ships Remaining: {game.game_map.klingons}") - game.display(f" Starbases: {game.game_map.starbases}") + game.display(f" Klingon Ships Remaining: {game.game_map.game_klingons}") + game.display(f" Starbases: {game.game_map.game_starbases}") game.display(f" Warp Engine Damage: {game.enterprise.navigation_damage}") game.display(f" Short Range Scanner Damage: {game.enterprise.short_range_scan_damage}") game.display(f" Long Range Scanner Damage: {game.enterprise.long_range_scan_damage}") @@ -17,19 +19,17 @@ def show_ship_status(game): game.display(f" Phaser Damage: {game.enterprise.phaser_damage}") game.display() - @staticmethod def show_galactic_status(game): game.display() - str_ = f"| KLINGONS: {game.game_map.klingons:>04} | " + \ - f"STARBASES: {game.game_map.starbases:>04} | " + \ - f"STARS: {game.game_map.stars:>04} |" + str_ = f"| KLINGONS: {game.game_map.game_klingons:>04} | " + \ + f"STARBASES: {game.game_map.game_starbases:>04} | " + \ + f"STARS: {game.game_map.game_stars:>04} |" dots = len(str_) * '-' game.display(dots) game.display(str_) game.display(dots) - @staticmethod def show_exit_status(game): if game.destroyed: @@ -42,7 +42,7 @@ def show_exit_status(game): game.display('!' * len(msg)) game.display(msg) game.display('!' * len(msg)) - elif game.game_map.klingons == 0: + elif game.game_map.game_klingons == 0: msg = "MISSION ACCOMPLISHED: ALL ENEMY SHIPS DESTROYED. WELL DONE!!!" game.display('!' * len(msg)) game.display(msg) diff --git a/Quadrant.py b/Sector.py similarity index 76% rename from Quadrant.py rename to Sector.py index bff5aac..001cddc 100644 --- a/Quadrant.py +++ b/Sector.py @@ -1,15 +1,15 @@ import Glyphs -class Quadrant(): +class Sector(): def __init__(self, num=-1, name='', aliens=-1, stars=-1, starbases=-1, lines=[]): self.name = name self.number = num self.lines = lines - self.klingons = aliens - self.stars = stars - self.starbases = starbases + self.area_klingons = aliens + self.area_stars = stars + self.area_starbases = starbases self.scanned = True # meh def is_null(self): @@ -18,11 +18,11 @@ def is_null(self): @staticmethod def from_area(area): if not area: - return Quadrant() + return Sector() name = area.name num = area.number map = area.get_map() - return Quadrant(num, name, + return Sector(num, name, area.count_glyphs(Glyphs.KLINGON), area.count_glyphs(Glyphs.STAR), area.count_glyphs(Glyphs.STARBASE), @@ -30,25 +30,25 @@ def from_area(area): @staticmethod - def display_area(game, quad): + def display_area(game, sector): game.enterprise.condition = "GREEN" - if game.game_map.num_area_klingons() > 0: + if sector.area_klingons > 0: game.enterprise.condition = "RED" elif game.enterprise.energy < 300: game.enterprise.condition = "YELLOW" sb = " a b c d e f g h \n" - sb += f" -=--=--=--=--=--=--=--=- Quadrant: {quad.name}\n" + sb += f" -=--=--=--=--=--=--=--=- Sector: {sector.name}\n" info = list() - info.append(f" Area: [{quad.number}]\n") - info.append(f" Hazzards: [{quad.stars + quad.klingons}]\n") + info.append(f" Number: [{sector.number}]\n") + info.append(f" Hazzards: [{sector.area_stars + sector.area_klingons}]\n") info.append(f" Stardate: {game.star_date}\n") info.append(f" Condition: {game.enterprise.condition}\n") info.append(f" Energy: {game.enterprise.energy}\n") info.append(f" Shields: {game.enterprise.shield_level}\n") info.append(f" Photon Torpedoes: {game.enterprise.photon_torpedoes}\n") info.append(f" Time remaining: {game.time_remaining}\n") - for row, line in enumerate(quad.lines): + for row, line in enumerate(sector.lines): sb += f" {row+1} |" for col in line: sb += col @@ -57,9 +57,9 @@ def display_area(game, quad): sb += " a b c d e f g h \n" print(sb, end='') - if quad.klingons > 0: + if sector.area_klingons > 0: game.display() - game.display("Condition RED: Klingon ship{0} detected.".format("" if quad.klingons == 1 else "s")) + game.display("Condition RED: Klingon ship{0} detected.".format("" if sector.area_klingons == 1 else "s")) if game.enterprise.shield_level == 0 and not game.enterprise.docked: game.display("Warning: Shields are down.") elif game.enterprise.energy < 300: diff --git a/ShipEnterprise.py b/ShipEnterprise.py index 281edd0..a625093 100644 --- a/ShipEnterprise.py +++ b/ShipEnterprise.py @@ -1,8 +1,10 @@ import random from AbsShip import AbsShip from ShipStarbase import ShipStarbase -from Quadrant import Quadrant +from Sector import Sector +from Difficulity import Probabilities import Glyphs +from Quips import Quips class ShipEnterprise(AbsShip): @@ -29,11 +31,9 @@ def damage(self, game, item): ''' Damage the Enterprise. ''' - if game.is_testing: + if not Probabilities.should_damage_enterprise(game, item): return - if random.randint(0, 6) > 0: - return - damage = 1 + random.randint(0, 4) + damage = Probabilities.calc_damage(game, item) if item < 0: item = random.randint(0, 6) if item == 0: @@ -41,10 +41,10 @@ def damage(self, game, item): game.display(Quips.jibe_damage('Warp Engines')) elif item == 1: self.short_range_scan_damage = damage - game.display(Quips.jibe_damage('Short Range Scanners')) + game.display(Quips.jibe_damage('Short Range Scanner')) elif item == 2: self.long_range_scan_damage = damage - game.display(Quips.jibe_damage('Long Range Scanners')) + game.display(Quips.jibe_damage('Long Range Scanner')) elif item == 3: self.shield_control_damage = damage game.display(Quips.jibe_damage('Shield Controls')) @@ -73,7 +73,7 @@ def repair(self, game): self.short_range_scan_damage -= 1 if self.short_range_scan_damage == 0: game.display("Short range scanner has been repaired.") - self.display() + game.display() return True if self.long_range_scan_damage > 0: self.long_range_scan_damage -= 1 @@ -109,16 +109,18 @@ def repair(self, game): def short_range_scan(self, game): if self.short_range_scan_damage > 0: - game.display(Quips.jibe_damage('Short Ranged Scanners')) + game.display(Quips.jibe_damage('Short Ranged Scanner')) game.display() else: - quad = game.game_map.quad() - Quadrant.display_area(game, quad) + quad = game.game_map.get_pw_sector() + Sector.display_area(game, quad) game.display() + if not game.enterprise.repair(game): + game.enterprise.damage(game, Probabilities.SRS) def long_range_scan(self, game): if self.long_range_scan_damage > 0: - game.display(Quips.jibe_damage('Long Ranged Scanners')) + game.display(Quips.jibe_damage('Long Ranged Scanner')) game.display() return @@ -129,11 +131,11 @@ def long_range_scan(self, game): pw_sector = 60 lines = [] for peek in range(pw_sector-4, pw_sector + 5): - quad = game.game_map.scan_quad(peek) + quad = game.game_map.scan_sector(peek) lines.append(f"SEC: {quad.number:>03}") - lines.append(f"{Glyphs.KLINGON}: {quad.klingons:>03}") - lines.append(f"{Glyphs.STARBASE}: {quad.starbases:>03}") - lines.append(f"{Glyphs.STAR}: {quad.stars:>03}") + lines.append(f"{Glyphs.KLINGON}: {quad.area_klingons:>03}") + lines.append(f"{Glyphs.STARBASE}: {quad.area_starbases:>03}") + lines.append(f"{Glyphs.STAR}: {quad.area_stars:>03}") dots = ' +' + ('-' * 35) + '+' game.display(dots) game.display(' | LONG RANGE SCAN |') @@ -144,4 +146,6 @@ def long_range_scan(self, game): game.display(line) game.display(dots) game.display() + if not game.enterprise.repair(game): + game.enterprise.damage(game, Probabilities.SRS) diff --git a/ShipKlingon.py b/ShipKlingon.py index d597eda..31d8a10 100644 --- a/ShipKlingon.py +++ b/ShipKlingon.py @@ -15,7 +15,7 @@ def get_glyph(self): def from_map(self, xpos, ypos): self.xpos = xpos self.ypos = ypos - self.shield_level = 300 + random.randint(0, 199) + self.shield_level = random.randint(300, 599) @staticmethod def attack_if_you_can(game): diff --git a/StarTrek2020.py b/StarTrek2020.py index 5873ebf..602168c 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -38,14 +38,23 @@ def move_to(self, dest): ShipStarbase.launch_enterprise(self.enterprise) return pos + def game_over(self): + ''' + Check to see if the game is over. + ''' + running = self.enterprise.energy > 0 and not \ + self.destroyed and self.game_map.game_klingons > 0 and \ + self.time_remaining > 0 + return running + def run(self): self.show_strings(TrekStrings.LOGO_TREKER) - game.star_date = random.randint(0, 50) + 2250 - game.time_remaining = 40 + random.randint(0, 9) + game.star_date = random.randint(2250, 2300) + game.time_remaining = random.randint(40, 45) game.destroyed = False - stars = random.randrange(400, 600) # 4096 = ALL - aliens = random.randrange(12, 16) - starbases = random.randrange(6, 8) + stars = random.randint(500, 700) # 4096 = ALL + aliens = random.randint(14, 24) + starbases = random.randint(6, 8) game.game_map.randomize(starbases, stars, aliens) dest = WarpDest(64, 0) game.move_to(dest) @@ -57,10 +66,7 @@ def run(self): try: while running: self.command_prompt() - running = self.enterprise.energy > 0 and not \ - self.destroyed and self.game_map.klingons > 0 and \ - self.time_remaining > 0 - if not running: + if not self.game_over(): Stats.show_exit_status(game) except ErrorEnterpriseCollision as ex: Stats.show_exit_status(game) @@ -104,7 +110,7 @@ def command_prompt(self): def print_mission(self): self.display("Mission: Destroy {0} Klingon ships in {1} stardates with {2} starbases.".format( - self.game_map.klingons, self.time_remaining, self.game_map.starbases)) + self.game_map.game_klingons, self.time_remaining, self.game_map.game_starbases)) self.display() diff --git a/test_MapSparse.py b/test_MapSparse.py index 9f48c5c..5edcf09 100644 --- a/test_MapSparse.py +++ b/test_MapSparse.py @@ -17,7 +17,7 @@ def define_map(): map.init() for ypos, area in enumerate(range(8)): for xpos, area in enumerate(range(8)): - which = random.randrange(0, 14) + which = random.randint(0, 14) glyph = Glyphs.SPACE if which < 0: pass @@ -29,8 +29,8 @@ def define_map(): glyph = Glyphs.KLINGON map.plot(area, - random.randrange(0, 7), - random.randrange(0, 7), + random.randint(0, 7), + random.randint(0, 7), glyph) return map From 9af1de69eb1e084eead76d29993d79732109a434 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Fri, 25 Dec 2020 02:17:48 -0500 Subject: [PATCH 032/100] Random damage & probability updates. --- .gitignore | 2 + AbsShip.py | 2 +- Calculators.py | 15 ++-- Controls.py | 32 +++++---- Difficulity.py | 49 +++++++++++++ MapGame.py | 149 +++++++++++++++++++++++---------------- MapSparse.py | 8 +-- Quips.py | 33 ++++----- Reports.py | 18 ++--- Quadrant.py => Sector.py | 28 ++++---- ShipEnterprise.py | 36 +++++----- ShipKlingon.py | 2 +- StarTrek2020.py | 26 ++++--- test_MapSparse.py | 6 +- 14 files changed, 244 insertions(+), 162 deletions(-) create mode 100644 Difficulity.py rename Quadrant.py => Sector.py (76%) diff --git a/.gitignore b/.gitignore index b922ded..e7cf513 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,5 @@ /__pycache__/ShipKlingon.cpython-37.pyc /__pycache__/ShipEnterprise.cpython-37.pyc /__pycache__/ErrorCollision.cpython-37.pyc +/__pycache__/Sector.cpython-37.pyc +/__pycache__/Difficulity.cpython-37.pyc diff --git a/AbsShip.py b/AbsShip.py index 4b856a3..958cf3b 100644 --- a/AbsShip.py +++ b/AbsShip.py @@ -3,7 +3,7 @@ import Glyphs from Quips import Quips -from Quadrant import Quadrant +from Sector import Sector class AbsShip(abc.ABC): ''' The first step, into a much larger universe ... ''' diff --git a/Calculators.py b/Calculators.py index 494e0db..1ffca4a 100644 --- a/Calculators.py +++ b/Calculators.py @@ -4,6 +4,7 @@ from MapGame import * from AbsShip import * from Points import * +from Difficulity import Probabilities class Calc(): @@ -36,11 +37,11 @@ def sublight_navigation(game): game.display("Enterprise successfully docked with starbase.") game.display() else: - if game.game_map.klingons > 0: + if game.game_map.count_area_klingons() > 0: ShipKlingon.attack_if_you_can(game) game.display() elif not game.enterprise.repair(game): - game.enterprise.damage(game, -1) + game.enterprise.damage(game, Probabilities.LRS) @staticmethod def warp_navigation(game): @@ -80,11 +81,11 @@ def warp_navigation(game): game.display("Enterprise successfully docked with starbase.") game.display() else: - if game.game_map.klingons > 0: + if game.game_map.count_area_klingons() > 0: ShipKlingon.attack_if_you_can(game) game.display() elif not game.enterprise.repair(game): - game.enterprise.damage(game, -1) + game.enterprise.damage(game, Probabilities.RANDOM) @staticmethod @@ -107,7 +108,7 @@ def show_torp_targets(game): game.display() kships = game.game_map.get_area_klingons() if len(kships) == 0: - game.display("There are no enemies in this quadrant.") + game.display("There are no enemies in this sector.") return game.display("Enemies:") @@ -115,7 +116,3 @@ def show_torp_targets(game): game.display(f"\tKlingon [{ship.xpos},{ship.ypos}].") game.display() - - - - diff --git a/Controls.py b/Controls.py index 3f07f37..b56f74d 100644 --- a/Controls.py +++ b/Controls.py @@ -9,6 +9,7 @@ from Calculators import Calc from Reports import Stats from Quips import Quips +from Difficulity import Probabilities class Control(): @@ -32,7 +33,7 @@ def computer(game): game.display() game.display("Invalid computer command.") game.display() - game.enterprise.damage(game, 4) + game.enterprise.damage(game, Probabilities.COMPUTER) @staticmethod @@ -43,7 +44,7 @@ def phasers(game): return kships = game.game_map.get_area_klingons() if len(kships) == 0: - game.display("There are no Klingon ships in this quadrant.") + game.display("There are no Klingon ships in this sector.") game.display() return game.display("Phasers locked on target.") @@ -72,11 +73,12 @@ def phasers(game): else: game.display(f"Hit ship at [{ship.xpos + 1},{ship.ypos + 1}].") game.display(f"Enemy shield down to {ship.shield_level}.") - game.game_map.remove_items(destroyed_ships) - if game.game_map.klingons > 0: + game.game_map.remove_area_items(destroyed_ships) + if game.game_map.count_area_klingons() > 0: game.display() ShipKlingon.attack_if_you_can(game) game.display() + game.enterprise.damage(game, Probabilities.PHASERS) def shields(game): @@ -111,6 +113,7 @@ def shields(game): game.enterprise.shield_level -= int(transfer) game.display("Shield strength is now {0}. Energy level is now {1}.".format(game.enterprise.shield_level, game.enterprise.energy)) game.display() + game.enterprise.damage(game, Probabilities.SHIELDS) def torpedos(game): @@ -122,8 +125,8 @@ def torpedos(game): game.display("Photon torpedoes exhausted.") game.display() return - if len(game.game_map.get_area_klingons()) == 0: - game.display("There are no Klingon ships in this quadrant.") + if game.game_map.count_area_klingons() == 0: + game.display("There are no Klingon ships in this sector.") game.display() return shot = game.read_xypos() @@ -140,33 +143,34 @@ def torpedos(game): print(f'{ship.glyph}({ship.xpos},{ship.ypos}), shot({shot.xpos},{shot.ypos})') if ship.xpos == shot.xpos and ship.ypos == shot.ypos: if ship.glyph == Glyphs.KLINGON: - num = game.game_map.game_id(ship) + num = game.game_map.get_game_id(ship) game.display(f"Klingon ship #{num} destroyed.") game.display(Quips.jibe_defeat('enemy')) - game.game_map.remove_items([ship]) + game.game_map.remove_area_items([ship]) hit = True break elif ship.glyph == Glyphs.STARBASE: - game.game_map.starbases -= 1 - num = game.game_map.game_id(ship) + game.game_map.game_starbases -= 1 + num = game.game_map.get_game_id(ship) game.display("Federation Starbase #{num} destroyed!") game.display(Quips.jibe_defeat('commander')) - game.game_map.remove_items([ship]) + game.game_map.remove_area_items([ship]) hit = True break elif ship.glyph == Glyphs.STAR: - num = game.game_map.game_id(ship) + num = game.game_map.get_game_id(ship) game.display(f"Torpedo vaporizes star #{num}!") game.display(Quips.jibe_defeat('academic')) - game.game_map.remove_items([ship]) + game.game_map.remove_area_items([ship]) hit = True break if not hit: game.display("Torpedo missed.") - if len(game.game_map.get_area_klingons()) > 0: + if game.game_map.count_area_klingons() > 0: game.display() ShipKlingon.attack_if_you_can(game) game.display() + game.enterprise.damage(game, Probabilities.PHOTON) diff --git a/Difficulity.py b/Difficulity.py new file mode 100644 index 0000000..53a0410 --- /dev/null +++ b/Difficulity.py @@ -0,0 +1,49 @@ +import random + +class Probabilities: + ''' + Extracting allows for easier customization. + ''' + _LEVEL = 4 + RANDOM = -1 + NAV = 0 + SRS = 1 + LRS = 2 + SHIELDS = 3 + COMPUTER = 4 + PHOTON = 5 + PHASERS = 6 + + @staticmethod + def set_difficulity(game, level): + ''' + The HIGHER the level, the MORE difficult + the game will be. 0 = EASY, 6 = HIGHEST + ''' + if level < 0: level = 0 + if level > 6: level = 6 + Probabilities._LEVEL = level + + @staticmethod + def calc_damage(game, item): + ''' + How mch damage? + ''' + return random.randint(1, 3) + + @staticmethod + def should_damage_enterprise(game, item): + ''' + Should we damage? + Lowest level (above) eliminates damage to ITEM + ''' + if game.is_testing: + return False + if item == Probabilities.SHIELDS: + return False + if random.randint(0, 6) < Probabilities._LEVEL: + return True + return False + + + diff --git a/MapGame.py b/MapGame.py index 00a6dd2..3eb8026 100644 --- a/MapGame.py +++ b/MapGame.py @@ -4,7 +4,7 @@ import Glyphs from ShipKlingon import ShipKlingon from Points import * -from Quadrant import Quadrant +from Sector import Sector from ErrorCollision import ErrorEnterpriseCollision import MapSparse @@ -15,9 +15,9 @@ def __init__(self): super().__init__() self.sector = -1 self.xpos = self.ypos = -1 - self.stars = -1 - self.klingons = -1 - self.starbases = -1 + self.game_stars = -1 + self.game_klingons = -1 + self.game_starbases = -1 self.last_nav = None def place(self, takers): @@ -30,16 +30,16 @@ def place(self, takers): for which, nelem in enumerate(takers): if not nelem: continue - to_take = random.randrange(0, nelem) + to_take = random.randint(0, nelem) if nelem is 1: to_take = 1 if not to_take: continue taken = 0 while taken != to_take: - ss = random.randrange(1, 64) + ss = random.randrange(1, 64) # Ignore "Outer Limits" area = self.get_area(ss) - should_take = random.randrange(1, 8) + should_take = random.randint(1, 8) if which is 0: if area.count_glyphs(Glyphs.STARBASE) != 0: continue @@ -57,12 +57,14 @@ def place(self, takers): return tuple(takers) def enterprise_in(self, dest=None): - ''' Place the ENTERPRISE at the destination, else a + ''' + Place the ENTERPRISE at the destination, else a random one. Will raise an ErrorEnterpriseCollision, upon same. - Returns the final x, y location upon success ''' + Returns the final x, y location upon success + ''' area = self.pw_area() if not dest: return area.place_glyph(Glyphs.ENTERPRISE) @@ -80,7 +82,9 @@ def enterprise_in(self, dest=None): return False def enterprise_location(self): - ''' Get Enterprise location. False if not found. ''' + ''' + Get Enterprise location. False if not found. + ''' area = self.pw_area() if area: for obj in area._pieces: @@ -88,14 +92,18 @@ def enterprise_location(self): return obj.xpos, obj.ypos return False - def enterprise_out(self): - ''' Remove the ENTERPRISE from the present AREA ''' + def enterprise_out(self)->None: + ''' + Remove the ENTERPRISE from the present AREA + ''' pos = self.enterprise_location() if pos: - self.remove(*pos) + self.clear_area(*pos) - def place_glyph(self, glyph, dest=None): - ''' Place the glyph as the destination, else a random one ''' + def place_glyph(self, glyph, dest=None)->bool: + ''' + Place the glyph at the destination, else a random one + ''' area = self.pw_area() if area: pos = area.place_glyph(self, glyph, dest) @@ -103,13 +111,15 @@ def place_glyph(self, glyph, dest=None): return True return False - def remove(self, xpos, ypos): - ''' Remove ANYTHING from the present AREA ''' + def clear_area(self, xpos, ypos)->None: + ''' + Remove ANYTHING from the present AREA + ''' area = self.pw_area() if area: area.remove(xpos, ypos) - def pw_area(self): + def pw_area(self)->MapSparse.SparseMap.Area: ''' Return the internal / sparsely populated AREA object. Return an empty / default AREA upon coordinate error. @@ -120,18 +130,38 @@ def pw_area(self): return area return MapSparse.SparseMap.Area() - def scan_quad(self, sector): + def scan_sector(self, sector)->Sector: ''' - Return a scan (LRS?) for a specific quadrant. - Return empty quadrant, on error. + Return Sector() information (e.g. LRS) for a specific AREA. + Return empty Sector() upon error. ''' area = self.get_area(sector) if area: - return Quadrant.from_area(area) - return Quadrant() + return Sector.from_area(area) + return Sector() + + def count_area_klingons(self)->int: + ''' + How many surround, U.S.S? + ''' + return self._count_area(Glyphs.KLINGON) + + def count_area_starbases(self)->int: + ''' + How many surround, U.S.S? + ''' + return self._count_area(Glyphs.STARBASE) + + def count_area_stars(self)->int: + ''' + How many surround, U.S.S? + ''' + return self._count_area(Glyphs.STAR) - def _count_area(self, glyph): - ''' Tally the number of glyphs in the AREA ''' + def _count_area(self, glyph)->int: + ''' + Tally the number of glyphs in the DEFAULT AREA + ''' count = 0 area = self.pw_area() if area: @@ -140,20 +170,29 @@ def _count_area(self, glyph): count += 1 return count - def update_counts(self): - self.klingons = self.starbases = self.stars = 0 + def update_counts(self)->None: + ''' + Update this map's official game-pieces-in-play tally + ''' + self.game_klingons = self.game_starbases = self.game_stars = 0 for area in self.areas(): - self.klingons += area.count_glyphs(Glyphs.KLINGON) - self.starbases += area.count_glyphs(Glyphs.STARBASE) - self.stars += area.count_glyphs(Glyphs.STAR) + self.game_klingons += area.count_glyphs(Glyphs.KLINGON) + self.game_starbases += area.count_glyphs(Glyphs.STARBASE) + self.game_stars += area.count_glyphs(Glyphs.STAR) + area = self.get_area() + - def remove_items(self, removed): + def remove_area_items(self, piece_array)->None: + ''' + Remove a collection of pieces (e.g. ships), + from the PRESENT / default AREA. + ''' area = self.pw_area() - for obj in removed: + for obj in piece_array: area.remove(obj.xpos, obj.ypos) self.update_counts() - def get_area_klingons(self): + def get_area_klingons(self)->list: ''' Return this Area's data for Kingons, in an array. ''' @@ -165,16 +204,7 @@ def get_area_klingons(self): results.append(ship) return results - def num_area_klingons(self): - return self._count_area(Glyphs.KLINGON) - - def num_area_starbases(self): - return self._count_area(Glyphs.STARBASE) - - def num_area_stars(self): - return self._count_area(Glyphs.STAR) - - def get_area_objects(self): + def get_area_objects(self)->list: ''' Return the actual objects, as located in the Area. NOTE: Changes to this collection will update Area @@ -183,7 +213,7 @@ def get_area_objects(self): area = self.pw_area() return area._pieces - def game_id(self, piece): + def get_game_id(self, piece)->str: ''' Uniquely identify a game piece / object. ''' @@ -191,7 +221,7 @@ def game_id(self, piece): num = (area.number * 100) + (piece.ypos * 8) + piece.xpos return f"{piece.glyph[1]}x{num}" - def get_all(self, glyph): + def get_all(self, glyph)->list: ''' Return [ [AREA, PIECE], ... ] for every glyph found. ''' @@ -201,25 +231,20 @@ def get_all(self, glyph): results.append([area, piece]) return results - def quad(self): + def get_pw_sector(self)->Sector: + ''' + Create a Sector() report for the DEFAULT AREA + ''' area = self.pw_area() - return Quadrant.from_area(area) + return Sector.from_area(area) - def get_map(self): + def get_map(self)->list: ''' Generate AREA map of the present sector. ''' area = self.pw_area() return area.get_map() - def random_jump(self): - dest = SubDest( - random.randint(1, 64), - random.randint(0, 7), - random.randint(0, 7) - ) - self._go_to(dest) - def _go_to(self, dest): ''' Either a WARP ~or~ a SUBSPACE destination is ok. Place the main player (Enterprise, for now) into the Area. @@ -247,14 +272,14 @@ def _go_to(self, dest): self.last_nav = dest return dest - def randomize(self, bases=None, stars=None, aliens=None): + def randomize(self, bases=None, stars=None, aliens=None)->None: if not aliens: - aliens = 15 + random.randint(0, 5) + aliens = random.randint(5, 10) if not bases: - bases = 2 + random.randint(0, 2) - self.starbases = bases - self.klingons = aliens - self.stars = stars + bases = random.randint(2, 4) + self.game_starbases = bases + self.game_klingons = aliens + self.game_stars = stars self.init() takers = bases, stars, aliens while takers: diff --git a/MapSparse.py b/MapSparse.py index 253a6bf..557bc7b 100644 --- a/MapSparse.py +++ b/MapSparse.py @@ -65,7 +65,7 @@ def remove(self, xpos, ypos): self._pieces.remove(obj) return - def get_map(self): + def get_map(self)->list: ''' Generate a map of this AREA. Map is full of Glyphs.SPACE on error. @@ -125,8 +125,8 @@ def place_glyph(self, glyph, dest=None): area = self.get_map() if not dest: while True: - xpos = random.randrange(0,7) - ypos = random.randrange(0,7) + xpos = random.randint(0,7) + ypos = random.randint(0,7) if area[xpos][ypos] == Glyphs.SPACE: self.plot_glyph(xpos, ypos, glyph) return xpos, ypos @@ -190,7 +190,7 @@ def name_areas(self): ''' names = list(TrekStrings.AREA_NAMES) for num, area in enumerate(self.areas(),1): - index = random.randint(0, len(names) - 1) + index = random.randrange(0, len(names)) area.name = names[index] area.number = num del names[index] diff --git a/Quips.py b/Quips.py index 085374d..5731b09 100644 --- a/Quips.py +++ b/Quips.py @@ -28,7 +28,7 @@ ] DEFEAT_SUFFIX = [ " says: `I'll be back!`", - " cries: ... 'a lucky shot!'", + " cries: 'lucky shot!'", " sighs bitterly.", " dies.", " is rescued.", @@ -38,20 +38,16 @@ " is eliminated.", " was aborted. Few lives, matter?", " ejects.", + " was confused.", " crew is rescued.", " crew is spaced.", " crew is recycled.", " crew is recovered.", - " yells: 'Thy mother mates poorly!'", " snarls: 'Lucky shot.'", " laughs: 'You'll not do THAT again!'", " says nothing.", - " screams: 'Thy father is a Targ!'", - " yells: 'Your parents eat bats!'", - " snarls: 'Thy people eat vermin!'", - " yells: 'May you create social disease!'", - " curses: 'Thy fathers spreadeth pox!'", - " yells: 'Your mother is progressive!'", + " screams: 'Thy father was a Targ!'", + " yells: 'Thy mother is progressive!'", ] MISTAKES = [ "... the crew was not impressed ...", @@ -59,18 +55,17 @@ "... next time, remember to 'carry the 1'? ...", "... math lives matter ...", "... that's coming out of your paycheck ...", - "... this is not a bumper car ...", + "... this is not a bumpy car ...", "... life can be tough, that way ...", "... who ordered THAT take-out ...", "... random is, what random does ...", "... you've got their attention ...", - "... next time, just text them ...", "... how rude!", "... yes, karma CAN hurt ...", "... life is but a dream!", "... game over.", - "... they will talk about this one for years.", - "... who is going to pay for this?", + "... they will talk about this for years.", + "... who is going to pay for that?", "... galactic insurance premiums skyrocket ...", "... captain goes down with the starship ...", "... we'll notify your next-of-kin.", @@ -82,25 +77,25 @@ class Quips(): @staticmethod def jibe(noun, prefix, suffix): - prand = random.randrange(0, len(prefix) - 1) - srand = random.randrange(0, len(suffix) - 1) + prand = random.randrange(0, len(prefix)) + srand = random.randrange(0, len(suffix)) return prefix[prand] + noun + suffix[srand] @staticmethod def jibe_damage(noun): - if random.randrange(0, 100) > 25: + if random.randint(0, 100) > 25: return f"{noun.capitalize()} damaged. Repairs are underway." - return Quips.jibe(noun, DAMAGE_PREFIX, DAMAGE_SUFFIX) + return Quips.jibe(noun.lower(), DAMAGE_PREFIX, DAMAGE_SUFFIX) @staticmethod def jibe_defeat(noun): - if random.randrange(0, 100) > 25: + if random.randint(0, 100) > 25: return f"Another {noun.lower()} defeated." - return Quips.jibe(noun, DEFEAT_PREFIX, DEFEAT_SUFFIX) + return Quips.jibe(noun.lower(), DEFEAT_PREFIX, DEFEAT_SUFFIX) @staticmethod def jibe_fatal_mistake(): - return MISTAKES[random.randrange(0, len(MISTAKES) - 1)] + return MISTAKES[random.randrange(0, len(MISTAKES))] diff --git a/Reports.py b/Reports.py index e079b6e..73e87d2 100644 --- a/Reports.py +++ b/Reports.py @@ -1,13 +1,15 @@ import Glyphs class Stats(): - + ''' + Reports do not generate damage. + ''' @staticmethod def show_ship_status(game): game.display() game.display(f" Time Remaining: {game.time_remaining}") - game.display(f" Klingon Ships Remaining: {game.game_map.klingons}") - game.display(f" Starbases: {game.game_map.starbases}") + game.display(f" Klingon Ships Remaining: {game.game_map.game_klingons}") + game.display(f" Starbases: {game.game_map.game_starbases}") game.display(f" Warp Engine Damage: {game.enterprise.navigation_damage}") game.display(f" Short Range Scanner Damage: {game.enterprise.short_range_scan_damage}") game.display(f" Long Range Scanner Damage: {game.enterprise.long_range_scan_damage}") @@ -17,19 +19,17 @@ def show_ship_status(game): game.display(f" Phaser Damage: {game.enterprise.phaser_damage}") game.display() - @staticmethod def show_galactic_status(game): game.display() - str_ = f"| KLINGONS: {game.game_map.klingons:>04} | " + \ - f"STARBASES: {game.game_map.starbases:>04} | " + \ - f"STARS: {game.game_map.stars:>04} |" + str_ = f"| KLINGONS: {game.game_map.game_klingons:>04} | " + \ + f"STARBASES: {game.game_map.game_starbases:>04} | " + \ + f"STARS: {game.game_map.game_stars:>04} |" dots = len(str_) * '-' game.display(dots) game.display(str_) game.display(dots) - @staticmethod def show_exit_status(game): if game.destroyed: @@ -42,7 +42,7 @@ def show_exit_status(game): game.display('!' * len(msg)) game.display(msg) game.display('!' * len(msg)) - elif game.game_map.klingons == 0: + elif game.game_map.game_klingons == 0: msg = "MISSION ACCOMPLISHED: ALL ENEMY SHIPS DESTROYED. WELL DONE!!!" game.display('!' * len(msg)) game.display(msg) diff --git a/Quadrant.py b/Sector.py similarity index 76% rename from Quadrant.py rename to Sector.py index bff5aac..001cddc 100644 --- a/Quadrant.py +++ b/Sector.py @@ -1,15 +1,15 @@ import Glyphs -class Quadrant(): +class Sector(): def __init__(self, num=-1, name='', aliens=-1, stars=-1, starbases=-1, lines=[]): self.name = name self.number = num self.lines = lines - self.klingons = aliens - self.stars = stars - self.starbases = starbases + self.area_klingons = aliens + self.area_stars = stars + self.area_starbases = starbases self.scanned = True # meh def is_null(self): @@ -18,11 +18,11 @@ def is_null(self): @staticmethod def from_area(area): if not area: - return Quadrant() + return Sector() name = area.name num = area.number map = area.get_map() - return Quadrant(num, name, + return Sector(num, name, area.count_glyphs(Glyphs.KLINGON), area.count_glyphs(Glyphs.STAR), area.count_glyphs(Glyphs.STARBASE), @@ -30,25 +30,25 @@ def from_area(area): @staticmethod - def display_area(game, quad): + def display_area(game, sector): game.enterprise.condition = "GREEN" - if game.game_map.num_area_klingons() > 0: + if sector.area_klingons > 0: game.enterprise.condition = "RED" elif game.enterprise.energy < 300: game.enterprise.condition = "YELLOW" sb = " a b c d e f g h \n" - sb += f" -=--=--=--=--=--=--=--=- Quadrant: {quad.name}\n" + sb += f" -=--=--=--=--=--=--=--=- Sector: {sector.name}\n" info = list() - info.append(f" Area: [{quad.number}]\n") - info.append(f" Hazzards: [{quad.stars + quad.klingons}]\n") + info.append(f" Number: [{sector.number}]\n") + info.append(f" Hazzards: [{sector.area_stars + sector.area_klingons}]\n") info.append(f" Stardate: {game.star_date}\n") info.append(f" Condition: {game.enterprise.condition}\n") info.append(f" Energy: {game.enterprise.energy}\n") info.append(f" Shields: {game.enterprise.shield_level}\n") info.append(f" Photon Torpedoes: {game.enterprise.photon_torpedoes}\n") info.append(f" Time remaining: {game.time_remaining}\n") - for row, line in enumerate(quad.lines): + for row, line in enumerate(sector.lines): sb += f" {row+1} |" for col in line: sb += col @@ -57,9 +57,9 @@ def display_area(game, quad): sb += " a b c d e f g h \n" print(sb, end='') - if quad.klingons > 0: + if sector.area_klingons > 0: game.display() - game.display("Condition RED: Klingon ship{0} detected.".format("" if quad.klingons == 1 else "s")) + game.display("Condition RED: Klingon ship{0} detected.".format("" if sector.area_klingons == 1 else "s")) if game.enterprise.shield_level == 0 and not game.enterprise.docked: game.display("Warning: Shields are down.") elif game.enterprise.energy < 300: diff --git a/ShipEnterprise.py b/ShipEnterprise.py index 281edd0..a625093 100644 --- a/ShipEnterprise.py +++ b/ShipEnterprise.py @@ -1,8 +1,10 @@ import random from AbsShip import AbsShip from ShipStarbase import ShipStarbase -from Quadrant import Quadrant +from Sector import Sector +from Difficulity import Probabilities import Glyphs +from Quips import Quips class ShipEnterprise(AbsShip): @@ -29,11 +31,9 @@ def damage(self, game, item): ''' Damage the Enterprise. ''' - if game.is_testing: + if not Probabilities.should_damage_enterprise(game, item): return - if random.randint(0, 6) > 0: - return - damage = 1 + random.randint(0, 4) + damage = Probabilities.calc_damage(game, item) if item < 0: item = random.randint(0, 6) if item == 0: @@ -41,10 +41,10 @@ def damage(self, game, item): game.display(Quips.jibe_damage('Warp Engines')) elif item == 1: self.short_range_scan_damage = damage - game.display(Quips.jibe_damage('Short Range Scanners')) + game.display(Quips.jibe_damage('Short Range Scanner')) elif item == 2: self.long_range_scan_damage = damage - game.display(Quips.jibe_damage('Long Range Scanners')) + game.display(Quips.jibe_damage('Long Range Scanner')) elif item == 3: self.shield_control_damage = damage game.display(Quips.jibe_damage('Shield Controls')) @@ -73,7 +73,7 @@ def repair(self, game): self.short_range_scan_damage -= 1 if self.short_range_scan_damage == 0: game.display("Short range scanner has been repaired.") - self.display() + game.display() return True if self.long_range_scan_damage > 0: self.long_range_scan_damage -= 1 @@ -109,16 +109,18 @@ def repair(self, game): def short_range_scan(self, game): if self.short_range_scan_damage > 0: - game.display(Quips.jibe_damage('Short Ranged Scanners')) + game.display(Quips.jibe_damage('Short Ranged Scanner')) game.display() else: - quad = game.game_map.quad() - Quadrant.display_area(game, quad) + quad = game.game_map.get_pw_sector() + Sector.display_area(game, quad) game.display() + if not game.enterprise.repair(game): + game.enterprise.damage(game, Probabilities.SRS) def long_range_scan(self, game): if self.long_range_scan_damage > 0: - game.display(Quips.jibe_damage('Long Ranged Scanners')) + game.display(Quips.jibe_damage('Long Ranged Scanner')) game.display() return @@ -129,11 +131,11 @@ def long_range_scan(self, game): pw_sector = 60 lines = [] for peek in range(pw_sector-4, pw_sector + 5): - quad = game.game_map.scan_quad(peek) + quad = game.game_map.scan_sector(peek) lines.append(f"SEC: {quad.number:>03}") - lines.append(f"{Glyphs.KLINGON}: {quad.klingons:>03}") - lines.append(f"{Glyphs.STARBASE}: {quad.starbases:>03}") - lines.append(f"{Glyphs.STAR}: {quad.stars:>03}") + lines.append(f"{Glyphs.KLINGON}: {quad.area_klingons:>03}") + lines.append(f"{Glyphs.STARBASE}: {quad.area_starbases:>03}") + lines.append(f"{Glyphs.STAR}: {quad.area_stars:>03}") dots = ' +' + ('-' * 35) + '+' game.display(dots) game.display(' | LONG RANGE SCAN |') @@ -144,4 +146,6 @@ def long_range_scan(self, game): game.display(line) game.display(dots) game.display() + if not game.enterprise.repair(game): + game.enterprise.damage(game, Probabilities.SRS) diff --git a/ShipKlingon.py b/ShipKlingon.py index d597eda..31d8a10 100644 --- a/ShipKlingon.py +++ b/ShipKlingon.py @@ -15,7 +15,7 @@ def get_glyph(self): def from_map(self, xpos, ypos): self.xpos = xpos self.ypos = ypos - self.shield_level = 300 + random.randint(0, 199) + self.shield_level = random.randint(300, 599) @staticmethod def attack_if_you_can(game): diff --git a/StarTrek2020.py b/StarTrek2020.py index 5873ebf..602168c 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -38,14 +38,23 @@ def move_to(self, dest): ShipStarbase.launch_enterprise(self.enterprise) return pos + def game_over(self): + ''' + Check to see if the game is over. + ''' + running = self.enterprise.energy > 0 and not \ + self.destroyed and self.game_map.game_klingons > 0 and \ + self.time_remaining > 0 + return running + def run(self): self.show_strings(TrekStrings.LOGO_TREKER) - game.star_date = random.randint(0, 50) + 2250 - game.time_remaining = 40 + random.randint(0, 9) + game.star_date = random.randint(2250, 2300) + game.time_remaining = random.randint(40, 45) game.destroyed = False - stars = random.randrange(400, 600) # 4096 = ALL - aliens = random.randrange(12, 16) - starbases = random.randrange(6, 8) + stars = random.randint(500, 700) # 4096 = ALL + aliens = random.randint(14, 24) + starbases = random.randint(6, 8) game.game_map.randomize(starbases, stars, aliens) dest = WarpDest(64, 0) game.move_to(dest) @@ -57,10 +66,7 @@ def run(self): try: while running: self.command_prompt() - running = self.enterprise.energy > 0 and not \ - self.destroyed and self.game_map.klingons > 0 and \ - self.time_remaining > 0 - if not running: + if not self.game_over(): Stats.show_exit_status(game) except ErrorEnterpriseCollision as ex: Stats.show_exit_status(game) @@ -104,7 +110,7 @@ def command_prompt(self): def print_mission(self): self.display("Mission: Destroy {0} Klingon ships in {1} stardates with {2} starbases.".format( - self.game_map.klingons, self.time_remaining, self.game_map.starbases)) + self.game_map.game_klingons, self.time_remaining, self.game_map.game_starbases)) self.display() diff --git a/test_MapSparse.py b/test_MapSparse.py index 9f48c5c..5edcf09 100644 --- a/test_MapSparse.py +++ b/test_MapSparse.py @@ -17,7 +17,7 @@ def define_map(): map.init() for ypos, area in enumerate(range(8)): for xpos, area in enumerate(range(8)): - which = random.randrange(0, 14) + which = random.randint(0, 14) glyph = Glyphs.SPACE if which < 0: pass @@ -29,8 +29,8 @@ def define_map(): glyph = Glyphs.KLINGON map.plot(area, - random.randrange(0, 7), - random.randrange(0, 7), + random.randint(0, 7), + random.randint(0, 7), glyph) return map From 8e6ee574ee0f70077c5c21a3a2a60211cf9cf807 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Fri, 25 Dec 2020 09:18:46 -0500 Subject: [PATCH 033/100] fixed a bug. --- MapGame.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MapGame.py b/MapGame.py index 3eb8026..3ae2109 100644 --- a/MapGame.py +++ b/MapGame.py @@ -179,7 +179,7 @@ def update_counts(self)->None: self.game_klingons += area.count_glyphs(Glyphs.KLINGON) self.game_starbases += area.count_glyphs(Glyphs.STARBASE) self.game_stars += area.count_glyphs(Glyphs.STAR) - area = self.get_area() + area = self.get_pw_sector() def remove_area_items(self, piece_array)->None: From 3c0bb805f33002aede5dd5b548237256ec757eef Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Sat, 26 Dec 2020 07:44:11 -0500 Subject: [PATCH 034/100] Added a banner -w- closing Quips. --- AbsDisplay.py | 36 +++++++++++++++++++++++++++++------- Console.py | 2 ++ MapGame.py | 1 + Quips.py | 46 ++++++++++++++++++++++++++++++---------------- Reports.py | 28 ++++++++++++---------------- StarTrek2020.py | 31 +++++++++++++++++++++++-------- 6 files changed, 97 insertions(+), 47 deletions(-) diff --git a/AbsDisplay.py b/AbsDisplay.py index 030c2b8..bbdf0fb 100644 --- a/AbsDisplay.py +++ b/AbsDisplay.py @@ -3,12 +3,15 @@ class abs_display(abc.ABC): ''' The plan is to have several places to - display information. The goal is to - use only one display, to display a - certain type of message. Networked - screens would also be a great idea. - Logging would be in there somewhere, - as well. + display information. The idea is to + use only one display to show a certain + type of message. + + Networked screens would (let alone game + play)would also be a great idea. + + Event logging would be in there somewhere + as well? ''' ST_DEFAULT = 'd' @@ -26,9 +29,28 @@ def __init__(self, type_ = ST_DEFAULT, width = 80, height = 24): def display(self, message): pass - def show_strings(self, string_list): + ''' + Enumerate an array of strings into + self.display. + ''' for string in string_list: self.display(string) self.display() + def show_banner(self, string_list, star = '*'): + ''' + Enumerate an array of strings into a + single-character self.display box. + ''' + if not star: + star = '*' + star = star[0] + sz = len(max(string_list, key=len)) + max_ = sz + 4 + self.display(star * max_) + for str_ in string_list: + self.display(star + ' ' + str_.center(sz) + ' ' + star) + self.display(star * max_) + return sz + diff --git a/Console.py b/Console.py index 513ac60..9f737cc 100644 --- a/Console.py +++ b/Console.py @@ -47,3 +47,5 @@ def read_xypos(self, prompt= "Helm: a-h, 1-8?"): if __name__ == '__main__': con = Con() con.display("Testing!") + con.show_banner(["Testing, too!"]) + con.show_banner(["Testing", " .......... too!"]) diff --git a/MapGame.py b/MapGame.py index 3ae2109..04eda01 100644 --- a/MapGame.py +++ b/MapGame.py @@ -180,6 +180,7 @@ def update_counts(self)->None: self.game_starbases += area.count_glyphs(Glyphs.STARBASE) self.game_stars += area.count_glyphs(Glyphs.STAR) area = self.get_pw_sector() + area = self.get_pw_sector() def remove_area_items(self, piece_array)->None: diff --git a/Quips.py b/Quips.py index cc60d31..b1c14ef 100644 --- a/Quips.py +++ b/Quips.py @@ -42,35 +42,34 @@ " crew is spaced.", " crew is recycled.", " crew is recovered.", - " yells: 'Thy mother mates poorly!'", - " snarls: 'Lucky shot.'", - " laughs: 'You'll not do THAT again!'", + " yells: 'thy mother mates poorly!'", + " snarls: 'lucky shot.'", + " laughs: 'you'll not do THAT again!'", " says nothing.", - " screams: 'Thy father is a Targ!'", - " yells: 'Your parents eat bats!'", - " snarls: 'Thy people eat vermin!'", - " yells: 'May you create social disease!'", - " curses: 'Thy fathers spreadeth pox!'", - " yells: 'Your mother is progressive!'", + " screams: 'thy father is a Targ!'", + " yells: 'thine family eats bats!'", + " snarls: 'thine people eat vermin!'", + " curses: 'thy fathers spreadeth pox!'", + " yells: 'thy mother is progressive!'", ] MISTAKES = [ "... the crew was not impressed ...", "... that's going to leave a mark ...", - "... next time, remember to 'carry the 1'? ...", + "... next time carry the 1?", "... math lives matter ...", - "... that's coming out of your paycheck ...", + "... its coming out of your pay ...", "... this is not a bumper car ...", - "... life can be tough, that way ...", - "... who ordered THAT take-out ...", + "... life can be tough that way ...", + "... who ordered THAT take-out?", "... random is, what random does ...", "... you've got their attention ...", - "... next time, just text them ...", + "... next time, just text them?", "... how rude!", "... yes, karma CAN hurt ...", "... life is but a dream!", "... game over.", - "... they will talk about this one for years.", - "... who is going to pay for this?", + "... starfleet will talk about this for years.", + "... who is going to pay for that?", "... galactic insurance premiums skyrocket ...", "... captain goes down with the starship ...", "... we'll notify your next-of-kin.", @@ -78,6 +77,17 @@ "... you never did THAT in the simulator ...", ] +QUITS = [ + "-Let's call it a draw?", + "-You call yourself a 'Trekkie?", + "Kobayashi Maru. Python is for you!", + "(Spock shakes his head)", + "(... and the Klingons rejoyce)", + "(... and our enemies, rejoyce)", + "Kobayashi Maru: Learn Python?", + "(Kirk shakes his head)", + ] + class Quips(): @staticmethod @@ -85,6 +95,10 @@ def jibe(noun, prefix, suffix): prand = random.randrange(0, len(prefix)) srand = random.randrange(0, len(suffix)) return prefix[prand] + noun + suffix[srand] + + @staticmethod + def jibe_quit(): + return QUITS[random.randrange(0, len(QUITS))] @staticmethod def jibe_damage(noun): diff --git a/Reports.py b/Reports.py index 73e87d2..7235b7c 100644 --- a/Reports.py +++ b/Reports.py @@ -1,4 +1,5 @@ import Glyphs +from Quips import Quips class Stats(): ''' @@ -33,23 +34,18 @@ def show_galactic_status(game): @staticmethod def show_exit_status(game): if game.destroyed: - msg = "MISSION FAILED: ENTERPRISE DESTROYED!!!" - game.display('!' * len(msg)) - game.display(msg) - game.display('!' * len(msg)) + msg = "MISSION FAILED: SHIP DESTROYED" + game.show_banner([msg], '!') elif game.enterprise.energy == 0: - msg = "MISSION FAILED: ENTERPRISE RAN OUT OF ENERGY." - game.display('!' * len(msg)) - game.display(msg) - game.display('!' * len(msg)) + msg = "MISSION FAILED: OUT OF ENERGY." + game.show_banner([msg], '!') elif game.game_map.game_klingons == 0: - msg = "MISSION ACCOMPLISHED: ALL ENEMY SHIPS DESTROYED. WELL DONE!!!" - game.display('!' * len(msg)) - game.display(msg) - game.display('!' * len(msg)) + msg = "MISSION ACCOMPLISHED: ENEMIES DESTROYED. WELL DONE!" + game.show_banner([msg]) elif game.time_remaining == 0: - msg = "MISSION FAILED: ENTERPRISE RAN OUT OF TIME." - game.display('!' * len(msg)) - game.display(msg) - game.display('!' * len(msg)) + msg = "MISSION FAILED: OUT OF TIME." + game.show_banner([msg], '!') + else: + ary = ["::::::::: MISSION ABORTED :::::::::", Quips.jibe_quit()] + game.show_banner(ary, ':') diff --git a/StarTrek2020.py b/StarTrek2020.py index 602168c..64432df 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -24,6 +24,15 @@ def __init__(self): self.destroyed = False def move_to(self, dest): + ''' + Move the player to a nav, or a sub, + destination. Handles docking, random + warp-in placement, as well as deliberate + collisions / rammming. + + Returns final resting coordinate on success. + Raises ErrorEnterpriseCollision on yikes. + ''' pos = self.game_map._go_to(dest) area = self.game_map.pw_area() was_docked = self.enterprise.docked @@ -38,9 +47,9 @@ def move_to(self, dest): ShipStarbase.launch_enterprise(self.enterprise) return pos - def game_over(self): + def game_on(self): ''' - Check to see if the game is over. + See if the game is still running. ''' running = self.enterprise.energy > 0 and not \ self.destroyed and self.game_map.game_klingons > 0 and \ @@ -48,6 +57,9 @@ def game_over(self): return running def run(self): + ''' + The game loop - runs until the game is over. + ''' self.show_strings(TrekStrings.LOGO_TREKER) game.star_date = random.randint(2250, 2300) game.time_remaining = random.randint(40, 45) @@ -64,10 +76,9 @@ def run(self): self.show_strings(TrekStrings.HELM_CMDS) running = True try: - while running: - self.command_prompt() - if not self.game_over(): - Stats.show_exit_status(game) + while self.game_on(): + if not self.command_prompt(): + break except ErrorEnterpriseCollision as ex: Stats.show_exit_status(game) game.display() @@ -79,7 +90,10 @@ def run(self): self.display("You flew into a STAR?") self.destroyed = True game.display() - self.display(Quips.jibe_fatal_mistake()) + Stats.show_exit_status(game) + game.display() + if self.destroyed == True: + self.display(Quips.jibe_fatal_mistake()) game.display() game.display(';-)') return False @@ -104,9 +118,10 @@ def command_prompt(self): elif command == "com": Control.computer(game) elif command.startswith('qui') or command.startswith('exi'): - exit() + return False else: self.show_strings(TrekStrings.HELM_CMDS) + return True def print_mission(self): self.display("Mission: Destroy {0} Klingon ships in {1} stardates with {2} starbases.".format( From e727a1b0b37c2b84ed98c715b1a3d1e76b7490a4 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Sat, 26 Dec 2020 07:44:11 -0500 Subject: [PATCH 035/100] Added a banner -w- closing Quips. --- AbsDisplay.py | 36 +++++++++++++++++++++++++++++------- Console.py | 2 ++ MapGame.py | 1 + MapSparse.py | 1 - Quips.py | 47 +++++++++++++++++++++++++++++++---------------- Reports.py | 28 ++++++++++++---------------- StarTrek2020.py | 32 +++++++++++++++++++++++--------- 7 files changed, 98 insertions(+), 49 deletions(-) diff --git a/AbsDisplay.py b/AbsDisplay.py index 030c2b8..bbdf0fb 100644 --- a/AbsDisplay.py +++ b/AbsDisplay.py @@ -3,12 +3,15 @@ class abs_display(abc.ABC): ''' The plan is to have several places to - display information. The goal is to - use only one display, to display a - certain type of message. Networked - screens would also be a great idea. - Logging would be in there somewhere, - as well. + display information. The idea is to + use only one display to show a certain + type of message. + + Networked screens would (let alone game + play)would also be a great idea. + + Event logging would be in there somewhere + as well? ''' ST_DEFAULT = 'd' @@ -26,9 +29,28 @@ def __init__(self, type_ = ST_DEFAULT, width = 80, height = 24): def display(self, message): pass - def show_strings(self, string_list): + ''' + Enumerate an array of strings into + self.display. + ''' for string in string_list: self.display(string) self.display() + def show_banner(self, string_list, star = '*'): + ''' + Enumerate an array of strings into a + single-character self.display box. + ''' + if not star: + star = '*' + star = star[0] + sz = len(max(string_list, key=len)) + max_ = sz + 4 + self.display(star * max_) + for str_ in string_list: + self.display(star + ' ' + str_.center(sz) + ' ' + star) + self.display(star * max_) + return sz + diff --git a/Console.py b/Console.py index 513ac60..9f737cc 100644 --- a/Console.py +++ b/Console.py @@ -47,3 +47,5 @@ def read_xypos(self, prompt= "Helm: a-h, 1-8?"): if __name__ == '__main__': con = Con() con.display("Testing!") + con.show_banner(["Testing, too!"]) + con.show_banner(["Testing", " .......... too!"]) diff --git a/MapGame.py b/MapGame.py index 3ae2109..04eda01 100644 --- a/MapGame.py +++ b/MapGame.py @@ -180,6 +180,7 @@ def update_counts(self)->None: self.game_starbases += area.count_glyphs(Glyphs.STARBASE) self.game_stars += area.count_glyphs(Glyphs.STAR) area = self.get_pw_sector() + area = self.get_pw_sector() def remove_area_items(self, piece_array)->None: diff --git a/MapSparse.py b/MapSparse.py index 557bc7b..1d76c91 100644 --- a/MapSparse.py +++ b/MapSparse.py @@ -136,7 +136,6 @@ def place_glyph(self, glyph, dest=None): @staticmethod def clone(piece): - ''' Copy a piece. ''' ''' Copy a piece. ''' return SparseMap.Area.Piece(piece.xpos, piece.ypos, piece.glyph) diff --git a/Quips.py b/Quips.py index cc60d31..234253d 100644 --- a/Quips.py +++ b/Quips.py @@ -42,35 +42,34 @@ " crew is spaced.", " crew is recycled.", " crew is recovered.", - " yells: 'Thy mother mates poorly!'", - " snarls: 'Lucky shot.'", - " laughs: 'You'll not do THAT again!'", + " yells: 'thy mother mates poorly!'", + " snarls: 'lucky shot.'", + " laughs: 'you'll not do THAT again!'", " says nothing.", - " screams: 'Thy father is a Targ!'", - " yells: 'Your parents eat bats!'", - " snarls: 'Thy people eat vermin!'", - " yells: 'May you create social disease!'", - " curses: 'Thy fathers spreadeth pox!'", - " yells: 'Your mother is progressive!'", + " screams: 'thy father is a Targ!'", + " yells: 'thine family eats bats!'", + " snarls: 'thine people eat vermin!'", + " curses: 'thy fathers spreadeth pox!'", + " yells: 'thy mother is progressive!'", ] MISTAKES = [ "... the crew was not impressed ...", "... that's going to leave a mark ...", - "... next time, remember to 'carry the 1'? ...", + "... next time carry the 1?", "... math lives matter ...", - "... that's coming out of your paycheck ...", + "... its coming out of your pay ...", "... this is not a bumper car ...", - "... life can be tough, that way ...", - "... who ordered THAT take-out ...", + "... life can be tough that way ...", + "... who ordered THAT take-out?", "... random is, what random does ...", "... you've got their attention ...", - "... next time, just text them ...", + "... next time, just text them?", "... how rude!", "... yes, karma CAN hurt ...", "... life is but a dream!", "... game over.", - "... they will talk about this one for years.", - "... who is going to pay for this?", + "... starfleet will talk about this for years.", + "... who is going to pay for that?", "... galactic insurance premiums skyrocket ...", "... captain goes down with the starship ...", "... we'll notify your next-of-kin.", @@ -78,6 +77,18 @@ "... you never did THAT in the simulator ...", ] +QUITS = [ + "-Let's call it a draw?", + "-You call yourself a 'Trekkie?", + "Kobayashi Maru. Python for you?", + "(Spock shakes his head)", + "(Duras, stop laughing!)", + "(... and the Klingons rejoice)", + "(... and our enemies, rejoice)", + "Kobayashi Maru... Got Python?", + "(Kirk shakes his head)", + ] + class Quips(): @staticmethod @@ -85,6 +96,10 @@ def jibe(noun, prefix, suffix): prand = random.randrange(0, len(prefix)) srand = random.randrange(0, len(suffix)) return prefix[prand] + noun + suffix[srand] + + @staticmethod + def jibe_quit(): + return QUITS[random.randrange(0, len(QUITS))] @staticmethod def jibe_damage(noun): diff --git a/Reports.py b/Reports.py index 73e87d2..7235b7c 100644 --- a/Reports.py +++ b/Reports.py @@ -1,4 +1,5 @@ import Glyphs +from Quips import Quips class Stats(): ''' @@ -33,23 +34,18 @@ def show_galactic_status(game): @staticmethod def show_exit_status(game): if game.destroyed: - msg = "MISSION FAILED: ENTERPRISE DESTROYED!!!" - game.display('!' * len(msg)) - game.display(msg) - game.display('!' * len(msg)) + msg = "MISSION FAILED: SHIP DESTROYED" + game.show_banner([msg], '!') elif game.enterprise.energy == 0: - msg = "MISSION FAILED: ENTERPRISE RAN OUT OF ENERGY." - game.display('!' * len(msg)) - game.display(msg) - game.display('!' * len(msg)) + msg = "MISSION FAILED: OUT OF ENERGY." + game.show_banner([msg], '!') elif game.game_map.game_klingons == 0: - msg = "MISSION ACCOMPLISHED: ALL ENEMY SHIPS DESTROYED. WELL DONE!!!" - game.display('!' * len(msg)) - game.display(msg) - game.display('!' * len(msg)) + msg = "MISSION ACCOMPLISHED: ENEMIES DESTROYED. WELL DONE!" + game.show_banner([msg]) elif game.time_remaining == 0: - msg = "MISSION FAILED: ENTERPRISE RAN OUT OF TIME." - game.display('!' * len(msg)) - game.display(msg) - game.display('!' * len(msg)) + msg = "MISSION FAILED: OUT OF TIME." + game.show_banner([msg], '!') + else: + ary = ["::::::::: MISSION ABORTED :::::::::", Quips.jibe_quit()] + game.show_banner(ary, ':') diff --git a/StarTrek2020.py b/StarTrek2020.py index 602168c..ee62f13 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -24,6 +24,15 @@ def __init__(self): self.destroyed = False def move_to(self, dest): + ''' + Move the player to a nav, or a sub, + destination. Handles docking, random + warp-in placement, as well as deliberate + collisions / rammming. + + Returns final resting coordinate on success. + Raises ErrorEnterpriseCollision on yikes. + ''' pos = self.game_map._go_to(dest) area = self.game_map.pw_area() was_docked = self.enterprise.docked @@ -38,9 +47,9 @@ def move_to(self, dest): ShipStarbase.launch_enterprise(self.enterprise) return pos - def game_over(self): + def game_on(self): ''' - Check to see if the game is over. + See if the game is still running. ''' running = self.enterprise.energy > 0 and not \ self.destroyed and self.game_map.game_klingons > 0 and \ @@ -48,6 +57,9 @@ def game_over(self): return running def run(self): + ''' + The game loop - runs until the game is over. + ''' self.show_strings(TrekStrings.LOGO_TREKER) game.star_date = random.randint(2250, 2300) game.time_remaining = random.randint(40, 45) @@ -64,12 +76,10 @@ def run(self): self.show_strings(TrekStrings.HELM_CMDS) running = True try: - while running: - self.command_prompt() - if not self.game_over(): - Stats.show_exit_status(game) + while self.game_on(): + if not self.command_prompt(): + break except ErrorEnterpriseCollision as ex: - Stats.show_exit_status(game) game.display() if ex.glyph == Glyphs.KLINGON: self.display("You flew into a KLINGON!") @@ -79,7 +89,10 @@ def run(self): self.display("You flew into a STAR?") self.destroyed = True game.display() - self.display(Quips.jibe_fatal_mistake()) + Stats.show_exit_status(game) + game.display() + if self.destroyed == True: + self.display(Quips.jibe_fatal_mistake()) game.display() game.display(';-)') return False @@ -104,9 +117,10 @@ def command_prompt(self): elif command == "com": Control.computer(game) elif command.startswith('qui') or command.startswith('exi'): - exit() + return False else: self.show_strings(TrekStrings.HELM_CMDS) + return True def print_mission(self): self.display("Mission: Destroy {0} Klingon ships in {1} stardates with {2} starbases.".format( From 9030ec12adbc6f3d8c00a9900800bca1c1cdc943 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Sat, 26 Dec 2020 09:35:27 -0500 Subject: [PATCH 036/100] Fixed generous starbase docking logic. --- Calculators.py | 23 +++++++++++++++++++++++ StarTrek2020.py | 10 +++++----- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/Calculators.py b/Calculators.py index 1ffca4a..cd5d1eb 100644 --- a/Calculators.py +++ b/Calculators.py @@ -8,6 +8,29 @@ class Calc(): + @staticmethod + def surrounding(pos): + ''' + Return the complete set of + points surrounding a piece. + Sanity checking is not performed. + ''' + results = [] + if pos: + above = pos.ypos - 1 + below = pos.ypos + 1 + left = pos.xpos - 1 + right = pos.xpos + 1 + results.append([left, above]) + results.append([right, below]) + results.append([left, below]) + results.append([right, above]) + results.append([pos.xpos, above]) + results.append([pos.xpos, below]) + results.append([left, pos.ypos]) + results.append([right, pos.ypos]) + return results + @staticmethod def distance(x1, y1, x2, y2): x = x2 - x1 diff --git a/StarTrek2020.py b/StarTrek2020.py index ee62f13..b8cf10b 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -39,10 +39,11 @@ def move_to(self, dest): self.enterprise.docked = False for p in area._pieces: if p.glyph == Glyphs.STARBASE: - if p.xpos + 1 == pos.xpos or p.ypos + 1 == pos.ypos or \ - p.xpos - 1 == pos.xpos or p.ypos - 1 == pos.ypos: - self.enterprise.docked = True - ShipStarbase.dock_enterprise(self.enterprise) + for point in Calc.surrounding(pos): + if p.xpos == point[0] and \ + p.ypos == point[1]: + self.enterprise.docked = True + ShipStarbase.dock_enterprise(self.enterprise) if was_docked and self.enterprise.docked == False: ShipStarbase.launch_enterprise(self.enterprise) return pos @@ -80,7 +81,6 @@ def run(self): if not self.command_prompt(): break except ErrorEnterpriseCollision as ex: - game.display() if ex.glyph == Glyphs.KLINGON: self.display("You flew into a KLINGON!") if ex.glyph == Glyphs.STARBASE: From dc4b8475537dffb023f373c0d89d12f35971aaf6 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Sun, 27 Dec 2020 00:14:01 -0500 Subject: [PATCH 037/100] Alpha testing underway ... --- Controls.py | 2 -- MapGame.py | 24 ++++++++++++++++-------- MapSparse.py | 24 +++++++++++++++++------- Reports.py | 4 ++-- Sector.py | 1 - ShipKlingon.py | 2 +- StarTrek2020.py | 10 ++++++++-- 7 files changed, 44 insertions(+), 23 deletions(-) diff --git a/Controls.py b/Controls.py index b56f74d..153fd2e 100644 --- a/Controls.py +++ b/Controls.py @@ -172,5 +172,3 @@ def torpedos(game): game.display() game.enterprise.damage(game, Probabilities.PHOTON) - - diff --git a/MapGame.py b/MapGame.py index 04eda01..1a60017 100644 --- a/MapGame.py +++ b/MapGame.py @@ -12,6 +12,10 @@ class GameMap(MapSparse.SparseMap): def __init__(self): + ''' + Prepare a 'Trekian GameMap for future + initialization. + ''' super().__init__() self.sector = -1 self.xpos = self.ypos = -1 @@ -179,9 +183,6 @@ def update_counts(self)->None: self.game_klingons += area.count_glyphs(Glyphs.KLINGON) self.game_starbases += area.count_glyphs(Glyphs.STARBASE) self.game_stars += area.count_glyphs(Glyphs.STAR) - area = self.get_pw_sector() - area = self.get_pw_sector() - def remove_area_items(self, piece_array)->None: ''' @@ -199,7 +200,7 @@ def get_area_klingons(self)->list: ''' results = [] area = self.pw_area() - for data in area.get_data(Glyphs.KLINGON): + for data in area.query(Glyphs.KLINGON): ship = ShipKlingon() ship.from_map(data.xpos, data.ypos) results.append(ship) @@ -207,8 +208,8 @@ def get_area_klingons(self)->list: def get_area_objects(self)->list: ''' - Return the actual objects, as located in the Area. - NOTE: Changes to this collection will update Area + Return the actual pieces, as maintained in the Area. + WARNING: Changes to this collection WILL update Area content. ''' area = self.pw_area() @@ -228,7 +229,7 @@ def get_all(self, glyph)->list: ''' results = [] for area in self.areas(): - for piece in area.get_data(glyph): + for piece in area.query(glyph): results.append([area, piece]) return results @@ -247,7 +248,8 @@ def get_map(self)->list: return area.get_map() def _go_to(self, dest): - ''' Either a WARP ~or~ a SUBSPACE destination is ok. + ''' + Either a WARP ~or~ a SUBSPACE destination is ok. Place the main player (Enterprise, for now) into the Area. Returns the final, effective, player location. ''' @@ -274,6 +276,12 @@ def _go_to(self, dest): return dest def randomize(self, bases=None, stars=None, aliens=None)->None: + ''' + Randomly place the inventoried items into the map. + If no bases ot aliens are specified, a random number + will be selected. Stars are not required. Not having + any stars is ok. + ''' if not aliens: aliens = random.randint(5, 10) if not bases: diff --git a/MapSparse.py b/MapSparse.py index 1d76c91..0695d34 100644 --- a/MapSparse.py +++ b/MapSparse.py @@ -20,7 +20,7 @@ class Area(): A minimalist collection of Area-plotted Glyphs. Area numbers are 1's based. Area plotting is 0's based. - Names are Trekian. + Area names are Trekian. ''' class Piece: ''' @@ -37,7 +37,6 @@ def __init__(self): ''' self.name = "" self.number = -1 - self.scanned = False self._pieces = [] def is_null(self): @@ -47,15 +46,14 @@ def is_null(self): dum = Area() return dum.name == self.name and \ dum.number == self.number and \ - dum.scanned == self.scanned and \ len(dum.objs) == len(self._pieces) def is_empty(self): ''' Checks to see if the Area has anything ...''' return len(self._pieces) == True - def items(self): - ''' Items in the Area ...''' + def item_count(self)->int: + ''' The number of pieces / items in the randint ...''' return len(self._pieces) def remove(self, xpos, ypos): @@ -67,7 +65,7 @@ def remove(self, xpos, ypos): def get_map(self)->list: ''' - Generate a map of this AREA. Map is full + Generate a map of this randint. Map is full of Glyphs.SPACE on error. ''' results = [[Glyphs.SPACE for _ in range(8)] for _ in range(8)] @@ -89,7 +87,12 @@ def range_ok(self, xpos, ypos): return False return True - def get_data(self, glyph): + def query(self, glyph): + ''' + Clone each Piece for a glyph into a new + collection. Changes to the results WILL NOT + affect the glyph in the AREA. + ''' results = [] for p in self._pieces: if p.glyph == glyph: @@ -140,10 +143,17 @@ def clone(piece): return SparseMap.Area.Piece(piece.xpos, piece.ypos, piece.glyph) def __init__(self): + ''' + Create the uninitialized REGION. Use .init() to + populate same with AREAs. + ''' self.initalized = False self._map = [[[y,x] for y in range(8)] for x in range(8)] def init(self, reset=False): + ''' + Fill a newly-created map with a set of randomly-named AREAs. + ''' if not reset and self.initalized: return for xx, row in enumerate(self._map): diff --git a/Reports.py b/Reports.py index 7235b7c..8bbada2 100644 --- a/Reports.py +++ b/Reports.py @@ -40,8 +40,8 @@ def show_exit_status(game): msg = "MISSION FAILED: OUT OF ENERGY." game.show_banner([msg], '!') elif game.game_map.game_klingons == 0: - msg = "MISSION ACCOMPLISHED: ENEMIES DESTROYED. WELL DONE!" - game.show_banner([msg]) + msg = "MISSION ACCOMPLISHED","ENEMIES DESTROYED","WELL DONE!" + game.show_banner(msg) elif game.time_remaining == 0: msg = "MISSION FAILED: OUT OF TIME." game.show_banner([msg], '!') diff --git a/Sector.py b/Sector.py index 001cddc..d52541b 100644 --- a/Sector.py +++ b/Sector.py @@ -10,7 +10,6 @@ def __init__(self, num=-1, name='', self.area_klingons = aliens self.area_stars = stars self.area_starbases = starbases - self.scanned = True # meh def is_null(self): return self.num == -1 diff --git a/ShipKlingon.py b/ShipKlingon.py index 31d8a10..54bae14 100644 --- a/ShipKlingon.py +++ b/ShipKlingon.py @@ -22,7 +22,7 @@ def attack_if_you_can(game): ''' IF you ever find yourself in the AREA, then have at USS? ''' - if game.is_testing: + if game.is_cloked: return False from Calculators import Calc kships = game.game_map.get_area_klingons() diff --git a/StarTrek2020.py b/StarTrek2020.py index b8cf10b..56748ce 100644 --- a/StarTrek2020.py +++ b/StarTrek2020.py @@ -3,8 +3,8 @@ import TrekStrings from Console import Con from ShipKlingon import ShipKlingon -from ShipStarbase import ShipStarbase from ShipEnterprise import ShipEnterprise +from ShipStarbase import ShipStarbase from Calculators import Calc from Controls import Control from Reports import Stats @@ -17,6 +17,7 @@ class Game(Con): def __init__(self): self.is_testing = False + self.is_cloked = False # unable to be fired-upon self.game_map = GameMap() self.enterprise = ShipEnterprise() self.star_date = 0 @@ -80,6 +81,12 @@ def run(self): while self.game_on(): if not self.command_prompt(): break + if self.is_testing: + self.destoryed = False + ShipStarbase.dock_enterprise(self.enterprise) + ShipStarbase.launch_enterprise(self.enterprise) + self.enterprise.shield_level = 1000 + except ErrorEnterpriseCollision as ex: if ex.glyph == Glyphs.KLINGON: self.display("You flew into a KLINGON!") @@ -94,7 +101,6 @@ def run(self): if self.destroyed == True: self.display(Quips.jibe_fatal_mistake()) game.display() - game.display(';-)') return False def command_prompt(self): From 70fd2abc77093787b981e64123c993f0bc5f897a Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Sun, 27 Dec 2020 12:42:21 -0500 Subject: [PATCH 038/100] Welcome! --- README.rst | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 0ba3db6..ea99235 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,10 @@ -The original free-and-open StarTrek console game was THE most played game of the day .... back in the 1970's! +================ + StarTrek 1971 - 2020 +================ +The original free-and-open Star Trek console game was THE most played game of the day .... back in the 1970's! + +Originally written in B.A.S.I.C, from C/C++, FORTRAN, C#, Python 2 ... and now Python 3, many have been inspired to re-create, improve, and / or simply experiment with the concept. So far: @@ -17,8 +22,14 @@ Video: https://youtu.be/TpmtCLOJ5Uw Original authors did an excellent job here - made the modernization a WHOLE LOT easier! +Feel free to do a 'Kirk here - Kobayashi Maru? + + + +Enjoy the journey, + --- Nagy +-- Randall Nagy Original: From 6e00d5b16238631b61e9123af98a895a2c54f3c8 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Sun, 27 Dec 2020 12:45:41 -0500 Subject: [PATCH 039/100] Welcome! --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index ea99235..141556c 100644 --- a/README.rst +++ b/README.rst @@ -20,7 +20,7 @@ So far: Video: https://youtu.be/TpmtCLOJ5Uw -Original authors did an excellent job here - made the modernization a WHOLE LOT easier! +Original authors did an excellent job - made the modernization a WHOLE LOT easier! Feel free to do a 'Kirk here - Kobayashi Maru? From 8077847e71a1ff03fd1ac9dcbd29022f33b53803 Mon Sep 17 00:00:00 2001 From: "R.A. Nagy" Date: Mon, 28 Dec 2020 03:20:36 -0500 Subject: [PATCH 040/100] Added a distance-based cost for sublight navigation. --- Calculators.py | 13 +++++++++++++ Controls.py | 2 +- MapGame.py | 19 ++++++++++++------- Points.py | 33 +++++++++++++++++++++++++++++++++ ShipEnterprise.py | 18 +++++++++--------- 5 files changed, 68 insertions(+), 17 deletions(-) diff --git a/Calculators.py b/Calculators.py index cd5d1eb..22326e9 100644 --- a/Calculators.py +++ b/Calculators.py @@ -45,8 +45,18 @@ def sublight_navigation(game): game.display() return + + dist = Calc.distance(game.game_map.xpos, game.game_map.ypos, + dest_sys.xpos, dest_sys.ypos) + energy_required = int(dist) + if energy_required >= game.enterprise.energy: + game.display("Insufficient energy move to that location.") + game.display() + return + game.display() game.display("Sub-light engines engaged.") + game.enterprise.energy -= energy_required game.display() game.move_to(dest_sys) @@ -81,6 +91,9 @@ def warp_navigation(game): game.display() + if dest_sys.warp < 1: + dest_sys.warp = 1 + dist = dest_sys.warp * 8 energy_required = int(dist) if energy_required >= game.enterprise.energy: diff --git a/Controls.py b/Controls.py index 153fd2e..ba0567f 100644 --- a/Controls.py +++ b/Controls.py @@ -39,7 +39,7 @@ def computer(game): @staticmethod def phasers(game): if game.enterprise.phaser_damage > 0: - game.display(Quips.jibe_damage("phasers")) + game.display(Quips.jibe_damage("phaser")) game.display() return kships = game.game_map.get_area_klingons() diff --git a/MapGame.py b/MapGame.py index 1a60017..b8ddde4 100644 --- a/MapGame.py +++ b/MapGame.py @@ -22,7 +22,7 @@ def __init__(self): self.game_stars = -1 self.game_klingons = -1 self.game_starbases = -1 - self.last_nav = None + self.last_nav = Dest() def place(self, takers): ''' @@ -251,11 +251,11 @@ def _go_to(self, dest): ''' Either a WARP ~or~ a SUBSPACE destination is ok. Place the main player (Enterprise, for now) into the Area. - Returns the final, effective, player location. + Returns the final, effective, arrival Dest(). ''' if not dest: return - if self.last_nav: + if not self.last_nav.is_null(): self.enterprise_out() pos = None if isinstance(dest, WarpDest): @@ -263,6 +263,8 @@ def _go_to(self, dest): self.sector = dest.sector dest.sector = self.sector pos = self.enterprise_in() # SAFE WARP-IN! + self.last_nav.sector = dest.sector + self.last_nav.warp = dest.warp else: if dest.xpos != -1: self.xpos = dest.xpos @@ -270,10 +272,13 @@ def _go_to(self, dest): dest.xpos = self.xpos dest.ypos = self.ypos pos = self.enterprise_in(dest) # CAPIN' KNOWS BEST? - self.xpos = dest.xpos = pos[0] - self.ypos = dest.ypos = pos[1] - self.last_nav = dest - return dest + dest.xpos = pos[0] + dest.ypos = pos[1] + self.xpos = pos[0] + self.ypos = pos[1] + self.last_nav.xpos = pos[0] + self.last_nav.ypos = pos[1] + return self.last_nav.clone() def randomize(self, bases=None, stars=None, aliens=None)->None: ''' diff --git a/Points.py b/Points.py index 7825906..6b1217c 100644 --- a/Points.py +++ b/Points.py @@ -73,3 +73,36 @@ def parse(dest, sep=','): pass return None + +class Dest(WarpDest, SubDest): + + def __init__(self): + WarpDest.__init__(self) + SubDest.__init__(self) + + def is_null(self): + return self.xpos == 0 and \ + self.sector == -1 + + def clone(self): + result = Dest() + result.xpos = self.xpos + result.ypos = self.ypos + result.sector = self.sector + result.warp = self.warp + return result + + +if __name__ == '__main__': + test = Dest() + assert(test.is_null() == True) + test.xpos = test.ypos = 123 + test.sector = 22 + test.warp = 22 + assert(test.is_null() == False) + clone = test.clone() + assert(clone.sector == test.sector) + assert(clone.warp == test.warp) + assert(clone.xpos == test.xpos) + assert(clone.ypos == test.ypos) + diff --git a/ShipEnterprise.py b/ShipEnterprise.py index a625093..cc06bbd 100644 --- a/ShipEnterprise.py +++ b/ShipEnterprise.py @@ -38,25 +38,25 @@ def damage(self, game, item): item = random.randint(0, 6) if item == 0: self.navigation_damage = damage - game.display(Quips.jibe_damage('Warp Engines')) + game.display(Quips.jibe_damage('warp engine')) elif item == 1: self.short_range_scan_damage = damage - game.display(Quips.jibe_damage('Short Range Scanner')) + game.display(Quips.jibe_damage('short range scanner')) elif item == 2: self.long_range_scan_damage = damage - game.display(Quips.jibe_damage('Long Range Scanner')) + game.display(Quips.jibe_damage('long range scanner')) elif item == 3: self.shield_control_damage = damage - game.display(Quips.jibe_damage('Shield Controls')) + game.display(Quips.jibe_damage('shield control')) elif item == 4: self.computer_damage = damage - game.display(Quips.jibe_damage('Main Computer')) + game.display(Quips.jibe_damage('main computer')) elif item == 5: self.photon_damage = damage - game.display(Quips.jibe_damage('Photon Torpedo Controls')) + game.display(Quips.jibe_damage('torpedo controller')) elif item == 6: self.phaser_damage = damage - game.display(Quips.jibe_damage('Phasers')) + game.display(Quips.jibe_damage('phaser')) game.display() def repair(self, game): @@ -109,7 +109,7 @@ def repair(self, game): def short_range_scan(self, game): if self.short_range_scan_damage > 0: - game.display(Quips.jibe_damage('Short Ranged Scanner')) + game.display(Quips.jibe_damage('short ranged scanner')) game.display() else: quad = game.game_map.get_pw_sector() @@ -120,7 +120,7 @@ def short_range_scan(self, game): def long_range_scan(self, game): if self.long_range_scan_damage > 0: - game.display(Quips.jibe_damage('Long Ranged Scanner')) + game.display(Quips.jibe_damage('long ranged scanner')) game.display() return From b6fcadd30a7dd7a0a3b81f6004af5673c385aff2 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Mon, 28 Dec 2020 03:50:07 -0500 Subject: [PATCH 041/100] Added a link to the free Python Primer. Pythonic Torpedos ... Kirk knew Python 2,721.3? --- README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rst b/README.rst index 141556c..7f8ac79 100644 --- a/README.rst +++ b/README.rst @@ -24,6 +24,8 @@ Original authors did an excellent job - made the modernization a WHOLE LOT easie Feel free to do a 'Kirk here - Kobayashi Maru? +https://www.udemy.com/course/python-1000/ + Enjoy the journey, From 287c8f9f680f197d9d41f510dbeb3e80cafaf7fb Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sun, 31 Jan 2021 10:41:36 -0500 Subject: [PATCH 042/100] Update MapSparse.py Qualification for Cython. --- MapSparse.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MapSparse.py b/MapSparse.py index 0695d34..374f518 100644 --- a/MapSparse.py +++ b/MapSparse.py @@ -43,7 +43,7 @@ def is_null(self): ''' See if this AREA has anything important. ''' - dum = Area() + dum = SparseMap.Area() return dum.name == self.name and \ dum.number == self.number and \ len(dum.objs) == len(self._pieces) @@ -75,7 +75,7 @@ def get_map(self)->list: def __str__(self): result = '' - for line in get_map(): + for line in self.get_map(): result += ''.join(line) result += '\n' return result @@ -234,4 +234,4 @@ def plot_ones_based(self, ones_based, xpos, ypos, glyph): Add an item to a MAP using the 1's based AREA identifier. Coordinates here are ONES based. ''' - return self.plot(ones_based, xpos -1, ypos -1, glyph) \ No newline at end of file + return self.plot(ones_based, xpos -1, ypos -1, glyph) From ba972603fce34ada9742c9b4a0e1b4bcb84ba5d7 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sun, 31 Jan 2021 10:44:00 -0500 Subject: [PATCH 043/100] Update ShipKlingon.py Cython cleanup. --- ShipKlingon.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ShipKlingon.py b/ShipKlingon.py index 54bae14..710d433 100644 --- a/ShipKlingon.py +++ b/ShipKlingon.py @@ -1,4 +1,5 @@ import random +import Glyphs from AbsShip import AbsShip class ShipKlingon(AbsShip): @@ -48,7 +49,3 @@ def attack_if_you_can(game): return True return True return False - - - - From fc84efb8908f6f39a540931e6e1ed22257faa5db Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sun, 31 Jan 2021 10:44:51 -0500 Subject: [PATCH 044/100] Update ShipStarbase.py --- ShipStarbase.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ShipStarbase.py b/ShipStarbase.py index 50a0c10..a7f67b5 100644 --- a/ShipStarbase.py +++ b/ShipStarbase.py @@ -1,3 +1,4 @@ +import Glyphs from AbsShip import AbsShip class ShipStarbase(AbsShip): @@ -25,5 +26,3 @@ def dock_enterprise(ship): @staticmethod def launch_enterprise(ship): ship.docked = False - - From a840fc66bfa6b82ff2311934ce75c1dded5663c1 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Tue, 9 Aug 2022 10:01:40 -0400 Subject: [PATCH 045/100] Update README.rst --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index 7f8ac79..d16005c 100644 --- a/README.rst +++ b/README.rst @@ -75,3 +75,7 @@ Here is a list of possible improvements: - Easier navigation (using cartesian system maybe) - Make some parts more 'Pythonic' - ...Plenty more! + +## zSupport? +If you want to support the effort, I seek no donations. Instead, simply feel free to purchase one of [my educational](https://www.udemy.com/user/randallnagy2/) or [printed](https://www.amazon.com/Randall-Nagy/e/B08ZJLH1VN?ref=sr_ntt_srch_lnk_1&qid=1660050704&sr=8-1) productions? + From 283e32be950ee667bba6011b1bd728feb165dc0b Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 7 Jan 2023 09:43:34 -0500 Subject: [PATCH 046/100] Create README.md --- README.md | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e1c508f --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +================ + StarTrek 1971 - 2020 +================ + +The original free-and-open Star Trek console game was THE most played game of the day .... back in the 1970's! + +Originally written in B.A.S.I.C, from C/C++, FORTRAN, C#, Python 2 ... and now Python 3, many have been inspired to re-create, improve, and / or simply experiment with the concept. + +So far: + +* Converted from Python 2, to Python 3. + +* Changed in-system coordinates to simple 'chess like' (b,4 (etc)) references. + +* Added random event Quips – should make the game a tad more ‘NPC’? + +* Added that classic sublight / in system propulsion system. Warp speeds engines are now a seperate navigational system. + +* Heavily re-factored for growth, testing, re-use, and maintenance using modern Python. + +Video: https://youtu.be/TpmtCLOJ5Uw + +Original authors did an excellent job - made the modernization a WHOLE LOT easier! + +Feel free to do a 'Kirk here - Kobayashi Maru? + +https://www.udemy.com/course/python-1000/ + + + +Enjoy the journey, + + +-- Randall Nagy + +Original: + + +================ + Star Trek 1971 +================ +------------ + for Python +------------ + +About +===== + +I recently discovered the classic old BASIC game `Star Trek`_ from 1971, through a post seen on Reddit_. + +The post contained a version of the game rewritten in C-Sharp which I thought was quite good. +I wondered if anyone had ported it to Python. + +After a little bit of research, I didn't find a definitive version for Python. + +This is by no means a definitive version itself; I just took the C# version and converted it to Python. + +.. _Star Trek: http://en.wikipedia.org/wiki/Star_Trek_%28text_game%29 +.. _Reddit: http://www.codeproject.com/Articles/28228/Star-Trek-Text-Game + +Improvements +============ + +There's heaps that can be done with this program. A lot of implementations used global variables. +I tried to fix this by encapsulating them in a global object, but this can definitely be improved further. + +Here is a list of possible improvements: + +- Encapsulate everything in classes +- Include help/instructions +- Add extra features; + + new ships, celestial objects, etc + + new weapon types + + crew functions +- Easier navigation (using cartesian system maybe) +- Make some parts more 'Pythonic' +- ...Plenty more! + +## zSupport? +If you want to support the effort, I seek no donations. Instead, simply feel free to purchase one of [my educational](https://www.udemy.com/user/randallnagy2/) or [printed](https://www.amazon.com/Randall-Nagy/e/B08ZJLH1VN?ref=sr_ntt_srch_lnk_1&qid=1660050704&sr=8-1) productions? From 0b74b5ed97d97cdda6b254315905e8731140595e Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 7 Jan 2023 09:44:50 -0500 Subject: [PATCH 047/100] Delete README.rst --- README.rst | 81 ------------------------------------------------------ 1 file changed, 81 deletions(-) delete mode 100644 README.rst diff --git a/README.rst b/README.rst deleted file mode 100644 index d16005c..0000000 --- a/README.rst +++ /dev/null @@ -1,81 +0,0 @@ -================ - StarTrek 1971 - 2020 -================ - -The original free-and-open Star Trek console game was THE most played game of the day .... back in the 1970's! - -Originally written in B.A.S.I.C, from C/C++, FORTRAN, C#, Python 2 ... and now Python 3, many have been inspired to re-create, improve, and / or simply experiment with the concept. - -So far: - -* Converted from Python 2, to Python 3. - -* Changed in-system coordinates to simple 'chess like' (b,4 (etc)) references. - -* Added random event Quips – should make the game a tad more ‘NPC’? - -* Added that classic sublight / in system propulsion system. Warp speeds engines are now a seperate navigational system. - -* Heavily re-factored for growth, testing, re-use, and maintenance using modern Python. - -Video: https://youtu.be/TpmtCLOJ5Uw - -Original authors did an excellent job - made the modernization a WHOLE LOT easier! - -Feel free to do a 'Kirk here - Kobayashi Maru? - -https://www.udemy.com/course/python-1000/ - - - -Enjoy the journey, - - --- Randall Nagy - -Original: - - -================ - Star Trek 1971 -================ ------------- - for Python ------------- - -About -===== - -I recently discovered the classic old BASIC game `Star Trek`_ from 1971, through a post seen on Reddit_. - -The post contained a version of the game rewritten in C-Sharp which I thought was quite good. -I wondered if anyone had ported it to Python. - -After a little bit of research, I didn't find a definitive version for Python. - -This is by no means a definitive version itself; I just took the C# version and converted it to Python. - -.. _Star Trek: http://en.wikipedia.org/wiki/Star_Trek_%28text_game%29 -.. _Reddit: http://www.codeproject.com/Articles/28228/Star-Trek-Text-Game - -Improvements -============ - -There's heaps that can be done with this program. A lot of implementations used global variables. -I tried to fix this by encapsulating them in a global object, but this can definitely be improved further. - -Here is a list of possible improvements: - -- Encapsulate everything in classes -- Include help/instructions -- Add extra features; - + new ships, celestial objects, etc - + new weapon types - + crew functions -- Easier navigation (using cartesian system maybe) -- Make some parts more 'Pythonic' -- ...Plenty more! - -## zSupport? -If you want to support the effort, I seek no donations. Instead, simply feel free to purchase one of [my educational](https://www.udemy.com/user/randallnagy2/) or [printed](https://www.amazon.com/Randall-Nagy/e/B08ZJLH1VN?ref=sr_ntt_srch_lnk_1&qid=1660050704&sr=8-1) productions? - From 3c215daa1666af8ce680dfccb9f289512beced79 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 7 Jan 2023 09:46:12 -0500 Subject: [PATCH 048/100] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e1c508f..a2827b7 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,10 @@ Enjoy the journey, -- Randall Nagy + +## zSupport? +If you want to support the effort, I seek no donations. Instead, simply feel free to purchase one of [my educational](https://www.udemy.com/user/randallnagy2/) or [printed](https://www.amazon.com/Randall-Nagy/e/B08ZJLH1VN?ref=sr_ntt_srch_lnk_1&qid=1660050704&sr=8-1) productions? + Original: @@ -76,5 +80,3 @@ Here is a list of possible improvements: - Make some parts more 'Pythonic' - ...Plenty more! -## zSupport? -If you want to support the effort, I seek no donations. Instead, simply feel free to purchase one of [my educational](https://www.udemy.com/user/randallnagy2/) or [printed](https://www.amazon.com/Randall-Nagy/e/B08ZJLH1VN?ref=sr_ntt_srch_lnk_1&qid=1660050704&sr=8-1) productions? From 552748fc7aaa520ddf001f7b22de27d313679eed Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sun, 8 Jan 2023 09:06:24 -0500 Subject: [PATCH 049/100] Removed duplicate import. --- Controls.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Controls.py b/Controls.py index ba0567f..68504e3 100644 --- a/Controls.py +++ b/Controls.py @@ -3,7 +3,6 @@ import TrekStrings import Glyphs from ShipKlingon import ShipKlingon -from ShipKlingon import ShipKlingon #from ShipStarbase import ShipStarbase from ShipEnterprise import ShipEnterprise from Calculators import Calc From 78edafc34ef823810f4cad2a75f6db440e4a31fc Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sun, 8 Jan 2023 09:08:32 -0500 Subject: [PATCH 050/100] Removed duplicate read_xypos() --- Console.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Console.py b/Console.py index 9f737cc..8094c6e 100644 --- a/Console.py +++ b/Console.py @@ -24,17 +24,6 @@ def read_double(self, prompt): pass return False - def read_xypos(self, prompt = "Location (alpha,num)"): - ''' - Parse: [a-h], ypos - or - #,# - Return None on error - Example: b,4 - ''' - text = input(prompt + ': ') - return SubDest.parse(text) - def read_sector(self, prompt= "Helm: sector 1-64, speed 1.0-9.0?"): text = input(prompt + ': ') return WarpDest.parse(text) From 768726e2613fee267202d92ecb19c7e7b4011237 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sun, 8 Jan 2023 14:21:53 -0500 Subject: [PATCH 051/100] Comment clean-up. --- AbsDisplay.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AbsDisplay.py b/AbsDisplay.py index bbdf0fb..d5d5166 100644 --- a/AbsDisplay.py +++ b/AbsDisplay.py @@ -7,10 +7,10 @@ class abs_display(abc.ABC): use only one display to show a certain type of message. - Networked screens would (let alone game - play)would also be a great idea. + Networked screens (let alone game + play) would also be a great idea. - Event logging would be in there somewhere + Event logging might be in there somewhere as well? ''' From 516208fccd1e3887ea39ed7c8e21c4c104592b0c Mon Sep 17 00:00:00 2001 From: Loondas Date: Tue, 10 Jan 2023 11:53:05 -0500 Subject: [PATCH 052/100] Rudimentary time management --- Calculators.py | 8 +++++--- __pycache__/AbsDisplay.cpython-39.pyc | Bin 0 -> 1876 bytes __pycache__/AbsShip.cpython-39.pyc | Bin 0 -> 782 bytes __pycache__/Calculators.cpython-39.pyc | Bin 0 -> 4143 bytes __pycache__/Console.cpython-39.pyc | Bin 0 -> 1724 bytes __pycache__/Controls.cpython-39.pyc | Bin 0 -> 4812 bytes __pycache__/Difficulity.cpython-39.pyc | Bin 0 -> 1456 bytes __pycache__/ErrorCollision.cpython-39.pyc | Bin 0 -> 627 bytes __pycache__/Glyphs.cpython-39.pyc | Bin 0 -> 274 bytes __pycache__/MapGame.cpython-39.pyc | Bin 0 -> 8456 bytes __pycache__/MapSparse.cpython-39.pyc | Bin 0 -> 8654 bytes __pycache__/Points.cpython-39.pyc | Bin 0 -> 2987 bytes __pycache__/Quips.cpython-39.pyc | Bin 0 -> 3504 bytes __pycache__/Reports.cpython-39.pyc | Bin 0 -> 2288 bytes __pycache__/Sector.cpython-39.pyc | Bin 0 -> 2439 bytes __pycache__/ShipEnterprise.cpython-39.pyc | Bin 0 -> 4340 bytes __pycache__/ShipKlingon.cpython-39.pyc | Bin 0 -> 1889 bytes __pycache__/ShipStarbase.cpython-39.pyc | Bin 0 -> 1280 bytes __pycache__/TrekStrings.cpython-39.pyc | Bin 0 -> 2273 bytes 19 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 __pycache__/AbsDisplay.cpython-39.pyc create mode 100644 __pycache__/AbsShip.cpython-39.pyc create mode 100644 __pycache__/Calculators.cpython-39.pyc create mode 100644 __pycache__/Console.cpython-39.pyc create mode 100644 __pycache__/Controls.cpython-39.pyc create mode 100644 __pycache__/Difficulity.cpython-39.pyc create mode 100644 __pycache__/ErrorCollision.cpython-39.pyc create mode 100644 __pycache__/Glyphs.cpython-39.pyc create mode 100644 __pycache__/MapGame.cpython-39.pyc create mode 100644 __pycache__/MapSparse.cpython-39.pyc create mode 100644 __pycache__/Points.cpython-39.pyc create mode 100644 __pycache__/Quips.cpython-39.pyc create mode 100644 __pycache__/Reports.cpython-39.pyc create mode 100644 __pycache__/Sector.cpython-39.pyc create mode 100644 __pycache__/ShipEnterprise.cpython-39.pyc create mode 100644 __pycache__/ShipKlingon.cpython-39.pyc create mode 100644 __pycache__/ShipStarbase.cpython-39.pyc create mode 100644 __pycache__/TrekStrings.cpython-39.pyc diff --git a/Calculators.py b/Calculators.py index 22326e9..a5ee91d 100644 --- a/Calculators.py +++ b/Calculators.py @@ -105,10 +105,12 @@ def warp_navigation(game): game.display() game.enterprise.energy -= energy_required - game.move_to(dest_sys) + n = lambda dist, speed: round(0.5 + speed/dist) #Quick calculator for time passage - game.time_remaining -= 1 - game.star_date += 1 + game.time_remaining -= n(abs(game.game_map.sector - dest_sys.sector),dest_sys.warp) # before moving there, adjust time by lambda calc + game.star_date += n(abs(game.game_map.sector - dest_sys.sector),dest_sys.warp) + + game.move_to(dest_sys) game.enterprise.short_range_scan(game) diff --git a/__pycache__/AbsDisplay.cpython-39.pyc b/__pycache__/AbsDisplay.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c4a59f51d6cf8ddf44cf1473958039ae31a2f734 GIT binary patch literal 1876 zcma)6UvDEd5Vvq*amStes@9o88uS znkGu0TB%QbhxYNl1JAtj?pL1r748LQoV1rKFL>qI@p#7LnfZ;y@^X#9`0MhI#&Bd!!lNfDUOVNEZj5fy3+rQ6#34 zphX#}h{;<{XwEAqhw zjT@IFBJnbKe$UlK$8edNqfCrNixN^}F!uY3fh1?CVYXm>aiW+}CrXP9<%#lQuR6D7 zY2GdLK-jd%Ti!mEO3dxO;?O8oB9~jMwE1BVu(yq#R znx~fYxIT-XW2RhbluFxo<-SULee0srqr$jo473@!$f&Fvmr#-GI$S|FfV`$|iSr~A z#&G_cym_8HJ9uf7HV2!#J3qA#wu(`n6+)T=V}-U_9X|c~tEW!}!dRu>ksWMw%+?G* zt)sEVw)g<1@%=$-wCumh+5*s8w_zj!XxCJz@~&iCK(h?PM{-XjBMO1H>wD`!xXD>4nPDJ91d@>nn5s=?%i zuRAu$c0L?HM_9mA&V<$ipxtH0YCw?z^Z>T+bg>4l`4w7s(sq+-%vCd-1y`RL^DH&i zm1m3lfi|#T_^lT(Hf12BRHY3%d9)buqN1Z;BpB`OK${9oAGro*8knl25P2Yj$K))q z#L_9X@KpUCoYONvsEpRh8D;}98?6z{j?dSpXMk9g%F;TSmaahenywSS3f8^e@w0n& zA)vcF>D*=Ff85j;Aum&r$285I% z8qq3Ug}DOr6QGmz|I}x0Mg2XSE7;*VJYSr<8s~#T4m0E%oF5NGHs7gmE{g;nf!f|a z-`f6hx4bVFP9Rh4evde6chG;+E&n zK?08(UyN}TRj|o4_7$SYU`JMIw2UD}!CEDvwXnM6_W{eF!LAE8e%SPag>0djKgm_U OnZ@=kR>t>hHTV}rlG9!Q literal 0 HcmV?d00001 diff --git a/__pycache__/AbsShip.cpython-39.pyc b/__pycache__/AbsShip.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7ee5c57506f57641f7f137e2b80f3d4aca2deb94 GIT binary patch literal 782 zcmZva&1%~~5P)~JvZSO=NZ&xGf}u6|6k1A2>d;UqF2(Id7?!nmV<}xp&h9EDrndz8 zEP02%L+^X-sjtveXXMzpv;#9cKg-OwBZ-59eFF01+xPsK67my+T?rvL0kvgsq?-fQ~^e?n%RRc0>O-sa#XT_zlz*S)FJ_-Cw4aUNzk55Goi$%--3V!C)(PW` z`aF7mJbG3Mz%zg4W)F`TE^mCod0Cf^^G8U6NQADAHWxOWg^#60(hVs4!gxvP{b8fox3I~ZFQgTNSBGzkrZgoU)r4q|fzIUgBO%ck-WbRRXLNs!P!?FWAVSpTi# literal 0 HcmV?d00001 diff --git a/__pycache__/Calculators.cpython-39.pyc b/__pycache__/Calculators.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3a8eaa9fbe5f00e9b74f5c7c5bbc6165fffcd0fb GIT binary patch literal 4143 zcmZ`+OOM;u6(+Ap>M@#^J$@uy%}+C_f=R|UFqx82RA{m!K{BTZZhJomwKU+13h zJBR+_V#UDkFMs%JYirFg{zZ-1UjdDe@u<%rxWUcP=$Q@Eq&f>(gP|;hg(uW5gw~|A zb!ml8uh=M>#yx}E+<9Se=Q(SXINLO8#aEcm_}0uUwJVd2nwgoGAQnHDano-GVUPqu zwMb|7ceI-)=oLo8AH=&UKRZg>P24C{YBKvyrSzR)E9VF z*UNkn`&!DZ+kV(;nKR2es9Sh$<5Ay1w2fzGYREsQMi&-2Z#-jp?VRzffSRfMth|Ok zJ2l5FwNln*2e6!O*=b>>WzDthIZe#>z4rWA>|$mvoAxqo<3wyUs<@NiW04GG^Z#gt=BUpMY>`t;e{)W9 z0lg`l09>DxK)rA?Bi_TCS0AE_}m4#mK0O=+=QQ#MyXrgv1LcklKb||EYwRg>bHe_ zjc&;@y5+QR-C%}Sp3$hJlU?Bb0=M-0g%q&sR=M>dX;*2z@nULBXX-A=f9tvJ>HfJh ztnpbpj|MPZ9_JuaVs{{L_4RuF@XFl? z9^RLM0)7XrmQZSY5QamoEV#QDBpsJ9(e$xdsX=%)t4QHP2w&-k{!o%@$kPy6 zsqOcK*Yo?bOnoKlD}W5L3XV8gEpzgtW<@%ym&Dmp5@3`RJwJ$Wf~-u-dfZP$wxT+* zOg!mFZQ-ewA7u_5M)2%3%ort}j}3V{A%?|~$`&>|LH}2ID_ixG#Bc3*!L~Py2c8}* zMc)r3Ch>bPp0xD_A3WZyS(!z92RwvIJT(N<5EQcIe6!fy?jVqYpM=wCHE8O4@go0e z(AL-W9%fZHAP8B+29Sjnv-DpJ?P}getpZknWZ(!^)ot(wThZLHWRA{HxZ-=$&q0%H zPvKWX^B)?TT^&AlEP0(Xf+0d%;ec`LEieWJow3CM#jlN*Q@B|Zh}nQNOPOkDohcCX zTY@z8YE9O400%=#4j_9@O6|fL0vCW?0IG!vfUJ<6+c<{UM@#y{E__BXQ3AtDEy8F=I z4|;>1yGL)g{T5=@x+{^K8JaCdmtRLc#5&S{Dnb|3qxnbm1qfzzW^R!w?~KmS?8G?R zGVUP<$X6LviN20niwONmocJMlXx$w-?f`LLwJ2gue^jRkvx!HoKqN3)3P&Y})gg{; zOiujIkC5QmI;*HLc?r6itv7iRmZck^-)nOJW)C|5!DEarYCO@NXP{cYK^z;Zo2cXi zM^oGO2iwP1480)FDp_Bev{`(aY2(~e)Pk}`cgBSf-XW(5N*eqMKLb3sO#iaE+RbcdDAFOc2op% ziaSdbb#$y*G2g=#jZW!HnHw;7B?XKla?z2bgUbAsP`Z~O4}FegZ-+^wIWVGT$4P9! z$D3w1x*V52XY^&TuB9)7=}U25>O^aIeLA-`d@<*^(S2CgFeN-t=LcRNiq;M;L2?1OX7<0U>YTM7H2!&8YGX^i@26uLlHuYg~Do$E?RT~W) z+V|idm{R>7E2vWtWa)~I>6Qk`+ve!(v7Kj!Y}6`Q$piHu)$y{5=k;Pf2&rE6yxoBx zPTo{;n@P~>iKG*ANpz@FD|wk}zaVj!#AhVvi)Kbpey@`;O1>0Xp~RS3Ig7`}a}m!q zJWI^fTD5X!_57qG>E`9nAhO~^zkiR?pyI8jqFgF-KGz>}*}|QGQq=*zs)w3~@~rPQ YJIG2m@}u3PoKaOFs+v;hE2GN(2irya7XSbN literal 0 HcmV?d00001 diff --git a/__pycache__/Console.cpython-39.pyc b/__pycache__/Console.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6bd86f82b0476c76206af57ea51ab2de2afa7ef8 GIT binary patch literal 1724 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 wl2}~0iwpcUZ)eAYnwK01Vks$s^=1 z{J1PGeEa~zybnqc;ber9J48_7J|n_?O1UGPh_t4;c;KocwP9sA?kbs?154q|i(zMoG=mnXyH#7Kv5Gv{U(?0|Vsz z9}w*zsuV?pX`I(k`Jhs?y%NMY_F$NgK|KLRCPX)d^P2;hPCR{GP{fwRj&PB!#iTkA zgB+bn);+k>4TsDE%;Y1P-KgNGu?PEJ%h%Pd>1K)2H*mu#-Gj2+7k`<#8t!rkbX z8|*7U)o#&fETXgtvdE4(Jh$$yPMt~-!)R3@!p_! z&>!y?^J!Kj!i?s{NuHd_?^kw>7pUu? zAa7qMQ&Hq)9skwTzNC5+W=c<4nO8I{)fO5z(zn{7YVM5B&>R z`GnjjI>5$(qHylh3561YFY7+{u(e)Lu-2f6I>L*f=^(+{g0B*Z&Wc$k*j&DmVy~D> zW0yt5K245`N3zXirgAk+tTY$?%oglm6dtZN{PA^(jM{z~C=-J>HqNqK>QVO~?CnQ- z2ZGmli5i~`eH9g!%q6a_n<}~swqiMj8hN0Vk=Pps=_J1IcuoN0DvZS^>m2ls)}pSe*tkqQw0D3 literal 0 HcmV?d00001 diff --git a/__pycache__/ErrorCollision.cpython-39.pyc b/__pycache__/ErrorCollision.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f79a6c2c94fea41bf54da0e0e0093120bc908de0 GIT binary patch literal 627 zcmZ{hv2N5r5I|>bU+|r{j)HP2U0^8{0zrfnP6&aH0?}BOR-4@ou~>V}j*sM`bcuAo z0cHMyf1sgq%O}uLF}pd?rC_8P&&=-Zycx^+duktF}KnB%>>a+3w!h7cz-C%t0 z8#IT`+6Eifogd6NNm-Ws$SAo&!_l>d_ud^@(;~;F?d_VM$j^okj-SeAh_{~=u}~#D zT)__-=;Aa3T*4Rj6&PHw3lND0qG8J-9VfWzjURI%nywjy7$+a>x<4tBF+*dIeOSsh z8>d1jD-ngbhTpH%llnaxkM-f(H?NlU3wPRCCpFeMNI!VvdyMn# z2+CMXxtzM)n7!algJFSyG_vF@OJin9%a|_Cl<5chQ8Bes9p4GnWB&Ap;~+foixmC< Dmu;MC literal 0 HcmV?d00001 diff --git a/__pycache__/Glyphs.cpython-39.pyc b/__pycache__/Glyphs.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f966aaee4f2c0068ed2a482418b07eb4a303e90c GIT binary patch literal 274 zcmYe~<>g`kg7fWrl4k+w#~=!?c?d^?(Y}H=I#?2;1Rr%p$Oy(F!9Sd*(xTq zIJKxa#@QdJEXF0jJTE6dF{L=BxFoTtq$oAp(9+ycH#f1kB((@dEXF;jvLK^aub}c4 XhfQvNN@-529V5tRpa5WDghD0&OSD1? literal 0 HcmV?d00001 diff --git a/__pycache__/MapGame.cpython-39.pyc b/__pycache__/MapGame.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ea062523d1a30797762fe90ea4ce4e8d9b8ad5c5 GIT binary patch literal 8456 zcmbtZOKcoRdhX}UaQF~K$rANgZ(Dw8Y>Hm*I`OX7yEa9Ul3?waASoz2mN6MkH^~__ zr-#)&k~tXq5D77I2?7K;1iPD%ha7wikX!beYl7qy^dX1MNkFid-1d@u-`_pmGb9}> zkQsD!RdrQ&{eOM`vl`RWWevZ7`TEz*=9`-KpKOf&EHpmB6+TAcYOd~UwdAhXbZHwk z19!tWcg>oq^O@;eo4i}Ty=&KO>9hU9Zn0LBy6%^1r8}BiaEmWAx9FAH6VJ_B+0{3+ zO6euOqg5+VE3CI@>`9P5m7dg$=J61q!wK6{P~T(uq9PRjtrl4t&2Awt`NR z^GAQAfWPpTu4$geRo9HKwJqJ%UE@WmX1buT?eg;-n_i?HTN1?m(tej?i*-b z_O8gYH{G|;x|%+F+r5s~chZ$r+;`A=HGTH3yMWer-5c&AXm{Knq~Cha{T`@&?Q6}_ zYS*wsAH>Bwja~0&jcyYR&3>$#=@s5YCDNX2hx(C*E!PKH-EehF!`;MXNsldMLCRuO zdd{a4u7OXO{k5`_{??S&Z79!aIB#z%?@6oCanjE_TY+-6dQlHgv*E2yD{3|TR=*Je z42xO+%m2ZzS}DhN*z0;KF4gNCTCc~2P%sr+Uv`5qw)R<;w?Sb&j2bG8r=|WR0b&@> zWRD&jixZ7ytcP z4#L>QA!SX2gVG;o+PIc+g(YlOqz&}vdN@U?i*(ix^vK}-w)Vwu9vKJ5fjKb4clNGE z=Aq>p1M|o@um+Hpo~CZOChAsrckile9M}VUU_CL_Z!yxQG+|_6pdA(lg(Ll-DDzF% zMsI0gxCZ9`&7gRQEpJa8K?X7NFZS-Er=0ZYTIVB-<9Gfc?VUW*(fby93+Rp0*;ANZ zd}678&Ss-W*9KU_hg!NSL*3u|EuQNG!`3e0*$;uzk2FvohWdk9naYXmosEl6`}u9iceT8u^{hXQXVQZu^IMuV+-mj ziYL5IZ`V_e$cqa~z7-dF$E)KBR&Z^5acSF&>Og%Xo@xfYPE_Ca_q#h`T)30mOB$jFRR^mxnX!1O^*c}%?1;FlnR*mhb*Y&;1ggS?H#D%Ew1o*4j&vshPotoY8d~df_ zjDk8J)NGcW*a!h>ez`Uo?gTyGm8a?g-jEa*`7T?&dIi<+rzkY5q+5DPpG9c^k!-QX zzA3#dJ+o-fpv{YQj^emEy+1ufuDrE6hT8()j!SSmKn1wcjabexcSp`6WK_n-_rp{!sFpZA?F7o2^^51O)) zbWX3?^ujP-&T3^ME_R;@-qhP*v4SI@#pRr;xLEJDJj_y)d_2X+wm?!*r&J0F!Yop) zZlI@Dc$r>gtkp_Uy@xfZ_gQ?O1v#s}$0Flo#T4!d-(nNW<~Xy? zjgULs%0I#@LheH%dK57T(v?#fG@JpSsh|WOV+^C7;w22bjLHbZE)29b829I5!Ug>w z=ftghyTMaWpq2y0*;2u-^mUaNV%^Tt`pQy1sai1uoi9 zeu{k2(#;@Hu<&?^BU&+^Ev^I9Cu6YKrrCv!hlc>|8Bf5M+mKbn6UiMNv9*Lj-=rc# zReMZi1ZH2MKa{u*F5(paWxao9$lFxYk6BqVHDfF_F~I^`s8dy{`A9#+omMu|pOb-l z|JgC4<0O&U^$NTs_~pBa!MW}&ZZA6b*EcHStT(_`ui4saHHDcuA5tzREX>{{%sa+0 zXv^10HK83(P~9X-Bvqm$`ZT!3lVP*bsVA=fpJ7l)FO42FEln;>BcsNUH;irsdDOdP zPz0QjDc|V*cQba}4W7Y2?Cd*X4;ByxVZnK@xUsnLaWca-Hlc!dsyP

-UF8biWIVnRXe2B4&gh79e(Zdy8 z9U|?tf&ZT+UH`Tv%^v$w__rg=ng5pMgkut5V@4(c)XeZFp+v;jq^VdOnBqKK5Wf=M zCzQ(tMl*;sj6KvK6=wfdu2wc1KC}nD!$h8)V9QCocu0u!-(Fc=dT@X9n28jXpysgx zY{$6wFlsnrTWC(O{vk#m!;S3Z-=RMV6|KaHDg*4Ja36u;*v1fBw6g;DEmYFr9To*a zx`gxKjVTIu6$%&qZRm?bE3(^&`96e8QO8L1LK#bMG3`ypf`8ImN_&mH%c;>_&BWwE z*QLgcc3L3=uD3&Q5SjzQy|c}*Eb&Nhv^qCn0>NqWJDV(AtRnPbpsdcYm}c=47H_Z+ zkc-p_(gj<$_~4lQP4{FS38%up$B0C;T655=7x2&B(y@_a=%ThF!i1lTsHDgOA7HZ1 zGjf3=V!~{hh-P4v_ogtyN|GmHu(mVOQtRAsnn-yeFh!b!*h<*pBpNqF>MX1*(N zvbFV<4ft!v>{PCas{omx?jx)+cT&}-Xr_j}HYwkN-c^nLZv|j{Ht_~TJ=a^2w;TQ= z-jV8E#(r>EFAZh$#Mm)7l64vTxJla@L6-)CSvUt)zHwki)^m+QdWbL%L7&+!lA!=x zX<#uuus1)T$D{X`M_8J=0Dv0pE3gLaHN<9pDhWu5{%Pff=$u_Zn7BUnUe8neBcP%L z#U-&%0B_F7xX|c!y^fp8GNOMkgtrh1A7hK3MFI)icN~Xjhbe)~3j7nEjvf(hIfoCbvxeiJUZNU3Hc4@csl zhfC{K_>niA5T7!Q0$z_G_~E_#_Yt3p$a8x3>1F_@tP_o}Jawfds3I7Sb80rD zJ8{;+f5o7XBB&KgdOx!V$A_Je*vuXzuI3PKZDfwm15j;f|MS{K*363`J6J*g~rP7Jq3`6wprx2~gcBUbA#!;9^(da+JO4Mg4MopwzW3Twg4_P~=*o(6NzW*CMOI12^ z4>QzDnX{aZIUzV1H0ZJo1xMUu&@L3_{@ya+3`5q)U1X%R1I2uSI^hV6k|uhXxK+z6 zPQ&^%7YL6&acuvKqzKTFkjw4T*q9TfWIAAWgcPVtgi}Juk8>+>$LmP$GI3d;*Jya? z;tZqxWEm%9H5Oh|51vAUdW7%(_t?tE*pF#r5G3m}_WuXhtcN8Au?+dR>hLl)#7J!C z0n$7J9VWq0e+>Dwk!`lrP1fMY;9`c5_rpSxQ)GXePxN+CYQ@f7)Jv|3EOnnX%q!tO z!NUrSKpkxjZJll8ywj-3HIQxQGsCr{HbHL@HO^1^_=dC(-^_YZ=bN>|vh0A}|8>3t zD=n~F0ZY)SYtC1J`U>@p2e&rXmX=o#dS+Qi2kJF=lJ7*G!JxWkdV3%5xxSL+;T8mr zo!}WGxHQi#dOSm9BB>+UMPxR&w&;O8^G{6;FGC|@c~&Xi_x z%}vgfXA1J4LajVAH8U|&!o4_CEWIXkE0eOT@gz@oHzEaqgoz(b!xR_R0uUBTzNa=L r$06BKzZ^b{u!Tz*S)|0 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 F`xj7+QHlTn literal 0 HcmV?d00001 diff --git a/__pycache__/Quips.cpython-39.pyc b/__pycache__/Quips.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c635ac25a99c903e0099db46a3dd75465ec0a7ad GIT binary patch literal 3504 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 RMd$2@4y<%;%zr4U{|6k9AK?H1 literal 0 HcmV?d00001 diff --git a/__pycache__/ShipKlingon.cpython-39.pyc b/__pycache__/ShipKlingon.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4b1d5a39d1bf5f1d06e4519d4954c234cfd8185d GIT binary patch literal 1889 zcmb7E&2Jk;6rY)$U9TOdNlIFf5NIzTSt?P=g;F8fD*d1oxe}p5T2hUsI}>}I^{zWJ zE;zAIiIl$qPWG|?11C=0xbKxyZ=5+0-diWB+i+o4`{wI?{N9`Qo?KpT5Ey?P|C;n_ zg#3w{#lc~78-BY9L=i_z_WDvqLZT6x}8*{}o7)c8iv^ zJJ0NPHytE+usFQajlBU2O;Bmfj>#@nRI#HF6jf?tu6z|7k=WOPs;TgZ9MZUUOgM={ zFjOy>Q2V1S%{xV&&;<*)X7HmS8v$|TkWA@}Q1E6<1gj|Eg*8_Ml(Du!p_X6zb~wE1Bxmo5Ot{7bs!V?fi!lb7j2Tes*c5`U*bH~`z1nrFJji8}vv{504>?UK< zBc_2#t(fvM+Gi6=@zk608JRHWkJ%x3v&YRpV|JH3{e9xWZP2TkoiUk)icjlfuh&ri zy9DMXoM&tXI-YNi>9mQOdX0)MAs_P0_=Ky#El)3D#?RO~QQ?@Y`upTPvQ8#G>gS}l z;#SB0A-w@vE>yxJ&QM-tg?8}ah)KEvR zh_IBNNe~4Ys7Sl<3KQO32GW7Q8mEiDZgqb78OO)BzuVvXKUN{#QFo+FF&Jotb`L(C zY_u+y_0&Se7kgTjOX$rolYrQot6;bcJF>4a3F9>^5^1y)d-FDBOE1%T+0f^{mw_r0 z)KgQb9b|G;2D^pnOZPg-;}EW#%oAXG3WbC6$R=2g80BhqC50=o3gMF0Q* literal 0 HcmV?d00001 diff --git a/__pycache__/ShipStarbase.cpython-39.pyc b/__pycache__/ShipStarbase.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b919fe5b4eec2c45003fd96dd32395acbdf9af84 GIT binary patch literal 1280 zcmZ`&OK;Oa5Z<*N$4MPR4=oZ@<%$m=^@Knbq7+(HLO~+sVnteQz1zfe{b1KAYQ?RU z`ZwU%f53qwckaG&>R;f*jPsDwfGvNXotd4-&bPeNX%l#UUHyoDT7>+@Mg4JL@e)4s z2tW`)6$$ZgDVorbQnF8kEu2dt97!+i&=Ryyg2oMalU_i}=FXAnkK#N+Mg6g-3$qP^ zBq0?fw64f86;xQ4UT9CkhK_8AhHx**1r1%0o5HK)<`r>B=s~hp>0^d|!SxY0GNQFK zC_`HWvza>p1-T$!={G{5i9Wfey}&9PW}Hi1dW^+sTrhS`OUFoc4F48mk>bXHlKeS{ zo)114sm);b-P?oS;C1#nRT&p%U?6v)<;m8wr(2H`ZVIUvbc1?Y7^vWE3kjmCj7Ho)~ zEm+R7uPJNOE_jI3x!~Day}f|y2cXm& z2)D?vs`xmKMzyl;gV%%<*7@c_2}`bU?clQFUA~-`k#4_yRd*Fq%hw>o4uOICB61 literal 0 HcmV?d00001 diff --git a/__pycache__/TrekStrings.cpython-39.pyc b/__pycache__/TrekStrings.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6d4e6d1d188d63cc1ed5d20589a090307cfcf02b GIT binary patch literal 2273 zcma)8&2k$>5VjNj+a@V;;XuKhFs_R1Bovhj5DHmVY}t~nNV1(wiQ2SxC#xZ=9Wk@( zL{r>(4dBK*aNrHN`^qD57MSde|NpKwpLrh`s?RE{6BH}+c8(y zbui!I&wPe0So&otSpIdHFNaIPwcnQcHPGvz*Fg)Qg`hZC+9**CW;M3BylkGo2lwx?I=gr0-kt3JT~=8@SGGBz_b#K6 z=Y9S#Ut8WoFN<=sUSF?2tJgOH_AcAG1JJy9&u-W2w=*+90OY-lq55nzg7)U-*83Q& z1KCC9d7D3df3aNK=&_yuI$>Lip~U5dT{rCeb?6ZQvE{Z zE=z4+ArD(?pDTTtac@C{CnZeFB0u zWwo}oCn63c8_-$GOHX7RAcwW51jnyESHTJ-?e5ISW{sNsG!)EOI9FpSqQGnvt;>mZ2?@VeTF9_&Kh?sANi)TGP$JI- z+eJ?k>9f8-j{|$lpn$+kD8cym#S~fFkKdLm8lgkAFsH6tKl6sx~;)Qb+6Uwdd=?6fLEHmG$yW)(RN1gWJXh*$_BSnE3AyS=a@xuLIsZYqDCJVCB5SN1lubL8bg3UDj}J literal 0 HcmV?d00001 From a4a3f5445c63b2702031c5db8923cbac7dfb6078 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 21 Jan 2023 08:05:38 -0500 Subject: [PATCH 053/100] Delete TrekStrings.cpython-39.pyc --- __pycache__/TrekStrings.cpython-39.pyc | Bin 2273 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/TrekStrings.cpython-39.pyc diff --git a/__pycache__/TrekStrings.cpython-39.pyc b/__pycache__/TrekStrings.cpython-39.pyc deleted file mode 100644 index 6d4e6d1d188d63cc1ed5d20589a090307cfcf02b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2273 zcma)8&2k$>5VjNj+a@V;;XuKhFs_R1Bovhj5DHmVY}t~nNV1(wiQ2SxC#xZ=9Wk@( zL{r>(4dBK*aNrHN`^qD57MSde|NpKwpLrh`s?RE{6BH}+c8(y zbui!I&wPe0So&otSpIdHFNaIPwcnQcHPGvz*Fg)Qg`hZC+9**CW;M3BylkGo2lwx?I=gr0-kt3JT~=8@SGGBz_b#K6 z=Y9S#Ut8WoFN<=sUSF?2tJgOH_AcAG1JJy9&u-W2w=*+90OY-lq55nzg7)U-*83Q& z1KCC9d7D3df3aNK=&_yuI$>Lip~U5dT{rCeb?6ZQvE{Z zE=z4+ArD(?pDTTtac@C{CnZeFB0u zWwo}oCn63c8_-$GOHX7RAcwW51jnyESHTJ-?e5ISW{sNsG!)EOI9FpSqQGnvt;>mZ2?@VeTF9_&Kh?sANi)TGP$JI- z+eJ?k>9f8-j{|$lpn$+kD8cym#S~fFkKdLm8lgkAFsH6tKl6sx~;)Qb+6Uwdd=?6fLEHmG$yW)(RN1gWJXh*$_BSnE3AyS=a@xuLIsZYqDCJVCB5SN1lubL8bg3UDj}J From 2d74aff738efa2e5dbddbeb9fdbad41e7f6ba025 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 21 Jan 2023 08:05:45 -0500 Subject: [PATCH 054/100] Delete AbsDisplay.cpython-39.pyc --- __pycache__/AbsDisplay.cpython-39.pyc | Bin 1876 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/AbsDisplay.cpython-39.pyc diff --git a/__pycache__/AbsDisplay.cpython-39.pyc b/__pycache__/AbsDisplay.cpython-39.pyc deleted file mode 100644 index c4a59f51d6cf8ddf44cf1473958039ae31a2f734..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1876 zcma)6UvDEd5Vvq*amStes@9o88uS znkGu0TB%QbhxYNl1JAtj?pL1r748LQoV1rKFL>qI@p#7LnfZ;y@^X#9`0MhI#&Bd!!lNfDUOVNEZj5fy3+rQ6#34 zphX#}h{;<{XwEAqhw zjT@IFBJnbKe$UlK$8edNqfCrNixN^}F!uY3fh1?CVYXm>aiW+}CrXP9<%#lQuR6D7 zY2GdLK-jd%Ti!mEO3dxO;?O8oB9~jMwE1BVu(yq#R znx~fYxIT-XW2RhbluFxo<-SULee0srqr$jo473@!$f&Fvmr#-GI$S|FfV`$|iSr~A z#&G_cym_8HJ9uf7HV2!#J3qA#wu(`n6+)T=V}-U_9X|c~tEW!}!dRu>ksWMw%+?G* zt)sEVw)g<1@%=$-wCumh+5*s8w_zj!XxCJz@~&iCK(h?PM{-XjBMO1H>wD`!xXD>4nPDJ91d@>nn5s=?%i zuRAu$c0L?HM_9mA&V<$ipxtH0YCw?z^Z>T+bg>4l`4w7s(sq+-%vCd-1y`RL^DH&i zm1m3lfi|#T_^lT(Hf12BRHY3%d9)buqN1Z;BpB`OK${9oAGro*8knl25P2Yj$K))q z#L_9X@KpUCoYONvsEpRh8D;}98?6z{j?dSpXMk9g%F;TSmaahenywSS3f8^e@w0n& zA)vcF>D*=Ff85j;Aum&r$285I% z8qq3Ug}DOr6QGmz|I}x0Mg2XSE7;*VJYSr<8s~#T4m0E%oF5NGHs7gmE{g;nf!f|a z-`f6hx4bVFP9Rh4evde6chG;+E&n zK?08(UyN}TRj|o4_7$SYU`JMIw2UD}!CEDvwXnM6_W{eF!LAE8e%SPag>0djKgm_U OnZ@=kR>t>hHTV}rlG9!Q From f4b69be4d6d058fec02ce61d9be53c6fb994ee93 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 21 Jan 2023 08:05:52 -0500 Subject: [PATCH 055/100] Delete AbsShip.cpython-39.pyc --- __pycache__/AbsShip.cpython-39.pyc | Bin 782 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/AbsShip.cpython-39.pyc diff --git a/__pycache__/AbsShip.cpython-39.pyc b/__pycache__/AbsShip.cpython-39.pyc deleted file mode 100644 index 7ee5c57506f57641f7f137e2b80f3d4aca2deb94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 782 zcmZva&1%~~5P)~JvZSO=NZ&xGf}u6|6k1A2>d;UqF2(Id7?!nmV<}xp&h9EDrndz8 zEP02%L+^X-sjtveXXMzpv;#9cKg-OwBZ-59eFF01+xPsK67my+T?rvL0kvgsq?-fQ~^e?n%RRc0>O-sa#XT_zlz*S)FJ_-Cw4aUNzk55Goi$%--3V!C)(PW` z`aF7mJbG3Mz%zg4W)F`TE^mCod0Cf^^G8U6NQADAHWxOWg^#60(hVs4!gxvP{b8fox3I~ZFQgTNSBGzkrZgoU)r4q|fzIUgBO%ck-WbRRXLNs!P!?FWAVSpTi# From fee9961eb1d721253d32ec993699c4fd3bc68762 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 21 Jan 2023 08:06:00 -0500 Subject: [PATCH 056/100] Delete ShipStarbase.cpython-39.pyc --- __pycache__/ShipStarbase.cpython-39.pyc | Bin 1280 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/ShipStarbase.cpython-39.pyc diff --git a/__pycache__/ShipStarbase.cpython-39.pyc b/__pycache__/ShipStarbase.cpython-39.pyc deleted file mode 100644 index b919fe5b4eec2c45003fd96dd32395acbdf9af84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1280 zcmZ`&OK;Oa5Z<*N$4MPR4=oZ@<%$m=^@Knbq7+(HLO~+sVnteQz1zfe{b1KAYQ?RU z`ZwU%f53qwckaG&>R;f*jPsDwfGvNXotd4-&bPeNX%l#UUHyoDT7>+@Mg4JL@e)4s z2tW`)6$$ZgDVorbQnF8kEu2dt97!+i&=Ryyg2oMalU_i}=FXAnkK#N+Mg6g-3$qP^ zBq0?fw64f86;xQ4UT9CkhK_8AhHx**1r1%0o5HK)<`r>B=s~hp>0^d|!SxY0GNQFK zC_`HWvza>p1-T$!={G{5i9Wfey}&9PW}Hi1dW^+sTrhS`OUFoc4F48mk>bXHlKeS{ zo)114sm);b-P?oS;C1#nRT&p%U?6v)<;m8wr(2H`ZVIUvbc1?Y7^vWE3kjmCj7Ho)~ zEm+R7uPJNOE_jI3x!~Day}f|y2cXm& z2)D?vs`xmKMzyl;gV%%<*7@c_2}`bU?clQFUA~-`k#4_yRd*Fq%hw>o4uOICB61 From b46c299d894764a6c01d5c7adefd0622aa4ab2d0 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 21 Jan 2023 08:06:06 -0500 Subject: [PATCH 057/100] Delete Calculators.cpython-39.pyc --- __pycache__/Calculators.cpython-39.pyc | Bin 4143 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/Calculators.cpython-39.pyc diff --git a/__pycache__/Calculators.cpython-39.pyc b/__pycache__/Calculators.cpython-39.pyc deleted file mode 100644 index 3a8eaa9fbe5f00e9b74f5c7c5bbc6165fffcd0fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4143 zcmZ`+OOM;u6(+Ap>M@#^J$@uy%}+C_f=R|UFqx82RA{m!K{BTZZhJomwKU+13h zJBR+_V#UDkFMs%JYirFg{zZ-1UjdDe@u<%rxWUcP=$Q@Eq&f>(gP|;hg(uW5gw~|A zb!ml8uh=M>#yx}E+<9Se=Q(SXINLO8#aEcm_}0uUwJVd2nwgoGAQnHDano-GVUPqu zwMb|7ceI-)=oLo8AH=&UKRZg>P24C{YBKvyrSzR)E9VF z*UNkn`&!DZ+kV(;nKR2es9Sh$<5Ay1w2fzGYREsQMi&-2Z#-jp?VRzffSRfMth|Ok zJ2l5FwNln*2e6!O*=b>>WzDthIZe#>z4rWA>|$mvoAxqo<3wyUs<@NiW04GG^Z#gt=BUpMY>`t;e{)W9 z0lg`l09>DxK)rA?Bi_TCS0AE_}m4#mK0O=+=QQ#MyXrgv1LcklKb||EYwRg>bHe_ zjc&;@y5+QR-C%}Sp3$hJlU?Bb0=M-0g%q&sR=M>dX;*2z@nULBXX-A=f9tvJ>HfJh ztnpbpj|MPZ9_JuaVs{{L_4RuF@XFl? z9^RLM0)7XrmQZSY5QamoEV#QDBpsJ9(e$xdsX=%)t4QHP2w&-k{!o%@$kPy6 zsqOcK*Yo?bOnoKlD}W5L3XV8gEpzgtW<@%ym&Dmp5@3`RJwJ$Wf~-u-dfZP$wxT+* zOg!mFZQ-ewA7u_5M)2%3%ort}j}3V{A%?|~$`&>|LH}2ID_ixG#Bc3*!L~Py2c8}* zMc)r3Ch>bPp0xD_A3WZyS(!z92RwvIJT(N<5EQcIe6!fy?jVqYpM=wCHE8O4@go0e z(AL-W9%fZHAP8B+29Sjnv-DpJ?P}getpZknWZ(!^)ot(wThZLHWRA{HxZ-=$&q0%H zPvKWX^B)?TT^&AlEP0(Xf+0d%;ec`LEieWJow3CM#jlN*Q@B|Zh}nQNOPOkDohcCX zTY@z8YE9O400%=#4j_9@O6|fL0vCW?0IG!vfUJ<6+c<{UM@#y{E__BXQ3AtDEy8F=I z4|;>1yGL)g{T5=@x+{^K8JaCdmtRLc#5&S{Dnb|3qxnbm1qfzzW^R!w?~KmS?8G?R zGVUP<$X6LviN20niwONmocJMlXx$w-?f`LLwJ2gue^jRkvx!HoKqN3)3P&Y})gg{; zOiujIkC5QmI;*HLc?r6itv7iRmZck^-)nOJW)C|5!DEarYCO@NXP{cYK^z;Zo2cXi zM^oGO2iwP1480)FDp_Bev{`(aY2(~e)Pk}`cgBSf-XW(5N*eqMKLb3sO#iaE+RbcdDAFOc2op% ziaSdbb#$y*G2g=#jZW!HnHw;7B?XKla?z2bgUbAsP`Z~O4}FegZ-+^wIWVGT$4P9! z$D3w1x*V52XY^&TuB9)7=}U25>O^aIeLA-`d@<*^(S2CgFeN-t=LcRNiq;M;L2?1OX7<0U>YTM7H2!&8YGX^i@26uLlHuYg~Do$E?RT~W) z+V|idm{R>7E2vWtWa)~I>6Qk`+ve!(v7Kj!Y}6`Q$piHu)$y{5=k;Pf2&rE6yxoBx zPTo{;n@P~>iKG*ANpz@FD|wk}zaVj!#AhVvi)Kbpey@`;O1>0Xp~RS3Ig7`}a}m!q zJWI^fTD5X!_57qG>E`9nAhO~^zkiR?pyI8jqFgF-KGz>}*}|QGQq=*zs)w3~@~rPQ YJIG2m@}u3PoKaOFs+v;hE2GN(2irya7XSbN From 793ccef8dc602d6d8daaa466d29fdb573b0cdfb3 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 21 Jan 2023 08:06:14 -0500 Subject: [PATCH 058/100] Delete Console.cpython-39.pyc --- __pycache__/Console.cpython-39.pyc | Bin 1724 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/Console.cpython-39.pyc diff --git a/__pycache__/Console.cpython-39.pyc b/__pycache__/Console.cpython-39.pyc deleted file mode 100644 index 6bd86f82b0476c76206af57ea51ab2de2afa7ef8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1724 zcmbVMOK;;g5GM7oe2vp~`Y6$}uxNGI;fl1kFu zjgdViK>kL0%zx;A=v~*I`WJHQ4DC2hie5^AqZtmx`M%K%MXOaOF#f#wBk2Z&{DsEy zfHm?JOcR5UMADRuX-p~VUg{l??}+qea86{P=$Rk;Dv;p|PyeL+GZKd?ysXH|@30@V zs;nN-g&xV;k%yM7?~``pZ#bW{Y1t41!{x{nsW<_Xew3hNdH8d~JO@RQm`W0RlE(f8 z8B*y<|2&EV`9OxUa!%t=K9p4%fmV?Z=brMZx%@3?C9qWkpI?&eq+KzL`Z4~a5)syfAqu0pgLV#Kh7PMhHC z++Zn5;+D|`19hA`FijJLC8zWZD*@Q(5EcMySm;q^+n$cVE~{f@j5t!d0oF|5hh=r1 zWi)O=H!$>k{lDYlv9q{KF-KW3S;VXqIv*GIe#k&8Ay=2;MHmkk?*zlfslaq3KU@TR z?M+uKJ@wA$YyZ?g1j5ukKaI*vsnQ_Xhc1j757Y6Z_v*7U9W$y((yJkDzQ+H-OW!v-e9IsO0sTe zYx8Mm>&rX5Zi>7^BdI$Ul^GRrvE)ke{uUBUT#OCn^!2j%j!PRfW>2t7gb$>EItQrIB zcTwCcyShvCtCJ!(AAtK7+{z-m&e^8Ag$FNQZ_TXt@zua)&BR!7Ue-Au=W>#w-sJq( ziAd+3Du*AHKtE%L=`|FOP&`5L9tuQIw&pFJs5FJmw|KEBHMWPw4B~WE5z!!M`gM4s zT0L++gfkYSjPq%90QBKfTc5V(+6G*H`FdQPo6|McSq$guwWGNH^}y`Tu5Nezl$GZ> zG_i5VYX-4nKgl!4B5s)D{3RcVEK_<3uS4#7JNkT Date: Sat, 21 Jan 2023 08:06:20 -0500 Subject: [PATCH 059/100] Delete Controls.cpython-39.pyc --- __pycache__/Controls.cpython-39.pyc | Bin 4812 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/Controls.cpython-39.pyc diff --git a/__pycache__/Controls.cpython-39.pyc b/__pycache__/Controls.cpython-39.pyc deleted file mode 100644 index 57ca9d3a84e3cd5befe541d1502e31a1006328e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4812 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 wl2}~0iwpcUZ)eAYnwK01Vks Date: Sat, 21 Jan 2023 08:06:25 -0500 Subject: [PATCH 060/100] Delete Difficulity.cpython-39.pyc --- __pycache__/Difficulity.cpython-39.pyc | Bin 1456 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/Difficulity.cpython-39.pyc diff --git a/__pycache__/Difficulity.cpython-39.pyc b/__pycache__/Difficulity.cpython-39.pyc deleted file mode 100644 index 55e8e12efb893d213c95799b74df00333a4a1d2d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1456 zcmZ`(UvJws5T__vb`(2Fi=pc_4B+-K%s^+X1Gb^X{soCv2XO4ba=VQ%ASfb}u$HWr zr0dn_o?2jEqkZgm*mu~wUiXx*u$S#lPThE2&*1r|$s^=1 z{J1PGeEa~zybnqc;ber9J48_7J|n_?O1UGPh_t4;c;KocwP9sA?kbs?154q|i(zMoG=mnXyH#7Kv5Gv{U(?0|Vsz z9}w*zsuV?pX`I(k`Jhs?y%NMY_F$NgK|KLRCPX)d^P2;hPCR{GP{fwRj&PB!#iTkA zgB+bn);+k>4TsDE%;Y1P-KgNGu?PEJ%h%Pd>1K)2H*mu#-Gj2+7k`<#8t!rkbX z8|*7U)o#&fETXgtvdE4(Jh$$yPMt~-!)R3@!p_! z&>!y?^J!Kj!i?s{NuHd_?^kw>7pUu? zAa7qMQ&Hq)9skwTzNC5+W=c<4nO8I{)fO5z(zn{7YVM5B&>R z`GnjjI>5$(qHylh3561YFY7+{u(e)Lu-2f6I>L*f=^(+{g0B*Z&Wc$k*j&DmVy~D> zW0yt5K245`N3zXirgAk+tTY$?%oglm6dtZN{PA^(jM{z~C=-J>HqNqK>QVO~?CnQ- z2ZGmli5i~`eH9g!%q6a_n<}~swqiMj8hN0Vk=Pps=_J1IcuoN0DvZS^>m2ls)}pSe*tkqQw0D3 From 80f76e48f9f1e921d54f002bb0709d9092039c04 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 21 Jan 2023 08:06:31 -0500 Subject: [PATCH 061/100] Delete ErrorCollision.cpython-39.pyc --- __pycache__/ErrorCollision.cpython-39.pyc | Bin 627 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/ErrorCollision.cpython-39.pyc diff --git a/__pycache__/ErrorCollision.cpython-39.pyc b/__pycache__/ErrorCollision.cpython-39.pyc deleted file mode 100644 index f79a6c2c94fea41bf54da0e0e0093120bc908de0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 627 zcmZ{hv2N5r5I|>bU+|r{j)HP2U0^8{0zrfnP6&aH0?}BOR-4@ou~>V}j*sM`bcuAo z0cHMyf1sgq%O}uLF}pd?rC_8P&&=-Zycx^+duktF}KnB%>>a+3w!h7cz-C%t0 z8#IT`+6Eifogd6NNm-Ws$SAo&!_l>d_ud^@(;~;F?d_VM$j^okj-SeAh_{~=u}~#D zT)__-=;Aa3T*4Rj6&PHw3lND0qG8J-9VfWzjURI%nywjy7$+a>x<4tBF+*dIeOSsh z8>d1jD-ngbhTpH%llnaxkM-f(H?NlU3wPRCCpFeMNI!VvdyMn# z2+CMXxtzM)n7!algJFSyG_vF@OJin9%a|_Cl<5chQ8Bes9p4GnWB&Ap;~+foixmC< Dmu;MC From 615f188f55c2a93db3277c6d96b166f3190ff0b8 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 21 Jan 2023 08:06:36 -0500 Subject: [PATCH 062/100] Delete Glyphs.cpython-39.pyc --- __pycache__/Glyphs.cpython-39.pyc | Bin 274 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/Glyphs.cpython-39.pyc diff --git a/__pycache__/Glyphs.cpython-39.pyc b/__pycache__/Glyphs.cpython-39.pyc deleted file mode 100644 index f966aaee4f2c0068ed2a482418b07eb4a303e90c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 274 zcmYe~<>g`kg7fWrl4k+w#~=!?c?d^?(Y}H=I#?2;1Rr%p$Oy(F!9Sd*(xTq zIJKxa#@QdJEXF0jJTE6dF{L=BxFoTtq$oAp(9+ycH#f1kB((@dEXF;jvLK^aub}c4 XhfQvNN@-529V5tRpa5WDghD0&OSD1? From 9d55a91323983dc73bf51d93b324d31dc5a5ebca Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 21 Jan 2023 08:06:42 -0500 Subject: [PATCH 063/100] Delete MapGame.cpython-39.pyc --- __pycache__/MapGame.cpython-39.pyc | Bin 8456 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/MapGame.cpython-39.pyc diff --git a/__pycache__/MapGame.cpython-39.pyc b/__pycache__/MapGame.cpython-39.pyc deleted file mode 100644 index ea062523d1a30797762fe90ea4ce4e8d9b8ad5c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8456 zcmbtZOKcoRdhX}UaQF~K$rANgZ(Dw8Y>Hm*I`OX7yEa9Ul3?waASoz2mN6MkH^~__ zr-#)&k~tXq5D77I2?7K;1iPD%ha7wikX!beYl7qy^dX1MNkFid-1d@u-`_pmGb9}> zkQsD!RdrQ&{eOM`vl`RWWevZ7`TEz*=9`-KpKOf&EHpmB6+TAcYOd~UwdAhXbZHwk z19!tWcg>oq^O@;eo4i}Ty=&KO>9hU9Zn0LBy6%^1r8}BiaEmWAx9FAH6VJ_B+0{3+ zO6euOqg5+VE3CI@>`9P5m7dg$=J61q!wK6{P~T(uq9PRjtrl4t&2Awt`NR z^GAQAfWPpTu4$geRo9HKwJqJ%UE@WmX1buT?eg;-n_i?HTN1?m(tej?i*-b z_O8gYH{G|;x|%+F+r5s~chZ$r+;`A=HGTH3yMWer-5c&AXm{Knq~Cha{T`@&?Q6}_ zYS*wsAH>Bwja~0&jcyYR&3>$#=@s5YCDNX2hx(C*E!PKH-EehF!`;MXNsldMLCRuO zdd{a4u7OXO{k5`_{??S&Z79!aIB#z%?@6oCanjE_TY+-6dQlHgv*E2yD{3|TR=*Je z42xO+%m2ZzS}DhN*z0;KF4gNCTCc~2P%sr+Uv`5qw)R<;w?Sb&j2bG8r=|WR0b&@> zWRD&jixZ7ytcP z4#L>QA!SX2gVG;o+PIc+g(YlOqz&}vdN@U?i*(ix^vK}-w)Vwu9vKJ5fjKb4clNGE z=Aq>p1M|o@um+Hpo~CZOChAsrckile9M}VUU_CL_Z!yxQG+|_6pdA(lg(Ll-DDzF% zMsI0gxCZ9`&7gRQEpJa8K?X7NFZS-Er=0ZYTIVB-<9Gfc?VUW*(fby93+Rp0*;ANZ zd}678&Ss-W*9KU_hg!NSL*3u|EuQNG!`3e0*$;uzk2FvohWdk9naYXmosEl6`}u9iceT8u^{hXQXVQZu^IMuV+-mj ziYL5IZ`V_e$cqa~z7-dF$E)KBR&Z^5acSF&>Og%Xo@xfYPE_Ca_q#h`T)30mOB$jFRR^mxnX!1O^*c}%?1;FlnR*mhb*Y&;1ggS?H#D%Ew1o*4j&vshPotoY8d~df_ zjDk8J)NGcW*a!h>ez`Uo?gTyGm8a?g-jEa*`7T?&dIi<+rzkY5q+5DPpG9c^k!-QX zzA3#dJ+o-fpv{YQj^emEy+1ufuDrE6hT8()j!SSmKn1wcjabexcSp`6WK_n-_rp{!sFpZA?F7o2^^51O)) zbWX3?^ujP-&T3^ME_R;@-qhP*v4SI@#pRr;xLEJDJj_y)d_2X+wm?!*r&J0F!Yop) zZlI@Dc$r>gtkp_Uy@xfZ_gQ?O1v#s}$0Flo#T4!d-(nNW<~Xy? zjgULs%0I#@LheH%dK57T(v?#fG@JpSsh|WOV+^C7;w22bjLHbZE)29b829I5!Ug>w z=ftghyTMaWpq2y0*;2u-^mUaNV%^Tt`pQy1sai1uoi9 zeu{k2(#;@Hu<&?^BU&+^Ev^I9Cu6YKrrCv!hlc>|8Bf5M+mKbn6UiMNv9*Lj-=rc# zReMZi1ZH2MKa{u*F5(paWxao9$lFxYk6BqVHDfF_F~I^`s8dy{`A9#+omMu|pOb-l z|JgC4<0O&U^$NTs_~pBa!MW}&ZZA6b*EcHStT(_`ui4saHHDcuA5tzREX>{{%sa+0 zXv^10HK83(P~9X-Bvqm$`ZT!3lVP*bsVA=fpJ7l)FO42FEln;>BcsNUH;irsdDOdP zPz0QjDc|V*cQba}4W7Y2?Cd*X4;ByxVZnK@xUsnLaWca-Hlc!dsyP

-UF8biWIVnRXe2B4&gh79e(Zdy8 z9U|?tf&ZT+UH`Tv%^v$w__rg=ng5pMgkut5V@4(c)XeZFp+v;jq^VdOnBqKK5Wf=M zCzQ(tMl*;sj6KvK6=wfdu2wc1KC}nD!$h8)V9QCocu0u!-(Fc=dT@X9n28jXpysgx zY{$6wFlsnrTWC(O{vk#m!;S3Z-=RMV6|KaHDg*4Ja36u;*v1fBw6g;DEmYFr9To*a zx`gxKjVTIu6$%&qZRm?bE3(^&`96e8QO8L1LK#bMG3`ypf`8ImN_&mH%c;>_&BWwE z*QLgcc3L3=uD3&Q5SjzQy|c}*Eb&Nhv^qCn0>NqWJDV(AtRnPbpsdcYm}c=47H_Z+ zkc-p_(gj<$_~4lQP4{FS38%up$B0C;T655=7x2&B(y@_a=%ThF!i1lTsHDgOA7HZ1 zGjf3=V!~{hh-P4v_ogtyN|GmHu(mVOQtRAsnn-yeFh!b!*h<*pBpNqF>MX1*(N zvbFV<4ft!v>{PCas{omx?jx)+cT&}-Xr_j}HYwkN-c^nLZv|j{Ht_~TJ=a^2w;TQ= z-jV8E#(r>EFAZh$#Mm)7l64vTxJla@L6-)CSvUt)zHwki)^m+QdWbL%L7&+!lA!=x zX<#uuus1)T$D{X`M_8J=0Dv0pE3gLaHN<9pDhWu5{%Pff=$u_Zn7BUnUe8neBcP%L z#U-&%0B_F7xX|c!y^fp8GNOMkgtrh1A7hK3MFI)icN~Xjhbe)~3j7nEjvf(hIfoCbvxeiJUZNU3Hc4@csl zhfC{K_>niA5T7!Q0$z_G_~E_#_Yt3p$a8x3>1F_@tP_o}Jawfds3I7Sb80rD zJ8{;+f5o7XBB&KgdOx!V$A_Je*vuXzuI3PKZDfwm15j;f|MS{K*363`J6J*g~rP7Jq3`6wprx2~gcBUbA#!;9^(da+JO4Mg4MopwzW3Twg4_P~=*o(6NzW*CMOI12^ z4>QzDnX{aZIUzV1H0ZJo1xMUu&@L3_{@ya+3`5q)U1X%R1I2uSI^hV6k|uhXxK+z6 zPQ&^%7YL6&acuvKqzKTFkjw4T*q9TfWIAAWgcPVtgi}Juk8>+>$LmP$GI3d;*Jya? z;tZqxWEm%9H5Oh|51vAUdW7%(_t?tE*pF#r5G3m}_WuXhtcN8Au?+dR>hLl)#7J!C z0n$7J9VWq0e+>Dwk!`lrP1fMY;9`c5_rpSxQ)GXePxN+CYQ@f7)Jv|3EOnnX%q!tO z!NUrSKpkxjZJll8ywj-3HIQxQGsCr{HbHL@HO^1^_=dC(-^_YZ=bN>|vh0A}|8>3t zD=n~F0ZY)SYtC1J`U>@p2e&rXmX=o#dS+Qi2kJF=lJ7*G!JxWkdV3%5xxSL+;T8mr zo!}WGxHQi#dOSm9BB>+UMPxR&w&;O8^G{6;FGC|@c~&Xi_x z%}vgfXA1J4LajVAH8U|&!o4_CEWIXkE0eOT@gz@oHzEaqgoz(b!xR_R0uUBTzNa=L r$06BKzZ^b{u!Tz*S) Date: Sat, 21 Jan 2023 08:06:47 -0500 Subject: [PATCH 064/100] Delete MapSparse.cpython-39.pyc --- __pycache__/MapSparse.cpython-39.pyc | Bin 8654 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/MapSparse.cpython-39.pyc diff --git a/__pycache__/MapSparse.cpython-39.pyc b/__pycache__/MapSparse.cpython-39.pyc deleted file mode 100644 index 6a72b93a19cb2fd3164df2cf3b0bbe634ce7c387..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8654 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 Date: Sat, 21 Jan 2023 08:06:52 -0500 Subject: [PATCH 065/100] Delete Points.cpython-39.pyc --- __pycache__/Points.cpython-39.pyc | Bin 2987 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/Points.cpython-39.pyc diff --git a/__pycache__/Points.cpython-39.pyc b/__pycache__/Points.cpython-39.pyc deleted file mode 100644 index 252de0c4dbc7befea663c733b1b805fdac23fa33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2987 zcmai0OOG2x5bmDo8P9qj%1f}}rC}2Z9M(}*B0?-tShLxLpfHKniISK_!^GW5yz8AY zJ+pZjTS9CkE{Fp+5QpqB5`O?G2mS%~xpMMf$R&K$V|%lCKwDi?)m`0PT~%MTqv`1~ zL;L&3$IbJTjQvBxv(169gr5Eda*jzR`2+NAt3i?_ZAdmG4oOG{lB1a7+oEA9Te=&T zeypr*)(}cObat35ZCL4rFW3)UdV(nty67c20qPkF&ghk)mysUi@(yd1Re9Z0V%@{| zPiDNl4&C($$iEL|?6r;)(?5oC2{N7cm}EIwXO*cYZn38cNK5GH`yh%nxMU4W@`f$T z<~|&jJ91K%r1yYt^M)%YXrJ7>8tKj%m1f<`KCyniqm*3q%Rbu0SiP6}H=xej_$N>MOiC}j~kV9Tak|93~T&)?d*!*X-7@9sp71d9y~=Gz$DhRi4Gg_7Wy)J z`XNYC&S{ zDM>4h6TSzNu^!vzeb9%z$9H(&%5dpza*d^X-AkEGt~tyeiXGCkd$w`TDLBW@9CFoo zPV@wv$n-TS`oueMsFZGBWNy#yiEZmD9LUY@I*Y9nNN70J>s~WKrPyDJbgCBp!jaW@ zYjfUDDK)A$;it^6`au#aKZ$*%b)v`1R_;Zcoi-MpoL@M;P^1xUH=vuFAPqRUTfhBE z?axmK6pmZyXmd+JrIg!grgJClv|Cwjw^f|m@HYlB-Rk6yIbG8h6(<)GiHilQlZ$53 zPEDK}SPMH%oC`vc$(;^eXc}z#76@}aUPi1ezK?rcfQ}-E*v*V%XBGt&OOMU3a6N_P zk4hB&INDTUn3uzFGm%?u;-|v!+pVZQoGFE&OqyY+QIl9ch2+Xw%}tfvPNY7Jp=Ycl zM`)AEbUW&)2Lj_nxnyy3=OzaBv{%D^LfTS1C}3Zft}G253b$1 zbvyHeF|-#=I2%eQ1^DOv+UiQ}d2BC7cT|+k`-G!+{ZFbDv&wkt)nH$O`Okr!fIkc1 zTNtODJqq9#MS$rOrU($^nSp-+d^;EzM2|3kual&?xDQ&fH91Ys5jjG{xOLaJ6bCAi zDFu-YgFeL(^nF8@jPYvXya%y#=oqoTK=@C@{@lGW#H+nyFiY6&+qjYF+4MN*fY1nh z+q0}MVlOL^M0o8x;4LYDXRM`l7e>`6K?G(N&dg>G=OD#f|xsyQ?%Iw5Su`5H|x7R3`L367~~0K;#fe?zEG;O6R3k z8nrvOqufrk)CXzW2dR|wYs9}!WEP|$NUdR`mc2SZ2$Uz#(|17FLBVBx*qK@Z+z}=)GGHS#VUY5~Qaz{q54BO$HW!8wJXY~;efFe>iMa$Uqh!?PW z379U@epH4S>S=eH&K)D@1q0|R#sG?6kFDb$*oKuH07uZbkiK?cf^Vt_%I+NWir4!X zaeL3F$cOP(yIsdzO28x=yrH*@U3K@T9Ica^|Guk1ea F`xj7+QHlTn From 8147e7fd149a57d1a774f96c4e384405e3658590 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 21 Jan 2023 08:06:57 -0500 Subject: [PATCH 066/100] Delete Quips.cpython-39.pyc --- __pycache__/Quips.cpython-39.pyc | Bin 3504 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/Quips.cpython-39.pyc diff --git a/__pycache__/Quips.cpython-39.pyc b/__pycache__/Quips.cpython-39.pyc deleted file mode 100644 index c635ac25a99c903e0099db46a3dd75465ec0a7ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3504 zcmbVOTW=f36<#hcT2hiPaVlGO;|yb`GEs|wfdWN?qOxksj_O!(A{ng(q0DG^NUpiN z!_Lf_=0JUNfc}UgfZaF$hyI7Y^R+MaU&vFxGfR<_lLAEu?p*eqIhXHzGdp~Bwc+9S zufP2>{LiZA{hKC>zcMCw@#sIGiM*(kc!yrki~N6-4om3E=za7R^kwu_^cD0q^i}jr z=xYzXD2VFcdQttAf4CHt_Pti)9qf5~t*Wgb^aV?KoH4s{(C3ETy>au#-Cr=<_%c^4 z>&lp zGnt#y*CVM0an?H(e@J4Uq*5EE#E{2IL`_?#w~^pc+kQ&Jt||;q*TPemV*&b+Kww$Z z-Xt|6@fMDLsJ2^ZT_UYxLH^+^;UU7c&6zXyBoSN-hW3SEoTWl*-V^QCl3m_LJYB(! zh?rd^;9iKVC%SpUY<)XpJnO0PR3e^>(2x&W70RreYpnV{*v=%-Qb7BeK=9L9>xx}t znveBo?3>+VN~8+}09(eDQ<@{w-T)U8o&y>z9?P5{1=K8(?BMh51IBw`F;<^* zpp&SNS`iI265#2n&n|a9kq>7FT=lS|xe!#G36L<2lQ9D;PzE$mxiOE4>-9h0>=i%$26Xy6g&1n&~0@N5b@x;!CLATyQtT0Pzf!?4i6Gm1u6X*6b%l4+LA_ zNEM@e;}qsJF%M#Uv(VvYL$jVFavC}3IadRxb(OR-@zO98r?j&aNKKaSY}s{^p#uGa z0#gRKWiEgiAcPVLVsGb$$u0xW5SwtiWp9vN@hp-l{M?2r7EkAq1bHAY@FHelllKq_ z5{wliLT4t%u|+!0(F}>(?0Js!#yDj9BHgm9C+RPe+V zwp^3c2@Tkt6_o%d9l~v^u-M}`>P#H6IMX@M2ti9F(l}2+y1`h>&tQ1h!?@Zas>z zGvALVq!0MwuZ+oEJofib}>mDZMJa@&8($&3!kooRm(= z>)wfX**o!1D(mR?y|@0JDq(G_JgF6%b5f@sPftwBiO5>jNhOncHmQNA-T39Crt>cP z!|IR}538EGx1L&tneTrees=U!3#E_lefh=i-qC$ii+GAV55D$a zyXzP}f4I!$8ID^V!ng{}6PYw{Qp7l)Vk;DpMByImO;+!3Ki+=0(|Pjs&V$`Q&8GWL zA7J{nqyo~Mr|&Xfc9|Eh`;gCyaIR!8F63Wm{BH!>So-R9I6&R=s z6xKy*2zT3<-S^JsTutOis59yAJlNSjn5SDzi*(h`$l#AB>#ma- Date: Sat, 21 Jan 2023 08:07:02 -0500 Subject: [PATCH 067/100] Delete Reports.cpython-39.pyc --- __pycache__/Reports.cpython-39.pyc | Bin 2288 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/Reports.cpython-39.pyc diff --git a/__pycache__/Reports.cpython-39.pyc b/__pycache__/Reports.cpython-39.pyc deleted file mode 100644 index dc61f83f037e0f22a9122b4392a82e325e3ebad4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2288 zcmaJ?!EW0|5ZxsyiIQd4PTe>#f_Bpa1$2nf06~iiMNr3L93isgib{hB1_)Y9P?RZ> z-KCp~kWUWKYwv*p``CZzKlIiEuRZk_d}uqn5*^WYy8>4`Z)S(HZ)b+~@^S^i`2FYK z27l-X{V9aSp@Q%&Jp6N*D5BU$eetjOc#QiPqg_N*s=Y;2J5~A$#U`p1{sLRnuHm%s z-LV((fe;tRmD9(7I;f8+5?lMKqfv#bZ_z347htW?f?OA2U8E(sE>Rs`QBDhHY{xvQ zRS1l(6NN11goY#tW8yl2!|d20)E?Wevn6c?cp(I_*5KKJho>-2(K)(6SpHKyMI-zU zohcV^K%t=uAj(M1VXDNm9Hs$Q7!`9^L1LvGR+N~Y!%7k>=P+Gjl^j-<*isIwNUXYu ziPKO7TrIVePXtK|qvwqsAZ=`Wffu-Sk{P`4K@0<84&mBvGg$BeOSl4dXmf|Z_aF^k z*(@SP;Cg{W8uAL}2Idg1iFED2b%;5z1GuKV0cnMS`@aU_wL{PGDcK2wn1w#S=0QfV z2PXrAadaH#Ua>z6V>n+gWRU~OGIw#C2kC~8{UMz1eUP=~v_w4~`Sv7TiGf9nWh|z; zYlA$tqjXuWj%H-?bVZ6hBP*>q0Ynusk2~pFVE^d3cI<_LHOtm?gA0}{CRnmKu#_q8 z`asSt_(xn4Vhv`5Wab|X=I76VK@?}3i%_kai1Sy(?m#_UHU{;Bm!RecJDpau zeb5Ns1b%2!ejpAKGw0~h*Izw)IJP;QC5Ii%t8puuq^oe2Hx|SfS+FfW=FnphzXuai zbbJS|-}ohWA**7(b$w&5d_@DfDqkOjtbAvsJ5s3fPNV7>bS5YaJW?}x15r_qcm$0G zEQ)9920FoUVTw;NEv=&yDD-nQy(;`E&RW0>lLe)>lj@Yb09JN8Z4**kee%WQL?u&_ zESbIS?$d445O7HdVxf@fC4N{dG7&Q?im4Y#vPU}4h|xB>yRWxuYO Date: Sat, 21 Jan 2023 08:07:08 -0500 Subject: [PATCH 068/100] Delete Sector.cpython-39.pyc --- __pycache__/Sector.cpython-39.pyc | Bin 2439 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/Sector.cpython-39.pyc diff --git a/__pycache__/Sector.cpython-39.pyc b/__pycache__/Sector.cpython-39.pyc deleted file mode 100644 index 46e6613aaf8cfff6d246d7ffa06199defc4d10f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2439 zcmb6bO>f&al$2yyRvb4?(zMMwjKFrNfi-AP#f+_Jn*{05z#Zxq#k3THVls{rS#n8b zMLheI06PunallX@Ircy7H0-`RuR9gkVdrAl_8#T9j+$h@@$o(CJx8;%K7sMu z_dmCP0ql2NOb#0sci~mb065_^ApzMS+~W2z;r5XgP)=KdIFLC#n1db^2GWU+j5e;0xE8I7Dna{vJRqeJ!JJ00X ze_&|RE`!~(fw%?lD!l4CfPpn2AsJABbl?KC1~x!@-~e<6C4ePPTI3CF)?MwSQCDa; zJ?L%=sY^+m3Z-WwDWY&67M(0r+BZv;M^Xi~F}@usq3UJrD3R=F8!SjXxOSr?7NAu! z3c7-mk(C~>-w-(m)4SDnW9z9BQf;k1+WfM)wU)h1lPuzD3*~bu_HTW5`__$aq;et8 z(YA_Mtn?1G7lv^f=V9o8NmT_vY?q!r{R<<>GpRO3iP1oO95=iV1F{FH-nSs&R#V~~ zs8fkHVVZ%-_+5aDu+-&Ph3P?()L@~|5~2OtXvY!j+=l2QM!+QM0U!gS{G1#?Dqw3m zgoN!`LrC6?5~DWC@JbD-wM$DUf(4f^tXXVK?dp z)pmA}=3yr}?CmP;ZWMF*A%uP7QBymuC-)v}58?fLt@XO29n5iI3D2)>urhu6%8tys zAqrwJ)Di$-l-! zgQ(w+Bv;70G@;XiD#fE*G}t70HA{J%$60!w40`LSke$P6a%(ph2^u#>zS_<5EM-qJ z*%LeyXJp2n#9hIp=tfZO(oTcDqwFmPt8cNv|2Y3z*4`Jq!6cTVI@PvFdH?#@X9kgP zu!lv}XKFX@eRp%nxX7XR2)?4J>MuWwWZ}Zda|RWFaj4xZ{g2-pDiYUVo7qby%)wbA zz7@$zeL?#og^J#ju@XV0eHJfS0hhE}2p4_CNn({lH|h1jO;ge&mg%CQgcy5W1t%eX zp)nrJ^-TOiXp}|#bS;O#h2y~KihwR9B&eERq+MzMYaO#2NiwXK~v-N^!5W-m2(n2Nw|XUTMRtd1<10{IbmZT<=n%QHo>N Date: Sat, 21 Jan 2023 08:07:15 -0500 Subject: [PATCH 069/100] Delete ShipEnterprise.cpython-39.pyc --- __pycache__/ShipEnterprise.cpython-39.pyc | Bin 4340 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/ShipEnterprise.cpython-39.pyc diff --git a/__pycache__/ShipEnterprise.cpython-39.pyc b/__pycache__/ShipEnterprise.cpython-39.pyc deleted file mode 100644 index 05002b40838e838315125454cbb5d88a09918117..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4340 zcmai1&2JmW72nx!eu|bqq$F;-XcM=LYsXHC)(H$Ft|hBM4B8dl4-jrPE6$3dv|Q4& zs~B1=fdV$*9)0K`fD?eaCAaA03rX@J3%iaD}r#>CjgV*no8yqp}vL1GS^dvL0vy zt)t1Z5$FS>W5_ZK%#I0LGq46$$70Hw!Yyt;Q@HK3r&`D6tgSRl2k1p; z{Sk^)`nF?FYtdmx4z-bO#@$9+G7!uZW@e-w48k)w}RRH79We5J#< z(ovr)n~XEAKC?R-*SP*n>FC_xCcZ{KGz_@J%cxtt!mIe&&lO$ilrYd*R;N*|hOsY3 zq96HPcBDfpQ=jxk93obpDigM^U@BOuxGGm6(JQ1bHHMU?l$Mm35TGR~%TiXPtj4uT zJyrHG^(ZamC9YshdP`8pcQa#ceRZ|fY-C2XJMu+lyKX=1$F7^1e&~zdUS{%PcgN>h zsXGigCT|#KXF~7Ge$S(_%e{fu^RuOBYbat@cwx_XqpmjvE(F7{cZ&XewAJ?m?xNLL z41>dV7P`a1XcseesHly$hViT)R1w)J+9*)Oc;xe;9|@YrY=Oq?`qLTD&II0W*xfp! z`i^CKB6l!TP7|Rj~{kL4D`q2PkEwo*%nCvV9BHNQF>XvOL%S)Tm1n zdiW5-4ZLyy7crC=OEqPwy01nJVkPQoULR{ImhO%suEp9!=PK9s)v+pds(6snayC*n zF=K0DbA6xDA`Slz+}KgYNaCd_ZWj0ixCQ)$#LH9MF7Q7AF9H9n#4A(0T;N{-uK@q2 z#H&-hTHv1muL1wB#A{Q$Uf>RJZAX2fj!q@L5uDd=@T zkxOa=uOC8{GwgsOnJgC6IkXIX(J^z9H5UY#be7TmE~uJQ{RoFTm97_b51DFWe0(^_ zEc*7r>N=b=i}#~Z;OzF0PxOf$O8Wjm`kIBW3133U_nz#xbc!$bHR<~o>1!3f7JLaI-#<%V z5c_z)yaM7?lMklMTK7j@UpRR@op|_43d#*p{0IR~oZrtF7&%+sm%g*%`=KLbTRy+~ zFuByG{q8vPU>VIBChy)mLD198evIXZ-SCivr*@jW^AOqN7==%3>hc4*VdAgKE%E!C zeCvVSPEYOcZqt?&7ER2_YsjifvWm-OIk(@K`K;Xn6#WiD(aWrkt*{JY>X5H5S7B2v z>|a$rLEyaCV+1DhPIs>jRIr?K0>49xDOM+-)HIJvx`r20wyjT$ePyi1=ETbPw%L*c zYEQ6F?X&1}S;n3eSGKGB@`Q_}sO6bGId>$5^TQn8tmV@xCz$f1cn>18Ddo8XZ`7&L zHavRb;>?I}3QFQxwMeM0Cwwm}&ki}_Dz!k#P^RrnYp=JP+AJ`c{&?5p^Wka8fgL%Z zg=iq6tW4*X1}m%OBAX^ZoXe5(p2sGejz09tZ29%kYJL#aNf2vQmAYjg3^pvBFG^?Gm?M>fa!& z2pV*8dAsrw7YQI$iR9TiM`{I9KY=V1NMnXP{+yS_CjFOmnsNCwALY6jnJzw)YEK!j zEGxYFRKrNO#uoI@q1+nVyoRHMmD)?n8w#(#)cFF{xwfR7&^34?NqnL%H$ z$LD6FLCvNb?Kzm2#mQM(q%TYb0BM7wqE!$d{lJ%^slS6=^IE^JfjA;rD>tu<%;c57|bY2UfsngOXy#RpaD(UR)a zNz|JkC7P2u2R5lyCv7g}2Z-Yg67K`f%$zluAnioBH+I@24C{E%m6xI5VJg`nd@ zW_^YO|JwalRwHV;J3&9}4Z|q2+YfKA|LS&oHLFX2E&_DFj53{&tUT35nHKn=xQ^E5 z*eE`Lu34V3u~VAzIy2A{wKnqo9q}Oyal0JGQAdrUjy~Mn1Vk3|)LodnTJ6Czx&e_h z7wJ{C<>`kKt#(b{ms)VIU;X8!oe`|WF*tlJBBC8d*t*##gu6yJ^y-6l?MG+Q632#Kvx7BLH z)@;YVW>+NAEQz0x6`jZAbx-ESPGzOPx!LdT;)1^?6QB&LJa$UABR$C-N?wNSoB4mZ RMd$2@4y<%;%zr4U{|6k9AK?H1 From fa1ac367758d549211027868e95765301b8871f4 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 21 Jan 2023 08:07:20 -0500 Subject: [PATCH 070/100] Delete ShipKlingon.cpython-39.pyc --- __pycache__/ShipKlingon.cpython-39.pyc | Bin 1889 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 __pycache__/ShipKlingon.cpython-39.pyc diff --git a/__pycache__/ShipKlingon.cpython-39.pyc b/__pycache__/ShipKlingon.cpython-39.pyc deleted file mode 100644 index 4b1d5a39d1bf5f1d06e4519d4954c234cfd8185d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1889 zcmb7E&2Jk;6rY)$U9TOdNlIFf5NIzTSt?P=g;F8fD*d1oxe}p5T2hUsI}>}I^{zWJ zE;zAIiIl$qPWG|?11C=0xbKxyZ=5+0-diWB+i+o4`{wI?{N9`Qo?KpT5Ey?P|C;n_ zg#3w{#lc~78-BY9L=i_z_WDvqLZT6x}8*{}o7)c8iv^ zJJ0NPHytE+usFQajlBU2O;Bmfj>#@nRI#HF6jf?tu6z|7k=WOPs;TgZ9MZUUOgM={ zFjOy>Q2V1S%{xV&&;<*)X7HmS8v$|TkWA@}Q1E6<1gj|Eg*8_Ml(Du!p_X6zb~wE1Bxmo5Ot{7bs!V?fi!lb7j2Tes*c5`U*bH~`z1nrFJji8}vv{504>?UK< zBc_2#t(fvM+Gi6=@zk608JRHWkJ%x3v&YRpV|JH3{e9xWZP2TkoiUk)icjlfuh&ri zy9DMXoM&tXI-YNi>9mQOdX0)MAs_P0_=Ky#El)3D#?RO~QQ?@Y`upTPvQ8#G>gS}l z;#SB0A-w@vE>yxJ&QM-tg?8}ah)KEvR zh_IBNNe~4Ys7Sl<3KQO32GW7Q8mEiDZgqb78OO)BzuVvXKUN{#QFo+FF&Jotb`L(C zY_u+y_0&Se7kgTjOX$rolYrQot6;bcJF>4a3F9>^5^1y)d-FDBOE1%T+0f^{mw_r0 z)KgQb9b|G;2D^pnOZPg-;}EW#%oAXG3WbC6$R=2g80BhqC50=o3gMF0Q* From 60b49be08ce862b132164d8ba9de6bf04a7bf443 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 21 Jan 2023 08:09:39 -0500 Subject: [PATCH 071/100] Better. --- .gitignore | 39 ++++----------------------------------- 1 file changed, 4 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index e7cf513..9936d17 100644 --- a/.gitignore +++ b/.gitignore @@ -2,38 +2,7 @@ # This .gitignore file was automatically created by Microsoft(R) Visual Studio. ################################################################################ -/.vs/slnx.sqlite -/.vs/startrek1971/v16/.suo -/__pycache__/TrekStrings.cpython-37.pyc -/.vs/ProjectSettings.json -/__pycache__/strings.cpython-37.pyc -/__pycache__/AbsDisplay.cpython-37.pyc -/.vs/VSWorkspaceState.json -/__pycache__/Aliens.cpython-37.pyc -/__pycache__/Scanners.cpython-37.pyc -/__pycache__/Reports.cpython-37.pyc -/__pycache__/Controls.cpython-37.pyc -/__pycache__/Calculators.cpython-37.pyc -/__pycache__/Assets.cpython-37.pyc -/.vs/2020_12_20_StarTrek1971/v16/.suo -/__pycache__/Map.cpython-37.pyc -/__pycache__/MapGame.cpython-37.pyc -/__pycache__/AbsShip.cpython-37.pyc -/__pycache__/Glyphs.cpython-37.pyc -/.vs/slnx.sqlite-journal -/__pycache__/Charts.cpython-37.pyc -/.vs/PythonSettings.json -/__pycache__/Calculators.cpython-37.pyc.2654468500952 -/__pycache__/Quadrant.cpython-37.pyc -/__pycache__/Quips.cpython-37.pyc -/__pycache__/Quadrant.cpython-37.pyc -/__pycache__/Points.cpython-37.pyc -/__pycache__/MapSparse.cpython-37.pyc -/__pycache__/MapSparce.cpython-37.pyc -/__pycache__/Console.cpython-37.pyc -/__pycache__/ShipStarbase.cpython-37.pyc -/__pycache__/ShipKlingon.cpython-37.pyc -/__pycache__/ShipEnterprise.cpython-37.pyc -/__pycache__/ErrorCollision.cpython-37.pyc -/__pycache__/Sector.cpython-37.pyc -/__pycache__/Difficulity.cpython-37.pyc +/.vs/ +.vs/ +/__pycache__/ +__pycache__/ From e3f4acce0424c684716e9300335b0fe9fa281420 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 21 Jan 2023 09:05:47 -0500 Subject: [PATCH 072/100] Warp speed selection now matters! --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a2827b7..c48abf3 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ So far: * Added that classic sublight / in system propulsion system. Warp speeds engines are now a seperate navigational system. +* Warp speed selection changes game time. (Thanks Loondas!) + * Heavily re-factored for growth, testing, re-use, and maintenance using modern Python. Video: https://youtu.be/TpmtCLOJ5Uw From f96b8941d423473caff15d229c6d0df046222ca2 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 29 Apr 2023 07:16:16 -0400 Subject: [PATCH 073/100] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c48abf3..fdce328 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ================ - StarTrek 1971 - 2020 + PyTrek 2020 ================ The original free-and-open Star Trek console game was THE most played game of the day .... back in the 1970's! From a09cc219d4f8c16d20a5c4fe104c0ec426631896 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 29 Apr 2023 07:54:59 -0400 Subject: [PATCH 074/100] New Project Name --- PyTrek.png | Bin 0 -> 119647 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 PyTrek.png diff --git a/PyTrek.png b/PyTrek.png new file mode 100644 index 0000000000000000000000000000000000000000..75ca9e0886b2453dcb23742369ea1e8f498ad24b GIT binary patch literal 119647 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 z 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 STQt$(rFlSCEp^|C%l`q4+L>$s literal 0 HcmV?d00001 From a771427dab8d28ed2d685e6526d4046b54514cf8 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 29 Apr 2023 07:58:03 -0400 Subject: [PATCH 075/100] Celebrating the project renaming. --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fdce328..7216e8f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ -================ +*** PyTrek 2020 -================ +*** The original free-and-open Star Trek console game was THE most played game of the day .... back in the 1970's! +![PyTrek 2020](https://github.com/Python3-Training/PyTrek-2020/blob/master/PyTrek.png) + Originally written in B.A.S.I.C, from C/C++, FORTRAN, C#, Python 2 ... and now Python 3, many have been inspired to re-create, improve, and / or simply experiment with the concept. So far: From 1b4e98d4007fe373c465ffbd108c60d01ffa7712 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 29 Apr 2023 08:07:49 -0400 Subject: [PATCH 076/100] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7216e8f..8e0afaf 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ *** - PyTrek 2020 +## PyTrek 2020 *** The original free-and-open Star Trek console game was THE most played game of the day .... back in the 1970's! From a0e3c272e55cacaa4cfe053bb2a9b5b9f0648caa Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 29 Apr 2023 10:15:21 -0400 Subject: [PATCH 077/100] New PyTrek 2020 Logo --- PyTrek.png | Bin 119647 -> 119625 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/PyTrek.png b/PyTrek.png index 75ca9e0886b2453dcb23742369ea1e8f498ad24b..d10fb4db5f9c54e637d399529da81751c75ae257 100644 GIT binary patch literal 119625 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

P+=~>>|KM_e$1X zLGt(?O)fpp`_o1wi&hoVGm@#Zv(FTLT;ZC_UpvihOpT47Kq)7ytNUVRf*}w_>?o zR99aEUOMPB_q^~efd(|*z*DvU9eJ^LABGQc792F>F_d`H`9WBjQ4qq!?h;X}b-g2Z zU21P^!E#;fA`tal4*G1|6FPOAzw_<+Qn&)6Z*zQ+sw+!?g1&q?IL!GaB?ck>Gf7so zD~hR9D6DnVF70M4E`EjDr2km5!(szzBS8GEyuR^?cFAL${!RlY4lW z=JjP{XAz2)4Z+X^)KYS+?~L+}dYlQ<6g|2pQb!_}K~}HN66CSNWE&kXft?=EyWpr^ z6ISxNB&)K8F(Sn4l@L}H7;Fz*yhj>$BQBP+{L;saRES_)0t2m}J9MntYTkg~Fo*aP z?J&*Jo4k)`oEf>z748l8yD#!;#3EvO;|9;xL_j*R2p6w|*5*>YgSD6=k{{{y; z%vKv$^HguE2wg0jwWw)Dv*VfX`#kX%`KF`21R+qZKA`U*AeFDKKxKneLals!gv# z^F&fjt;}L+dM)0;w)w`XM!Qdl6JSg1?wD>OH#hmE%v3*Fu+U-3ngcaTW?BIlHs&{ z78m*UNpY-&U~K>mb43= zd=W(SHF6Cy$9|e2mDT9JnT;b`_XWd9L!X!SEt_tHk&52EoC@X-zuhWXF-TrufA|KT zsLvHyUn{t^7S4bb6KJ%$do@TsDDk5Kl~ZcbQiU|*AA_90Quuq#>i3P0g~jyI5a;*L zSn@Qth5R@=%X@I;w;zZ3T(3la92th~*!*#HSL*yM>yJYd(NOgtM^D*yuYZpk|GO_K sAHtQj&T)$E$3v|g%ll7z5ns1{N#>_>bX~EqMeb4i!sYYDn%6`B4>E8`4*&oF From 490fb05be8a5ccaff79b100e32bfa1635a93e67c Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 3 Jun 2023 14:13:43 -0400 Subject: [PATCH 083/100] packaged. --- __init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 __init__.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 From 65d39abdccbf763e121087ad5f71de0161357b89 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 3 Jun 2023 14:16:14 -0400 Subject: [PATCH 084/100] New Name / Logo. --- StarTrek2020.py => PyTrek.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename StarTrek2020.py => PyTrek.py (100%) diff --git a/StarTrek2020.py b/PyTrek.py similarity index 100% rename from StarTrek2020.py rename to PyTrek.py From dec1e8fb9ea589df4458430d7410ff07efd1e92d Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 3 Jun 2023 14:43:31 -0400 Subject: [PATCH 085/100] . --- MapGame.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MapGame.py b/MapGame.py index b8ddde4..c4c0c6b 100644 --- a/MapGame.py +++ b/MapGame.py @@ -35,7 +35,7 @@ def place(self, takers): if not nelem: continue to_take = random.randint(0, nelem) - if nelem is 1: + if nelem == 1: to_take = 1 if not to_take: continue @@ -44,13 +44,13 @@ def place(self, takers): ss = random.randrange(1, 64) # Ignore "Outer Limits" area = self.get_area(ss) should_take = random.randint(1, 8) - if which is 0: + if which == 0: if area.count_glyphs(Glyphs.STARBASE) != 0: continue area.place_glyph(Glyphs.STARBASE) - elif which is 1: + elif which == 1: area.place_glyph(Glyphs.STAR) - elif which is 2: + elif which == 2: if area.count_glyphs(Glyphs.KLINGON) > 3: continue area.place_glyph(Glyphs.KLINGON) From 18627e9e4faeebf9d80bfe4d52ce5c66c6fa8bc4 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 3 Jun 2023 15:58:34 -0400 Subject: [PATCH 086/100] asa package\ --- AbsShip.py | 6 ++-- Calculators.py | 8 ++--- Console.py | 4 +-- Controls.py | 17 +++++----- MapGame.py | 22 ++++++------- MapSparse.py | 4 +-- PyTrek.py | 80 +++++++++++++++++++++++++---------------------- Reports.py | 4 +-- Sector.py | 2 +- ShipEnterprise.py | 12 +++---- ShipKlingon.py | 6 ++-- ShipStarbase.py | 4 +-- test_MapSparse.py | 6 ++-- 13 files changed, 89 insertions(+), 86 deletions(-) diff --git a/AbsShip.py b/AbsShip.py index 958cf3b..7f116a3 100644 --- a/AbsShip.py +++ b/AbsShip.py @@ -1,9 +1,9 @@ import abc import random -import Glyphs -from Quips import Quips -from Sector import Sector +from PyTrek9000 import Glyphs as Glyphs +from PyTrek9000.Quips import Quips as Quips +from PyTrek9000.Sector import Sector as Sector class AbsShip(abc.ABC): ''' The first step, into a much larger universe ... ''' diff --git a/Calculators.py b/Calculators.py index a5ee91d..072484e 100644 --- a/Calculators.py +++ b/Calculators.py @@ -1,10 +1,10 @@ from math import sqrt import random -from MapGame import * -from AbsShip import * -from Points import * -from Difficulity import Probabilities +from PyTrek9000.MapGame import * +from PyTrek9000.AbsShip import * +from PyTrek9000.Points import * +from PyTrek9000.Difficulity import Probabilities class Calc(): diff --git a/Console.py b/Console.py index 8094c6e..e46e2a3 100644 --- a/Console.py +++ b/Console.py @@ -1,5 +1,5 @@ -from AbsDisplay import abs_display -from Points import * +from PyTrek9000.AbsDisplay import abs_display +from PyTrek9000.Points import * class Con(abs_display): ''' diff --git a/Controls.py b/Controls.py index 68504e3..ac9f18a 100644 --- a/Controls.py +++ b/Controls.py @@ -1,14 +1,13 @@ import random -import TrekStrings -import Glyphs -from ShipKlingon import ShipKlingon -#from ShipStarbase import ShipStarbase -from ShipEnterprise import ShipEnterprise -from Calculators import Calc -from Reports import Stats -from Quips import Quips -from Difficulity import Probabilities +from PyTrek9000 import TrekStrings +from PyTrek9000 import Glyphs +from PyTrek9000.ShipKlingon import ShipKlingon +from PyTrek9000.ShipEnterprise import ShipEnterprise +from PyTrek9000.Calculators import Calc +from PyTrek9000.Reports import Stats +from PyTrek9000.Quips import Quips +from PyTrek9000.Difficulity import Probabilities class Control(): diff --git a/MapGame.py b/MapGame.py index b8ddde4..c71ba2f 100644 --- a/MapGame.py +++ b/MapGame.py @@ -1,13 +1,13 @@ import random -import TrekStrings +import PyTrek9000.TrekStrings as TrekStrings -import Glyphs -from ShipKlingon import ShipKlingon -from Points import * -from Sector import Sector -from ErrorCollision import ErrorEnterpriseCollision +from PyTrek9000 import Glyphs as Glyphs +from PyTrek9000.ShipKlingon import ShipKlingon as ShipKlingon +from PyTrek9000.Points import * +from PyTrek9000.Sector import Sector as Sector +from PyTrek9000.ErrorCollision import ErrorEnterpriseCollision as ErrorEnterpriseCollision -import MapSparse +import PyTrek9000.MapSparse as MapSparse class GameMap(MapSparse.SparseMap): @@ -35,7 +35,7 @@ def place(self, takers): if not nelem: continue to_take = random.randint(0, nelem) - if nelem is 1: + if nelem == 1: to_take = 1 if not to_take: continue @@ -44,13 +44,13 @@ def place(self, takers): ss = random.randrange(1, 64) # Ignore "Outer Limits" area = self.get_area(ss) should_take = random.randint(1, 8) - if which is 0: + if which == 0: if area.count_glyphs(Glyphs.STARBASE) != 0: continue area.place_glyph(Glyphs.STARBASE) - elif which is 1: + elif which == 1: area.place_glyph(Glyphs.STAR) - elif which is 2: + elif which == 2: if area.count_glyphs(Glyphs.KLINGON) > 3: continue area.place_glyph(Glyphs.KLINGON) diff --git a/MapSparse.py b/MapSparse.py index 374f518..e0a29b1 100644 --- a/MapSparse.py +++ b/MapSparse.py @@ -1,6 +1,6 @@ import random -import TrekStrings -import Glyphs +import PyTrek9000.TrekStrings as TrekStrings +import PyTrek9000.Glyphs as Glyphs class SparseMap: ''' diff --git a/PyTrek.py b/PyTrek.py index 56748ce..288f3ee 100644 --- a/PyTrek.py +++ b/PyTrek.py @@ -1,16 +1,16 @@ import random -import TrekStrings -from Console import Con -from ShipKlingon import ShipKlingon -from ShipEnterprise import ShipEnterprise -from ShipStarbase import ShipStarbase -from Calculators import Calc -from Controls import Control -from Reports import Stats -from Points import * -from Quips import Quips -from MapGame import * +import PyTrek9000.TrekStrings as TrekStrings +from PyTrek9000.Console import Con +from PyTrek9000.ShipKlingon import ShipKlingon as ShipKlingon +from PyTrek9000.ShipEnterprise import ShipEnterprise +from PyTrek9000.ShipStarbase import ShipStarbase +from PyTrek9000.Calculators import Calc +from PyTrek9000.Controls import Control +from PyTrek9000.Reports import Stats +from PyTrek9000.Points import * +from PyTrek9000.Quips import Quips +from PyTrek9000.MapGame import * class Game(Con): @@ -63,16 +63,16 @@ def run(self): The game loop - runs until the game is over. ''' self.show_strings(TrekStrings.LOGO_TREKER) - game.star_date = random.randint(2250, 2300) - game.time_remaining = random.randint(40, 45) - game.destroyed = False + self.star_date = random.randint(2250, 2300) + self.time_remaining = random.randint(40, 45) + self.destroyed = False stars = random.randint(500, 700) # 4096 = ALL aliens = random.randint(14, 24) starbases = random.randint(6, 8) - game.game_map.randomize(starbases, stars, aliens) + self.game_map.randomize(starbases, stars, aliens) dest = WarpDest(64, 0) - game.move_to(dest) - game.game_map.get_area(64).name = 'Outer Limits' + self.move_to(dest) + self.game_map.get_area(64).name = 'Outer Limits' self.print_mission() self.show_strings(TrekStrings.HELM_CMDS) @@ -95,33 +95,33 @@ def run(self): if ex.glyph == Glyphs.STAR: self.display("You flew into a STAR?") self.destroyed = True - game.display() - Stats.show_exit_status(game) - game.display() + self.display() + Stats.show_exit_status(self) + self.display() if self.destroyed == True: self.display(Quips.jibe_fatal_mistake()) - game.display() + self.display() return False def command_prompt(self): command = self.read("Enter command: ").strip().lower() self.display() if command == "nav": - Calc.warp_navigation(game) + Calc.warp_navigation(self) if command == "sub": - Calc.sublight_navigation(game) + Calc.sublight_navigation(self) elif command == "srs": - game.enterprise.short_range_scan(game) + self.enterprise.short_range_scan(self) elif command == "lrs": - game.enterprise.long_range_scan(game) + self.enterprise.long_range_scan(self) elif command == "pha": - Control.phasers(game) + Control.phasers(self) elif command == "tor": - Control.torpedos(game) + Control.torpedos(self) elif command == "she": - Control.shields(game) + Control.shields(self) elif command == "com": - Control.computer(game) + Control.computer(self) elif command.startswith('qui') or command.startswith('exi'): return False else: @@ -132,14 +132,18 @@ def print_mission(self): self.display("Mission: Destroy {0} Klingon ships in {1} stardates with {2} starbases.".format( self.game_map.game_klingons, self.time_remaining, self.game_map.game_starbases)) self.display() + + @staticmethod + def mainloop(): + import traceback + game = Game() + try: + game.run() + except Exception as ex: + print(ex) + # Stack trace: + traceback.print_exc() -if __name__ == '__main__': - import traceback - game = Game() - try: - game.run() - except Exception as ex: - print(ex) - # Stack trace: - traceback.print_exc() +Game.mainloop() + diff --git a/Reports.py b/Reports.py index 8bbada2..46d413c 100644 --- a/Reports.py +++ b/Reports.py @@ -1,5 +1,5 @@ -import Glyphs -from Quips import Quips +from PyTrek9000 import Glyphs as Glyphs +from PyTrek9000.Quips import Quips as Quips class Stats(): ''' diff --git a/Sector.py b/Sector.py index d52541b..9060f44 100644 --- a/Sector.py +++ b/Sector.py @@ -1,4 +1,4 @@ -import Glyphs +import PyTrek9000.Glyphs as Glyphs class Sector(): def __init__(self, num=-1, name='', diff --git a/ShipEnterprise.py b/ShipEnterprise.py index cc06bbd..4fb9222 100644 --- a/ShipEnterprise.py +++ b/ShipEnterprise.py @@ -1,10 +1,10 @@ import random -from AbsShip import AbsShip -from ShipStarbase import ShipStarbase -from Sector import Sector -from Difficulity import Probabilities -import Glyphs -from Quips import Quips +from PyTrek9000.AbsShip import AbsShip +from PyTrek9000.ShipStarbase import ShipStarbase +from PyTrek9000.Sector import Sector +from PyTrek9000.Difficulity import Probabilities +from PyTrek9000 import Glyphs as Glyphs +from PyTrek9000.Quips import Quips as Quips class ShipEnterprise(AbsShip): diff --git a/ShipKlingon.py b/ShipKlingon.py index 710d433..2f33657 100644 --- a/ShipKlingon.py +++ b/ShipKlingon.py @@ -1,6 +1,6 @@ import random -import Glyphs -from AbsShip import AbsShip +import PyTrek9000.Glyphs as Glyphs +from PyTrek9000.AbsShip import AbsShip as AbsShip class ShipKlingon(AbsShip): @@ -25,7 +25,7 @@ def attack_if_you_can(game): ''' if game.is_cloked: return False - from Calculators import Calc + from PyTrek9000.Calculators import Calc as Calc kships = game.game_map.get_area_klingons() if len(kships) > 0: for ship in kships: diff --git a/ShipStarbase.py b/ShipStarbase.py index a7f67b5..b65a45c 100644 --- a/ShipStarbase.py +++ b/ShipStarbase.py @@ -1,5 +1,5 @@ -import Glyphs -from AbsShip import AbsShip +import PyTrek9000.Glyphs as Glyphs +from PyTrek9000.AbsShip import AbsShip as AbsShip class ShipStarbase(AbsShip): diff --git a/test_MapSparse.py b/test_MapSparse.py index 5edcf09..1c103b2 100644 --- a/test_MapSparse.py +++ b/test_MapSparse.py @@ -1,7 +1,7 @@ import random -import MapGame -import Glyphs -from MapSparse import SparseMap +import PyTrek9000.MapGame as MapGame +import PyTrek9000.Glyphs as Glyphs +from PyTrek9000.MapSparse import SparseMap as SparseMap def fill_map(): map = SparseMap() From 0fd4bb11988b4b5b5fe2134adfd2f79840a7ed18 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 3 Jun 2023 16:16:49 -0400 Subject: [PATCH 087/100] room for more revs! --- PyTrek.py => PyTrek1.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename PyTrek.py => PyTrek1.py (100%) diff --git a/PyTrek.py b/PyTrek1.py similarity index 100% rename from PyTrek.py rename to PyTrek1.py From 42021a73e4902c92d37ca71f1ff948b37fdaece2 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 3 Jun 2023 16:20:50 -0400 Subject: [PATCH 088/100] renamed package --- AbsShip.py | 6 +++--- Calculators.py | 8 ++++---- Console.py | 4 ++-- Controls.py | 16 ++++++++-------- MapGame.py | 14 +++++++------- MapSparse.py | 4 ++-- PyTrek1.py | 22 +++++++++++----------- Reports.py | 4 ++-- Sector.py | 2 +- ShipEnterprise.py | 12 ++++++------ ShipKlingon.py | 6 +++--- ShipStarbase.py | 4 ++-- test_MapSparse.py | 6 +++--- 13 files changed, 54 insertions(+), 54 deletions(-) diff --git a/AbsShip.py b/AbsShip.py index 7f116a3..a686abc 100644 --- a/AbsShip.py +++ b/AbsShip.py @@ -1,9 +1,9 @@ import abc import random -from PyTrek9000 import Glyphs as Glyphs -from PyTrek9000.Quips import Quips as Quips -from PyTrek9000.Sector import Sector as Sector +from PyTrek import Glyphs as Glyphs +from PyTrek.Quips import Quips as Quips +from PyTrek.Sector import Sector as Sector class AbsShip(abc.ABC): ''' The first step, into a much larger universe ... ''' diff --git a/Calculators.py b/Calculators.py index 072484e..23530b2 100644 --- a/Calculators.py +++ b/Calculators.py @@ -1,10 +1,10 @@ from math import sqrt import random -from PyTrek9000.MapGame import * -from PyTrek9000.AbsShip import * -from PyTrek9000.Points import * -from PyTrek9000.Difficulity import Probabilities +from PyTrek.MapGame import * +from PyTrek.AbsShip import * +from PyTrek.Points import * +from PyTrek.Difficulity import Probabilities class Calc(): diff --git a/Console.py b/Console.py index e46e2a3..3f2e596 100644 --- a/Console.py +++ b/Console.py @@ -1,5 +1,5 @@ -from PyTrek9000.AbsDisplay import abs_display -from PyTrek9000.Points import * +from PyTrek.AbsDisplay import abs_display +from PyTrek.Points import * class Con(abs_display): ''' diff --git a/Controls.py b/Controls.py index ac9f18a..3654605 100644 --- a/Controls.py +++ b/Controls.py @@ -1,13 +1,13 @@ import random -from PyTrek9000 import TrekStrings -from PyTrek9000 import Glyphs -from PyTrek9000.ShipKlingon import ShipKlingon -from PyTrek9000.ShipEnterprise import ShipEnterprise -from PyTrek9000.Calculators import Calc -from PyTrek9000.Reports import Stats -from PyTrek9000.Quips import Quips -from PyTrek9000.Difficulity import Probabilities +from PyTrek import TrekStrings +from PyTrek import Glyphs +from PyTrek.ShipKlingon import ShipKlingon +from PyTrek.ShipEnterprise import ShipEnterprise +from PyTrek.Calculators import Calc +from PyTrek.Reports import Stats +from PyTrek.Quips import Quips +from PyTrek.Difficulity import Probabilities class Control(): diff --git a/MapGame.py b/MapGame.py index c71ba2f..2de4058 100644 --- a/MapGame.py +++ b/MapGame.py @@ -1,13 +1,13 @@ import random -import PyTrek9000.TrekStrings as TrekStrings +import PyTrek.TrekStrings as TrekStrings -from PyTrek9000 import Glyphs as Glyphs -from PyTrek9000.ShipKlingon import ShipKlingon as ShipKlingon -from PyTrek9000.Points import * -from PyTrek9000.Sector import Sector as Sector -from PyTrek9000.ErrorCollision import ErrorEnterpriseCollision as ErrorEnterpriseCollision +from PyTrek import Glyphs as Glyphs +from PyTrek.ShipKlingon import ShipKlingon as ShipKlingon +from PyTrek.Points import * +from PyTrek.Sector import Sector as Sector +from PyTrek.ErrorCollision import ErrorEnterpriseCollision as ErrorEnterpriseCollision -import PyTrek9000.MapSparse as MapSparse +import PyTrek.MapSparse as MapSparse class GameMap(MapSparse.SparseMap): diff --git a/MapSparse.py b/MapSparse.py index e0a29b1..1e1f98a 100644 --- a/MapSparse.py +++ b/MapSparse.py @@ -1,6 +1,6 @@ import random -import PyTrek9000.TrekStrings as TrekStrings -import PyTrek9000.Glyphs as Glyphs +import PyTrek.TrekStrings as TrekStrings +import PyTrek.Glyphs as Glyphs class SparseMap: ''' diff --git a/PyTrek1.py b/PyTrek1.py index 288f3ee..6f49bb0 100644 --- a/PyTrek1.py +++ b/PyTrek1.py @@ -1,16 +1,16 @@ import random -import PyTrek9000.TrekStrings as TrekStrings -from PyTrek9000.Console import Con -from PyTrek9000.ShipKlingon import ShipKlingon as ShipKlingon -from PyTrek9000.ShipEnterprise import ShipEnterprise -from PyTrek9000.ShipStarbase import ShipStarbase -from PyTrek9000.Calculators import Calc -from PyTrek9000.Controls import Control -from PyTrek9000.Reports import Stats -from PyTrek9000.Points import * -from PyTrek9000.Quips import Quips -from PyTrek9000.MapGame import * +import PyTrek.TrekStrings as TrekStrings +from PyTrek.Console import Con +from PyTrek.ShipKlingon import ShipKlingon as ShipKlingon +from PyTrek.ShipEnterprise import ShipEnterprise +from PyTrek.ShipStarbase import ShipStarbase +from PyTrek.Calculators import Calc +from PyTrek.Controls import Control +from PyTrek.Reports import Stats +from PyTrek.Points import * +from PyTrek.Quips import Quips +from PyTrek.MapGame import * class Game(Con): diff --git a/Reports.py b/Reports.py index 46d413c..e965517 100644 --- a/Reports.py +++ b/Reports.py @@ -1,5 +1,5 @@ -from PyTrek9000 import Glyphs as Glyphs -from PyTrek9000.Quips import Quips as Quips +from PyTrek import Glyphs as Glyphs +from PyTrek.Quips import Quips as Quips class Stats(): ''' diff --git a/Sector.py b/Sector.py index 9060f44..9979bfc 100644 --- a/Sector.py +++ b/Sector.py @@ -1,4 +1,4 @@ -import PyTrek9000.Glyphs as Glyphs +import PyTrek.Glyphs as Glyphs class Sector(): def __init__(self, num=-1, name='', diff --git a/ShipEnterprise.py b/ShipEnterprise.py index 4fb9222..aba24ec 100644 --- a/ShipEnterprise.py +++ b/ShipEnterprise.py @@ -1,10 +1,10 @@ import random -from PyTrek9000.AbsShip import AbsShip -from PyTrek9000.ShipStarbase import ShipStarbase -from PyTrek9000.Sector import Sector -from PyTrek9000.Difficulity import Probabilities -from PyTrek9000 import Glyphs as Glyphs -from PyTrek9000.Quips import Quips as Quips +from PyTrek.AbsShip import AbsShip +from PyTrek.ShipStarbase import ShipStarbase +from PyTrek.Sector import Sector +from PyTrek.Difficulity import Probabilities +from PyTrek import Glyphs as Glyphs +from PyTrek.Quips import Quips as Quips class ShipEnterprise(AbsShip): diff --git a/ShipKlingon.py b/ShipKlingon.py index 2f33657..a135afb 100644 --- a/ShipKlingon.py +++ b/ShipKlingon.py @@ -1,6 +1,6 @@ import random -import PyTrek9000.Glyphs as Glyphs -from PyTrek9000.AbsShip import AbsShip as AbsShip +import PyTrek.Glyphs as Glyphs +from PyTrek.AbsShip import AbsShip as AbsShip class ShipKlingon(AbsShip): @@ -25,7 +25,7 @@ def attack_if_you_can(game): ''' if game.is_cloked: return False - from PyTrek9000.Calculators import Calc as Calc + from PyTrek.Calculators import Calc as Calc kships = game.game_map.get_area_klingons() if len(kships) > 0: for ship in kships: diff --git a/ShipStarbase.py b/ShipStarbase.py index b65a45c..e2bb9cb 100644 --- a/ShipStarbase.py +++ b/ShipStarbase.py @@ -1,5 +1,5 @@ -import PyTrek9000.Glyphs as Glyphs -from PyTrek9000.AbsShip import AbsShip as AbsShip +import PyTrek.Glyphs as Glyphs +from PyTrek.AbsShip import AbsShip as AbsShip class ShipStarbase(AbsShip): diff --git a/test_MapSparse.py b/test_MapSparse.py index 1c103b2..4770945 100644 --- a/test_MapSparse.py +++ b/test_MapSparse.py @@ -1,7 +1,7 @@ import random -import PyTrek9000.MapGame as MapGame -import PyTrek9000.Glyphs as Glyphs -from PyTrek9000.MapSparse import SparseMap as SparseMap +import PyTrek.MapGame as MapGame +import PyTrek.Glyphs as Glyphs +from PyTrek.MapSparse import SparseMap as SparseMap def fill_map(): map = SparseMap() From acca18b0c5e2a10c3fe29112aa92b4ad41d25df2 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 3 Jun 2023 16:30:58 -0400 Subject: [PATCH 089/100] Starting the TUI --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5d5bb31..e396399 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,13 @@ Enjoy the journey, -- Randall Nagy ### P.S -Changed the official PyTrek number from 2020 to 9000 to better support age-nostic updates & enhancements. +Changed the official PyTrek number from 2020 to 9000 to better support age-nostic updates & enhancements. Same for the `Game` Class in PyTrek1.py + +To play PyTrek 9000: + +>>> from PyTrek import PyTrek1 + +-will automaticall run this TUI universal. ## zSupport? From 049790fc7379960cd89f537cf7b390792e2b47c0 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sat, 3 Jun 2023 16:32:24 -0400 Subject: [PATCH 090/100] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e396399..d7a0a22 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,9 @@ Changed the official PyTrek number from 2020 to 9000 to better support age-nosti To play PyTrek 9000: +``` >>> from PyTrek import PyTrek1 - +``` -will automaticall run this TUI universal. From c128aa23ebb9e2b199f4219dc9f679fb56ef1880 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sun, 5 Nov 2023 04:40:42 -0500 Subject: [PATCH 091/100] Free education for beginners. Updated the link to -> The PyQuest Primer. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d7a0a22..2b60283 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Original authors did an excellent job - made the modernization a WHOLE LOT easie Feel free to do a 'Kirk here - Kobayashi Maru? -https://www.udemy.com/course/python-1000/ +[(Free Education for Beginners](https://www.udemy.com/course/python-1000-the-python-primer/?referralCode=A22C48BD99DBF167A3DE) Thinking about adding mult-user / networked features? -Then [here is a good video](https://www.oreilly.com/library/view/tcpip-and-udpip/9781484294543/) to assist with those networking 'Py-Spirations. From b997d13ebde3a808c4f44c36b6cc4a7ec3aae075 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Thu, 23 Nov 2023 05:06:59 -0500 Subject: [PATCH 092/100] Updated Links --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2b60283..02e4c66 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Original authors did an excellent job - made the modernization a WHOLE LOT easie Feel free to do a 'Kirk here - Kobayashi Maru? -[(Free Education for Beginners](https://www.udemy.com/course/python-1000-the-python-primer/?referralCode=A22C48BD99DBF167A3DE) +[(Free Education for Beginners)](https://www.udemy.com/course/python-1000-the-python-primer/?referralCode=A22C48BD99DBF167A3DE) Thinking about adding mult-user / networked features? -Then [here is a good video](https://www.oreilly.com/library/view/tcpip-and-udpip/9781484294543/) to assist with those networking 'Py-Spirations. From cee4c796c58e1ca9750de1fea35e27b5ff63782d Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Mon, 27 Nov 2023 06:48:06 -0500 Subject: [PATCH 093/100] Links to BASIC & COBOL editions. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 02e4c66..8b65a95 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The original free-and-open Star Trek console game was THE most played game of th ![PyTrek 9000](https://github.com/Python3-Training/PyTrek-9000/blob/master/PyTrek.png) -Originally written in B.A.S.I.C, from C/C++, FORTRAN, C#, Python 2 ... and now Python 3, many have been inspired to re-create, improve, and / or simply experiment with the concept. +Originally written in [B.A.S.I.C](https://github.com/soft9000/Blog9000/blob/master/BASIC/SuperStarTrek_1973_10_00/STTR1.BAS), from [COBOL](https://github.com/soft9000/Blog9000/blob/master/GnuCOBOL/star_trek/star_trek.COB), C/C++, FORTRAN, C#, Python 2 ... and now Python 3, many have been inspired to re-create, improve, and / or simply experiment with the concept. So far: From 2bc2112663cbd6ba62e5a92f61427823d63b3ca5 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Thu, 4 Jul 2024 09:37:32 -0400 Subject: [PATCH 094/100] No 'mo YouTube for THIS American! --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8b65a95..e523b25 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ *** -# PyTrek 9000 +# PyTrek 9000 (a.k.a PyTrek 2020) *** The original free-and-open Star Trek console game was THE most played game of the day .... back in the 1970's! ![PyTrek 9000](https://github.com/Python3-Training/PyTrek-9000/blob/master/PyTrek.png) +The How-To Video is [now here](https://takelessons.com/provider/profilev2/video/edit/b265b9922c7e46d688b28cb93abb9686?service=python)! + Originally written in [B.A.S.I.C](https://github.com/soft9000/Blog9000/blob/master/BASIC/SuperStarTrek_1973_10_00/STTR1.BAS), from [COBOL](https://github.com/soft9000/Blog9000/blob/master/GnuCOBOL/star_trek/star_trek.COB), C/C++, FORTRAN, C#, Python 2 ... and now Python 3, many have been inspired to re-create, improve, and / or simply experiment with the concept. So far: @@ -22,8 +24,6 @@ So far: * Heavily re-factored for growth, testing, re-use, and maintenance using modern Python. -Video: https://youtu.be/TpmtCLOJ5Uw - Original authors did an excellent job - made the modernization a WHOLE LOT easier! Feel free to do a 'Kirk here - Kobayashi Maru? From 1ada862ffc8d58b142822068c77c1753b33556de Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Thu, 4 Jul 2024 10:01:19 -0400 Subject: [PATCH 095/100] Re-linked the restored COBOL 'Trek. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e523b25..5161718 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The original free-and-open Star Trek console game was THE most played game of th The How-To Video is [now here](https://takelessons.com/provider/profilev2/video/edit/b265b9922c7e46d688b28cb93abb9686?service=python)! -Originally written in [B.A.S.I.C](https://github.com/soft9000/Blog9000/blob/master/BASIC/SuperStarTrek_1973_10_00/STTR1.BAS), from [COBOL](https://github.com/soft9000/Blog9000/blob/master/GnuCOBOL/star_trek/star_trek.COB), C/C++, FORTRAN, C#, Python 2 ... and now Python 3, many have been inspired to re-create, improve, and / or simply experiment with the concept. +Originally written in [B.A.S.I.C](https://github.com/soft9000/Blog9000/blob/master/BASIC/SuperStarTrek_1973_10_00/STTR1.BAS), from [COBOL](https://github.com/soft9000/COBOL/tree/main/star_trek/star_trek.COB), C/C++, FORTRAN, C#, Python 2 ... and now Python 3, many have been inspired to re-create, improve, and / or simply experiment with the concept. So far: From fe4ddc1a564609af58d9fe672716480341dc460f Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Thu, 3 Oct 2024 12:35:35 -0400 Subject: [PATCH 096/100] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 5161718..7d1dd18 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,6 @@ The original free-and-open Star Trek console game was THE most played game of th ![PyTrek 9000](https://github.com/Python3-Training/PyTrek-9000/blob/master/PyTrek.png) -The How-To Video is [now here](https://takelessons.com/provider/profilev2/video/edit/b265b9922c7e46d688b28cb93abb9686?service=python)! - Originally written in [B.A.S.I.C](https://github.com/soft9000/Blog9000/blob/master/BASIC/SuperStarTrek_1973_10_00/STTR1.BAS), from [COBOL](https://github.com/soft9000/COBOL/tree/main/star_trek/star_trek.COB), C/C++, FORTRAN, C#, Python 2 ... and now Python 3, many have been inspired to re-create, improve, and / or simply experiment with the concept. So far: From ed23bb845d0e0b105ff126c0b3673cd26cc39bc3 Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Sun, 13 Oct 2024 08:34:36 -0400 Subject: [PATCH 097/100] Fleeing leftist tyranny ... Video re-hosted. --- README.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 7d1dd18..d6bc984 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ *** -# PyTrek 9000 (a.k.a PyTrek 2020) +# PyTrek 9000 *** The original free-and-open Star Trek console game was THE most played game of the day .... back in the 1970's! ![PyTrek 9000](https://github.com/Python3-Training/PyTrek-9000/blob/master/PyTrek.png) -Originally written in [B.A.S.I.C](https://github.com/soft9000/Blog9000/blob/master/BASIC/SuperStarTrek_1973_10_00/STTR1.BAS), from [COBOL](https://github.com/soft9000/COBOL/tree/main/star_trek/star_trek.COB), C/C++, FORTRAN, C#, Python 2 ... and now Python 3, many have been inspired to re-create, improve, and / or simply experiment with the concept. +Originally written in B.A.S.I.C, from C/C++, FORTRAN, C#, Python 2 ... and now Python 3, many have been inspired to re-create, improve, and / or simply experiment with the concept. So far: @@ -22,13 +22,13 @@ So far: * Heavily re-factored for growth, testing, re-use, and maintenance using modern Python. -Original authors did an excellent job - made the modernization a WHOLE LOT easier! +Video: [Game Overview](https://s3.amazonaws.com/soft9000.com/vids/2020_12_24_StarTrek2020_Overview.mp4) -Feel free to do a 'Kirk here - Kobayashi Maru? +Original authors did an excellent job - made the modernization a WHOLE LOT easier! -[(Free Education for Beginners)](https://www.udemy.com/course/python-1000-the-python-primer/?referralCode=A22C48BD99DBF167A3DE) +Feel free to do a 'Kirk here - learn how to code a [Kobayashi Maru](https://www.udemy.com/course/python-1000-the-python-primer/?referralCode=A22C48BD99DBF167A3DE)? -Thinking about adding mult-user / networked features? -Then [here is a good video](https://www.oreilly.com/library/view/tcpip-and-udpip/9781484294543/) to assist with those networking 'Py-Spirations. +Thinking about adding mult-user / networked features? -Then [here is a good video](https://www.oreilly.com/library/view/tcpip-and-udpip/9781484294543/) to assist with those networking 'Py-spirations. @@ -50,5 +50,3 @@ To play PyTrek 9000: ## zSupport? If you want to support the effort, I seek no donations. Instead, simply feel free to purchase one of [my educational](https://www.udemy.com/user/randallnagy2/) or [printed](https://www.amazon.com/Randall-Nagy/e/B08ZJLH1VN?ref=sr_ntt_srch_lnk_1&qid=1660050704&sr=8-1) productions? - - From f8b325253b3cdc971f1634d4dabe0cdd7f48a5ac Mon Sep 17 00:00:00 2001 From: Randall Nagy Date: Mon, 24 Mar 2025 09:45:44 -0400 Subject: [PATCH 098/100] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6bc984..cededb3 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ So far: * Added random event Quips – should make the game a tad more ‘NPC’? -* Added that classic sublight / in system propulsion system. Warp speeds engines are now a seperate navigational system. +* Added that classic sublight / in system propulsion system. Warp speeds engines are now a separate navigational system. * Warp speed selection changes game time. (Thanks Loondas!) From db96d6b327973d8fd5f2c9ebb8fde22d4f97a16a Mon Sep 17 00:00:00 2001 From: "Mr. Nagy" Date: Tue, 6 May 2025 09:20:54 -0400 Subject: [PATCH 099/100] Back on YouTube as 'Total Pythoneering.' --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cededb3..a0fe36d 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ So far: * Heavily re-factored for growth, testing, re-use, and maintenance using modern Python. -Video: [Game Overview](https://s3.amazonaws.com/soft9000.com/vids/2020_12_24_StarTrek2020_Overview.mp4) +Video: [Game Overview](https://youtu.be/VLEXHtqKKaA?si=5FAw48gFkjAgbnmi) Original authors did an excellent job - made the modernization a WHOLE LOT easier! From 0ab3e0c2dea30713789d9eb326c72399d5602c51 Mon Sep 17 00:00:00 2001 From: "Mr. Nagy" Date: Mon, 19 May 2025 13:50:29 -0400 Subject: [PATCH 100/100] Hack a Trek @TotalPythoneering ... epic software is never completed ... --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a0fe36d..e16cbae 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ # PyTrek 9000 *** -The original free-and-open Star Trek console game was THE most played game of the day .... back in the 1970's! +The original free-and-open Star Trek console game was THE most played game of the day .... back in the 1970's! + +Today, however, we're adding a multi user interface on the [@TotalPythoneering](https://www.youtube.com/@TotalPythoneering) playlist... [Check it out](https://youtu.be/dRoMF2orxew?si=fxtwwoZQo6u3ViMv)? ![PyTrek 9000](https://github.com/Python3-Training/PyTrek-9000/blob/master/PyTrek.png)