-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #95 from Mickhat/oli-heeeckers-new-system
change the 1337 game to use heeeckers early voting system
- Loading branch information
Showing
4 changed files
with
297 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
|
||
import { CommandInteraction, EmbedBuilder, SlashCommandBuilder } from 'discord.js' | ||
import LogManager from '../logger/logger' | ||
import { EliteGameDataStorage } from '../service/eliteGameDataStorage' | ||
import { getTodayAsDate } from '../service/promotionService' | ||
import { calcValidFrom, parse } from 'src/service/eliteEarlyBirdService' | ||
|
||
export default { | ||
data: new SlashCommandBuilder() | ||
.setName('1337-early-bird') | ||
.setDescription('Plays the 1337 game as an early bird.') | ||
.addStringOption((opt) => opt.setName('time').setDescription('The time (HH:mm:ss.sss) you would have /1337`ed').setRequired(true)), | ||
async execute(interaction: CommandInteraction) { | ||
const logger = LogManager.getInstance().logger('EliteEarlyBirdCommand') | ||
if (!interaction.isRepliable()) { | ||
logger.logSync('ERROR', 'Gegebene interaction kann nicht beantwortet werden.') | ||
return | ||
} | ||
const berlinDate = getTodayAsDate() | ||
|
||
const userId = interaction.member?.user.id ?? '<ERROR>' | ||
const time = interaction.options.get('time', true).value | ||
if (!time) { | ||
throw new Error('No time provided') | ||
} | ||
|
||
const rows = await EliteGameDataStorage.instance().loadGamePlayForUser(userId, berlinDate) | ||
try { | ||
if (rows.length > 0) { | ||
if (rows[0].player === '\uFFFF') { | ||
// the player '\uFFFF' indicates that the game has been played for this day | ||
await interaction.reply({ | ||
embeds: [new EmbedBuilder() | ||
.setColor(0x0099ff) | ||
.setTitle('Too late!') | ||
.setDescription( | ||
'Es ist nach 13:37. Morgen kannst du wieder mitmachen.' | ||
) | ||
.setTimestamp()], | ||
ephemeral: true | ||
}) | ||
} else { | ||
await interaction.reply({ | ||
embeds: [new EmbedBuilder() | ||
.setColor(0x0099ff) | ||
.setTitle('That`s not going to happen!') | ||
.setDescription( | ||
'Du hast heute bereits deinen Tipp abgegeben. Warte auf das Ergebnis.' | ||
) | ||
.setTimestamp()], | ||
ephemeral: true | ||
}) | ||
} | ||
} else { | ||
const playTime = parse(time) | ||
if (!playTime) { | ||
await interaction.reply({ | ||
embeds: [new EmbedBuilder() | ||
.setColor(0x0099ff) | ||
.setTitle('Invalid time!') | ||
.setDescription( | ||
'Die Zeit muss im Format `HH:mm:ss.sss` sein.' | ||
) | ||
.setTimestamp()], | ||
ephemeral: true | ||
}) | ||
return | ||
} | ||
const validFrom = calcValidFrom(playTime) | ||
await EliteGameDataStorage.instance().writeGamePlayEarlyBird( | ||
userId, // discord-id user | ||
berlinDate, // german format date of play e.g. 17.06.2024 | ||
playTime, // submission time (the guess) in millis since epoc e.g. 1710419768333 for 13.03.2024 23:05 | ||
validFrom // valid starting time in millis since epoc e.g. 1710419768333 for 13.03.2024 23:05 | ||
) | ||
await interaction.reply({ | ||
embeds: [new EmbedBuilder() | ||
.setColor(0x0099ff) | ||
.setTitle('Got it early bird!') | ||
.setDescription( | ||
'Dein Tipp wurde registriert. Warte auf das Ergebnis.' | ||
) | ||
.setTimestamp()], | ||
ephemeral: true | ||
}) | ||
} | ||
} catch (err) { | ||
console.log(err) | ||
logger.logSync('ERROR', `Reply to elite command konnte nicht gesendet werden. ${JSON.stringify(err)}`) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import { expect, test } from '@jest/globals' | ||
import { parse } from './eliteEarlyBirdService' | ||
|
||
test('full time - at 13:37', async () => { | ||
const now = new Date() | ||
const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0).getTime() | ||
const result = parse('13:37:37.137') | ||
expect(result).toBeDefined() | ||
if (result) { | ||
expect(result - midnight).toBe(13 * 60 * 60 * 1000 + 37 * 60 * 1000 + 37 * 1000 + 137) | ||
} | ||
}) | ||
|
||
test('full time - early morning', async () => { | ||
const now = new Date() | ||
const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0).getTime() | ||
const result = parse('2:37:37.137') | ||
expect(result).toBeDefined() | ||
if (result) { | ||
expect(result - midnight).toBe(2 * 60 * 60 * 1000 + 37 * 60 * 1000 + 37 * 1000 + 137) | ||
} | ||
}) | ||
|
||
test('full time - early morning - single digits', async () => { | ||
const now = new Date() | ||
const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0).getTime() | ||
const result = parse('2:02:02.1') | ||
expect(result).toBeDefined() | ||
if (result) { | ||
expect(result - midnight).toBe(2 * 60 * 60 * 1000 + 2 * 60 * 1000 + 2 * 1000 + 100) | ||
} | ||
}) | ||
|
||
test('time without millis - early morning - single digits', async () => { | ||
const now = new Date() | ||
const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0).getTime() | ||
const result = parse('2:02:02') | ||
expect(result).toBeDefined() | ||
if (result) { | ||
expect(result - midnight).toBe(2 * 60 * 60 * 1000 + 2 * 60 * 1000 + 2 * 1000) | ||
} | ||
}) | ||
|
||
test('time without hour - single digits', async () => { | ||
const now = new Date() | ||
const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0).getTime() | ||
const result = parse('2:02') | ||
expect(result).toBeDefined() | ||
if (result) { | ||
expect(result - midnight).toBe(13 * 60 * 60 * 1000 + 2 * 60 * 1000 + 2 * 1000) | ||
} | ||
}) | ||
|
||
test('time just in seconcs', async () => { | ||
const now = new Date() | ||
const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0).getTime() | ||
const result = parse('37') | ||
expect(result).toBeDefined() | ||
if (result) { | ||
expect(result - midnight).toBe(13 * 60 * 60 * 1000 + 37 * 60 * 1000 + 37 * 1000) | ||
} | ||
}) | ||
|
||
test('time just in seconcs and millis(3 digit pending 0)', async () => { | ||
const now = new Date() | ||
const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0).getTime() | ||
const result = parse('3.370') | ||
expect(result).toBeDefined() | ||
if (result) { | ||
expect(result - midnight).toBe(13 * 60 * 60 * 1000 + 37 * 60 * 1000 + 3 * 1000 + 370) | ||
} | ||
}) | ||
|
||
test('time just in seconcs and millis(2 digits)', async () => { | ||
const now = new Date() | ||
const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0).getTime() | ||
const result = parse('3.37') | ||
expect(result).toBeDefined() | ||
if (result) { | ||
expect(result - midnight).toBe(13 * 60 * 60 * 1000 + 37 * 60 * 1000 + 3 * 1000 + 370) | ||
} | ||
}) | ||
|
||
test('time just in seconcs and millis(3 digits, leading 0)', async () => { | ||
const now = new Date() | ||
const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0).getTime() | ||
const result = parse('3.037') | ||
expect(result).toBeDefined() | ||
if (result) { | ||
expect(result - midnight).toBe(13 * 60 * 60 * 1000 + 37 * 60 * 1000 + 3 * 1000 + 37) | ||
} | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
|
||
export function parse(dateToParse: string | number | boolean): undefined | number { | ||
if (typeof dateToParse !== 'string') { | ||
return undefined | ||
} | ||
const now = new Date() | ||
const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0).getTime() | ||
if (/^\d{1,2}:\d{1,2}:\d{1,2}\.\d{1,3}$/g.test(dateToParse)) { | ||
const splitByColon = dateToParse.split(':') | ||
if (splitByColon.length !== 3) { | ||
return undefined | ||
} | ||
const hours = parseInt(splitByColon[0]) | ||
const minutes = parseInt(splitByColon[1]) | ||
const seconds = parseFloat(splitByColon[2]) | ||
if (hours < 0 || hours > 23) { | ||
return undefined | ||
} | ||
if (minutes < 0 || minutes > 59) { | ||
return undefined | ||
} | ||
if (seconds < 0 || seconds >= 60) { | ||
return undefined | ||
} | ||
return midnight + (seconds * 1000) + (minutes * 60 * 1000) + (hours * 60 * 60 * 1000) | ||
} | ||
if (/^\d{1,2}:\d{1,2}:\d{1,2}$/g.test(dateToParse)) { | ||
const splitByColon = dateToParse.split(':') | ||
if (splitByColon.length !== 3) { | ||
return undefined | ||
} | ||
const hours = parseInt(splitByColon[0]) | ||
const minutes = parseInt(splitByColon[1]) | ||
const seconds = parseInt(splitByColon[2]) | ||
if (hours < 0 || hours > 23) { | ||
return undefined | ||
} | ||
if (minutes < 0 || minutes > 59) { | ||
return undefined | ||
} | ||
if (seconds < 0 || seconds > 59) { | ||
return undefined | ||
} | ||
return midnight + (seconds * 1000) + (minutes * 60 * 1000) + (hours * 60 * 60 * 1000) | ||
} | ||
if (/^\d{1,2}:\d{1,2}$/g.test(dateToParse)) { | ||
const splitByColon = dateToParse.split(':') | ||
if (splitByColon.length !== 2) { | ||
return undefined | ||
} | ||
const minutes = parseInt(splitByColon[0]) | ||
const seconds = parseInt(splitByColon[1]) | ||
if (minutes < 0 || minutes > 59) { | ||
return undefined | ||
} | ||
if (seconds < 0 || seconds > 59) { | ||
return undefined | ||
} | ||
return midnight + (seconds * 1000) + (minutes * 60 * 1000) + (13 * 60 * 60 * 1000) | ||
} | ||
if (/^\d{1,2}\.\d{1,3}$/g.test(dateToParse)) { | ||
const seconds = parseFloat(dateToParse) | ||
if (seconds < 0 || seconds >= 60) { | ||
return undefined | ||
} | ||
return midnight + (seconds * 1000) + (37 * 60 * 1000) + (13 * 60 * 60 * 1000) | ||
} | ||
if (/^\d{1,2}$/g.test(dateToParse)) { | ||
const seconds = parseInt(dateToParse) | ||
if (seconds < 0 || seconds > 59) { | ||
return undefined | ||
} | ||
return midnight + seconds * 1000 + (37 * 60 * 1000) + (13 * 60 * 60 * 1000) | ||
} | ||
return undefined | ||
} | ||
|
||
export function calcValidFrom(playTime: number): number { | ||
const now = new Date() | ||
let offset = 999 | ||
// rules: Mitternacht tippt sind es 65s, wenn man um 8 Uhr tippt 30s, um 12 Uhr -> 7s, 13 Uhr -> 3s, ab 13:37 dann 0s | ||
if (now.getHours() >= 0 && now.getHours() <= 7) { | ||
offset = 65 | ||
} else if (now.getHours() >= 8 && now.getHours() <= 11) { | ||
offset = 30 | ||
} else if (now.getHours() === 12) { | ||
offset = 7 | ||
} else if (now.getHours() === 13) { | ||
offset = 3 | ||
} | ||
return playTime + offset * 1000 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters