From 74df9e928742803b2a1db89a77f1fa0f5dd528a1 Mon Sep 17 00:00:00 2001 From: Stefan Harmuth Date: Sat, 18 Dec 2021 20:48:01 +0100 Subject: [PATCH 1/2] general irc bot interface --- tools/irc.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tools/irc.py b/tools/irc.py index 865fae9..44150af 100644 --- a/tools/irc.py +++ b/tools/irc.py @@ -1,4 +1,8 @@ +from time import sleep + +from .schedule import Scheduler from .simplesocket import ClientSocket +from datetime import timedelta from enum import Enum from typing import Callable, Dict, List, Union @@ -365,3 +369,43 @@ class Client: def getChannelList(self) -> List[Channel]: return list(self.__channellist.values()) + + +class IrcBot(Client): + def __init__(self, server: str, port: int, nick: str, username: str, realname: str = "Python Bot"): + super().__init__(server, port, nick, username, realname) + self._scheduler = Scheduler() + self._channel_commands = {} + self._privmsg_commands = {} + self.subscribe(ServerMessage.MSG_PRIVMSG, self.on_privmsg) + + def on(self, *args, **kwargs): + self.subscribe(*args, **kwargs) + + def schedule(self, name: str, every: timedelta, func: Callable): + self._scheduler.schedule(name, every, func) + + def register_channel_command(self, command: str, channel: str, func: Callable): + if channel not in self._channel_commands: + self._channel_commands[channel] = {} + + self._channel_commands[channel][command] = func + + def register_privmsg_command(self, command: str, func: Callable): + self._privmsg_commands[command] = func + + def on_privmsg(self, msg_from, msg_to, message): + if not message: + return + command = message.split()[0] + if msg_to in self._channel_commands and command in self._channel_commands[msg_to]: + self._channel_commands[msg_to][command](msg_from, " ".join(message.split()[1:])) + + if msg_to == self.getUser().nickname and command in self._privmsg_commands: + self._privmsg_commands[command](msg_from, " ".join(message.split()[1:])) + + def run(self): + while True: + self._scheduler.run_pending() + self.receive() + sleep(0.01) From d8d71120980d4b0daf8e7fecc9ca04622270bc9c Mon Sep 17 00:00:00 2001 From: Stefan Harmuth Date: Sun, 19 Dec 2021 16:26:50 +0100 Subject: [PATCH 2/2] Grid.transform() in 3D! --- tools/grid.py | 94 ++++++++++++++++++++++++++++---------------------- tools/types.py | 6 ++++ 2 files changed, 58 insertions(+), 42 deletions(-) create mode 100644 tools/types.py diff --git a/tools/grid.py b/tools/grid.py index 2d4e23f..22f2210 100644 --- a/tools/grid.py +++ b/tools/grid.py @@ -1,23 +1,33 @@ from __future__ import annotations from .coordinate import Coordinate, DistanceAlgorithm +from .types import Numeric from enum import Enum from heapq import heappop, heappush from typing import Any, Dict, List, Union OFF = False ON = True -Numeric = Union[int, float] class GridTransformation(Enum): - FLIP_X = 1 - FLIP_HORIZONTALLY = 1 # alias for FLIP_X; prep for 3d-transformations - FLIP_VERTICALLY = 2 - FLIP_DIAGONALLY = 3 - FLIP_DIAGONALLY_REV = 4 - ROTATE_RIGHT = 5 - ROTATE_LEFT = 6 - ROTATE_TWICE = 7 + # Rotations always take the axis to rotate around as if it were the z-axis and then rotate clockwise + # Counter-Rotations likewise, just anti-clockwise + # 3D-only OPs have a number > 10 + ROTATE_Z = 3 + ROTATE_X = 11 + ROTATE_Y = 12 + COUNTER_ROTATE_X = 14 + COUNTER_ROTATE_Y = 15 + COUNTER_ROTATE_Z = 7 + FLIP_X = 4 + FLIP_Y = 5 + FLIP_Z = 13 + + # Handy aliases + FLIP_HORIZONTALLY = 5 + FLIP_VERTICALLY = 4 + ROTATE_RIGHT = 3 + ROTATE_LEFT = 7 class Grid: @@ -162,40 +172,40 @@ class Grid: self.set(c2, buf) def transform(self, mode: GridTransformation): - if self.mode3D: - raise NotImplementedError() # that will take some time and thought + if mode.value > 10 and not self.mode3D: + raise ValueError("Operation not possible in 2D space", mode) - if mode == GridTransformation.FLIP_HORIZONTALLY: - for x in range(self.minX, (self.maxX - self.minX) // 2 + 1): - for y in range(self.minY, self.maxY + 1): - self.flip(Coordinate(x, y), Coordinate(self.maxX - x, y)) - elif mode == GridTransformation.FLIP_VERTICALLY: - for y in range(self.minY, (self.maxY - self.minY) // 2 + 1): - for x in range(self.minX, self.maxX + 1): - self.flip(Coordinate(x, y), Coordinate(x, self.maxY - y)) - elif mode == GridTransformation.FLIP_DIAGONALLY: - self.transform(GridTransformation.ROTATE_LEFT) - self.transform(GridTransformation.FLIP_HORIZONTALLY) - elif mode == GridTransformation.FLIP_DIAGONALLY_REV: - self.transform(GridTransformation.ROTATE_RIGHT) - self.transform(GridTransformation.FLIP_HORIZONTALLY) - elif mode == GridTransformation.ROTATE_LEFT: - newGrid = Grid() - for x in range(self.maxX, self.minX - 1, -1): - for y in range(self.minY, self.maxY + 1): - newGrid.set(Coordinate(y, self.maxX - x), self.get(Coordinate(x, y))) - - self.__dict__.update(newGrid.__dict__) - elif mode == GridTransformation.ROTATE_RIGHT: - newGrid = Grid() - for x in range(self.minX, self.maxX + 1): - for y in range(self.maxY, self.minY - 1, -1): - newGrid.set(Coordinate(self.maxY - y, x), self.get(Coordinate(x, y))) - - self.__dict__.update(newGrid.__dict__) - elif mode == GridTransformation.ROTATE_TWICE: - self.transform(GridTransformation.ROTATE_RIGHT) - self.transform(GridTransformation.ROTATE_RIGHT) + coords = self.__grid + self.__grid, self.minX, self.maxX, self.minY, self.maxY, self.minZ, self.maxZ = {}, 0, 0, 0, 0, 0, 0 + if mode == GridTransformation.ROTATE_X: + for c, v in coords.items(): + self.set(Coordinate(c.x, -c.z, c.y), v) + elif mode == GridTransformation.ROTATE_Y: + for c, v in coords.items(): + self.set(Coordinate(-c.z, c.y, c.x), v) + elif mode == GridTransformation.ROTATE_Z: + for c, v in coords.items(): + self.set(Coordinate(c.y, -c.x, c.z), v) + elif mode == GridTransformation.COUNTER_ROTATE_X: + for c, v in coords.items(): + self.set(Coordinate(c.x, c.z, -c.y), v) + elif mode == GridTransformation.COUNTER_ROTATE_Y: + for c, v in coords.items(): + self.set(Coordinate(c.z, c.y, -c.x), v) + elif mode == GridTransformation.COUNTER_ROTATE_Z: + for c, v in coords.items(): + self.set(Coordinate(-c.y, c.x, c.z), v) + elif mode == GridTransformation.FLIP_X: + for c, v in coords.items(): + self.set(Coordinate(-c.x, c.y, c.z), v) + elif mode == GridTransformation.FLIP_Y: + for c, v in coords.items(): + self.set(Coordinate(c.x, -c.y, c.z), v) + elif mode == GridTransformation.FLIP_Z: + for c, v in coords.items(): + self.set(Coordinate(c.x, c.y, -c.z), v) + else: + raise NotImplementedError(mode) def getPath(self, pos_from: Coordinate, pos_to: Coordinate, includeDiagonal: bool, walls: List[Any] = None, weighted: bool = False) -> Union[None, List[Coordinate]]: diff --git a/tools/types.py b/tools/types.py new file mode 100644 index 0000000..b19ac97 --- /dev/null +++ b/tools/types.py @@ -0,0 +1,6 @@ +from typing import Union + +Numeric = Union[int, float] +IntOrNone = Union[int, None] +FloatOrNone = Union[float, None] +NumericOrNone = Union[Numeric, None]