class Team(Resource):
    db = Database()

    def get(self):
        return {"status": logic.team}

    def put(self, name):
        logic.team = name
        return {"status": logic.team}
class HighScores(Resource):
    db = Database()

    def get(self):
        scores = self.db.get_rows(success=True)
        scores.sort(key=lambda x: x.time, reverse=False)
        return {
            "team{}".format(i + 1): {
                "name": "{}".format(row.name),
                "time": "{}".format(row.time)
            }
            for i, row in enumerate(scores)
        }
Exemple #3
0
class Logic:
    bus_num = 1
    db = Database()
    shared = Manager().dict()
    scheduler = None
    lasers = None
    _comQueue = Queue()
    _process = Lock()
    _solenoid = SOLENOID_STATE.UNLOCKED
    _ultrasonic = ULTRASONIC_STATE.ENABLED
    _laserState = LaserPattern.LASER_OFF
    _laserCounter = 0
    _patternIndex = 0
    _laserValue = 0x00

    def __init__(self):
        self.laserPattern = LaserPattern.ONE_CYCLES
        self._timer = 0
        self._patternIndex = 0

        # Initialize ICc Devices
        self._bus = SMBus(self.bus_num)
        self.lasers = LaserControl(self._bus)
        self.arduino = SevenSeg(self._bus)
        self.photo_resistors = ReceptorControl(self._bus)

    @property
    def patternIndex(self) -> int:
        return self._patternIndex

    @patternIndex.setter
    def patternIndex(self, value: int):
        self._patternIndex = value

    @property
    def laserCounter(self) -> int:
        return self._laserCounter

    @laserCounter.setter
    def laserCounter(self, value: int):
        self._laserCounter = value

    def laserCounterIncrement(self):
        self.laserCounter = self.laserCounter + 1

    @property
    def laserState(self) -> LaserPattern:
        return LaserPattern(
            self.shared.get("laserpattern", LaserPattern.LASER_OFF.value))

    @laserState.setter
    def laserState(self, value: LaserPattern):
        self.shared["laserpattern"] = value.value

    @property
    def laserValue(self) -> int:
        return self.shared.get("laservalue", 0x00)

    @laserValue.setter
    def laserValue(self, value: int):
        self.shared["laservalue"] = value

    @property
    def timer_text(self) -> str:
        newDatetime = datetime.now() - self.start_time
        seconds = MAX_TIME - newDatetime.seconds
        minutes = seconds // 60
        secondsToPrint = seconds - minutes * 60
        if self.state is STATE.WAIT:
            return "RESET"
        if self.state is STATE.RUNNING:
            if minutes < 0 or seconds < 0:
                ComQueue().getComQueue().put([INTERRUPT.KILL_PLAYER])
                return "DEAD"
        elif self.state is STATE.EXPLODE:
            return "DEAD"
        elif self.state is STATE.WIN:
            return "SUCCESS!"
        return "{}:{:2}".format(minutes, str(secondsToPrint).zfill(2))

    @property
    def start_time(self) -> datetime:
        return self.shared.get("start time", datetime.now())

    @start_time.setter
    def start_time(self, value: datetime):
        self.shared["start time"] = value

    @property
    def ultrasonic(self) -> ULTRASONIC_STATE:
        return ULTRASONIC_STATE(
            self.shared.get("ultrasonic", ULTRASONIC_STATE.ENABLED.value))

    @ultrasonic.setter
    def ultrasonic(self, value: ULTRASONIC_STATE):
        # TODO send the new ultrasonic logic over I2C
        log.debug("Ultrasonic logic changed from {} to {}".format(
            self.ultrasonic.value, value.value))
        self.shared["ultrasonic"] = value.value

    @property
    def comQueue(self) -> Queue:
        return self._comQueue

    @comQueue.setter
    def comQueue(self, value):
        log.debug("Queue was created")
        self._comQueue = value

    @property
    def solenoid(self) -> SOLENOID_STATE:
        return SOLENOID_STATE(
            self.shared.get("solenoid", SOLENOID_STATE.UNLOCKED.value))

    @solenoid.setter
    def solenoid(self, value: SOLENOID_STATE):
        # TODO send the new solenoid logic over I2C
        log.debug("Solenoid logic changed from {} to {}".format(
            self.solenoid.value, value.value))
        self.shared["solenoid"] = value.value

    @property
    def state(self):
        return STATE(self.shared.get("logic", STATE.WAIT.value))

    @state.setter
    def state(self, value: STATE):
        log.debug("State changed from {} to {}".format(self.state.value,
                                                       value.value))
        self.shared["logic"] = value.value

    @property
    def keypad_code(self) -> hex:
        return self.shared.get("code", 0x000)

    @keypad_code.setter
    def keypad_code(self, value: hex):
        assert 0x0 <= value <= 0xfff
        log.debug("Setting new keypad code: 0x{}".format(value))
        self.shared["code"] = value

    @property
    def team(self) -> str:
        return self.shared.get(
            "team", self.db.last.name if self.db.get_rows() else "--")

    @team.setter
    def team(self, value: str):
        log.debug("Setting current team name to: {}".format(value))
        self.shared["team"] = value
        if self.db.get_rows():
            self.db.last = Row(name=value)

    @property
    def rgb_color(self) -> RGBColor:
        return RGBColor(self.shared.get("rgb", RGBColor.BLANK.value))

    @rgb_color.setter
    def rgb_color(self, value: RGBColor):
        log.debug("Setting new rgb color: {}".format(value))
        # TODO send the command over i2c to change the rgb color
        self.shared["rgb"] = value.value

    def run(self, queue: Queue, mock: bool):
        """
        Start the game and make sure there is only a single instance of this process
        This is the setup function, when it is done, it will start the game loop
        """
        with self._process:
            # Initialize I2C server
            self.state = STATE.WAIT  # Change logic of game to WAIT
            self.solenoid = SOLENOID_STATE.LOCKED
            self.comQueue = queue
            self.ultrasonic = ULTRASONIC_STATE.ENABLED
            self.laserPattern = LaserPattern.ONE_CYCLES
            self.scheduler = APScheduler(scheduler=BackgroundScheduler(),
                                         app=current_app)
            self.scheduler.add_job("loop",
                                   self._loop,
                                   trigger='interval',
                                   seconds=1,
                                   max_instances=1,
                                   replace_existing=False)
            self.scheduler.start()

            # TODO start thread polling sensors
            try:
                while True:
                    self.poll_sensors()
            except KeyboardInterrupt:
                return

    def poll_sensors(self):
        """
        Poll all of the sensors and raise a flag if one of them has tripped.
        If the right wire was clipped at the end of the puzzle, raise the win flag
        """
        """
        for i in I2C:
            word = self._bus.read_byte_data(self.bus_num, i)
            if word is not None:
                # log.info("{}: {}".format(i.name, hex(word)))
                if i is I2C.RESET:
                    ComQueue().getComQueue().put([INTERRUPT.TOGGLE_TIMER])
                elif i is I2C.LASERS:
                    if self.laserValue != word:
                        ComQueue().getComQueue().put([INTERRUPT.KILL_PLAYER])
        """

        # self._bus.write_byte_data(I2C.LASERS.value, 0, 9) # for i2c in I2C:
        #     log.debug("Reading from I2C on {}".format(i2c.name))
        #     foo = self._bus.read_word_data(i2c.value, 0)
        #     self._send(I2C.SEVEN_SEG, "Hello!")

    def getNextLaserPatternList(self):
        if self.laserState is LaserPattern.ONE_CYCLES:
            return LaserPattern.TWO_CYCLES
        elif self.laserState is LaserPattern.TWO_CYCLES:
            return LaserPattern.UP_AND_DOWN
        elif self.laserState is LaserPattern.UP_AND_DOWN:
            return LaserPattern.INVERSION
        elif self.laserState is LaserPattern.INVERSION:
            return LaserPattern.LASER_OFF
        else:
            return self.laserState

    def getLaserPattern(self):
        if self.laserState is LaserPattern.ONE_CYCLES:
            pattern = LaserPatternValues.ONE_CYCLES.value
        elif self.laserState is LaserPattern.TWO_CYCLES:
            pattern = LaserPatternValues.TWO_CYCLES.value
        elif self.laserState is LaserPattern.UP_AND_DOWN:
            pattern = LaserPatternValues.UP_AND_DOWN.value
        elif self.laserState is LaserPattern.INVERSION:
            pattern = LaserPatternValues.INVERSION.value
        elif self.laserState is LaserPattern.LASER_OFF:
            pattern = LaserPatternValues.LASER_OFF.value
        elif self.laserState is LaserPattern.RANDOM:
            pattern = LaserPatternValues.RANDOM.value
        elif self.laserState is LaserPattern.STATIC:
            return self.laserValue
        else:
            pattern = None

        # Increment the patternIndex
        if pattern is not None:
            if self.patternIndex < len(pattern):
                retValue = pattern[self.patternIndex]
                self.patternIndex += 1
            else:
                self.patternIndex = 0
                retValue = pattern[self.patternIndex]

            if retValue == 0xFF:
                return random.randint(0, 0x3F)
            else:
                return retValue
        else:
            # All lasers turn
            return 0x3F

    def updateLaserPattern(self):
        if self.laserCounter < SECONDS_PER_PATTERN:
            self.laserCounterIncrement()
        else:
            self.laserState = self.getNextLaserPatternList()
            self.patternIndex = 0  # So that we start at the beginning
            self.laserCounter = 0

        # Time per element of pattern
        self.laserValue = self.getLaserPattern()

        # Set laser pattern
        setVar = 0
        while setVar < NUMBER_OF_LASERS:
            self.lasers.state[setVar] = self.laserValue & (1 << setVar)
            setVar += 1
        self.lasers.update()

    def _loop(self):
        command_id = None
        if not self.comQueue.empty():
            command = self.comQueue.get()
            command_id = command[0]

        # State Actions
        if self.state is STATE.WAIT:
            self.laserState = LaserPattern.LASER_OFF
        elif self.state is STATE.RUNNING:
            self.updateLaserPattern()
        elif self.state is STATE.EXPLODE:
            pass
            # TODO randomize laser pattern so that they flash
        elif self.state is STATE.WIN:
            pass
        else:
            log.error("Reached an unknown state: {}".format(self.state))

        # State Transitions
        if self.state is STATE.WAIT:
            if command_id is INTERRUPT.TOGGLE_TIMER:
                # TODO? Verify that the box is reset before starting the game
                self.state = STATE.RUNNING
                self.start_game()
        elif self.state is STATE.RUNNING:
            if command_id is INTERRUPT.RESET_GAME or command_id is INTERRUPT.TOGGLE_TIMER:
                self.state = STATE.WAIT
                # FIXME? Delete last row on reset
                self.end_game(success=False)
            elif command_id is INTERRUPT.KILL_PLAYER:
                self.state = STATE.EXPLODE
                self.end_game(success=False)
            elif command_id is INTERRUPT.DEFUSED:
                self.state = STATE.WIN
                self.end_game(success=True)
        elif self.state is STATE.EXPLODE:
            if command_id is INTERRUPT.RESET_GAME or command_id is INTERRUPT.TOGGLE_TIMER:
                self.state = STATE.WAIT
        elif self.state is STATE.WIN:
            if command_id is INTERRUPT.RESET_GAME or command_id is INTERRUPT.TOGGLE_TIMER:
                self.state = STATE.WAIT

    def _send(self, device: I2C, message: str):
        """
        Send a command to a device over I2c.  Nothing external should call this, only "loop"
        :param device:
        :param message:
        :return:
        """
        assert len(message) < 32
        log.debug("Address: 0x{:02x}  Message: '{}'".format(
            device.value, message))
        try:
            self._bus.write_i2c_block_data(device.value, 0x00,
                                           [ord(c) for c in message])
        except IOError:
            pass

    @staticmethod
    def random_laser_pattern() -> int:
        # TODO make sure the laser pattern conforms to certain rules
        return random.randint(0, 0x3f)

    def start_game(self):
        """
        Add a row to the database, generate random data for all the puzzles
        """
        self.solenoid = SOLENOID_STATE.LOCKED
        self.start_time = datetime.now()
        self.keypad_code = random.randint(0, 0xfff)
        self.rgb_color = random.choice([RGBColor.RED, RGBColor.BLUE])
        self.laserState = LaserPattern.ONE_CYCLES
        row = Row(
            name=self.team,
            lasers=self.laserValue,
            code=self.keypad_code,
            success=False,
            time=MAX_TIME,
            color=self.rgb_color.value,
        )
        log.debug("Adding new row to the database:\n{}".format(row))
        self.db.add_row(row)

    def end_game(self, success: bool = False):
        log.debug("Game Over")
        self.db.last = Row(name=self.team,
                           code=self.keypad_code,
                           lasers=self.laserValue,
                           success=success,
                           time=(datetime.now() - self.start_time).seconds)
Exemple #4
0
 def __init__(self, bot):
     self.bot = bot
     self.user_tag = dict()
     self.db = Database()  # it's the right place?
Exemple #5
0
admin = Blueprint('admin', __name__, url_prefix='/admin')
base = Blueprint('base', __name__)


@admin.route('/', methods=['GET'])
def admin_view():
    return render_template("admin.html")


@base.route('/', methods=['GET'])
def base_view():
    return render_template("index.html")


# TODO 404 not found and other error pages

@base.route('/favicon.ico', methods=['GET'])
def favicon():
    return url_for('static', filename='favicon.ico')


@base.route('/credits', methods=['GET'])
def credits_view():
    return render_template("credits.html")


app.db = Database()
app.register_blueprint(admin)
app.register_blueprint(base)
app.register_blueprint(resource)
class Successes(Resource):
    db = Database()

    def get(self):
        return {"successes": len(self.db.get_rows(success=True))}
class Attempts(Resource):
    db = Database()

    def get(self):
        return {"attempts": len(self.db.get_rows())}
Exemple #8
0
class Logic:
    bus_num = 1
    db = Database()
    shared = Manager().dict()
    scheduler = None
    lasers = None
    _comQueue = Queue()
    _process = Lock()
    _solenoid = SOLENOID_STATE.UNLOCKED
    _ultrasonic = ULTRASONIC_STATE.ENABLED
    _laserState = LaserPattern.LASER_OFF
    _laserCounter = 0
    _patternIndex = 0
    _laserValue = 0x00
    _command = None

    def __init__(self):
        self.laserPattern = LaserPattern.ONE_CYCLES
        self._timer = 0
        self._patternIndex = 0

        # Initialize ICc Devices
        self._bus = SMBus(self.bus_num)
        self.lasers = LaserControl(self._bus, I2C.LASERS)
        self.sevenseg = SevenSeg(self._bus, I2C.SEVENSEG).sevenseg
        self.arduino = ArduinoI2C(self._bus, I2C.ARDUINO)
        self.photo_resistors = ReceptorControl(self._bus, I2C.PHOTO_RESISTORS)
        self.lock = BoxLock(self._bus, I2C.SOLENOID)
        self.switches = SwitchesI2C(self._bus, I2C.SWITCHES)

    @property
    def patternIndex(self) -> int:
        return self._patternIndex

    @patternIndex.setter
    def patternIndex(self, value: int):
        self._patternIndex = value

    @property
    def laserCounter(self) -> int:
        return self._laserCounter

    @laserCounter.setter
    def laserCounter(self, value: int):
        self._laserCounter = value

    def laserCounterIncrement(self):
        self.laserCounter = self.laserCounter + 1

    @property
    def laserState(self) -> LaserPattern:
        return LaserPattern(self.shared.get("laserpattern", LaserPattern.LASER_OFF.value))

    @laserState.setter
    def laserState(self, value: LaserPattern):
        self.shared["laserpattern"] = value.value

    @property
    def laserValue(self) -> int:
        return self.shared.get("laservalue", 0x00)

    @laserValue.setter
    def laserValue(self, value: int):
        self.shared["laservalue"] = value

    @property
    def command(self):
        return self.shared.get("command", None)

    @command.setter
    def command(self, value: str):
        self.shared["command"] = value

    def timer_values(self) -> Tuple[int, int, int]:
        newDatetime = datetime.now() - self.start_time
        seconds = MAX_TIME - newDatetime.seconds
        minutes = seconds // 60
        secondsToPrint = seconds - minutes * 60
        return minutes, secondsToPrint, seconds

    @property
    def timer_text(self) -> str:
        minutes, secondsToPrint, seconds = self.timer_values()
        if self.state is STATE.WAIT:
            return "RESET"
        if self.state is STATE.RUNNING:
            if minutes < 0 or seconds < 0:
                self.shared[INTERRUPT.KILL_PLAYER] = True
                return "DEAD"
        elif self.state is STATE.EXPLODE:
            return "DEAD"
        elif self.state is STATE.WIN:
            return "SUCCESS!"
        return "{}:{:2}".format(minutes, str(secondsToPrint).zfill(2))

    @property
    def start_time(self) -> datetime:
        return self.shared.get("start time", datetime.now())

    @start_time.setter
    def start_time(self, value: datetime):
        self.shared["start time"] = value

    @property
    def ultrasonic(self) -> ULTRASONIC_STATE:
        return ULTRASONIC_STATE(self.shared.get("ultrasonic", ULTRASONIC_STATE.ENABLED.value))

    @ultrasonic.setter
    def ultrasonic(self, value: ULTRASONIC_STATE):
        # TODO send the new ultrasonic logic over I2C
        log.debug("Ultrasonic logic changed from {} to {}".format(self.ultrasonic.value, value.value))
        self.shared["ultrasonic"] = value.value

    @property
    def comQueue(self) -> Queue:
        return self._comQueue

    @comQueue.setter
    def comQueue(self, value):
        log.debug("Queue was created")
        self._comQueue = value

    @property
    def solenoid(self) -> SOLENOID_STATE:
        return SOLENOID_STATE(self.shared.get("solenoid", SOLENOID_STATE.UNLOCKED.value))

    @solenoid.setter
    def solenoid(self, value: SOLENOID_STATE):
        # send the new solenoid logic over I2C
        if value is SOLENOID_STATE.UNLOCKED:
            self.lock.open()
        else:
            self.lock.close()
        log.debug("Solenoid logic changed from {} to {}".format(self.solenoid.value, value.value))
        self.shared["solenoid"] = value.value

    @property
    def state(self):
        return STATE(self.shared.get("logic", STATE.WAIT.value))

    @state.setter
    def state(self, value: STATE):
        log.debug("State changed from {} to {}".format(self.state.value, value.value))
        self.shared["logic"] = value.value

    @property
    def entered_code(self) -> hex:
        return self.shared.get("enteredcode", 0xFFF)

    @entered_code.setter
    def entered_code(self, value: hex):
        assert 0x0 <= value <= 0xfff
        log.debug("Setting new entered code: 0x{}".format(value))
        self.shared["enteredcode"] = value

    @property
    def keypad_code(self) -> hex:
        return self.shared.get("code", 0x000)

    @keypad_code.setter
    def keypad_code(self, value: hex):
        assert 0x0 <= value <= 0xfff
        log.debug("Setting new keypad code: 0x{}".format(value))
        self.shared["code"] = value

    @property
    def team(self) -> str:
        return self.shared.get("team", self.db.last.name if self.db.get_rows() else "--")

    @team.setter
    def team(self, value: str):
        log.debug("Setting current team name to: {}".format(value))
        self.shared["team"] = value
        if self.db.get_rows():
            self.db.last = Row(name=value)

    @property
    def rgb_color(self) -> RGBColor:
        return RGBColor(self.shared.get("rgb", RGBColor.BLANK.value))

    @rgb_color.setter
    def rgb_color(self, value: RGBColor):
        log.debug("Setting new rgb color: {}".format(value))
        # send the command over i2c to change the rgb color
        color_map = {'green': 0x1c, 'red': 0xe0, 'blue': 0x03, 'black': 0x00}
        self.arduino.color = color_map[value.value]
        self.shared["rgb"] = value.value

    def run(self, queue: Queue):
        """
        Start the game and make sure there is only a single instance of this process
        This is the setup function, when it is done, it will start the game loop
        """
        with self._process:
            # Initialize I2C server
            self.state = STATE.WAIT  # Change logic of game to WAIT
            self.solenoid = SOLENOID_STATE.LOCKED
            self.comQueue = queue
            self.ultrasonic = ULTRASONIC_STATE.ENABLED
            self.laserPattern = LaserPattern.ONE_CYCLES
            self.scheduler = APScheduler(scheduler=BackgroundScheduler(), app=current_app)
            self.scheduler.add_job("loop", self._loop, trigger='interval', seconds=1, max_instances=1,
                                   replace_existing=False)
            self.scheduler.start()

            # TODO start thread polling sensors
            try:
                while True:
                    self.poll_sensors()
            except KeyboardInterrupt:
                return

    # Commented out because we are doing it in other functions
    def poll_sensors(self):
        """
        Poll all of the sensors and raise a flag if one of them has tripped.
        If the right wire was clipped at the end of the puzzle, raise the win flag
        """
        pass

        # self._bus.write_byte_data(I2C.LASERS.value, 0, 9) # for i2c in I2C:
        #     log.debug("Reading from Project_Theseus_API.i2c on {}".format(i2c.name))
        #     foo = self._bus.read_word_data(i2c.value, 0)
        #     self._send(I2C.SEVEN_SEG, "Hello!")

    def getNextLaserPatternList(self):
        if self.laserState is LaserPattern.ONE_CYCLES:
            return LaserPattern.TWO_CYCLES
        elif self.laserState is LaserPattern.TWO_CYCLES:
            return LaserPattern.UP_AND_DOWN
        elif self.laserState is LaserPattern.UP_AND_DOWN:
            return LaserPattern.INVERSION
        elif self.laserState is LaserPattern.INVERSION:
            return LaserPattern.LASER_OFF
        else:
            return self.laserState

    def getLaserPattern(self):
        if self.laserState is LaserPattern.ONE_CYCLES:
            pattern = LaserPatternValues.ONE_CYCLES.value
        elif self.laserState is LaserPattern.TWO_CYCLES:
            pattern = LaserPatternValues.TWO_CYCLES.value
        elif self.laserState is LaserPattern.UP_AND_DOWN:
            pattern = LaserPatternValues.UP_AND_DOWN.value
        elif self.laserState is LaserPattern.INVERSION:
            pattern = LaserPatternValues.INVERSION.value
        elif self.laserState is LaserPattern.LASER_OFF:
            pattern = LaserPatternValues.LASER_OFF.value
        elif self.laserState is LaserPattern.RANDOM:
            pattern = LaserPatternValues.RANDOM.value
        elif self.laserState is LaserPattern.STATIC:
            return self.laserValue
        else:
            pattern = None

        # Increment the patternIndex
        if pattern is not None:
            if self.patternIndex < len(pattern):
                retValue = pattern[self.patternIndex]
                self.patternIndex += 1
            else:
                self.patternIndex = 0
                retValue = pattern[self.patternIndex]

            if retValue == 0xFF:
                return random.randint(0, 0x3F)
            else:
                return retValue
        else:
            # All lasers turn
            return 0x3F

    def updateLaserPattern(self):
        if self.laserCounter < SECONDS_PER_PATTERN:
            self.laserCounterIncrement()
        else:
            self.laserState = self.getNextLaserPatternList()
            self.patternIndex = 0  # So that we start at the beginning
            self.laserCounter = 0

        # Time per element of pattern
        self.laserValue = self.getLaserPattern()

        # Set laser pattern
        self.lasers.state = self.laserValue

    def checkCode(self):
        """
        Need to verify that the code they entered was correct.

        Verifies against the current keycode
        """
        # Get the last entered key
        key = self.arduino.keypad
        # The key should be a single hex character between 0 and 9
        # The entered_code variable stores the 3 numbers they have entered
        # If they enter a fourth number they die
        # Start Game initializes it to 0xFFF so we check that it isn't F
        # to see if a number has been previously entered
        str_keypad_code = "{:2X}".format(self.keypad_code)
        str_entered_code = "{:2X}".format(self.entered_code)

        # Iterate through characters and verify
        for i in range(0, 3):
            # Add latest key to entered code
            if str_entered_code[i] == "F":
                if key != None:
                    # We need to fill this space
                    str_entered_code[i] = key
                    # Save in the shared dict
                    self.entered_code = int(str_entered_code)

                    # Now we need to check if it matches
                    if str_entered_code[i] != str_keypad_code[i]:
                        return False
                    else:
                        # The key matched so far, continue
                        pass
                else:
                    # Key was none, don't update entered and don't check
                    pass

            else:
                # entered code is not F, so we need to see if it matches
                # admitedly this shouldn't be called because of how we check
                if str_entered_code[i] != str_keypad_code[i]:
                    return False

        # We are assuming it has matched so far, but if they have entered another key,
        # it no longer does, and they should fail
        if key != None:
            return False
        else:
            # They didn't type a key, so they lived and won
            # They didn't exceed the code size
            # TODO: Add additional code for more logic later, this will
            # make them win right now
            self.state = STATE.WIN
            self.end_game(success=True)
        # If you reached here, the codes matched so far, so return True
        return True

    def updateLed(self):
        """
        There are 6 switches on the box. The four black correspond to a number
        in hex, and the 2 white help you know which number in the keypad_code
        you are looking at. The light will be RED if the white switches are 0
        or the current code is wrong, and GREEN if the corresponding number from
        keypad_code is correct.
        """
        # TODO: Verify that my understanding of how the switches are organized
        # as far as the number they return is correct

        # Determined by the white switches. 0 corresponds to none of the numbers
        # and 1, 2, and 3 respectively correspond to the 1, 2, and 3 numbers in
        # keypad_code
        keypad_code_index = self.switches.read_switches()[-2:]
        # What number does the user want to test?
        test_number = self.switches.read_switches()[:-2]
        # Get the keypad code as a string
        str_keypad_code = "{:2X}".format(self.keypad_code)

        # set the led based on if they are correct
        if keypad_code_index > 0:
            if str_keypad_code[keypad_code_index - 1] == str(test_number):
                # It matches, make the light green
                self.rgb_color = RGBColor.GREEN
            else:
                # It doesn't match, make the light red
                self.rgb_color = RGBColor.RED
        else:
            # They haven't selected one, make it blue
            self.rgb_color = RGBColor.BLUE


    def _loop(self):
        command_id = None
        if not self.comQueue.empty():
            command = self.comQueue.get()
            command_id = command[0]
            print("\n\n\n{}\n\n\n".format(command_id))

        # State Actions
        if self.state is STATE.WAIT:
            self.sevenseg(0x0)
            self.laserState = LaserPattern.LASER_OFF
        elif self.state is STATE.RUNNING:
            # Update the seven segment display to show the correct time
            minutes, seconds, total_seconds = self.timer_values(self.sevenseg(int("0x{:02}{:02}".format(minutes, seconds), 16)))
            # Update what the current laser pattern should be
            self.updateLaserPattern()
            # Update LED by checking switches
            self.updateLed()

        elif self.state is STATE.EXPLODE:
            self.sevenseg(0xdead)
            # TODO randomize laser pattern so that they flash
        elif self.state is STATE.WIN:
            self.sevenseg(0xbeef)
        else:
            log.error("Reached an unknown state: {}".format(self.state))

        # State Transitions
        if self.state is STATE.WAIT:
            if self.command == "toggle-game":
                self.command = None
                # TODO? Verify that the box is reset before starting the game
                self.state = STATE.RUNNING
                self.start_game()
        elif self.state is STATE.RUNNING:
            minutes, seconds, total_seconds = self.timer_values()

            if self.command == "toggle-game" or self.command == "toggle-game":
                if self.command is not None:
                    self.command = None
                self.state = STATE.WAIT
                # FIXME? Delete last row on reset
                self.end_game(success=False)
            elif self.shared[INTERRUPT.KILL_PLAYER]:
                self.state = STATE.EXPLODE
                self.end_game(success=False)
            elif self.shared[INTERRUPT.DEFUSED]:
                self.state = STATE.WIN
                self.end_game(success=True)

            # Kill the player if time has run out
            elif total_seconds <= 0:
                self.state = STATE.EXPLODE
                self.end_game(success=False)

            elif self.laserValue != self.photo_resistors.read_int():
                self.state = STATE.EXPLODE
                self.end_game(success=False)

            elif not self.checkCode():
                # If they reached here the code didn't match
                self.state = STATE.EXPLODE
                self.end_game(success=False)

        elif self.state is STATE.EXPLODE:
            if self.shared[INTERRUPT.RESET_GAME] or self.shared[INTERRUPT.TOGGLE_TIMER]:
                self.state = STATE.WAIT
        elif self.state is STATE.WIN:
            if self.shared[INTERRUPT.RESET_GAME] or self.shared[INTERRUPT.TOGGLE_TIMER]:
                self.state = STATE.WAIT

    def _send(self, device: I2C, message: str):
        """
        Send a command to a device over I2c.  Nothing external should call this, only "loop"
        :param device:
        :param message:
        :return:
        """
        assert len(message) < 32
        log.debug("Address: 0x{:02x}  Message: '{}'".format(device.value, message))
        try:
            self._bus.write_i2c_block_data(device.value, 0x00, [ord(c) for c in message])
        except IOError:
            pass

    @staticmethod
    def random_laser_pattern() -> int:
        return random.randint(0, 0x40)

    def generateKeyCode() -> int:
        """
        Generate a 3 number code where all numbers are less than 9 and >= 0
        """
        # We can't go over 9 because our keypad doesn't go above 9
        return (random.randint(0, 0x9) << 8) | (random.randint(0, 0x9) << 4) | (random.randint(0, 0x9))


    def start_game(self):
        """
        Add a row to the database, generate random data for all the puzzles
        """
        self.solenoid = SOLENOID_STATE.LOCKED
        self.start_time = datetime.now()
        self.keypad_code = generateKeyCode()
        self.entered_code = 0xFFF       # Set as this because it is impossible to get on our keypad
        self.rgb_color = RGBColor.BLUE
        self.laserState = LaserPattern.ONE_CYCLES
        row = Row(
            name=self.team, lasers=self.laserValue, code=self.keypad_code, success=False, time=MAX_TIME,
            color=self.rgb_color.value,
        )
        log.debug("Adding new row to the database:\n{}".format(row))
        self.db.add_row(row)

    def end_game(self, success: bool = False):
        log.debug("Game Over")
        self.db.last = Row(
            name=self.team,
            code=self.keypad_code,
            lasers=self.laserValue,
            success=success,
            time=(datetime.now() - self.start_time).seconds
        )
Exemple #9
0
    def generate_words(self, tag):
        """Generate the word from the database

            """
        db = Database()
        listOfWord = db.get_words_by_tag(tag)
        if len(listOfWord) < self.size:
            raise NotAllowedCommand(_('error_missing_words', tag=tag))
        self.words_str = random.sample(listOfWord, self.size)
        self.red_words = random.sample(self.words_str, self.number_red)

        red_set = set(self.red_words)
        self.blue_words = random.sample(
            [x for x in self.words_str if x not in red_set], self.number_blue)

        blue_set = set(self.blue_words)
        self.assassin_words = random.sample([
            x for x in self.words_str if x not in red_set and x not in blue_set
        ], self.number_assassin)
        self.white_words = [
            x for x in self.words_str if x not in red_set and x not in blue_set
            and x not in self.assassin_words
        ]

        try:
            self.red_revealed_path = random.sample([
                f for f in glob.glob(self.images_res_path +
                                     "/red_revealed/*.png")
            ], self.number_red)
        except ValueError:
            self.red_revealed_path = glob.glob(self.images_res_path +
                                               "/red_revealed/*.png")
        try:
            self.blue_revealed_path = random.sample([
                f for f in glob.glob(self.images_res_path +
                                     "/blue_revealed/*.png")
            ], self.number_blue)
        except ValueError:
            self.blue_revealed_path = glob.glob(self.images_res_path +
                                                "/blue_revealed/*.png")
        try:
            self.assassin_revealed_path = random.sample([
                f for f in glob.glob(self.images_res_path +
                                     "/black_revealed/*.png")
            ], self.number_assassin)
        except ValueError:
            self.assassin_revealed_path = glob.glob(self.images_res_path +
                                                    "/assassin_revealed/*.png")
        try:
            self.white_revealed_path = random.sample([
                f for f in glob.glob(self.images_res_path +
                                     "/white_revealed/*.png")
            ], self.number_white)
        except ValueError:
            self.white_revealed_path = glob.glob(self.images_res_path +
                                                 "/white_revealed/*.png")

        self.revealed_counter = {
            'red': 0,
            'blue': 0,
            'white': 0,
            'assassin': 0
        }

        self.create_grid()