検索ガイド -Search Guide-

単語と単語を空白で区切ることで AND 検索になります。
例: python デコレータ ('python' と 'デコレータ' 両方を含む記事を検索します)
単語の前に '-' を付けることで NOT 検索になります。
例: python -デコレータ ('python' は含むが 'デコレータ' は含まない記事を検索します)
" (ダブルクオート) で語句を囲むことで 完全一致検索になります。
例: "python data" 実装 ('python data' と '実装' 両方を含む記事を検索します。'python data 実装' の検索とは異なります。)
  • ただいまサイドメニューのテスト中/ただいまサイドメニューのテスト中
  • ただいまサイドメニューのテスト中/ただいまサイドメニューのテスト中
  • ただいまサイドメニューのテスト中/ただいまサイドメニューのテスト中
  • ただいまサイドメニューのテスト中/ただいまサイドメニューのテスト中
  • ただいまサイドメニューのテスト中/ただいまサイドメニューのテスト中
  • ただいまサイドメニューのテスト中/ただいまサイドメニューのテスト中
  • ただいまサイドメニューのテスト中/ただいまサイドメニューのテスト中
  • ただいまサイドメニューのテスト中/ただいまサイドメニューのテスト中
  • ただいまサイドメニューのテスト中/ただいまサイドメニューのテスト中
  • ただいまサイドメニューのテスト中/ただいまサイドメニューのテスト中
  • ただいまサイドメニューのテスト中/ただいまサイドメニューのテスト中
>>
effective_python

【 Effective Python, 2nd Edition + coding challenge 】プログラム開発のどの段階で並列処理 ( concurrency ) が必要になるのだろう? そのときどのようにリファクタリング ( refactoring ) していけばいいのだろう? を考えてみるシリーズ ( のはず ) 第1回 投稿一覧へ戻る

Published 2020年8月25日10:18 by mootaro23

SUPPORT UKRAINE

- Your indifference to the act of cruelty can thrive rogue nations like Russia -

プログラムが大きくなってくれば、必然的に、その複雑さも増していきます。


コードの明快さ、テストのし易さ、効率性を維持しながらプログラムを大きくしていくのは、プログラム開発における最も難しい課題のひとつであることは疑う余地がありません。


またプログラムの拡大に伴う変更の中でも、シングルスレッドプログラムのマルチスレッドプログラムへの移行はもっとも困難を伴うもののひとつでしょう。


今後数回は、この問題にどう対処していったらよいのか、ということを取り上げていければ、と考えています。


ということで、このシリーズでは、Conway's Game of Life の実装例で考えていきたいと思っていますので、


今回はこのゲームの coding challenge にしたいと思います。


Conway's Game of Life のルールはいたってシンプルです。


まず、任意の大きさの 2 次元グリッド ( Python では 2 次元のリストで表現します ) を用意します。


グリッド ( grid ) を構成する全てのセル ( cell ) は、生きている ( live ) か死んでいる ( dead ) 状態のどちらかをとります。


LIVE = '■' # 生存セル

DEAD = '□' # 死滅セル



プログラムはある 1 単位時間 ( 1 ティック, 1 tick ) で 1 ステップずつ進行します。


あるセルの次のステップにおける状態は、そのセルを取り囲む 8 つのセルの現在のステップにおける状態によって決定します。


もし現ステップで生存しているセルの場合、取り囲む 8 つのセルのうち 2 個もしくは 3 個のセルが生存していれば次のステップも生き続けます。


もし現ステップで死滅している場合、取り囲む 8 つのセルのうちピッタリ 3 個のセルが生存していれば復活 (誕生、生存) します。







また Conway's Game of Life において、グリッドの上と下、右と左はつながっているものと考えるため、あるセルがグリッドの端にある場合でも、取り囲むセルは常に 8 個存在します。







例えば、5 行 9 列のグリッドにおいて、最初の生存セルが (0, 3), (1, 4), (2, 2), (2, 3), (2, 4) である場合の遷移は次のような表示になります。


□□□■□□□□□   □□□□□□□□□   □□□□□□□□□   □□□□□□□□□   □□□□□□□□□   □□□□□□□□□
□□□□■□□□□   □□■□■□□□□   □□□□■□□□□   □□□■□□□□□   □□□□■□□□□   □□□□□□□□□
□□■■■□□□□ → □□□■■□□□□ → □□■□■□□□□ → □□□□■■□□□ → □□□□□■□□□ → □□□■□■□□□
□□□□□□□□□   □□□■□□□□□   □□□■■□□□□   □□□■■□□□□   □□□■■■□□□   □□□□■■□□□
□□□□□□□□□   □□□□□□□□□   □□□□□□□□□   □□□□□□□□□   □□□□□□□□□   □□□□■□□□□

□□□□□□□□□   □□□□□□□□□   □□□□□□□□□   □□□□□■□□□   □□□□□■■□□   □□□□□■■□□
□□□□□□□□□   □□□□□□□□□   □□□□□□□□□   □□□□□□□□□   □□□□□□□□□   □□□□□□□□□
□□□□□■□□□ → □□□□■□□□□ → □□□□□■□□□ → □□□□□□□□□ → □□□□□□□□□ → □□□□□□□□□
□□□■□■□□□   □□□□□■■□□   □□□□□□■□□   □□□□■□■□□   □□□□□□■□□   □□□□□■□□□
□□□□■■□□□   □□□□■■□□□   □□□□■■■□□   □□□□□■■□□   □□□□■□■□□   □□□□□□■■□



このパターンは、左上から右下に向けて斜めに移動しながら「生き延びていく」ものです。


では実装してみてください。( 制限時間: 150 分)


ヒント ( になるかな? ):

私は、まず、グリッドを象徴するクラスを用意しました。


class Grid:
"""
グリッドを象徴する
:param rows: 行数
:param columns: 列数
"""

def __init__(self, rows, columns):
self.rows = rows
self.columns = columns
# 与えられた行数、列数をもつ 2 次元リストを作成する。全ての要素のデフォルト値は DEAD
self.mat = [[DEAD] * self.columns for _ in range(self.rows)]

def get(self, row, column):
"""
対象セルの値 ( 状態: LIVE or DEAD ) を返す
"""

return self.mat[row % self.rows][column % self.columns]

def set(self, row, column, state):
"""
対象セルに値 ( 状態: LIVE or DEAD ) をセットする
"""

self.mat[row % self.rows][column % self.columns] = state

def __str__(self):
"""
このグリッドを象徴する文字列を返す
この文字列は '□□□\n■□□\n□□■\n■■□\n' のように、各列の末尾に '\n' が付加されたもの
"""

result = ''
for row in range(self.rows):
result += ''.join([self.mat[row][column] for column in range(self.columns)]) + '\n'
return result



このクラスを元に、以下のオブジェクトを作成し表示した結果が、上の出力例の左上のグリッドになります。


grid = Grid(5, 9)

grid.set(0, 3, LIVE)
grid.set(1, 4, LIVE)
grid.set(2, 2, LIVE)
grid.set(2, 3, LIVE)
grid.set(2, 4, LIVE)


print(grid)

# □□□■□□□□□
# □□□□■□□□□
# □□■■■□□□□
# □□□□□□□□□
# □□□□□□□□□



このほか、いくつかのヘルパー関数を用意し、最終的にそれらを組み合わせることでシミュレーションを達成しています。


実装例は、次回の記事で掲載します。


では、実装、楽しんでください!
この記事に興味のある方は次の記事にも関心を持っているようです...
- People who read this article may also be interested in following articles ... -
【 Effective Python, 2nd Edition + coding challenge 】プログラムを並列処理 ( concurrency ) パターンへ移行するタイミングとツールを考えるシリーズ 第2回 - Conway's Game of Life coding challenge の実装例と課題、の巻
【 Effective Python, 2nd Edition 】プログラムを並列処理 ( concurrency ) パターンへ移行するタイミングとツールを考えるシリーズ 第 5 回 - 並列処理 ( concurrency ) のためにスレッド ( thread ) を利用する場合は concurrent.futures モジュールの ThreadPoolExecutor の導入を検討しましょう、の巻
【 Effective Python, 2nd Edition 】プログラムを並列処理 ( concurrency ) パターンへ移行するタイミングとツールを考えるシリーズ 第 6 回 - コルーチン ( coroutines ) を利用して数多くのブロッキング I/O を並列処理する fan-out、fan-in パターンを実現しよう、の巻
【 Effective Python, 2nd Edition 】プログラムを並列処理 ( concurrency ) パターンへ移行するタイミングとツールを考えるシリーズ 第 4 回 - 並列処理 ( concurrency ) 実現のために queue を利用するとリファクタリング ( refactoring ) 作業が大変です、の巻
【 Effective Python, 2nd Edition 】プログラムを並列処理 ( concurrency ) パターンへ移行するタイミングとツールを考えるシリーズ 第 3 回 - Thread インスタンスの頻繁な start / join による fan-out / fan-in パターン実装は避けるべし、の巻
Python coding challenge - 変化球バイナリサーチアルゴリズム (binary search algorithm) を ループ処理 / 再帰処理 の2通りで実装してみよう!
【 Effective Python, 2nd Edition 】スレッド ( thread ) とコルーチン ( coroutine ) を混在させながら、asyncio を利用した非同期プログラムへ段階的に移行させよう!