Skip to content

Instantly share code, notes, and snippets.

@alexpersian
Last active April 27, 2020 15:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexpersian/88bf5a6e1caae0436db1de794a150aad to your computer and use it in GitHub Desktop.
Save alexpersian/88bf5a6e1caae0436db1de794a150aad to your computer and use it in GitHub Desktop.
//
// 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