<commit_before>import imp
import os
import tornado.escape
import tornado.ioloop
import datetime


def load(name, path, client):
    file, pathname, description = imp.find_module(name, path)
    mod = imp.load_module(name, file, pathname, description)

    return mod.create(client)

def get_games(paths):
    games = []
    for path in paths:
        try:
            for file in os.listdir(path):
                if file.endswith(".py"):
                    games += [file.split('.')[0]]
        except FileNotFoundError:
            pass

    return games


#### Game API ###################################
# This is the API that game modules make use of (by extending the Game class
# and invoking the other functions provided here).

def send_msg(handler, msg):
    if handler != None:
        handler.write_message(tornado.escape.json_encode(msg))

def send_msgs(handlers, msg):
    for h in handlers:
        send_msg(h, msg)

def send_msgs_animation(handlers, coords, message, callback = None, revert = False):
    for i, (x,y) in enumerate(coords):
        send_msgs(handlers, dict(message, x = x, y = y, delay = i * 500, transitiontime = 10))
        if revert:
            send_msgs(handlers, dict(message, power = False, x = x, y = y, delay = i*500 + 1000, transitiontime = 10))

    if callback:
        set_timeout(datetime.timedelta(seconds = len(coords)/2 + (0.5 if revert else 0)), callback)

def reply_wrong_player(game, handler):
    if handler in game.players:
        print("Wrong player")
        send_msg(handler, {'error':'Not your turn!'})
    else:
        print("Spectator")
        send_msg(handler, {'error':'You are not a player!'})

def game_over(game, winnerH, coords = frozenset()):
    if winnerH == None:
        send_msgs(game.players,     {'state': 'gameover'})
        send_msgs(game.connections, {'message': 'The game tied'})
        print("The game tied")

    else:
        winner = game.players.index(winnerH)
        send_msg(winnerH, {'state': 'gameover', 'message': 'You won!'})
        send_msgs((p for p in game.players if p != winnerH),
                          {'state': 'gameover', 'message': 'You lost!'})
        send_msgs(game.get_spectators(), {'message': "Player %d won" % (winner + 1)})
        print("Player %d wins!" % winner)

    changes = []
    for (x,y) in coords:
        changes += [ { 'x': x, 'y': y,             'change': { 'alert': 'lselect' } },
                     { 'x': x, 'y': y, 'delay': 3, 'change': { 'alert': 'none'    } } ]
    game.send_lamp_multi(changes)

    set_timeout(datetime.timedelta(seconds = len(coords) + 3), game.reset)
  # game.reset()

def set_timeout(deadline, callback):
    """
    Runs `callback` at the time `deadline` from Tornado's I/O loop.

    Thin wrapper over Tornado's `IOLoop.add_timeout`.
    """
    ioloop = tornado.ioloop.IOLoop.instance()
    ioloop.add_timeout(deadline, callback)

def get_grid_size():
    import manager
    return (manager.grid['height'], manager.grid['width'])

def add_auth_cookie(headers):
    if light_cookie and 'user' in light_cookie:
        headers['Cookie'] = light_cookie['user'].output(attrs=[], header='')
    return headers

light_cookie = None

def rgb_to_xyz(r, g, b):
    X =  1.076450 * r - 0.237662 * g + 0.161212 * b
    Y =  0.410964 * r + 0.554342 * g + 0.034694 * b
    Z = -0.010954 * r - 0.013389 * g + 1.024343 * b

    x = X / (X + Y + Z)
    y = Y / (X + Y + Z)
    return x, y, Z

def parse_color(color):
    return int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16)

def rgb_to_hsl(r, g, b):
    # via http://en.wikipedia.org/wiki/HSL_and_HSV
    M, m = max(r,g,b), min(r,g,b)
    c = M - m

    if   c == 0: hue = 0
    elif M == r: hue = (g - b)/c * 256
    elif M == g: hue = (b - r)/c * 256 + (256 * 3)
    elif M == b: hue = (r - g)/c * 256 + (256 * 6)

    hue /= 6
    lum = M/2 + m/2
    divisor = 2 * (lum if lum < 128 else 256 - lum)
    sat = c / divisor * 256

    return (int(hue), int(sat), int(lum))


class Game:
    config_file = "defaultconfig.html"
    template_file = "default.html"
    template_vars = {
        'module_name': '<name not set>',
        'cell_w':      64,
        'cell_h':      64,
        'color_empty': "#222222",
        'color_hover': "#999999"
    }

    def __init__(self, client):
        # State variables, to be used by the game
        self.queue       = None
        self.connections = set()
        self.players     = []

        # Internal variables
        self.client      = client

        if 'grid_x' not in self.template_vars or \
           'grid_y' not in self.template_vars:
            self.template_vars['grid_x'] = get_grid_size()[1]
            self.template_vars['grid_y'] = get_grid_size()[0]

    # Internal, do not override/use
    def set_queue(self, queue):
        self.queue = queue
        queue.enqueue_callback = self.on_enqueue


    # Methods for updating the lamps
    def send_lamp_multi(self, changes):
        json    = tornado.escape.json_encode(changes)
        headers = add_auth_cookie({'Content-Type': 'application/json'})
        self.client.request("POST", "/lights", json, headers)
        # Print response
        print(self.client.getresponse().read().decode())

    def send_lamp(self, x, y, change):
        self.send_lamp_multi([ { 'x': x, 'y': y, 'change': change } ])

    def send_lamp_all(self, change):
        json    = tornado.escape.json_encode(change)
        headers = add_auth_cookie({'Content-Type': 'application/json'})
        self.client.request("POST", "/lights/all", json, headers)
        # Print response
        print(self.client.getresponse().read().decode())

    def reset_lamp_all(self):
        self.send_lamp_all({ 'on': True, 'sat':0, 'hue':0, 'bri':0 })

    def send_lamp_animation(self, coords, change, callback = None, revert = False):
        changes = []
        for i, (x,y) in enumerate(coords):
            changes += [ { 'x': x, 'y': y, 'delay': i*0.5, 'change': dict(change, transitiontime = 10) } ]
            if revert:
                changes += [ { 'x': x, 'y': y, 'delay': i*0.5 + 1, 'change': { 'bri':0, 'transitiontime':10 } } ]
        self.send_lamp_multi(changes)<commit_msg>[games] Fix game-animation lamp-revert issue (closes #46)<commit_after>import imp
import os
import tornado.escape
import tornado.ioloop
import datetime


def load(name, path, client):
    file, pathname, description = imp.find_module(name, path)
    mod = imp.load_module(name, file, pathname, description)

    return mod.create(client)

def get_games(paths):
    games = []
    for path in paths:
        try:
            for file in os.listdir(path):
                if file.endswith(".py"):
                    games += [file.split('.')[0]]
        except FileNotFoundError:
            pass

    return games


#### Game API ###################################
# This is the API that game modules make use of (by extending the Game class
# and invoking the other functions provided here).

def send_msg(handler, msg):
    if handler != None:
        handler.write_message(tornado.escape.json_encode(msg))

def send_msgs(handlers, msg):
    for h in handlers:
        send_msg(h, msg)

def send_msgs_animation(handlers, coords, message, callback = None, revert = False):
    for i, (x,y) in enumerate(coords):
        send_msgs(handlers, dict(message, x = x, y = y,
                                          delay = i * 500,
                                          transitiontime = 10))
        if revert:
            send_msgs(handlers, dict(message, power = False, x = x, y = y,
                                              delay = i*500 + 1000,
                                              transitiontime = 10))

    if callback:
        set_timeout(datetime.timedelta(seconds = len(coords)/2 + (0.5 if revert else 0)), callback)

def reply_wrong_player(game, handler):
    if handler in game.players:
        print("Wrong player")
        send_msg(handler, {'error':'Not your turn!'})
    else:
        print("Spectator")
        send_msg(handler, {'error':'You are not a player!'})

def game_over(game, winnerH, coords = frozenset()):
    if winnerH == None:
        send_msgs(game.players,     {'state': 'gameover'})
        send_msgs(game.connections, {'message': 'The game tied'})
        print("The game tied")

    else:
        winner = game.players.index(winnerH)
        send_msg(winnerH, {'state': 'gameover', 'message': 'You won!'})
        send_msgs((p for p in game.players if p != winnerH),
                          {'state': 'gameover', 'message': 'You lost!'})
        send_msgs(game.get_spectators(), {'message': "Player %d won" % (winner + 1)})
        print("Player %d wins!" % winner)

    changes = []
    for (x,y) in coords:
        changes += [ { 'x': x, 'y': y,             'change': { 'alert': 'lselect' } },
                     { 'x': x, 'y': y, 'delay': 3, 'change': { 'alert': 'none'    } } ]
    game.send_lamp_multi(changes)

    set_timeout(datetime.timedelta(seconds = len(coords) + 3), game.reset)
  # game.reset()

def set_timeout(deadline, callback):
    """
    Runs `callback` at the time `deadline` from Tornado's I/O loop.

    Thin wrapper over Tornado's `IOLoop.add_timeout`.
    """
    ioloop = tornado.ioloop.IOLoop.instance()
    ioloop.add_timeout(deadline, callback)

def get_grid_size():
    import manager
    return (manager.grid['height'], manager.grid['width'])

def add_auth_cookie(headers):
    if light_cookie and 'user' in light_cookie:
        headers['Cookie'] = light_cookie['user'].output(attrs=[], header='')
    return headers

light_cookie = None

def rgb_to_xyz(r, g, b):
    X =  1.076450 * r - 0.237662 * g + 0.161212 * b
    Y =  0.410964 * r + 0.554342 * g + 0.034694 * b
    Z = -0.010954 * r - 0.013389 * g + 1.024343 * b

    x = X / (X + Y + Z)
    y = Y / (X + Y + Z)
    return x, y, Z

def parse_color(color):
    return int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16)

def rgb_to_hsl(r, g, b):
    # via http://en.wikipedia.org/wiki/HSL_and_HSV
    M, m = max(r,g,b), min(r,g,b)
    c = M - m

    if   c == 0: hue = 0
    elif M == r: hue = (g - b)/c * 256
    elif M == g: hue = (b - r)/c * 256 + (256 * 3)
    elif M == b: hue = (r - g)/c * 256 + (256 * 6)

    hue /= 6
    lum = M/2 + m/2
    divisor = 2 * (lum if lum < 128 else 256 - lum)
    sat = c / divisor * 256

    return (int(hue), int(sat), int(lum))


class Game:
    config_file = "defaultconfig.html"
    template_file = "default.html"
    template_vars = {
        'module_name': '<name not set>',
        'cell_w':      64,
        'cell_h':      64,
        'color_empty': "#222222",
        'color_hover': "#999999"
    }

    def __init__(self, client):
        # State variables, to be used by the game
        self.queue       = None
        self.connections = set()
        self.players     = []

        # Internal variables
        self.client      = client

        if 'grid_x' not in self.template_vars or \
           'grid_y' not in self.template_vars:
            self.template_vars['grid_x'] = get_grid_size()[1]
            self.template_vars['grid_y'] = get_grid_size()[0]

    # Internal, do not override/use
    def set_queue(self, queue):
        self.queue = queue
        queue.enqueue_callback = self.on_enqueue


    # Methods for updating the lamps
    def send_lamp_multi(self, changes):
        json    = tornado.escape.json_encode(changes)
        headers = add_auth_cookie({'Content-Type': 'application/json'})
        self.client.request("POST", "/lights", json, headers)
        # Print response
        print(self.client.getresponse().read().decode())

    def send_lamp(self, x, y, change):
        self.send_lamp_multi([ { 'x': x, 'y': y, 'change': change } ])

    def send_lamp_all(self, change):
        json    = tornado.escape.json_encode(change)
        headers = add_auth_cookie({'Content-Type': 'application/json'})
        self.client.request("POST", "/lights/all", json, headers)
        # Print response
        print(self.client.getresponse().read().decode())

    def reset_lamp_all(self):
        self.send_lamp_all({ 'on': True, 'sat':0, 'hue':0, 'bri':0 })

    def send_lamp_animation(self, coords, change, callback = None, revert = False):
        changes = []
        for i, (x,y) in enumerate(coords):
            changes += [ { 'x': x, 'y': y, 'delay': i*0.5, 'change': dict(change, transitiontime = 10) } ]
            if revert:
                changes += [ { 'x': x, 'y': y, 'delay': i*0.5 + 1, 'change': { 'sat':0, 'bri':0, 'transitiontime':10 } } ]
        self.send_lamp_multi(changes)
{'fraction_non_alphanumeric': 0.15373027828430985, 'fraction_numerical': 0.02560849916752557, 'mean_word_length': 2.4165763813651138, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '303971', 'n_tokens_mistral': 4499, 'n_tokens_neox': 4163, 'n_words': 1110}