def play(): game = Game() dt = 1 / 2 reactor = Input() schedule_next_frame = reactor.scheduled_event_trigger(Frame) schedule_next_frame(when=time.time()) with reactor: for e in reactor: if game.d.endgame == True: print 'Final Score: %d' % sum(game.score) sys.exit() if isinstance(e, Frame): game.tick() when = e.when + dt while when < time.time(): when += dt schedule_next_frame(when) elif e == u'<ESC>': break else: game.process_event(e)
def play(): game = Game() dt = 1/2 reactor = Input() schedule_next_frame = reactor.scheduled_event_trigger(Frame) schedule_next_frame(when=time.time()) with reactor: for e in reactor: if game.d.endgame == True: print 'Final Score: %d' % sum(game.score) sys.exit() if isinstance(e, Frame): game.tick() when = e.when + dt while when < time.time(): when += dt schedule_next_frame(when) elif e == u'<ESC>': break else: game.process_event(e)
def realtime(fps=15): world = World() dt = 1/fps reactor = Input() schedule_next_frame = reactor.scheduled_event_trigger(Frame) schedule_next_frame(when=time.time()) with reactor: for e in reactor: if isinstance(e, Frame): world.tick() print(world.s) when = e.when + dt while when < time.time(): when += dt schedule_next_frame(when) elif e == '<ESC>': break else: world.process_event(e)
def realtime(fps=15): world = World() dt = 1/fps reactor = Input() schedule_next_frame = reactor.scheduled_event_trigger(Frame) schedule_next_frame(when=time.time()) with reactor: for e in reactor: if isinstance(e, Frame): world.tick() print(world.s) when = e.when + dt while when < time.time(): when += dt schedule_next_frame(when) elif e == u'<ESC>': break else: world.process_event(e)
def mainloop(window, p2_bot=False): p1_attrs = { "appearance": on_blue(cyan("1")), "x": window.width // 4, "y": window.height // 2, "keys": { "w": 90, "a": 180, "s": 270, "d": 0 }, } p2_attrs = { "appearance": on_red(yellow("2")), "x": 3 * window.width // 4, "y": window.height // 2, "keys": { "<UP>": 90, "<LEFT>": 180, "<DOWN>": 270, "<RIGHT>": 0 }, } FPS = 15 players = [Cycle(p1_attrs), Cycle(p2_attrs)] if p2_bot: # make p2 a bot players[1] = Bot(p2_attrs) world = gameboard(window.width, window.height, players) dt = 1 / FPS world.draw_border() window.render_to_terminal(world.grid) reactor = Input() schedule_next_frame = reactor.scheduled_event_trigger(Frame) schedule_next_frame(when=time.time()) with reactor: for c in reactor: if isinstance(c, Frame): tick = world.tick() window.render_to_terminal(world.grid) if not tick: # if no crashes when = c.when + dt while when < time.time(): when += dt schedule_next_frame(when) else: # if crashed world.grid[0:4, 0:25] = fsarray([ world.winner_msg(tick), "r to restart", "q to quit", "b to make player 2 a bot", ]) window.render_to_terminal(world.grid) elif c.lower() in ["r", "q", "b"]: break else: # common case world.process_event(c) if c.lower() == "r": mainloop(window, p2_bot) elif c.lower() == "b": mainloop(window, True)
class Game: """represents the game board, where game state is displayed""" SIZE = (10, 10) def __init__(self, window: FullscreenWindow): # save game window, plus window size info self.window = window self.max_rows = window.height self.max_cols = window.width # initialize reactor system + schedule first tick self.reactor = Input() self.schedule_tick = self.reactor.scheduled_event_trigger(Tick) self.schedule_tick(when=time.time()) self.last_event: Optional[str] = None # initialize game state self.field: Optional[Field] = None self.menu: Optional[str] = None self.menu_opened_at: Optional[pendulum.DateTime] = None # initialize game display + add borders and header self.chars = FSArray(self.max_rows, self.max_cols) self.draw_game_border() self.draw_header() def draw_game_border(self) -> None: """Draws a border around the whole board""" self.chars[0, 0] = '┌' self.chars[0, self.max_cols - 1] = '┐' self.chars[self.max_rows - 1, 0] = '└' self.chars[self.max_rows - 1, self.max_cols - 1] = '┘' for row in range(1, self.max_rows - 1): self.chars[row, 0] = '│' self.chars[row, self.max_cols - 1] = '│' self.chars[2, 0] = '├' self.chars[2, self.max_cols - 1] = "┤" for col in range(1, self.max_cols - 1): self.chars[0, col] = '─' self.chars[2, col] = '-' self.chars[self.max_rows - 1, col] = '─' def draw_header(self) -> None: """renders the header into our array""" title = fmtstr(" No-Guess Sweeper :", fg="blue", underline=True) self.chars[1, 1:1 + title.width] = [title] clock = ff.plain('┊ ') + ff.green( self.field.clock if self.field else "00:00") self.chars[1, (self.max_cols - 1 - clock.width):(self.max_cols - 1)] = [clock] avail = self.max_cols - 2 - title.width - clock.width instructions: List[FmtStr] = [ ff.yellow(' h: ') + ff.gray("Help "), ff.yellow(' q: ') + ff.gray("Quit "), ff.yellow(' n: ') + ff.gray("New "), ] # drop instructions until they fit on top line while sum(i.width for i in instructions) > avail: instructions.pop() per = int(avail / len(instructions)) istr = FmtStr().join(i.ljust(per) for i in instructions) self.chars[1, title.width:(title.width + istr.width)] = [istr] def draw_menu(self, title: FmtStr, items: List[FmtStr]) -> None: """Draws the menu of the specified items""" height = len(items) width = max(( title.width, max(item.width for item in items) if items else 0, )) header = [ "╭" + "-" * (width + 2) + "╮", "|" + title.center(width + 2) + "|", "|" + "-" * (width + 2) + "|", ] footer = [ "╰" + "-" * (width + 2) + "╯", ] body = fsarray(header + ["| " + i.ljust(width) + " |" for i in items] + footer) rows = len(body) cols = max(row.width for row in body) min_row = int(self.max_rows / 2 - rows / 2) min_col = int(self.max_cols / 2 - cols / 2) self.chars[min_row:min_row + rows, min_col:min_col + cols] = body def draw_help(self) -> None: """brings up the help menu""" self.state = "menu" items = [ ('q', 'Quit Sweeper'), ('c', 'Close menu'), ('n', 'New game'), ('←,↑,→,↓', 'Move Cursor'), ('f', 'Flag/unflag'), ('SPACE', 'Clear'), ] max_key = max(len(item[0]) for item in items) lines = [ ff.yellow(item[0]).ljust(max_key) + " : " + ff.gray(item[1]) for item in items ] self.draw_menu(ff.bold("Help"), lines) def draw_confirm_new(self) -> None: """Confirms we want to restart the game""" items = [ ff.red("A game is already in-progress!"), ff.plain("Press ") + fmtstr("n", fg="yellow", underline=True) + " again to start a new", ff.plain("game, or ") + fmtstr("c", fg="yellow", underline=True) + " to cancel", ] self.draw_menu(ff.plain("Restart?"), items) def draw_won(self) -> None: """Confirms we want to restart the game""" assert self.field is not None items = [ ff.plain( f"Congratulations! You won in {self.field.game_time.in_words()}" ), ff.plain(f"Press ") + fmtstr("n", fg="yellow", underline=True) + " to start a new game,", ff.plain("or ") + fmtstr("c", fg="yellow", underline=True) + " to savor your success.", ] self.draw_menu(ff.green("Victory!"), items) def draw_lost(self) -> None: """Confirms we want to restart the game""" assert self.field is not None items = [ ff.plain(f"Alas, you appear to have ") + fmtstr("exploded", fg="red", bold=True) + ".", ff.plain(f"Press ") + fmtstr("n", fg="yellow", underline=True) + " to start a new game,", ff.plain("or ") + fmtstr("c", fg="yellow", underline=True) + " to learn from failure.", ] self.draw_menu(ff.red("Defeat!"), items) def draw_field(self) -> None: """draws the minefield on the board""" if not self.field: return field = self.field.chars rows, cols = field.shape min_row = int(self.max_rows / 2 - rows / 2) min_col = int(self.max_cols / 2 - cols / 2) self.chars[min_row:min_row + rows, min_col:min_col + cols] = field def clear_main(self) -> None: """Hides the game display""" height = self.max_rows - 1 - 3 - 1 # subtract 3 rows for header, 1 for footer width = self.max_cols - 1 - 1 - 1 # subtract left + right border fill = [" " * width] * height self.chars[4:4 + height, 1:1 + width] = fill def draw_debug(self) -> None: """Draws some debug info about game state""" menu = f"menu: {str(self.menu)}" self.chars[self.max_rows - 2, 1:1 + len(menu)] = [menu] event = f"event: {str(self.last_event)}" self.chars[self.max_rows - 3, 1:1 + len(event)] = [event] def update(self) -> None: """Updates display based on game state""" self.clear_main() if self.menu: if not self.menu_opened_at: self.menu_opened_at = pendulum.now() self.clear_main() if self.menu == "help": self.draw_help() elif self.menu == "confirm_new": self.draw_confirm_new() elif self.menu == "won": self.draw_won() elif self.menu == "lost": self.draw_lost() else: self.draw_menu(ff.blue("test"), []) elif self.field: if self.menu_opened_at: self.field.add_stoppage(pendulum.now() - self.menu_opened_at) self.menu_opened_at = None self.draw_header() self.draw_field() if not self.field.ended: if self.field.won: self.menu = "won" elif self.field.lost: self.menu = "lost" self.draw_debug() self.window.render_to_terminal(self.chars) def process_event(self, event: Optional[str]) -> None: """process an input event""" self.last_event = event if self.menu and event == "c": self.menu = None if event == "h": self.menu = "help" if event == "t": self.menu = "test" if event == "n": if not self.field or self.field.ended or self.menu == "confirm_new": self.menu = None self.field = Field() else: self.menu = "confirm_new" if self.field: if event == "<SPACE>": self.field.open() if event == "<UP>": self.field.move(-1, 0) if event == "<LEFT>": self.field.move(0, -1) if event == "<RIGHT>": self.field.move(0, 1) if event == "<DOWN>": self.field.move(1, 0) if event == "f": self.field.flag() def play(self) -> None: """Main loop of the game""" with self.reactor: for e in self.reactor: self.update() if e == '<ESC>' or e == 'q': break elif isinstance(e, Tick): self.schedule_tick(time.time() + 1 / 15) else: self.process_event(str(e))