From 7f25dd6548875b22e7ffde01e9108fc6b0d123fd Mon Sep 17 00:00:00 2001 From: zaphod77 Date: Mon, 14 Apr 2025 14:38:30 -0500 Subject: [PATCH 1/2] Make Sega 88 Randomizer accurate. This commit makes it so the Sega 88 randomizer actually only generates sequences the system 16 arcade version can. Since the seed was well chosen enough to make the period maximal length for the bits that alter, i was able to shortcut it, because every possible seed with those bits constant is visited. The seed at the top generates the TITII power on pattern. --- tetris/randomizers/sega.lua | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/tetris/randomizers/sega.lua b/tetris/randomizers/sega.lua index 14fa746..5895134 100644 --- a/tetris/randomizers/sega.lua +++ b/tetris/randomizers/sega.lua @@ -1,19 +1,32 @@ local Randomizer = require 'tetris.randomizers.randomizer' local SegaRandomizer = Randomizer:extend() - +local seed=711800410 -- all sega starts with this seed. preserved here for future modification +local dummy=0 function SegaRandomizer:initialize() - self.bag = {"I", "J", "L", "O", "S", "T", "Z"} - self.sequence = {} - for i = 1, 1000 do - self.sequence[i] = self.bag[love.math.random(table.getn(self.bag))] - end - self.counter = 0 + seed=love.math.random(0,268435455)*16+10 -- pick a valid Sega seed, using love.math.random so it will work in replays. + -- When starting with seed 711800410, the period is maximum length, so we can randomly select the bits that change. + self.bag = {"I", "Z", "S", "O", "T", "L", "J"} + self.sequence = {} + for i = 1, 1000 do + self.sequence[i] = self.bag[self:SegaRandom()+1] + end + self.counter = 0 end function SegaRandomizer:generatePiece() - self.counter = self.counter + 1 - return self.sequence[self.counter % 1000 + 1] + self.counter = self.counter + 1 + return self.sequence[(self.counter-1) % 1000 + 1] +end +function SegaRandomizer:SegaRandom() + local temp=seed + local d0 + seed=seed * 41 + seed=seed % 4294967296 + seed=seed % 4294967296 + temp=seed % 65536 + math.floor(seed / 65536) + temp=temp % 65536 + seed=temp * 65536 + seed % 65536 + d0=temp % 64 + return (d0 % 7) end - -return SegaRandomizer From dfd63e68004157e2893b067802cf1f4278e0c298 Mon Sep 17 00:00:00 2001 From: zaphod77 Date: Mon, 14 Apr 2025 15:09:26 -0500 Subject: [PATCH 2/2] Implement DAS bug in Marathon C88 When you switch directions in one frame on Tetris (Sega 1988), the game rests das one frame too late. This makes it move two cells in two frames. This commit implements this bug, just as Marathon C99 implements that game's DAS bug. Will break existing replays. --- tetris/modes/marathon_c88.lua | 49 +++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/tetris/modes/marathon_c88.lua b/tetris/modes/marathon_c88.lua index ab09bef..90dc129 100644 --- a/tetris/modes/marathon_c88.lua +++ b/tetris/modes/marathon_c88.lua @@ -46,11 +46,50 @@ function MarathonC88Game:new(secret_inputs) end end -function MarathonC88Game:getARE() return 30 end -function MarathonC88Game:getLineARE() return 30 end -function MarathonC88Game:getDasLimit() return 20 end -function MarathonC88Game:getLineClearDelay() return 42 end -function MarathonC88Game:getLockDelay() return 30 end +function MarathonC88Game:continueDAS() -- implement sega 88's DAS bug. + local das_frames = self.das.frames + 1 + if das_frames > 1000 then -- frame perfect reversal set by startLeftDAS or startRightDAS below. + self.move=self.das.direction + self.das.frames=0 + elseif das_frames >= self:getDasLimit() then + if self.das.direction == "left" then + self.move = (self:getARR() == 0 and "speed" or "") .. "left" + self.das.frames = self:getDasLimit() - self:getARR() + elseif self.das.direction == "right" then + self.move = (self:getARR() == 0 and "speed" or "") .. "right" + self.das.frames = self:getDasLimit() - self:getARR() + end + else + self.move = "none" + self.das.frames = das_frames + end +end + +function MarathonC88Game:startRightDAS() + self.move = "right" + if self.das.direction == "left" then + self.das.frames=1000 -- check for this in continueDAS to do one more move. + else + self.das.frames=0 -- reset UNLESS we switched in one frame + end + self.das.direction = "right" + if self:getDasLimit() == 0 then + self:continueDAS() + end +end + +function MarathonC88Game:startLeftDAS() + self.move = "left" + if self.das.direction == "right" then + self.das.frames=1000 -- check for this in continueDAS to do one more move. + else + self.das.frames=0 -- reset UNLESS we switched in one frame + end + self.das.direction = "left" + if self:getDasLimit() == 0 then + self:continueDAS() + end +end function MarathonC88Game:getGravity() local gravity