이 글에 대해서
이 글은 두 가지 파트로 구성됩니다. 첫 번째 파트에서는 ChatGPT를 이용해 단순한 복사 붙여 넣기 만으로 파이썬 프로그램을 만든 실험을 소개합니다. 전투 시뮬레이션 게임에 대한 전문 지식도 파이썬으로 게임을 만들어 본 경험도 없지만, 코드 한 줄 작성하지 않고 GPT만으로 프로그램을 구현하는 과정을 상세히 작성해 보았습니다.
두 번째 파트에서는, 이 과정을 통해 느낀 점과 AI 시대의 개발자라는 주제로 조금 더 깊이 있는 회고와 성찰을 담았습니다. 단순히 AI로 프로그램을 만드는 것을 넘어, AI 시대에 ‘개발자’란 어떤 의미가 있는지, 그 미래에 대해 최근 생각하는 개인적인 견해를 정리해 보았습니다.
☘️ PART 1. GPT 복붙만으로 프로그램을 만들 수 있을까?
사건의 발단
노앤써라는 시스템 디자인 모임을 시작하면서 매주 스터디를 이끌어갈 사람을 뽑기로 했다. 우리는 이 사람을 "마스터"라고 부르기로 했는데, 문제는 누굴 마스터로 정할지 기준이 애매하다는 점이었다. 고민하던 중, 한 참가자가 재미 삼아 슬랙 채팅방에서 전투 시뮬레이션을 제안하며 대화는 예기치 않은 방향으로 흘러가게 된다.
말하자면, ChatGPT를 통해 참가자들에게 무기를 랜덤으로 배정하고, 그 무기들로 토너먼트 대결을 벌이는 가상의 전투 시나리오를 진행한 것이다. 참가자 11명에게 무기들이 하나씩 랜덤 배정되었고, 이들은 1:1 대결을 통해 최종 승자를 가리게 되었다.
토너먼트 방식으로 진행된 결투는 각 라운드마다 승자를 추렸고, 최종 마지막 결투에서 고대 마법 지팡이의 비물리적 힘이 무적의 방패와 거대 로봇을 모두 무력화하며 한 명의 최종 승자가 결정되었다. 그 사람이 곧 돌아오는 주간의 마스터로 선정되는 것이다.
제비 뽑기를 할 수도 있고, 지목을 할 수도 있고 혹은 핀볼을 돌릴 수도 있지만 전투 시뮬레이션을 통해 한 명을 선정한다는 것이 재밌었다. 그러다 문득, 걸 아예 프로그램으로 만들어볼 수 있지 않을까? 하는 생각이 떠올랐다. 그리고 ChatGPT라면 이 정도 프로그램은 아주 쉽게 짤 것 같다는 예감이 들었다.
그리하여 자진하고야 말았다.
CLI 프로그램 먼저
먼저 내가 한 일
슬랙 대화내용을 긁어서 ChatGPT o1-preview(이하 GPT)한테 주면서 다음과 같이 명령했다.
다음과 같은 방식으로 여러 사람을 받은 다음에 가상 전투 상황을 실제 게임처럼 세팅하고, 이를 기반으로 랜덤하게 누가 이길지를 추출하는 콘솔 게임을 만들려고 합니다. 파이썬 콘솔창에서 처음으로 받아야 하는 입력은 사람 이름들입니다. 그런 후 "라운드 시작" 과 같은 다음 명령어를 수행하면 1라운드에 대한 결과가 마치 실제 전투가 진행되는 것과 같은 속도(너무 느리면 안됨)와 텍스트로 출력되어야 합니다. 그렇게 라운드 결과가 나오면 유저가 다음 진행을 명령하면 또 같은 것을 반복합니다. 이렇게 하여 최종 1인 위너를 선출합니다. 내부적으로 작동해야 하는 로직은 입력으로 받은 유저에 대해 랜덤으로 섞어 매번 다른 결과를 내주어야 한다는 것이며, 게임이 작동하는 것과 같은 상황을 연출하되, 이를 텍스트형 콘솔로 출력해주어야 한다는 것입니다. 이러한 요구사항과 원리에 따라 파이썬 코드로 해당 프로그램을 작성해주세요.
요약하자면 다음과 같은 요구사항이었다.
- 참가자 이름 입력: 프로그램이 시작되면 참가자들의 이름을 입력받는다. 이를 기반으로 토너먼트를 시작하게 되며, 이때 모든 참가자에게 무기를 랜덤하게 할당한다.
- 라운드 진행: “라운드 시작” 명령을 통해 매 라운드의 대결이 진행된다. 전투는 텍스트로 표현되며, 빠른 진행 속도를 위해 각 라운드가 짧은 지연 시간과 함께 출력된다. 매 대결에서 승자는 랜덤으로 결정되고, 각 라운드마다 남은 인원이 줄어들어 최종 1인 우승자가 남을 때까지 반복된다.
- 랜덤 매칭 및 무기 할당: 매 라운드마다 무기와 대결 상대가 랜덤하게 결정되며, 배틀 로직 역시 매번 달라지도록 설정되어 있다.
그리고 다음과 같은 예시를 제공해 주었다.
다음 마스터 추첨중 @channel
**참가자 목록**:
A, B, C, D, ...
**무기 목록**:
레이저 칼, RPG 로켓 런처, 전기 톱, 전투 드론, 사제 폭탄, 무적의 방패, 고대 마법 지팡이, 스나이퍼 라이플, 무중력 수트, 생화학 무기, 거대 로봇
각 참가자에게 무기를 랜덤하게 할당한 다음, 토너먼트를 시작.
각 참가자에게 무기가 배정되었습니다
// 중략
이제 이 무기를 기반으로 토너먼트를 시작하겠습니다. 한 명이 부전승으로 올라가고, 나머지 참가자들이 1:1로 대결하게 됩니다. 첫 번째 대진을 시작하죠!
첫 번째 대결을 시작합니다!
### 1. **A (전투 드론)** vs **B (생화학 무기)**
- **전투 드론**: 전투 드론은 원거리 공격과 정밀 타격에 강합니다. 빠르게 날아다니며 원격으로 적을 감시하고 공격할 수 있기 때문에 기동성과 공격 범위에서 강력한 장점이 있습니다.
- **생화학 무기**: 생화학 무기는 일단 퍼지면 광범위한 지역을 오염시키고, 생명체를 빠르게 무력화시킬 수 있는 치명적인 무기입니다. 그러나 제어하기 어려운 위험성이 있습니다.
**결과**: 생화학 무기가 퍼지기 전에, 전투 드론은 빠르고 치명적인 정밀 타격으로 **B**을 제압했습니다. 생화학 무기의 강력함에도 불구하고, 전투 드론의 속도와 원거리 타격이 더 우세했습니다.
한방에 만들어준 프로토타입 (완벽함을 곁들인)
GPT는 이 요구사항을 바탕으로 약 40초 만에 코드를 만들어 주었다. 다음과 같은 코드였다.
import random
import time
# 참가자 이름 입력
names_input = input("참가자 이름들을 입력하세요 (쉼표로 구분): ")
participants = [name.strip() for name in names_input.split(",")]
# 무기 목록
weapons = [
"레이저 칼", "RPG 로켓 런처", "전기 톱", "전투 드론", "사제 폭탄",
"무적의 방패", "고대 마법 지팡이", "스나이퍼 라이플", "무중력 수트",
"생화학 무기", "거대 로봇"
]
# 무기 할당
random.shuffle(weapons)
assigned_weapons = {}
for i, name in enumerate(participants):
assigned_weapons[name] = weapons[i % len(weapons)]
# 무기 배정 결과 출력
print("\n각 참가자에게 무기가 배정되었습니다:\n")
for name in participants:
print(f"{name} - {assigned_weapons[name]}")
def simulate_battle(name1, name2, weapon1, weapon2):
time.sleep(1)
winner = random.choice([name1, name2])
print(f"**결과**: {winner}가 승리했습니다!")
return winner
round_number = 1
# 토너먼트 진행
while len(participants) > 1:
input("다음 명령을 입력하세요 ('라운드 시작' 또는 '종료'): ")
print(f"\n라운드 {round_number} 시작!\n")
random.shuffle(participants)
next_round_participants = []
if len(participants) % 2 == 1:
bye_player = participants.pop()
print(f"{bye_player}는 부전승으로 다음 라운드에 진출합니다.")
next_round_participants.append(bye_player)
while participants:
name1 = participants.pop()
name2 = participants.pop()
winner = simulate_battle(name1, name2, assigned_weapons[name1], assigned_weapons[name2])
next_round_participants.append(winner)
participants = next_round_participants
round_number += 1
if len(participants) == 1:
print(f"최종 우승자는 {participants[0]}입니다! 축하합니다!")
완벽하게 작동하는 프로토타입이었다! 명령을 입력하고 코드를 받기까지 총 약 6분가량이 소요되었는데, 이 중 5분은 명령어 작성에 걸린 시간이었다. 실제로 GPT가 코드를 쓴 시간은 단 40초였다.
고도화를 해볼까?
먼저 든 감정은 일단 신기함과 놀라움이었다. 그리고 약간의 감격...!? 될 줄은 알았지만 '이게 진짜 되네?'와 같은 생각이 교차했다.
다음과 같이 실제로 작동했다.
단 몇 줄의 명령으로 완성된 프로그램을 보며 모두가 "이거 진짜 파이썬에서 돌려봐!"라며 흥분했다. 그야말로 6분 만에 게임의 기본 틀이 완성된 셈이었다.
프로토타입의 한계 발견
하지만 프로그램을 돌려보면서 문제점이 보이기 시작했다.
문제는 고대 마법 지팡이
와 같이 특정 무기를 할당받은 참가자가 거의 항상 승리한다는 것이었다. 참가자들 사이에서 “고대 마법 지팡이만 나오면 무조건 이기는 거 아냐?”라는 의구심이 나오기 시작했고, 결국 첫 라운드에서 무기 배정만 확인하면 최종 승자가 누구일지 예측할 수 있다는 점을 문제점으로 떠올랐다.
- 고대 마법지팡이 나오면
- 무조건 1등인 거
- 를 다 알게 됨 ㅋㅋㅋㅋ - 변수를 추가하고 뭔가 설정이 더 필요할 거 같음
- gpt 공짜로 이용 가능한 api가 있나 있으면 데이터 연결해서 실시간 llm으로 판단하게 하는 것도 가능할 거 같은디
이 문제를 해결하기 위해 GPT에게 다음과 같은 추가 요청을 보냈다.
지금 코드의 문제는 특정 무기를 배정받은 참가자가 무조건 이기는 구조입니다. 매 라운드마다 무기를 재할당하거나, 무기 특성을 다양화하여 예측 불가능한 결과가 나오도록 고도화할 방법이 있을까요?
GPT의 솔루션 제안
GPT는 즉시 문제를 이해하고 해결책을 제안했다.
지적하신 문제를 이해했습니다.
현재 코드에서는 무기가 한 번만 랜덤하게 할당되고,
그 이후에는 변경되지 않기 때문에 첫 라운드부터 무기 배정을 알면 최종 승자를 예측할 수 있게 됩니다.
이 문제를 해결하기 위해 각 라운드마다 무기를 재할당하도록 코드를 수정하겠습니다.
이렇게 하면 매 라운드마다 참가자들에게 새로운 무기가 배정되어 결과를 예측하기 어려워집니다.
GPT는 이를 반영하여 매 라운드마다 무기를 무작위로 새로 할당하는 코드를 제안했고, 특정 무기가 지나치게 강력하지 않도록 속성 시스템을 도입했다.
예를 들어, 각 무기에 공격력, 방어력, 속도, 정확도 같은 속성을 추가하여 전투 시 특정 무기의 승리가 절대적으로 보장되지 않도록 개선한 버전을 작성해 주었다.
# 무기 속성 할당
weapons_data = {
"레이저 칼": {"공격력": 8, "방어력": 3, "속도": 7},
"RPG 로켓 런처": {"공격력": 9, "방어력": 2, "속도": 4},
"전기 톱": {"공격력": 7, "방어력": 4, "속도": 5},
"전투 드론": {"공격력": 6, "방어력": 5, "속도": 9},
# 생략...
}
# 각 라운드마다 무기 재할당 및 속성 기반 승부 결정
def assign_weapons():
random.shuffle(weapons)
for i, name in enumerate(participants):
assigned_weapons[name] = weapons[i % len(weapons)]
def simulate_battle(name1, name2):
weapon1, weapon2 = assigned_weapons[name1], assigned_weapons[name2]
stats1, stats2 = weapons_data[weapon1], weapons_data[weapon2]
winner = name1 if stats1["공격력"] + stats1["속도"] > stats2["방어력"] + stats2["속도"] else name2
return winner
고도화 아이디어 확장
GPT와의 몇 차례 더 질문과 답변을 주고받으며 다음과 같은 추가적인 고도화 방법을 제안받았다.
- 캐릭터 속성 추가: 각 참가자에게도 속성을 부여하여 캐릭터의 능력치(힘, 민첩성, 지능 등)를 기반으로 전투가 더욱 다양해지도록 했다.
- 게임 내 랜덤 이벤트 도입: 전투 중 돌발 이벤트(날씨 변화, 지형 효과 등)가 등장하여 매 라운드 예기치 못한 상황을 추가할 수 있도록 했다.
- 상성 시스템: 일부 무기는 특정 무기나 상황에서 강하거나 약하도록 상성 시스템을 추가했다. 예를 들어, “RPG 로켓 런처”는 방어력이 낮은 무기에 강하지만, “무적의 방패”를 든 상대에게는 약한 설정을 도입했다.
이로써 게임은 더 이상 단순한 랜덤 추첨이 아닌, 캐릭터 속성과 환경 변수를 모두 고려하는 진짜 게임적인 요소까지 곁들인 콘솔 전투 시뮬레이션으로 업그레이드되었다.
UI를 입혀보자
이제 다음 니즈는 이 게임을 콘솔이 아닌 그럴듯한 UI 환경에서 보고 싶다는 것이었다.
다음과 같이 명령했다.
현재 만든 콘솔 게임에 대해서, 이것을 ui로 변경하는 고도화 작업을 하려고 합니다. 실제 캐릭터가 적당한 모습을 보여지고 전투 장면에 대해서 표현할 수 있도록 도와주는 적절한 파이썬 라이브러리를 찾고, 해당 라이브러리를 이용해서 동일한 로직을 ui 를 통해서 제어하고 볼 수 있도록, 코드 리팩토링 및 고도화해주세요
우선 파이썬에서 gui 툴이 여러 개 있는 것은 알고 있었지만, 뭔가 gpt가 최적의 라이브러리를 선택해 주길 바랐다.
또한 내가 잘 모르는 분야이기 때문에 처음부터 끝까지 다 해주었으면 하는 바람이 있었다.
그랬더니, 우선 pygame으로 라이브러리를 선정했다.
그다음에 다음과 같은 계획을 세우고 코드를 짜기 시작했다.
## 2. Pygame을 이용한 코드 리팩토링 및 고도화
### **전체적인 구현 계획**
- **윈도우 생성**: 게임을 실행할 창을 생성하고, 기본적인 설정을 합니다.
- **이미지 및 리소스 로드**: 참가자 캐릭터와 무기, 배경 등에 사용할 이미지를 로드합니다.
- **게임 상태 관리**: 게임의 진행 상태를 관리하기 위한 클래스를 생성합니다.
- **이벤트 처리**: 사용자 입력(예: 버튼 클릭, 키보드 입력 등)을 처리하여 게임이 진행되도록 합니다.
- **화면 렌더링**: 게임의 현재 상태를 화면에 그려줍니다.
- **게임 루프**: 게임이 지속적으로 실행되도록 메인 루프를 작성합니다.
### **구현 단계**
#### **1) 필요한 이미지 및 리소스 준비**
- 참가자 캐릭터 이미지: 간단한 캐릭터 이미지를 준비합니다. (예: 기본적인 아바타 이미지)
- 무기 이미지: 각 무기를 대표하는 아이콘이나 이미지가 필요합니다.
- 배경 이미지: 전투 장면에 사용할 배경 이미지를 준비합니다.
- 버튼 및 UI 요소 이미지: 시작 버튼, 종료 버튼 등 UI에 필요한 이미지를 준비합니다.
이미지를 직접 생성하거나, 저작권에 문제가 없는 무료 이미지를 사용하시면 됩니다.
이미지의 경우 직접 폴더에 추가해주어야 했다.
적당한 아이콘을 다운받아서 recources에 추가해 주었다.
버그 수정은 어떻게?
그리고 몇 가지 리터칭이 필요했다.
자잘한 버그들이 있었는데, 폰트가 깨지는 것들, 입력에서 쉼표가 안 눌리는 문제, 이미지가 원하는 위치에 출력되지 않는 것들, 콘솔 프로그램보다는 UI 프로그램이 복잡했던 것 같다.
역시 전부 GPT에게 해결을 시켰다.
폰트가 깨지는데 폰트를 현재 시스템에서 찾고 동적으로 가져오도록 할 수 있으려면 어떻게 수정해야 할까요
쉼표를 분명히 눌렀는데도 화면에 나타나지지가 않는게 이상합니다. 확인해주세요
역시 쉽게 고쳐주었고 몇 가지 버그를 수정하고 나니 특별히 모난데 없이 그럭저럭 돌아가는 UI 프로그램이 되었다.
UI도 고도화
이번엔 볼품이 없다는 게 문제였다. 그래서 UI도 고도화를 요청했다.
이제 ui 로직을 고도화합시다. 이전에는 콘솔 텍스트로 전투의 진행 상황을 세세하게 노출해주었고, 캐릭터가 어떤 속성 등을 갖고 있는지, 어떤 무기를 갖고 있는지 등도 세세히 출력해주었습니다. 현재 ui로 변경하면서 그런 정보들이 전부 누락되었습니다. 먼저 게임을 설정하고, 이름을 입력했을 때 어떤 무기를 어떻게 갖고 있는지, 그리고 캐릭터의 정보는 어떠한지 화면을 나타내도록 합시다. 그런 다음에 라운드가 진행될 수 있도록 스페이스 바를 눌러서 진행하도록 합시다. 아래에 기존 코드를 보고 참고해서 개선해주세요.
이때 만들어준 코드는 다음과 같다.
def render_battle_result():
# ... 기존 코드 ...
# 전투 정보 표시
battle_text = f"라운드 {game_state.round_number} - 전투 {game_state.current_battle + 1}"
battle_surface = font.render(battle_text, True, BLACK)
screen.blit(battle_surface, (50, 20))
# 참가자 정보 표시
info1 = f"{name1} ({trait1}) - 무기: {weapon1}"
info2 = f"{name2} ({trait2}) - 무기: {weapon2}"
info1_surface = font.render(info1, True, BLACK)
info2_surface = font.render(info2, True, BLACK)
screen.blit(info1_surface, (50, 70))
screen.blit(info2_surface, (50, 100))
# 무기 설명 표시
weapon1_desc = weapon_descriptions.get(weapon1, "")
weapon2_desc = weapon_descriptions.get(weapon2, "")
weapon1_surface = font.render(f"{weapon1}: {weapon1_desc}", True, BLACK)
weapon2_surface = font.render(f"{weapon2}: {weapon2_desc}", True, BLACK)
screen.blit(weapon1_surface, (50, 140))
screen.blit(weapon2_surface, (50, 170))
# 랜덤 이벤트 표시
if game_state.event:
event_text = f"랜덤 이벤트 발생: {game_state.event['이름']} - {game_state.event['설명']}"
event_surface = font.render(event_text, True, BLACK)
screen.blit(event_surface, (50, 210))
# 결과 텍스트 표시
winner = game_state.next_round_participants[-1]
loser = name1 if winner == name2 else name2
message = random.choice(victory_messages)
result_text = message.format(winner=winner, loser=loser)
result_surface = font.render(result_text, True, BLACK)
screen.blit(result_surface, (50, 250))
# 안내 문구
info_text = "스페이스바를 눌러서 진행하세요."
info_surface = font.render(info_text, True, BLACK)
screen.blit(info_surface, (50, 300))
결과적으로 이런 모양새가 되었다.
모듈 분리
대충 원하는 것이 다 구현되었고 어느 정도 구색도 갖췄는데 생각해 보니 자꾸 GPT가 전체 코드를 써주고 있었다.
물론 문제없이 완성도가 높아지고 있으니 계속 이런 방식으로 사용해도 되겠지만, 유지보수성 차원에서 좋지 않을 것이 뻔했다. 여기서 유지보수성이란, 어떤 의미에서 gpt의 처리량을 최적화해주는 측면에서의 유지보수성이다. 즉, 어차피 내가 코드를 보고 고칠 일은 없었고, 그러고 싶지도 않았다. 잘 모르기도 하거니와 이렇게 다 해주는데 그런 수고를 들여야 할 필요가 있을까? 와 같은 생각이 깔려있었기 때문이다. 따라서 유지보수성이란 gpt 입장에서 명령을 더 잘 처리하기 위해 입력과 출력 데이터를 최적화할 수 있게 도와주는 의미였다.
그런 의미에서, 변경되지 않을 부분들을 굳이 계속해서 명령에 포함할 필요는 없었다. 따라서 수정이 필요한 부분에서 보다 타겟팅을 집중시키기 위해 모듈을 나누고자 했다.
물론, 모듈 나누는 일도 직접 할 필요가 없다. GPT에게 다음과 같이 명령했다.
현재 로직에서 모듈을 좀 나눌 수 있을까요. 현재 weapon-game.py라는 하나의 파일에 모든 코드가 작성되어 있는데, 별도의 py 파일들로 나누어서 분리해보려고 합니다. 각기 다른 기능을 수행하는 코드들을 별도의 클래스 및 함수 및 py 파일로 분리해주세요.
역시 다음과 같이 계획을 세우고 깔끔하게 짜주었다.
## 1. 모듈 분리 계획
코드를 다음과 같이 기능별로 분리하겠습니다:
1. **`main.py`**: 게임의 진입점이며, 메인 게임 루프를 포함합니다.
2. **`game_state.py`**: `GameState` 클래스를 정의하고 게임 상태를 관리합니다.
3. **`game_logic.py`**: 게임의 주요 로직과 기능을 구현합니다.
4. **`render.py`**: 화면에 요소를 그리는 렌더링 함수들을 포함합니다.
5. **`resources.py`**: 리소스 로딩과 관련된 함수들을 포함합니다.
6. **`constants.py`**: 게임에서 사용되는 상수와 데이터 구조를 정의합니다.
7. **`utils.py`** (선택 사항): 공용으로 사용되는 유틸리티 함수들을 포함합니다.
코드를 전부 짜주고 나서 패키지구조까지 신경 써주는 센스.
1. **폴더 구조 구성**
프로젝트 폴더를 다음과 같이 구성합니다:
project_folder/
├── main.py
├── game_state.py
├── game_logic.py
├── render.py
├── resources.py
├── constants.py
├── images/
│ ├── strength.png
│ ├── agility.png
│ ├── intelligence.png
│ ├── laser_sword.png
│ ├── rpg.png
│ └── background.png
├── fonts/
│ └── maruburi/
│ └── TTF/
│ └── MaruBuri-Regular.ttf
그런데 모듈을 나누고 나니 몇 가지 오류가 나기 시작했다.
현재 Constants.py에 폰트 파일 경로가 들어가 있는데, 그래서 그런지 게임 실행에서 에러가 발생합니다. 다시 확인해서 수정해주세요.
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "/Users/Rene/weapone-game/main.py", line 98, in <module>
main()
File "/Users/Rene/weapone-game/main.py", line 74, in main
render_input_screen(screen, input_text)
File "/Users/Rene/weapone-game/render.py", line 11, in render_input_screen
prompt_surface = font.render(prompt_text, True, BLACK)
^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'render'
(venv) Rene@Rene-MacBookPro weapone-game %
여기서 좀 시간을 많이 썼다. 몇 번의 수정을 거치니 다시 깔끔하게 돌아가기 시작했다.
좀 더 좀 더...
프로그램을 이제 몇 번 돌려보았다.
몇 가지 개선하고 싶은 부분이 또 보였다. 우선 게임이 한 번만 진행되니, 테스트하는 것이 너무 불편했다. 그래서 다음과 같이 다시 시작할 수 있도록 업그레이드를 명령했다.
이제 이 게임의 최종 우승자가 결정되면 그 다음에 다시 처음으로 돌아갈 수 있도록 하는 버튼을 만들어 마우스로 클릭하고, 해당 이벤트에 따라서 다시 처음 화면으로 돌아갈 수 있도록 만들어주세요
다음과 같이 만들어주었다.
그리고 또 하나는 좀 더 게임 같이 바꿔보고자 하는 니즈였다.
UI로 변경하긴 했지만 여전히 콘솔 프로그램의 냄새가 강했다. 진짜 게임처럼 바꿔볼 수는 없을까?
이 게임에서, 현재 콘솔로 모든 정보가 표현되고 있습니다. 먼저 사람부터 캐릭터를 실제로 표현하고자 하는데요, 사람들을 입력하고 엔터를 누르면 참가자 정보가 특성 정보와 함께 뜨는데요. 이때, 사람들에 대해서 실제 캐릭터처럼 표현을 하고자 합니다. 가능한가요 ?
이미지를 추가하는 것이 가능했다. 다음과 같이 추가해 주었다.
썩 마음에 들지는 않았지만, 마치 게임에서 공격을 할 때, 캐릭터가 움직여서 공격을 구현하는 것은 조금 다른 레벨이라는 생각이 들었다. 그래서 이 부분은 일단 제쳐두고 프로그램 자체의 완성도를 높여보는 쪽으로 업그레이드를 결정했다.
현재 로직에서 또 한 가지 문제는 아무래도 랜덤성의 부족이었다. 그리고 유저 인터랙션이 없는 부분이었다. 한 번 정해지면 어찌 됐든 어떤 사람이 뽑히는 이유가 그렇게 랜덤하지 않다고 생각했다.
좀 더 랜덤성을 높이고, 결과에 유저의 개입이 영향을 미칠 수 없을까?
재 로직에서 매 라운드별로 유저의 무기가 바뀌어서, 최종 결과가 라운드 별로 진행되면서 얼마든지 뒤바뀔 수 있는 랜덤성이 부여되어 있나요 ? 없다면 그러한 장치를 추가해서 어떤 사람이 우승을 하게 될지 정말 모르게끔, 그리고 랜덤 확률이 더 올라가게끔 고도화해주세요
유저의 인터랙션에 따라서 능력치를 조정할 수 있었으면 합니다. 유저는 매 라운드 시작에 앞서 능력치를 조정할 수 있는 기회를 부여받습니다. 이때 모든 유저는 5개의 stat을 강화할 수 있습니다. 능력치 조절은 ui로서 조절되어야 하고 키보드로 입력하고, 각각 유저에 대한 선택 칸은 마우스로 선택 가능할 수 있어야 할 것입니다. 유저가 각 스탯을 전부 선택하면, 이제 스탯 반영이라는 버튼을 클릭할 수 있고, 그렇게 되면 능력치가 조절됩니다. 이와 같은 방식으로 하여 유저의 인터랙션에 따라 결과가 바뀔 수 있도록 하여 랜덤 요소와 재미를 추가할 수 있습니다. 이를 구현해서 완성된 코드로 제시해주세요
이와 같은 명령으로 얻은 답변이다.
안녕하세요!
유저 인터랙션을 통해 참가자들의 능력치를 조정할 수 있도록 기능을 추가하길 원하시는군요. 이를 위해 게임에 새로운 상태와 UI를 추가하여 사용자가 각 참가자의 스탯을 조정하고, 게임 결과에 영향을 미칠 수 있도록 구현하겠습니다.
## **구현 개요**
1. **새로운 게임 상태 추가**: `game_state.state`에 `"능력치 조정"` 상태를 추가합니다.
2. **능력치 데이터 구조 추가**:
- 각 참가자의 능력치를 저장하기 위해 `game_state.participant_stats`를 추가합니다.
- 기본 능력치는 공격력, 방어력, 속도이며, 초기값은 0으로 설정합니다.
3. **렌더링 함수 추가**:
- `render_stat_adjustment` 함수를 `render.py`에 추가하여 능력치 조정 화면을 렌더링합니다.
- 참가자 목록과 능력치 조정 슬라이더 또는 입력 필드를 표시합니다.
4. **사용자 입력 처리**:
- 마우스 클릭으로 참가자를 선택하고, 키보드로 능력치 값을 입력합니다.
- 각 참가자는 총 5포인트의 능력치를 분배할 수 있습니다.
- "스탯 반영" 버튼을 클릭하면 능력치가 적용되고 다음 단계로 진행합니다.
5. **전투 로직 수정**:
- `calculate_win_probability` 함수에서 참가자의 능력치를 고려하여 승리 확률을 계산합니다.
## **코드 수정**
### **1\. `game_state.py` 수정**
# game_state.py
class GameState:
def __init__(self):
self.participants = []
self.round_number = 1
self.assigned_weapons = {}
self.participant_traits = {}
self.participant_stats = {} # 참가자 능력치 추가
self.next_round_participants = []
self.event = None
self.current_battle = 0
self.battle_results = []
self.state = "입력 대기" # 가능한 상태: 입력 대기, 참가자 정보, 라운드 시작 알림, 능력치 조정, 라운드 준비, 전투 진행, 전투 결과, 게임 종료
self.victory_message = ""
def reset(self):
self.round_number = 1
self.assigned_weapons = {}
self.participant_traits = {}
self.participant_stats = {}
self.next_round_participants = []
self.event = None
self.current_battle = 0
self.battle_results = []
self.state = "입력 대기"
self.victory_message = ""
- `participant_stats` 딕셔너리를 추가하여 각 참가자의 능력치를 저장합니다.
---
### **2\. `main.py` 수정**
# main.py
import pygame
import sys
from constants import SCREEN_WIDTH, SCREEN_HEIGHT, WHITE, BLACK
import resources # resources 모듈 전체를 임포트
from game_state import GameState
from game_logic import (
assign_traits, assign_weapons, assign_event,
prepare_battles, simulate_battle
)
from render import (
render_input_screen, render_participant_info,
render_battle_result, render_game_over,
render_round_start_notification,
render_stat_adjustment # 추가
)
def main():
pygame.init()
# 로컬 변수로 화면 크기를 관리
screen_width = SCREEN_WIDTH
screen_height = SCREEN_HEIGHT
screen = pygame.display.set_mode((screen_width, screen_height), pygame.RESIZABLE)
pygame.display.set_caption("전투 시뮬레이션 게임")
clock = pygame.time.Clock()
resources.load_resources()
resources.load_font(18) # 폰트 크기는 필요에 따라 조절 가능합니다.
game_state = GameState()
input_active = True
input_text = ""
restart_button_rect = None # 게임 종료 화면에서의 재시작 버튼 위치 저장
# 능력치 조정 관련 변수
selected_participant = None
stat_inputs = {"공격력": 0, "방어력": 0, "속도": 0}
total_points = 5
apply_button_rect = None
while True:
screen.fill(WHITE)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# 화면 크기 조정 이벤트 처리
elif event.type == pygame.VIDEORESIZE:
screen_width, screen_height = event.w, event.h
screen = pygame.display.set_mode((screen_width, screen_height), pygame.RESIZABLE)
# 키보드 및 마우스 입력 처리
elif event.type == pygame.KEYDOWN:
if game_state.state == "입력 대기":
if input_active:
if event.key == pygame.K_RETURN:
# 참가자 입력 완료
game_state.participants = [name.strip() for name in input_text.split(",")]
assign_traits(game_state)
assign_weapons(game_state)
# 참가자 능력치 초기화
for name in game_state.participants:
game_state.participant_stats[name] = {"공격력": 0, "방어력": 0, "속도": 0}
game_state.state = "참가자 정보"
input_active = False
elif event.key == pygame.K_BACKSPACE:
input_text = input_text[:-1]
else:
input_text += event.unicode
elif game_state.state == "참가자 정보":
if event.key == pygame.K_SPACE:
game_state.state = "라운드 시작 알림"
elif game_state.state == "라운드 시작 알림":
if event.key == pygame.K_SPACE:
game_state.state = "능력치 조정"
elif game_state.state == "능력치 조정":
if selected_participant:
if event.key == pygame.K_BACKSPACE:
# 마지막 입력 삭제
pass # 입력 필드 구현 시 구체적으로 처리
elif event.unicode.isdigit():
# 숫자 입력 처리
pass # 입력 필드 구현 시 구체적으로 처리
elif game_state.state == "전투 결과":
if event.key == pygame.K_SPACE:
# 다음 전투로 진행
game_state.current_battle += 1
if game_state.current_battle >= len(game_state.battle_results):
# 라운드 종료, 다음 라운드 시작 알림 상태로 전환
game_state.participants = game_state.next_round_participants
game_state.next_round_participants = []
game_state.round_number += 1
if len(game_state.participants) <= 1:
game_state.state = "게임 종료"
else:
game_state.state = "라운드 시작 알림"
game_state.current_battle = 0
else:
game_state.state = "전투 진행"
elif game_state.state == "게임 종료":
pass # 게임 종료 시 키보드 입력 처리 (필요에 따라 추가)
elif event.type == pygame.MOUSEBUTTONDOWN:
if game_state.state == "능력치 조정":
mouse_pos = event.pos
# 참가자 선택 처리
for name, rect in participant_rects.items():
if rect.collidepoint(mouse_pos):
selected_participant = name
stat_inputs = {"공격력": 0, "방어력": 0, "속도": 0}
total_points = 5
# "스탯 반영" 버튼 클릭 처리
if apply_button_rect and apply_button_rect.collidepoint(mouse_pos):
if selected_participant and total_points == 0:
game_state.participant_stats[selected_participant]["공격력"] += stat_inputs["공격력"]
game_state.participant_stats[selected_participant]["방어력"] += stat_inputs["방어력"]
game_state.participant_stats[selected_participant]["속도"] += stat_inputs["속도"]
selected_participant = None
# 모든 참가자의 능력치 조정이 완료되면 다음 단계로 진행
if all(stat["공격력"] + stat["방어력"] + stat["속도"] >= game_state.round_number * 5 for stat in game_state.participant_stats.values()):
game_state.state = "라운드 준비"
elif game_state.state == "게임 종료" and restart_button_rect:
if restart_button_rect.collidepoint(event.pos):
# 게임 상태 초기화
game_state.reset()
input_active = True
input_text = ""
restart_button_rect = None
# 마우스 커서 변경 (선택 사항)
elif event.type == pygame.MOUSEMOTION:
if game_state.state == "게임 종료" and restart_button_rect:
if restart_button_rect.collidepoint(event.pos):
pygame.mouse.set_cursor(pygame.SYSTEM_CURSOR_HAND)
else:
pygame.mouse.set_cursor(pygame.SYSTEM_CURSOR_ARROW)
# 상태에 따른 렌더링
if game_state.state == "입력 대기":
# 참가자 이름 입력 화면
render_input_screen(screen, input_text, resources.font)
elif game_state.state == "참가자 정보":
# 참가자 정보 화면
render_participant_info(screen, game_state, resources.font)
elif game_state.state == "라운드 시작 알림":
# 라운드 시작 알림 화면 렌더링
render_round_start_notification(screen, game_state, resources.font)
elif game_state.state == "능력치 조정":
# 능력치 조정 화면 렌더링
participant_rects, apply_button_rect = render_stat_adjustment(screen, game_state, resources.font, selected_participant, stat_inputs, total_points)
elif game_state.state == "라운드 준비":
# 라운드 준비 단계
assign_event(game_state)
if game_state.round_number > 1:
assign_weapons(game_state) # 2라운드부터 무기 재할당
prepare_battles(game_state)
game_state.state = "전투 진행"
elif game_state.state == "전투 진행":
# 전투 진행 화면
simulate_battle(game_state)
game_state.state = "전투 결과"
elif game_state.state == "전투 결과":
# 전투 결과 화면
render_battle_result(screen, game_state, resources.font)
elif game_state.state == "게임 종료":
# 게임 종료 화면
restart_button_rect = render_game_over(screen, game_state, resources.font)
pygame.display.flip()
clock.tick(60)
if __name__ == "__main__":
main()
**설명:**
- 새로운 상태 `"능력치 조정"`을 추가하고, 해당 상태에서 참가자 선택 및 능력치 입력을 처리합니다.
- `participant_rects`와 `apply_button_rect`를 사용하여 마우스 클릭 영역을 관리합니다.
- 각 참가자는 라운드마다 총 5포인트의 능력치를 분배할 수 있습니다.
- 모든 참가자의 능력치 조정이 완료되면 `"라운드 준비"` 상태로 전환합니다.
---
### **3\. `render.py` 수정**
# render.py
import pygame
import random
from constants import WHITE, BLACK
import resources # 모듈 자체를 임포트합니다.
from game_state import GameState
# 기존 렌더링 함수들 유지
def render_stat_adjustment(screen, game_state, font, selected_participant, stat_inputs, total_points):
# 배경 이미지 표시
bg_image = pygame.transform.scale(resources.background_image, (screen.get_width(), screen.get_height()))
screen.blit(bg_image, (0, 0))
participant_rects = {}
y_offset = 50
# 참가자 목록 표시
title_text = f"라운드 {game_state.round_number} - 능력치 조정"
title_surface = font.render(title_text, True, BLACK)
screen.blit(title_surface, (50, 20))
info_text = "각 참가자마다 5포인트의 능력치를 분배하세요."
info_surface = font.render(info_text, True, BLACK)
screen.blit(info_surface, (50, y_offset))
y_offset += 30
for name in game_state.participants:
participant_surface = font.render(name, True, BLACK)
participant_rect = participant_surface.get_rect(topleft=(50, y_offset))
screen.blit(participant_surface, participant_rect)
participant_rects[name] = participant_rect
y_offset += 30
# 선택된 참가자에 대한 능력치 조정 UI 표시
if selected_participant:
# 왼쪽에 참가자 정보 표시
y_offset = 100
info_surface = font.render(f"{selected_participant}의 능력치 조정", True, BLACK)
screen.blit(info_surface, (300, y_offset))
y_offset += 30
# 능력치 입력 필드 표시
for stat_name in ["공격력", "방어력", "속도"]:
stat_value = stat_inputs[stat_name]
stat_surface = font.render(f"{stat_name}: {stat_value}", True, BLACK)
screen.blit(stat_surface, (300, y_offset))
y_offset += 30
# 남은 포인트 표시
points_surface = font.render(f"남은 포인트: {total_points}", True, BLACK)
screen.blit(points_surface, (300, y_offset))
y_offset += 30
# "스탯 반영" 버튼 표시
apply_button_surface = font.render("스탯 반영", True, WHITE)
apply_button_rect = apply_button_surface.get_rect(center=(500, y_offset + 20))
pygame.draw.rect(screen, BLACK, apply_button_rect.inflate(20, 10))
screen.blit(apply_button_surface, apply_button_rect)
else:
apply_button_rect = None
return participant_rects, apply_button_rect
**설명:**
- `render_stat_adjustment` 함수를 추가하여 능력치 조정 화면을 렌더링합니다.
- 참가자 목록을 표시하고, 선택된 참가자의 능력치를 조정할 수 있는 UI를 제공합니다.
- "스탯 반영" 버튼을 표시하고, 해당 버튼의 위치 정보를 반환합니다.
---
### **4\. `game_logic.py` 수정**
# game_logic.py
import random
from constants import weapons, character_traits, random_events, weapon_advantages, victory_messages
from game_state import GameState
def assign_traits(game_state):
# 기존 코드 유지
def assign_weapons(game_state):
# 기존 코드 유지
def assign_event(game_state):
# 기존 코드 유지
def prepare_battles(game_state):
# 기존 코드 유지
def simulate_battle(game_state):
# 기존 코드 유지
def run_battle_simulation(name1, name2, game_state):
# 기존 코드 유지
def calculate_win_probability(p1, p2, assigned_weapons, event, game_state):
weapon1 = assigned_weapons[p1]
weapon2 = assigned_weapons[p2]
stats1 = weapons[weapon1].copy()
stats2 = weapons[weapon2].copy()
# 참가자 능력치 적용
participant_stats1 = game_state.participant_stats[p1]
participant_stats2 = game_state.participant_stats[p2]
stats1["공격력"] += participant_stats1["공격력"]
stats1["방어력"] += participant_stats1["방어력"]
stats1["속도"] += participant_stats1["속도"]
stats2["공격력"] += participant_stats2["공격력"]
stats2["방어력"] += participant_stats2["방어력"]
stats2["속도"] += participant_stats2["속도"]
# 캐릭터 특성 적용
# 기존 코드 유지
# 랜덤 이벤트 적용
# 기존 코드 유지
# 무기 상성 적용
# 기존 코드 유지
# 랜덤 요소 추가
# 기존 코드 유지
# 승리 확률 계산 (랜덤 요소 포함)
# 기존 코드 유지
return prob1
**설명:**
- `calculate_win_probability` 함수에서 참가자의 능력치를 무기 능력치에 추가합니다.
- 이를 통해 능력치 조정이 전투 결과에 영향을 미치게 됩니다.
---
### **5\. \*\*입력 처리 및 UI 구현에 대한 추가 설명**
입력 처리와 UI 구현은 프로젝트의 복잡성을 고려하여 간단한 형태로 설명했습니다. 실제로는 각 참가자의 능력치 입력을 위한 입력 필드와 입력값 검증, 그리고 키보드 입력에 따른 값 변경 등의 로직을 추가로 구현해야 합니다.
예를 들어, 능력치 조정 화면에서 키보드로 숫자를 입력하여 각 능력치의 값을 변경하고, 남은 포인트를 실시간으로 업데이트해야 합니다. 이 부분은 `main.py`의 이벤트 처리 루프에서 구현해야 합니다.
---
## **요약**
- **게임 상태에 능력치 조정 기능을 추가**하여 사용자 인터랙션을 통해 참가자의 능력치를 조정할 수 있게 했습니다.
- **새로운 상태와 렌더링 함수**를 추가하여 능력치 조정 화면을 구현했습니다.
- **전투 로직을 수정**하여 참가자의 능력치가 전투 결과에 반영되도록 했습니다.
- **입력 처리와 UI 구현**은 기본적인 구조를 제시했으며, 세부적인 입력 로직은 프로젝트의 요구사항에 따라 추가로 구현해야 합니다.
---
이렇게 수정하시면 유저의 인터랙션에 따라 능력치를 조정할 수 있으며, 이는 게임 결과에 직접적인 영향을 미치게 됩니다. 이를 통해 게임의 랜덤성과 재미 요소를 더욱 높일 수 있습니다.
혹시 추가로 궁금한 사항이나 도움이 필요한 부분이 있으시면 언제든지 말씀해주세요!
이에 따라 드디어 유저와의 인터랙션도 가능하게 되었다!
화면은 다음과 같다.
완성된 프로그램
☘️ PART 2. AI 시대 개발자의 역할, 미래, 그리고 어쩌면 무서운 질문들
회고
이 프로그램은 아직 완성본은 아니다. 여전히 디테일을 다듬어야 할 부분이 남아있고, 몇몇 버그도 존재한다. UI도 사실 형편없다. 솔직히 말해서 "게임"이라고 부르기엔 조금 무리가 있다. 기본적으로는 콘솔 환경에서 작동하는 알고리즘에 간단한 텍스트 출력을 추가한 형태로, 시각적인 매력이나 복잡한 인터페이스는 없다.
그럼에도 불구하고, 이 프로그램은 기대 이상으로 의미 있는 결과물이라고 생각했다. 다음 두 가지 이유 때문이다.
첫째, 프로그램은 목표한 기능을 충실히 수행하면서도 흥미로운 요소를 더했다는 점이다. 초기 목적은 간단한 추첨 프로그램이었지만, GPT와 협력해 확장하며 게임으로서의 완성도가 높아졌다. 상성 시스템, 캐릭터와 무기의 속성 차이 등 다양한 요소가 추가되면서 매 라운드 예측할 수 없는 긴장감이 생겨났다. "지금 무기로는 누가 이길까?"라는 질문에 결과가 나오기 전까지는 답할 수 없다. 이러한 요소가 더해진 덕분에 단순한 랜덤 추첨 이상의 재미를 주며, 사용자들이 몰입할 수 있는 작은 "경험"을 만들어냈다.
둘째, 개발 과정에서 새로운 가능성을 확인했다는 점이다. 평일 저녁 퇴근 후 단 120분 만에 GPT와 간단한 질문과 답변만으로 완성된 프로그램이라는 사실은 특히 인상적이고 경험적으로 큰 임팩트를 주었다고 생각한다. 파이썬 GUI 프로그램에 능숙한 개발자라 하더라도 이와 같은 프로그램을 순수한 인간의 코딩으로 120분 만에 완성할 수 있는 사람이 지구상에 얼마나 있을까? 즉, 인공지능과 협력해 프로토타입을 빠르게 완성하고 반복적으로 개선하는 작업 방식의 강력함을 체감할 수 있었다.
이 경험은 다음과 같은 시사점을 남겼다.
- AI와의 협업이 개발 속도와 완성도를 높인다는 것. GPT의 답변을 통해 추가적인 기능을 손쉽게 구현하고, 빠른 피드백을 받을 수 있었다. 이는 짧은 시간 안에 반복적 개선을 가능하게 해 주었고, 결과적으로 더 완성도 있는 프로그램을 만들어낼 수 있게 했다.
- 창의적 시도에 대한 접근성이 향상된다는 점이다. 게임 시스템에 대한 전문 지식이 전무하더라도 무기 속성, 상성 시스템, 랜덤 이벤트 도입 등도 GPT의 도움으로 쉽게 시도할 수 있었다. 작은 실험적 아이디어라도 빠르게 테스트할 수 있는 환경이 충분했다.
한편으론 마냥 좋아할 일은 아니라는 생각이 들었다. 지금의 과정에서 내가 한 일이란 무엇인가? 나는 "개발"을 했다고 말할 수 있을까?
어쩌면 기묘한 다음과 같은 질문들이 떠올랐다.
만약 내가 게임 기획자였다면 어땠을까? 혹은 시뮬레이션 게임에 능통한 사람이었다면? 이보다 20배 좋은 퀄리티의 게임을 만들 수도 있지 않았을까? 그런 사람이 존재했다면, 그 사람은 기획자였을까 프로게이머였을까 개발자였을까? 만약에 그런 사람이 파이썬까지 능숙하게 다뤘다면 그런 퀄리티의 게임을 30분 만에 만들 수도 있지 않았을까? 그런데, 그런 존재를 설정하고 나니 하나 떠오르는 무언가가 있다. 낯설고도 친절한 어떤 존재. 그게 바로 GPT 아닌가?
2020년대 이후 탄생한 GenAI라는 것이 유발 하라리의 표현을 빌리자면, "모든 인간 제도의 문을 딸 수 있는 마스터키를 손에 넣고 있"으며, 이로서 인공 지능에 의해 인류 자체가 해킹당하는 시나리오의 서막이 열리고 있는 것이라면, 이후 달라질 세상에서 개발자란 무엇이 될 것이며 무엇이 되어야 하는가? 아니 AI 시대에 직업인으로서의 역할은 도대체 무엇이라고 말할 수 있을까?
내가 한 일이란
이 프로그램을 만들면서 직접 코딩한 부분은 단 한 줄도 없다. 내가 한 일이라곤 이미지와 폰트를 다운로드해 폴더에 넣고 이름을 정리해 주는 정도였다. 약 120분가량 계속된 코드 작성의 매 순간은 말 그대로 말 그대로 묻고 답변받고, 복사하고 붙여 넣고의 반복이었다.
GPT와 나눈 대화를 살펴보면, ChatGPT o1-preview와 약 30번의 대화를 주고받았다. 중간에 1주일 리밋이 25개 남았다는 메시지를 받았다. 이 제한이 아쉬워서 중간중간 간단해 보이는 작업은 일반 커스텀 GPT로 옮겨 해결했다.
코드 작성 측면에서 내가 기여한 부분은 전혀 없었다. 정말로 모든 코드는 복사와 붙여 넣기로 만들었다.
그렇다면 120분 동안 나는 뭘 한 것일까?
내 생각에 내가 한 일은 다음과 같다.
- 내가 원하는 것이 무엇인지 생각하기 → 추첨의 기본 기능을 넘어서, 매 라운드 결과가 흥미롭고 예측 불가한 전투 시뮬레이션으로 만들어져야 한다는 목표
- 완성본은 어떤 식이어야 하는지 상상하기 → 최종적인 프로그램은 어떤 형태를 가져야 할지, 사용자 경험 측면에서 어떤 기능들이 필요할지를 상상
- 좀 더 프로그램을 쉽고 편하게 사용하려면 어떤 것들이 추가되고 수정되어야 하는지 생각하기 → 매 라운드마다 새로운 무기와 속성 설정을 제안하며, 사용자에게 신선함을 주는 게임 구성
- 이 모든 것들을 종합해서 질문하고 명령하기
이를 요약해 보자면, 무엇을 원하는지 명확히 이해하고 그 요구 사항을 구체화하여 질문하는 일이었다. 그저 더 나은 프로그램이 되기를 바랐을 뿐이고 그렇게 해달라고 요청했을 뿐이다.
여기서 필요한 역량은 원하는 것을 스스로 알고 질문을 잘하는 것이 실제로 전부였다고 생각한다.
AI 시대의 개발자란?
이쯤에서 생각해 본다.
AI 시대에 개발자라는 역할은 무엇일까? 이제는 조금 식상하고 뻔해 보이기까지 한 질문이다. (벌써?)
나는 익숙하지 않은 파이썬과 처음 접하는 pygame 라이브러리를 이용해 핵심적인 원리조차 몰라도 나만의 프로그램을 완성할 수 있었다. 이 과정에서 필수적이었던 기술은 단순히 코딩 지식이 아니라, 내가 원하는 프로그램을 명확히 상상하고 AI에게 그 의도를 전달하는 능력이었다. GPT가 내 상상 속 프로그램을 구현할 수 있다는 믿음이 없었다면 지금의 결과물조차 얻지 못했을 것이다.
그렇다면 "개발자란 무엇인가?"라는 질문에 대한 답이 새롭게 다가온다. 과거의 개발자는 주로 코드를 직접 작성하고 시스템을 설계해 기능을 실현하는 역할이었다. 오픈소스가 등장하기 이전에는 기술적 장벽이 높아 개발자의 역할이 매우 독점적이었다. 하지만 오픈소스의 확산으로 개발자들은 더 이상 독점적인 지식을 가진 사람이라기보다는, 서로의 노하우를 공유하고 더욱 광범위한 문제 해결의 주체로 자리 잡게 되었다.
다시 한 번, “개발자”란 어떤 사람인가? 과거의 개발자는 0과 1로 구성된 기계어에서 시작해, 코드를 직접 작성하고 시스템을 설계하는 존재였다. 현재의 개발자는 좀 더 넓은 의미의 역할을 가진다. 비즈니스 맥락에서 문제를 이해하고 해결하는 데 중점을 두며, 시스템 운영과 관리를 비롯해 소통과 협업을 통해 다양한 이해관계자들과 협력한다. 이렇게 된 핵심적인 배경은 단연 추상화의 발전이다. <AI 시대의 프로그래밍>(톰 타울리 지음, 이일섭, 황은옥 옮김, 한빛 미디어)에서는 "프로그래밍 언어가 발전해온 핵심 요소는 추상화다"(p. 25)라고 언급하며, 추상화가 개발자의 중요한 일에 더 집중하도록 도와왔음을 설명한다. 추상화 덕분에 "인터넷, 클라우드 컴퓨팅, 모바일, AI 같은 획기적인 발전이 가능했(p. 25)."고, 개발자의 역할이 광대하고 깊어졌다.
책에 따르면, 현재의 프로그래밍 도구는 레벨 3, 즉 학습 기반 자동화 수준에 도달해 있다. AI가 코드 생성부터 버그 수정까지 어느 정도 자동으로 수행하지만, 여전히 인간의 검토와 피드백이 필요하다. 더 나아가 레벨 4와 5의 완전 자동화 단계에 도달하면, AI는 개발자 없이도 코드의 생성, 수정, 문제 해결을 완벽히 자율적으로 수행하게 될 것이다. 이 책에서는 이러한 단계에 대해 "레벨 4에서는 사람이 코드를 최종 승인할 필요 없이 복잡한 작업을 스스로 처리"한다고 설명하며, AI의 발전 속도가 얼마나 빠르게 진행되고 있는지 강조한다 (p. 57).
이러한 흐름이 맞다면, 이제 개발자는 단순히 코드 작성자가 아닌, 자신의 요구를 명확히 전달하고 AI에게 효과적으로 문제를 해결하게 하는 조정자가 되어가는 것은 아닐까? 마이크로소프트의 연구에 따르면, GitHub Copilot을 사용한 개발자가 그렇지 않은 개발자보다 55% 더 빠르게 작업을 완료할 수 있었는데, 이는 단순한 코드 작성을 넘어 문제 해결 능력의 증진을 의미한다. 개발자는 AI를 통해 문제를 해결하고 더 빠르게 다음 단계로 나아갈 수 있게 된 것이다.
미래의 개발자는 단순히 AI에게 명령을 내리는 사람이 될까? AI가 레벨 5에 도달해 자율적 목표 설정까지 가능해진다면, 개발자란 개념이 사실상 사라질 가능성도 있다. 즉, 추상화의 마지막 단계에서 개발자는 더 이상 '개발'을 하지 않는다. 그저 기획하고 명령한다. 예컨대, AI가 코드의 모든 부분을 관리하고 최적화할 수 있게 되면, 인간이 “좋은 코드란 무엇인가”를 판단하는 역할조차 사라질 수 있다. 개발자는 AI가 해결하기 어려운 추상적 사고와 창의적 접근을 설계하는 사람으로서, 기술적 장벽을 넘어서 다양한 문제를 아우르는 협력자로 남을 것이다.
그렇다면 여기서 두 가지 의문이 든다. 첫 번째는 레벨 5 단계가 올 것인가? 온다면 언제일 것인가? 두 번째는 레벨 5 단계가 온다고 해서 정말로 개발자가 사라질까? 즉, 많은 사람들의 표현과 같이 개발자는 대체될까?
개발자는 대체된다는 논쟁에 대해서
다양한 관점이 있고 참 뜨거운 논쟁이라고 생각한다. 이 지면에서 이 주제를 다 다루기는 힘들 것 같다. 간단하게나마 최근에 든 몇 가지 생각을 정리해보고자 한다.
역사가 일관성을 보장한다면, 역시 문제는 추상화다. 단, 현재의 문제는 역사가 일관성을 보장하느냐 그 자체에 있다.
유튜브를 보다가 "개발자는 AI에 의해 절대 대체되지 않을 것"이라고 주장하는 영상을 보았다. 요점은 3가지였다. 첫째, AI는 개발자의 도구에 불과하며, 도구의 발전이 개발자를 대체하지는 않았듯, AI 역시 개발자를 대체할 수 없다는 것이다. 오히려 개발자의 역할은 문제 해결자로서 확장하고 있다는 점이다. 둘째, AI는 특정 상황에서 훌륭한 성능을 보일지 몰라도 기업의 복잡한 문맥과 요구를 충족하기엔 아직 부족하다. 셋째, AI가 기초적인 코드 작성에 있어서는 뛰어나지만, 유지보수나 코드 품질 측면에서의 신뢰성은 떨어지며, 주니어 개발자가 조직 내에서 수행하는 문화적 역할도 대체할 수 없다.
3개월 전만 해도 나는 이러한 주장에 전적으로 동의했을 것이다. 그때까지는 “개발자는 AI에 의해 대체되는 것이 아니라, AI를 잘 사용하는 개발자에 의해 대체될 것”이라고 생각했고, 이 문장은 꽤 멋있다고 생각했다.
그런데 최근에는 이런 생각이 든다. AI는 정말로 도구가 맞는가? 추상화의 영역은 인간의 고유한 역할이 맞는가? 어떻게 확신할 수 있을까?
유발하라리는 최근의 저서 <넥서스>에서 역시 선지자적인 통찰을 보여주고 있는데, 개인적으로 읽으면서 정말 소름 돋았던 대목이 있다. 바로 다음과 같은 부분이다.
당신은 방금 읽은 것에 충격을 받았거나 화가 났을지도 모른다.
어쩌면 컴퓨터 혁명을 주도하는 사람들과 그것을 제대로 규제하지 못하는 정부에 화가 났을 수도 있다. 아니면 내가 현실을 왜곡하고 불안을 조장하면서 당신을 오도하고 있다는 생각에 나에게 화가 있을지도 모른다. 그런데 당신이 어떻게 생각하든 앞의 단락들은 당신에게 어떤 감정적 영향을 주었다. 나는 이야기를 들려주었고 이 이야기는 특정한 문제에 대한 당신의 생각을 바꾸고, 나아가 당신으로 하여금 세상에서 특정 행동을 취하게 할지도 모른다. 그러면 당신이 방금 읽은 이야기는 누가 만들었을까?
약속건대 내가 몇몇 사람들의 도움을 받아 직접 썼다. 이 이야기는 인간의 정신이 생산한 문화적 산물일을 약속한다. 그런데 당신은 그게 정말이라고 100퍼센트 확신할 수 있는가? 몇 년 전이라면 그럴 수 있었을 것이다. 2020년대 이전에는 지구상에 인간의 정신 외에는 정교한 텍스트를 생산할 수 있는 존재가 없었다. 오늘날은 상황이 다르다. 이론상 당신이 방금 읽은 텍스트는 어떤 컴퓨터의 이질적인 지능이 생성한 것일 수도 있다.
<넥서스> 유발 하라리 지음, 김명주 옮김, 김영사 p. 311
정말 소름 돋는 지적이다. 그렇다. 오늘날은 상황이 다르다. '이론상' 지금 이 텍스트는 어떤 이질적인 지능(Alien Intelligence)이 생성한 것일 수 있으며, 이것은 이제 전혀 이상한 이야기가 아니라는 점이다. 마찬가지로, 지금 이 글을 읽는 독자가 AI가 개발자를 대체할 수 있다고 긍정하는 견해에 고개를 갸우뚱한다면, 나는 동일한 질문을 던져보고 싶다. 그렇다면 지금 이 글을 쓰고 있는 나는 AI일까? 사람일까?
어쩌면 우리는 아직 제대로 된 질문을 못하고 있는 걸지도 모른다
조금 더 나아가서, 어쩌면 '대체'라는 개념 자체가 지금까지의 역사적 일관성을 토대로 한 '인간'이 가진 한계를 드러내는 표현은 아닐까?
유발 하라리는 AI의 발전과 이에 대한 최근의 우려에 대해서 다음과 같이 썼다.
또 하나 지적해 둘 것은, 사람들은 흔히 '인간 수준의 지능'을 기준으로 AI를 정의하고 평가하며, 따라서 AI가 언제 인간 수준의 지능에 도달할 것인지를 두고 많은 논쟁이 벌어지고 있다는 점이다. 하지만 이 기준은 심각 한 혼란을 부를 수 있다. 이는 마치 '새 수준의 비행 능력'을 기준으로 비행기를 정의하고 평가하는 것과 같다. AI는 인간 수준의 지능을 향해 발전하고 있지 않다. 그것은 완전히 다른 종류의 지능으로 진화하고 있다.
<넥서스> 유발 하라리 지음, 김명주 옮김, 김영사 p. 317
개발자 대체 논쟁을 유발 하라리의 통찰로 비춰보면, 애초에 이 논쟁 자체가 잘못된 질문에서 비롯된 것이 아닌가 하는 생각이 든다. 하라리는 인간과 AI의 지능을 비교하는 문제를 “새 수준의 비행 능력”으로 비행기를 평가하는 것과 같다고 비유한다. 인간처럼 지능을 구현하는 것이 AI의 목표가 아닌 것처럼, AI는 인간과는 전혀 다른 종류의 지능으로 나아가고 있다. 개발자를 대체할 수 있는지, 개발자의 역할을 수행할 수 있는지 묻는 질문은 결국 인간의 기준과 인간의 역할에 AI를 억지로 맞추려는 시도일 수 있다는 것이다.
따라서 AI가 개발자를 대체할지 여부에 대한 논쟁 자체가 근본적으로 틀린 질문일 수 있다. 인간의 한계를 토대로 한 질문으로, 이미 다른 지능을 구현하고 있는 AI의 본질을 이해하려는 시도는 본질적으로 모순적이다. 마치 하늘을 나는 비행기를 보고, 이 기계가 새의 능력을 대체했는지 묻는 것이 어색한 것처럼, AI가 개발자의 역할을 수행할 수 있는지, 개발자를 “대체”할 수 있는지 묻는 것 역시 어색하다.
AI를 단순히 도구로 보는 관점 역시 마찬가지이다. 흔히 AI를 ‘더 강력한 개발자 도구’로 보는 시각은, AI가 문제 해결을 지원하거나 특정 작업을 자동화하는 단순한 보조적 역할로만 머물러야 한다는 전제에서 비롯된다. 하지만 유발 하라리의 통찰처럼, AI가 인간과 전혀 다른 지능을 향해 진화하고 있다면? 그 낯선 지능이 "인간과 비슷한 방식으로 결정을 내리고 아이디어를 생성한다면"(p. 333)? AI를 도구로 단순화해서 평가하는 것은 AI의 잠재성에 대한 심각한 오해이며 낡은 패러다임이 아닐까?
실제로 AI는 더 이상 단순히 개발자의 "도구"로만 기능하지 않는다. AI는 스스로 학습하며, 독자적인 패턴을 발견하고, 인간이 예측하지 못한 방식으로 문제를 해결할 수 있는 가능성을 보여주고 있다. AI가 도구라면, 그 도구는 자율적으로 문제를 정의하고 스스로 해결해 나가는 도구인 셈이다. 그러나 그런 도구가 역사적으로 존재했던 적이 있었나? 이 답에 예스라고 답할 수 없다면, 역사적 일관성이 보장될 것은 어떻게 확신할 수 있을까?
어쩌면 앞으로의 AI 시대에는 “개발자”와 “개발”의 개념이 인간 중심의 사고에서 벗어나야 할지도 모른다. AI는 기존의 직업과 역할을 대체하기보다, 우리의 직업과 역할 자체를 새롭게 정의하고 확장하는 것으로 이어질 수 있다.
그리고 이는 비단 개발자 대 AI 구도에서만 작동할 프레임이 아닐 것이다. 본질적으로 이는 능력을 갖고 일을 하는 존재로서의 인간에 대한 새로운 정체성을 관통하는 중대한 철학적 주제이다.
나는 셜록 홈즈를 개인적으로 좋아하고 즐겨 읽었는데, 그의 추리 방식은 어릴 때부터 내게 참 큰 인상을 남겼던 것 같다. 그의 방식 중 하나는 모든 가능한 설명을 하나씩 지워나가고, 남은 것을 진실로 받아들이는 것이다. AI와 인간의 역할에 대한 논쟁에서도 우리는 비슷한 추리를 적용할 수 있지 않을까? 셜록이 말했듯, “모든 가능성을 지워나갔을 때 남는 것이 진실”이라면, 지금 시대에서 개발자가, 직업인이, 인류가 바로 보아야 할 진실이란 무엇일까? 이질적인 지능 AI가 단순한 도구나 인간의 역할을 대체하는 존재가 아니라, 인간과 새로운 방식으로 함께 진실을 탐구하는 존재로 자리 잡을 것이라는 인식이라면, 너무 비관적일까?
미래는 참 불투명하고 예측할 재주도 없다. 다만, 우리가 AI와 함께하는 시대를 제대로 이해하기 위해서는 기존의 패러다임을 벗어난 새로운 시각을 가져야 할 때는 아닌지 생각해 본다. 어쩌면, 우리는 아직 진정으로 올바른 질문을 찾지 못하고 있는지도 모른다. 어떤 질문을 가져야 할까?
이 글에서 인용한 책
- https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=344820692
- https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=349172323&start=slayer
글에서 언급한 ChatGPT를 이용해 완성한 파이썬 게임 레포
- https://github.com/noanswer-system-design-study/noanswer/tree/main/util/weapone-game
'회고' 카테고리의 다른 글
항해 플러스 백엔드 5기 수료 회고 - 여름 방학 경험치 이벤트가 끝나면? (8) | 2024.08.28 |
---|---|
2024년 8월 3-4주차 내가 깨야했던 퀘스트에 대해서 (feat. 패시브 스킬 회고) (0) | 2024.08.26 |
MSA 사가 패턴에서 '사가'라는 용어에 대해서 (0) | 2024.08.11 |
1년차 백엔드 개발자의 퇴사 회고 a.k.a 이직 후기 인트로 (2) | 2024.07.26 |
항해 플러스 백엔드 5기 1~5주차 현실 100% 회고 (1+1=N) (2) | 2024.07.19 |