class BUXRealTime: # TODO """ Subscribe to realtime data. """ def __init__(self, access_token: str): self.url = "wss://rtf.getbux.com/subscriptions/me" self.action = "portfolio.performance" self.access_token = access_token self.headers = [("Authorization", f"Bearer {access_token}")] self.event = Event() self.product = '"trading.product.sb26503"' async def connect(self): async with websockets.connect( self.url, extra_headers=self.headers ) as websocket: # Subscribe to product # await websocket.send(self.product) # await websocket.send(self.action) async for message in websocket: self.event(RealTimeEvent(message)) def start(self): asyncio.get_event_loop().run_until_complete(self.connect()) def subscribe(self, callback): self.event.append(callback)
class KlotskiTable: def __init__(self, filename): if filename != None: self.loadtable(filename) self.on_solved = Event() self.on_block_move = Event() self.heuristic = closest_heuristic self.on_block_move.append(lambda block: update_blocks(block)) def __getitem__(self, index): if type(index) is int: return self.table[index] if type(index) is tuple: return self.table[index[0]][index[1]] raise Exception( "Expected integer or tuple but got {}.".format(type(index))) def __str__(self): digits = 1 while 10 ^ digits < len(self.blocks): digits += 1 ret = [] for i in range(len(self.table)): ret.append(' ; '.join(['{0:3.0f}'.format(x) for x in self.table[i]])) return '\n'.join(ret) def __ge__(self, other): return self.heuristic(self) >= self.heuristic(other) def __gt__(self, other): return self.heuristic(self) > self.heuristic(other) def __le__(self, other): return self.heuristic(self) <= self.heuristic(other) def __lt__(self, other): return self.heuristic(self) < self.heuristic(other) def __eq__(self, other): return str(self) == str(other) def __ne__(self, other): return str(self) != str(other) def set_heuristic(self, heuristic): self.heuristic = heuristic def get_block(self, index): return self.blocks[index] def is_solved(self): goalblock = self.get_block(self.goalblock) # get the goal block for y in range(goalblock.height): # for its height for x in range(goalblock.width): # for its width if (goalblock.y + y, goalblock.x + x) not in self.goalpositions and goalblock.shape[y][x]: return False # if the "pixel" of the block is not in any of goal positions, return False self.on_solved(self) return True def get_move_heuristic_value(self, block_index, position): block = self.get_block(block_index) if not position in block.available_movements: raise Exception("Movement to position not available.") (blocky, blockx) = position for y in range(block.height): for x in range(block.width): if block.shape[y][x]: # clear my position self.table[block.y + y][block.x + x] = inf if self.original_table[block.y + y][block.x + x] == inf else 0 for y in range(block.height): for x in range(block.width): if block.shape[y][x]: self.table[blocky + y][blockx + x] = block.index # set new position position = block.position block.y = blocky block.x = blockx block.position = (y, x) heuristic_value = self.heuristic(self) (blocky, blockx) = position for y in range(block.height): for x in range(block.width): if block.shape[y][x]: # clear my position self.table[block.y + y][block.x + x] = inf if self.original_table[block.y + y][block.x + x] == inf else 0 for y in range(block.height): for x in range(block.width): if block.shape[y][x]: self.table[blocky + y][blockx + x] = block.index # set new position block.y = blocky block.x = blockx block.position = (y, x) return heuristic_value def move_block(self, block_index, position): block = self.get_block(block_index) if not position in block.available_movements: # is position reachable? raise Exception("Movement to position not available.") (blocky, blockx) = position for y in range(block.height): for x in range(block.width): if block.shape[y][x]: # clear my position self.table[block.y + y][block.x + x] = inf if self.original_table[block.y + y][block.x + x] == inf else 0 for y in range(block.height): for x in range(block.width): if block.shape[y][x]: self.table[blocky + y][blockx + x] = block.index # set new position block.y = blocky block.x = blockx block.position = (block.y, block.x) self.on_block_move(block) def loadtable(self, filename): with open(filename) as f: lines = f.readlines() # file is short so it's ok parts = lines[0].split() # split sizes height = int(parts[0]) # height of table width = int(parts[1]) # width of table goalpositions = set([]) # empty set of goal positions # init table (all positions non-reachable -- walls) table = [[nan for x in range(width)] for y in range(height)] characters = { nan: '-', inf: '+', '.': 0, 0: '.', '-': nan, '+': inf } for y in range(height): for x in range(width): # translate characters into digits table[y][x] = character_to_code(lines[y+1][x], characters) characters[table[y][x]] = lines[y+1][x] if(lines[y+1][x] == '+'): # goal position goalpositions.add((y, x)) # read which block should end in goal position goalblock = character_to_code(lines[len(lines) - 1], characters) self.goalpositions = goalpositions self.goalblock = goalblock self.width = width self.height = height self.table = table self.original_table = copy.deepcopy(table) self.filename = filename self.characters = characters self.desired_position = most_extreme_position(goalpositions) shapes = {} # shapes of blocks represented as logical 2D array for y in range(height): for x in range(width): if table[y][x] != 0 and table[y][x] != inf and not isnan(table[y][x]): if table[y][x] not in shapes: shapes[table[y][x]] = set([]) shapes[table[y][x]].add((y, x)) blocks = {index: create_block(index, self.characters[index], shapes[index], self) for index in shapes} # create blocks from shapes self.blocks = blocks def copy(self): table = KlotskiTable(None) table.goalpositions = self.goalpositions table.goalblock = self.goalblock table.width = self.width table.height = self.height table.original_table = self.original_table table.filename = self.filename table.characters = self.characters table.desired_position = self.desired_position table.table = copy.deepcopy(self.table) table.blocks = { index: self.blocks[index].copy(table) for index in self.blocks } return table