🌟現在、鉄壁 鉄壁ヘッドショットには対応済みです。
鉄壁HSは通常HSと同じダメージになります。LMG及びDMR、チャージライフル、ハンマーポイント弾を除き、すべてのダメージ値が一致していることを確認しています。

「モジュール:Utility/Scale」の版間の差分

提供:Apex Data
ナビゲーションに移動 検索に移動
(関数名を table.mapValue から table.MapValues に変更による改変)
(ticks算出のロジックを再改善)
 
(同じ利用者による、間の4版が非表示)
2行目: 2行目:
local table      = require('Module:TableExtensions')
local table      = require('Module:TableExtensions')


local ninf = -math.huge
local pinf = math.huge
function math.isInf(v)
return v == pinf or v == ninf
end
function math.isNaN(v)
function math.isNaN(v)
--return tostring(v) == '-nan'
--return tostring(v) == '-nan'
9行目: 14行目:
function math.log10(x)
function math.log10(x)
return math.log(x) * log10e  
return math.log(x) * log10e  
end
local eps = 2.2204460492503131e-16
function math.isSame(a, b)
local diff = math.abs(a - b)
local aa = math.abs(a)
local ab = math.abs(b)
if aa > ab then
return diff <= eps * ab
else
return diff <= eps * aa
end
end
end


124行目: 141行目:
return -(10 ^ -power) / nice
return -(10 ^ -power) / nice
end
end
end
-- function: ticks
local function ticks(start, stop, count)
if start == stop and count > 0 then
return { start }
end
local reverse = start > stop
if reverse then
start, stop = stop, start
end
local step = tickIncrement(start, stop, count)
if step == 0 or math.isInf(step) then
return {}
end
local ticks = {}
if step > 0 then
local r0 = math.floor(start / step + 0.5)
local r1 = math.floor(stop  / step + 0.5)
local r0s = r0 * step
local r1s = r1 * step
if r0s < start or math.isSame(r0s, start) then
r0 = r0 + 1
end
if r1s > stop  or math.isSame(r1s, stop) then
r1 = r1 - 1
end
for i = 0, r1 - r0 do
ticks[i + 1] = (r0 + i) * step
end
else
step = -step
local r0 = math.floor(start * step + 0.5)
local r1 = math.floor(stop  * step + 0.5)
local r0s = r0 / step
local r1s = r1 / step
if r0s < start or math.isSame(r0s, start) then
r0 = r0 + 1
end
if r1s > stop  or math.isSame(r1s, stop) then
r1 = r1 - 1
end
for i = 0, r1 - r0 do
ticks[i + 1] = (r0 + i) / step
end
end
if reverse then
table.reverse(ticks)
end
return ticks
end
end


140行目: 214行目:


-- [Constructor]
-- [Constructor]
function __Scale__Continuous.__new(transform, untransform)
function __Scale__Continuous.__new(typename, domain, transform, untransform)
local obj = {
local obj = {
typename    = __Scale__ContinuousType,
typename    = typename,
domain      = unit,
domain      = domain,
range        = { 0, 100 },
range        = { 0, 100 },
_clamp      = identity,
_clamp      = identity,
232行目: 306行目:
end
end
return self._clamp(self._untransform(self._input(y)))
return self._clamp(self._untransform(self._input(y)))
end
-- [Function] Nice
function __Scale__Continuous:_nice(floor, ceil)
local i0 = 1
local i1 = #self.domain
local start = self.domain[i0]
local stop  = self.domain[i1]
if start > stop then
start, stop = stop, start
i0, i1 = i1, i0
end
self.domain[i0] = floor(start)
self.domain[i1] = ceil(stop)
self:_rescale()
return self
end
end


245行目: 336行目:
-- [Constructor]
-- [Constructor]
function __Scale__Linear.new()
function __Scale__Linear.new()
local obj = __Scale__Continuous.__new(identity, identity)
local obj = __Scale__Continuous.__new(__Scale__LinearType, unit, identity, identity)
return setmetatable(obj, { __index = __Scale__Linear })
return setmetatable(obj, { __index = __Scale__Linear })
end
-- [Function] Get ticks
function __Scale__Linear:ticks(count)
libraryUtil.checkType('nice', 1, count, 'number', true)
count = count or 10
return ticks(self.domain[1], self.domain[#self.domain], count)
end
end


290行目: 389行目:
-- [Export]
-- [Export]
scale.LinearScale = __Scale__Linear
scale.LinearScale = __Scale__Linear
-- ==========================
-- type: LogScale: Continuous
-- ==========================
local logUnit = { 1, 10 }
local e = 2.7182818284590452
-- function: logn
local function logn(x)
return -math.log(-x)
end
-- function: expn
local function expn(x)
return -math.exp(-x)
end
-- function: fnlogp
local function fnlogp(base)
if base == e then
return math.log
else
local y = 1 / math.log(base)
return function(x)
return math.log(x) * y
end
end
end
-- function: fnpowp
local function fnpowp(base)
if base == e then
return math.exp
else
return function(x)
return math.pow(base, x)
end
end
end
-- function: fnlogn
local function fnlogn(base)
if base == e then
return function(x)
return -math.log(-x)
end
else
local y = 1 / math.log(base)
return function(x)
return -math.log(-x) * y
end
end
end
-- function: fnpown
local function fnpown(base)
if base == e then
return function(x)
return -math.exp(-x)
end
else
return function(x)
return -math.pow(base, -x)
end
end
end
-- function: reflect
local function reflect(fn)
return function(x)
return -fn(-x)
end
end
-- Define object
local __Scale__LogType = 'log'
local __Scale__Log = {
__typename = __Scale__LogType,
}
setmetatable(__Scale__Log, { __index = __Scale__Continuous })
-- [Constructor]
function __Scale__Log.new()
local obj = __Scale__Continuous.__new(__Scale__LogType, logUnit, math.log, math.exp)
obj.__base___rescale = obj._rescale
obj.base = 10
obj._log = fnlogp(10)
obj._pow = fnpowp(10)
return setmetatable(obj, { __index = __Scale__Log })
end
-- [Function] Get ticks
function __Scale__Log:ticks(count)
libraryUtil.checkType('nice', 1, count, 'number', true)
count = count or 10
local startLinear = self.domain[1]
local stopLinear  = self.domain[#self.domain]
if startLinear == stopLinear and count > 0 then
return { startLinear }
end
local reverse = startLinear > stopLinear
if reverse then
startLinear, stopLinear = stopLinear, startLinear
end
local start = self._log(startLinear)
local stop  = self._log(stopLinear)
local diff  = stop - start
local z
if (not (self.base % 1)) and diff < count then
start = math.floor(start)
stop  = math.ceil(stop)
z = {}
if startLinear > 0 then
for i = start, stop do
local p = self._pow(i)
for k = 1, base - 1 do
local tick = p * k
if tick >= startLinear then
if tick > stopLinear then
break
end
table.insert(z, tick)
end
end
end
else
for i = start, stop do
local p = self._pow(i)
for k = base - 1, 1, -1 do
local tick = p * k
if tick >= startLinear then
if tick > stopLinear then
break
end
table.insert(z, tick)
end
end
end
end
if 2 * #z < count then
z = ticks(startLinear, stopLinear, count)
end
else
z = table.mapValues(ticks(start, stop, math.min(diff, count)), self._pow)
end
if reverse then
table.reverse(z)
end
return z
end
-- [Property] Set base
function __Scale__Log:setBase(newBase)
libraryUtil.checkType('setBase', 1, newBase, 'number')
if self.base ~= newBase then
self.base = newBase
self:_rescale()
end
return self
end
-- [Function] Rescale
function __Scale__Log:_rescale()
if self.domain[1] < 0 then
self._log = fnlogn(self.base)
self._pow = fnpown(self.base)
self._transform  = logn
self._untransform = expn
else
self._log = fnlogp(self.base)
self._pow = fnpowp(self.base)
self._transform  = math.log
self._untransform = math.exp
end
self:__base___rescale()
end
-- [Function] Nice
function __Scale__Log:nice()
local floor = function(x)
return self._pow(math.floor(self._log(x)))
end
local ceil = function(x)
return self._pow(math.ceil(self._log(x)))
end
return self:_nice(floor, ceil)
end
-- [Export]
scale.LogScale = __Scale__Log


return scale
return scale

2021年9月2日 (木) 12:33時点における最新版

このモジュールについての説明文ページを モジュール:Utility/Scale/doc に作成できます

local libraryUtil = require('libraryUtil')
local table       = require('Module:TableExtensions')

local ninf = -math.huge
local pinf = math.huge
function math.isInf(v)
	return v == pinf or v == ninf
end
function math.isNaN(v)
	--return tostring(v) == '-nan'
	return v ~= v
end
local log10e = 1 / math.log(10)
function math.log10(x)
	return math.log(x) * log10e 
end

local eps = 2.2204460492503131e-16
function math.isSame(a, b)
	local diff = math.abs(a - b)
	local aa = math.abs(a)
	local ab = math.abs(b)
	if aa > ab then
		return diff <= eps * ab
	else
		return diff <= eps * aa
	end
end

-- ============
-- Define utils
-- ============
local unit = { 0, 1 }
local function identity(num)
	return num
end

-- function: asNumber - as number if possible
local function asNumber(value)
	local typename = type(value)
	if typename == 'number' then
		return value
	elseif typename == 'string' then
		return tonumber(value)
	else
		error('The "value" type must be "number" or "string".')
	end
end

-- function: constant
local function constant(num)
	return function()
		return num
	end
end

-- function: normalize
local function normalize(a, b)
	b = b - a
	if math.isNaN(b) then
		return constant(b)
	elseif b == 0 then
		return constant(0.5)
	else
		return function(x)
			return (x - a) / b
		end
	end
end

-- function: interpolateValue
local function interpolateValue(a, b)
	return function(t)
		return a + (b - a) * t
	end
end

-- function: clamper - generate clamp function
local function clamper(a, b)
	if a > b then
		a, b = b, a
	end
	return function(x)
		return math.max(a, math.min(b, x))
	end
end

-- function: bimap
local function bimap(domain, range, interpolate)
	local d1 = domain[1]
	local d2 = domain[2]
	local r1 = range[1]
	local r2 = range[2]
	if d2 < d1 then
		d1 = normalize(d2, d1)
		r1 = interpolate(r2, r1)
	else
		d1 = normalize(d1, d2)
		r1 = interpolate(r1, r2)
	end
	return function(x)
		return r1(d1(x))
	end
end

-- function: tickIncrement
local e10 = math.sqrt(50)
local e5  = math.sqrt(10)
local e2h = math.sqrt(5)
local e2  = math.sqrt(2)
local function tickIncrement(start, stop, count)
	local step  = (stop - start) / math.max(0, count)
	local power = math.floor(math.log10(step))
	local error = step / (10 ^ power)
	local nice
	if power >= 0 then
		if error >= e10 then
			nice = 10
		elseif error >= e5 then
			nice = 5
		elseif error >= e2h then
			nice = 2.5
		elseif error >= e2 then
			nice = 2
		else
			nice = 1
		end
		return nice * (10 ^ power)
	else
		if error >= e10 then
			nice = 10
		elseif error >= e5 then
			nice = 5
		elseif error >= e2h then
			nice = 2.5
		elseif error >= e2 then
			nice = 2
		else
			nice = 1
		end
		return -(10 ^ -power) / nice
	end
end

-- function: ticks
local function ticks(start, stop, count)
	if start == stop and count > 0 then
		return { start }
	end
	
	local reverse = start > stop
	if reverse then
		start, stop = stop, start
	end
	
	local step = tickIncrement(start, stop, count)
	if step == 0 or math.isInf(step) then
		return {}
	end
	
	local ticks = {}
	if step > 0 then
		local r0 = math.floor(start / step + 0.5)
		local r1 = math.floor(stop  / step + 0.5)
		local r0s = r0 * step
		local r1s = r1 * step
		if r0s < start or math.isSame(r0s, start) then
			r0 = r0 + 1
		end
		if r1s > stop  or math.isSame(r1s, stop) then
			r1 = r1 - 1
		end
		
		for i = 0, r1 - r0 do
			ticks[i + 1] = (r0 + i) * step
		end
	else
		step = -step
		
		local r0 = math.floor(start * step + 0.5)
		local r1 = math.floor(stop  * step + 0.5)
		local r0s = r0 / step
		local r1s = r1 / step
		if r0s < start or math.isSame(r0s, start) then
			r0 = r0 + 1
		end
		if r1s > stop  or math.isSame(r1s, stop) then
			r1 = r1 - 1
		end
		
		for i = 0, r1 - r0 do
			ticks[i + 1] = (r0 + i) / step
		end
	end
	
	if reverse then
		table.reverse(ticks)
	end
	return ticks
end

-- ================
-- namespace: scale
-- ================
local scale = {}

-- ================
-- type: Continuous
-- ================
local __Scale__ContinuousType = 'continuous'
local __Scale__Continuous = {
	__typename = __Scale__ContinuousType,
}

-- [Constructor]
function __Scale__Continuous.__new(typename, domain, transform, untransform)
	local obj = {
		typename     = typename,
		domain       = domain,
		range        = { 0, 100 },
		_clamp       = identity,
		_piecewise   = bimap,
		_interpolate = interpolateValue,
		_transform   = transform,
		_untransform = untransform,
		_input       = nil,
		_output      = nil,
	}
	return setmetatable(obj, { __index = __Scale__Continuous })
end

-- [Property] Set domain
function __Scale__Continuous:setDomain(newDomain)
	libraryUtil.checkType('setDomain', 1, newDomain, 'table')
	if #newDomain < 2 then
		error('The "domain" table size must be at least 2.')
	end

	self.domain = table.mapValues(newDomain, asNumber)
	self:_rescale()
	return self
end

-- [Property] Set range
function __Scale__Continuous:setRange(newRange)
	libraryUtil.checkType('setRange', 1, newRange, 'table')
	if #newRange < 2 then
		error('The "range" table size must be at least 2.')
	end

	self.range = table.map(newRange, asNumber)
	self:_rescale()
	return self
end

-- [Property] Set clamp
function __Scale__Continuous:setClamp(newClamp)
	libraryUtil.checkType('setClamp', 1, newClamp, 'boolean')

	self._clamp = newClamp or identity
	self:_rescale()
	return self
end

-- [Function] Rescale
function __Scale__Continuous:_rescale()
	local n = math.min(#self.domain, #self.range)
	if self._clamp ~= identity then
		self._clamp = clamper(self.domain[1], self.domain[n])
	end
	if n > 2 then
		error('The multiple values of the domain aren\'t currently supported.')
	else
		self._piecewise = bimap
	end
	self._input = nil
	self._output = nil
end

-- [Function] Scale
function __Scale__Continuous:scale(x)
	libraryUtil.checkType('scale', 1, x, 'number')

	if math.isNaN(x) then
		return nil
	else
		if not self._output then
			self._output = self._piecewise(
				table.mapValues(self.domain, self._transform),
				self.range,
				self._interpolate)
		end
		return self._output(self._transform(self._clamp(x)))
	end
end

-- [Function] Invert
function __Scale__Continuous:invert(y)
	libraryUtil.checkType('invert', 1, y, 'number')
	
	if not self._input then
		self._input = self._piecewise(
			self.range,
			table.mapValues(self.domain, self._transform),
			interpolateValue)
	end
	return self._clamp(self._untransform(self._input(y)))
end

-- [Function] Nice
function __Scale__Continuous:_nice(floor, ceil)
	local i0 = 1
	local i1 = #self.domain
	local start = self.domain[i0]
	local stop  = self.domain[i1]
	if start > stop then
		start, stop = stop, start
		i0, i1 = i1, i0
	end
	
	self.domain[i0] = floor(start)
	self.domain[i1] = ceil(stop)
	self:_rescale()
	return self
end

-- =============================
-- type: LinearScale: Continuous
-- =============================
local __Scale__LinearType = 'linear'
local __Scale__Linear = {
	__typename = __Scale__LinearType,
}
setmetatable(__Scale__Linear, { __index = __Scale__Continuous })

-- [Constructor]
function __Scale__Linear.new()
	local obj = __Scale__Continuous.__new(__Scale__LinearType, unit, identity, identity)
	return setmetatable(obj, { __index = __Scale__Linear })
end

-- [Function] Get ticks
function __Scale__Linear:ticks(count)
	libraryUtil.checkType('nice', 1, count, 'number', true)
	count = count or 10
	
	return ticks(self.domain[1], self.domain[#self.domain], count)
end

-- [Function] Nice
function __Scale__Linear:nice(count)
	libraryUtil.checkType('nice', 1, count, 'number', true)
	count = count or 10
	
	local i0 = 1
	local i1 = #self.domain
	local start = self.domain[i0]
	local stop  = self.domain[i1]
	if start > stop then
		start, stop = stop, start
		i0, i1 = i1, i0
	end
	
	local prestep, step
	local maxIter = 5
	while maxIter > 0 do
		step = tickIncrement(start, stop, count)
		if step == prestep then
			self.domain[i0] = start
			self.domain[i1] = stop
			self:_rescale()
			break
		elseif step > 0 then
			start = math.floor(start / step) * step
			stop  = math.ceil (stop  / step) * step
		elseif step < 0 then
			start = math.ceil (start * step) / step
			stop  = math.floor(stop  * step) / step
		else
			break
		end
		
		prestep = step
		maxIter = maxIter - 1
	end
	return self
end

-- [Export]
scale.LinearScale = __Scale__Linear

-- ==========================
-- type: LogScale: Continuous
-- ==========================
local logUnit = { 1, 10 }
local e = 2.7182818284590452

-- function: logn
local function logn(x)
	return -math.log(-x)
end

-- function: expn
local function expn(x)
	return -math.exp(-x)
end

-- function: fnlogp
local function fnlogp(base)
	if base == e then
		return math.log
	else
		local y = 1 / math.log(base)
		return function(x)
			return math.log(x) * y
		end
	end
end

-- function: fnpowp
local function fnpowp(base)
	if base == e then
		return math.exp
	else
		return function(x)
			return math.pow(base, x)
		end
	end
end

-- function: fnlogn
local function fnlogn(base)
	if base == e then
		return function(x)
			return -math.log(-x)
		end
	else
		local y = 1 / math.log(base)
		return function(x)
			return -math.log(-x) * y
		end
	end
end

-- function: fnpown
local function fnpown(base)
	if base == e then
		return function(x)
			return -math.exp(-x)
		end
	else
		return function(x)
			return -math.pow(base, -x)
		end
	end
end

-- function: reflect
local function reflect(fn)
	return function(x)
		return -fn(-x)
	end
end

-- Define object
local __Scale__LogType = 'log'
local __Scale__Log = {
	__typename = __Scale__LogType,
}
setmetatable(__Scale__Log, { __index = __Scale__Continuous })

-- [Constructor]
function __Scale__Log.new()
	local obj = __Scale__Continuous.__new(__Scale__LogType, logUnit, math.log, math.exp)
	obj.__base___rescale = obj._rescale
	obj.base = 10
	obj._log = fnlogp(10)
	obj._pow = fnpowp(10)
	return setmetatable(obj, { __index = __Scale__Log })
end

-- [Function] Get ticks
function __Scale__Log:ticks(count)
	libraryUtil.checkType('nice', 1, count, 'number', true)
	count = count or 10
	
	local startLinear = self.domain[1]
	local stopLinear  = self.domain[#self.domain]
	if startLinear == stopLinear and count > 0 then
		return { startLinear }
	end
	
	local reverse = startLinear > stopLinear
	if reverse then
		startLinear, stopLinear = stopLinear, startLinear
	end
	
	local start = self._log(startLinear)
	local stop  = self._log(stopLinear)
	local diff  = stop - start
	local z
	if (not (self.base % 1)) and diff < count then
		start = math.floor(start)
		stop  = math.ceil(stop)
		z = {}
		
		if startLinear > 0 then
			for i = start, stop do
				local p = self._pow(i)
				for k = 1, base - 1 do
					local tick = p * k
					if tick >= startLinear then
						if tick > stopLinear then
							break
						end
						table.insert(z, tick)
					end
				end
			end
		else
			for i = start, stop do
				local p = self._pow(i)
				for k = base - 1, 1, -1 do
					local tick = p * k
					if tick >= startLinear then
						if tick > stopLinear then
							break
						end
						table.insert(z, tick)
					end
				end
			end
		end
		if 2 * #z < count then
			z = ticks(startLinear, stopLinear, count)
		end
	else
		z = table.mapValues(ticks(start, stop, math.min(diff, count)), self._pow)
	end
	
	if reverse then
		table.reverse(z)
	end
	return z
end

-- [Property] Set base
function __Scale__Log:setBase(newBase)
	libraryUtil.checkType('setBase', 1, newBase, 'number')

	if self.base ~= newBase then
		self.base = newBase
		self:_rescale()
	end
	return self
end

-- [Function] Rescale
function __Scale__Log:_rescale()
	if self.domain[1] < 0 then
		self._log = fnlogn(self.base)
		self._pow = fnpown(self.base)
		self._transform   = logn
		self._untransform = expn
	else
		self._log = fnlogp(self.base)
		self._pow = fnpowp(self.base)
		self._transform   = math.log
		self._untransform = math.exp
	end
	self:__base___rescale()
end

-- [Function] Nice
function __Scale__Log:nice()
	local floor = function(x)
		return self._pow(math.floor(self._log(x)))
	end
	local ceil = function(x)
		return self._pow(math.ceil(self._log(x)))
	end
	return self:_nice(floor, ceil)
end

-- [Export]
scale.LogScale = __Scale__Log

return scale