From 7649d12f400f164dd06f6a45486221234052dbb6 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Mon, 18 Mar 2024 13:16:29 +0100 Subject: [PATCH] some guessing game fixes --- app/Http/Controllers/ChannelController.php | 15 +-- app/Models/Channel.php | 55 ++++++++- app/TwitchBot/GuessingSolveCommand.php | 16 +-- .../twitch-bot/GuessingSettingsForm.js | 52 +++++++++ resources/js/i18n/de.js | 11 ++ resources/js/i18n/en.js | 11 ++ tests/Unit/Models/ChannelTest.php | 108 ++++++++++++++++++ 7 files changed, 236 insertions(+), 32 deletions(-) create mode 100644 tests/Unit/Models/ChannelTest.php diff --git a/app/Http/Controllers/ChannelController.php b/app/Http/Controllers/ChannelController.php index dec17e9..c47a406 100644 --- a/app/Http/Controllers/ChannelController.php +++ b/app/Http/Controllers/ChannelController.php @@ -164,18 +164,7 @@ class ChannelController extends Controller { case 'solve': if ($channel->hasActiveGuessing() && $channel->isValidGuess($validatedData['solution'])) { $winners = $channel->solveGuessing($validatedData['solution']); - $names = []; - foreach ($winners as $winner) { - if ($winner->score > 0) { - $names[] = $winner->uname; - } - } - if (empty($names)) { - $msg = $channel->getGuessingSetting('no_winners_message'); - } else { - $msg = $channel->getGuessingSetting('winners_message'); - $msg = str_replace('{names}', $channel->listAnd($names), $msg); - } + $msg = $channel->listGuessingWinners($winners); if (!empty($msg)) { TwitchBotCommand::chat($channel->twitch_chat, $msg); } @@ -250,7 +239,9 @@ class ChannelController extends Controller { $validatedData = $request->validate([ 'active_message' => 'string', 'cancel_message' => 'string', + 'close_winners_message' => 'string', 'invalid_solution_message' => 'string', + 'leaderboard_type' => 'string', 'no_winners_message' => 'string', 'not_active_message' => 'string', 'points_exact_first' => 'numeric|min:1|max:5', diff --git a/app/Models/Channel.php b/app/Models/Channel.php index 8debe4f..bf3b98b 100644 --- a/app/Models/Channel.php +++ b/app/Models/Channel.php @@ -32,7 +32,20 @@ class Channel extends Model { } public function getGuessingLeaderboard() { - return $this->winners()->selectRaw('(select t2.uname from guessing_winners t2 where t2.uid = guessing_winners.uid order by created_at desc limit 1) as name, sum(score) as score')->groupBy('uid')->orderBy('score', 'desc')->limit(10)->get(); + $query = $this->winners() + ->selectRaw('(select t2.uname from guessing_winners t2 where t2.uid = guessing_winners.uid order by created_at desc limit 1) as name, sum(score) as score') + ->groupBy('uid') + ->orderBy('score', 'desc') + ->limit(10); + $type = $this->getGuessingSetting('leaderboard_type', 'all'); + if ($type == 'month') { + $query->where('created_at', '>=', now()->startOfMonth()); + } else if ($type == 'year') { + $query->where('created_at', '>=', now()->startOfYear()); + } else if (is_numeric($type)) { + $query->where('created_at', '>=', now()->sub($type, 'days')); + } + return $query->get(); } public function hasActiveGuessing() { @@ -119,23 +132,33 @@ class Channel extends Model { $this->save(); } + public function transformGuess($original) { + $transformed = trim($original); + if ($this->guessing_type == 'gtbk') { + $transformed = str_replace(['roodyo1Gtbigkey'], ['2'], $transformed); + $transformed = str_ireplace(['vier 4Head'], ['4'], $transformed); + } + return $transformed; + } + public function registerGuess($uid, $uname, $guess) { $model = new GuessingGuess(); $model->channel()->associate($this); $model->uid = $uid; $model->uname = $uname; - $model->guess = $guess; + $model->guess = $this->transformGuess($guess); $model->save(); } public function scoreGuessing($solution, $guess, $first) { - if ($guess == $solution) { + $transformed = $this->transformGuess($guess); + if ($transformed == $solution) { if ($first) { return $this->getGuessingSetting('points_exact_first', 1); } return $this->getGuessingSetting('points_exact_other', 1); } - $distance = abs(intval($guess) - intval($solution)); + $distance = abs(intval($transformed) - intval($solution)); if ($distance <= $this->getGuessingSetting('points_close_max', 3)) { if ($first) { return $this->getGuessingSetting('points_close_first', 1); @@ -146,13 +169,33 @@ class Channel extends Model { } public function isValidGuess($solution) { + $transformed = $this->transformGuess($solution); if ($this->guessing_type == 'gtbk') { - $int_solution = intval($solution); - return $int_solution > 0 && $int_solution < 23; + $int_solution = intval($transformed); + return is_numeric($transformed) && $int_solution > 0 && $int_solution < 23; } return false; } + public function listGuessingWinners($winners) { + $names = []; + $distance = 0; + foreach ($winners as $winner) { + if ($winner->score > 0) { + $names[] = $winner->uname; + $distance = abs(intval($winner->guess) - intval($winner->solution)); + } + } + $msg = ''; + if (empty($names)) { + $msg = $this->getGuessingSetting('no_winners_message'); + } else { + $msg = $this->getGuessingSetting($distance ? 'close_winners_message' : 'winners_message', $this->getGuessingSetting('winners_message')); + $msg = str_replace(['{distance}', '{names}'], [$distance, $this->listAnd($names)], $msg); + } + return $msg; + } + public function listAnd($entries) { $lang = empty($this->languages) ? 'en' : $this->languages[0]; if ($lang == 'de') { diff --git a/app/TwitchBot/GuessingSolveCommand.php b/app/TwitchBot/GuessingSolveCommand.php index b4a877d..e825791 100644 --- a/app/TwitchBot/GuessingSolveCommand.php +++ b/app/TwitchBot/GuessingSolveCommand.php @@ -16,20 +16,8 @@ class GuessingSolveCommand extends ChatCommand { return; } $winners = $this->channel->solveGuessing($args); - $names = []; - foreach ($winners as $winner) { - if ($winner->score > 0) { - $names[] = $winner->uname; - } - } - if (empty($names)) { - $msg = $this->channel->getGuessingSetting('no_winners_message'); - $this->messageChannel($msg); - } else { - $msg = $this->channel->getGuessingSetting('winners_message'); - $msg = str_replace('{names}', $this->listAnd($names), $msg); - $this->messageChannel($msg); - } + $msg = $this->channel->listGuessingWinners($winners); + $this->messageChannel($msg); $this->channel->clearGuessing(); } diff --git a/resources/js/components/twitch-bot/GuessingSettingsForm.js b/resources/js/components/twitch-bot/GuessingSettingsForm.js index 128d6f5..a465e4e 100644 --- a/resources/js/components/twitch-bot/GuessingSettingsForm.js +++ b/resources/js/components/twitch-bot/GuessingSettingsForm.js @@ -115,6 +115,27 @@ const GuessingSettingsForm = ({ : null} + + {t('twitchBot.guessingGame.leaderboardType')} + + {['all', 'year', '365', 'month', '30'].map(type => + + )} + + {touched.leaderboard_type && errors.leaderboard_type ? + + {t(errors.leaderboard_type)} + + : null} + {t('twitchBot.guessingGame.startMessage')} @@ -168,6 +189,26 @@ const GuessingSettingsForm = ({ } + + {t('twitchBot.guessingGame.closeWinnersMessage')} + + {touched.close_winners_message && errors.close_winners_message ? + + {t(errors.close_winners_message)} + + : + + {t('twitchBot.guessingGame.closeWinnersMessageHint')} + + } + {t('twitchBot.guessingGame.noWinnersMessage')} guessing_type = 'gtbk'; + + $this->assertTrue($channel->isValidGuess('1')); + $this->assertTrue($channel->isValidGuess('22')); + $this->assertTrue($channel->isValidGuess('3 ')); + $this->assertTrue($channel->isValidGuess('vier 4Head')); + $this->assertTrue($channel->isValidGuess('Vier 4Head')); + $this->assertTrue($channel->isValidGuess('roodyo1Gtbigkey')); + + $this->assertFalse($channel->isValidGuess('1:22:56')); + $this->assertFalse($channel->isValidGuess('torch')); + } + + public function test_guessing_scoring() { + $channel = new Channel(); + $channel->guessing_type = 'gtbk'; + $channel->guessing_settings = [ + 'gtbk' => [ + 'points_exact_first' => 5, + 'points_exact_other' => 4, + 'points_close_first' => 3, + 'points_close_other' => 2, + 'points_close_max' => 5, + ], + ]; + + $this->assertEquals(5, $channel->scoreGuessing('3', '3', true)); + $this->assertEquals(4, $channel->scoreGuessing('12', '12', false)); + $this->assertEquals(3, $channel->scoreGuessing('15', '14', true)); + $this->assertEquals(2, $channel->scoreGuessing('8', '6', false)); + $this->assertEquals(0, $channel->scoreGuessing('7', '1', true)); + $this->assertEquals(0, $channel->scoreGuessing('3', '22', false)); + + $this->assertEquals(5, $channel->scoreGuessing('2', 'roodyo1Gtbigkey', true)); + $this->assertEquals(5, $channel->scoreGuessing('4', 'Vier 4Head', true)); + $this->assertEquals(5, $channel->scoreGuessing('5', '5 ', true)); + } + + public function test_guessing_winners() { + $channel = new Channel(); + $channel->guessing_type = 'gtbk'; + $channel->guessing_settings = [ + 'gtbk' => [ + 'close_winners_message' => 'within {distance}: {names}', + 'no_winners_message' => 'no winners', + 'winners_message' => 'winners: {names}', + ], + ]; + + $this->assertEquals('no winners', $channel->listGuessingWinners([])); + + $winners = []; + $winner = new GuessingWinner(); + $winner->uname = 'Horstie'; + $winner->guess = '3'; + $winner->solution = '3'; + $winner->score = 1; + $winners[] = $winner; + + $this->assertEquals('winners: Horstie', $channel->listGuessingWinners($winners)); + + $winner = new GuessingWinner(); + $winner->uname = 'Borstie'; + $winner->guess = '3'; + $winner->solution = '3'; + $winner->score = 1; + $winners[] = $winner; + + $channel->languages = ['de']; + $this->assertEquals('winners: Horstie und Borstie', $channel->listGuessingWinners($winners)); + $channel->languages = ['en']; + $this->assertEquals('winners: Horstie and Borstie', $channel->listGuessingWinners($winners)); + + $winners[0]->guess = '1'; + $winners[1]->guess = '5'; + + + $channel->languages = ['de']; + $this->assertEquals('within 2: Horstie und Borstie', $channel->listGuessingWinners($winners)); + $channel->languages = ['en']; + $this->assertEquals('within 2: Horstie and Borstie', $channel->listGuessingWinners($winners)); + + $channel->guessing_settings = [ + 'gtbk' => [ + 'no_winners_message' => 'no winners', + 'winners_message' => 'winners: {names}', + ], + ]; + + $channel->languages = ['de']; + $this->assertEquals('winners: Horstie und Borstie', $channel->listGuessingWinners($winners)); + $channel->languages = ['en']; + $this->assertEquals('winners: Horstie and Borstie', $channel->listGuessingWinners($winners)); + } + +} -- 2.39.2