1
Fork 0

Generalize code to more scoring systems

This commit is contained in:
prescientmoon 2024-08-20 19:24:32 +02:00
parent 62949004f2
commit 4ed3fe276b
Signed by: prescientmoon
SSH key fingerprint: SHA256:UUF9JT2s8Xfyv76b8ZuVL7XrmimH4o49p4b+iexbVH4
10 changed files with 375 additions and 226 deletions

View file

@ -4,7 +4,7 @@ use sqlx::query;
use crate::{
arcaea::chart::Side,
context::{Context, Error},
get_user,
get_user, play_from_db_record,
recognition::fuzzy_song_name::guess_song_and_chart,
};
use std::io::Cursor;
@ -20,13 +20,9 @@ use plotters::{
style::{IntoFont, TextStyle, BLUE, WHITE},
};
use poise::CreateReply;
use sqlx::query_as;
use crate::{
arcaea::{
play::DbPlay,
score::{Score, ScoringSystem},
},
arcaea::score::{Score, ScoringSystem},
user::discord_it_to_discord_user,
};
@ -121,13 +117,18 @@ async fn best(
let user = get_user!(&ctx);
let (song, chart) = guess_song_and_chart(&ctx.data(), &name)?;
let play = query_as!(
DbPlay,
let play = query!(
"
SELECT * FROM plays
WHERE user_id=?
AND chart_id=?
ORDER BY score DESC
SELECT
p.id, p.chart_id, p.user_id, p.created_at,
p.max_recall, p.far_notes, s.score
FROM plays p
JOIN scores s ON s.play_id = p.id
WHERE s.scoring_system='standard'
AND p.user_id=?
AND p.chart_id=?
ORDER BY s.score DESC
LIMIT 1
",
user.id,
chart.id
@ -139,8 +140,8 @@ async fn best(
"Could not find any scores for {} [{:?}]",
song.title, chart.difficulty
)
})?
.into_play();
})?;
let play = play_from_db_record!(chart, play);
let (embed, attachment) = play
.to_embed(
@ -176,13 +177,17 @@ async fn plot(
let (song, chart) = guess_song_and_chart(&ctx.data(), &name)?;
// SAFETY: we limit the amount of plotted plays to 1000.
let plays = query_as!(
DbPlay,
let plays = query!(
"
SELECT * FROM plays
WHERE user_id=?
AND chart_id=?
ORDER BY created_at ASC
SELECT
p.id, p.chart_id, p.user_id, p.created_at,
p.max_recall, p.far_notes, s.score
FROM plays p
JOIN scores s ON s.play_id = p.id
WHERE s.scoring_system='standard'
AND p.user_id=?
AND p.chart_id=?
ORDER BY s.score DESC
LIMIT 1000
",
user.id,
@ -204,7 +209,7 @@ async fn plot(
let max_time = plays.iter().map(|p| p.created_at).max().unwrap();
let mut min_score = plays
.iter()
.map(|p| p.clone().into_play().score(scoring_system))
.map(|p| play_from_db_record!(chart, p).score(scoring_system))
.min()
.unwrap()
.0 as i64;
@ -228,7 +233,7 @@ async fn plot(
{
let root = BitMapBackend::with_buffer(&mut buffer, (width, height)).into_drawing_area();
let mut chart = ChartBuilder::on(&root)
let mut chart_buider = ChartBuilder::on(&root)
.margin(25)
.caption(
format!("{} [{:?}]", song.title, chart.difficulty),
@ -241,7 +246,7 @@ async fn plot(
min_score..max_score,
)?;
chart
chart_buider
.configure_mesh()
.light_line_style(WHITE)
.y_label_formatter(&|s| format!("{}", Score(*s as u32)))
@ -261,7 +266,7 @@ async fn plot(
.map(|play| {
(
play.created_at.and_utc().timestamp_millis(),
play.into_play().score(scoring_system),
play_from_db_record!(chart, play).score(scoring_system),
)
})
.collect();
@ -269,12 +274,12 @@ async fn plot(
points.sort();
points.dedup();
chart.draw_series(LineSeries::new(
chart_buider.draw_series(LineSeries::new(
points.iter().map(|(t, s)| (*t, s.0 as i64)),
&BLUE,
))?;
chart.draw_series(points.iter().map(|(t, s)| {
chart_buider.draw_series(points.iter().map(|(t, s)| {
Circle::new((*t, s.0 as i64), 3, plotters::style::Color::filled(&BLUE))
}))?;
root.present()?;

View file

@ -1,11 +1,11 @@
use std::time::Instant;
use crate::arcaea::play::{CreatePlay, Play};
use crate::arcaea::play::CreatePlay;
use crate::arcaea::score::Score;
use crate::context::{Context, Error};
use crate::recognition::recognize::{ImageAnalyzer, ScoreKind};
use crate::user::{discord_it_to_discord_user, User};
use crate::{edit_reply, get_user, timed};
use crate::{edit_reply, get_user, play_from_db_record, timed};
use image::DynamicImage;
use poise::serenity_prelude::futures::future::join_all;
use poise::serenity_prelude::CreateMessage;
@ -117,11 +117,11 @@ pub async fn magic(
let maybe_fars =
Score::resolve_distibution_ambiguities(score, note_distribution, chart.note_count);
let play = CreatePlay::new(score, &chart)
let play = CreatePlay::new(score)
.with_attachment(file)
.with_fars(maybe_fars)
.with_max_recall(max_recall)
.save(&ctx.data(), &user)
.save(&ctx.data(), &user, &chart)
.await?;
// }}}
// }}}
@ -220,12 +220,16 @@ pub async fn show(
let res = query!(
"
SELECT
p.id,p.chart_id,p.user_id,p.score,p.zeta_score,
p.max_recall,p.created_at,p.far_notes,
p.id, p.chart_id, p.user_id, p.created_at,
p.max_recall, p.far_notes, s.score,
u.discord_id
FROM plays p
FROM plays p
JOIN scores s ON s.play_id = p.id
JOIN users u ON p.user_id = u.id
WHERE p.id=?
WHERE s.scoring_system='standard'
AND p.id=?
ORDER BY s.score DESC
LIMIT 1
",
id
)
@ -233,24 +237,12 @@ pub async fn show(
.await
.map_err(|_| format!("Could not find play with id {}", id))?;
let play = Play {
id: res.id as u32,
chart_id: res.chart_id as u32,
user_id: res.user_id as u32,
score: Score(res.score as u32),
zeta_score: Score(res.zeta_score as u32),
max_recall: res.max_recall.map(|r| r as u32),
far_notes: res.far_notes.map(|r| r as u32),
created_at: res.created_at,
discord_attachment_id: None,
creation_ptt: None,
creation_zeta_ptt: None,
};
let (song, chart) = ctx.data().song_cache.lookup_chart(res.chart_id as u32)?;
let play = play_from_db_record!(chart, res);
let author = discord_it_to_discord_user(&ctx, &res.discord_id).await?;
let user = User::by_id(&ctx.data().db, play.user_id).await?;
let (song, chart) = ctx.data().song_cache.lookup_chart(play.chart_id)?;
let (embed, attachment) = play
.to_embed(&ctx.data().db, &user, song, chart, i, Some(&author))
.await?;

View file

@ -13,6 +13,7 @@ use crate::{
chart::Level,
jacket::BITMAP_IMAGE_SIZE,
play::{compute_b30_ptt, get_best_plays},
rating::rating_as_float,
score::ScoringSystem,
},
assert_is_pookie,
@ -55,14 +56,15 @@ async fn best_plays(
get_best_plays(
&user_ctx.db,
&user_ctx.song_cache,
&user,
user.id,
scoring_system,
if require_full {
grid_size.0 * grid_size.1
} else {
grid_size.0 * (grid_size.1.max(1) - 1) + 1
} as usize,
(grid_size.0 * grid_size.1) as usize
(grid_size.0 * grid_size.1) as usize,
None
)
.await?
);
@ -287,7 +289,7 @@ async fn best_plays(
// }}}
// {{{ Display status text
with_font(&EXO_FONT, |faces| {
let status = play.short_status(chart).ok_or_else(|| {
let status = play.short_status(scoring_system, chart).ok_or_else(|| {
format!(
"Could not get status for score {}",
play.score(scoring_system)
@ -379,7 +381,7 @@ async fn best_plays(
style,
&format!(
"{:.2}",
play.play_rating(scoring_system, chart.chart_constant) as f32 / 100.0
play.play_rating_f32(scoring_system, chart.chart_constant)
),
)?;
@ -415,7 +417,7 @@ async fn best_plays(
.attachment(CreateAttachment::bytes(out_buffer, "b30.png"))
.content(format!(
"Your ptt is {:.2}",
compute_b30_ptt(scoring_system, &plays) as f32 / 100.0
rating_as_float(compute_b30_ptt(scoring_system, &plays))
));
ctx.send(reply).await?;