✅ 가장 먼저 확인할 것
실행 직후 사람 위치는 (8,4), 컴퓨터 위치는 (0,4)입니다.
사람이 UP 버튼을 한 번 누르면 사람은 (7,4)로 이동하고,
곧바로 컴퓨터는 (1,4)로 이동해야 합니다.
사람이 UP 버튼을 한 번 누르면 사람은 (7,4)로 이동하고,
곧바로 컴퓨터는 (1,4)로 이동해야 합니다.
🔧 이번 수정 핵심
이전 버전에서는 컴퓨터가 후보 이동을 만든 뒤 BFS로 가장 좋은 후보를 선택했습니다. 이번에는 그 구조를 제거했습니다. 컴퓨터는 자신의 목표가 아래쪽이므로 우선 아래로 한 칸 이동하고, 앞이 막혔을 때만 좌우 또는 위쪽을 시도합니다.
즉, 이번 버전은 먼저 “컴퓨터 말이 확실히 움직이는가?”를 검증하는 안정판입니다. 이동이 정상 확인된 뒤 BFS AI와 방해벽 전략을 다시 단계적으로 붙이는 것이 안전합니다.
💻 Web VPython 3.2 전체 코드
Web VPython 3.2
# ============================================================
# QUORIDOR - 사람(파랑) vs 컴퓨터(빨강)
# 컴퓨터 말 확실히 이동하는 안정판
#
# 핵심:
# 1) 사람은 버튼으로 직접 이동
# 2) 컴퓨터는 매 턴 목표 방향(+row)으로 직접 이동 시도
# 3) 앞이 막히면 좌/우, 그다음 위쪽을 시도
# 4) 복잡한 BFS 이동 선택을 제거해 CPU가 반드시 움직이도록 단순화
# ============================================================
N = 9
HALF = 4
human = [8,4]
cpu = [0,4]
human_walls = 10
cpu_walls = 10
h_walls = []
v_walls = []
mode = "MOVE"
game_over = False
cursor_r = 3
cursor_c = 3
scene.width = 900
scene.height = 680
scene.background = vector(0.06,0.08,0.12)
scene.center = vector(0,0,0)
scene.range = 6
scene.forward = vector(0,-0.9,-0.55)
def pof(r,c):
return vector(c-HALF,0,r-HALF)
# ------------------------------------------------------------
# 보드
# ------------------------------------------------------------
base = box(
pos=vector(0,-0.2,0),
size=vector(9.5,0.25,9.5),
color=vector(0.20,0.14,0.08)
)
cells = []
for r in range(N):
row = []
for c in range(N):
p = pof(r,c)
sq = box(
pos=vector(p.x,0,p.z),
size=vector(0.86,0.08,0.86),
color=vector(0.68,0.48,0.27)
)
row.append(sq)
cells.append(row)
# ------------------------------------------------------------
# 말
# ------------------------------------------------------------
human_piece = cylinder(
pos=pof(human[0],human[1])+vector(0,0.05,0),
axis=vector(0,0.50,0),
radius=0.30,
color=color.cyan
)
cpu_piece = cylinder(
pos=pof(cpu[0],cpu[1])+vector(0,0.05,0),
axis=vector(0,0.50,0),
radius=0.30,
color=color.red
)
wall_cursor = box(
pos=vector(0,0.45,0),
size=vector(1.9,0.10,0.12),
color=color.yellow,
opacity=0
)
scene.append_to_caption("\n")
status = wtext(text="상태: 시작")
scene.append_to_caption("\n")
debug = wtext(text="사람 위치: (8,4) / 컴퓨터 위치: (0,4)")
scene.append_to_caption("\n")
wallinfo = wtext(text="내 벽: 10 / 컴퓨터 벽: 10")
scene.append_to_caption("\n\n")
# ------------------------------------------------------------
# 화면 갱신
# ------------------------------------------------------------
def redraw():
human_piece.pos = pof(human[0],human[1]) + vector(0,0.05,0)
cpu_piece.pos = pof(cpu[0],cpu[1]) + vector(0,0.05,0)
debug.text = (
"사람 위치: (" + str(human[0]) + "," + str(human[1]) +
") / 컴퓨터 위치: (" + str(cpu[0]) + "," + str(cpu[1]) + ")"
)
wallinfo.text = (
"내 벽: " + str(human_walls) +
" / 컴퓨터 벽: " + str(cpu_walls)
)
# ------------------------------------------------------------
# 벽 판정
# ------------------------------------------------------------
def blocked(r1,c1,r2,c2):
# 위/아래 이동 -> 가로벽 검사
if c1 == c2:
top = r1
if r2 < r1:
top = r2
for w in h_walls:
if w[0] == top:
if w[1] == c1 or w[1]+1 == c1:
return True
# 좌/우 이동 -> 세로벽 검사
if r1 == r2:
left = c1
if c2 < c1:
left = c2
for w in v_walls:
if w[1] == left:
if w[0] == r1 or w[0]+1 == r1:
return True
return False
# ------------------------------------------------------------
# 칸 색 표시
# ------------------------------------------------------------
def clear_colors():
for r in range(N):
for c in range(N):
cells[r][c].color = vector(0.68,0.48,0.27)
def show_human_moves():
clear_colors()
dirs = [
[-1,0],
[1,0],
[0,-1],
[0,1]
]
for d in dirs:
nr = human[0] + d[0]
nc = human[1] + d[1]
if nr >= 0 and nr < N and nc >= 0 and nc < N:
if not blocked(human[0],human[1],nr,nc):
cells[nr][nc].color = color.yellow
# ------------------------------------------------------------
# 사람 직접 이동
# ------------------------------------------------------------
def direct_human_move(dr,dc):
global human
global game_over
if game_over:
return
if mode != "MOVE":
status.text = "상태: MOVE 버튼을 먼저 누르세요."
return
r = human[0]
c = human[1]
nr = r + dr
nc = c + dc
if nr < 0 or nr >= N or nc < 0 or nc >= N:
status.text = "상태: 보드 밖으로 갈 수 없습니다."
return
if blocked(r,c,nr,nc):
status.text = "상태: 벽 때문에 이동할 수 없습니다."
return
# 컴퓨터 말과 같은 칸이면 한 칸 더 점프 시도
if nr == cpu[0] and nc == cpu[1]:
jr = nr + dr
jc = nc + dc
if jr < 0 or jr >= N or jc < 0 or jc >= N:
status.text = "상태: 상대 뒤가 보드 끝입니다."
return
if blocked(nr,nc,jr,jc):
status.text = "상태: 상대 뒤가 벽이라 점프할 수 없습니다."
return
human = [jr,jc]
else:
human = [nr,nc]
redraw()
clear_colors()
if human[0] == 0:
game_over = True
status.text = "상태: 당신의 승리!"
return
status.text = "상태: 컴퓨터 차례"
cpu_turn()
# ------------------------------------------------------------
# 컴퓨터가 한 칸 갈 수 있는지
# ------------------------------------------------------------
def cpu_can_go(nr,nc):
if nr < 0 or nr >= N or nc < 0 or nc >= N:
return False
if blocked(cpu[0],cpu[1],nr,nc):
return False
# 사람 말이 있으면 그 칸으로 직접 못 감
if nr == human[0] and nc == human[1]:
return False
return True
# ------------------------------------------------------------
# 컴퓨터 직접 이동
# 목표는 row 8
# 우선순위: 아래 -> 왼쪽 -> 오른쪽 -> 위
# ------------------------------------------------------------
def cpu_move_direct():
global cpu
r = cpu[0]
c = cpu[1]
# 1. 아래로
if cpu_can_go(r+1,c):
cpu = [r+1,c]
return True
# 2. 왼쪽
if cpu_can_go(r,c-1):
cpu = [r,c-1]
return True
# 3. 오른쪽
if cpu_can_go(r,c+1):
cpu = [r,c+1]
return True
# 4. 위로
if cpu_can_go(r-1,c):
cpu = [r-1,c]
return True
return False
# ------------------------------------------------------------
# 컴퓨터 턴
# ------------------------------------------------------------
def cpu_turn():
global game_over
if game_over:
return
moved = cpu_move_direct()
redraw()
if moved:
status.text = (
"상태: 컴퓨터 이동 완료 -> (" +
str(cpu[0]) + "," + str(cpu[1]) + ")"
)
else:
status.text = "상태: 컴퓨터가 움직일 수 없습니다."
if cpu[0] == 8:
game_over = True
clear_colors()
status.text = "상태: 컴퓨터 승리"
return
# 사람이 다시 움직일 수 있게 표시
show_human_moves()
# ------------------------------------------------------------
# 이동 모드
# ------------------------------------------------------------
def enter_move_mode():
global mode
if game_over:
return
mode = "MOVE"
wall_cursor.opacity = 0
show_human_moves()
status.text = "상태: MOVE | 방향 버튼으로 이동"
# ------------------------------------------------------------
# 벽 커서
# ------------------------------------------------------------
def update_cursor():
global cursor_r
global cursor_c
if cursor_r < 0:
cursor_r = 0
if cursor_r > 7:
cursor_r = 7
if cursor_c < 0:
cursor_c = 0
if cursor_c > 7:
cursor_c = 7
p = pof(cursor_r,cursor_c)
wall_cursor.opacity = 0.8
wall_cursor.pos = vector(p.x+0.5,0.45,p.z+0.5)
if mode == "H":
wall_cursor.size = vector(1.9,0.10,0.12)
elif mode == "V":
wall_cursor.size = vector(0.12,0.10,1.9)
# ------------------------------------------------------------
# 벽 설치 가능 여부
# ------------------------------------------------------------
def wall_same(kind,r,c):
if kind == "H":
for w in h_walls:
if w[0] == r and w[1] == c:
return True
else:
for w in v_walls:
if w[0] == r and w[1] == c:
return True
return False
def can_wall(kind,r,c):
if r < 0 or r > 7 or c < 0 or c > 7:
return False
if wall_same(kind,r,c):
return False
if kind == "H":
for w in v_walls:
if w[0] == r and w[1] == c:
return False
else:
for w in h_walls:
if w[0] == r and w[1] == c:
return False
return True
def draw_wall(kind,r,c,col):
p = pof(r,c)
if kind == "H":
box(
pos=vector(p.x+0.5,0.34,p.z+0.5),
size=vector(1.9,0.65,0.12),
color=col
)
else:
box(
pos=vector(p.x+0.5,0.34,p.z+0.5),
size=vector(0.12,0.65,1.9),
color=col
)
# ------------------------------------------------------------
# 방향 버튼
# ------------------------------------------------------------
def up_btn(b):
global cursor_r
if mode == "MOVE":
direct_human_move(-1,0)
else:
cursor_r = cursor_r-1
update_cursor()
def down_btn(b):
global cursor_r
if mode == "MOVE":
direct_human_move(1,0)
else:
cursor_r = cursor_r+1
update_cursor()
def left_btn(b):
global cursor_c
if mode == "MOVE":
direct_human_move(0,-1)
else:
cursor_c = cursor_c-1
update_cursor()
def right_btn(b):
global cursor_c
if mode == "MOVE":
direct_human_move(0,1)
else:
cursor_c = cursor_c+1
update_cursor()
# ------------------------------------------------------------
# 모드 버튼
# ------------------------------------------------------------
def move_btn(b):
enter_move_mode()
def h_btn(b):
global mode
if game_over:
return
mode = "H"
clear_colors()
update_cursor()
status.text = "상태: H-WALL | 방향 버튼으로 노란 벽 이동"
def v_btn(b):
global mode
if game_over:
return
mode = "V"
clear_colors()
update_cursor()
status.text = "상태: V-WALL | 방향 버튼으로 노란 벽 이동"
# ------------------------------------------------------------
# 벽 설치
# ------------------------------------------------------------
def place_btn(b):
global human_walls
if game_over:
return
if mode != "H" and mode != "V":
status.text = "상태: H-WALL 또는 V-WALL을 먼저 선택하세요."
return
if human_walls <= 0:
status.text = "상태: 남은 벽이 없습니다."
return
if not can_wall(mode,cursor_r,cursor_c):
status.text = "상태: 이 위치에는 벽을 놓을 수 없습니다."
return
if mode == "H":
h_walls.append([cursor_r,cursor_c])
else:
v_walls.append([cursor_r,cursor_c])
draw_wall(mode,cursor_r,cursor_c,color.cyan)
human_walls = human_walls-1
wall_cursor.opacity = 0
redraw()
status.text = "상태: 벽 설치 완료 / 컴퓨터 차례"
cpu_turn()
# ------------------------------------------------------------
# 버튼 배치
# ------------------------------------------------------------
button(text="UP",bind=up_btn)
scene.append_to_caption(" ")
button(text="DOWN",bind=down_btn)
scene.append_to_caption(" ")
button(text="LEFT",bind=left_btn)
scene.append_to_caption(" ")
button(text="RIGHT",bind=right_btn)
scene.append_to_caption("\n\n")
button(text="MOVE",bind=move_btn)
scene.append_to_caption(" ")
button(text="H-WALL",bind=h_btn)
scene.append_to_caption(" ")
button(text="V-WALL",bind=v_btn)
scene.append_to_caption(" ")
button(text="PLACE WALL",bind=place_btn)
scene.append_to_caption("\n\n")
# ------------------------------------------------------------
# 시작
# ------------------------------------------------------------
redraw()
enter_move_mode()
print("======================================")
print("QUORIDOR 컴퓨터 말 직접 이동 안정판")
print("======================================")
print("사람 시작 = (8,4)")
print("컴퓨터 시작 = (0,4)")
print("사람이 UP 버튼을 누르면")
print("사람 -> (7,4)")
print("컴퓨터 -> (1,4)")
print("가 되어야 정상입니다.")