最初にダブらないパズルゲームのステージ初期化の作り方

パズルゲームの初期ステージは完全ランダムだと好ましくない場合があります。

今回のブログでは縦横3つ揃わないようにするという条件でサンプルと考え方を紹介したいと思います。

ソースコード

import random


def generate_array(width: int, height: int, between:tuple[int]) -> list[int]:
    # width x heightの二次元配列を作成し、-1で初期化
    arr = [[-1 for _ in range(width)] for _ in range(height)]

    # 0から5までの数字をランダムに割り当てる
    for i in range(height):
        for j in range(width):
            while True:
                num = random.randint(between[0], between[1])
                if not is_continuous(arr, i, j, num):
                    arr[i][j] = num
                    break

    return arr


def is_continuous(arr, i, j, num):
    # 縦方向に3つ以上連続しているかをチェック
    if i >= 2 and arr[i - 1][j] == num and arr[i - 2][j] == num:
        return True
    # 横方向に3つ以上連続しているかをチェック
    if j >= 2 and arr[i][j - 1] == num and arr[i][j - 2] == num:
        return True
    return False


# 生成した二次元配列の表示
arr = generate_array(width=7, height=9, between=(1,5))
for row in arr:
    print(row)

下記は出力結果

> $ python initial_stage.py
[2, 4, 5, 5, 4, 1, 1]
[4, 2, 2, 3, 5, 3, 2]
[4, 5, 4, 2, 3, 4, 1]
[2, 3, 4, 2, 2, 5, 1]
[5, 3, 5, 4, 4, 1, 2]
[1, 2, 4, 5, 1, 3, 5]
[5, 3, 2, 3, 2, 1, 4]
[4, 1, 5, 1, 4, 4, 2]
[1, 4, 4, 3, 3, 5, 2]

> $ python initial_stage.py
[3, 5, 1, 5, 3, 4, 4]
[5, 1, 3, 4, 4, 1, 4]
[1, 3, 2, 1, 3, 3, 2]
[3, 5, 5, 1, 2, 4, 4]
[3, 5, 5, 2, 2, 1, 3]
[1, 4, 2, 2, 5, 4, 3]
[2, 1, 2, 5, 4, 5, 5]
[5, 5, 4, 3, 5, 3, 4]
[1, 1, 2, 5, 3, 1, 3]

解説

次のようなフローで作られています。

  1. 縦、横、数字の範囲(今回は1〜5)を指定します。
  2. 縦x横の大きさの二次元配列を-1で初期化して作成します。
  3. それぞれの値に1~5を割り当てます
    1. この時に左方向、または上方向に二つずつの値を取得し同じだった場合は再抽選します
    2. 左から2つ目まで、上から二つまでは判定できないので被りがないものとしています
  4. 全ての数字を入力できたら出来上がった二次元配列を返す

なお、今回の判定は縦か横なので、ぷよぷよみたいにギザギザでくっついているものは判定できてません。この場合はis_continuousの判定式を変更する必要があります。

懸念

  • 割り当てが不可能な場合、無限ループになる

今日はここまで、またお会いしましょう。