現在、最初のルールは常に「時期尚早に最適化しない」です。よりクリーンなコードよりもその最適化が必要であることを確認する必要があります。
さて、人生ゲームでは、最初はかなり空の画面を見ています。ただし、ゲームが進むにつれて、ますます多くのセルが埋められ、最終的にはボード全体が埋められます。現在、GOL 規則では、これらのセルのほとんどが 1 つのサイクルから別のサイクルに変化することが規定されています。
また、領域を「無効化」することの意味を理解する必要があります。Windows では、無効化された領域が「追加」されて「更新領域」が形成されるため、WM_PAINT メッセージが画面のどの部分を描画するかをプログラムに伝えることができます。Paint イベント ハンドラーではRectVisible
、セルを更新するかどうかを決定するために使用します。
言い換えれば、方法 1 を実行するための「コスト」 (ボードの寸法を n と仮定):
(n x n) x (redraw cell + update cell on screen)
セルをペイントする前にスクリーンをクリアすることを忘れないでください。そうしないと、最後のサイクルで「生きていた」セルが画面に残ります。したがって、これは、ライブ セルまたは空白のセルを画面全体に描画していることを前提としています。
方法 2 の「コスト」:
(v) x (redraw cell + update cell on screen) + (n x n) x (RectVisible call)
ここで、v = 変更されたセルの数 (以下の注意事項を参照)。
したがって、次の場合、方法 1 は方法 2 よりも高速です。
(n x n) x redraw < v x redraw + (n x n) x RectVisible
n2 x (redraw - RectVisible) < v x redraw
v > ((redraw - RectVisible) / redraw) x n2
v > (1 - RectVisible/redraw) x n2
つまり、変更されたセルの数は、1 から (RectVisible コスト / 再描画コスト) の比率を引いた値より大きくなければなりません。現在、RectVisible
特にセルの解像度が高い場合は、ビットマップを画面に描画する場合と比較して、通常は非常に高速です。したがって、Rectvisible/redraw は通常非常に小さい数値であり、方法 1 が方法 2 よりも高速になるのは、たとえばボードの 99% が同時に変更される可能性が低い場合のみです。
言い換えれば、方法 2 は通常DrawImage
、クリッピング領域の外側 (つまり、更新領域内ではない) で画像を描画する場合、操作全体をスキップするため、パフォーマンスが向上することがわかります。
警告 - あなたのコードはそのままでは機能しません
ただし、方法 2 のコードは機能しません。最後のサイクルで「生きている」セルを持っていた「死んだ」セルを「空白にする」ことを忘れないでください。つまり、「生きている」セルだけでなく、「変化した」セルを無効にします。複数のサイクルで「生きている」セルを無効にする必要はありません。したがって、MyInvalidate
メソッドのロジックには欠陥があります。