예제 #1
0
class Game:
    LEDS = None

    SWITCHES = None

    COUNTDOWN = None

    GAME_TIME = None

    FINISH_TIME = 0

    RAND = -1
    RANDS = []

    BUTTONS_STATE = False
    BUTTONS_PRESSED = []

    GAMEOVER = False

    BUTTON_ACTION_ALL = 'all'
    BUTTON_ACTION_SNAKE = 'snake'

    LEVEL = 1

    SCORE_INCREMENT = None

    gpio = None
    lcd = None
    db = None

    def __init__(self, leds, switches, countdown, game_time, score_increment):
        self.LEDS = leds
        self.SWITCHES = switches
        self.COUNTDOWN = countdown
        self.GAME_TIME = game_time
        self.SCORE_INCREMENT = score_increment

        self.gpio = Gpio
        self.lcd = Lcd()
        self.db = TinyDB('data/database.json')

        if len(self.LEDS) != len(self.SWITCHES):
            print(
                "[Game][error] There isn't the same number of LEDS as SWITCHES"
            )
            exit()

        try:
            self.gpio.setmode(self.gpio.BCM)

            for switch in self.SWITCHES:
                self.gpio.setup(switch, self.gpio.IN)
                self.gpio.add_event_detect(switch,
                                           self.gpio.RISING,
                                           bouncetime=300)
                self.gpio.add_event_callback(switch, self.__button_press)

            for led in self.LEDS:
                self.gpio.setup(led, self.gpio.OUT)
                self.gpio.output(led, False)
        except AttributeError:
            print("[Game][error] An error occurred initialising game")

    def start(self, run_once=False):
        print("[Game][info] Starting game")

        self.lcd.print("Press lit button", self.lcd.LINE_1)
        self.lcd.print("to start", self.lcd.LINE_2)

        try:
            self.gpio.output(self.LEDS[2], True)

            while self.gpio.input(self.SWITCHES[2]) == self.gpio.LOW:
                time.sleep(0.01)

            for led in self.LEDS:
                self.gpio.output(led, True)
        except AttributeError:
            print("[Game][error] An error occurred starting game")

        self.__countdown()
        self.__loop()
        self.finish()

        if run_once is not True:
            self.start()

    def __countdown(self):
        print("[Game][info] Starting game countdown")

        try:
            self.lcd.clear()

            for i in range(self.COUNTDOWN, -1, -1):
                if i == 0:
                    self.lcd.print("Go Go Go!", self.lcd.LINE_1)
                elif i == self.COUNTDOWN:
                    self.lcd.print("Starting in %d!" % i, self.lcd.LINE_1)
                else:
                    self.lcd.print("%d!" % i, self.lcd.LINE_1)

                time.sleep(1)

                self.gpio.output(self.LEDS[(i - 1)], False)

            self.lcd.clear()
        except AttributeError:
            print("[Game][error] An error occurred starting game countdown")

    def __loop(self):
        print("[Game][info] Starting game loop")

        self.FINISH_TIME = time.time() + (self.GAME_TIME + 1)

        try:
            while time.time() < self.FINISH_TIME and self.GAMEOVER is not True:
                print("[Game][info] Game loop iteration")

                self.BUTTONS_STATE = False
                self.BUTTONS_PRESSED = []

                for i in range(self.LEVEL):
                    self.print_information("Repeat following")

                    if len(self.RANDS) >= (i + 1):
                        self.RAND = self.SWITCHES.index(self.RANDS[i])
                    else:
                        self.RAND = random.randint(0, (len(self.LEDS) - 1))
                        self.RANDS.append(self.SWITCHES[self.RAND])

                    print("[Game][info] Activating button: %s" %
                          (self.SWITCHES[self.RAND]))

                    self.gpio.output(self.LEDS[self.RAND], True)
                    time.sleep(0.5)
                    self.gpio.output(self.LEDS[self.RAND], False)

                start = time.time()

                print("[Game][info] Waiting for button press")

                while len(self.BUTTONS_PRESSED) < self.LEVEL:
                    self.print_information()

                    if time.time() >= self.FINISH_TIME:
                        break

                end = time.time()
                time_taken = end - start

                time.sleep(0.5)

                print("[Game][info] Button presses time taken: %f" %
                      time_taken)

                if time.time() < self.FINISH_TIME:
                    if self.BUTTONS_STATE is True:
                        print("[Game][info] Level increased by %d" % 1)

                        self.LEVEL += 1
                    else:
                        self.GAMEOVER = True
        except AttributeError:
            print("[Game][error] An error occurred during game loop")

    def __button_press(self, channel):
        print("[Game][info] Button pressed: %d" % channel)

        if len(self.RANDS) == 0:
            return

        self.BUTTONS_PRESSED.append(channel)

        if len(self.BUTTONS_PRESSED) <= len(
                self.RANDS) and channel == self.RANDS[(
                    len(self.BUTTONS_PRESSED) - 1)]:
            self.BUTTONS_STATE = True
        else:
            self.BUTTONS_STATE = False

    def get_score(self):
        print("[Game][info] Calculating score")

        level = self.LEVEL - 1

        if level < 1:
            return 0

        return (level * (level + 1) / level) * self.SCORE_INCREMENT

    def print_information(self, message=None):
        print("[Game][info] Printing information")

        score = self.get_score()
        remaining = int(self.FINISH_TIME - time.time())

        try:
            self.lcd.print("Remaining: %ds" % remaining, self.lcd.LINE_1)

            if message is None:
                self.lcd.print("Score: %d" % score, self.lcd.LINE_2)
            else:
                self.lcd.print(message, self.lcd.LINE_2)
        except AttributeError:
            print("[Game][error] An error occurred printing information")

    def print_score(self, high_score=False):
        print("[Game][info] Printing score")

        score = self.get_score()

        try:
            if high_score:
                self.lcd.print("High score: %d!" % self.get_score(),
                               self.lcd.LINE_1)
                self.flash_buttons(self.BUTTON_ACTION_ALL)
                time.sleep(3)
            else:
                self.lcd.print("Your score: %d" % score, self.lcd.LINE_1)
                time.sleep(3)
        except AttributeError:
            print("[Game][error] An error occurred printing score")

    def flash_buttons(self, action):
        print("[Game][info] Flashing buttons '%s'" % action)

        try:
            if action == self.BUTTON_ACTION_SNAKE:
                for x in range(0, 4):
                    for y in range(0, len(self.LEDS)):
                        self.gpio.output(self.LEDS[y], True)
                        time.sleep(0.2)
                        self.gpio.output(self.LEDS[y], False)
            elif action == self.BUTTON_ACTION_ALL:
                for x in range(0, 4):
                    for y in range(0, len(self.LEDS)):
                        self.gpio.output(self.LEDS[y], True)

                    time.sleep(0.2)

                    for y in range(0, len(self.LEDS)):
                        self.gpio.output(self.LEDS[y], False)

                    time.sleep(0.2)
        except AttributeError:
            print("[Game][error] An error occurred flashing buttons")

    def finish(self):
        print("[Game][info] Finishing game")

        score = self.get_score()

        self.lcd.clear()

        if self.db.contains(Query().score >= score):
            self.print_score()
        else:
            self.print_score(True)

        self.db.insert({'score': score})
        self.reset()

    def reset(self):
        print("[Game][info] Resetting game")

        self.GAMEOVER = False
        self.RAND = -1
        self.RANDS = []
        self.LEVEL = 1
        self.FINISH_TIME = 0
        self.BUTTONS_STATE = False
        self.BUTTONS_PRESSED = []
        self.flash_buttons(self.BUTTON_ACTION_SNAKE)
        self.lcd.clear()

    def cleanup(self):
        print("[Lcd][info] Game clean up")

        try:
            self.gpio.cleanup()
            self.lcd.cleanup()
        except AttributeError:
            print("[Game][error] An error occurred cleaning up")

    def __exit__(self):
        print("[Game][info] Game exit")

        self.cleanup()