diff --git a/terminis/music.sh b/terminis/music.sh deleted file mode 100755 index a70b3c3..0000000 --- a/terminis/music.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -C0=-f16; Db0=-f17; D0=-f18; Eb0=-f19; E0=-f20; F0=-f21; Gb0=-f23; G0=-f24; Ab0=-f25; A0=-f27; Bb0=-f29; B0=-f30 -C1=-f32; Db1=-f34; D1=-f36; Eb1=-f38; E1=-f41; F1=-f43; Gb1=-f46; G1=-f49; Ab1=-f51; A1=-f55; Bb1=-f58; B1=-f61 -C2=-f65; Db2=-f69; D2=-f73; Eb2=-f77; E2=-f82; F2=-f87; Gb2=-f92; G2=-f98; Ab2=-f103; A2=-f110; Bb2=-f116; B2=-f123 -C3=-f130; Db3=-f138; D3=-f146; Eb3=-f155; E3=-f164; F3=-f174; Gb3=-f185; G3=-f196; Ab3=-f207; A3=-f220; Bb3=-f233; B3=-f246 -C4=-f261; Db4=-f277; D4=-f293; Eb4=-f311; E4=-f329; F4=-f349; Gb4=-f369; G4=-f392; Ab4=-f415; A4=-f440; Bb4=-f466; B4=-f493 -C5=-f523; Db5=-f554; D5=-f587; Eb5=-f622; E5=-f659; F5=-f698; Gb5=-f739; G5=-f783; Ab5=-f830; A5=-f880; Bb5=-f932; B5=-f987 -C6=-f1046; Db6=-f1108; D6=-f1174; Eb6=-f1244; E6=-f1318; F6=-f1396; Gb6=-f1479; G6=-f1567; Ab6=-f1661; A6=-f1760; Bb6=-f1864; B6=-f1975 -C7=-f2093; Db7=-f2217; D7=-f2349; Eb7=-f2489; E7=-f2637; F7=-f2793; Gb7=-f2959; G7=-f3135; Ab7=-f3322; A7=-f3520; Bb7=-f3729; B7=-f3951 -C8=-f4186; Db8=-f4434; D8=-f4698; Eb8=-f4978; E8=-f5274; F8=-f5587; Gb8=-f5919; G8=-f6271; Ab8=-f6644; A8=-f7040; Bb8=-f7458; B8=-f7902 - -dc=-l100; dcp=-l150; c=-l200; cp=-l300; n=-l400; np=-l600; b=-l800; bp=-l1200; r=-l1600 - -if command -v beep > /dev/null; then - while [ $? -eq 0 ]; do - beep $n $E5 -n $c $B4 -n $c $C5 -n $c $D5 -n $dc $E5 -n $dc $D5 -n $c $C5 -n $c $B4 \ - -n $n $A4 -n $c $A4 -n $c $C5 -n $n $E5 -n $c $D5 -n $c $C5 \ - -n $c $B4 -n $c $E4 -n $c $Ab4 -n $c $C5 -n $n $D5 -n $n $E5 \ - -n $n $C5 -n $n $A4 -n $n $A4 -n $c $B3 -n $c $C4 \ - -n $np $D5 -n $c $F5 -n $c $A5 -n $dc $A5 -n $dc $A5 -n $c $G5 -n $c $F5 \ - -n $n $E5 -n $c $E5 -n $c $C5 -n $c $E5 -n $dc $F5 -n $dc $E5 -n $c $D5 -n $c $C5 \ - -n $c $B4 -n $c $E4 -n $c $Ab4 -n $c $C5 -n $n $D5 -n $n $E5 \ - -n $n $C5 -n $n $A4 -n $b $A4 \ - -n $n $E5 -n $c $B4 -n $c $C5 -n $c $D5 -n $dc $E5 -n $dc $D5 -n $c $C5 -n $c $B4 \ - -n $n $A4 -n $c $A4 -n $c $C5 -n $n $E5 -n $c $D5 -n $c $C5 \ - -n $c $B4 -n $c $E4 -n $c $Ab4 -n $c $C5 -n $n $D5 -n $n $E5 \ - -n $n $C5 -n $n $A4 -n $n $A4 -n $c $B3 -n $c $C4 \ - -n $np $D5 -n $c $F5 -n $c $A5 -n $dc $A5 -n $dc $A5 -n $c $G5 -n $c $F5 \ - -n $n $E5 -n $c $E5 -n $c $C5 -n $c $E5 -n $dc $F5 -n $dc $E5 -n $c $D5 -n $c $C5 \ - -n $c $B4 -n $c $E4 -n $c $Ab4 -n $c $C5 -n $n $D5 -n $n $E5 \ - -n $n $C5 -n $n $A4 -n $b $A4 \ - -n $b $E5 -n $b $C5 -n $b $D5 -n $b $B4 -n $b $C5 -n $b $A4 -n $b $Ab4 -n $c $B4 -n $c $E4 -n $c $Ab4 -n $c $B4 \ - -n $b $E5 -n $b $C5 -n $b $D5 -n $b $B4 -n $n $C5 -n $n $E5 -n $n $A5 -n $n $A5 -n $r $Ab5 > /dev/null - done -fi \ No newline at end of file diff --git a/terminis/terminis.py b/terminis/terminis.py index 7a97a82..c7d20de 100644 --- a/terminis/terminis.py +++ b/terminis/terminis.py @@ -3,7 +3,6 @@ import sys import os import subprocess -import psutil try: import curses @@ -25,9 +24,11 @@ import subprocess try: from configparser import ConfigParser -except ImportError: # Python2 - from ConfigParser import SafeConfigParser as ConfigParser - +except ImportError: + try: + from configparser import SafeConfigParser as ConfigParser + except ImportError: # Python2 + import ConfigParser DIR_NAME = "Terminis" HELP_MSG = """terminis [options] @@ -254,7 +255,8 @@ class Window: def __init__(self, width, height, begin_x, begin_y): self.window = curses.newwin(height, width, begin_y, begin_x) if self.TITLE: - self.title_begin_x = (width-len(self.TITLE)) // 2 + 1 + self.title = "[" + self.TITLE + "]" + self.title_begin_x = (width-len(self.title)) // 2 + 1 self.piece = None self.refresh() @@ -262,7 +264,7 @@ class Window: self.window.erase() self.window.border() if self.TITLE: - self.window.addstr(0, self.title_begin_x, self.TITLE, curses.A_BOLD) + self.window.addstr(0, self.title_begin_x, self.title, curses.A_BOLD) def draw_piece(self): if self.piece: @@ -282,8 +284,8 @@ class Window: class Matrix(Window): NB_COLS = 10 NB_LINES = 21 - WIDTH = NB_COLS*2+2 - HEIGHT = NB_LINES+1 + WIDTH = NB_COLS*2 + 2 + HEIGHT = NB_LINES + 1 PIECE_POSITION = Point(4, -1) TITLE = "" @@ -418,7 +420,7 @@ class Stats(Window): self.draw_border() self.window.addstr(2, 2, "SCORE\t{:n}".format(self.score)) if self.score >= self.high_score: - self.window.addstr(3, 2, "HIGH\t{:n}".format(self.high_score), curses.A_BLINK|curses.A_BOLD) + self.window.addstr(3, 2, "HIGH\t{:n}".format(self.high_score), curses.A_BLINK | curses.A_BOLD) else: self.window.addstr(3, 2, "HIGH\t{:n}".format(self.high_score)) self.window.addstr(5, 2, "LEVEL\t%d" % self.level) @@ -426,7 +428,7 @@ class Stats(Window): self.window.addstr(7, 2, "LINES\t%d" % self.lines_cleared) start_y = self.height - len(self.strings) - 2 for y, string in enumerate(self.strings, start=start_y): - x = (self.width-len(string)) // 2 + 1 + x = (self.width - len(string)) // 2 + 1 self.window.addstr(y, x, string) self.refresh_time() @@ -506,9 +508,9 @@ class ControlsParser(ConfigParser): SECTION = "CONTROLS" COMMENT = """# You can change key below. # Acceptable values are: -# `SPACE`, `TAB`, `ENTER`, -# printable characters (`q`, `*`...) (case sensitive), -# curses's constants name starting with `KEY_` +# - `SPACE`, `TAB`, `ENTER`, +# - printable characters (`q`, `*`...) (case sensitive), +# - curses's constants name starting with `KEY_` # See https://docs.python.org/3/library/curses.html?highlight=curses#constants """ @@ -585,20 +587,30 @@ class ControlsWindow(Window, ControlsParser): class Music: - PATH = os.path.join(os.path.dirname(__file__), "music.sh") - def __init__(self): self.process = None def play(self): - self.process = subprocess.Popen(["sh", self.PATH]) + try: + self.process = subprocess.Popen(["beep", "-l400", "-f659", "-n", "-l200", "-f493", "-n", "-l200", "-f523", "-n", "-l200", "-f587", "-n", "-l100", "-f659", "-n", "-l100", "-f587", "-n", "-l200", "-f523", "-n", "-l200", "-f493", "-n", "-l400", "-f440", "-n", "-l200", "-f440", "-n", "-l200", "-f523", "-n", "-l400", "-f659", "-n", "-l200", "-f587", "-n", "-l200", "-f523", "-n", "-l200", "-f493", "-n", "-l200", "-f329", "-n", "-l200", "-f415", "-n", "-l200", "-f523", "-n", "-l400", "-f587", "-n", "-l400", "-f659", "-n", "-l400", "-f523", "-n", "-l400", "-f440", "-n", "-l400", "-f440", "-n", "-l200", "-f246", "-n", "-l200", "-f261", "-n", "-l600", "-f587", "-n", "-l200", "-f698", "-n", "-l200", "-f880", "-n", "-l100", "-f880", "-n", "-l100", "-f880", "-n", "-l200", "-f783", "-n", "-l200", "-f698", "-n", "-l400", "-f659", "-n", "-l200", "-f659", "-n", "-l200", "-f523", "-n", "-l200", "-f659", "-n", "-l100", "-f698", "-n", "-l100", "-f659", "-n", "-l200", "-f587", "-n", "-l200", "-f523", "-n", "-l200", "-f493", "-n", "-l200", "-f329", "-n", "-l200", "-f415", "-n", "-l200", "-f523", "-n", "-l400", "-f587", "-n", "-l400", "-f659", "-n", "-l400", "-f523", "-n", "-l400", "-f440", "-n", "-l800", "-f440", "-n", "-l400", "-f659", "-n", "-l200", "-f493", "-n", "-l200", "-f523", "-n", "-l200", "-f587", "-n", "-l100", "-f659", "-n", "-l100", "-f587", "-n", "-l200", "-f523", "-n", "-l200", "-f493", "-n", "-l400", "-f440", "-n", "-l200", "-f440", "-n", "-l200", "-f523", "-n", "-l400", "-f659", "-n", "-l200", "-f587", "-n", "-l200", "-f523", "-n", "-l200", "-f493", "-n", "-l200", "-f329", "-n", "-l200", "-f415", "-n", "-l200", "-f523", "-n", "-l400", "-f587", "-n", "-l400", "-f659", "-n", "-l400", "-f523", "-n", "-l400", "-f440", "-n", "-l400", "-f440", "-n", "-l200", "-f246", "-n", "-l200", "-f261", "-n", "-l600", "-f587", "-n", "-l200", "-f698", "-n", "-l200", "-f880", "-n", "-l100", "-f880", "-n", "-l100", "-f880", "-n", "-l200", "-f783", "-n", "-l200", "-f698", "-n", "-l400", "-f659", "-n", "-l200", "-f659", "-n", "-l200", "-f523", "-n", "-l200", "-f659", "-n", "-l100", "-f698", "-n", "-l100", "-f659", "-n", "-l200", "-f587", "-n", "-l200", "-f523", "-n", "-l200", "-f493", "-n", "-l200", "-f329", "-n", "-l200", "-f415", "-n", "-l200", "-f523", "-n", "-l400", "-f587", "-n", "-l400", "-f659", "-n", "-l400", "-f523", "-n", "-l400", "-f440", "-n", "-l800", "-f440", "-n", "-l800", "-f329", "-n", "-l800", "-f261", "-n", "-l800", "-f293", "-n", "-l800", "-f246", "-n", "-l800", "-f261", "-n", "-l800", "-f220", "-n", "-l800", "-f207", "-n", "-l200", "-f246", "-n", "-l200", "-f164", "-n", "-l200", "-f207", "-n", "-l200", "-f246", "-n", "-l800", "-f329", "-n", "-l800", "-f261", "-n", "-l800", "-f293", "-n", "-l800", "-f246", "-n", "-l400", "-f261", "-n", "-l400", "-f329", "-n", "-l400", "-f440", "-n", "-l400", "-f440", "-n", "-l1600", "-f415"]) + except FileNotFoundError: + pass + else: + scheduler.repeat("music", 0.02, self.repeat) + + def repeat(self): + if self.process: + if self.process.poll() is not None: + self.play() + else: + scheduler.cancel("music") + def stop(self): if self.process: - for proc in psutil.Process(self.process.pid).children(recursive=True): - proc.terminate() self.process.terminate() self.process = None + scheduler.cancel("music") class Game: @@ -612,12 +624,12 @@ class Game: curses.start_color() if curses.can_change_color(): curses.init_color(curses.COLOR_YELLOW, 1000, 500, 0) - for tetromino_class in self.TETROMINOES: - curses.init_pair(tetromino_class.COLOR, tetromino_class.COLOR, curses.COLOR_WHITE) - if tetromino_class.COLOR == curses.COLOR_ORANGE: - tetromino_class.color_pair = curses.color_pair(curses.COLOR_YELLOW) + for tetromino in self.TETROMINOES: + curses.init_pair(tetromino.COLOR, tetromino.COLOR, curses.COLOR_WHITE) + if tetromino.COLOR == curses.COLOR_ORANGE: + tetromino.color_pair = curses.color_pair(curses.COLOR_YELLOW) else: - tetromino_class.color_pair = curses.color_pair(tetromino_class.COLOR)|curses.A_BOLD + tetromino.color_pair = curses.color_pair(tetromino.COLOR) | curses.A_BOLD try: curses.curs_set(0) except curses.error: @@ -728,30 +740,27 @@ class Game: def over(self): self.stats.time = time.time() - self.stats.time - self.matrix.refresh() if curses.has_colors(): - for tetromino_class in self.TETROMINOES: - curses.init_pair(tetromino_class.COLOR, tetromino_class.COLOR, curses.COLOR_BLACK) - for y, word in enumerate((("GA", "ME") ,("OV", "ER")), start=Matrix.NB_LINES//2): - for x, syllable in enumerate(word, start=Matrix.NB_COLS//2-1): + for tetromino in self.TETROMINOES: + curses.init_pair(tetromino.COLOR, tetromino.COLOR, curses.COLOR_BLACK if tetromino.COLOR == curses.COLOR_YELLOW else curses.COLOR_WHITE) + for y, word in enumerate((("GA", "ME") ,("OV", "ER")), start=Matrix.NB_LINES // 2): + for x, syllable in enumerate(word, start=Matrix.NB_COLS//2 - 1): color = self.matrix.cells[y][x] - if color is None: - color = curses.COLOR_BLACK - else: - color |= curses.A_REVERSE - self.matrix.window.addstr(y, x*2+1, syllable, color) + self.matrix.window.addstr(y, 2*x + 1, syllable, (color | curses.A_REVERSE) if color else curses.COLOR_BLACK) self.matrix.window.refresh() curses.beep() self.scr.timeout(-1) + self.music.stop() + while self.scr.getkey() != self.controls["QUIT"]: pass - self.stats.time = time.time() - self.stats.time + self.quit() def quit(self): self.stats.save() - t = time.localtime(time.time() - self.stats.time) self.music.stop() + t = time.localtime(time.time() - self.stats.time) sys.exit( "SCORE\t{:n}\n".format(self.stats.score) + "HIGH\t{:n}\n".format(self.stats.high_score) +