Giới thiệu
Đây là một cuộc thi vua trên đồi tương tác trong đó bộ điều khiển được chứa đầy đủ trong một Đoạn trích ở cuối câu hỏi. Bộ điều khiển tự động đọc các câu trả lời và chơi qua các trò chơi. Bất cứ ai cũng có thể chạy nó bất cứ lúc nào ngay trong trình duyệt của họ.
Các cơ chế của cuộc thi này rất giống với cơ chế của Red vs Blue - Pixel Team Battlebots . Ngoại trừ trò chơi đang được chơi, trong khi vẫn dựa trên lưới, thì hoàn toàn khác. Mỗi trò chơi là 1 so với 1 và không có đội nào. Mỗi mục đang chiến đấu cho chính nó và chỉ có một người sẽ là nhà vô địch cuối cùng.
Bộ điều khiển sử dụng JavaScript và vì JavaScript là ngôn ngữ kịch bản phía máy khách duy nhất mà hầu hết các trình duyệt hỗ trợ, tất cả các câu trả lời cũng phải được viết bằng JavaScript .
Trong thông số kỹ thuật này, văn bản in nghiêng được sử dụng để chỉ thuật ngữ chính thức cho một cơ chế trò chơi hoặc tài sản. Các thuật ngữ này được sử dụng xuyên suốt để giúp duy trì một cách liên kết rõ ràng và liên quan đến các phần khác nhau của trò chơi.
Trò chơi
Khái niệm cơ bản
Mỗi câu trả lời cho câu hỏi này đại diện cho một người chơi . Một trò chơi là một cuộc cạnh tranh giữa hai cầu thủ, P1 và P2 . Mỗi người chơi điều khiển một đàn gồm 8 bot , được đánh số từ 0 đến 7. Các trò chơi diễn ra trong lưới , một đấu trường ô 128 × 64 có 8 hàng dưới cùng bắt đầu như những bức tường ('khối') và các hàng khác bắt đầu như không khí . Các tế bào bên ngoài giới hạn lưới được coi là không khí.
Tọa độ x của lưới nằm trong khoảng từ 0 ở bên trái đến 127 ở bên phải và y nằm trong khoảng từ 0 ở trên cùng đến 63 ở dưới cùng.
Lưới bắt đầu mẫu:
Các bot luôn luôn được liên kết với các ô lưới và nhiều bot có thể chiếm cùng một ô. Bots chỉ có thể chiếm các tế bào không khí. Các bot của P1 luôn bắt đầu trong một dòng 0-7 ở bên trái của hàng phía trên các bức tường và các bot của P2 luôn bắt đầu trong một dòng 7-0 ở bên phải.
Hàng xóm của bot hoặc ô là 8 ô trực tiếp trực giao và chéo với nó.
Trường nhìn ( FOV ) của bot là ô vuông 13 × 13 tập trung vào bot. Một tế bào hoặc bot kẻ thù được cho là nằm trong FOV của người chơi nếu nó nằm trong FOV của ít nhất một trong số các bot của người chơi.
Di chuyển & hành động
Trong một trò chơi, mỗi người chơi được di chuyển 1000 lần. P1 di chuyển đầu tiên, sau đó là P2, sau đó là P1 và cứ như vậy cho đến khi 2000 tổng số di chuyển đã được thực hiện, tại thời điểm trò chơi kết thúc.
Trong quá trình di chuyển, mỗi người chơi nhận được thông tin về trạng thái trò chơi và các ô lưới và bot kẻ thù trong FOV của họ và sử dụng nó để quyết định hành động cho mỗi bot của họ thực hiện.
Hành động mặc định là không làm gì cả , trong đó bot không di chuyển hoặc tương tác với lưới.
Các hành động khác là di chuyển , lấy và đặt :
Một bot có thể di chuyển đến một trong các ô lân cận C của nó nếu:
- C không nằm ngoài giới hạn,
- C là không khí (tức là không phải là một bức tường),
- và ít nhất một trong những hàng xóm của C là một bức tường.
Nếu thành công, bot sẽ chuyển sang C.
Một bot có thể lấy một trong các ô lân cận C của nó nếu:
- C không nằm ngoài giới hạn,
- C là một bức tường,
- và bot đã không mang một bức tường.
Nếu thành công, C sẽ trở thành không khí và bot sẽ mang theo một bức tường.
Một bot có thể đặt vào một trong các ô lân cận C nếu:
- C không nằm ngoài giới hạn,
- C là không khí,
- không có bot của một trong hai người chơi chiếm C,
- và bot đang mang một bức tường.
Nếu thành công, C sẽ trở thành một bức tường và bot sẽ không còn mang bức tường nữa.
Hành động không thành công dẫn đến không làm gì cả.
Một tế bào bị chiếm giữ bởi ít nhất một bot mang tường có một hình vuông nhỏ màu tường được vẽ trên nó. Bots bắt đầu mà không có bức tường.
Ký ức
Trong quá trình di chuyển, người chơi có thể truy cập và thay đổi bộ nhớ của họ , một chuỗi trống ban đầu kéo dài trong suốt trò chơi và có thể được sử dụng để lưu trữ dữ liệu chiến lược.
Mục tiêu
Các tế bào trong crosshair màu vàng là mục tiêu , bắt đầu ở một vị trí ngẫu nhiên. Mỗi người chơi có điểm bắt đầu từ 0. Khi bot của người chơi di chuyển đến mục tiêu, điểm của người chơi đó tăng thêm 1 và mục tiêu được định vị lại ngẫu nhiên trước lượt tiếp theo. Người chơi có số điểm cao nhất khi kết thúc trò chơi sẽ thắng. Đó là một sự ràng buộc nếu điểm số bằng nhau.
Nếu nhiều bot di chuyển đến mục tiêu trong khi di chuyển, người chơi vẫn chỉ được một điểm.
Nếu mục tiêu đã ở cùng một vị trí trong 500 lần di chuyển, nó sẽ được định vị lại một cách ngẫu nhiên. Bất cứ khi nào mục tiêu được định vị ngẫu nhiên, nó được đảm bảo không được đặt trên một ô bị chiếm bởi bot.
Chương trình gì
Viết một cơ thể cho chức năng này:
function myMove(p1, id, eid, move, goal, grid, bots, ebots, getMem, setMem) {
//body goes here
}
Nó sẽ được gọi một lần mỗi khi người chơi của bạn di chuyển và cần trả lại các hành động bạn muốn mỗi bot của bạn thực hiện trong quá trình di chuyển đó.
Bạn có thể sử dụng mã Đường cơ sở làm điểm bắt đầu.
Thông số
p1
là một bool đó làtrue
nếu bạn là P1 vàfalse
nếu bạn là P2id
là một số nguyên là ID câu trả lời của câu trả lời của bạn.
- Bạn có thể tìm ID của câu trả lời bằng cách nhấp vào liên kết 'chia sẻ' bên dưới và tìm số ngay sau
a/
URL.- ID của Bài kiểm tra là -1.
eid
là một số nguyên là ID câu trả lời cho câu trả lời của kẻ thù của bạn.move
là một số nguyên từ 1 đến 1000 cho biết bạn đang di chuyển cái gì.goal
là một đối tượng vớix
vày
thuộc tính. Đây là tọa độ của mục tiêu. Chúng được đưa ra ngay cả khi mục tiêu nằm ngoài FOV của bạn.grid
là một hàm lấy các đối số x và y, vdgrid(x,y)
. Nó trở lại:
-1
cho 'không xác định' nếu các đối số không có hai số nguyên hoặc nếux,y
không có trong FOV của bạn.0
cho 'không khí' nếux,y
nằm ngoài giới hạn hoặc nếu tế bào ởx,y
là không khí.1
cho 'tường' nếu ô tạix,y
là một bức tường.
bots
là một mảng gồm 8 bot của bạn. Phần tử của nó là những đối tượng có đặc tínhx
,y
vàhasWall
:
x
vày
là tọa độ của bot.hasWall
làtrue
nếu bot đang mang một bức tường vàfalse
nếu không.
bots
luôn được đặt hàng bình thường, chỉ số N tương ứng với số bot N.ebots
là một mảng của các đối tượng vớix
,y
vàhasWall
tính chất giống nhưbots
. Chỉ có các bot kẻ thù trong FOV của bạnebots
. Vì vậy, nó sẽ có độ dài 0 nếu không có bot kẻ thù trong FOV của bạn. Nó được đặt hàng ngẫu nhiên.getMem
là một hàm không có đối số trả về bộ nhớ của bạn.setMem
là một hàm có một đối số M. Nếu M là một chuỗi gồm 256 ký tự trở xuống, bộ nhớ của bạn được cập nhật thành M, nếu không thì không có gì xảy ra.
console
Đối tượng trình duyệt có sẵn cho Test Entry một mình.
Giá trị trả lại
Hàm của bạn cần trả về một mảng có đúng 8 số nguyên, mỗi số từ 0 đến 24. Giá trị tại chỉ số N là hành động mà số bot N sẽ thực hiện.
Tất cả các bot của bạn sẽ không làm gì nếu chức năng của bạn:
- Ném một lỗi của bất kỳ loại nào. ( lỗi )
- Mất hơn 20 mili giây để thực thi. ( hết thời gian )
- Không trả về một mảng gồm 8 số nguyên từ 0 đến 24. ( không đúng định dạng )
Để thuận tiện, số lỗi, thời gian chờ và hành động không đúng định dạng được hiển thị khi trò chơi kết thúc.
Mỗi số từ 0 đến 24 tương ứng với một hành động bot cụ thể:
- 0 là không làm gì cả.
- 1-8 là để di chuyển.
- 9-16 là để lấy.
- 17-24 là để đặt.
Mỗi trong số 8 giá trị để di chuyển, lấy và đặt tương ứng với một trong các ô lân cận của bot, như được hiển thị ở đây:
Vì vậy, ví dụ, 15
là hành động lấy tế bào bên dưới bot.
Các hành động của bot được xử lý theo thứ tự bot 0 đến bot 7. Ví dụ: nếu trong một lần di chuyển, bot 0 được yêu cầu đặt một bức tường trong cùng một tế bào không khí bot 1 được yêu cầu di chuyển đến, tế bào không khí sẽ trở thành một bức tường trước khi bot Hành động của 1 được xử lý và bot 1 sẽ không thành công.
Những hành động không thành công trở thành những điều không hay và được cho là đã thất bại . Bộ đếm hành động thất bại cũng được hiển thị khi trò chơi kết thúc.
Quy tắc
Tôi có thể tạm thời hoặc vĩnh viễn loại bỏ người dùng hoặc câu trả lời không tuân theo các quy tắc này. Các mục bị loại không đủ điều kiện để giành chiến thắng.
Khi khai báo các biến hoặc hàm, bạn phải sử dụng
var
từ khóa.
ví dụvar x = 10
hoặcvar sum = function(a, b){ return a + b }
Những điều được tuyên bố mà khôngvar
trở thành toàn cầu và có thể can thiệp vào bộ điều khiển. Các bước đã được thực hiện để can thiệp này là không thể, nhưng làm điều này để đảm bảo.Mã của bạn không nên chạy chậm hoặc lãng phí thời gian.
Không thể dừng các chức năng JavaScript giữa thực thi, do đó mã của mỗi người chơi được chạy đến khi hoàn thành. Nếu mã của bạn mất nhiều thời gian để chạy, mọi người đang chạy trình phát của bạn sẽ nhận thấy và khó chịu. Lý tưởng nhất, các mục sẽ luôn chạy tốt trong giới hạn 20ms.- Bạn phải sử dụng mã tương thích với ECMAScript 5 trong phiên bản Firefox mới nhất vì đây là nơi tôi sẽ chạy nó. Không sử dụng các tính năng từ ECMAScript 6 vì nó chưa được hỗ trợ trong nhiều trình duyệt.
- Bạn có thể trả lời tối đa 3 lần, nhưng chỉ khi mỗi chiến lược của bạn khác nhau đáng kể. Bạn có thể chỉnh sửa câu trả lời nhiều như mong muốn.
- Bạn không thể có bất kỳ loại bộ nhớ nào ngoại trừ việc sử dụng
getMem
vàsetMem
. - Bạn không được phép truy cập hoặc sửa đổi bộ điều khiển, mã của người chơi khác hoặc tài nguyên bên ngoài.
- Bạn không thể cố gắng sửa đổi bất cứ điều gì được tích hợp vào JavaScript.
- Câu trả lời không cần phải xác định. Bạn có thể sử dụng
Math.random
.
Định dạng câu trả lời
#EntryName
Notes, etc.
<!-- language: lang-js -->
//function body
//probably on multiple lines
More notes, etc.
Khối mã đa dòng đầu tiên phải chứa thân hàm của bạn.
Tên mục nhập được giới hạn trong 20 ký tự.
Mục nhập của bạn sẽ hiển thị trong bộ điều khiển với tiêu đề EntryName - Username [answer ID]
, cộng với [DQ]
nếu nó không đủ tiêu chuẩn.
Chiến thắng
Khi câu hỏi đã được đưa ra ít nhất 3 tuần và một khi câu trả lời đã lắng xuống, tôi sẽ trao vương miện cho nhà vô địch.
Tôi sẽ sử dụng tính năng tự động chạy của bộ điều khiển . Trong một vòng thi autorun, mọi người chơi không đủ tiêu chuẩn sẽ chơi hai trò chơi với nhau, một là P1, một là P2 (một vòng hai lần).
Tôi sẽ tự động chạy càng nhiều vòng càng tốt trong khoảng vài giờ. Điều này sẽ phụ thuộc vào số lượng bài nộp và mức độ chuyên sâu của chúng. Nhưng hãy yên tâm, tôi cam kết sẽ có được bảng xếp hạng chính xác cuối cùng. Người chơi có nhiều chiến thắng nhất là nhà vô địch và câu trả lời của họ sẽ được chấp nhận.
Tôi sẽ sử dụng Firefox trên máy tính xách tay có Windows 8.1 64 bit, ram 4 GB và bộ xử lý lõi tứ 1.6 GHz.
Giải thưởng
Tôi sẽ viết và đăng một thử thách PPCG dành riêng cho nhà vô địch. Nó bằng cách nào đó sẽ liên quan đến tên người dùng hoặc hình đại diện của họ hoặc một cái gì đó về họ. Tôi sẽ quyết định riêng về thử thách sẽ diễn ra khi cuộc thi này kết thúc. Tôi sẽ viết nó hết khả năng của mình và cố gắng đảm bảo nó trở thành Câu hỏi về Mạng nóng.
Bộ điều khiển
Chạy đoạn mã này hoặc đi tới JSFiddle này để sử dụng bộ điều khiển. Nó bắt đầu với những người chơi ngẫu nhiên được chọn. Tôi chỉ kiểm tra kỹ lưỡng nó trong Firefox và 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>
Câu hỏi này có phòng chat riêng. Tôi sẽ đăng bảng xếp hạng ở đó vài ngày một lần.