GLSLでの619千のテトリス、そのレンダリング、および単純なボットの発売

1つのシェーダー(1つのフレームバッファーテクスチャ)で同時に実行されるテトリスの最大数を作成する「アイデア」がありました。


以下は、結果のコードがどのように機能するかの簡単な説明です。


これは何ですか:


各テトリスは3ピクセルで動作し、 1920x1080解像度では、一度に619200コピーを実行できます。 また、自動再生用のシンプルなボットを作成しました。
投稿の最後に、実行およびソースへのリンクがあります。
ビデオが更新され、残りのフィールドの数がゼロまで表示されます。



データ保存


サイズ[10, 22] 10、22 [10, 22] (幅10、高さ22)のテトリステーブル。
各セルは空でも空でもありません。
テーブル全体を保存するには、合計22 * 10 = 220ビットが必要です。
1つの「ピクセル」は、ピクセルあたり96ビットの4つの24ビットフロートです。


視覚的に(デバッグフレームの一部)、3つのピクセルが赤で強調表示されます。これは1つの保存済みフィールドです。


画像


2 * 96 + 24 + 4
2つのピクセル、3番目のピクセルの1つのフロート、3番目のピクセルの2番目のフロートの4ビット
3番目のピクセルpixel3.zwには2つの未使用のフロートがあり、より正確にロジック状態を保存します



3番目のピクセルの2番目のフロートには20 が未使用のままです。


保存ロジックが正しく機能していることを示すデバッグフレーム
左側には、ギャップが正しく処理されることを示すために設定された3ピクセルのサイズの白いフィールドがあります(3の倍数ではない解像度では、ストリップは斜めになります)
75行目のバッファーAの状態


画像


アクションIDが必要な理由:



遅い場所



ストレージアルゴリズムのパフォーマンス


テストでは、 #define debugをCommonに設定し、 AI 0もそこに設定します。
私はこの結果を得ました -619,200のすべてのフィールドをレンダリングおよび処理するときに10FPS、
12万フィールド(25fps)


画像


ボットロジック


ロジック非常に悪い 、ボットは1分で燃え尽き、最大60ポイントを獲得します。


私は多くのサイクルで良いロジックを開始できませんでした、可能なすべての落下に基づいて最適な位置を考慮して、穴と棚と可燃性フィールドをチェックしました...
良いロジックは100コピーまで機能し、すべてのサイクルを回るときに大きな遅れが生じました。


ボットロジックは次のように動作します
すべてのロジックはバッファーAのAI_pos_gen関数にあり、10行あります。


擬似コード:
ブロックインストールの高さを現在の列のフィールドの最大値と同じにする(高さは1行で確認する)


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

ありふれた3つのサイクルが判明します-高さが最小になるようにブロックを配置します。


AI_pos_gen関数 、新しいブロックが表示されたときに呼び出され、 上から落下する位置を返し、ブロックIDを取得して回転させ、3番目のピクセル(ロジック)で機能します。つまり、完全に読み込まれたマップ(マップ配列)を持ちます。
必要に応じて、ボットを簡単に作成できます。


最も遅い場所
テストホールにループを1つ追加するだけで、ボットの数が1万を超えると、ビデオカードドライバーがクラッシュしました...私が書いたボットは、ボットの最も「最小」なバージョンであり、残念ながら非常に悪いです。


UIインターフェース/レンダリング


Imageのすべてのレンダリング、 バッファBの UIロジック


レンダリング:
画面はタイルに分割され、各タイルにテーブルを描画します。最小負荷です。


マップをロードするロジック-各ピクセルはアンパックされず、各ピクセルはアンパックされ、「文字通り」「必要なビット」のみがアンパックされます、機能コード:


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

43000から始まるスクロール中のピクセル化を回避するために、フロートの小数部分が失われ、スクロール用にUVに619千を追加しても機能しません(テーブルの代わりにピクセルがあります)。
すべてのスクロールは1つの大きなタイルに分割され、UVに最大32を追加して円状に回転します。 ( 画像の 207行目)。


フィールドIDを決定するために同じことが行われます。 ( 画像の 215行目)


UI


番号:
黄色はテトリスフィールドの数です。
左大-現在のフィールドの番号。
右下-現在のフィールドのポイント。


ソースと起動


Bufer Aロジック、 Bufer BはUIコントロール、 画像レンダリング
https://www.shadertoy.com/view/3dlSzsのソース(角度16秒でのコンパイル時間)
ボットはそこで無効にされ(有効にできます)、すべてのフィールドはキーボードから再生できます。


左/右/上/下矢印を制御します。


UIの赤い長方形をリセットし、移動(LMBをクリックしてマウスをドラッグ)し、フィールドをクリックしてスクロールするか、表示するフィールドを選択します。


Webブラウザーから起動します。



2番目のオプションは、任意の「シェーダーランチャー」でシェーダーを実行することです。このシェーダーで* .exeファイルがあるアーカイブ( ダウンロード )へのリンクがあります


OpenGLのコンパイル時間は約10秒です。


更新ホールチェック https://www.shadertoy.com/view/wsXXzHでシェーダーを追加
同じ高さでより良い位置の条件の代わりに。 関数check_block_at_wh (行380 BufA)。位置の有効性、新しいサイクルが追加されていないこと、および条件行442から459 BufAのチェックとともにホールがカウントされます。
また、30〜60ポイント以内で1分以内に急速に燃焼します(明らかに、穴の広い領域を確認する必要がありますが、これにより強いブレーキがかかります)。


そして、作品を少し説明する2つの写真:
ポジション選択https://i.imgur.com/e0uENgV.png
条件のブロック位置はhttps://i.imgur.com/ORECXUW.pngです



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


All Articles