LonamiWebs / Klooni1010

libGDX game based on the original 1010!
https://lonamiwebs.github.io/klooni
GNU General Public License v3.0
234 stars 72 forks source link

Better RNG #57

Open Lonami opened 6 years ago

Lonami commented 6 years ago

https://harddrop.com/wiki/Random_Generator is a useful link.

Quoting @bb010g:

basically, you don't normally want an algorithm that's friendly in certain ways, you want randomness that's less prone to dick the player over and that advanced players can work with at a higher level. Tetris handles this by allocating a "bag" of each piece type when new tetrominoes are needed, shuffling that, and then passing out from there.

Bags let you do things like avoid really long runs of certain pieces and adjust rarity without being complex or too deterministic.

alternatively, Akira's The Grand Master traditionally handles this by keeping a history of the last N pieces, and then generating a new piece up to M times until a unique piece appears or the limit is reached. https://harddrop.com/wiki/TGM_randomizer

huh, Terror Instinct does a thing where it keeps a 35 piece bag for that generation that starts with 5 of each piece, and when a piece is genned (pulled) from it a piece of the least recent type is put in its place, which keeps pieces from not showing up for a long while.

https://tetrisconcept.net/threads/randomizer-theory.512/page-9#post-55478

# PETE ROOLZ
#
# you can get a quick sequence out with
# python -c 'import tgm; r = tgm.TiRandomizer(); print "".join([r.next() for i in range(70)])'

import random
import collections

# On a Ti randomizer bug:
#
# > When these 3 conditions are met:
# >
# >     1. The randomizer has just chosen the most droughted piece
# >     2. A reroll happened during the choice of that piece.
# >     3. Excluding the first piece of the game, and including this chosen piece, you have received at least one of each of the 7 piece types.
# >
# > Then the roll that chose that most droughted piece will not update the bag of 35 pieces.
#
# -- colour_thief, http://tetrisconcept.net/threads/randomizer-theory.512/page-7

def TiRandomizer():
    bag = ['j', 'i', 'z', 'l', 'o', 't', 's'] * 5
    history = collections.deque(['s', 'z', 's', 'z'])
    drought_order = ['j', 'i', 'z', 'l', 'o', 't', 's']
    count = { 'j' : 0, 'i' : 0, 'z' : 0, 'l' : 0, 'o' : 0, 't' : 0, 's' : 0 }
    n = 1

    # first piece is special
    first = random.choice(['j','i','l','t'])
    history.popleft()
    history.append(first)
    yield first

    while True:
        for roll in range(6):
            i = random.randint(0, 34)
            piece = bag[i]
            if piece not in history:
                break
            if roll < 5:
                bag[i] = drought_order[0]
        count[piece] += 1
        emulate_bug = all ([
            piece == drought_order[0],
            roll > 0,
            0 not in count.values()
            ])
        if not emulate_bug:
            bag[i] = drought_order[0]
        drought_order.remove(piece)
        drought_order.append(piece)
        history.popleft()
        history.append(piece)
        yield piece

if __name__ == '__main__':
    r = TiRandomizer()
    print "".join([r.next() for i in range(70)])

anyways, point is that you can keep randomness in a lot of ways while not just calling rand and being done

I should probably just PR something for this

RustanHakansson commented 4 years ago

The point in playing the game that is most annoying is losing. It is really critical for enjoyment to feel that I lost through bad play, not through getting unjustly hosed by bad randomness. The most common loss to me is when I get 2 blocks of 3x3, and only have space for one. Today I even got 3 blocks of 3x3 at the same time, and could only place 2. This feel impossible to avoid risking while at the same time trying to get more than a 3-line bonus.

Tweaking the randomness is risky, and might be perceived as wrong. So a straight rule could be better. My suggestion is to make sure that no piece is duplicated. It is a simple and straightforward change. Maybe it makes the game too easy, as there are no duplicates of 3x3 blocks. But if the game is too heavily reliant on this specific piece breaking players, there needs to be some change. One example is to introduce more pieces, for example 2x3, 2x4, 2x5. I added some other thoughts that might be combined with a change like this in #70 .

Lonami commented 4 years ago

Note that RNG is also the thing that can keep some games interesting and testing your ability to deal with bad luck. It can be frustrating for sure, but you can also be extremely lucky.

RustanHakansson commented 4 years ago

Players will not really notice when they are really lucky, but will for sure notice when they get 3 3x3 blocks. I have gotten it two more times since I wrote this, and each time died because of it. It is by far my main frustration with the game. If I had gotten 3 different tiles, that were all bad shapes but not identical, my frustration with the randomness would have been greatly reduced.

It is quite boring to place multiple identical pieces anyway, even when you do not die from them. For example having more than one 1x1 piece is not very interesting.

Lonami commented 4 years ago

If the same block appears twice or thrice, would giving the random generation "a second chance" be a good option? For example, 3 pieces are generated the same so a new set is generated and used (without further checking). You might get unlucky and be stuck with pieces that are the same in this random re-roll, but it should generally be better. This way the RNG isn't changed much.

Also, three 3x3 might be just what you need to clear an entire 3-row if you only have the first blocks filled. It's the luck factor again.

RustanHakansson commented 4 years ago

Sure, it might be helpful to get 3 identical, but not much fun.

A simple way to generate 3 different pieces would be to have an array of them, randomize the order, and use the three first ones. For next round the same array is used, but re-randomized. Having it 100% guaranteed that the selection is random, but only 1 of each piece is drawn, would be very clear to players. If there was a 1% chance to get duplicates it might make players wonder.