diff options
Diffstat (limited to 'tui')
| -rw-r--r-- | tui/__init__.py | 1 | ||||
| -rw-r--r-- | tui/ansi_draw.py | 61 | ||||
| -rw-r--r-- | tui/autotui.py | 27 | ||||
| -rw-r--r-- | tui/kbd.py | 78 | ||||
| -rw-r--r-- | tui/tui.py | 173 | 
5 files changed, 202 insertions, 138 deletions
| diff --git a/tui/__init__.py b/tui/__init__.py index f39cd45..c1c5b91 100644 --- a/tui/__init__.py +++ b/tui/__init__.py @@ -1,4 +1,3 @@  """ tui - hoitaa käyttäjälle katseltavaa ja havaitsee syötteet """  from .tui import Tui -from .autotui import AutoTui  from .static import Action diff --git a/tui/ansi_draw.py b/tui/ansi_draw.py new file mode 100644 index 0000000..dd304d0 --- /dev/null +++ b/tui/ansi_draw.py @@ -0,0 +1,61 @@ +""" tui/ansi_draw.py - perustukset ansi tulostelulle """ +# pylint: disable = multiple-imports +from .ansi import Ansi +from .static import TileTypes + +class AnsiDraw(): +    """ AnsiDraw - "piirtelee" näytölle kirjailmilla """ +    def __init__(self, height = 15): +        print(end="\n"*height) + +    def __del__(self): +        print() + +    def __tile(self, tile, hilighted): +        """ "piirtää" yhden ruudun """ +        for ch, colors in zip(TileTypes[tile].text, TileTypes[tile].colors): +            color, bg = colors +            Ansi.color(Ansi.BLACK if hilighted else color) +            Ansi.bg(Ansi.CYAN if hilighted else bg) +            print(end=ch) +            Ansi.reset() + + +    def matrix(self, matrix, hx, hy): +        """ "piirtää" ruudukon """ +        Ansi.cup(len(matrix[0])) +        # pylint: disable=consider-using-enumerate +        for y in range(len(matrix[0])): +            for x in range(len(matrix)): +                hilight = matrix[x][y] != 9 and x == hx and y == hy +                self.__tile(matrix[x][y], hilight) +            print() + + +    def status_line(self, text): +        """ draw_status_line - tulostaa pelitietorivin""" +        print(end=text+'\r') + +class SuppressDraw(): +    """ SuppressDraw - vain status """ +    # pylint: disable = unused-argument + +    def matrix(self, matrix, hx, hy): +        """ "piirtää" ruudukon """ +        return True + +    def status_line(self, text): +        """ draw_status_line - tulostaa pelitietorivin""" +        print(end=text+'\r') + +class NoDraw(): +    """ NoDraw - ei mitään """ +    # pylint: disable = unused-argument + +    def matrix(self, matrix, hx, hy): +        """ "piirtää" ruudukon """ +        return True + +    def status_line(self, text): +        """ draw_status_line - tulostaa pelitietorivin""" +        return True diff --git a/tui/autotui.py b/tui/autotui.py deleted file mode 100644 index ae5d58c..0000000 --- a/tui/autotui.py +++ /dev/null @@ -1,27 +0,0 @@ -""" autotui - pelaa botin antamat vinkit jonka jälkeen käyttäjän """ -from .tui import Tui -from .static import Action -from .ansi import Ansi - -class AutoTui(Tui): -    """ Tui - Luokka joka tekee botin vinkit ensin """ -    def matrix_selector(self, matrix, x, y): -        """ yritetään pyydellä botilta vinkkiä ensin """ -        if self.bot is not None: -            action, x, y = self.bot.hint(matrix, x, y) -            if action != Action.NOOP: -                self.draw_matrix(matrix, -1, -1) -                if action==Action.SAFE: -                    action = Action.OPEN -                return action, x, y - -        return super().matrix_selector(matrix, x, y) - -    def show_board_with_text(self, matrix, x, y, text): -        """ näyttää laudan, tekstin alla (ei odota nappia) """ -        self.draw_matrix(matrix, x, y) -        print(text) -        Ansi.cup(1) - -    def game_end(self, matrix): -        """ pelin lopetus """ diff --git a/tui/kbd.py b/tui/kbd.py new file mode 100644 index 0000000..b6d2363 --- /dev/null +++ b/tui/kbd.py @@ -0,0 +1,78 @@ +""" tui/kbd.py - näppäimistön käsittellijä """ +# pylint: disable = multiple-imports +import termios, fcntl, sys, os +from time import sleep +from .static import ActionKeys, Action + +class NoKbd(): +    """ NoKbd - näppis-ei-käsittelijä """ +    # pylint: disable = unused-argument +    def read_action(self): +        """ read_action - ilman näppistä -> loppu """ +        return Action.QUIT + +    def read_matrix_action(self, w, h, x, y): +        """ read_matrix_action - ilman näppistä -> loppu """ +        return Action.QUIT, 0, 0 + +class Kbd(): +    """ Kbd - näppiskäsittelijä """ +    def __init__(self): +        # Vaatii hieman terminaaliasetusten muokkaamista jotta yksittäiset +        # napin painallukset voidaan lukea +        # https://stackoverflow.com/questions/983354/how-do-i-wait-for-a-pressed-key +        fd = sys.stdin.fileno() +        self.oldterm = termios.tcgetattr(fd) + +        newattr = termios.tcgetattr(fd) +        newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO +        termios.tcsetattr(fd, termios.TCSANOW, newattr) + +        self.oldflags = fcntl.fcntl(fd, fcntl.F_GETFL) +        fcntl.fcntl(fd, fcntl.F_SETFL, self.oldflags | os.O_NONBLOCK) + +    def __del__(self): +        # palautetaan terminaali takaisin alkupetäiseen uskoon +        fd = sys.stdin.fileno() +        termios.tcsetattr(fd, termios.TCSAFLUSH, self.oldterm) +        fcntl.fcntl(fd, fcntl.F_SETFL, self.oldflags) + +    def read_action(self): +        """ lukee näppäimistölä käyttäjän toiminnon """ +        while True: +            # Ehkä riittää jos näppäimiä luetaan 50x sekunnissa +            sleep(0.02) +            try: +                keycode = sys.stdin.read(16) +            except KeyboardInterrupt: +                return Action.QUIT +            if keycode: +                for key, action in ActionKeys.items(): +                    if keycode.startswith(key): +                        return action + +    def read_matrix_action(self, w, h, x, y): +        """ read_matrix_action - lukee actionit ja pitää huolen koordinaat""" +        action = self.read_action() +        match action: +            case Action.QUIT | Action.HINT: +                return (action, x, y) +            case Action.OPEN | Action.FLAG | Action.BOMB | Action.SAFE: +                return (action, x, y) +            case Action.UP: +                y = y-1 if y > 0 else 0 +            case Action.LEFT: +                x = x-1 if x > 0 else 0 +            case Action.DOWN: +                y = y+1 if y < h-1 else y +            case Action.RIGHT: +                x = x+1 if x < w-1 else x +            case Action.TOP: +                y = 0 +            case Action.BOTTOM: +                y = h-1 +            case Action.BEGIN: +                x = 0 +            case Action.END: +                x = w-1 +        return (Action.NOOP, x, y) @@ -1,136 +1,89 @@ -""" tui/tui.py - teksikäyttöliittymä """ +""" tui/tui.py - runko käyttöliittymälle """  # pylint: disable = multiple-imports -import termios, fcntl, sys, os -from time import sleep -from .static import Action, ActionKeys, TileTypes -from .ansi import Ansi +from .static import Action +from .kbd import Kbd, NoKbd +from .ansi_draw import AnsiDraw, SuppressDraw  class Tui():      """ Tui - Luokka käyttäjän interaktiota varten """ -    def __init__(self, bot = None): -        # Vaatii hieman terminaaliasetusten muokkaamista jotta yksittäiset -        # napin painallukset voidaan lukea -        # https://stackoverflow.com/questions/983354/how-do-i-wait-for-a-pressed-key -        fd = sys.stdin.fileno() -        self.oldterm = termios.tcgetattr(fd) +    # pylint: disable = unused-argument +    def __init__(self, **opts): +        self.bot = opts['bot'] if 'bot' in opts else None +        self.autoplay = opts['autoplay'] if 'autoplay' in opts else False +        self.interact = opts['interact'] if 'interact' in opts else True +        self.suppress = opts['suppress'] if 'suppress' in opts else False +        self.height = opts['height'] if 'height' in opts else 15 + +        # jos ei oo bottia pitää olla interaktiivinen +        if self.bot is None: +            self.autoplay = False +            self.interact = True +            self.suppress = False + +        # jos ei mitään näytetä ei voi olla interaktiivinen +        self.interact = False if self.suppress else self.interact + +        # automaattipeli pitää olla päällä jos ei interaktiivinen +        self.autoplay = self.autoplay if self.interact else True + +        if self.interact: +            self.kbd = Kbd() +        else: +            self.kbd = NoKbd() + +        if self.suppress: +            self.draw = SuppressDraw() +        else: +            self.draw = AnsiDraw(height=self.height) -        newattr = termios.tcgetattr(fd) -        newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO -        termios.tcsetattr(fd, termios.TCSANOW, newattr) - -        self.oldflags = fcntl.fcntl(fd, fcntl.F_GETFL) -        fcntl.fcntl(fd, fcntl.F_SETFL, self.oldflags | os.O_NONBLOCK) - -        self.bot = bot - - -    def __del__(self): -        # palautetaan terminaali takaisin alkupetäiseen uskoon -        fd = sys.stdin.fileno() -        termios.tcsetattr(fd, termios.TCSAFLUSH, self.oldterm) -        fcntl.fcntl(fd, fcntl.F_SETFL, self.oldflags) -        print() - - -    def draw_tile(self, tile, hilighted): -        """ "piirtää" yhden ruudun """ -        for ch, colors in zip(TileTypes[tile].text, TileTypes[tile].colors): -            color, bg = colors -            Ansi.color(Ansi.BLACK if hilighted else color) -            Ansi.bg(Ansi.CYAN if hilighted else bg) -            print(end=ch) -            Ansi.reset() - - -    def draw_matrix(self, matrix, hx, hy): -        """ "piirtää" ruudukon """ -        Ansi.cup(len(matrix[0])) -        # pylint: disable=consider-using-enumerate -        for y in range(len(matrix[0])): -            for x in range(len(matrix)): -                hilight = matrix[x][y] != 9 and x == hx and y == hy -                self.draw_tile(matrix[x][y], hilight) -            print() +    def matrix_selector(self, matrix, x, y): +        """ valinta matriisita """ +        # automaattipeli avaa botin vinkit heti +        if self.autoplay: +            action, x, y = self.bot.hint(matrix, x, y) +            if action != Action.NOOP: +                self.draw.matrix(matrix, -1, -1) +                return Action.OPEN if action==Action.SAFE else action, x, y -    def read_action(self): -        """ lukee näppäimistölä käyttäjän toiminnon """ -        while True: -            # Ehkä riittää jos näppäimiä luetaan 50x sekunnissa -            sleep(0.02) -            try: -                keycode = sys.stdin.read(16) -            except KeyboardInterrupt: -                return Action.QUIT -            if keycode: -                for key, action in ActionKeys.items(): -                    if keycode.startswith(key): -                        return action +        # ilman näppiskäsittelijää voidaan lopettaa +        if not self.interact: +            return Action.QUIT, 0, 0 -    def matrix_selector(self, matrix, x, y): -        """ piirtää ruudukon ja antaa käyttäjän valita nuolinäppäimillä """ -        self.draw_matrix(matrix, x, y) +        w, h = len(matrix), len(matrix[0])          while True: -            action = self.read_action() +            self.draw.matrix(matrix, x, y) +            action, x, y = self.kbd.read_matrix_action(w, h, x, y)              match action:                  case Action.QUIT:                      return (action, x, y)                  case Action.OPEN | Action.FLAG | Action.BOMB | Action.SAFE:                      if matrix[x][y] >= 10:                          return (action, x, y) -                case Action.UP: -                    y = y-1 if y > 0 else 0 -                case Action.LEFT: -                    x = x-1 if x > 0 else 0 -                case Action.DOWN: -                    y = y+1 if y < len(matrix[0])-1 else y -                case Action.RIGHT: -                    x = x+1 if x < len(matrix)-1 else x -                case Action.TOP: -                    y = 0 -                case Action.BOTTOM: -                    y = len(matrix[0])-1 -                case Action.BEGIN: -                    x = 0 -                case Action.END: -                    x = len(matrix)-1                  case Action.HINT:                      if self.bot is not None:                          return self.bot.hint(matrix, x, y) -            self.draw_matrix(matrix, x, y) - - -    def show_board_with_text(self, matrix, x, y, text): -        """ näyttää laudan, tekstin alla ja jää odottelemaan nappia """ -        self.draw_matrix(matrix, x, y) -        print(text) -        Ansi.cup(1) -        self.read_action() - - -    def game_begin(self, width, height): -        """ ruudun alustus ja lähtökoordinaatien määritys """ -        print(end="\n"*(height+1)) -        Ansi.cup(1) -        return width//2, height//2 -      def game_over(self, matrix, x, y): -        """ näyttää pelin lopputilanteen ja odottaa nappia """ -        self.show_board_with_text(matrix, x, y, -                "KUOLEMA! ...näppäimellä eteenpäin...") - +        """ tehtävät kun kuolee """ +        self.draw.matrix(matrix, x, y) +        self.draw.status_line( +            "K  " if self.suppress else "Peli ohitse! Kuolit!" +        ) +        self.kbd.read_action()      def game_win(self, matrix, x, y): -        """ näyttäää pelin lopputilanteen ja odottaa nappia """ -        self.show_board_with_text(matrix, x, y, -                "VOITTO! ...näppäimellä eteenpäin...") - +        """ tehtävät kun voittaa """ +        self.draw.matrix(matrix, x, y) +        self.draw.status_line( +            "V  " if self.suppress else "Peli ohitse! Voitit!" +        ) +        self.kbd.read_action()      def game_end(self, matrix): -        """ pelin lopetus """ -        self.show_board_with_text(matrix, -1, -1, -                "PELI OHI! ...näppäimellä eteenpäin...") -        print() +        """ tehtävät ihan pelin lopuksi """ +        if self.interact: +            self.draw.matrix(matrix, -1, -1) +            self.draw.status_line("Kiitos!             ") |