게임의 규칙을 확인하시고, 아래 함수들을 채운 후, 대결상대를 선택하고, 게임시작 버튼을 누르면 배틀이 시작됩니다.
15x15 좌표판 위에서 (0,0)부터 (14,14)까지의 좌표 중 하나를 선택하여 리턴하는 방식이고, 가로/세로/대각선 중 한 방향으로 연속된 다섯개의 좌표를 먼저 차지하면 승리합니다.
게임을 먼저 시작한 쪽이 1 round를 먼저 시작하고, 이전 round에서 진 쪽이 다음 round를 먼저 시작합니다.
총 6 round 중 4 round를 먼저 이기면 최종 승리하게 되며, 3대3이면 무승부 처리합니다.
나는 흰색, 상대방은 검정색입니다.
코드배틀은 내가 작성한 코드와 상대가 작성한 코드가 일대일로 대결하는 방식이며, 언어는 JAVASCRIPT 입니다.
코드를 작성하고, 대결상대를 RANDOM, LEVEL1, LEVEL2, LEVEL3, 온라인 상대 중에서 선택한 후 게임시작 버튼을 누르면 대결이 시작됩니다.
대결은 game이며, 1 game은 6 round로 구성되고, 1 round는 한쪽이 이기거나 모든 좌표가 점유될 때까지 turn이 계속됩니다.
각 game, round, turn의 시작과 끝에서 onGameStart, onRoundStart, onTurnStart, onRoundEnd, onGameEnd 함수가 호출되며, 사용자는 각 함수에 자신의 로직을 구현하면 됩니다.
게임의 규칙에 맞게 기본 전략을 세우고, 상대의 패턴을 분석하여 onTurnStart에서 최선의 선택을 반환하는 것이 승리의 핵심요소입니다.
/**
* 코드는 JAVASCRIPT 로 작성해 주세요.
*/
var turnMap = null; // 15x15 오목판의 상태를 나타내는 2차원 배열
var candidates = null; // 다음 턴에 선택할 수도 있는 위치값들의 후보들
var val_notyet = 0; // 오목판 특정위치의 상태값 중 아직 선택되지 않은 상태
var val_me = 1; // 오목판 특정위치의 상태값 중 내가 선택한 경우
var val_opponent = 2; // 오목판 특정위치의 상태값 중 상대가 선택한 경우
/**
* 게임이 시작되면 호출됩니다.
* 게임 중에 사용할 변수들의 초기화를 여기서 합니다.
*/
function onGameStart() {
// printLog(string)는 플레이 영역 하단의 게임 로그 영역에 텍스트를 출력하는 함수입니다.
printLog("onGameStart!");
}
/**
* 라운드가 시작되면 호출됩니다.
* 1번의 게임은 6번의 라운드를 실행합니다.
* 1번의 라운드가 오목 한판입니다.
*/
function onRoundStart() {
printLog("onRoundStart!");
// 15x15 오목판 초기화
turnMap = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]];
candidates = [];
}
/**
* [row,col] 위치값을 4자리 숫자로 변경
*/
function _locToNum(loc) {
return loc[0]*100 + loc[1];
}
/**
* 4자리 숫자를 다시 [row,col] 위치값으로 변경
*/
function _numToLoc(num) {
return [Math.floor(num/100), num%100];
}
/**
* 다음턴에 선택할수도 있는 후보 위치들 업데이트
* 바둑과 달리 오목은 놓여져 있는 돌들 근처에 다음돌을 두게 될 확률이 높다는 가정합니다.
*/
function _updateCandidates(loc) {
var diffs = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]];
candidates.splice(candidates.indexOf(_locToNum(loc)), 1);
diffs.forEach(function(diff) {
var r = loc[0] + diff[0];
var c = loc[1] + diff[1];
var num = _locToNum([r,c]);
if (r>=0 && r<15 && c>=0 && c<15 && turnMap[r][c]==0 && candidates.indexOf(num)<0) {
candidates.push(num);
}
});
}
/**
* 턴이 시작되면 호출됩니다.
* @param data
* data.turncnt: 턴이 실행된 횟수
* data.opponentchoice: 상대가 마지막에 선택한 위치. 없으면 첫턴임을 의미합니다.
* @return [row,col]
*/
function onTurnStart(data) {
var loc;
if (data.opponentchoice) {
loc = data.opponentchoice;
turnMap[loc[0]][loc[1]] = val_opponent;
_updateCandidates(loc);
loc = _numToLoc(candidates[Math.floor(Math.random()*candidates.length)]);
turnMap[loc[0]][loc[1]] = val_me;
_updateCandidates(loc);
} else {
// data가 없는 경우는, 첫번째 수를 두는 경우임을 의미합니다.
loc = [7,7];
turnMap[loc[0]][loc[1]] = val_me;
_updateCandidates(loc);
}
printLog("onTurnStart: op-"+data.opponentchoice+", me-"+loc);
return loc;
}
/**
* 라운드가 끝나면 호출되며, 라운드의 결과를 받아봅니다.
* @param result
* result.win: -1(졌을때) or 0(비겼을때) or 1(이겼을때)
* result.wincnt: 이번 게임에서 몇번의 라운드를 이겼는가
* result.losecnt: 이번 게임에서 몇번의 라운드를 졌는가
* result.turncnt: 턴이 실행된 횟수
* result.opponentchoice:
* 상대가 마지막에 선택한 위치.
* 상대가 해당 라운드를 이긴 경우 onTurnStart를 실행하지 않고 onRoundEnd가 호출되므로 이 값이 필요합니다.
*/
function onRoundEnd(result) {
printLog("onRoundEnd! win:"+result.win+", wincnt:"+result.wincnt+", losecnt:"+result.losecnt);
}
/**
* 게임이 끝나면 호출되며, 게임의 결과를 받아봅니다.
* @param result
* result.win: -1(졌을때) or 0(비겼을때) or 1(이겼을때)
*/
function onGameEnd(result) {
printLog("onGameEnd! win:"+result.win);
printLog("----------------------------");
}