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です








All Articles