2020-12-04 19:53:09 -06:00
|
|
|
-- A randomizer based on Tetra Legends' "Tetra-X" game mode
|
|
|
|
-- There are two main rules:
|
|
|
|
-- * if piece hasn't been generated for 13+ pieces, force it
|
|
|
|
-- * if piece has been generated in the last two pieces, don't give it out
|
|
|
|
--
|
|
|
|
-- The official implementation also has self-balancing functionality (bias
|
|
|
|
-- towards pieces that have appeared less often).
|
|
|
|
|
|
|
|
local Randomizer = require 'tetris.randomizers.randomizer'
|
|
|
|
|
|
|
|
local TetraXRandomizer = Randomizer:extend()
|
|
|
|
|
|
|
|
function TetraXRandomizer:initialize()
|
|
|
|
local pieces = {"I", "J", "L", "O", "S", "T", "Z"}
|
|
|
|
|
|
|
|
self.count = {}
|
|
|
|
self.lastseen = {}
|
|
|
|
self.totalcount = 0
|
|
|
|
self.pieceselection = pieces
|
|
|
|
|
|
|
|
for _, piece in ipairs(pieces) do
|
|
|
|
self.count[piece] = 0
|
|
|
|
self.lastseen[piece] = -1 -- use -1 as magic value for "not seen"
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
function TetraXRandomizer:generatePiece()
|
|
|
|
local generated = nil
|
|
|
|
while true do
|
2023-06-14 00:06:16 -05:00
|
|
|
generated = self.pieceselection[love.math.random(#self.pieceselection)]
|
2020-12-04 19:53:09 -06:00
|
|
|
if not (self.lastseen[generated] == 0 or self.lastseen[generated] == 1) then
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- piece has not been generated in the last 13+
|
|
|
|
for piece, val in pairs(self.lastseen) do
|
|
|
|
if val >= 13 then
|
|
|
|
generated = piece
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
for piece, val in pairs(self.lastseen) do
|
|
|
|
if piece == generated then
|
|
|
|
self.lastseen[piece] = 0
|
|
|
|
else
|
|
|
|
if val ~= -1 then
|
|
|
|
self.lastseen[piece] = val + 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
self.count[generated] = self.count[generated] + 1
|
|
|
|
self.totalcount = self.totalcount + 1
|
|
|
|
|
|
|
|
-- shuffle the piece selection for the next time
|
|
|
|
self.pieceselection = {}
|
|
|
|
for piece, count in pairs(self.count) do
|
|
|
|
-- in this case 6 = #piece types - 1, so all probabilities sum to 1
|
|
|
|
local probability = (self.totalcount - count) / (self.totalcount * 6)
|
|
|
|
local chances = math.floor(probability * 1000 + 0.5) -- simulated "round"
|
|
|
|
for _ = 1, chances do
|
|
|
|
table.insert(self.pieceselection, piece)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return generated
|
|
|
|
end
|
|
|
|
|
|
|
|
return TetraXRandomizer
|