"""
_
__ _____ ___ ___ ___ __| | ___ _ __
\ \ / / __|/ _ \/ __/ _ \ / _` |/ _ \ '__|
\ V /\__ \ __/ (_| (_) | (_| | __/ |
\_/ |___/\___|\___\___/ \__,_|\___|_|
Copyleft 2022 t.me/vsecoder
This program is free software; you can redistribute it and/or modify
"""
# meta developer: @vsecoder_m
# meta pic: https://img.icons8.com/external-icongeek26-linear-colour-icongeek26/344/external-maze-game-development-icongeek26-linear-colour-icongeek26.png
# meta banner: https://chojuu.vercel.app/api/banner?img=https://img.icons8.com/external-icongeek26-linear-colour-icongeek26/344/external-maze-game-development-icongeek26-linear-colour-icongeek26.png&title=MazeMod&description=Telegram%20Maze%20Game
__version__ = (2, 0, 0)
import logging
import random
from telethon import TelegramClient
from .. import loader # type: ignore
from ..inline.types import InlineCall # type: ignore
logger = logging.getLogger(__name__)
class Maze:
def __init__(self, rowsNumber, columnsNumber):
self.rowsNumber = rowsNumber
self.columnsNumber = columnsNumber
self.maze = []
def isEven(self, number):
return number % 2 == 0
def getRandomFrom(self, array):
return random.choice(array)
def setField(self, x, y, value):
if x < 0 or x >= self.columnsNumber or y < 0 or y >= self.rowsNumber:
return False
self.maze[y][x] = value
def getField(self, x, y):
if x < 0 or x >= self.columnsNumber or y < 0 or y >= self.rowsNumber:
return False
return self.maze[y][x]
def isMaze(self):
for x in range(self.columnsNumber):
for y in range(self.rowsNumber):
if self.isEven(x) and self.isEven(y) and self.getField(x, y) == "⬜️":
return False
return True
def moveTractor(self, tractor):
directs = []
if tractor["x"] > 0:
directs.append("left")
n = self.columnsNumber - 2
if tractor["x"] < n:
directs.append("right")
if tractor["y"] > 0:
directs.append("up")
n = self.rowsNumber - 2
if tractor["y"] < n:
directs.append("down")
direct = self.getRandomFrom(directs)
if direct == "left":
if self.getField(tractor["x"] - 2, tractor["y"]) == "⬜️":
self.setField(tractor["x"] - 1, tractor["y"], "⬛️")
self.setField(tractor["x"] - 2, tractor["y"], "⬛️")
tractor["x"] -= 2
if direct == "right":
if self.getField(tractor["x"] + 2, tractor["y"]) == "⬜️":
self.setField(tractor["x"] + 1, tractor["y"], "⬛️")
self.setField(tractor["x"] + 2, tractor["y"], "⬛️")
tractor["x"] += 2
if direct == "up":
if self.getField(tractor["x"], tractor["y"] - 2) == "⬜️":
self.setField(tractor["x"], tractor["y"] - 1, "⬛️")
self.setField(tractor["x"], tractor["y"] - 2, "⬛️")
tractor["y"] -= 2
if direct == "down":
if self.getField(tractor["x"], tractor["y"] + 2) == "⬜️":
self.setField(tractor["x"], tractor["y"] + 1, "⬛️")
self.setField(tractor["x"], tractor["y"] + 2, "⬛️")
tractor["y"] += 2
def generate_map(self):
for _ in range(self.rowsNumber):
row = ["⬜️" for _ in range(self.columnsNumber)]
self.maze.append(row)
evenColums = []
for column in range(self.columnsNumber):
if self.isEven(column):
evenColums.append(column)
startX = 2
startY = 2
tractor = {"x": startX, "y": startY}
self.setField(startX, startY, "⬛️")
while not self.isMaze():
self.moveTractor(tractor)
return self.maze
@loader.tds
class MazeModMod(loader.Module):
"""Module for play maze"""
strings = {
"name": "MazeMod",
"cfg_maze_width": "Maze width and height, default is 30x30",
"answer": "🕹 Click on the inline buttons to move: {0}",
"doc": "\n 🟦 - player \n ⬛️ - road\n ⬜️ - wall\n 🟩 - finish\n",
"move": "▶️ Moved\n",
"not_allowed": "💭 Not allowed\n",
"win": "🎉 You win!",
"error": "❗️ Error!",
}
strings_ru = {
"answer": "🕹 Нажимайте на инлайн кнопки что двигаться: {0}",
"doc": "\n 🟦 - игрок \n ⬛️ - дорога\n ⬜️ - стена\n 🟩 - финиш\n",
"move": "▶️ Передвинулся\n",
"not_allowed": "💭 Не разрешено\n",
"win": "🎉 Вы победили!",
"error": "❗️ Ошибка!",
}
def __init__(self):
self.config = loader.ModuleConfig(
"maze_width",
"10",
self.strings["cfg_maze_width"],
)
self.name = self.strings["name"]
async def client_ready(self, client: TelegramClient, db):
self._db = db
self._client = client
async def render(self, message: InlineCall, press, maze, player):
text = self.strings["answer"].format(self.strings["not_allowed"])
move = {"x": player["x"], "y": player["y"]}
if press == "up":
move["y"] = move["y"] - 1
if press == "left":
move["x"] = move["x"] - 1
if press == "down":
move["y"] = move["y"] + 1
if press == "right":
move["x"] = move["x"] + 1
if maze[move["y"]][move["x"]] == "⬜":
pass
elif maze[move["y"]][move["x"]] == "⬛️":
maze[player["y"]][player["x"]] = "⬛️"
player = move
text = self.strings["answer"].format(self.strings["move"])
elif maze[move["y"]][move["x"]] == "🟩":
text = self.strings["win"]
return await message.edit(text=text)
maze[player["y"]][player["x"]] = "🟦"
keyboard = [
[
{"text": "🔼", "callback": self.render, "args": ["up", maze, player]},
],
[
{"text": "◀️", "callback": self.render, "args": ["left", maze, player]},
{
"text": "▶️",
"callback": self.render,
"args": ["right", maze, player],
},
],
[
{"text": "🔽", "callback": self.render, "args": ["down", maze, player]},
],
]
for column in maze:
for row in column:
for i in row:
text = text + i
text = text + "\n"
await message.edit(text=text, reply_markup=keyboard)
@loader.unrestricted
@loader.ratelimit
async def mazecmd(self, message):
"""
- generate maze and start play
Based on... my code)
"""
size = int(self.config["maze_width"])
generate = Maze(size, size)
maze = generate.generate_map()
player = {"x": 0, "y": 0}
maze[player["y"]][player["x"]] = "🟦"
maze[size - 2][size - 2] = "🟩"
text = self.strings["answer"].format(self.strings["doc"])
keyboard = [
[
{"text": "🔼", "callback": self.render, "args": ["up", maze, player]},
],
[
{"text": "◀️", "callback": self.render, "args": ["left", maze, player]},
{
"text": "▶️",
"callback": self.render,
"args": ["right", maze, player],
},
],
[
{
"text": "🔽",
"callback": self.render,
"args": [
"down",
maze,
player,
],
},
],
]
for column in maze:
for row in column:
for i in row:
text = text + i
text = text + "\n"
await message.delete()
await self.inline.form(
text=text,
message=message,
always_allow=[message.from_id],
reply_markup=keyboard,
)