Skip to content

Commit

Permalink
improve jumble algorithm picker
Browse files Browse the repository at this point in the history
  • Loading branch information
th0mk committed Jun 18, 2024
1 parent f4d2e3c commit 8f90ef8
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 35 deletions.
15 changes: 9 additions & 6 deletions src/FMBot.Bot/Builders/GameBuilders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ public static ResponseModel GameModePick(ContextModel context)
}
}

var jumblesPlayedToday = await this._gameService.GetJumbleSessionsCountToday(context.ContextUser.UserId);
var recentJumbles = await this._gameService.GetJumbleSessionsCountToday(context.ContextUser.UserId);
var jumblesPlayedToday = recentJumbles.Count(c => c.DateStarted.Date == DateTime.Today);
const int jumbleLimit = 30;
if (!SupporterService.IsSupporter(context.ContextUser.UserType) && jumblesPlayedToday.Count > jumbleLimit)
if (!SupporterService.IsSupporter(context.ContextUser.UserType) && jumblesPlayedToday > jumbleLimit)
{
response.Embed.WithColor(DiscordConstants.InformationColorBlue);
response.Embed.WithDescription($"You've used up all your {jumbleLimit} jumbles of today. [Get supporter]({Constants.GetSupporterDiscordLink}) to play unlimited jumble games and much more.");
Expand All @@ -96,7 +97,7 @@ public static ResponseModel GameModePick(ContextModel context)
return response;
}

var artist = GameService.PickArtistForJumble(topArtists, jumblesPlayedToday);
var artist = GameService.PickArtistForJumble(topArtists, recentJumbles);

if (artist.artist == null)
{
Expand Down Expand Up @@ -281,7 +282,7 @@ public async Task JumbleProcessAnswer(ContextModel context, ICommandContext comm
var timeTaken = DateTime.UtcNow - currentGame.DateStarted;
separateResponse.WithFooter($"Answered in {timeTaken.TotalSeconds.ToString("F1", System.Globalization.CultureInfo.InvariantCulture)}s");
separateResponse.WithColor(DiscordConstants.SpotifyColorGreen);

if (context.DiscordChannel is IMessageChannel msgChannel)
{
_ = Task.Run(() => msgChannel.SendMessageAsync(embed: separateResponse.Build()));
Expand All @@ -308,15 +309,17 @@ public async Task JumbleProcessAnswer(ContextModel context, ICommandContext comm
}
else if (messageLength >= answerLength - 5 && messageLength <= answerLength + 2)
{
await commandContext.Message.AddReactionAsync(new Emoji(""));

var levenshteinDistance =
GameService.GetLevenshteinDistance(currentGame.CorrectAnswer.ToLower(), commandContext.Message.Content.ToLower());

if (levenshteinDistance == 1)
{
await commandContext.Message.AddReactionAsync(new Emoji("🤏"));
}
else
{
await commandContext.Message.AddReactionAsync(new Emoji(""));
}

await this._gameService.JumbleAddAnswer(currentGame, commandContext.User.Id, false);
}
Expand Down
83 changes: 54 additions & 29 deletions src/FMBot.Bot/Services/GameService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,55 +36,81 @@ public GameService(IMemoryCache cache, IDbContextFactory<FMBotDbContext> context
this._botSettings = botSettings.Value;
}

public static (string artist, long userPlaycount) PickArtistForJumble(List<TopArtist> topArtists,
HashSet<string> jumblesPlayedToday = null)
public static (string artist, long userPlaycount) PickArtistForJumble(List<TopArtist> topArtists, List<JumbleSession> recentJumbles = null)
{
jumblesPlayedToday ??= [];
recentJumbles ??= [];

var today = DateTime.Today;
var recentJumblesHashset = recentJumbles
.Where(w => w.DateStarted.Date == today)
.GroupBy(g => g.CorrectAnswer)
.Select(s => s.Key)
.ToHashSet(StringComparer.OrdinalIgnoreCase);

if (topArtists.Count > 250 && recentJumbles.Count > 50)
{
var recentJumbleAnswers = recentJumbles
.GroupBy(g => g.CorrectAnswer)
.Select(s => s.Key)
.ToHashSet(StringComparer.OrdinalIgnoreCase);

recentJumblesHashset.UnionWith(recentJumbleAnswers);
}

topArtists = topArtists
.Where(w => !jumblesPlayedToday.Contains(w.ArtistName))
.Where(w => !recentJumblesHashset.Contains(w.ArtistName))
.OrderByDescending(o => o.UserPlaycount)
.ToList();

var multiplier = topArtists.Count switch
{
> 7000 => 8,
> 5000 => 6,
> 2500 => 4,
> 1200 => 3,
> 500 => 2,
_ => 1
};

var minPlaycount = jumblesPlayedToday.Count switch
var minPlaycount = recentJumbles.Count(w => w.DateStarted.Date >= today.AddDays(-2)) switch
{
>= 120 => 1,
>= 75 => 2,
>= 40 => 3,
>= 12 => 6,
>= 5 => 20,
_ => 40
>= 75 => 1,
>= 40 => 2,
>= 12 => 5,
>= 4 => 15,
_ => 30
};

var finalMinPlaycount = minPlaycount * multiplier;
if (jumblesPlayedToday.Count > 250)
if (recentJumbles.Count(w => w.DateStarted.Date == today) >= 250)
{
finalMinPlaycount = 1;
}

var total = topArtists.Count(w => w.UserPlaycount >= finalMinPlaycount);
var eligibleArtists = topArtists
.Where(w => w.UserPlaycount >= finalMinPlaycount)
.ToList();

Log.Information("PickArtistForJumble: {topArtistCount} top artists - {jumblesPlayedTodayCount} jumbles played today - " +
"{multiplier} multiplier - {minPlaycount} min playcount - {finalMinPlaycount} final min playcount",
topArtists.Count, jumblesPlayedToday.Count, multiplier, minPlaycount, finalMinPlaycount);
topArtists.Count, recentJumbles.Count, multiplier, minPlaycount, finalMinPlaycount);

if (total == 0)
if (eligibleArtists.Count == 0)
{
return (null, 0);
}
TopArtist fallbackArtist = null;
if (topArtists.Count > 0)
{
var fallBackIndex = RandomNumberGenerator.GetInt32(topArtists.Count);
fallbackArtist = topArtists
.Where(w => !recentJumblesHashset.Contains(w.ArtistName))
.OrderByDescending(o => o.UserPlaycount)
.ElementAtOrDefault(fallBackIndex);
}

var random = RandomNumberGenerator.GetInt32(total);
return fallbackArtist != null ? (fallbackArtist.ArtistName, fallbackArtist.UserPlaycount) : (null, 0);
}

return (topArtists[random].ArtistName, topArtists[random].UserPlaycount);
var randomIndex = RandomNumberGenerator.GetInt32(eligibleArtists.Count);
return (eligibleArtists[randomIndex].ArtistName, eligibleArtists[randomIndex].UserPlaycount);
}

public async Task<JumbleSession> StartJumbleGame(int userId, ContextModel context, JumbleType jumbleType,
Expand Down Expand Up @@ -152,24 +178,21 @@ public async Task<JumbleSession> GetJumbleSessionForChannelId(ulong discordChann
.FirstOrDefaultAsync(f => f.DiscordChannelId == discordChannelId);
}

public async Task<HashSet<string>> GetJumbleSessionsCountToday(int userId)
public async Task<List<JumbleSession>> GetJumbleSessionsCountToday(int userId)
{
const string sql = "SELECT correct_answer FROM public.jumble_sessions " +
"WHERE starter_user_id = @userId AND date_started >= date_trunc('day', current_date); ";
const string sql = "SELECT correct_answer, date_started FROM public.jumble_sessions " +
"WHERE starter_user_id = @userId LIMIT 200 ";

DefaultTypeMap.MatchNamesWithUnderscores = true;
await using var connection = new NpgsqlConnection(this._botSettings.Database.ConnectionString);
await connection.OpenAsync();

var jumblesPlayedToday = await connection.QueryAsync<string>(sql, new
var jumblesPlayedToday = await connection.QueryAsync<JumbleSession>(sql, new
{
userId
});

return jumblesPlayedToday
.GroupBy(g => g)
.Select(s => s.Key)
.ToHashSet(StringComparer.OrdinalIgnoreCase);
return jumblesPlayedToday.ToList();
}

public async Task CancelToken(ulong channelId)
Expand Down Expand Up @@ -423,7 +446,9 @@ public static int GetLevenshteinDistance(string source1, string source2)
matrix[i - 1, j - 1] + cost);
}
}

return matrix[source1Length, source2Length];
}


}
41 changes: 41 additions & 0 deletions src/FMBot.Bot/TextCommands/GameCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,45 @@ public async Task JumbleAsync()
});
}

//[Command("pixelate", RunMode = RunMode.Async)]
//[Summary("Play the album Jumble game.")]
//[UsernameSetRequired]
//[CommandCategories(CommandCategory.Other)]
//[Alias("px")]
public async Task PixelateAsync()
{
var contextUser = await this._userService.GetUserSettingsAsync(this.Context.User);
var prfx = this._prefixService.GetPrefix(this.Context.Guild?.Id);

try
{
var context = new ContextModel(this.Context, prfx, contextUser);
var cancellationTokenSource = new CancellationTokenSource();
var response = await this._gameBuilders.StartJumbleFirstWins(context, contextUser.UserId, cancellationTokenSource);

if (response.CommandResponse == CommandResponse.Cooldown)
{
_ = Task.Run(() => this.Context.Message.AddReactionAsync(new Emoji("")));
this.Context.LogCommandUsed(response.CommandResponse);
return;
}

var responseId = await this.Context.SendResponse(this.Interactivity, response);
this.Context.LogCommandUsed(response.CommandResponse);

if (responseId.HasValue && response.GameSessionId.HasValue)
{
await this._gameService.JumbleAddResponseId(response.GameSessionId.Value, responseId.Value);
await JumbleTimeExpired(context, responseId.Value, cancellationTokenSource.Token, response.GameSessionId.Value);
}
}
catch (OperationCanceledException)
{
}
catch (Exception e)
{
await this.Context.HandleCommandException(e);
}
}

}

0 comments on commit 8f90ef8

Please sign in to comment.