Esempio n. 1
0
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)
Esempio n. 2
0
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)
Esempio n. 3
0
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)
Esempio n. 4
0
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)
Esempio n. 5
0
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)
Esempio n. 6
0
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))