The Farmer Was Replaced— 코딩 게임 완전 해부
Chapter 04 · 솔버

선인장은 정렬을 기다린다 — 2D 버블정렬의 사계절

선인장 솔버는 게임에서 가장 우아한 알고리즘 중 하나다. plant → wait → sort rows → sort cols → harvest. 4단계 사이클이 무한히 반복되며, 버블정렬이 두 번(행, 열) 적용되어 2D 격자를 완전 정렬한다.

Bubble Sort 2D measure & swap Chain Worker

§ 14단계 사이클

선인장 솔버는 계절처럼 순환한다. 심고, 기다리고, 정렬하고, 수확한다.

Phase 1 — plant: 모든 타일에 선인장을 심는다. K개 드론이 행을 분담한다.

Phase 2 — wait: 선인장이 다 자랄 때까지 기다린다. can_harvest()가 True가 될 때까지 do_a_flip()으로 시간을 보낸다.

Phase 3 — rows: 각 행을 버블정렬한다. measure()로 크기를 비교하고 swap(East)로 교환한다.

Phase 4 — cols: 각 열을 버블정렬한다. measure() + swap(North).

마지막으로 harvest()로 정렬된 선인장을 수확한다. 그리고 처음부터 다시.

선인장 4단계 사이클 STEP 01 / 6
space 재생 · ← → 단계 · R 리셋

§ 2버블정렬: 행 방향

measure()로 현재 타일의 선인장 크기를 읽고, measure(East)로 오른쪽 타일의 크기를 읽는다. 오른쪽이 더 작으면 swap(East)로 교환한다.

bubble_row(y) — 행 버블정렬
def bubble_row(y):
    for j in range(N - 1):        # N-1 패스
        goto(0, y)
        swapped = False
        for i in range(N - 1):
            cur = measure()        # 현재 칸 크기
            east_val = measure(East)  # 오른쪽 칸 크기
            if east_val < cur:     # 오름차순 정렬
                swap(East)         # 인접 교환!
                swapped = True
            move(East)
        if not swapped:            # 이미 정렬됨
            break
행 버블정렬 — swap(East) 시각화 STEP 01 / 5
space 재생 · ← → 단계 · R 리셋

§ 3버블정렬: 열 방향

행 정렬 후 열 정렬을 수행한다. 동일한 버블정렬이지만 방향만 North로 바뀐다. measure(North)로 위쪽 크기를 읽고 swap(North)로 교환한다.

핵심 APImeasure()와 swap()

measure() — 현재 타일 엔티티의 크기(선인장) 또는 꽃잎 수(해바라기)를 반환
measure(East) — 인접 타일의 크기를 읽음. 방향 인자 사용
swap(East) — 현재 타일과 인접 타일의 엔티티를 교환. 물리적 이동이 아닌 데이터 교환!

§ 4왜 두 번 정렬해야 하는가

행만 정렬하면 각 행 내에서는 정렬되지만, 행 간에는 무질서하다. 열 정렬까지 해야 전체 격자가 정렬된다.

이것은 "행 정렬 → 열 정렬"이 1D 정렬 두 번으로 2D 정렬을 근사하는 기법이다. 완벽한 2D 정렬을 보장하려면 추가 패스가 필요할 수 있지만, 게임에서는 행+열 두 패스로 충분하다.

핵심 버블정렬은 O(N²)이지만, 게임의 N이 작고(6~32), 드론이 K개 행/열을 병렬로 처리하므로 실제로는 O(N²/K)에 가깝다. 게임 내에서 가장 중요한 건 시간 복잡도가 아니라 move 횟수 최소화다.

§ 5실전 코드: f_cactus.py

실제 게임에서 돌아가는 f_cactus.py는 클로저 팩토리 대신 체인 워커를 사용하여 더 간결하게 구현되어 있다. _phase 리스트로 현재 단계를 공유하고, _spawn_i로 드론 인덱스를 분배한다.

메인 루프
go0()
while True:
    run_phase("plant")    # 모든 타일에 심기
    run_phase("wait")     # 성장 대기
    run_phase("rows")     # 행 버블정렬
    run_phase("cols")     # 열 버블정렬
    goto(0, 0)
    harvest()             # 정렬된 선인장 수확!