최종 2 위 : "AI이름: 이어팟 주세요"
결승전에서 1등 AI의 액션들을 예측하기는 하였지만, counter_action_for_block 함수에 있는 잘못된 조건으로 인해 패배한걸로 예상됨.
// code.js : counter_action_for_block : Line 202
// 최종 제출 했던 코드
if(you_mp*3 < mp) return "attack";
block이 예측되어도 you_mp*3 < mp 라는 조건에 의해서 attack을 하도록 한 이유는,
상대방의 mp가 1 정도인데 나의 mp가 4 정도라면, 상대방이 block 하고있더라도 데미지를 입히는게 더 합리적이라고 판단함.
하지만 미처 생각치 못한 부분은 you_mp가 0일때 나의 mp가 1이어도 attack을 하게 되어서 손해를 보는것..
// code.js : counter_action_for_block : Line 202
// 이렇게 짰어야 했는데.........
if(you_mp !== 0 && you_mp*3 < mp) return "attack";
위의 잘못된 조건을 고치고나서 1등AI와 가상 배틀을 돌려본 결과 승률이 100퍼 가까이 나오는것을 볼수있었음.......
반면 최종 제출햇던 내 (버그가 있는)AI와 1등AI를 배틀을 해보면 승률이 40퍼정도밖에 안나오는걸 볼수있었음. 왜냐면 예측을 제대로 했더라도 손해보는 선택을 반복해서 하니까...
시험기간에 급하게 짜느라 테스트도 별로 못해보고, 테스트 코드도 못짠것이 아쉽다. 테스트 기반으로 코딩하는 것의 중요성을 다시 깨닫는 계기가 되었다.
또한 빠르게 짜다보니 코드 퀄리티를 크게 신경쓰지못함.
NDC 둘째날 점심시간, 딱 심심할 때, 네코동에서 AI 챌린지가 진행됩니다. 여러분이 직접 만든 자식같은 AI가 다른 AI들과 한판 붙는 것이죠. 룰도 친숙할 겁니다! 어릴 때 쎄쎄쎄 좀 해보셨던 분이라면요.
게임 룰은 O래곤볼 게임을 기반으로 만들어졌습니다. 기억 나시나요? '아' '파' '막기'(지역차이 有)만으로 승부를 내던 그것입니다.
네코동 AI 챌린지에서는, 여러분의 AI가 공룡이 되어 '듀'래곤볼 게임을 합니다.
- 각 경기는 여러 개의 라운드로 진행됩니다.(8강 이전: 11라운드, 8강: 3라운드, 결승: 5라운드)
- 각 라운드는 최대 50턴으로 진행됩니다.
- 각 라운드는 50턴이 모두 경과하거나, 하나 이상의 AI의 체력이 0이 될 때까지 진행합니다.
- 라운드가 종료되었을 때 체력이 더 많은 AI가 승리합니다. 동일하다면 라운드 무승부가 됩니다.
- 라운드 시작 시 각 AI는 25의 체력과 0의 기를 가지고 시작합니다.
- 체력은 0 아래로 떨어지지 않습니다.
- 각 턴마다 AI는 집중, 공격, 방어 중 하나의 행동을 선택합니다. 선택한 행동은 동시에 공개합니다.
집중
- 이번 턴에 상대가 나를 공격하지 않았다면 기를 1 얻습니다.
공격
- 이번 턴에 상대가 방어하지 않았다면 (1 + 자신의 기)만큼 상대의 체력을 깎음과 동시에 상대의 기를 0으로 만듭니다.
- 이번 턴에 상대가 방어했다면 (1 + 자신의 기) 대신 (자신의 기)만큼 상대의 체력을 깎습니다. 방어에 성공한 상대는 기를 1 얻습니다. (아래의 방어 행동 참고)
- 공격을 마친 후 자신의 기가 0보다 크다면, 자신의 기를 1 줄입니다.
방어
- 이번 턴에 상대의 공격이 내 체력을 1만큼 덜 깎습니다. (위의 공격 행동 참고)
- 이번 턴에 상대가 나를 공격했다면 기를 1 얻습니다.
- AI 작성은 4월 13일부터 21일까지 진행됩니다. (21일 마감!)
- 제출한 AI 전체를 서로 상대로 하여 1:1로 대전시킵니다. (N*(N-1) 풀 리그 방식)
- 한 경기는 최대 11라운드로 이루어집니다.
- 각 경기 마다 승은 3점, 무승부는 1점의 승점을 얻습니다. 그리고 승점 별로 등수를 매깁니다. 승점이 같은 경우 제출 시간이 빠른 쪽을 상위 등수로 합니다.
- 21일 자정에 제출 만료된 AI 기준으로 상위 8개의 AI를 토너먼트로 대전 시켜 1등부터 등수를 결정합니다. 이 결과로 상품을 결정합니다.
- 대회가 끝나기전 20일까지 중간 집계로 당시 시점까지 제출된 AI별 등수를 매일 공개합니다. 단 21일 제출된 AI를 포함한 등수는 공개하지 않으며, 중간 집계로 공개된 등수는 최종 등수랑은 무관합니다.
- 한 사람당 하나의 AI만 인정합니다. 메일 주소 여럿을 쓰면 알아내기 어렵지만, 대회 진행을 위해 협력해주세요.
- 여러번 제출하는 경우 마지막 제출을 기준으로 진행합니다.
A, B, C가 AI를 제출했다고 해봅시다. A:B, B:C, C:A 상대로 11판 6선승제로 풀 리그 대전을 합니다. A:B = 6승 2패로 A가 대전을 승리(A는 3점, B는 0점 획득) - 6선승 시점에서 종료 B:C = 5승 4패 2무로 B가 대전을 승리(B는 3점, C는 0점 획득) C:A = 5승 5패 1무로 대전 무승부(C, A 모두 1점씩 획득) 위와 같이 경기 결과가 나온 경우, 대전 결과를 종합하면 A: 1승 1무로 4점 B: 1승 1패로 3점 C: 1무 1패로 1점 A, B, C 순서대로 1, 2, 3등이 됩니다. 만약 점수가 같았다면 제출 순서를 따져 먼저 제출한 AI가 상위 등수를 차지합니다.
- 최종 집계에서 승점과 제출시간 기준으로 1등부터 8등까지를 결정합니다.
- 8개의 AI를 랜덤하게 섞어 토너먼트로 대전시킵니다.
- 만약 대전 결과가 무승부인 경우, 추가로 1라운드를 더 진행하여 첫 데미지를 입힌 AI가 승리합니다. (단, 서로 동일한 데미지를 주고 받은 경우에는 어떤 AI도 상대에게 첫 데미지를 입히지 못한 것으로 봅니다.) 추가 라운드 동안에 승리를 거둔 AI가 없다면 제출 시간이 빠른 쪽이 토너먼트에서 승리합니다.
- 25일 점심시간에 8강 토너먼트 및 결승을 진행하여 우승자를 가립니다. GB1 1F 참관객 쉼터(NDC PLAY ZONE)에서 중계가 진행될 예정입니다.
- 중계장에서는 실물 게임으로 다른 사람과 붙어볼 수 있습니다. 네코동 진행자가 참관한 경우 이긴 분께는 작은 선물이 전달될지도 모릅니다.
- 상품을 전달드리기 위해 8강 이상에 진출하신 경우 해당 날짜의 중계에 오셔야 합니다. 8강 이상에 진출하신 경우 메일로 알려드립니다.
- 경품 지급은 NDC 참관객만 가능합니다. 사전 대회에서 1~16위를 차지하신 분들께 NDC 참관권을 지급 드립니다.
심사의 편의를 위해 참가 가능한 언어는 Javascript로 제한합니다. 불필요한 동작을 하는 코드의 경우 실격처리할 수 있습니다(파일 오픈, 외부와 통신, 해킹 시도, 특수한 기법으로 룰을 우회하는 등). 코드로 특정 파일을 읽어들이는 등의 일반적이지 않은 사용은 허용하지 않습니다. 다음 형태의 함수를 작성하시면 됩니다. 인자 설명은 아래에 있습니다. 만약 구현상 다른 함수를 추가해야할 경우 자유롭게 추가해서 구현해 주세요. 프로그래밍 초보이신 경우 아래의 return 부분을 수정하여 특정 순서로 내는 AI를 쉽게 만드실 수 있습니다.
// Javascript
// charge, attack, block(집중, 공격, 방어) 순서대로 내는 AI 예제입니다.
function think(hp, mp, you_hp, you_mp, history, old_games) {
if (history.length % 3 == 0)
return 'charge';
if (history.length % 3 == 1)
return 'attack';
if (history.length % 3 == 2)
return 'block';
}
- think 함수는 6개의 인자를 받아 이번 턴에 플레이할 액션을 리턴합니다.
- think 함수는 1초안에 실행이 완료되어야 합니다. (성능 측정 참고)
- 전역 변수를 사용할 수는 있지만, 매번 새로 실행하기 때문에, think가 호출될 때 이전에 저장한 값이 유지되지는 않습니다.
- think는 'charge', 'attack', 'block' 중 하나를 리턴해야합니다.
- hp: 이번 턴의 자신의 체력이 정수로 주어집니다.
- mp: 이번 턴의 자신의 기가 정수로 주어집니다.
- you_hp: 이번 턴의 상대의 체력이 정수로 주어집니다.
- you_mp: 이번 턴의 상대의 기가 정수로 주어집니다.
- history: 이번 게임에 각 턴마다 사용된 액션들의 기록이 배열의 배열 형태로 주어집니다. 각 턴은 [내가 낸 액션, 상대가 낸 액션] 형태로 저장되며, history[0]이 첫번째 턴, history[1]이 두번째 턴이 됩니다. 맨처음 think가 불릴 때 history는 빈 배열, [] 값을 가집니다.
- old_games: 이전 게임들의 history가 저장된 배열입니다. (즉 배열의 배열의 배열 꼴을 가집니다.) 한 대전은 최대 11번(8강 이전) 경기를 하므로 old_games에는 최대 10개의 history가 저장됩니다.
- old_games의 길이를 이용하여 몇번째 게임인지 확인할 수 있습니다.
- 실행 중에 1초가 넘거나, 오류가 나거나, 잘못된 액션을 리턴하는 경우, 해당 게임을 패배로 처리하고, 다음 게임으로 진행합니다. 오류가 발생한 게임의 history는 old_games에 저장되지않습니다.
- hp = 25
- mp = 2
- you_hp = 25
- you_mp = 0
- history = [[‘block’, ‘attack’], [‘charge’, ‘block’]]
- old_games = [[[‘charge’, ‘block’], [‘block’, ‘attack’], [‘charge’, ‘charge’]], (다른 history들)…]
내가 block을 내고 상대가 attack을 내서 내가 상대의 공격을 막고 기를 1 흡수했고, 내가 charge를 내고 상대는 block을 내어 아무 체력 감소 없이 내 기가 두 번 모인 상태입니다. 한 번 더 charge를 해서 기를 모으거나(모험지향), attack을 해서 내가 모은기로 공격하거나(공격지향), 내가 기를 연속으로 모은 것을 파악한 상태가 공격할 것을 예상하고 block을 할 수 있습니다.(안전지향). old_games를 살펴서 어떤 수가 더 유리할지 더 고민해 볼 수 있습니다.