Peluncuran 619 ribu tetris di GLSL, rendering dan bot sederhana

Saya punya "ide" untuk membuat jumlah maksimum menjalankan Tetris secara bersamaan untuk satu shader (satu tekstur framebuffer).


Berikut ini adalah deskripsi singkat tentang cara kerja kode yang dihasilkan.


Apa ini


Setiap tetris berfungsi dalam tiga piksel, untuk resolusi 1920x1080 Anda dapat menjalankan 619200 salinan sekaligus. Juga membuat bot sederhana untuk bermain otomatis.
Pada akhir posting, tautan untuk menjalankan dan sumber.
Video diperbarui, menunjukkan jumlah bidang yang tersisa, hingga nol.



Penyimpanan data


Tabel ukuran tetris [10, 22] (10 lebar, 22 tinggi).
Setiap sel bisa kosong atau tidak kosong.
Total 22 * 10 = 220 bit diperlukan untuk menyimpan seluruh tabel.
Satu "pixel" adalah empat float 24-bit, 96 bit per pixel.


Secara visual (bagian dari bingkai debug), tiga piksel disorot dalam warna merah, ini adalah satu bidang yang disimpan:


gambar


2 * 96 + 24 + 4
Dua piksel, satu float dari pixel ketiga, 4 bit float kedua dari pixel ketiga
Ada dua pelampung yang tidak terpakai di pixel3 pixel ketiga.zw , mereka menyimpan keadaan logika , lebih tepatnya


  • z menyimpan tiga angka delapan-bit [a,b,c]
    - posisi blok saat ini, sebagai ID posisi dalam array (array ukuran 220 bit, posisi maksimum 220 yang kurang dari 0xff)
    - b waktu sampai jatuh otomatis (timer) setiap frame -1 ke nomor ini, karena menjadi 0 maka jatuh pada blok ke bawah
    - ID c dari blok saat ini
  • w juga [a,b,c] , tetapi juga tanda (positif atau negatif) dari seluruh pelampung adalah bendera akhir pertandingan dalam tabel saat ini (agar tidak membuang-buang sumber daya jika lapangan kewalahan )
    - suatu tindakan, tidak ada tindakan (0), kiri (1), kanan (2), dan seterusnya, kode lengkap dalam Common , tindakan memiliki dua negara, periksa kiri dan periksa apakah mungkin untuk bergerak ke kiri, maka tindakan diatur ke kiri_ bergerak .
    - [b,c] 0xffff (16 bit) poin dari tabel saat ini, jumlah garis yang dibakar

Ada 20 tersisa tidak digunakan dalam float kedua dari pixel ketiga.


bingkai debug yang menunjukkan bahwa logika penyimpanan berfungsi dengan benar
di sebelah kiri ada bidang putih berukuran tiga piksel, atur khusus untuk menunjukkan bahwa celah diproses dengan benar (jika resolusinya bukan kelipatan tiga, strip akan miring)
kondisi pada saluran 75 Penyangga A


gambar


Mengapa saya memerlukan ID tindakan:


  • Data disimpan dalam tiga piksel, tidak mungkin untuk secara bersamaan memeriksa logika dan mengubah data dalam satu bingkai (tanpa mengeksekusi semua logika dan memuat seluruh peta di setiap piksel, beban akan meningkat puluhan kali).
  • Oleh karena itu, logika Penyimpanan Data berfungsi di setiap piksel dan menjalankan perintah yang diterima, gerakan kiri , perintah verifikasi pemeriksaan kiri dijalankan hanya dalam satu piksel (ketiga).

Tempat yang lambat


  • Setiap piksel ketiga (piksel logika) mendekompresi seluruh peta (membaca ketiga piksel).
  • Dua piksel yang tersisa hanya mendekompresi "dirinya" (satu piksel) untuk melakukan tindakan yang disimpan.
  • Selama aksi, garis dibakar, piksel lain dimuat, karena tabel jatuh dan bagian bawah tabel harus tahu apa yang ada di atas.

Kinerja Algoritma Penyimpanan


Untuk pengujian, atur #define debug ke Common dan AI 0 di sana juga.
Saya mendapat hasil seperti itu - 10FPS saat merender dan memproses semua 619200 bidang,
di 120 ribu bidang (25fps)


gambar


Logika bot


Logika Sangat buruk , bot terbakar dalam satu menit, dan mendapat hingga 60 poin.


Saya tidak dapat memulai logika yang baik dengan banyak siklus memeriksa lubang dan tepian dan bidang yang mudah terbakar, mengingat posisi terbaik berdasarkan semua kemungkinan jatuh ...
Logika yang bagus bekerja untuk saya hingga 100 salinan dan memberikan jeda yang kuat ketika melewati semua siklus.


Logika bot saya berfungsi seperti ini
Semua logika ada di fungsi AI_pos_gen di Buffer A, ada sepuluh baris di dalamnya.


Kodesemu:
periksa tinggi untuk pemasangan blok sama dengan maksimum untuk bidang pada kolom saat ini (periksa satu baris untuk ketinggian)


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

Ternyata tiga siklus itu biasa - mereka menempatkan blok sehingga tingginya minimal.


Fungsi AI_pos_gen dipanggil ketika blok baru muncul, dan mengembalikan posisi untuk jatuh dari atas , mengambil ID blok dan membuatnya berputar, fungsinya bekerja di pixel ketiga (logika), yaitu, ia memiliki peta yang dimuat penuh (array peta).
Anda dapat dengan mudah mencoba menulis bot Anda jika diinginkan.


Tempat paling lambat
Menambahkan hanya satu loop untuk menguji lubang , driver kartu video saya mogok ketika jumlah bot lebih dari 10 ribu ... bot yang saya tulis adalah versi bot paling "minimalis" dari bot yang bisa saya lakukan, dan sayangnya sangat buruk.


Antarmuka UI / Rendering


Semua render dalam Gambar , logika UI dalam Buffer B.


Rendering:
Membagi layar menjadi ubin dan menggambar meja di setiap ubin, beban minimum.


Logika memuat peta - setiap piksel tidak dibongkar, setiap piksel dibongkar, hanya "bit yang diperlukan" dibongkar (secara harfiah), kode fungsinya adalah:


 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; } 

Untuk menghindari pikselasi saat menggulir, mulai dari 43000, bagian pecahan float hilang, dan tidak berhasil menambahkan 619 ribu ke UV untuk menggulir (akan ada piksel alih-alih tabel).
Semua pengguliran dibagi menjadi satu ubin besar dan berputar dalam lingkaran menambahkan maksimum 32 ke UV. (baris 207 dalam Gambar ).


Hal yang sama dilakukan untuk menentukan ID bidang. (baris 215 pada Gambar )


UI


Angka:
Kuning adalah jumlah bidang tetris.
Kiri besar - jumlah bidang saat ini.
Di kanan bawah - titik-titik dari bidang saat ini.


Sumber dan Peluncuran


Bufer A logic, Bufer B adalah kontrol UI, rendering gambar
Sumber di https://www.shadertoy.com/view/3dlSzs (waktu kompilasi melalui Angle 16 detik)
Bot dinonaktifkan di sana (Anda dapat mengaktifkannya), dan semua bidang dapat dimainkan dari keyboard.


Kontrol panah kiri / kanan / atas / bawah.


Reset persegi panjang merah UI, pindahkan (seret mouse dengan mengklik LMB) dan klik bidang untuk menggulir atau memilih bidang yang akan ditampilkan.


Luncurkan dari browser web:


  • jalankan chrome dengan chrome.exe --use-angle = gl
  • ikuti tautan ke shadertoy
  • di editor di situs, pilih Common dan hapus #define no_AI
  • (juga sama) mengatur #define AI 199 ke 0, mis. #define AI 0
  • klik tombol kompilasi (di bawah jendela editor pada shader) dan klik layar penuh

Opsi kedua adalah menjalankan shader di "peluncur shader" apa pun, di sini adalah tautan ke arsip ( unduh ) di mana * .exe file dengan shader ini.


Waktu kompilasi OpenGL sekitar 10 detik.


Pembaruan : menambahkan shader dengan lubang memeriksa https://www.shadertoy.com/view/wsXXzH
bukannya kondisi untuk posisi yang lebih baik pada ketinggian yang sama. Fungsi check_block_at_wh (baris 380 BufA) menghitung lubang bersama dengan memeriksa validitas posisi, tidak ada siklus baru yang ditambahkan, dan baris kondisi 442 hingga 459 BufA.
Ini juga cepat terbakar dalam satu menit dalam 30-60 poin. (Jelas, Anda perlu memeriksa area yang luas untuk mencari lubang, tetapi ini memberikan rem yang kuat)


Dan dua gambar menjelaskan sedikit pekerjaan:
pemilihan posisi https://i.imgur.com/e0uENgV.png
posisi blokir untuk kondisinya adalah https://i.imgur.com/ORECXUW.png

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


All Articles