일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 메타
- 아두이노
- 휴머노이드 로봇
- 가상환경
- 딥마인드
- 생성형 AI
- LLM
- 티스토리챌린지
- 인공지능
- 오픈AI
- 멀티모달
- ControlNet
- 딥러닝
- 뉴럴링크
- ChatGPT
- PYTHON
- AI
- 서보모터
- OpenAI
- 일론 머스크
- LORA
- 우분투
- 트랜스포머
- 오블완
- 확산 모델
- TRANSFORMER
- ubuntu
- AI 기술
- 시간적 일관성
- tts
- Today
- Total
AI 탐구노트
'픽셀 넘버' 게임 : 예능 속 퍼즐을 직접 만들어보자 본문
1.들어가며: '대학전쟁'이 뿌린 씨앗
오늘은 바람이 서늘해지며 겨울이 다가왔음을 느끼게 하는 날씨입니다. 이런 날, 따뜻한 방 안에서 머리를 쓰며 퀴즈나 퍼즐을 푸는 재미는 어떨까요? 최근 방송된 예능 프로그램 ‘대학전쟁’의 한 장면을 떠올리며 시작된 이야기를 함께 나눠보려 합니다.
최근 쿠팡플레이를 통해 '대학전쟁'이라는 예능 프로그램을 본 적이 있습니다. 국내외 최고 대학들에서 재학 중인 뛰언잔 인재들이 자신의 대학을 대표해서 다른 학교의 학생들과 수학, 논리 등을 활용해 퀴즈, 퍼즐을 풀며 대결을 펼치는 컨셉이죠. 매회 메인매치에서 꼴지하는 팀이 탈락하게 되기 때문에 참가자 뿐만 아니라 보고 있는 시청자들도 긴장을 늦출 수 없는 재미 요소를 제공합니다. 게다가 매회 창의적이고 기발한 퀴즈와 퍼즐로 화제를 모으고 있기도 하구요. 참가자 전원이 대학이라는 이름을 떠나 각자의 필살기도 가지고 있고, 문제를 바라보는 시각, 그리고 그걸 풀어가는 과정에서 참신한 아이디어도 많이 제시해서 보는 내내 흥미진진 했었습니다.
한가지 아쉬웠던 것은, 문제가 저한테는 다소 어려워서(T^T) 방송 화면에 잠시잠깐씩 보여지는 것만 가지고는 주어진 짧은 시간 내에 어떻게 접근해야 할지 감을 못 잡기도 했다는 것입니다. 시청자가 직접 참여하기에는 시간도, 문제의 난이도도 딱 맞지는 않았던 것이죠. 일단 이 프로그램은 '참가자들이 어떻게 하는지 보는 것에 더 방점을 두세요...' 라고 말하는 것 같았습니다. 뭐 그것도 나쁘지는 않았습니다. 참가자 각각의 표정과 행동, 아이디어를 짜내는 과정 등 볼만한게 많았으니까요.
이 방송에서는 상당히 많은 게임들이 소개되었습니다. 그 가운데 하나를 보다가 '이건 만들어보면 재미있겠는데?' 싶은 것이 있었습니다. '픽셀 넘버'라는 게임이었죠. 방송 상에 나온 수학과 논리를 활용한 문제는 단순히 푸는 것만으로도 대단한 성취감을 줬지만 이 녀석은 단순히 푸는 것을 넘어 퀴즈를 직접 만들어보는 즐거움을 줄 수 있을 것 같았거든요. ^^;
2.픽셀넘버 게임: 어떻게 하는거야?
픽셀넘버 게임은 다음과 같은 원칙을 가지고 있습니다.
- '픽셀 넘버'는 그림을 겁쳤을 때 숫자를 만들어 내는 픽셀 조합을 더 많이 찾아내는 팀이 승리하는 게임입니다.
- 대결 시작과 동시에 3개의 타깃 넘버와 15개의 픽셀 카드가 공개됩니다.
- 타깃 넘버는 픽셀 카드들을 겹쳐 놓았을 때 보이는 숫자를 의미하며, 타깃 넘버를 만들 때 최소 3장 이상의 픽셀 카드가 사용되어야 합니다.
- 정답 판정을 받은 타깃 넘버와 픽셀 카드는 다시 사용될 수 없습니다.
- 제시된 3개의 타깃 넘버를 다 맞추면 게임은 끝나며 가장 많이 맞힌 팀이 승리하게 됩니다.
3.만들어 보자: 아니... 만들도록 시켜보자...
원리는 정해져 있으니 ChatGPT가 코드로 만드는 것은 어렵지 않을 것 같았습니다. 룰을 알려주고 몇 가지 제약사항을 알려주면 금방 끝나겠지 싶었죠.
쉽게 되겠지?: 그럴리가 있겠나...
ChatGPT 의 코딩 실력을 너무 믿었던 것 같습니다. 사실 ChatGPT의 한계가 아니라 어떻게 가이드를 하느냐의 문제일테니 정확히는 저의 문제였다고 하는게 맞겠죠. 우선 제가 제시한 내용은 다음과 같았습니다.
- 게임 설명은 위에 언급한 것을 그대로 이용했습니다.
- 게임의 예시는 인터넷 상에 공개되어 있는 당시 영상 캡처 이미지를 이용했고 아래 그림에 대한 설명을 제시했습니다.
그리고 개발되어야 하는 프로그램에 대한 가이드를 제시했습니다.
- 정답을 텍스트로 입력 받도록 해야 합니다. 예는 '6,1,4,7' 6은 타깃넘버, 1,4,7은 픽셀카드 번호입니다.
- 입력이 완료되면 선택한 타깃넘버와 선택한 픽셀카드 조합으로 만들어지는 결과물을 나란히 보여주고 정답 여부를 판정하는 화면이 있어야 합니다.
- 기타 등등....
ChatGPT 4o의 결과물
ChatGPT 4o의 경우, 가이드에 대해 다음과 같은 결과물을 제시했습니다. 흠... 뭔가 내가 제대로 된 가이드를 제시하지 않아서 그런 모양이구나 싶었죠. ChatGPT의 실력에 대해서는 똑똑한 녀석이니 의심하지 않았기 때문입니다.
Claude의 결과물
혹시나 싶어서 Claude에게 같은 가이드로 작성을 요청해 봤습니다. 그랬더니... 아래와 같은 기능을 구현해서 보여주었습니다. 헉... 이렇게 이해의 수준이 다르고 개발하는 방식도 다르다니... 최근 Claude가 훨씬 낫다 뭐 이런 얘기를 들은 바가 있었지만 그래도 이 정도까지? 하는 생각에 놀랐습니다.
아쉽게도 저는 Claude 유료 구독을 하고 있지 않아 하루에 질문할 수 있는 횟수 제한이 있어서 더 이상 사용할 수가 없었습니다. 유료 사용이면 몇 가지 추가적인 가이드를 주면 금방 문제가 해결될 듯 싶었는데 말입니다. 그래서 다시 ChatGPT 한테 추가적인 요청을 해 보기로 했죠. 게다가 Claude가 React를 이용하도록 된 코드를 제시하는데 저는 React를 사용해 보지 않아서 방식도 바꿀 필요가 있었습니다.
접근 방법을 바꾸다
ChatGPT를 이용해야 하니 아예 접근 방법을 바꿔야겠다는 생각이 들었습니다. 그래서 아래와 같이 진행키로 했죠.
- python을 이용하도록 하고 터미널에서 먼저 생성해 본 후에 GUI 화면으로 전환
- 3x5 격자로 숫자 생성하는 코드 만들기 (1~9) -> 타깃넘버의 기본형을 만듦
- 숫자가 선택되면 타깃넘버의 격자를 분해해서 3개로 나눠주는 함수를 생성. 원래 게임은 4개로도 분해가 가능하지만 게임을 간단하게 만들기 위해 이렇게 제한함.
- 숫자 3개를 입력받아 각각 해당 타깃넘버의 격자, 그리고 나머지 분해격자 3개와, 랜덤하게 추가 6개를 생성해서 반환하는 함수 생성. 단 분해격자 15개는 중복 불가
- 위 구현된 내용을 이용해 GUI 형태로 개발 진행
처음에는 ChatGPT가 Flask, HTMl, CSS ,Javascript 이용 방식으로 제시했습니다. 아무래도 화면 UI를 만들어야 하니 제일 손쉬운 방식으로 접근했을 것 같습니다. React가 아니라 다행이다 생각했죠. 하지만, 구성요소가 많다보니 만들어진 코드가 제대로 동작하지 않는 경우가 많아 디버깅, 반복적인 테스트 등 시행착오가 많이 발생했습니다. 그래서, 시각화를 위해 웹 기반이 아닌 Tkinter를 이용하는 방식으로 전환해서 개발하는 것으로 했고 결과는 아래 화면과 같습니다. 여기까지는 아직도 넘어야 할 산이 많이 남았습니다.
이후 정답 입력 방식과 픽셀카드 선택 방식, UI 요소, 배치 방식, 정렬 변경, 내부 처리 로직 구현 등 많은 것이 바뀌었고 그때마다 역시나 시행착오가 있었습니다. 이 과정은 생략하겠습니다.
최종 코드
이런저런 시행 착오 끝내 나온 결과물은 다음과 같습니다.
import random
import tkinter as tk
from tkinter import messagebox
# Digit grids 정의
digit_grids = {
1: [[0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1]],
2: [[1, 1, 1], [0, 0, 1], [1, 1, 1], [1, 0, 0], [1, 1, 1]],
3: [[1, 1, 1], [0, 0, 1], [1, 1, 1], [0, 0, 1], [1, 1, 1]],
4: [[1, 0, 1], [1, 0, 1], [1, 1, 1], [0, 0, 1], [0, 0, 1]],
5: [[1, 1, 1], [1, 0, 0], [1, 1, 1], [0, 0, 1], [1, 1, 1]],
6: [[1, 1, 1], [1, 0, 0], [1, 1, 1], [1, 0, 1], [1, 1, 1]],
7: [[1, 1, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1]],
8: [[1, 1, 1], [1, 0, 1], [1, 1, 1], [1, 0, 1], [1, 1, 1]],
9: [[1, 1, 1], [1, 0, 1], [1, 1, 1], [0, 0, 1], [1, 1, 1]],
}
class GameApp:
def __init__(self, root):
self.root = root
self.root.title("Digit Grids Visualization")
self.setup_fullscreen()
# 게임 상태 초기화
self.used_parts = set()
self.remaining_targets = []
self.original_numbers = []
self.parts_mapping = {}
self.current_grids = []
self.selected_target = None
self.selected_parts = set()
self.original_canvases = []
self.grid_canvases = []
# 메인 프레임 설정
self.main_frame = tk.Frame(root)
self.main_frame.pack(expand=True, fill="both")
for i in range(5): # 분해 격자 5열
self.main_frame.columnconfigure(i, weight=1)
for i in range(7): # 분해 격자 최대 5열, 여러 행을 고려하여 충분히 설정
self.main_frame.rowconfigure(i, weight=1)
# 게임 UI 구성
self.create_widgets()
# 게임 시작
self.start_new_game()
def setup_fullscreen(self):
"""창을 최대화 또는 전체 화면으로 설정"""
try:
self.root.state('zoomed') # Windows
except:
self.root.attributes('-fullscreen', True) # MacOS/Linux 대안
def create_widgets(self):
"""게임 UI 위젯 생성"""
# 원본 격자 표시 (타깃 격자)
self.original_canvases = []
for idx in range(3):
frame = tk.Frame(self.main_frame, relief=tk.RIDGE, borderwidth=2)
frame.grid(row=0, column=idx, padx=10, pady=10)
label = tk.Label(frame, text=f"Original")
label.pack()
canvas = tk.Canvas(frame, bg="white", cursor="hand2")
canvas.pack(expand=True, fill="both")
canvas.bind("<Button-1>", lambda e, num=idx: self.select_target(num))
self.original_canvases.append(canvas)
# 구분선
separator = tk.Frame(self.main_frame, height=2, bd=1, relief=tk.SUNKEN, bg="black")
separator.grid(row=1, column=0, columnspan=5, sticky="ew", pady=10)
# 분해 격자 배치
self.grid_canvases = []
for idx in range(15):
frame = tk.Frame(self.main_frame, relief=tk.RIDGE, borderwidth=2)
row = 2 + idx // 5
col = idx % 5
frame.grid(row=row, column=col, padx=10, pady=10)
label = tk.Label(frame, text=f"Grid {idx + 1}")
label.pack()
canvas = tk.Canvas(frame, bg="white", cursor="hand2")
canvas.pack(expand=True, fill="both")
canvas.bind("<Button-1>", lambda e, num=idx + 1: self.select_part(num))
self.grid_canvases.append(canvas)
# 제출 버튼
self.submit_button = tk.Button(self.main_frame, text="제출", command=self.submit_answer, state="disabled")
self.submit_button.grid(row=5, column=0, columnspan=5, pady=20)
# 키 이벤트 바인딩
self.root.bind("<Key>", self.on_key)
def start_new_game(self):
"""새로운 게임을 시작"""
try:
self.reset_game_state()
numbers = random.sample(range(1, 10), 3)
self.original_numbers = numbers
self.remaining_targets = numbers.copy()
grids = self.get_and_split_digits(*numbers)
if grids:
self.display_grids(grids, numbers)
except Exception as e:
messagebox.showerror("오류", str(e))
def reset_game_state(self):
"""게임 상태 초기화"""
self.used_parts.clear()
self.remaining_targets.clear()
self.original_numbers.clear()
self.parts_mapping.clear()
self.current_grids.clear()
self.selected_target = None
self.selected_parts.clear()
# 모든 캔버스 색상 초기화
for canvas in self.original_canvases + self.grid_canvases:
canvas.config(bg="white")
self.submit_button.config(state="disabled")
def split_digit_grid(self, grid):
"""주어진 격자를 랜덤하게 3개의 분해 격자로 나눔"""
parts = [[[0 for _ in row] for row in grid] for _ in range(3)]
for i, row in enumerate(grid):
for j, cell in enumerate(row):
if cell:
selected_part = random.choice(parts)
selected_part[i][j] = 1
return parts
def generate_random_grid(self, base_grid, max_one_ratio=0.4):
"""기존 격자를 바탕으로 1의 비율이 40% 미만인 랜덤 분해 격자 생성"""
total_cells = len(base_grid) * len(base_grid[0])
max_ones = int(total_cells * max_one_ratio)
one_count = random.randint(3, max(max_ones, 3))
new_grid = [[0 for _ in row] for row in base_grid]
indices = random.sample([(i, j) for i in range(len(base_grid)) for j in range(len(base_grid[0]))], one_count)
for i, j in indices:
new_grid[i][j] = 1
return new_grid
def get_and_split_digits(self, *numbers):
"""숫자 3개를 입력받아 15개의 분해 격자를 반환"""
try:
if len(numbers) != 3:
raise ValueError("숫자 3개를 입력해야 합니다.")
all_parts = []
# 각 입력 숫자에 대해 분해 격자 생성
for number in numbers:
parts = self.split_digit_grid(digit_grids[number])
for part in parts:
all_parts.append({'number': number, 'grid': part})
# 추가 분해 격자 생성
while len(all_parts) < 15:
base_grid = random.choice(list(digit_grids.values()))
random_part = self.generate_random_grid(base_grid)
if sum(cell for row in random_part for cell in row) >= 3:
all_parts.append({'number': None, 'grid': random_part})
# 분해 격자 순서 랜덤 배치
random.shuffle(all_parts)
self.current_grids = all_parts
# 매핑 정보를 그리드 번호로 변환
self.parts_mapping = {number: [] for number in numbers}
for idx, part in enumerate(all_parts):
grid_number = idx + 1
if part['number'] in self.parts_mapping:
self.parts_mapping[part['number']].append(grid_number)
return all_parts
except Exception as e:
messagebox.showerror("오류", str(e))
return None
def draw_grid(self, canvas, grid, cell_size=20):
"""격자를 그리는 함수 (중앙 정렬)"""
canvas.delete("all") # 기존 그리드 삭제
canvas.update_idletasks() # 업데이트를 반영하여 크기를 정확히 가져옴
canvas_width = canvas.winfo_width()
canvas_height = canvas.winfo_height()
grid_width = len(grid[0]) * cell_size
grid_height = len(grid) * cell_size
x_offset = (canvas_width - grid_width) // 2 if canvas_width > grid_width else 0
y_offset = (canvas_height - grid_height) // 2 if canvas_height > grid_height else 0
for i, row in enumerate(grid):
for j, cell in enumerate(row):
color = "black" if cell else "white"
canvas.create_rectangle(
j * cell_size + x_offset, i * cell_size + y_offset,
(j + 1) * cell_size + x_offset, (i + 1) * cell_size + y_offset,
fill=color, outline="gray"
)
def display_grids(self, grids, original_numbers_):
"""격자들을 GUI로 가시화"""
try:
# 원본 격자 업데이트
for idx, number in enumerate(original_numbers_):
canvas = self.original_canvases[idx]
self.draw_grid(canvas, digit_grids[number])
# 분해 격자 업데이트
for idx, part in enumerate(grids):
canvas = self.grid_canvases[idx]
self.draw_grid(canvas, part['grid'])
except Exception as e:
messagebox.showerror("오류", str(e))
def select_target(self, idx):
"""타깃 격자 선택 처리"""
try:
number = self.original_numbers[idx]
if number not in self.remaining_targets:
messagebox.showinfo("정보", "이미 정답으로 맞춘 타깃입니다.")
return
# 기존 선택된 타깃 해제
if self.selected_target is not None:
prev_idx = self.original_numbers.index(self.selected_target)
self.original_canvases[prev_idx].config(bg="white")
# 현재 선택된 타깃 설정
self.selected_target = number
self.original_canvases[idx].config(bg="yellow")
self.check_submit_ready()
except Exception as e:
messagebox.showerror("오류", str(e))
def select_part(self, grid_num):
"""분해 격자 선택 처리"""
try:
if grid_num in self.used_parts:
messagebox.showinfo("정보", "이미 사용된 분해 격자입니다.")
return
if grid_num in self.selected_parts:
# 선택 해제
self.selected_parts.remove(grid_num)
self.grid_canvases[grid_num - 1].config(bg="white")
else:
if len(self.selected_parts) >= 3:
messagebox.showinfo("정보", "분해 격자는 최대 3개까지 선택할 수 있습니다.")
return
self.selected_parts.add(grid_num)
self.grid_canvases[grid_num - 1].config(bg="lightblue")
self.check_submit_ready()
except Exception as e:
messagebox.showerror("오류", str(e))
def check_submit_ready(self):
"""제출 버튼 활성화 여부 확인"""
if self.selected_target and len(self.selected_parts) == 3:
self.submit_button.config(state="normal")
else:
self.submit_button.config(state="disabled")
def submit_answer(self):
"""정답 제출 처리"""
try:
if not self.selected_target or len(self.selected_parts) != 3:
messagebox.showinfo("정보", "타깃 격자 1개와 분해 격자 3개를 선택해주세요.")
return
target_num = self.selected_target
part_nums = list(self.selected_parts)
# 해당 타깃의 정답 분해 격자 번호
correct_grids = set(self.parts_mapping.get(target_num, []))
if set(part_nums) == correct_grids:
message = "정답입니다."
self.used_parts.update(part_nums)
self.remaining_targets.remove(target_num)
# UI 업데이트 - 타깃 격자 색상 변경
target_idx = self.original_numbers.index(target_num)
self.original_canvases[target_idx].config(bg="green")
# 분해 격자 색상 변경 및 비활성화
for num in part_nums:
self.grid_canvases[num - 1].config(bg="green")
self.grid_canvases[num - 1].unbind("<Button-1>")
# 선택 상태 초기화
self.selected_target = None
self.selected_parts.clear()
self.check_submit_ready()
# 결과 메시지
messagebox.showinfo("결과", message)
# 모든 타깃 완료 시 새로운 게임 시작
if not self.remaining_targets:
messagebox.showinfo("게임 완료", "모든 타깃을 맞추셨습니다. 다음 게임을 시작합니다.")
self.start_new_game()
else:
message = "틀렸습니다."
# 결과 표시 창
combined_window = tk.Toplevel(self.root)
combined_window.title("결과")
result_frame = tk.Frame(combined_window)
result_frame.pack(pady=10)
# 타깃 격자
tk.Label(result_frame, text="타깃 격자").grid(row=0, column=0, padx=10)
target_canvas = tk.Canvas(result_frame, bg="white")
target_canvas.grid(row=1, column=0, padx=10, pady=10)
self.draw_grid(target_canvas, digit_grids[target_num])
# 선택된 분해 격자 합산 결과
combined_grid = [[0 for _ in row] for row in digit_grids[target_num]]
for part_num in part_nums:
part_grid = self.current_grids[part_num - 1]['grid']
for i in range(len(part_grid)):
for j in range(len(part_grid[i])):
combined_grid[i][j] += part_grid[i][j]
tk.Label(result_frame, text="합산된 격자").grid(row=0, column=1, padx=10)
combined_canvas = tk.Canvas(result_frame, bg="white")
combined_canvas.grid(row=1, column=1, padx=10, pady=10)
self.draw_grid(combined_canvas, combined_grid)
# 결과 메시지
tk.Label(combined_window, text=message, fg="red").pack(pady=10)
# 선택 상태 초기화
self.original_canvases[self.original_numbers.index(target_num)].config(bg="white")
for num in part_nums:
self.grid_canvases[num - 1].config(bg="white")
self.selected_target = None
self.selected_parts.clear()
self.check_submit_ready()
combined_window.bind("<Key>", lambda event: combined_window.destroy())
except Exception as e:
messagebox.showerror("오류", str(e))
def on_key(self, event):
"""키 이벤트 처리: 'Return', 'q', 'w', 'e'"""
try:
if event.keysym == "Return":
self.submit_answer()
elif event.keysym in ["q", "w", "e"]:
key_map = {"q": 0, "w": 1, "e": 2}
target_idx = key_map[event.keysym]
if target_idx < len(self.original_numbers):
target_num = self.original_numbers[target_idx]
if target_num in self.remaining_targets:
correct_grids = self.parts_mapping.get(target_num, [])
messagebox.showinfo(
"타깃 정보",
f"타깃 넘버 {target_num}을 구성하는 분해 격자는 Grid 번호 {', '.join(map(str, correct_grids))}입니다."
)
else:
messagebox.showinfo("정보", f"타깃 넘버 {target_num}은 이미 정답으로 맞추어졌습니다.")
except Exception as e:
messagebox.showerror("오류", str(e))
if __name__ == "__main__":
root = tk.Tk()
app = GameApp(root)
root.mainloop()
결과물 확인
실행 결과는 다음과 같습니다. 생각보다 잘 동작해서 다행입니다.
게임 사용법
- 방송을 보셨으면 잘 아시겠지만, 맨 윗 3개는 타깃넘버이고 아래 15개는 조합해서 형태를 만들 수 있는 격자들입니다.
- 아래 격자 3개를 선택해 이들을 합치면 타깃넘버로 선택한 격자가 되어야 정답이 됩니다.
- 타깃넘버를 선택하면 노란색으로 변하고, 아래 격자를 선택하면 하늘색이 되어 선택했다는 것을 알려줍니다.
- 타깃넘버 포함 총 4개가 선택된 후에 엔터키를 누르면 정답 여부를 판별하게 되며, 타깃넘버 3개를 다 맞추면 다음 게임으로 넘어가는 방식입니다.
참고)
- 위 장면에서 초록색은 이미 정답을 맞춘 경우로 이때 사용된 타깃넘버나 격자는 선택할 수 없습니다.
- 격자 선택 시, 클릭 한번에 잘 안 되는 경우가 있는데 (Mac에서...) 그럴 경우, 누르고 있으면 선택이 쉽게 됩니다.
- 답을 못 맞힐 때를 대비해 정답을 중간에 확인할 수 있는 꼼수를 부려뒀습니다. 코드를 확인해 보시면... ^^;
아쉬운 점
동작은 잘 되는데 좀 아쉬운 것이 있습니다.
- 코드 지시를 할 때 생성되는 분해 격자의 생성 시 검정색(1로 표현) 셀을 최소한 몇 % 이상은 넣어야 한다는 조건을 걸었었는데 실제로는 그것을 벗어나는 경우가 가끔 나옵니다.
- 제 맥에서의 문제인지, 격자 클릭이 빠릿빠릿하게 되지 않는 경우가 가끔씩 발생합니다. 뭔지...
마무리하며: 재미있는 게임, 앞으로도 가끔씩 만들어봐야지...
‘대학전쟁’의 퍼즐을 코딩으로 만들어보는 과정은 생각보다 재미있었습니다. 방송에서 본 룰에 프로그램으로 만들기 위해 어떤 추가적인 요구사항이 필요한지 고민해 가면서 다양한 시행착오를 거치고 하는 전 과정이 나름 재미있었습니다. 안 풀릴 때는 ChatGPT를 많이 원망도 했었구요... 이 과정들은 단순한 재현을 넘어 자신만의 창의력을 발휘하는 기회가 될 수 있을 것 같습니다. 아하... 이런 기능을 붙이면 더 재미있겠구나 같은 아이디어가 떠오르기도 했으니까요. 나아가, 직접 제작한 퍼즐을 이용해 친구들이나 지인들과 예능 프로그램 형식으로 바꾸거나, 추가적인 난이도를 설정해보는 것도 훌륭한 확장 방법이 될 수 있죠.
오늘부터 여러분도 직접 도전해보세요. ‘대학전쟁’의 그 퀴즈가, 이젠 여러분의 프로그램 속에서 새로운 생명을 얻게 될지도 모릅니다. 흠... 시즌 2가 시작되었으니 그 속에서도 재미난 게임이 나오면 그것도 한번 구현해 봐야겠습니다.
'DIY 테스트' 카테고리의 다른 글
마인드맵 : 생각 정리 및 아이디어 도출 도구 (1) | 2024.12.10 |
---|---|
웹캠을 이용한 rPPG (원격 광혈류측정) 기반의 심박동수 측정 (2) | 2024.12.01 |
머리(Head) 자세 기반의 화면 주시 여부 감지 (0) | 2024.11.22 |
Yolov11-pose를 이용한 폭력 행위 감지 (Violence Detection) (29) | 2024.11.20 |
교통 CCTV 영상 기반의 자동차 속도 측정 (0) | 2024.11.19 |