Last active
April 27, 2020 15:21
-
-
Save alexpersian/88bf5a6e1caae0436db1de794a150aad to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// TurnipCalculator | |
// | |
// Translated from https://gist.github.com/Treeki/85be14d297c80c8b3c0a76375743325b#file-turnipprices-cpp | |
// | |
// TODO: Calculation is slightly off from C++ impl still | |
import Foundation | |
extension Int { | |
public static func * (lhs: Float, rhs: Int) -> Float { | |
return lhs * Float(rhs) | |
} | |
} | |
class Random { | |
private var mContext: [UInt32] = Array(repeating: 0, count: 4) | |
convenience init() { | |
self.init(seed: 42069) | |
} | |
init(seed: UInt32) { | |
mContext[0] = 0x6C078965 &* (seed ^ (seed >> 30)) + 1 | |
mContext[1] = 0x6C078965 &* (mContext[0] ^ (mContext[0] >> 30)) + 2 | |
mContext[2] = 0x6C078965 &* (mContext[1] ^ (mContext[1] >> 30)) + 3 | |
mContext[3] = 0x6C078965 &* (mContext[2] ^ (mContext[2] >> 30)) + 4 | |
} | |
init(seed1: inout UInt32, seed2: inout UInt32, seed3: inout UInt32, seed4: inout UInt32) { | |
if (seed1 | seed2 | seed3 | seed4) == 0 { | |
seed1 = 1 | |
seed2 = 0x6C078967 | |
seed3 = 0x714ACB41 | |
seed4 = 0x48077044 | |
} | |
mContext[0] = seed1 | |
mContext[1] = seed2 | |
mContext[2] = seed3 | |
mContext[3] = seed4 | |
} | |
func getU32() -> UInt32 { | |
let n: UInt32 = mContext[0] ^ (mContext[0] << 11) | |
mContext[0] = mContext[1] | |
mContext[1] = mContext[2] | |
mContext[2] = mContext[3] | |
mContext[3] = n ^ (n >> 8) ^ mContext[3] ^ (mContext[3] >> 19) | |
return mContext[3] | |
} | |
func getU64() -> UInt64 { | |
let n1: UInt32 = mContext[0] ^ (mContext[0] << 11) | |
let n2: UInt32 = mContext[1] | |
let n3: UInt32 = n1 ^ (n1 >> 8) ^ mContext[3] | |
mContext[0] = mContext[2] | |
mContext[1] = mContext[3] | |
mContext[2] = n3 ^ (mContext[3] >> 19) | |
mContext[3] = n2 ^ (n2 << 11) ^ ((n2 ^ (n2 << 11)) >> 8) ^ mContext[2] ^ (n3 >> 19) | |
return UInt64(mContext[2] << 32) | UInt64(mContext[3]) | |
} | |
func getContext(seed1: inout UInt32, seed2: inout UInt32, seed3: inout UInt32, seed4: inout UInt32) { | |
seed1 = mContext[0] | |
seed2 = mContext[1] | |
seed3 = mContext[2] | |
seed4 = mContext[3] | |
} | |
} | |
// Four possible patterns, zero indexed | |
enum TurnipPattern: Int { | |
/* PATTERN ONE: high, decreasing, high, decreasing, high */ | |
case first = 0 | |
/* PATTERN TWO: decreasing middle, high spike, random low */ | |
case second = 1 | |
/* PATTERN THREE: consistently decreasing */ | |
case third = 2 | |
/* PATTERN FOUR: decreasing, spike, decreasing */ | |
case fourth = 3 | |
} | |
class TurnipPrices { | |
var basePrice: Int = 0 | |
var sellPrices: [Int] = Array(repeating: 0, count: 14) | |
var pattern: TurnipPattern | |
var tmp40: Int = 0 // ??? | |
var rng: Random | |
init(pattern: TurnipPattern, seed: UInt32) { | |
self.pattern = pattern | |
self.rng = Random(seed: seed) | |
} | |
// MARK: - Helpers | |
func randBool() -> Bool { | |
return Bool(truncating: (rng.getU32() & 0x80000000) as NSNumber) | |
} | |
func randInt(_ min: Int, _ max: Int) -> Int { | |
return Int(((UInt64(rng.getU32()) * UInt64(max - min + 1)) >> 32)) + min | |
} | |
func randFloat(_ a: Float, _ b: Float) -> Float { | |
let val: UInt32 = 0x3F800000 | (rng.getU32() >> 9) | |
let fval: Float = Float(bitPattern: val) | |
return a + ((fval - 1.0) * (a - b)) | |
} | |
func intCeil(_ val: Float) -> Int { | |
return Int(val + 0.99999) | |
} | |
// MARK: - Main Calculation | |
func calculate() { | |
basePrice = randInt(90, 110) | |
let chance: Int = randInt(0, 99) | |
var nextPattern: TurnipPattern | |
if pattern.rawValue >= 4 { | |
nextPattern = .third | |
} | |
else { | |
switch pattern { | |
case .first: | |
if chance < 20 { nextPattern = .first } | |
else if chance < 50 { nextPattern = .second } | |
else if chance < 65 { nextPattern = .third } | |
else { nextPattern = .fourth } | |
case .second: | |
if chance < 50 { nextPattern = .first } | |
else if chance < 55 { nextPattern = .second } | |
else if chance < 75 { nextPattern = .third } | |
else { nextPattern = .fourth } | |
case .third: | |
if chance < 25 { nextPattern = .first } | |
else if chance < 70 { nextPattern = .second } | |
else if chance < 75 { nextPattern = .third } | |
else { nextPattern = .fourth } | |
case .fourth: | |
if chance < 45 { nextPattern = .first } | |
else if chance < 70 { nextPattern = .second } | |
else if chance < 85 { nextPattern = .third } | |
else { nextPattern = .fourth } | |
} | |
} | |
pattern = nextPattern | |
for i in 2..<14 { | |
sellPrices[i] = 0 | |
sellPrices[0] = basePrice // Price for Sunday AM | |
sellPrices[1] = basePrice // Price for Sunday PM | |
var work: Int | |
var decPhaseLen1: Int | |
var decPhaseLen2: Int | |
var peakStart: Int | |
var hiPhaseLen1: Int | |
var hiPhaseLen2and3: Int | |
var hiPhaseLen3: Int | |
var rate: Float | |
switch pattern { | |
// MARK: - PATTERN ONE: high, decreasing, high, decreasing, high | |
case .first: | |
work = 2 | |
decPhaseLen1 = randBool() ? 3 : 2 | |
decPhaseLen2 = 5 - decPhaseLen1 | |
hiPhaseLen1 = randInt(0, 6) | |
hiPhaseLen2and3 = 7 - hiPhaseLen1 | |
hiPhaseLen3 = randInt(0, hiPhaseLen2and3 - 1) | |
// High phase 1 | |
for _ in 0..<hiPhaseLen1 { | |
sellPrices[work] = intCeil(randFloat(0.9, 1.4) * basePrice) | |
work += 1 | |
} | |
// Decreasing phase 1 | |
rate = randFloat(0.8, 0.6) | |
for _ in 0..<decPhaseLen1 { | |
sellPrices[work] = intCeil(rate * basePrice) | |
work += 1 | |
rate -= 0.04 | |
rate -= randFloat(0, 0.06) | |
} | |
// High phase 2 | |
for _ in 0..<(hiPhaseLen2and3 - hiPhaseLen3) { | |
sellPrices[work] = intCeil(randFloat(0.9, 1.4) * basePrice) | |
work += 1 | |
} | |
// Decreasing phase 2 | |
rate = randFloat(0.8, 0.6) | |
for _ in 0..<decPhaseLen2 { | |
sellPrices[work] = intCeil(rate * basePrice) | |
work += 1 | |
rate -= 0.04 | |
rate -= randFloat(0, 0.06) | |
} | |
// High phase 3 | |
for _ in 0..<hiPhaseLen3 { | |
sellPrices[work] = intCeil(randFloat(0.9, 1.4) * basePrice) | |
} | |
// MARK: - PATTERN TWO: decreasing middle, high spike, random low | |
case .second: | |
work = 2 | |
peakStart = randInt(3, 9) | |
rate = randFloat(0.9, 0.85) | |
// Decreasing phase | |
for _ in work..<peakStart { | |
sellPrices[work] = intCeil(rate * basePrice) | |
rate -= 0.03 | |
rate -= randFloat(0, 0.02) | |
work += 1 | |
} | |
// High spike phase | |
sellPrices[work] = intCeil(randFloat(0.9, 1.4) * basePrice); work += 1; | |
sellPrices[work] = intCeil(randFloat(1.4, 2.0) * basePrice); work += 1; | |
sellPrices[work] = intCeil(randFloat(2.0, 6.0) * basePrice); work += 1; | |
sellPrices[work] = intCeil(randFloat(1.4, 2.0) * basePrice); work += 1; | |
sellPrices[work] = intCeil(randFloat(0.9, 1.4) * basePrice); work += 1; | |
// Random low phase | |
for _ in work..<14 { | |
sellPrices[work] = intCeil(randFloat(0.4, 0.9) * basePrice) | |
work += 1 | |
} | |
// MARK: - PATTERN THREE: consistently decreasing | |
case .third: | |
work = 2 | |
rate = 0.9 | |
rate -= randFloat(0, 0.05) | |
for _ in work..<14 { | |
sellPrices[work] = intCeil(rate * basePrice) | |
rate -= 0.03 | |
rate -= randFloat(0, 0.02) | |
work += 1 | |
} | |
// MARK: - PATTERN FOUR: decreasing, spike, decreasing | |
case .fourth: | |
work = 2 | |
peakStart = randInt(2, 9) | |
// Decreasing phase before spike | |
rate = randFloat(0.9, 0.4) | |
for _ in work..<peakStart { | |
sellPrices[work] = intCeil(rate * basePrice) | |
rate -= 0.03 | |
rate -= randFloat(0, 0.02) | |
work += 1 | |
} | |
// High spike phase | |
sellPrices[work] = intCeil(randFloat(0.9, 1.4) * basePrice); work += 1; | |
sellPrices[work] = intCeil(randFloat(0.9, 1.4) * basePrice); work += 1; | |
rate = randFloat(1.4, 2.0) | |
sellPrices[work] = intCeil(randFloat(1.4, rate) * basePrice) - 1; work += 1; | |
sellPrices[work] = intCeil(rate * basePrice); work += 1; | |
sellPrices[work] = intCeil(randFloat(1.4, rate) * basePrice) - 1; work += 1; | |
// Decreasing phase after spike | |
if work < 14 { | |
rate = randFloat(0.9, 0.4) | |
for _ in work..<14 { | |
sellPrices[work] = intCeil(rate * basePrice) | |
rate -= 0.03 | |
rate -= randFloat(0, 0.02) | |
work += 1 | |
} | |
} | |
} | |
sellPrices[0] = 0 | |
sellPrices[1] = 0 | |
} | |
} | |
} | |
func runit() { | |
let turnips = TurnipPrices(pattern: .first, seed: 42069) | |
turnips.calculate() | |
print("Pattern \(turnips.pattern.rawValue):") | |
print("Sun Mon Tue Wed Thu Fri Sat") | |
// AM prices | |
print(turnips.basePrice, turnips.sellPrices[2], turnips.sellPrices[4], | |
turnips.sellPrices[6], turnips.sellPrices[8], turnips.sellPrices[10], | |
turnips.sellPrices[12]) | |
// PM prices | |
print(turnips.sellPrices[3], turnips.sellPrices[5], turnips.sellPrices[7], | |
turnips.sellPrices[9], turnips.sellPrices[11], turnips.sellPrices[13]) | |
} | |
runit() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment