From cfaa3101e0501842a3972eb1779a9ed2c1e1b20a Mon Sep 17 00:00:00 2001 From: Dan Guzek Date: Sat, 21 Oct 2017 14:49:46 -0400 Subject: [PATCH] fix rounding error with ScreenEval's scatter plot Previously, I was rounding offset values to 3 decimal places before storing them in the SL table for later retrieval on ScreenEvaluation. This was problematic! For example, if a particular offset was -0.04250000, it should be categorized as a W2 judgment (ITG excellent), but by rounding it to three decimals it would become -0.043, which would be a W3 (ITG great). Thus, this commit changes JudgmentOffsetTracking.lua to store the full, un-rounded offset values in the order they occur in the sequential_offsets table within the SL table. This *should* resolve the scatter plot issue in which judgments on the edge of a TimingWindow could be rounded into the next-worse-TimingWindow. - - - - - Still, for ScreenEvaluation's histogram, the data is easier to process when there is a finite quantity of decimal places per offset value (three, currently). This is because I need to know how many of each offset a player earned which is represented by how tall the histogram is. How many +0.001 offsets? How many -0.001 offsets? How many +0.002 offsets? How many -0.002 offsets? Etc. Statistical buckets, if you will. For the histogram then, instead of rounding, I'm currently opting to truncate everything beyond three decimal places by multiplying by 1000 math.floor diving by 1000 But! Some TimingWindow boundaries need at least four digits of precision (W1 for Competitive is 0.0215 for example). So this system of truncating past three digits so we can organize offsets into buckets for the histogram is flawed. I intend to think about and investigate options here soon. The easy solution is to increase the histogram's "resolution" to 4 decimal places, which would mean 10x as many buckets, and 10x as many bars being drawn in the ActorMultiVertex. Performance could be an issue. --- .../PerPlayer/Pane4/default.lua | 28 +++++++++++++++++-- .../JudgmentOffsetTracking.lua | 24 +++++----------- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/BGAnimations/ScreenEvaluation common/PerPlayer/Pane4/default.lua b/BGAnimations/ScreenEvaluation common/PerPlayer/Pane4/default.lua index 46be2344f..2ed9de837 100644 --- a/BGAnimations/ScreenEvaluation common/PerPlayer/Pane4/default.lua +++ b/BGAnimations/ScreenEvaluation common/PerPlayer/Pane4/default.lua @@ -3,7 +3,7 @@ local pn = ToEnumShortString(player) -- table of offet values obtained during this song's playthrough -- obtained via ./BGAnimations/ScreenGameplay overlay/JudgmentOffsetTracking.lua -local offsets = SL[pn].Stages.Stats[SL.Global.Stages.PlayedThisGame + 1].timing_offsets +local sequential_offsets = SL[pn].Stages.Stats[SL.Global.Stages.PlayedThisGame + 1].sequential_offsets local pane_width, pane_height = 300, 180 -- --------------------------------------------- @@ -21,7 +21,31 @@ local num_judgments_available = (SL.Global.ActiveModifiers.DecentsWayOffs=="Dece local worst_window = SL.Preferences[SL.Global.GameMode]["TimingWindowSecondsW"..num_judgments_available] -- --------------------------------------------- --- first, smooth the offset distribution and store values in a new table, smooth_offsets +-- sequential_offsets is a table of all timing offsets in the order they were earned. +-- The sequence is important for the Scatter Plot, but irrelevant here; we are only really +-- interested in how many +0.001 offsets were earned, how many -0.001, how many +0.002, etc. +-- So, we loop through sequential_offsets, and tally offset counts into a new offsets table. +local offsets = {} +local val + +for t in ivalues(sequential_offsets) do + -- the first value in t is CurrentMusicSeconds when the offset occurred, which we don't need here + -- the second value in t is the offset value or the string "Miss" + val = t[2] + + if val ~= "Miss" then + val = (math.floor(val*1000))/1000 + + if not offsets[val] then + offsets[val] = 1 + else + offsets[val] = offsets[val] + 1 + end + end +end + +-- --------------------------------------------- +-- next, smooth the offset distribution and store values in a new table, smooth_offsets local smooth_offsets = {} -- gaussian distribution for smoothing the histogram's jagged peaks and troughs diff --git a/BGAnimations/ScreenGameplay overlay/JudgmentOffsetTracking.lua b/BGAnimations/ScreenGameplay overlay/JudgmentOffsetTracking.lua index b016a5e96..f29232974 100644 --- a/BGAnimations/ScreenGameplay overlay/JudgmentOffsetTracking.lua +++ b/BGAnimations/ScreenGameplay overlay/JudgmentOffsetTracking.lua @@ -1,5 +1,4 @@ local player = ... -local offsets = {} local sequential_offsets = {} return Def.Actor{ @@ -8,26 +7,17 @@ return Def.Actor{ if params.HoldNoteScore then return end if params.TapNoteOffset then - local offset = round(params.TapNoteOffset, 3) + -- if the judgment was a Miss, store the string "Miss" as offset instead of 0 + -- for all other judgments, store the numerical offset as provided by the engine + local offset = params.TapNoteScore == "TapNoteScore_Miss" and "Miss" or params.TapNoteOffset - if params.TapNoteScore ~= "TapNoteScore_Miss" then - if not offsets[offset] then - offsets[offset] = 1 - else - offsets[offset] = offsets[offset] + 1 - end - else - offset = "Miss" - end - - -- store judgment offsets (including misses) in an indexed table as they come - -- also store the CurrentMusicSeconds - sequential_offsets[#sequential_offsets+1] = { GAMESTATE:GetCurMusicSeconds(), offset } + -- store judgment offsets (including misses) in an indexed table as they come + -- also store the CurMusicSeconds for Evaluation's scatter plot + sequential_offsets[#sequential_offsets+1] = { GAMESTATE:GetCurMusicSeconds(), offset } end end, OffCommand=function(self) local storage = SL[ToEnumShortString(player)].Stages.Stats[SL.Global.Stages.PlayedThisGame + 1] - storage.timing_offsets = offsets - storage.sequential_offsets = sequential_offsets + storage.sequential_offsets = sequential_offsets end } \ No newline at end of file