mirror of
https://github.com/SashLilac/cambridge.git
synced 2024-11-22 08:09:03 -06:00
Large commit, read below
DAS Cut Delay added and configurable (like ARR and DAS) BigInt lib added IRS / IHS do not take effect when ARE = 0 Game now saves highscore correctly on game over
This commit is contained in:
parent
3c83ae0bf4
commit
086f327371
30
SOURCES.md
30
SOURCES.md
@ -140,3 +140,33 @@ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|||||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
bigint.lua (https://github.com/empyreuma/bigint.lua)
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
3-Clause BSD License
|
||||||
|
|
||||||
|
Copyright (c) Emily "empyreuma" 2016
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the <organization> nor the
|
||||||
|
names of its contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
555
libs/bigint/bigint.lua
Normal file
555
libs/bigint/bigint.lua
Normal file
@ -0,0 +1,555 @@
|
|||||||
|
#!/usr/bin/env lua
|
||||||
|
-- If this variable is true, then strict type checking is performed for all
|
||||||
|
-- operations. This may result in slower code, but it will allow you to catch
|
||||||
|
-- errors and bugs earlier.
|
||||||
|
local strict = true
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local bigint = {}
|
||||||
|
|
||||||
|
local named_powers = require("libs.bigint.named-powers-of-ten")
|
||||||
|
|
||||||
|
-- Create a new bigint or convert a number or string into a big
|
||||||
|
-- Returns an empty, positive bigint if no number or string is given
|
||||||
|
function bigint.new(num)
|
||||||
|
local self = {
|
||||||
|
sign = "+",
|
||||||
|
digits = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Return a new bigint with the same sign and digits
|
||||||
|
function self:clone()
|
||||||
|
local newint = bigint.new()
|
||||||
|
newint.sign = self.sign
|
||||||
|
for _, digit in pairs(self.digits) do
|
||||||
|
newint.digits[#newint.digits + 1] = digit
|
||||||
|
end
|
||||||
|
return newint
|
||||||
|
end
|
||||||
|
|
||||||
|
setmetatable(self, {
|
||||||
|
__add = function(lhs, rhs)
|
||||||
|
return bigint.add(lhs, rhs)
|
||||||
|
end,
|
||||||
|
__unm = function()
|
||||||
|
if (self.sign == "+") then
|
||||||
|
self.sign = "-"
|
||||||
|
else
|
||||||
|
self.sign = "+"
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end,
|
||||||
|
__sub = function(lhs, rhs)
|
||||||
|
return bigint.subtract(lhs, rhs)
|
||||||
|
end,
|
||||||
|
__mul = function(lhs, rhs)
|
||||||
|
return bigint.multiply(lhs, rhs)
|
||||||
|
end,
|
||||||
|
__div = function(lhs, rhs)
|
||||||
|
return bigint.divide(lhs, rhs)
|
||||||
|
end,
|
||||||
|
__mod = function(lhs, rhs)
|
||||||
|
return bigint.modulus(lhs, rhs)
|
||||||
|
end,
|
||||||
|
__pow = function(lhs, rhs)
|
||||||
|
return bigint.exponentiate(lhs, rhs)
|
||||||
|
end,
|
||||||
|
__eq = function(lhs, rhs)
|
||||||
|
return bigint.compare(lhs, rhs, "==")
|
||||||
|
end,
|
||||||
|
__lt = function(lhs, rhs)
|
||||||
|
return bigint.compare(lhs, rhs, "<")
|
||||||
|
end,
|
||||||
|
__le = function(lhs, rhs)
|
||||||
|
return bigint.compare(lhs, rhs, "<=")
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
if (num) then
|
||||||
|
local num_string = tostring(num)
|
||||||
|
for digit in string.gmatch(num_string, "[0-9]") do
|
||||||
|
table.insert(self.digits, tonumber(digit))
|
||||||
|
end
|
||||||
|
if string.sub(num_string, 1, 1) == "-" then
|
||||||
|
self.sign = "-"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check the type of a big
|
||||||
|
-- Normally only runs when global variable "strict" == true, but checking can be
|
||||||
|
-- forced by supplying "true" as the second argument.
|
||||||
|
function bigint.check(big, force)
|
||||||
|
if (strict or force) then
|
||||||
|
assert(#big.digits > 0, "bigint is empty")
|
||||||
|
assert(type(big.sign) == "string", "bigint is unsigned")
|
||||||
|
for _, digit in pairs(big.digits) do
|
||||||
|
assert(type(digit) == "number", digit .. " is not a number")
|
||||||
|
assert(digit < 10, digit .. " is greater than or equal to 10")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Return a new big with the same digits but with a positive sign (absolute
|
||||||
|
-- value)
|
||||||
|
function bigint.abs(big)
|
||||||
|
bigint.check(big)
|
||||||
|
local result = big:clone()
|
||||||
|
result.sign = "+"
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Convert a big to a number or string
|
||||||
|
function bigint.unserialize(big, output_type, precision)
|
||||||
|
bigint.check(big)
|
||||||
|
|
||||||
|
local num = ""
|
||||||
|
if big.sign == "-" then
|
||||||
|
num = "-"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if ((output_type == nil)
|
||||||
|
or (output_type == "number")
|
||||||
|
or (output_type == "n")
|
||||||
|
or (output_type == "string")
|
||||||
|
or (output_type == "s")) then
|
||||||
|
-- Unserialization to a string or number requires reconstructing the
|
||||||
|
-- entire number
|
||||||
|
|
||||||
|
for _, digit in pairs(big.digits) do
|
||||||
|
num = num .. math.floor(digit) -- lazy way of getting rid of .0$
|
||||||
|
end
|
||||||
|
|
||||||
|
if ((output_type == nil)
|
||||||
|
or (output_type == "number")
|
||||||
|
or (output_type == "n")) then
|
||||||
|
return tonumber(num)
|
||||||
|
else
|
||||||
|
return num
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
-- Unserialization to human-readable form or scientific notation only
|
||||||
|
-- requires reading the first few digits
|
||||||
|
if (precision == nil) then
|
||||||
|
precision = 3
|
||||||
|
else
|
||||||
|
assert(precision > 0, "Precision cannot be less than 1")
|
||||||
|
assert(math.floor(precision) == precision,
|
||||||
|
"Precision must be a positive integer")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- num is the first (precision + 1) digits, the first being separated by
|
||||||
|
-- a decimal point from the others
|
||||||
|
num = num .. big.digits[1]
|
||||||
|
if (precision > 1) then
|
||||||
|
num = num .. "."
|
||||||
|
for i = 1, (precision - 1) do
|
||||||
|
num = num .. big.digits[i + 1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ((output_type == "human-readable")
|
||||||
|
or (output_type == "human")
|
||||||
|
or (output_type == "h")) then
|
||||||
|
-- Human-readable output contributed by 123eee555
|
||||||
|
|
||||||
|
local name
|
||||||
|
local walkback = 0 -- Used to enumerate "ten", "hundred", etc
|
||||||
|
|
||||||
|
-- Walk backwards in the index of named_powers starting at the
|
||||||
|
-- number of digits of the input until the first value is found
|
||||||
|
for i = (#big.digits - 1), (#big.digits - 4), -1 do
|
||||||
|
name = named_powers[i]
|
||||||
|
if (name) then
|
||||||
|
if (walkback == 1) then
|
||||||
|
name = "ten " .. name
|
||||||
|
elseif (walkback == 2) then
|
||||||
|
name = "hundred " .. name
|
||||||
|
end
|
||||||
|
break
|
||||||
|
else
|
||||||
|
walkback = walkback + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return num .. " " .. name
|
||||||
|
|
||||||
|
else
|
||||||
|
return num .. "*10^" .. (#big.digits - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Basic comparisons
|
||||||
|
-- Accepts symbols (<, >=, ~=) and Unix shell-like options (lt, ge, ne)
|
||||||
|
function bigint.compare(big1, big2, comparison)
|
||||||
|
bigint.check(big1)
|
||||||
|
bigint.check(big2)
|
||||||
|
|
||||||
|
local greater = false -- If big1.digits > big2.digits
|
||||||
|
local equal = false
|
||||||
|
|
||||||
|
if (big1.sign == "-") and (big2.sign == "+") then
|
||||||
|
greater = false
|
||||||
|
elseif (#big1.digits > #big2.digits)
|
||||||
|
or ((big1.sign == "+") and (big2.sign == "-")) then
|
||||||
|
greater = true
|
||||||
|
elseif (#big1.digits == #big2.digits) then
|
||||||
|
-- Walk left to right, comparing digits
|
||||||
|
for digit = 1, #big1.digits do
|
||||||
|
if (big1.digits[digit] > big2.digits[digit]) then
|
||||||
|
greater = true
|
||||||
|
break
|
||||||
|
elseif (big2.digits[digit] > big1.digits[digit]) then
|
||||||
|
break
|
||||||
|
elseif (digit == #big1.digits)
|
||||||
|
and (big1.digits[digit] == big2.digits[digit]) then
|
||||||
|
equal = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If both numbers are negative, then the requirements for greater are
|
||||||
|
-- reversed
|
||||||
|
if (not equal) and (big1.sign == "-") and (big2.sign == "-") then
|
||||||
|
greater = not greater
|
||||||
|
end
|
||||||
|
|
||||||
|
return (((comparison == "<") or (comparison == "lt"))
|
||||||
|
and ((not greater) and (not equal)) and true)
|
||||||
|
or (((comparison == ">") or (comparison == "gt"))
|
||||||
|
and ((greater) and (not equal)) and true)
|
||||||
|
or (((comparison == "==") or (comparison == "eq"))
|
||||||
|
and (equal) and true)
|
||||||
|
or (((comparison == ">=") or (comparison == "ge"))
|
||||||
|
and (equal or greater) and true)
|
||||||
|
or (((comparison == "<=") or (comparison == "le"))
|
||||||
|
and (equal or not greater) and true)
|
||||||
|
or (((comparison == "~=") or (comparison == "!=") or (comparison == "ne"))
|
||||||
|
and (not equal) and true)
|
||||||
|
or false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- BACKEND: Add big1 and big2, ignoring signs
|
||||||
|
function bigint.add_raw(big1, big2)
|
||||||
|
bigint.check(big1)
|
||||||
|
bigint.check(big2)
|
||||||
|
|
||||||
|
local result = bigint.new()
|
||||||
|
local max_digits = 0
|
||||||
|
local carry = 0
|
||||||
|
|
||||||
|
if (#big1.digits >= #big2.digits) then
|
||||||
|
max_digits = #big1.digits
|
||||||
|
else
|
||||||
|
max_digits = #big2.digits
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Walk backwards right to left, like in long addition
|
||||||
|
for digit = 0, max_digits - 1 do
|
||||||
|
local sum = (big1.digits[#big1.digits - digit] or 0)
|
||||||
|
+ (big2.digits[#big2.digits - digit] or 0)
|
||||||
|
+ carry
|
||||||
|
|
||||||
|
if (sum >= 10) then
|
||||||
|
carry = 1
|
||||||
|
sum = sum - 10
|
||||||
|
else
|
||||||
|
carry = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
result.digits[max_digits - digit] = sum
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Leftover carry in cases when #big1.digits == #big2.digits and sum > 10, ex. 7 + 9
|
||||||
|
if (carry == 1) then
|
||||||
|
table.insert(result.digits, 1, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- BACKEND: Subtract big2 from big1, ignoring signs
|
||||||
|
function bigint.subtract_raw(big1, big2)
|
||||||
|
-- Type checking is done by bigint.compare
|
||||||
|
assert(bigint.compare(bigint.abs(big1), bigint.abs(big2), ">="),
|
||||||
|
"Size of " .. bigint.unserialize(big1, "string") .. " is less than "
|
||||||
|
.. bigint.unserialize(big2, "string"))
|
||||||
|
|
||||||
|
local result = big1:clone()
|
||||||
|
local max_digits = #big1.digits
|
||||||
|
local borrow = 0
|
||||||
|
|
||||||
|
-- Logic mostly copied from bigint.add_raw ---------------------------------
|
||||||
|
-- Walk backwards right to left, like in long subtraction
|
||||||
|
for digit = 0, max_digits - 1 do
|
||||||
|
local diff = (big1.digits[#big1.digits - digit] or 0)
|
||||||
|
- (big2.digits[#big2.digits - digit] or 0)
|
||||||
|
- borrow
|
||||||
|
|
||||||
|
if (diff < 0) then
|
||||||
|
borrow = 1
|
||||||
|
diff = diff + 10
|
||||||
|
else
|
||||||
|
borrow = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
result.digits[max_digits - digit] = diff
|
||||||
|
end
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
-- Strip leading zeroes if any, but not if 0 is the only digit
|
||||||
|
while (#result.digits > 1) and (result.digits[1] == 0) do
|
||||||
|
table.remove(result.digits, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
-- FRONTEND: Addition and subtraction operations, accounting for signs
|
||||||
|
function bigint.add(big1, big2)
|
||||||
|
-- Type checking is done by bigint.compare
|
||||||
|
|
||||||
|
local result
|
||||||
|
|
||||||
|
-- If adding numbers of different sign, subtract the smaller sized one from
|
||||||
|
-- the bigger sized one and take the sign of the bigger sized one
|
||||||
|
if (big1.sign ~= big2.sign) then
|
||||||
|
if (bigint.compare(bigint.abs(big1), bigint.abs(big2), ">")) then
|
||||||
|
result = bigint.subtract_raw(big1, big2)
|
||||||
|
result.sign = big1.sign
|
||||||
|
else
|
||||||
|
result = bigint.subtract_raw(big2, big1)
|
||||||
|
result.sign = big2.sign
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif (big1.sign == "+") and (big2.sign == "+") then
|
||||||
|
result = bigint.add_raw(big1, big2)
|
||||||
|
|
||||||
|
elseif (big1.sign == "-") and (big2.sign == "-") then
|
||||||
|
result = bigint.add_raw(big1, big2)
|
||||||
|
result.sign = "-"
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
function bigint.subtract(big1, big2)
|
||||||
|
-- Type checking is done by bigint.compare in bigint.add
|
||||||
|
-- Subtracting is like adding a negative
|
||||||
|
local big2_local = big2:clone()
|
||||||
|
if (big2.sign == "+") then
|
||||||
|
big2_local.sign = "-"
|
||||||
|
else
|
||||||
|
big2_local.sign = "+"
|
||||||
|
end
|
||||||
|
return bigint.add(big1, big2_local)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- BACKEND: Multiply a big by a single digit big, ignoring signs
|
||||||
|
function bigint.multiply_single(big1, big2)
|
||||||
|
bigint.check(big1)
|
||||||
|
bigint.check(big2)
|
||||||
|
assert(#big2.digits == 1, bigint.unserialize(big2, "string")
|
||||||
|
.. " has more than one digit")
|
||||||
|
|
||||||
|
local result = bigint.new()
|
||||||
|
local carry = 0
|
||||||
|
|
||||||
|
-- Logic mostly copied from bigint.add_raw ---------------------------------
|
||||||
|
-- Walk backwards right to left, like in long multiplication
|
||||||
|
for digit = 0, #big1.digits - 1 do
|
||||||
|
local this_digit = big1.digits[#big1.digits - digit]
|
||||||
|
* big2.digits[1]
|
||||||
|
+ carry
|
||||||
|
|
||||||
|
if (this_digit >= 10) then
|
||||||
|
carry = math.floor(this_digit / 10)
|
||||||
|
this_digit = this_digit - (carry * 10)
|
||||||
|
else
|
||||||
|
carry = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
result.digits[#big1.digits - digit] = this_digit
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Leftover carry in cases when big1.digits[1] * big2.digits[1] > 0
|
||||||
|
if (carry > 0) then
|
||||||
|
table.insert(result.digits, 1, carry)
|
||||||
|
end
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
-- FRONTEND: Multiply two bigs, accounting for signs
|
||||||
|
function bigint.multiply(big1, big2)
|
||||||
|
-- Type checking done by bigint.multiply_single
|
||||||
|
|
||||||
|
local result = bigint.new(0)
|
||||||
|
local larger, smaller -- Larger and smaller in terms of digits, not size
|
||||||
|
|
||||||
|
if (bigint.unserialize(big1) == 0) or (bigint.unserialize(big2) == 0) then
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
if (#big1.digits >= #big2.digits) then
|
||||||
|
larger = big1
|
||||||
|
smaller = big2
|
||||||
|
else
|
||||||
|
larger = big2
|
||||||
|
smaller = big1
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Walk backwards right to left, like in long multiplication
|
||||||
|
for digit = 0, #smaller.digits - 1 do
|
||||||
|
-- Sorry for going over column 80! There's lots of big names here
|
||||||
|
local this_digit_product = bigint.multiply_single(larger,
|
||||||
|
bigint.new(smaller.digits[#smaller.digits - digit]))
|
||||||
|
|
||||||
|
-- "Placeholding zeroes"
|
||||||
|
if (digit > 0) then
|
||||||
|
for placeholder = 1, digit do
|
||||||
|
table.insert(this_digit_product.digits, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = bigint.add(result, this_digit_product)
|
||||||
|
end
|
||||||
|
|
||||||
|
if (larger.sign == smaller.sign) then
|
||||||
|
result.sign = "+"
|
||||||
|
else
|
||||||
|
result.sign = "-"
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Raise a big to a positive integer or big power (TODO: negative integer power)
|
||||||
|
function bigint.exponentiate(big, power)
|
||||||
|
-- Type checking for big done by bigint.multiply
|
||||||
|
assert(bigint.compare(power, bigint.new(0), ">="),
|
||||||
|
" negative powers are not supported")
|
||||||
|
local exp = power:clone()
|
||||||
|
|
||||||
|
if (bigint.compare(exp, bigint.new(0), "==")) then
|
||||||
|
return bigint.new(1)
|
||||||
|
elseif (bigint.compare(exp, bigint.new(1), "==")) then
|
||||||
|
return big
|
||||||
|
else
|
||||||
|
local result = big:clone()
|
||||||
|
|
||||||
|
while (bigint.compare(exp, bigint.new(1), ">")) do
|
||||||
|
result = bigint.multiply(result, big)
|
||||||
|
exp = bigint.subtract(exp, bigint.new(1))
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- BACKEND: Divide two bigs (decimals not supported), returning big result and
|
||||||
|
-- big remainder
|
||||||
|
-- WARNING: Only supports positive integers
|
||||||
|
function bigint.divide_raw(big1, big2)
|
||||||
|
-- Type checking done by bigint.compare
|
||||||
|
if (bigint.compare(big1, big2, "==")) then
|
||||||
|
return bigint.new(1), bigint.new(0)
|
||||||
|
elseif (bigint.compare(big1, big2, "<")) then
|
||||||
|
return bigint.new(0), bigint.new(0)
|
||||||
|
else
|
||||||
|
assert(bigint.compare(big2, bigint.new(0), "!="), "error: divide by zero")
|
||||||
|
assert(big1.sign == "+", "error: big1 is not positive")
|
||||||
|
assert(big2.sign == "+", "error: big2 is not positive")
|
||||||
|
|
||||||
|
local result = bigint.new()
|
||||||
|
|
||||||
|
local dividend = bigint.new() -- Dividend of a single operation, not the
|
||||||
|
-- dividend of the overall function
|
||||||
|
local divisor = big2:clone()
|
||||||
|
local factor = 1
|
||||||
|
|
||||||
|
-- Walk left to right among digits in the dividend, like in long
|
||||||
|
-- division
|
||||||
|
for _, digit in pairs(big1.digits) do
|
||||||
|
dividend.digits[#dividend.digits + 1] = digit
|
||||||
|
|
||||||
|
-- The dividend is smaller than the divisor, so a zero is appended
|
||||||
|
-- to the result and the loop ends
|
||||||
|
if (bigint.compare(dividend, divisor, "<")) then
|
||||||
|
if (#result.digits > 0) then -- Don't add leading zeroes
|
||||||
|
result.digits[#result.digits + 1] = 0
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Find the maximum number of divisors that fit into the
|
||||||
|
-- dividend
|
||||||
|
factor = 0
|
||||||
|
while (bigint.compare(divisor, dividend, "<=")) do
|
||||||
|
divisor = bigint.add(divisor, big2)
|
||||||
|
factor = factor + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Append the factor to the result
|
||||||
|
if (factor == 10) then
|
||||||
|
-- Fixes a weird bug that introduces a new bug if fixed by
|
||||||
|
-- changing the comparison in the while loop to "<="
|
||||||
|
result.digits[#result.digits] = 1
|
||||||
|
result.digits[#result.digits + 1] = 0
|
||||||
|
else
|
||||||
|
result.digits[#result.digits + 1] = factor
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Subtract the divisor from the dividend to obtain the
|
||||||
|
-- remainder, which is the new dividend for the next loop
|
||||||
|
dividend = bigint.subtract(dividend,
|
||||||
|
bigint.subtract(divisor, big2))
|
||||||
|
|
||||||
|
-- Reset the divisor
|
||||||
|
divisor = big2:clone()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The remainder of the final loop is returned as the function's
|
||||||
|
-- overall remainder
|
||||||
|
return result, dividend
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- FRONTEND: Divide two bigs (decimals not supported), returning big result and
|
||||||
|
-- big remainder, accounting for signs
|
||||||
|
function bigint.divide(big1, big2)
|
||||||
|
local result, remainder = bigint.divide_raw(bigint.abs(big1),
|
||||||
|
bigint.abs(big2))
|
||||||
|
if (big1.sign == big2.sign) then
|
||||||
|
result.sign = "+"
|
||||||
|
else
|
||||||
|
result.sign = "-"
|
||||||
|
end
|
||||||
|
|
||||||
|
return result, remainder
|
||||||
|
end
|
||||||
|
|
||||||
|
-- FRONTEND: Return only the remainder from bigint.divide
|
||||||
|
function bigint.modulus(big1, big2)
|
||||||
|
local result, remainder = bigint.divide(big1, big2)
|
||||||
|
|
||||||
|
-- Remainder will always have the same sign as the dividend per C standard
|
||||||
|
-- https://en.wikipedia.org/wiki/Modulo_operation#Remainder_calculation_for_the_modulo_operation
|
||||||
|
remainder.sign = big1.sign
|
||||||
|
return remainder
|
||||||
|
end
|
||||||
|
|
||||||
|
return bigint
|
3340
libs/bigint/named-powers-of-ten.lua
Normal file
3340
libs/bigint/named-powers-of-ten.lua
Normal file
File diff suppressed because it is too large
Load Diff
2
load/bigint.lua
Normal file
2
load/bigint.lua
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
bigint = require "libs.bigint.bigint"
|
||||||
|
number_names = require "libs.bigint.named-powers-of-ten"
|
3
main.lua
3
main.lua
@ -7,6 +7,7 @@ function love.load()
|
|||||||
require "load.sounds"
|
require "load.sounds"
|
||||||
require "load.bgm"
|
require "load.bgm"
|
||||||
require "load.save"
|
require "load.save"
|
||||||
|
require "load.bigint"
|
||||||
loadSave()
|
loadSave()
|
||||||
require "scene"
|
require "scene"
|
||||||
--config["side_next"] = false
|
--config["side_next"] = false
|
||||||
@ -15,8 +16,10 @@ function love.load()
|
|||||||
|
|
||||||
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
|
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
|
||||||
|
|
||||||
|
-- init config
|
||||||
if not config.das then config.das = 10 end
|
if not config.das then config.das = 10 end
|
||||||
if not config.arr then config.arr = 2 end
|
if not config.arr then config.arr = 2 end
|
||||||
|
if not config.dcd then config.dcd = 0 end
|
||||||
if not config.sfx_volume then config.sfx_volume = 0.5 end
|
if not config.sfx_volume then config.sfx_volume = 0.5 end
|
||||||
if not config.bgm_volume then config.bgm_volume = 0.5 end
|
if not config.bgm_volume then config.bgm_volume = 0.5 end
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ function GameScene:render()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function GameScene:onInputPress(e)
|
function GameScene:onInputPress(e)
|
||||||
if self.game.completed and (e.input == "menu_decide" or e.input == "menu_back" or e.input == "retry") then
|
if (self.game.game_over or self.game.completed) and (e.input == "menu_decide" or e.input == "menu_back" or e.input == "retry") then
|
||||||
highscore_entry = self.game:getHighscoreData()
|
highscore_entry = self.game:getHighscoreData()
|
||||||
highscore_hash = self.game.hash .. "-" .. self.ruleset.hash
|
highscore_hash = self.game.hash .. "-" .. self.ruleset.hash
|
||||||
submitHighscore(highscore_hash, highscore_entry)
|
submitHighscore(highscore_hash, highscore_entry)
|
||||||
|
@ -9,6 +9,7 @@ TuningScene.options = {
|
|||||||
-- Serves as a reference for the options available in the menu. Format: {name in config, name as displayed if applicable, slider name}
|
-- Serves as a reference for the options available in the menu. Format: {name in config, name as displayed if applicable, slider name}
|
||||||
{"das", "DAS", "dasSlider"},
|
{"das", "DAS", "dasSlider"},
|
||||||
{"arr", "ARR", "arrSlider"},
|
{"arr", "ARR", "arrSlider"},
|
||||||
|
{"dcd", "DCD", "dcdSlider"},
|
||||||
}
|
}
|
||||||
|
|
||||||
local optioncount = #TuningScene.options
|
local optioncount = #TuningScene.options
|
||||||
@ -21,12 +22,14 @@ function TuningScene:new()
|
|||||||
self.highlight = 1
|
self.highlight = 1
|
||||||
|
|
||||||
self.dasSlider = newSlider(290, 225, 400, config.das, 0, 20, function(v) config.das = math.floor(v) end, {width=20, knob="circle", track="roundrect"})
|
self.dasSlider = newSlider(290, 225, 400, config.das, 0, 20, function(v) config.das = math.floor(v) end, {width=20, knob="circle", track="roundrect"})
|
||||||
self.arrSlider = newSlider(290, 325, 400, config.arr, 0, 6, function(v) config.arr = math.floor(v) end, {width=20, knob="circle", track="roundrect"})
|
self.arrSlider = newSlider(290, 300, 400, config.arr, 0, 6, function(v) config.arr = math.floor(v) end, {width=20, knob="circle", track="roundrect"})
|
||||||
|
self.dcdSlider = newSlider(290, 375, 400, config.dcd, 0, 6, function(v) config.dcd = math.floor(v) end, {width=20, knob="circle", track="roundrect"})
|
||||||
end
|
end
|
||||||
|
|
||||||
function TuningScene:update()
|
function TuningScene:update()
|
||||||
self.dasSlider:update()
|
self.dasSlider:update()
|
||||||
self.arrSlider:update()
|
self.arrSlider:update()
|
||||||
|
self.dcdSlider:update()
|
||||||
end
|
end
|
||||||
|
|
||||||
function TuningScene:render()
|
function TuningScene:render()
|
||||||
@ -38,7 +41,7 @@ function TuningScene:render()
|
|||||||
)
|
)
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1, 0.5)
|
love.graphics.setColor(1, 1, 1, 0.5)
|
||||||
love.graphics.rectangle("fill", 75, 73 + self.highlight * 100, 400, 33)
|
love.graphics.rectangle("fill", 75, 98 + self.highlight * 75, 400, 33)
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
|
||||||
@ -50,11 +53,13 @@ function TuningScene:render()
|
|||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.print("Delayed Auto-Shift (DAS): " .. math.floor(self.dasSlider:getValue()) .. "F", 80, 175)
|
love.graphics.print("Delayed Auto-Shift (DAS): " .. math.floor(self.dasSlider:getValue()) .. "F", 80, 175)
|
||||||
love.graphics.print("Auto-Repeat Rate (ARR): " .. math.floor(self.arrSlider:getValue()) .. "F", 80, 275)
|
love.graphics.print("Auto-Repeat Rate (ARR): " .. math.floor(self.arrSlider:getValue()) .. "F", 80, 250)
|
||||||
|
love.graphics.print("DAS Cut Delay (DCD): " .. math.floor(self.dcdSlider:getValue()) .. "F", 80, 325)
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1, 0.75)
|
love.graphics.setColor(1, 1, 1, 0.75)
|
||||||
self.dasSlider:draw()
|
self.dasSlider:draw()
|
||||||
self.arrSlider:draw()
|
self.arrSlider:draw()
|
||||||
|
self.dcdSlider:draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
function TuningScene:onInputPress(e)
|
function TuningScene:onInputPress(e)
|
||||||
|
@ -75,6 +75,7 @@ function GameMode:getLineARE() return 25 end
|
|||||||
function GameMode:getLockDelay() return 30 end
|
function GameMode:getLockDelay() return 30 end
|
||||||
function GameMode:getLineClearDelay() return 40 end
|
function GameMode:getLineClearDelay() return 40 end
|
||||||
function GameMode:getDasLimit() return 15 end
|
function GameMode:getDasLimit() return 15 end
|
||||||
|
function GameMode:getDasCutDelay() return 0 end
|
||||||
|
|
||||||
function GameMode:getNextPiece(ruleset)
|
function GameMode:getNextPiece(ruleset)
|
||||||
return {
|
return {
|
||||||
@ -177,7 +178,9 @@ function GameMode:update(inputs, ruleset)
|
|||||||
self.hard_drop_locked = false
|
self.hard_drop_locked = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- diff vars to use in checks
|
||||||
local piece_y = self.piece.position.y
|
local piece_y = self.piece.position.y
|
||||||
|
local piece_rot = self.piece.rotation
|
||||||
|
|
||||||
ruleset:processPiece(
|
ruleset:processPiece(
|
||||||
inputs, self.piece, self.grid, self:getGravity(), self.prev_inputs,
|
inputs, self.piece, self.grid, self:getGravity(), self.prev_inputs,
|
||||||
@ -187,6 +190,22 @@ function GameMode:update(inputs, ruleset)
|
|||||||
)
|
)
|
||||||
|
|
||||||
local piece_dy = self.piece.position.y - piece_y
|
local piece_dy = self.piece.position.y - piece_y
|
||||||
|
local piece_drot = self.piece.rotation - piece_rot
|
||||||
|
|
||||||
|
-- das cut
|
||||||
|
if (
|
||||||
|
(piece_dy ~= 0 and (inputs.up or inputs.down)) or
|
||||||
|
(piece_drot ~= 0 and (
|
||||||
|
inputs.rotate_left or inputs.rotate_right or
|
||||||
|
inputs.rotate_left2 or inputs.rotate_right2 or
|
||||||
|
inputs.rotate_180
|
||||||
|
))
|
||||||
|
) then
|
||||||
|
self.das.frames = math.max(
|
||||||
|
self.das.frames - self:getDasCutDelay(),
|
||||||
|
-self:getDasCutDelay()
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
if inputs["up"] == true and
|
if inputs["up"] == true and
|
||||||
self.piece:isDropBlocked(self.grid) and
|
self.piece:isDropBlocked(self.grid) and
|
||||||
@ -421,7 +440,9 @@ function GameMode:processDelays(inputs, ruleset, drop_speed)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:initializeOrHold(inputs, ruleset)
|
function GameMode:initializeOrHold(inputs, ruleset)
|
||||||
if self.ihs and self.enable_hold and inputs["hold"] == true then
|
if (
|
||||||
|
self.frames == 0 or (ruleset.are and self:getARE() ~= 0) and self.ihs or false
|
||||||
|
) and self.enable_hold and inputs["hold"] == true then
|
||||||
self:hold(inputs, ruleset, true)
|
self:hold(inputs, ruleset, true)
|
||||||
else
|
else
|
||||||
self:initializeNextPiece(inputs, ruleset, self.next_queue[1])
|
self:initializeNextPiece(inputs, ruleset, self.next_queue[1])
|
||||||
@ -464,7 +485,10 @@ function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next
|
|||||||
self.prev_inputs, self.move,
|
self.prev_inputs, self.move,
|
||||||
self:getLockDelay(), self:getDropSpeed(),
|
self:getLockDelay(), self:getDropSpeed(),
|
||||||
self.lock_drop, self.lock_hard_drop, self.big_mode,
|
self.lock_drop, self.lock_hard_drop, self.big_mode,
|
||||||
self.irs, self.buffer_hard_drop, self.buffer_soft_drop,
|
(
|
||||||
|
self.frames == 0 or (ruleset.are and self:getARE() ~= 0)
|
||||||
|
) and self.irs or false,
|
||||||
|
self.buffer_hard_drop, self.buffer_soft_drop,
|
||||||
self.lock_on_hard_drop, self.lock_on_soft_drop
|
self.lock_on_hard_drop, self.lock_on_soft_drop
|
||||||
)
|
)
|
||||||
if self.piece:isDropBlocked(self.grid) and
|
if self.piece:isDropBlocked(self.grid) and
|
||||||
|
@ -255,12 +255,10 @@ function Ruleset:initializePiece(
|
|||||||
|
|
||||||
self:onPieceCreate(piece)
|
self:onPieceCreate(piece)
|
||||||
if irs then
|
if irs then
|
||||||
if inputs.rotate_left or inputs.rotate_left2 or
|
self:rotatePiece(inputs, piece, grid, {}, true)
|
||||||
inputs.rotate_right or inputs.rotate_right2 or
|
if (data.orientation - 1) ~= piece.rotation then
|
||||||
inputs.rotate_180 then
|
|
||||||
playSE("irs")
|
playSE("irs")
|
||||||
end
|
end
|
||||||
self:rotatePiece(inputs, piece, grid, {}, true)
|
|
||||||
end
|
end
|
||||||
self:dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked)
|
self:dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked)
|
||||||
if (buffer_hard_drop and config.gamesettings.buffer_lock == 1) then
|
if (buffer_hard_drop and config.gamesettings.buffer_lock == 1) then
|
||||||
|
Loading…
Reference in New Issue
Block a user