Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Color Tiles 자동 플레이 봇 — 개발 명세

이 문서는 IDE(Claude Code 등)에서 바로 구현을 이어가기 위한 작업 지시서입니다. 게임: https://en.gamesaien.com/game/color_tiles/


1. 게임 규칙 요약

  • 빈칸(blank space)을 클릭한다.
  • 클릭한 칸을 기준으로 상/하/좌/우 네 방향 각각에서 가장 가까운 타일을 본다.
  • 그렇게 찾은 타일들 중 같은 색끼리 매칭되면 해당 타일들을 획득(제거)한다.
  • 타일 1개당 1점.
  • 제한시간 120초. 오답 클릭(매칭 0개) 시 시간 -10초.
  • 목표: 200점.

핵심 통찰 (사용자 요구사항)

  • 한 클릭으로 사라지는 타일은 항상 짝수다. 같은 색 타일이 "쌍"으로만 매칭되기 때문.
  • 따라서 고득점의 핵심은 고립 타일(영영 짝을 못 만나 보드에 남는 타일)을 최소화하여 보드를 끝까지 비워내는 것이다. → "고립 타일 최소화" 전략을 1순위로 둔다.

2. 전체 아키텍처

화면 캡처 기반 봇(게임 canvas는 단일 <canvas>라 DOM 파싱 불가).

[화면 캡처] → [격자 분할 + 색 인식] → [보드 배열 생성]
   → [후보 평가: 고립 최소화 우선] → [최적 빈칸 클릭] → [반복]

권장 모듈 분리(추후 파일 단위로 나눠도 됨, 초기엔 단일 파일 가능):

모듈 역할
capture 게임판 영역 스크린샷 (mss 권장, 빠름)
vision 격자 분할, 각 칸 중앙 픽셀 색 추출, 색 분류
board 2D 배열 모델. 0 또는 색 ID.
solver 클릭 후보 평가 및 최적 칸 선택 (핵심 로직)
control pyautogui 마우스 이동/클릭, 좌표 변환
calibrate 보정 모드: 게임판 bbox, 격자 크기, 색 팔레트 학습

3. 의존성 및 실행

# 의존성 설치
pip install mss pyautogui numpy opencv-python

# 보정 (첫 실행 또는 화면 배치가 바뀐 경우)
python calibrate.py

# 봇 실행 (게임을 브라우저에서 먼저 열어둘 것)
python main.py

중단: Ctrl+C 또는 마우스를 화면 좌상단으로 이동 (pyautogui FAILSAFE).

  • mss: 빠른 화면 캡처
  • pyautogui: 마우스 제어
  • numpy / opencv-python: 픽셀 처리, 색 군집화

macOS는 화면 기록/손쉬운 사용 권한 허용 필요. 다중 모니터/HiDPI(레티나) 환경은 캡처 좌표와 클릭 좌표 배율이 다를 수 있으니 보정 단계에서 반드시 검증할 것.


4. 보정(Calibration) 절차 — 먼저 구현

자동 플레이 전에 한 번 실행하여 환경값을 JSON으로 저장한다.

  1. 게임판 bbox 지정: 좌상단/우하단 두 점을 클릭하거나 좌표 입력으로 받음.
  2. 격자 크기(rows, cols) 결정: 게임 기본 보드 크기 확인 후 입력 (실제 보드 크기는 구현 중 화면에서 직접 카운트하여 확정할 것).
  3. 셀 크기 계산: cell_w = (x2-x1)/cols, cell_h = (y2-y1)/rows.
  4. 색 팔레트 학습: 현재 보드를 캡처해 모든 셀 중앙색을 모아 유사색을 군집화(예: HSV 거리 임계값) → 색 ID 부여. 빈칸 배경색도 한 클래스로.
  5. 결과를 config.json에 저장: bbox, rows, cols, palette, bg_color.

5. 색 인식 (vision)

  • 각 셀 중앙의 작은 패치(예: 5x5) 평균 RGB를 대표색으로 사용 (노이즈 완화).
  • RGB→HSV 변환 후 팔레트와 최근접 매칭.
  • 빈칸 판정: 배경(체크무늬 회색/흰색)에 가까우면 0(빈칸). 배경이 체크무늬라 두 톤이 번갈아 나오므로, 채도(S)가 매우 낮으면 빈칸으로 처리.
  • 매 프레임 전체 재인식하지 말고, 클릭으로 바뀐 영역만 갱신하면 빠름(최적화는 후순위).

6. 핵심 알고리듬 (solver) — 고립 타일 최소화 우선

6.1 한 칸 클릭 시 획득 타일 계산

def tiles_gained(board, r, c):
    # (r,c)가 빈칸일 때만 유효
    neighbors = {}  # 방향 -> (색, 위치)
    for dir in [up, down, left, right]:
        찾기: 그 방향으로 첫 번째 비어있지 않은 타일
        있으면 neighbors[dir] = (color, pos)
    # 같은 색끼리 그룹화. 2개 이상 같은 색이면 그 위치들 전부 획득.
    color별로 위치 모으고, 그룹 크기 >= 2 인 색의 위치들을 결과에 포함
    return 획득 위치 집합

확인된 동작: 한 클릭에서 같은 색이 3개 이상 만나면 그 색을 전부 제거한다.홀수 제거가 실제로 가능하다. (예시 이미지는 2개 케이스만 보여주지만, 3개 이상이면 3개 모두 사라짐.)

이것이 핵심 함정이다. 각 색의 보드 내 총 개수가 짝수라고 할 때, 홀수개를 한 번 제거하면 그 색의 잔여가 홀수가 되어 마지막에 1개가 고립될 위험이 생긴다. → 기본 원칙: 홀수 제거를 피하고 짝수로만 떨어낸다. → 부득이/의도적으로 홀수를 제거했다면, 같은 색을 다시 홀수개 제거해 (홀수 + 홀수 = 짝수) 그 색의 잔여가 0으로 깔끔히 떨어지게 만든다.

6.2 후보 평가 점수 (고립 최소화가 1순위)

각 빈칸 후보에 대해 다음을 계산해 정렬:

  1. gained = 이번 클릭으로 없어지는 타일 수 (많을수록 좋음)
  2. isolation_after = 클릭 후 보드에서 "더 이상 어떤 색과도 같은 행/열에서 매칭 불가능해질" 타일 수 추정 (적을수록 좋음) — 최우선 가중치
  3. parity_risk = 이 클릭이 만들어내는 색별 홀짝 위험 (6.2.1 참고)
  4. 동점이면 gained 큰 쪽, 그다음 보드 중앙 가까운 쪽 등 타이브레이크.
정렬 키 (사전식, 작을수록 우선):
   ( isolation_after,      # 1순위: 고립 최소화
     parity_risk,          # 2순위: 홀짝 위험 최소화
     -gained,              # 3순위: 많이 제거
     tie_breaker )

6.2.1 색별 패리티(홀짝) 추적 — 홀수 제거 함정 회피

홀수 제거가 가능하므로, 색마다 "보드 잔여 개수의 홀짝"을 항상 추적한다. 초기 보드에서 각 색의 총 개수를 세어 시작한다.

remaining[color] = 보드에 남아있는 그 색 타일 수   # 매 클릭 후 갱신

후보 클릭이 색 C를 k개 제거한다고 할 때(k는 그 클릭에서 색 C로 매칭된 개수):

  • 클릭 후 remaining[C] 가 짝수로 유지/도달 → 안전 (parity_risk += 0)
  • 클릭 후 remaining[C] 가 홀수가 됨 → 위험. 단, 그 색이 보드에 아직 홀수개 더 매칭될 여지가 있으면(즉 나중에 홀수+홀수=짝수로 회수 가능하면) 경미한 위험으로 취급. 회수 불가(잔여가 흩어져 더 못 만남)면 큰 페널티.
def parity_risk(board_after, removed_color, k):
    rem = remaining_after[removed_color]
    if rem % 2 == 0:
        return 0                      # 짝수 잔여 → 안전
    # 홀수 잔여가 됐다. 회수 가능성 평가:
    if 같은_색이_앞으로_홀수개_매칭_가능(board_after, removed_color):
        return 1                      # 만회 경로 있음 (홀+홀=짝)
    else:
        return 10                     # 만회 불가 → 고립 확정 위험, 강한 회피

운용 규칙 요약:

  • 평상시: 색 C의 잔여를 짝수로 유지하는 클릭을 선호(짝수 제거).
  • 홀수를 제거하게 되는 경우: 그 색의 잔여를 다시 홀수개 제거해 0(짝수)으로 떨어뜨릴 경로가 보장될 때만 허용. 추적 중인 "홀수 부채(odd debt)" 색은 우선적으로 해소하도록 점수 가중.
  • 매 클릭 후 remaining[] 갱신 → 다음 후보 평가에 즉시 반영(탐욕적이되 패리티 인지).

6.3 고립도 추정 (간단 버전 → 점진 고도화)

  • v1(간단): 각 색에 대해 보드에 남은 개수가 홀수면 +1 페널티(언젠가 1개는 고립).
  • v2: 행/열별로 같은 색이 더 이상 만날 수 없는 배치인지 검사.
  • v3(선택): 짧은 수읽기(1~2수 시뮬레이션) 후 잔여 고립 최소 경로 선택.
  • 먼저 v1으로 동작시키고, 점수가 안 나오면 v2/v3로 고도화.

6.4 오답 회피

  • gained == 0 인 칸은 절대 클릭 금지(시간 -10초). 후보에서 제외.
  • 유효 후보가 없으면 클릭하지 않고 잠깐 대기 후 재인식.

7. 제어(control) & 루프

보정값 로드
while time_left > 0:
    frame = capture()
    board = recognize(frame)
    if board 비었으면 break  # 클리어
    cand = solver.best_click(board)
    if cand is None: continue
    screen_xy = cell_to_screen(cand)
    pyautogui.click(screen_xy)
    sleep(짧게)  # 애니메이션/반영 대기
  • 안전장치: 마우스를 화면 좌상단으로 옮기면 pyautogui FAILSAFE로 즉시 중단.
  • 키보드 인터럽트(Ctrl+C)로 종료 가능하게.
  • 클릭 간 딜레이는 게임 반영 속도에 맞춰 튜닝(처음엔 0.15~0.3s).

8. 구현 순서 (체크리스트)

  • 의존성 설치 및 config.json 스키마 정의
  • 보정 모드: bbox/격자/색 팔레트 저장
  • vision: 보드 → 2D 배열 (콘솔에 보드 출력해 눈으로 검증)
  • solver tiles_gained 구현 + 단위 테스트(작은 보드 손계산 대조)
  • 실제 게임 동작 검증: 3개 이상 같은 색 = 전부 제거(홀수 제거 가능) 재확인
  • 색별 패리티 추적(remaining[]) 구현 — 홀수 제거 함정 회피 (6.2.1)
  • solver 후보 평가 v1(고립 + 패리티 위험) + 오답 회피
  • control 루프로 한 클릭씩 자동 진행 (느린 딜레이로 관찰)
  • 점수 측정 → 부족하면 고립도 v2/v3로 고도화, 딜레이 단축
  • 200점 도달까지 튜닝

9. 주의/리스크

  • 색 인식 오류가 가장 흔한 실패 원인. 보정에서 팔레트를 충분히 학습하고, 애니메이션 중 캡처를 피하도록 클릭 후 딜레이를 둘 것.
  • HiDPI/멀티모니터 좌표 배율 문제를 보정 단계에서 클릭 정확도로 반드시 검증.
  • 리더보드가 있는 사이트라면 자동화는 약관 위반일 수 있음. 개인 학습/실험 용도로, 본인 화면에서만 사용할 것.
  • "홀수 제거가 가능하다"는 점이 솔버의 핵심 함정이다. 색별 패리티(remaining[])를 반드시 추적해, 홀수 제거 후 잔여가 짝수로 회수되는 경로가 있을 때만 허용할 것(6.2.1). 추적이 어긋나면 마지막에 1개씩 고립되어 200점(완전 클리어)이 막힌다.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages