Skip to content

Instantly share code, notes, and snippets.

@kyb3r
Created September 19, 2018 11:59
Show Gist options
  • Select an option

  • Save kyb3r/04414b7560625af5ab7d1d5efbff7d12 to your computer and use it in GitHub Desktop.

Select an option

Save kyb3r/04414b7560625af5ab7d1d5efbff7d12 to your computer and use it in GitHub Desktop.
from functools import partial
import random
class Point:
def __init__(self, row=0, col=0):
self.r = row
self.c = col
def __eq__(self, other):
return self.r == other.r and self.c == other.c
class Part(Point):
def __repr__(self):
return 'x'
class Entity(Point):
'''Represents an entity that can be interacted with in the game'''
def __init__(self, *position, game):
super().__init__(*position)
self.game = game
def is_inside_grid(self, r, c):
return (
r < len(self.game.grid)
and r >= 0
and c < len(self.game.grid[0])
and c >= 0
)
def move(self):
raise NotImplemented
class Missile(Entity):
'''Represents a missile'''
def destroy(self):
'''Removes the missile from game'''
self.game.missiles.remove(self)
def move(self):
'''Moves the missile down'''
if not self.is_inside_grid(self.r + 1, self.c):
self.destroy()
else:
self.r += 1
def __repr__(self):
return '#'
class Player(Entity):
'''Represents the player and all it's parts'''
def __init__(self, row, col, game):
super().__init__(row, col, game=game)
self.health = 20
self.parts = [ # modify this to change player structure
self, # midpoint
Part(row, col+1),
Part(row, col-1),
Part(row+1, col+1),
Part(row+1, col-1),
Part(row-1, col),
Part(row-2, col),
Part(row-3, col)
]
def __repr__(self):
return 'o'
@property
def lifeleft(self):
self.health -= 1
if self.health == 0:
return False
else:
return True
def move(self, delta):
'''Updates the location of the player and all its parts'''
if any(not self.is_inside_grid(part.r + delta[0], part.c + delta[1]) for part in self.parts):
return # moving would go outside grid so dont do it
for part in self.parts:
part.r += delta[0]
part.c += delta[1]
print(f'Moving: {delta}')
def rotate(self, direction):
'''Rotates all parts with the player location being the pivot'''
new_locations = []
for part in self.parts[1:]:
new_row = (direction) * (part.c - self.c) + self.r
new_col = (-direction) * (part.r - self.r) + self.c
new_locations.append(Point(new_row, new_col))
if any(not self.is_inside_grid(point.r, point.c) for point in new_locations):
return
for i, part in enumerate(self.parts[1:]):
part.r = new_locations[i].r
part.c = new_locations[i].c
print(f'Rotating: {direction}')
class Game:
'''Algorithms assignment game implemented in python cos i was bored'''
def __init__(self):
self.running = True
self.reset()
def reset(self):
'''Resets everything'''
self.player = Player(10, 5, game=self)
self.ticks = 0
self.max_missiles = 2 # number of missiles on screen
self.missiles = []
self.clear_grid()
def clear_grid(self):
'''Clears the grid'''
self.grid = [['.'] * 20 for _ in range(20)]
def display(self):
'''Prints out the grid in an aesthetically pleasing way'''
for row in self.grid:
print(" ".join(str(i) for i in row))
print(f'Health: {self.player.health}/20')
def run(self):
'''Game loop'''
while self.running:
if not self.ticks: # display initial grid
self.update_grid()
self.display()
mappings = { # cleaner than a million if elifs
"w": partial(self.player.move, delta=(-1, 0)),
"a": partial(self.player.move, delta=(0, -1)),
"d": partial(self.player.move, delta=(0, 1)),
"q": partial(self.player.rotate, direction=-1),
"e": partial(self.player.rotate, direction=1),
"quit": self.end,
"": lambda *args: None # do nothing
}
cmd = input('> ').strip().lower()
function = mappings.get(
cmd, lambda *args: print("Invalid command entered.")
)
function() # do the thing u wanted to do
if cmd != 'w': # move down anyways
self.player.move(delta=(1, 0))
for missile in self.missiles:
missile.move() # move missiles down
self.check_collisions()
self.spawn_missiles()
self.update_grid()
self.display()
self.ticks += 1
self.max_missiles = 2 + self.ticks // 10 # increase max misiles by one every 10 moves
# u could add ur own retarded progression system
print('Game over.')
restart = input("Restart? (y/n) > ")
if restart == 'y':
self.running = True
self.reset()
self.run()
else:
print("Bye!")
def spawn_missiles(self):
'''only let the max_missiles amount of missiles be on the screen at any one time'''
for _ in range(self.max_missiles - len(self.missiles)):
random_pos = (0, random.randint(0, len(self.grid[0]) - 1))
self.missiles.append(Missile(*random_pos, game=self))
@property
def entities(self):
'''A generator that yields everything that will be displayed'''
yield from self.missiles
yield from self.player.parts
def check_collisions(self):
'''Checks for collisions and ends the game if no health left'''
for part in self.player.parts:
for missile in self.missiles:
if missile == part: # collided
if not self.player.lifeleft: # decrement health and check if lifeleft
return self.end()
missile.destroy()
def update_grid(self):
'''Updates the grid with the locations of all entities'''
self.clear_grid()
for entity in self.entities:
self.grid[entity.r][entity.c] = entity
def end(self):
self.running = False
game = Game()
game.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment