Compare commits

..

2 Commits

Author SHA1 Message Date
tamservo
cf2af10110 added bingo card commands 2024-02-17 08:41:15 -05:00
tamservo
745300c921 adding bingo module 2024-02-17 08:01:17 -05:00
35 changed files with 135 additions and 12 deletions

55
bingo.py Normal file
View File

@@ -0,0 +1,55 @@
import glob
from PIL import Image
from random import randrange
from uuid import uuid4
class Bingo:
"""Class which allows creation and cleanup of F1 bingo card images."""
def __init__(self):
self.LAYOUT_WIDTH = 88
self.X_OFFSET = 10
self.Y_OFFSET = 110
self.SQUARES_PATH = "bingo_images/squares/*.png"
self.FREE_SQUARE_PATH = "bingo_images/free_space.png"
self.BLANK_CARD_PATH = "bingo_images/card_blank.png"
self.TEMP_FOLDER = "bingo_images/temp/"
self.square_files = glob.glob(self.SQUARES_PATH)
def get_card(self):
used_files = set()
with Image.open(self.BLANK_CARD_PATH) as card_img:
card_img.load()
card_img = card_img.convert('RGBA')
# Fill the grid
for y in range(5):
for x in range(5):
square_file = ""
# If this is the center square, use the free square
if x == 2 and y == 2:
square_file = self.FREE_SQUARE_PATH
# otherwise, find a random file that hasn't been used yet
else:
rand_file_idx = randrange(len(self.square_files))
while rand_file_idx in used_files:
rand_file_idx = randrange(len(self.square_files))
square_file = self.square_files[rand_file_idx]
used_files.add(rand_file_idx)
with Image.open(square_file) as square:
position = (self.X_OFFSET + (x * self.LAYOUT_WIDTH),
self.Y_OFFSET + (y * self.LAYOUT_WIDTH))
card_img.paste(square, position, square)
# Write image to temp file
outfile = "".join((self.TEMP_FOLDER, str(uuid4()), ".png"))
print(f"{outfile=}")
card_img.save(outfile)
return outfile

BIN
bingo_images/card_blank.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
bingo_images/card_blank.xcf Normal file

Binary file not shown.

BIN
bingo_images/free_space.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -1,11 +1,13 @@
#!/usr/bin/python3
import asyncio
from bingo import Bingo
import collections.abc
import datetime
import json
import logging
import os
import pathlib
import random
import re
import sqlite3
@@ -611,16 +613,36 @@ class Robottas(commands.Bot):
return 'Not Watched Yet'
else:
return 'Watched Already'
def get_delta_str(self, delta):
min_str = "minute"
hour_str = "hour"
day_str = "day"
delta_str = str(delta)
(days, junk, rest) = delta_str.split(" ")
rest = rest.split(".")[0]
(hours, minutes, seconds) = rest.split(":")
if int(days) > 1:
day_str = "days"
if int(minutes) > 1:
min_str = "minutes"
if int(hours) > 1:
hour_str = "hours"
return f"{days} {day_str} {hours} {hour_str} {minutes} {min_str}"
async def report_next_event(self, ctx):
try:
tz = datetime.timezone.utc
con = sqlite3.connect('schedule.db')
cur = con.cursor()
now_str = datetime.datetime.now(tz=tz).isoformat(sep=' ')
now_str = now_str.split(".")[0]
t1 = datetime.datetime.now(tz=tz)
now_str = f"{t1.year}-{t1.month:02d}-{t1.day:02d} {t1.hour:02d}:{t1.minute:02d}:{t1.second}"
query = 'select * from schedule where date_start > ? ' + \
'order by date_start asc limit 1'
@@ -629,12 +651,12 @@ class Robottas(commands.Bot):
rows = cur.fetchall()
for row in rows:
t1 = datetime.datetime.fromisoformat(now_str)
t2 = datetime.datetime.fromisoformat(row[3])
t2 = datetime.datetime.fromisoformat(row[3] + "+00:00")
delta = t2 - t1
message = f"The next event is the {row[1]} - {row[2]} which is {delta} from now."
delta_str = self.get_delta_str(delta)
message = f"The next event is Round {row[5]}: {row[1]} in {row[4]} which is {delta_str} from now."
await ctx.send(message)
break # There should only be one row anyway
@@ -648,8 +670,8 @@ class Robottas(commands.Bot):
tz = datetime.timezone.utc
con = sqlite3.connect('schedule.db')
cur = con.cursor()
now_str = datetime.datetime.now(tz=tz).isoformat(sep=' ')
now_str = now_str.split(".")[0]
t1 = datetime.datetime.now(tz=tz)
now_str = f"{t1.year}-{t1.month:02d}-{t1.day:02d} {t1.hour:02d}:{t1.minute}:{t1.second}"
query = "SELECT * FROM schedule WHERE date_start > ? AND " + \
"session_type = 'Race' ORDER BY date_start ASC LIMIT 1"
@@ -658,11 +680,12 @@ class Robottas(commands.Bot):
rows = cur.fetchall()
for row in rows:
t1 = datetime.datetime.fromisoformat(now_str)
t2 = datetime.datetime.fromisoformat(row[3])
t2 = datetime.datetime.fromisoformat(row[3] + "+00:00")
delta = t2 - t1
message = f"The next race is the {row[1]} which is {delta} from now."
delta_str = self.get_delta_str(delta)
message = f"The next race is Round {row[5]}: {row[1]} in {row[4]} which is {delta_str} from now."
await ctx.send(message)
break
@@ -670,6 +693,25 @@ class Robottas(commands.Bot):
except:
await ctx.send("Sorry, hit the wall tring to find the next race.")
async def report_all_races(self, ctx):
try:
con = sqlite3.connect('schedule.db')
cur = con.cursor()
query = "SELECT * FROM schedule where session_type = 'Race' ORDER BY date_start ASC"
cur.execute(query)
rows = cur.fetchall()
await ctx.send( "All times UTC\n" )
for row in rows:
await ctx.send( f"Round {row[5]}: {row[1]} in {row[4]} which takes place {row[3]}\n" )
except:
await ctx.send("Sorry, hit the wall tring to show all races.")
# Register to alert for next race
async def register_next_race_alerts(self, ctx):
@@ -775,6 +817,8 @@ class Robottas(commands.Bot):
# Set debug or not
self.debug = True
self.bingo = Bingo()
# Discord authentication token
self.token = self.get_token("token.txt")
self.collector_command = "robottas_collector.py"
@@ -926,6 +970,7 @@ class Robottas(commands.Bot):
"(but you knew that already)\n" +
"!next_event - Prints time until the next event.\n" +
"!next_race - Prints time until the next race.\n" +
"!all_races - Prints the loation and date of all races in the schedule.\n" +
"!rbname - I will tell you my name.\n" +
"!rbroot - I will tell you who I root for.\n" +
"!rbreport - I will start race reporting in this channel. " +
@@ -943,6 +988,7 @@ class Robottas(commands.Bot):
" !forecast\n" +
" !grandma\n" +
" !grass\n" +
" !liked\n" +
" !no\n" +
" !noengine\n" +
" !pants\n" +
@@ -1147,6 +1193,11 @@ class Robottas(commands.Bot):
await ctx.send("Bono, my tyres are gone " + self.name_dict["HAM"])
# Commands that send images
@self.command()
async def bingo(ctx):
await self.send_image(ctx, "images/bingo_win.png")
@self.command()
async def calm(ctx):
await self.send_image(ctx, "images/calm.png")
@@ -1163,6 +1214,10 @@ class Robottas(commands.Bot):
async def forecast(ctx):
await self.send_image(ctx, "images/forecast.png")
@self.command()
async def liked(ctx):
await self.send_image(ctx, "images/liked.png")
@self.command()
async def no(ctx):
await self.send_image(ctx, "images/no.png")
@@ -1214,6 +1269,11 @@ class Robottas(commands.Bot):
async def next_race(ctx):
await self.report_next_race(ctx)
# Show all races
@self.command()
async def all_races(ctx):
await self.report_all_races(ctx)
# Register to get monday next race alerts
@self.command()
async def register_next_race_alerts(ctx):
@@ -1230,6 +1290,14 @@ class Robottas(commands.Bot):
await self.unregister_alerts(ctx)
# Bingo card
@self.command()
async def bingo_card(ctx):
card_file = self.bingo.get_card()
await self.send_image(ctx, card_file)
pathlib.Path.unlink(card_file)
if __name__ == '__main__':
rb = Robottas()
rb.run_robottas()