Lançamento de 619 mil tetris no GLSL, sua renderização e um bot simples

Eu tive uma "idéia" de criar o número máximo de execução simultânea do Tetris para um shader (uma textura de buffer de quadro).


A seguir, é apresentada uma breve descrição de como o código resultante funciona.


O que é isso:


Cada tetris funciona em três pixels. Para uma resolução de 1920x1080 você pode executar 619200 cópias por vez. Também criou um bot simples para reprodução automática.
No final do post, links para execução e origem.
Vídeo atualizado, mostra o número de campos restantes, até zero.



Armazenamento de dados


Tabela Tetris de tamanho [10, 22] (10 largura, 22 altura).
Cada célula pode estar vazia ou não.
É necessário um total de 22 * 10 = 220 bits para armazenar a tabela inteira.
Um "pixel" são quatro flutuadores de 24 bits, 96 bits por pixel.


Visualmente (uma parte do quadro de depuração), três pixels são destacados em vermelho, este é um campo salvo:


imagem


2 * 96 + 24 + 4
Dois pixels, um flutuador do terceiro pixel, 4 bits do segundo flutuador do terceiro pixel
Existem dois carros alegóricos não utilizados no terceiro pixel pixel3.zw , eles armazenam o estado da lógica , mais precisamente


  • z armazena três números de oito bits [a,b,c]
    - uma posição do bloco atual, como o ID da posição na matriz (uma matriz de tamanho 220 bits, a posição máxima é 220 que é menor que 0xff)
    - b tempo até a queda automática (temporizador) de cada quadro -1 para esse número, que se tornou 0 e depois cai no bloco
    - c ID do bloco atual
  • w também [a,b,c] , mas também o sinal (positivo ou negativo) de todo o flutuador é a bandeira do final do jogo na tabela atual (para não desperdiçar recursos se o campo estiver sobrecarregado )
    - uma ação, nenhuma ação (0), esquerda (1), direita (2) e assim por diante, o código completo em Common , ações tem dois estados, verifique a esquerda e verifique se é possível mover para a esquerda, então a ação é definida para a esquerda_ mova .
    - [b,c] 0xffff (16 bits) pontos da tabela atual, o número de linhas que queimaram

Restam 20 não utilizados no segundo flutuador do terceiro pixel.


quadro de depuração mostrando que a lógica de salvamento está funcionando corretamente
à esquerda, há um campo branco de três pixels de tamanho, definido especificamente para mostrar que as lacunas são processadas corretamente (se a resolução não for um múltiplo de três, a faixa será inclinada)
condição na linha 75 Tampão A


imagem


Por que preciso de IDs de ação:


  • Os dados são armazenados em três pixels, é impossível verificar simultaneamente a lógica e alterar os dados em um quadro (sem executar toda a lógica e carregar o mapa inteiro em cada pixel, a carga aumentará dezenas de vezes).
  • Portanto, a lógica de armazenamento de dados funciona em cada pixel e executa os comandos recebidos left_ move , os comandos de verificação left_ check são executados apenas em um pixel (terceiro).

Lugar lento


  • Cada terceiro pixel (pixel lógico) descomprime o mapa inteiro (lendo todos os três pixels).
  • Os dois pixels restantes descompactam apenas "eles mesmos" (um pixel) para executar a ação salva.
  • Durante a ação, a linha gravada, outro pixel é carregado, pois a tabela cai e os pedaços inferiores da tabela devem saber o que está em cima.

Desempenho do algoritmo de armazenamento


Para o teste, defina #define debug como Common e AI 0 também.
Eu obtive esse resultado - 10FPS ao renderizar e processar todos os 619200 campos,
em 120 mil campos (25fps)


imagem


Lógica bot


Lógica Muito ruim , o bot queima em um minuto e chega a 60 pontos.


Não consegui iniciar uma boa lógica com muitos ciclos verificando furos e bordas e campos combustíveis, considerando a melhor posição com base em todas as quedas possíveis ...
Uma boa lógica funcionou para mim até 100 cópias e deu um forte atraso ao contornar todos os ciclos.


Minha lógica bot funciona assim
Toda a lógica está na função AI_pos_gen no Buffer A, existem dez linhas.


Pseudocódigo:
verificar a altura para instalação do bloco é igual ao máximo para o campo na coluna atual (verifique uma linha para a altura)


 (4   ){ (  (10)){ (     ){  (    ,  )   best ID()  best POS } } }  (     )   (  )      0     1 

Acontece três ciclos comuns - eles colocam o bloco para que a altura seja mínima.


A função AI_pos_gen é chamada quando um novo bloco aparece e retorna a posição para cair de cima , pegando o ID do bloco e fazendo-o girar; a função funciona no terceiro pixel (lógica), ou seja, possui um mapa totalmente carregado (matriz do mapa).
Você pode facilmente escrever seu bot, se desejar.


Lugar mais lento
Adicionando apenas um loop para testar as falhas , o driver da minha placa de vídeo travou quando o número de bots era superior a 10 mil ... o bot que escrevi é a versão mais "minimalista" do bot que eu poderia fazer, e é muito ruim, infelizmente.


Interface / Renderização da interface do usuário


Toda a renderização em imagem , lógica da interface do usuário no buffer B.


Renderização:
Dividir a tela em ladrilhos e desenhar uma tabela em cada ladrilho, carga mínima.


Lógica de carregamento de um mapa - cada pixel não é descompactado, cada pixel é descompactado, apenas o “bit necessário” é descompactado (literalmente), o código da função é:


 int maptmp(int id, int midg) { int nBits = 8; ivec4 pixeldata = loadat(id, midg); int itt = (id / 24) / 4; //data pixel id 0-2 int jtt = (id - itt * 24 * 4) / 24; //component in data pizel id 0-3 int ott = (id - itt * 24 * 4 - jtt * 24) / 8; //component in unpacked value 0-2 int ttt = (id - itt * 24 * 4 - jtt * 24 - ott * 8); //bit after int2bit 0-7 ivec3 val = decodeval16(pixeldata[jtt]); int n = val[ott]; for (int i = 0; i < nBits; ++i, n /= 2) { if (i == ttt) { if ((n % 2) == 0)return 0; else return 1; //switch + return does not work on windows(Angle) /*switch (n % 2) { case 0:return 0;break; case 1:return 1;break; }*/ } } return 0; } 

Para evitar pixelização durante a rolagem, a partir de 43000, a parte fracionária do flutuador é perdida e não é necessário adicionar 619 mil ao UV para rolagem (haverá pixels em vez de tabelas).
Toda a rolagem é dividida em um bloco grande e gira em um círculo, adicionando no máximo 32 a UV. (linha 207 na imagem ).


O mesmo é feito para determinar o ID do campo. (linha 215 na imagem )


UI


Números:
Amarelo é o número de campos tetris.
Deixado grande - o número do campo atual.
No canto inferior direito - os pontos do campo atual.


Origem e Lançamento


Bufer A lógica, Bufer B é controle de UI, Renderização de imagem
Fonte em https://www.shadertoy.com/view/3dlSzs (tempo de compilação até o ângulo 16 seg)
O bot está desativado lá (você pode habilitá-lo) e todos os campos podem ser reproduzidos no teclado.


Controle as setas esquerda / direita / cima / baixo.


Redefinição do retângulo vermelho da interface do usuário, mova (arraste o mouse clicando em LMB) e clique nos campos para rolar ou selecione o campo a ser exibido.


Inicie a partir de um navegador da web:


  • execute chrome com chrome.exe --use-angle = gl
  • siga o link para shadertoy
  • no editor do site, selecione Comum e exclua #define no_AI
  • (também em comum) defina #define AI 199 como 0, ou seja, #define AI 0
  • clique no botão de compilação (abaixo da janela do editor no shader) e clique em tela cheia

A segunda opção é executar o sombreador em qualquer "iniciador de sombreador", eis o link para o arquivo morto ( download ) no qual o arquivo * .exe com esse sombreador.


O tempo de compilação do OpenGL é de cerca de 10 segundos.


Atualização : adicionado um sombreador com verificação de orifício https://www.shadertoy.com/view/wsXXzH
em vez da condição para uma melhor posição na mesma altura. A função check_block_at_wh (linha 380 BufA) conta os furos juntamente com a verificação da validade da posição, nenhum novo ciclo foi adicionado e a linha de condição 442 a 459 BufA.
Ele também queima rapidamente em um minuto, dentro de 30 a 60 pontos (obviamente, você precisa verificar se há uma grande área em busca de orifícios, mas isso gera freios fortes).


E duas fotos explicando um pouco o trabalho:
seleção de posição https://i.imgur.com/e0uENgV.png
a posição do bloco para a condição é https://i.imgur.com/ORECXUW.png

Source: https://habr.com/ru/post/pt443042/


All Articles