소개
컨트롤러가 문제의 맨 아래에있는 스택 스 니펫에 완전히 포함되어있는 대화식 King-of-the-Hill 콘테스트입니다. 컨트롤러는 자동으로 답변을 읽고 게임을 통해 재생합니다. 누구나 언제든지 브라우저에서 언제든지 실행할 수 있습니다.
이 콘테스트의 메커니즘은 Red vs. Blue-Pixel Team Battlebots 의 메커니즘과 매우 유사합니다 . 그리드 기반이지만 게임이 진행되는 것을 제외하고는 완전히 다릅니다. 각 게임은 1 대 1이며 팀이 없습니다. 각 출전 작은 자신을 위해 싸우고 있으며 오직 한 사람 만이 최종 챔피언이 될 것입니다.
컨트롤러는 JavaScript를 사용하며 JavaScript는 대부분의 브라우저에서 지원하는 유일한 클라이언트 측 스크립팅 언어이므로 모든 답변도 JavaScript로 작성해야합니다 .
이 사양에서 기울임 꼴 텍스트 는 게임 메카닉 또는 속성의 공식 용어를 나타내는 데 사용됩니다. 이 용어는 게임의 다른 부분을 일관되고 명확하게 언급하는 데 도움을주기 위해 사용됩니다.
게임 플레이
기초
이 질문에 대한 모든 답변은 플레이어를 나타냅니다 . 게임은 두 선수 사이의 경쟁 P1 및 P2 . 각 플레이어는 0에서 7까지 번호가 매겨진 8 개의 봇 무리 를 제어합니다 . 게임은 그리드 에서 이루어집니다. 128x64 셀 경기장은 아래쪽 8 개의 행이 벽 ( '블록')으로 시작하고 다른 행은 공기로 시작합니다 . 그리드 경계 외부의 셀은 공기로 간주됩니다.
그리드의 x 좌표 범위는 왼쪽은 0에서 오른쪽은 127, y는 위쪽은 0, 아래쪽은 63입니다.
샘플 시작 그리드 :
봇은 항상 그리드 셀에 정렬 된 상태를 유지하며 여러 봇이 동일한 셀을 차지할 수 있습니다. 봇은 공기 셀만 차지할 수 있습니다. P1의 봇은 항상 벽 위 줄의 가장 왼쪽에있는 0-7 라인에서 시작하고 P2의 봇은 항상 맨 오른쪽에 7-0 라인에서 시작합니다.
봇 또는 셀 의 이웃 은 직접 직교하고 대각선 인 8 개의 셀입니다.
봇의 FOV (field of view )는 봇을 중심으로하는 13 × 13 셀 사각형입니다. 셀 또는 적 봇은 플레이어 봇 중 하나 이상의 FOV에있는 경우 플레이어의 FOV에 있다고합니다.
이동 및 동작
게임 중에 각 플레이어는 1000 번 움직 입니다. P1이 먼저 이동 한 다음 P2, P1 등이 2000 회 이동하여 게임이 종료됩니다.
이동하는 동안 각 플레이어는 FOV의 게임 상태와 그리드 셀 및 적 봇에 대한 정보를 수신하고이를 사용 하여 각 봇이 수행 할 작업 을 결정합니다 .
봇이 그리드를 움직이거나 그리드와 상호 작용하지 않는 기본 동작은 nothing 입니다.
다른 행동은 움직이고 , 잡고 , 장소입니다 :
다음과 같은 경우 봇은 인접 셀 C 중 하나로 이동할 수 있습니다 .
- C는 한계를 벗어난 것이 아니며
- C는 공기 (즉 벽이 아님)
- C의 이웃 중 적어도 하나는 벽이다.
성공하면 봇은 C로 이동합니다.
봇은 다음 과 같은 경우 인접 셀 C 중 하나를 잡을 수 있습니다 .
- C는 한계를 벗어난 것이 아니며
- C는 벽이고
- 봇은 이미 벽을 가지고 있지 않습니다.
성공하면 C는 공중이되고 봇은 이제 벽을 옮길 것입니다.
다음과 같은 경우 봇은 인접 셀 C 중 하나에 배치 할 수 있습니다 .
- C는 한계를 벗어난 것이 아니며
- C는 공기입니다
- 어느 플레이어의 봇도 C를 차지하지 않습니다.
- 봇이 벽을 들고 있습니다.
성공하면 C는 벽이되고 봇은 더 이상 벽을 운반하지 않습니다.
실패한 조치는 아무것도하지 않습니다.
하나 이상의 벽 운반 봇이 차지하는 셀에는 작은 벽 색 사각형이 그려져 있습니다. 봇은 벽없이 시작합니다.
기억
이동 중에 플레이어는 게임 전체에서 지속되며 전략적 데이터를 저장하는 데 사용할 수있는 초기 빈 문자열 인 메모리에 액세스하고 메모리를 변경할 수 있습니다.
골
노란색 십자형의 셀은 목표 이며, 이는 임의의 위치에서 시작됩니다. 각 플레이어는 0에서 시작 하는 점수 를 갖습니다 . 플레이어의 봇이 목표로 이동하면 해당 플레이어의 점수가 1 씩 증가하고 다음 턴 전에 목표의 위치가 임의로 변경됩니다. 게임 종료시 가장 높은 점수를 얻은 플레이어가 승리합니다. 점수가 같으면 동점입니다.
이동 중에 여러 봇이 목표로 이동해도 플레이어는 여전히 1 점을 얻습니다.
목표가 500 이동에 대해 같은 장소에 있다면, 무작위로 다시 위치가 변경됩니다. 목표가 무작위로 배치 될 때마다 봇이 차지하는 셀에 배치되지 않습니다.
무엇을 프로그램
이 함수 의 본문 을 작성하십시오 .
function myMove(p1, id, eid, move, goal, grid, bots, ebots, getMem, setMem) {
//body goes here
}
플레이어가 움직일 때마다 한 번씩 호출되며 이동 중에 각 봇이 원하는 동작을 반환해야합니다.
기준 코드를 시작점으로 사용할 수 있습니다 .
매개 변수
p1
true
당신이 P1이고false
P2라면 부울입니다.id
는 답변의 답변 ID 인 정수입니다.
- 답변 아래에있는 '공유'링크를 클릭
a/
하고 URL에서 바로 뒤에있는 번호를 찾아 답변의 ID를 찾을 수 있습니다 .- 테스트 항목의 ID는 -1입니다.
eid
적의 답변의 답변 ID 인 정수입니다.move
1에서 1000 사이의 정수로, 현재 이동중인 것을 나타냅니다.goal
x
와y
속성 이있는 객체입니다 . 목표의 좌표입니다. 목표가 FOV를 벗어난 경우에도 제공됩니다.grid
x 및 y 인수를받는 함수입니다 (예 :)grid(x,y)
. 다음을 반환합니다.
-1
인수가 두 개의 정수x,y
가 아니거나 FOV에 없는 경우 '알 수 없음' 입니다.0
'공기'x,y
가 범위를 벗어나거나 셀x,y
이 공기 인 경우1
셀이 벽이면 '벽'x,y
입니다.
bots
8 개의 봇 배열입니다. 그 요소는 속성을 가진 객체x
,y
및hasWall
:
x
그리고y
로봇의 좌표입니다.hasWall
이다true
봇이와 벽을 운반하는 경우false
그렇지 않은 경우.
bots
N은 항상 봇 번호 N에 해당합니다.ebots
와 오브젝트의 배열x
,y
및hasWall
특성 막 등bots
. FOV의 적 봇만에 있습니다ebots
. 따라서 FOV에 적 로봇이 없으면 길이는 0입니다. 무작위로 주문됩니다.getMem
메모리를 반환하는 인수가없는 함수입니다.setMem
M이 하나의 인수 M을받는 함수입니다. M이 256 자 이하의 문자열 인 경우 메모리가 M으로 업데이트되고, 그렇지 않으면 아무 일도 일어나지 않습니다.
브라우저 console
항목은 테스트 항목에만 사용할 수 있습니다.
반환 값
함수는 각각 0에서 24 사이의 정확히 8 개의 정수 배열을 반환해야합니다. 인덱스 N의 값은 봇 번호 N이 취할 동작입니다.
당신의 모든 봇은 당신의 기능이라면 아무것도하지 않을 것입니다 :
- 모든 종류의 오류가 발생합니다. ( 오류 )
- 실행하는 데 20 밀리 초 보다 오래 걸립니다 . ( 시간 초과 )
- 0에서 24 사이의 정수 8 개 배열을 반환하지 않습니다. ( malformed )
편의를 위해 게임이 끝날 때 오류, 시간 초과 및 잘못된 조치 수가 표시됩니다.
0에서 24까지의 각 숫자는 특정 봇 동작에 해당합니다.
- 0은 아무것도하지 않습니다.
- 1-8은 움직입니다.
- 9-16은 잡기위한 것입니다.
- 17-24는 배치합니다.
이동, 잡기 및 배치에 대한 각각의 8 개 값은 다음과 같이 봇의 인접 셀 중 하나에 해당합니다.
예를 들어, 15
봇 아래에서 셀을 잡는 동작입니다.
봇 동작은 봇 0에서 봇 7까지의 순서로 처리됩니다. 예를 들어, 한 번의 이동 중 봇 0이 동일한 에어셀 봇 1에 벽을 놓으라고 지시되면, 에어셀은 봇 전에 벽이됩니다. 1의 동작이 처리되고 봇 1이 실패합니다.
실패한 행동은 아무것도하지 않고 실패 했다고합니다 . 게임이 종료되면 실패한 작업 카운터도 표시됩니다.
규칙
이 규칙을 따르지 않는 사용자 또는 답변을 일시적 또는 영구적으로 실격 시킬 수 있습니다 . 실격 된 참가작은 이길 수 없습니다.
변수 나 함수를 선언 할 때는
var
키워드 를 사용해야합니다 .
예를 들어var x = 10
, 전역이var sum = function(a, b){ return a + b }
되지 않고 선언 된 것들은var
컨트롤러를 방해 할 수 있습니다. 이 간섭이 불가능 해 지도록 조치를 취했지만이를 확인하십시오.코드가 느리게 실행되거나 시간을 낭비해서는 안됩니다.
실행 중 JavaScript 함수를 중지 할 수 없으므로 각 플레이어의 코드가 실행됩니다. 코드를 실행하는 데 시간이 오래 걸리면 플레이어를 실행하는 모든 사람이 알아 차리고 짜증을냅니다. 이상적으로는 항목이 항상 20ms 제한 내에서 잘 실행됩니다.- 최신 버전의 Firefox에서는 ECMAScript 5와 호환되는 코드를 사용해야합니다. ECMAScript 6의 기능은 아직 많은 브라우저에서 지원 되지 않으므로 사용하지 마십시오 .
- 각 전략이 상당히 다른 경우에만 최대 3 번 까지 답변 할 수 있습니다 . 원하는만큼 답변을 편집 할 수 있습니다.
- 당신의 사용을 통해 제외하고 메모리의 어떤 종류를 시도하지 않을 수 있습니다
getMem
와setMem
. - 컨트롤러, 다른 플레이어 코드 또는 외부 리소스에 액세스하거나 수정하려고 시도해서는 안됩니다.
- JavaScript에 내장 된 것을 수정하려고 시도하지 않을 수 있습니다.
- 답은 결정론적일 필요는 없다. 을 사용할 수 있습니다
Math.random
.
답변 형식
#EntryName
Notes, etc.
<!-- language: lang-js -->
//function body
//probably on multiple lines
More notes, etc.
첫 번째 여러 줄 코드 블록에는 함수 본문이 포함되어야합니다.
항목 이름은 20 자로 제한됩니다.
귀하의 항목은 제목 컨트롤러에 표시됩니다 EntryName - Username [answer ID]
, 플러스 [DQ]
그것은 실격 않다면.
승리
질문이 최소 3 주 동안 완료되고 일단 답변이 확정되면 챔피언을 선정합니다.
컨트롤러의 자동 실행 기능을 사용하겠습니다 . 자동 실행 라운드에서 실격되지 않은 모든 플레이어는 서로 P1과 P2 (이중 라운드 로빈)의 두 게임을합니다.
몇 시간 동안 가능한 한 많은 라운드를 자동 실행합니다. 제출 횟수와 제출 시간에 따라 달라집니다. 그러나 정확한 최종 순위표를 얻는 데 최선을 다하고 있습니다. 가장 많은 승리를 한 플레이어가 챔피언이며 그들의 답변이 수락됩니다.
Windows 8.1 64 비트, 4GB 램 및 1.6GHz 쿼드 코어 프로세서가 장착 된 랩톱에서 Firefox를 사용합니다.
상
나는 챔피언에게 특별히 헌신 된 PPCG 챌린지를 작성하고 게시 할 것입니다. 그것은 어떻게 든 그들의 사용자 이름이나 아바타 또는 그들에 관한 무언가를 포함 할 것입니다. 이 콘테스트가 끝났을 때 어떤 도전이 될지 개인적으로 결정하겠습니다. 최선을 다해 작성하여 핫 네트워크 질문이되도록 노력하겠습니다.
제어 장치
이 스 니펫을 실행 하거나이 JSFiddle 로 이동 하여 컨트롤러를 사용하십시오. 무작위 플레이어가 선택된 상태에서 시작합니다. Firefox와 Chrome에서만 철저히 테스트했습니다.
<style>html *{font-family:Consolas,Arial,sans-serif}canvas{margin:6px}button,input table,select{font-size:100%}textarea{font-family:monospace}input[type=text],textarea{padding:2px}textarea[readonly]{background-color:#eee}select{width:250pt;margin:3px 0}input[type=radio]{vertical-align:-.25em}input[type=checkbox]{vertical-align:-.15em}.c{margin:12px}.h{font-size:125%;font-weight:700}#main td{padding:12px;text-align:left}#main table{margin-left:auto;margin-right:auto}#main{text-align:center}#title{margin:12px;font-size:175%;font-weight:700;color:#333}#delay{text-align:right}#statsTable table{border-collapse:collapse}#statsTable td{border:1px solid gray;padding:3pt;font-family:monospace;text-align:center}#footnotes{margin:18px 0 0;font-size:75%}#arWrapper{border:2px solid red;background-color:#fff4f4}</style><div id=loadStatus>Loading entries...</div><div id=main><div id=title>Block Building Bot Flocks</div><div><span id=p1Title class=p1Color></span> vs. <span id=p2Title class=p2Color></span></div><canvas id=canvas>Canvas unsupported!</canvas><div><span id=p1Score class=p1Color>0</span> | <span id=moveCounter>0</span> | <span id=p2Score class=p2Color>0</span></div><div class=c><button id=runPause type=button onclick=runPause()>Run</button> <button id=moveOnce type=button onclick=moveOnce()>Move Once</button> <button type=button onclick=newGame()>New Game</button></div><div class=c><input id=delay size=4 value=20> ms delay <input id=showNumbers type=checkbox onclick=toggleNumbers()><label for=showNumbers>Show bot numbers</label> <input id=showLOS type=checkbox onclick=toggleLOS()><label for=showLOS>Show field of view</label></div><table><tr><td><div id=p1Header class="p1Color h">Player 1</div><div><select id=p1Select onchange=changeSelect(!0)></select></div><div><a id=p1Link href=javascript:;>Answer Link</a></div><td><div id=p2Header class="p2Color h">Player 2</div><div><select id=p2Select onchange=changeSelect(!1)></select></div><div><a id=p2Link href=javascript:;>Answer Link</a></div></table><div>Test Entry</div><div><textarea id=testEntry rows=8 cols=64>return [0,0,0,0,0,0,0,0]</textarea></div><div class=c><button type=button onclick=autorun()>Autorun N Rounds</button> N = <input id=N size=4 value=1> <input id=arTestEntry type=checkbox><label for=arTestEntry>Include Test Entry</label></div><div id=footnotes><input id=debug type=checkbox onclick=toggleDebug()><label for=debug>Console debug messages</label> | Scale: <input id=sc1 type=radio name=sc value=1><label for=sc1>Micro</label><input id=sc3 type=radio name=sc value=3><label for=sc3>Small</label><input id=sc6 type=radio name=sc value=6 checked><label for=sc6>Normal</label><input id=sc9 type=radio name=sc value=9><label for=sc9>Large</label> | Colors: <input id=normalCo type=radio name=co value=normal checked><label for=normalCo>Normal</label><input id=pastelCo type=radio name=co value=pastel><label for=pastelCo>Pastels</label><input id=neonCo type=radio name=co value=neon><label for=neonCo>Neon</label> <button type=button onclick=reload()>Reload</button><div id=invalidWrapper><br>No entry name/code found: <span id=invalid></span></div></div></div><div id=arWrapper><div id=arInfo class=c>Autorun in progress. Running game <span id=arProgress></span>.</div><div id=arResults><div class="c h">Autorun Results</div><div class=c>Players: <span id=arPlayers></span><br>Rounds: <span id=arRounds></span><br>Games per round: <span id=arGpR></span><br>Total games: <span id=arTotal></span><br></div><div class=c><strong>Leaderboard:</strong></div><div id=leaderboard class=c></div><div class=c>(W = wins, T = ties, L = losses, G = total goals, E = errors, I = timeouts, M = malformed actions, F = failed actions)</div><div class=c><strong>Player vs. Player Statistics:</strong></div><div id=statsTable class=c></div><div class=c>The top row has the ID's of P1.<br>The left column has the ID's of P2.<br>Every other cell not on the diagonal has the form "[P1 win count] [tie count] [P2 win count]".</div><div class=c><button type=button onclick=closeAutorun()>Close</button></div></div></div><script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><script>function setGlobals(e){G={},G.QID=50690,G.SITE="codegolf",G.DQ_ANSWERS=[],G.DQ_USERS=[],G.DEBUG=Q("#debug").is(":checked"),G.SHOW_NUMBERS=Q("#showNumbers").is(":checked"),G.SHOW_LOS=Q("#showLOS").is(":checked"),G.BOTS=8,G.LOS=6,G.W=128,G.H=64,G.SCALE=e?6:parseInt(Q('input[name="sc"]:checked').val()),G.CW=G.SCALE*G.W,G.CH=G.SCALE*G.H,G.TOTAL_MOVES=2e3,G.GOAL_LIFESPAN=500,G.MEM_MAX_LENGTH=256,G.TIME_LIMIT=20;var t=Q('input[name="co"]:checked').val();e||"normal"===t?G.COLORS={AIR:"#ccc",WALL:"#888",GOAL:"rgba(255,255,0,0.6)",BG:"#f7f7f7",P1:"#00f",P1_TEXT:"#008",P1_LOS:"rgba(0,0,255,0.1)",P2:"#f00",P2_TEXT:"#800",P2_LOS:"rgba(255,0,0,0.1)"}:"pastel"===t?G.COLORS={AIR:"#cef0ff",WALL:"#66cc66",GOAL:"rgba(0,0,0,0.3)",BG:"#fdfde6",P1:"#f4a034",P1_TEXT:"#a35f00",P1_LOS:"rgba(255,179,71,0.2)",P2:"#f67cf6",P2_TEXT:"#b408b4",P2_LOS:"rgba(249,128,249,0.2)"}:"neon"===t&&(G.COLORS={AIR:"#000",WALL:"#444",GOAL:"rgba(255,255,0,0.9)",BG:"#999",P1:"#0f0",P1_TEXT:"#5f5",P1_LOS:"rgba(255,128,0,0.15)",P2:"#f0f",P2_TEXT:"#f5f",P2_LOS:"rgba(0,255,255,0.15)"}),G.SCOREBOARD={P1SCORE:void 0,MOVE:void 0,P2SCORE:void 0},G.CTX=void 0,G.PLAYERS=void 0,G.GAME=void 0,G.TIMER=void 0,G.RUNNING=!1}function reload(){var e="undefined"==typeof G;e||stopTimer(),setGlobals(e);var t=Q("#canvas");t.width(G.CW).height(G.CH).prop({width:G.CW,height:G.CH}),G.CTX=t[0].getContext("2d"),G.CTX.font=(2*G.SCALE).toString()+"px Courier New",G.SCOREBOARD.P1SCORE=Q("#p1Score"),G.SCOREBOARD.MOVE=Q("#moveCounter"),G.SCOREBOARD.P2SCORE=Q("#p2Score"),Q("body").css("background-color",G.COLORS.BG),Q(".p1Color").css("color",G.COLORS.P1),Q(".p2Color").css("color",G.COLORS.P2),Q("#invalidWrapper").hide(),Q("#arWrapper").hide(),loadAnswers(G.SITE,G.QID,function(e){Q.isArray(e)?(Q("#loadStatus").remove(),loadPlayers(e),newGame()):Q("#loadStatus").text("Error loading entries - "+e)})}function maskedEval(e,t){var r={};for(i in this)r[i]=void 0;for(i in t)t.hasOwnProperty(i)&&(r[i]=t[i]);return new Function("with(this) { "+e+";}").call(r)}function toKey(e,t){return G.W*t+e}function fromKey(e){return{x:e%G.W,y:Math.floor(e/G.W)}}function outOfBounds(e,t){return 0>e||e>=G.W||0>t||t>=G.H}function rnd(e){return Math.floor(Math.random()*e)}function isInt(e){return"number"==typeof e&&e%1===0}function isString(e){return"string"==typeof e||e instanceof String}function decode(e){return Q("<textarea>").html(e).text()}function shuffle(e){for(var t,r,o=e.length;o;t=rnd(o),r=e[--o],e[o]=e[t],e[t]=r);}function makeTable(e){for(var t=Q("<table>"),r=0;r<e.length;r++){for(var o=Q("<tr>"),a=0;a<e[r].length;a++)o.append(Q("<td>").text(e[r][a]));t.append(o)}return t}function toggleDebug(){G.DEBUG=Q("#debug").is(":checked")}function toggleNumbers(){G.SHOW_NUMBERS=Q("#showNumbers").is(":checked"),drawGame(G.GAME)}function toggleLOS(){G.SHOW_LOS=Q("#showLOS").is(":checked"),drawGame(G.GAME)}function closeAutorun(){Q("#arWrapper").hide(),Q("#main").show()}function changeSelect(e){var t=Q(e?"#p1Select":"#p2Select").val(),r=Q(e?"#p1Link":"#p2Link");null===t&&0>t?r.attr("href","javascript:;"):r.attr("href",G.PLAYERS[t].link)}function stopTimer(){"undefined"!=typeof G.TIMER&&clearInterval(G.TIMER)}function moveOnce(){gameOver(G.GAME)||(moveGame(G.GAME),drawGame(G.GAME),gameOver(G.GAME)&&(stopTimer(),Q("#runPause").text("Run").prop("disabled",!0),Q("#moveOnce").prop("disabled",!0),G.DEBUG&&console.log("======== GAME OVER: "+G.GAME.p1.score+" TO "+G.GAME.p2.score+" ========"),alert(gameOverMessage(G.GAME))))}function runPause(){if(G.RUNNING)stopTimer(),Q("#runPause").text("Run"),Q("#moveOnce").prop("disabled",!1);else{var e=parseInt(Q("#delay").val());if(isNaN(e)||0>e)return void alert("Delay must be a non-negative integer.");Q("#runPause").text("Pause"),Q("#moveOnce").prop("disabled",!0),G.TIMER=setInterval(moveOnce,e)}G.RUNNING=!G.RUNNING}function newGame(){stopTimer();var e=G.PLAYERS[Q("#p1Select").val()],t=G.PLAYERS[Q("#p2Select").val()];G.RUNNING=!1,Q("#runPause").text("Run").prop("disabled",!1),Q("#moveOnce").prop("disabled",!1),Q("#p1Title").text(e.title),Q("#p2Title").text(t.title),G.GAME=createGame(e,t),drawGame(G.GAME)}function tryParse(e,t){var r=parseInt(Q(e).val());return!isNaN(r)&&r>=0?r:void alert(t+" must be a non-negative integer.")}function autorun(){function e(){for(var e=new Array(a.length),t={},r=["wins","goals","errors","timeouts","malformed","invalid"],n=0;n<e.length;n++){t.wins=t.ties=t.losses=t.goals=t.errors=t.timeouts=t.malformed=t.invalid=0;for(var l=0;l<e.length;l++)n!==l&&(t.ties+=s[n][l].ties+s[l][n].ties,t.losses+=s[n][l].p2.wins+s[l][n].p1.wins,r.forEach(function(e){t[e]+=s[n][l].p1[e]+s[l][n].p2[e]}));e[n]={wins:t.wins,text:a[n].title+" : "+t.wins+"W, "+t.ties+"T, "+t.losses+"L, "+t.goals+"G, "+t.errors+"E, "+t.timeouts+"I, "+t.malformed+"M, "+t.invalid+"F"}}e=e.sort(function(e,t){return t.wins-e.wins}).map(function(t,r){return r+1+". "+t.text+(r<e.length-1?"<br>":"")});for(var i=new Array(s.length+1),G=0;G<i.length;G++){i[G]=new Array(s.length+1);for(var c=0;c<i.length;c++){var f;i[G][c]=0===c&&0===G?"P2\\P1":0===c?a[G-1].id:0===G?a[c-1].id:(f=s[c-1][G-1])?f.p1.wins+" "+f.ties+" "+f.p2.wins:"-"}}Q("#arPlayers").text(a.length),Q("#arRounds").text(o),Q("#arGpR").text(S/o),Q("#arTotal").text(S),Q("#leaderboard").empty().append(e),Q("#statsTable").empty().append(makeTable(i)),Q("#arInfo").hide(),Q("#arResults").show()}function t(e,t){for(var r=createGame(a[e],a[t]);!gameOver(r);)moveGame(r);r.p1.score>r.p2.score?s[e][t].p1.wins++:r.p1.score<r.p2.score?s[e][t].p2.wins++:s[e][t].ties++,["p1","p2"].forEach(function(o){s[e][t][o].goals+=r[o].score,s[e][t][o].errors+=r[o].stats.errors,s[e][t][o].timeouts+=r[o].stats.timeouts,s[e][t][o].malformed+=r[o].stats.malformed,s[e][t][o].invalid+=r[o].stats.invalid.reduce(function(e,t){return e+t},0)})}function r(){if(c!==f&&(t(c,f),++p<=S&&Q("#arProgress").text(p+"/"+S)),f+1<a.length)f++;else if(f=0,c+1<a.length)c++;else{if(c=0,!(o>i+1))return void e();i++}setTimeout(r,0)}var o=parseInt(Q("#N").val());if(isNaN(o)||1>o)return void alert("N must be a positive integer.");var a=[];Q("#arTestEntry").is(":checked")&&a.push(G.PLAYERS[0]);for(var n=1;n<G.PLAYERS.length;n++)G.PLAYERS[n].dq||a.push(G.PLAYERS[n]);for(var s=new Array(a.length),n=0;n<a.length;n++){s[n]=new Array(a.length);for(var l=0;l<a.length;l++)n!==l&&(s[n][l]={ties:0,p1:{wins:0,goals:0,errors:0,timeouts:0,malformed:0,invalid:0},p2:{wins:0,goals:0,errors:0,timeouts:0,malformed:0,invalid:0}})}var i=0,c=0,f=0,p=1,S=o*a.length*(a.length-1);Q("#arProgress").text("1/"+S),Q("#main").hide(),Q("#arInfo").show(),Q("#arResults").hide(),Q("#arWrapper").show(),setTimeout(r,0)}function gameOver(e){return e.move>=G.TOTAL_MOVES}function gameOverMessage(e){function t(e,t){return"P"+(t?1:2)+": "+e.entry.title+"\nScore: "+e.score+"\nErrors: "+e.stats.errors+"\nTimeouts: "+e.stats.timeouts+"\nMalformed actions: "+e.stats.malformed+"\nFailed actions: ["+e.stats.invalid.toString().replace(/,/g,", ")+"]"}var r="GAME OVER - ";return r+=e.p1.score>e.p2.score?"PLAYER 1 WINS":e.p1.score<e.p2.score?"PLAYER 2 WINS":"TIE GAME",r+="\n\n"+t(e.p1,!0)+"\n\n"+t(e.p2,!1)}function createGame(e,t){function r(e){return{entry:e,bots:new Array(G.BOTS),mem:"",score:0,stats:{errors:0,timeouts:0,malformed:0,invalid:Array.apply(null,new Array(G.BOTS)).map(Number.prototype.valueOf,0)}}}var o={},a=Math.floor(.875*G.H)-1;o.move=0,o.walls=new Array(G.H);for(var n=0;n<G.H;n++){o.walls[n]=new Array(G.W);for(var s=0;s<G.W;s++)o.walls[n][s]=n>a}o.p1=r(e),o.p2=r(t);for(var l=0;l<G.BOTS;l++)o.p1.bots[l]={x:l,y:a,hasWall:!1},o.p2.bots[l]={x:G.W-1-l,y:a,hasWall:!1};if(-1===o.p1.entry.id||-1===o.p2.entry.id){var i=decode(Q("#testEntry").val());-1===o.p1.entry.id&&(o.p1.entry.code=i),-1===o.p2.entry.id&&(o.p2.entry.code=i)}return resetGoal(o),G.DEBUG&&console.log("======== NEW GAME: "+o.p1.entry.title+" VS "+o.p2.entry.title+" ========"),o}function moveGame(e){movePlayer(e,++e.move%2===1),++e.goal.age>=G.GOAL_LIFESPAN&&resetGoal(e)}function setupParams(e,t){function r(e,t){var r=toKey(e,t);if(!n.hasOwnProperty(r)){n[r]=!1;for(var a=0;a<G.BOTS;a++)if(Math.abs(o.bots[a].x-e)<=G.LOS&&Math.abs(o.bots[a].y-t)<=G.LOS){n[r]=!0;break}}return n[r]}var o=t?e.p1:e.p2,a=t?e.p2:e.p1,n={},s={};s.p1=t,s.id=o.entry.id,s.eid=a.entry.id,s.score=o.score,s.escore=a.score,s.move=Math.floor((e.move+1)/2),s.goal={x:e.goal.x,y:e.goal.y},s.getMem=function(){return o.mem},s.setMem=function(e){isString(e)&&e.length<=G.MEM_MAX_LENGTH&&(o.mem=e)},s.grid=function(t,o){return isInt(t)&&isInt(o)&&r(t,o)?outOfBounds(t,o)?0:e.walls[o][t]?1:0:-1},s.bots=new Array(G.BOTS),s.ebots=[];for(var l=0;l<G.BOTS;l++)s.bots[l]={x:o.bots[l].x,y:o.bots[l].y,hasWall:o.bots[l].hasWall},r(a.bots[l].x,a.bots[l].y)&&s.ebots.push({x:a.bots[l].x,y:a.bots[l].y,hasWall:a.bots[l].hasWall});return shuffle(s.ebots),-1===o.entry.id&&(s.console=console),s}function movePlayer(e,t){var r,o,a=t?e.p1:e.p2,n=t?e.p2:e.p1,s=setupParams(e,t);G.DEBUG&&(console.log("######## MOVE "+e.move+" - P"+(t?1:2)+" ########"),console.log("PARAMETERS:"),console.log(s)),o=performance.now();try{r=maskedEval(a.entry.code,s)}catch(n){return a.stats.errors++,void(G.DEBUG&&(console.log("!!!! ERRORED !!!!"),console.log(n)))}if(o=performance.now()-o,G.DEBUG&&console.log("TIME TAKEN: "+o+"ms"),o>G.TIME_LIMIT)return a.stats.timeouts++,void(G.DEBUG&&console.log("!!!! TIMED OUT !!!!"));if(G.DEBUG&&(console.log("ACTIONS:"),console.log(r)),!Array.isArray(r)||r.length!==G.BOTS)return a.stats.malformed++,void(G.DEBUG&&console.log("!!!! MALFORMED ACTIONS !!!!"));for(var l=0;l<G.BOTS;l++)if(!isInt(r[l])||r[l]<0||r[l]>24)return a.stats.malformed++,void(G.DEBUG&&console.log("!!!! MALFORMED ACTIONS !!!!"));performActions(e,a,r)}function performActions(e,t,r){function o(e){t.stats.invalid[e]++,G.DEBUG&&console.log("!! BOT"+e+" ACTION FAILED !!")}function a(e){return e.x!==i||e.y!==c}for(var n=!1,s=0;s<G.BOTS;s++){var l=r[s];if(l){var i,c;switch((l-1)%8){case 0:i=-1,c=-1;break;case 1:i=0,c=-1;break;case 2:i=1,c=-1;break;case 3:i=-1,c=0;break;case 4:i=1,c=0;break;case 5:i=-1,c=1;break;case 6:i=0,c=1;break;case 7:i=1,c=1}if(i+=t.bots[s].x,c+=t.bots[s].y,outOfBounds(i,c))o(s);else switch(Math.floor((l-1)/8)){case 0:!e.walls[c][i]&&(i>0&&c>0&&e.walls[c-1][i-1]||c>0&&e.walls[c-1][i]||i<G.W-1&&c>0&&e.walls[c-1][i+1]||i>0&&e.walls[c][i-1]||i<G.W-1&&e.walls[c][i+1]||i>0&&c<G.H-1&&e.walls[c+1][i-1]||c<G.H-1&&e.walls[c+1][i]||i<G.W-1&&c<G.H-1&&e.walls[c+1][i+1])?(t.bots[s].x=i,t.bots[s].y=c,i!==e.goal.x||c!==e.goal.y||n||(n=!0,G.DEBUG&&console.log("** BOT"+s+" REACHED GOAL **"))):o(s);break;case 1:e.walls[c][i]&&!t.bots[s].hasWall?(e.walls[c][i]=!1,t.bots[s].hasWall=!0):o(s);break;case 2:!e.walls[c][i]&&t.bots[s].hasWall&&e.p1.bots.every(a)&&e.p2.bots.every(a)?(e.walls[c][i]=!0,t.bots[s].hasWall=!1):o(s)}}}n&&(t.score++,resetGoal(e)),G.DEBUG&&(console.log("FINAL PLAYER STATE:"),console.log(t))}function resetGoal(e){for(var t={},r=[],o=0;o<G.BOTS;o++)t[toKey(e.p1.bots[o].x,e.p1.bots[o].y)]=!0,t[toKey(e.p2.bots[o].x,e.p2.bots[o].y)]=!0;for(var a=0;a<G.H;a++)for(var n=0;n<G.W;n++){var s=toKey(n,a);t.hasOwnProperty(s)||r.push(s)}var l=fromKey(r[rnd(r.length)]);e.goal={age:0,x:l.x,y:l.y}}function drawGame(e){function t(e,t){G.CTX.fillRect(e*G.SCALE,t*G.SCALE,G.SCALE,G.SCALE)}function r(e,t){G.CTX.fillRect(e*G.SCALE+1,t*G.SCALE+1,G.SCALE-2,G.SCALE-2)}G.CTX.fillStyle=G.COLORS.AIR,G.CTX.fillRect(0,0,G.CW,G.CH),G.CTX.fillStyle=G.COLORS.WALL;for(var o=0;o<G.H;o++)for(var a=0;a<G.W;a++)e.walls[o][a]&&t(a,o);if(G.SHOW_LOS){var n=(2*G.LOS+1)*G.SCALE;G.CTX.fillStyle=G.COLORS.P1_LOS;for(var s=0;s<G.BOTS;s++)G.CTX.fillRect((e.p1.bots[s].x-G.LOS)*G.SCALE,(e.p1.bots[s].y-G.LOS)*G.SCALE,n,n);G.CTX.fillStyle=G.COLORS.P2_LOS;for(var s=0;s<G.BOTS;s++)G.CTX.fillRect((e.p2.bots[s].x-G.LOS)*G.SCALE,(e.p2.bots[s].y-G.LOS)*G.SCALE,n,n)}G.CTX.fillStyle=G.COLORS.P1;for(var s=0;s<G.BOTS;s++)t(e.p1.bots[s].x,e.p1.bots[s].y);G.CTX.fillStyle=G.COLORS.P2;for(var s=0;s<G.BOTS;s++)t(e.p2.bots[s].x,e.p2.bots[s].y);G.CTX.fillStyle=G.COLORS.WALL;for(var s=0;s<G.BOTS;s++)e.p1.bots[s].hasWall&&r(e.p1.bots[s].x,e.p1.bots[s].y),e.p2.bots[s].hasWall&&r(e.p2.bots[s].x,e.p2.bots[s].y);if(G.SHOW_NUMBERS){var l=-.1,i=2.75;G.CTX.fillStyle=G.COLORS.P1_TEXT;for(var s=0;s<G.BOTS;s++)G.CTX.fillText(s.toString(),(e.p1.bots[s].x+l)*G.SCALE,(e.p1.bots[s].y+i)*G.SCALE);G.CTX.fillStyle=G.COLORS.P2_TEXT;for(var s=0;s<G.BOTS;s++)G.CTX.fillText(s.toString(),(e.p2.bots[s].x+l)*G.SCALE,(e.p2.bots[s].y+i)*G.SCALE)}G.CTX.fillStyle=G.COLORS.GOAL,t(e.goal.x+1,e.goal.y),t(e.goal.x-1,e.goal.y),t(e.goal.x,e.goal.y+1),t(e.goal.x,e.goal.y-1),G.SCOREBOARD.P1SCORE.text(e.p1.score),G.SCOREBOARD.MOVE.text(e.move),G.SCOREBOARD.P2SCORE.text(e.p2.score)}function loadPlayers(e){var t=/<pre\b[^>]*><code\b[^>]*>([\s\S]*?)<\/code><\/pre>/,r=/<h1\b[^>]*>(.*?)<\/h1>/;G.PLAYERS=[];var o={id:-1,dq:!1,code:void 0,link:"javascript:;",title:"TEST ENTRY [-1]"};G.PLAYERS.push(o);var a=[];e.forEach(function(e){var o=decode(e.owner.display_name),n=t.exec(e.body),s=r.exec(e.body);if(null===n||n.length<=1||null===s||s.length<=1)return a.push(" "),void a.push(Q("<a>").text(o).attr("href",e.link));var l={};l.id=e.answer_id,l.dq=G.DQ_ANSWERS.indexOf(e.answer_id)>-1||G.DQ_USERS.indexOf(e.owner.user_id)>-1,l.code=decode(n[1]),l.link=e.link,l.title=s[1].substring(0,20)+" - "+o+" ["+l.id.toString()+"]",l.dq&&(l.title+="[DQ]"),G.PLAYERS.push(l)}),a.length>0&&(Q("#invalid").empty().append(a),Q("#invalidWrapper").show());for(var n=new Array(G.PLAYERS.length),s=new Array(G.PLAYERS.length),l=0;l<G.PLAYERS.length;l++)n[l]=Q("<option>").text(G.PLAYERS[l].title).val(l),s[l]=Q("<option>").text(G.PLAYERS[l].title).val(l);Q("#p1Select").empty().append(n).val(rnd(G.PLAYERS.length)),changeSelect(!0),Q("#p2Select").empty().append(s).val(rnd(G.PLAYERS.length)),changeSelect(!1)}function loadAnswers(e,t,r){function o(){Q.get("https://api.stackexchange.com/2.2/questions/"+t.toString()+"/answers?page="+(s++).toString()+"&pagesize=100&order=asc&sort=creation&site="+e+"&filter=!YOKGPOBC5Yad4mOOn8Z4WcAE6q",a)}function a(e){e.hasOwnProperty("error_id")?r(e.error_id.toString()):(n=n.concat(e.items),e.hasMore?o():r(n))}var n=[],s=1;o(s,a)}Q=jQuery,Q(reload);</script>
이 질문에는 자체 대화방이 있습니다. 며칠마다 리더 보드를 게시 할 것입니다.