Generalize code to more scoring systems
This commit is contained in:
parent
62949004f2
commit
4ed3fe276b
10 changed files with 375 additions and 226 deletions
|
@ -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()?;
|
||||
|
|
|
@ -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?;
|
||||
|
|
|
@ -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?;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue