Heads up: This post will contain math.
So I'm trying to build an accuracy calculator for my rhythm project, but the equation to calculate the accuracy requires division by 0. In words, the equasion goes like this:
Find the average of the time between the keypress and the time they key was supposed to be pressed for every keypresses since the song began
Subtract the average by the true value
Divide that by the true value
Multiply by 100
This is all well and good, but in my case, the true value is 0, because a second difference of 0 seconds means the key was hit at the perfect time. But of course, you can't divide by 0, and doing so seems to result in math.huge.
How would I go about resolving this?
If you need my code, here you go:
local sounds = game.SoundService
local CAS = game.ContextActionService
local rep = game.ReplicatedStorage
local getLevel = require(rep.GetLevel)
local beat = 0
local multiplier = 1000
local active = {}
local secDifs = {}
local testLvl = getLevel.GetLevel('TestingLevel')
local selectedLvl = testLvl
local beatDur = 60 / selectedLvl['BPM']
local TPU = 1 / selectedLvl['Speed'] -- Short for Time per unit
local function ProcessKeyPress(color)
print(color..' has been pressed!')
local correctNote
for i, v in ipairs(active) do
if v[1] == color then
correctNote = v
end
end
if correctNote ~= nil then
-- This is the part to focus on! -- This is the part to focus on! -- This is the part to focus on!
print('Nice!')
local secDif = math.ceil((math.abs(beat - correctNote[2]) * beatDur) * multiplier)
table.insert(secDifs, secDif)
local all = 0
for i, v in ipairs(secDifs) do
all += v
end
local average = all / #secDifs
local accuracy = ((average - 0) / 0) * 100
print(accuracy)
rep.AddPoints:Fire(secDif)
print(beat, correctNote[2], beat - correctNote[2], math.abs(beat - correctNote[2]), (math.abs(beat - correctNote[2]) * beatDur), ((math.abs(beat - correctNote[2]) * beatDur) * multiplier))
print('beat: '..tostring(beat), 'correctNote[2]: '..tostring(correctNote[2]), 'secDif before math.ceil: '..tostring((math.abs(beat - correctNote[2]) * beatDur) * multiplier), 'secDif: ', tostring(secDif))
else
print('Miss!')
end
local closest = workspace.Notes:GetChildren()[1]
if closest ~= nil then
for i, v in ipairs(workspace.Notes:GetChildren()) do
if math.floor(math.abs(v.Position.X)) < math.floor(closest.Position.X) and v.Name == color then
--closest.Color = Color3.new(1, 0, 0)
closest = v
end
end
if math.ceil(math.abs(closest.Position.X) - workspace.Strumline[color].Position.X) <= 3 then
coroutine.resume(coroutine.create(function()
closest.Color = Color3.new(1, 1, 0)
--wait(0.3)
closest:Destroy()
end))
end
end
end
rep.TempStart.Event:Wait()
print('eyey')
local keybinds = {
Red = nil,
Blue = nil,
Green = nil,
White = nil
}
for i, keybind in ipairs(rep.Keybinds:GetChildren()) do
for i, enum in ipairs(Enum.KeyCode:GetEnumItems()) do
if string.sub(tostring(enum), 14, string.len(tostring(enum))) == keybind.Value then
keybinds[keybind.Name] = enum
end
end
end
selectedLvl['Song']:Play()
CAS:BindAction('Press red', function(nagareteku, instate, toki, no, naka, de, demo)
if instate ~= Enum.UserInputState.Begin then return end
ProcessKeyPress('Red')
end, false, keybinds['Red'])
CAS:BindAction('Press blue', function(nagareteku, instate, toki, no, naka, de, demo)
if instate ~= Enum.UserInputState.Begin then return end
ProcessKeyPress('Blue')
end, false, keybinds['Blue'])
CAS:BindAction('Press Green', function(nagareteku, instate, toki, no, naka, de, demo)
if instate ~= Enum.UserInputState.Begin then return end
ProcessKeyPress('Green')
end, false, keybinds['Green'])
CAS:BindAction('Press white', function(nagareteku, instate, toki, no, naka, de, demo)
if instate ~= Enum.UserInputState.Begin then return end
ProcessKeyPress('White')
end, false, keybinds['White'])
local stTick = tick()
local permT = tick()
game:GetService('RunService').Heartbeat:Connect(function()
beat += math.floor(((tick() - stTick) / beatDur) * 1000) / 1000 -- Reduce time to 3 decimals
stTick = tick()
end)
for i, v in ipairs(selectedLvl['Chart']) do
local activateKeyPress = coroutine.create(function()
print(v[1]..' wait duration: '..tostring((v[2] * beatDur) - TPU * 3), 'unactivate wait duration: '..tostring(((v[2] * beatDur) - TPU * 3) + (TPU * 6)))
wait((v[2] * beatDur) - TPU * 3)
table.insert(active, v)
print(v[1]..' active')
wait(TPU * 6)
print(v[1]..' not active')
for I, V in ipairs(active) do
if v == V then
rep.AddPoints:Fire(-25)
table.remove(active, I)
end
end
end)
local createKeys = coroutine.create(function()
wait((v[2] * beatDur) - (TPU * 20))
local keyClone = workspace.Strumline[v[1]]:Clone()
keyClone.Parent = workspace.Notes
keyClone.Transparency = 0
print(workspace.Strumline[v[1]])
keyClone.Position = workspace.Strumline[v[1]].Position - Vector3.new(20, 0, 0)
local tween = game.TweenService:Create(keyClone, TweenInfo.new(
TPU * 40,
Enum.EasingStyle.Linear,
Enum.EasingDirection.InOut
), {Position = workspace.Strumline[v[1]].Position + Vector3.new(20, 0, 0)})
tween:Play()
end)
coroutine.resume(activateKeyPress)
coroutine.resume(createKeys)
end
If you need the module script code and the bindable event code, here you also go:
local levels = {
TestingLevel = {
Song = game.SoundService.Tem,
Speed = 32, -- 32 units per second, or 32u/s
BPM = 120,
Chart = { -- Every table in the Chart represents a note. Properties: string button, num beat, num beatToReleaseAt
{'Red', 10},
{'Green', 11},
{'Blue', 12},
{'White', 13},
{'Blue', 14},
{'Green', 15},
{'Red', 16, 21},
{'Green', 17},
{'Blue', 18},
{'White', 19},
{'Blue', 20},
{'Green', 21},
{'Red', 22, 27},
{'Green', 24},
{'Blue', 25},
{'White', 26},
{'Blue', 27},
{'Green', 28},
{'Red', 29, 34},
{'Green', 30},
{'Blue', 31},
{'White', 32},
{'Blue', 33},
{'Green', 34},
{'Red', 35, 45}
}
}
}
local module = {}
module.GetLevel = function(name)
return levels[name]
end
return module
e
local rep = game.ReplicatedStorage
local frame = script.Parent
local points = 0
rep.AddPoints.Event:Connect(function(pointsToAdd)
points += pointsToAdd
frame.Score.Text = 'Points: '..tostring(points)
print(points)
end)
rep.ChangeAccuracy.Event:Connect(function(accuracy) -- Currently unused
frame.Accuracy = tostring(accuracy)..'%'
end)
rep.TempStart.Event:Connect(function()
script.Parent.Visible = true
end)
Anything is appreciated!

4 comments
Just answering blindly here; cant you just use an id statement? If its 0 then make it 1 or something so then when it multiplies, it gives the highest score.
The issue here is not whether the players pressed the key with a second difference of 0. No matter the difference, the equation requires division by 0 unless I change something about the equasion.
Then change the equation. If your not smart enough to do it the first time, you will figure it out eventually.
How can I change the equation to still provide an accurate accuracy if the true value is 0?