Thread Tools Display Modes
09-07-12, 01:34 PM   #1
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
math logic bomb

I am working with random numbers, with the intent to attach them to a frame that moves. Never mind the code issues of moving the frame, I am struggling with the math. The average of all the numbers is what moves the pointer frame. So far so good.

The trouble is the end number has to be between 1 and 21, inclusive. Here is a hard-coded example.
Lua Code:
  1. local pointer = 97846.7851 -- this would actually be random
  2. if pointer < 0 then
  3.     pointer = pointer * -1 -- can't have neg numbers because frames are numbered in the positive
  4. end
  5. pointer = mod(pointer, 21) -- this won't work, because 0 is a possibility
  6. pointer = round() -- local function that rounds better than floor or ceil
  7. -- attach pointer to frame
Is it possible to do something like the following? I've tried Googling for a hint, but haven't found anything. Also, I'm not sure if mod(pointer, 21) is correct either.
Lua Code:
  1. pointer = mod(pointer, 21) > 0
  Reply With Quote
09-07-12, 01:47 PM   #2
Haleth
This Space For Rent
 
Haleth's Avatar
Featured
Join Date: Sep 2008
Posts: 1,173
You can't have a mathematically correct average of a set of numbers if you're going to limit the average below the highest number of the set.

Why don't you limit your random numbers (e.g. random(21)) then divide the end result by the amount of numbers?

Last edited by Haleth : 09-07-12 at 01:51 PM.
  Reply With Quote
09-07-12, 02:22 PM   #3
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
The random numbers aren't generated from math.random. They are the average of all the mana deltas within x amount of time. For example, say you gain or lose the following amount of mana:
  • 100
  • -500
  • 450
  • 800
Which sums up to 850. The average is 212.5. I need to convert 212.5 into a spread from 1 to 21 plot points. Because there is no way to determine ahead of time mana deltas, I have to add them as I get them, then average them.
  Reply With Quote
09-07-12, 02:38 PM   #4
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
Is it a sliding window that always contains 21 datapoints?
(ie starts plotting when you have at least 21 datapoints and from that point on displays the last 21)
  Reply With Quote
09-07-12, 02:56 PM   #5
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
If I understand you correctly, then yes, sort of. Think of the PvP capture bar, where it swings between Horde and Alliance. The vertical slider is my plot point, and moves the slider based on the mana returns. Obviously, a mana delta value measured in hundreds, or thousands, isn't any good; the graph would have to be huge, which is why I am making it 21 segments. The main frame behind has a width of 210, so breaking it up into 21 chunks makes setting a width of each segment easy.

That is why I am trying to figure out the math to convert the average deltas into somewhere on a 21 segment frame. I have the average, deltas, frame segments, all that built. It is just the math that converts I am having a challenge with.

Does that make more sense? Oh, in fact, I AM using the PvP capture bar texture.
  Reply With Quote
09-07-12, 03:50 PM   #6
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
Actually the math would be simple if I could understand what the bar represents.
I'm not sure you have decided that yet yourself

I mean ok it's 21 segments, let's say 10 'negative' segments (losing mana) 1 'zero' segment (not losing or gaining), 10 'positive' segments (gaining mana)
|----------|-|----------|

What amount does the total width of the bar represent (splitting it in 21 segments aside, there must be something to divide to 21 parts)
What is a meaningful number for the user to be at the left end of the bar (highest rate of losing mana) to the right end of the bar (highest rate of gaining mana)?

Edit: What I posted above should get you an average MPS over 21 seconds if your deltas are 1/sec.
There's no way to place -215 MPS (or +450 MPS) on a bar if you can't know what's the range of the bar,
that's not a math problem it's a logic problem.
Tell me what the full range of the bar corresponds to and I can help with the rest.

Last edited by Dridzt : 09-07-12 at 03:55 PM.
  Reply With Quote
09-07-12, 07:35 PM   #7
Jamash
A Fallenroot Satyr
 
Jamash's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2006
Posts: 20
You can't scale your sliding window average to your display range until you figure out what your display range is. What are the minimum and maximum values you intend to display? What will you do with values outside that range? Does the minimum = (-the maximum)?

Is the range fixed value? Is it determined by the values in the sliding window? Does it depend on values that have passed out of the sliding window?

Once you have answered that, scaling the input value (the sliding window average) to an output value (an integer between -10 and +10, or equivalently 0 to 20, inclusive) is easy.
  Reply With Quote
09-07-12, 09:28 PM   #8
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
Hrrmph... proof of concept.

Tried to think as a caster

<<Center>> = "Rest"
<< Left = "How fast to OOM at current mana expenditure" (the more left the slider the faster we're going oom)
Right >> = "How fast to mana-full at current mana-gain" (the more right, the faster we're gaining full mana)

This makes it so we don't need a static MPS range, rather the user can set a "warning time" before the slider will start moving.
In example code warning time = 30, 10 segments for each side, slider moves 1 notch at 30sec to OOM, another notch at 27sec to OOM and so on until full left at 3sec to OOM.
Similar for right side with slider closer to center for slow mana-regen, further right for mana-tide/innervate etc.
Code:
local frame = CreateFrame("Frame")
frame:SetScript("OnEvent", 
function(self,event,...) 
	return self[event] and self[event](...)
end)
frame:RegisterEvent("PLAYER_LOGIN")

-- These would be options
local averageOver = 20 -- delta segments to average
local polling = 0.5 -- changing this changes the averaging timeframe (10*1sec segments = 10sec, 10*2sec segments = 20sec to get rolling average etc)
local time_to_either_end = 30 -- middle of bar to either end in seconds (leftmost = oom, rightmost = full mana)
local bar_segments = {10,1,10} -- 10 negative, 1 steady, 10 positive

-- function upvalues
local tinsert, tremove, ipairs, floor, abs, max = tinsert, tremove, ipairs, floor, abs, max
local UnitPower, UnitPowerMax = UnitPower, UnitPowerMax

local mDeltas = {} -- temp table
local lastMana
local function getRollingMPS()
	local mps_per_sec
	local mana = UnitPower("player",SPELL_POWER_MANA)
	local now = GetTime()
	local delta = {mana-lastMana, now}
	lastMana = mana
	table.insert(mDeltas, 1, delta) -- always insert at first position
	if mDeltas[averageOver+1] then mDeltas[averageOver+1] = nil end -- remove the tail to keep the size down
	local sum, startt, endt = 0
	for i,delta in ipairs(mDeltas) do
		if i==1 then
			endt = delta[2]
		else
			startt = delta[2]
		end
		sum = sum + delta[1]
		if i==averageOver then break end
	end
	mps_per_sec = (startt and endt and startt~=endt) and sum/(endt-startt) or 0
	return mps_per_sec
end

local function Update(self, elapsed)
	self.lastTime = self.lastTime + elapsed
	if self.lastTime >= polling then
		local barsegment, time_per_segment -- -10.....-1,0,1.....10
		local rollingMPS = getRollingMPS()
		local manaMax = UnitPowerMax("player",SPELL_POWER_MANA)
		local mana = UnitPower("player",SPELL_POWER_MANA)
		-- edge cases first: oom, full mana, 0 mps
		if rollingMPS == 0 then
			if mana==manaMax then
				barsegment = 0
			elseif mana == 0 then
				barsegment = -bar_segments[1]
			end
		else
			local mana_to_full = manaMax - mana
			if rollingMPS > 0 then -- gaining mana
				if mana_to_full > 0 then
					local time_to_full = mana_to_full/rollingMPS
					time_per_segment = time_to_either_end/bar_segments[3]
					barsegment = floor((bar_segments[3]+1)-(min(max(time_to_full,time_per_segment),time_to_either_end)/time_per_segment)+0.5)
				else
					barsegment = 0
				end
			else -- losing mana
				if mana == 0 then
					barsegment = -bar_segments[1]
				else
					local time_to_empty = mana/abs(rollingMPS)
					time_per_segment = time_to_either_end/bar_segments[1]
					barsegment = -floor((bar_segments[1]+1)-(min(max(time_to_empty,time_per_segment),time_to_either_end)/time_per_segment)+0.5)
				end
			end
		end
		barsegment = barsegment or 0
 		frame.slider:SetValue(barsegment)
 		_G[frame.slider:GetName().."Text"]:SetText(barsegment)
		self.lastTime = 0
	end
end

local updateEngine = CreateFrame("Frame")
function frame.PLAYER_LOGIN()
	local slider = CreateFrame("Slider","TestRollingManaSlider",UIParent,"OptionsSliderTemplate")
	slider:SetPoint("TOP",0,-50)
	slider:SetSize(200,30)
	slider:SetMinMaxValues(-10,10)
	slider:SetValueStep(1)
	slider:SetValue(0)
	slider:EnableMouse(false)
	_G[slider:GetName().."Low"]:SetText("-10")
	_G[slider:GetName().."Text"]:SetText("0")
	_G[slider:GetName().."High"]:SetText("10")
	frame.slider = slider
	updateEngine.lastTime = 0
	lastMana = UnitPower("player",SPELL_POWER_MANA)
	updateEngine:SetScript("OnUpdate", Update)
end
  Reply With Quote
09-08-12, 03:24 AM   #9
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Proof of concept is fun! Anyway, I thought I would post my code, before attempting to add Dridzt's modifications, just to see where I am at. The first pastebin is my entire code, complete with unnecessary, sometimes commented out parts. The second is pared down to include just the relevant stuff.

http://pastebin.com/A3w443DG -- full code. math breaks at line 476
http://pastebin.com/12RqSrk1 -- slimmed down. math breaks down at line 120
  Reply With Quote
09-08-12, 03:35 AM   #10
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Originally Posted by Dridzt View Post
I mean ok it's 21 segments, let's say 10 'negative' segments (losing mana) 1 'zero' segment (not losing or gaining), 10 'positive' segments (gaining mana)
|----------|-|----------|
That is what I was thinking, yes.

Originally Posted by Dridzt View Post
What is a meaningful number for the user to be at the left end of the bar (highest rate of losing mana) to the right end of the bar (highest rate of gaining mana)?
I was wondering about that back when I started this project. Given that in Pandaria, I am seeing values of +/-1000 right now, I would suggest that is the limit; however, the values spike even higher during Innervate, ShadowFiend, potions, etc, and might go the opposite way if a mob drains mana. This needs to be future-proofed. Any suggestions on safe upper and lower limits?

Originally Posted by Dridzt View Post
Edit: What I posted above should get you an average MPS over 21 seconds if your deltas are 1/sec.
There's no way to place -215 MPS (or +450 MPS) on a bar if you can't know what's the range of the bar,
that's not a math problem it's a logic problem.
Tell me what the full range of the bar corresponds to and I can help with the rest.
Whoa, are you telling me that LOGIC has something to do with MATH? UNPOSSIBLE! LOL see above paragraph.
  Reply With Quote
09-08-12, 01:40 PM   #11
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
ACM Slim modified
http://pastebin.com/fGJRa9Xg
  Reply With Quote
09-08-12, 02:33 PM   #12
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Thank you Dridzt. Will drop it in and see what happens. I have some other bugs that need squashing, and they are preventing the addon from working in the first place, but one way or the other, I will post back and let you know.
  Reply With Quote
09-08-12, 02:33 PM   #13
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,325
Originally Posted by myrroddin View Post
I was wondering about that back when I started this project. Given that in Pandaria, I am seeing values of +/-1000 right now, I would suggest that is the limit; however, the values spike even higher during Innervate, ShadowFiend, potions, etc, and might go the opposite way if a mob drains mana. This needs to be future-proofed. Any suggestions on safe upper and lower limits?
If you want a static limit, I'd say the entire mana pool as a base since you can never lose or gain more than the entire pool at a time. Otherwise, you could try to keep track of a peak value and adjust accordingly to that.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote
09-08-12, 03:09 PM   #14
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Originally Posted by SDPhantom View Post
If you want a static limit, I'd say the entire mana pool as a base since you can never lose or gain more than the entire pool at a time. Otherwise, you could try to keep track of a peak value and adjust accordingly to that.
I was thinking of that originally, but that seemed extreme. Besides, I am not dealing with mana gains or losses; I am dealing with the difference between your current mana and the mana quantity you had during last update, or mana delta. This is a much smaller amount.

The idea for ACM came from a guild healer that wanted to know how effective he was at conserving mana partway though a fight. He can see his current mana on his unit frame. "Am I actually conserving mana, and how effectively am I conserving it?" was his question.

SDPhantom, if 1100 is too low, I can either hard code it up, or take Dridzt's suggestion and make it a user setting.
  Reply With Quote
09-08-12, 08:38 PM   #15
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,325
Originally Posted by myrroddin View Post
I was thinking of that originally, but that seemed extreme. Besides, I am not dealing with mana gains or losses; I am dealing with the difference between your current mana and the mana quantity you had during last update, or mana delta. This is a much smaller amount.
Any way you look at it, by definition, delta and gain/loss is the exact same thing. The size of the input values makes no difference. That, however, was not the focus of my post.

The first suggestion was rather extreme, but I have yet to see a better one for a static value. I was leaning more toward the dynamic "peak" value though, having the addon display out of the largest value it currently has come across (taking the absolute value of all deltas).



Originally Posted by myrroddin View Post
The idea for ACM came from a guild healer that wanted to know how effective he was at conserving mana partway though a fight. He can see his current mana on his unit frame. "Am I actually conserving mana, and how effectively am I conserving it?" was his question.
A couple years ago, I had an idea of an addon like this that would take mana consumption and apply it to damage done. This would result in an efficiency rating I called DPM (Damage per Mana). The higher DPM you have, the more efficient you are at casting. To make sure the value was truly honest and serve as a baseline to smarter casting, it would disregard mana gains and on the healing side, overheals would not count either.

What lead to scrapping this idea was the complexity of all the abilities I would have to support that applies buffs/debuffs that increase damage dealt from you and other players or decreases the target's armor/resistance rating. This would be so the associated ability would get proper credit for its own efficiency rating.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 09-08-12 at 08:50 PM.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » math logic bomb


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off