Intro
Ini adalah kontes interaktif king-of-the-hill di mana controller sepenuhnya terkandung dalam Stack Snippet di bagian bawah pertanyaan. Pengontrol secara otomatis membaca jawaban dan bermain melalui permainan. Siapa pun dapat menjalankannya kapan saja di browser mereka.
Mekanik dari kontes ini sangat mirip dengan yang ada di Red vs Blue - Pixel Team Battlebots . Kecuali permainan yang dimainkan, sementara masih berbasis grid, sama sekali berbeda. Setiap pertandingan adalah 1 lawan 1 dan tidak ada tim. Setiap entri berjuang untuk dirinya sendiri dan hanya satu yang akan menjadi juara akhir.
Pengontrol menggunakan JavaScript, dan karena JavaScript adalah satu-satunya bahasa skrip sisi-klien yang didukung sebagian besar browser, semua jawaban harus ditulis dalam JavaScript juga .
Dalam spesifikasi ini, teks yang dicetak miring digunakan untuk menunjukkan istilah formal untuk mekanik game atau properti. Istilah-istilah ini digunakan sepanjang untuk membantu mempertahankan cara yang kohesif dan jelas merujuk ke berbagai bagian permainan.
Gameplay
Dasar-dasar
Setiap jawaban untuk pertanyaan ini mewakili pemain . Sebuah permainan adalah kompetisi antara dua pemain, P1 dan P2 . Setiap pemain mengontrol kawanan 8 bot , bernomor 0 hingga 7. Permainan berlangsung di grid , arena sel 128 × 64 yang 8 baris bawahnya dimulai sebagai dinding ('blok') dan baris lainnya dimulai sebagai udara . Sel di luar batas grid dianggap udara.
Koordinat x grid berkisar dari 0 di sebelah kiri hingga 127 di sebelah kanan, dan y berkisar dari 0 di atas hingga 63 di bawah.
Contoh grid awal:
Bot selalu tetap sejajar dengan sel kisi dan beberapa bot dapat menempati sel yang sama. Bot hanya bisa menempati sel udara. Bot P1 selalu dimulai pada garis 0-7 di paling kiri dari baris di atas dinding dan bot P2 selalu dimulai pada garis 7-0 di paling kanan.
The tetangga dari bot atau sel adalah 8 sel secara langsung orthogonal dan diagonal untuk itu.
Bidang pandang ( FOV ) dari sebuah bot adalah sel 13x13 yang berpusat pada sebuah bot. Bot sel atau musuh dikatakan berada di FOV pemain jika berada di FOV setidaknya satu bot pemain.
Gerakan & Tindakan
Selama pertandingan, setiap pemain bisa bergerak 1000 kali. P1 bergerak terlebih dahulu, lalu P2, lalu P1 dan seterusnya hingga 2000 total gerakan telah dibuat, pada titik mana permainan berakhir.
Selama bergerak, setiap pemain menerima informasi tentang keadaan permainan dan sel-sel kisi dan bot musuh dalam FOV mereka, dan menggunakannya untuk memutuskan tindakan yang akan diambil masing-masing bot mereka.
Tindakan default adalah tidak melakukan apa-apa , di mana bot tidak bergerak atau berinteraksi dengan kisi.
Tindakan lain adalah bergerak , ambil , dan tempat :
Bot dapat pindah ke salah satu sel tetangganya C jika:
- C tidak keluar batas,
- C adalah udara (yaitu bukan dinding),
- dan setidaknya salah satu tetangga C adalah tembok.
Jika berhasil, bot akan pindah ke C.
Bot dapat mengambil salah satu sel tetangganya C jika:
- C tidak keluar batas,
- C adalah dinding,
- dan bot belum membawa dinding.
Jika berhasil, C akan menjadi udara dan bot sekarang akan membawa dinding.
Bot dapat menempatkan ke salah satu sel tetangganya C jika:
- C tidak keluar batas,
- C adalah udara,
- tidak ada bot dari salah satu pemain yang menempati C,
- dan bot itu membawa dinding.
Jika berhasil, C akan menjadi dinding dan bot tidak akan lagi membawa dinding.
Tindakan yang gagal menghasilkan do do nothing.
Sel yang ditempati oleh setidaknya satu bot pembawa dinding memiliki kotak kecil berwarna dinding yang digambar di atasnya. Bot mulai tanpa dinding.
Ingatan
Selama bergerak, pemain dapat mengakses dan mengubah ingatan mereka , string yang awalnya kosong yang berlangsung sepanjang permainan dan dapat digunakan untuk menyimpan data strategis.
Tujuan
Sel dalam crosshair kuning adalah tujuannya , yang dimulai dalam posisi acak. Setiap pemain memiliki skor yang dimulai dari 0. Ketika bot pemain bergerak ke gawang, skor pemain itu meningkat sebesar 1 dan gawang secara acak diposisikan ulang sebelum belokan berikutnya. Pemain dengan skor tertinggi di akhir pertandingan menang. Ini seri jika nilainya sama.
Jika beberapa bot bergerak ke gawang selama bergerak, pemain hanya mendapatkan satu poin.
Jika gawang telah berada di tempat yang sama untuk 500 gerakan, itu secara acak diposisikan lagi. Setiap kali tujuan diposisikan secara acak, dijamin tidak akan ditempatkan pada sel yang ditempati oleh bot.
Apa yang Diprogram?
Tulis badan untuk fungsi ini:
function myMove(p1, id, eid, move, goal, grid, bots, ebots, getMem, setMem) {
//body goes here
}
Ini akan dipanggil sekali setiap kali pemain Anda bergerak dan perlu mengembalikan tindakan yang Anda inginkan dari masing-masing bot Anda selama gerakan itu.
Anda dapat menggunakan kode Baseline sebagai titik awal.
Parameter
p1
adalah bool itutrue
jika Anda P1 danfalse
jika Anda P2id
adalah bilangan bulat yang merupakan ID jawaban dari jawaban Anda.
- Anda dapat menemukan ID jawaban dengan mengeklik tautan 'bagikan' di bawahnya dan mencari nomornya
a/
di URL.- ID Entri Tes adalah -1.
eid
adalah bilangan bulat yang merupakan ID jawaban dari jawaban musuh Anda.move
adalah bilangan bulat dari 1 hingga 1000 yang menyatakan gerakan Anda saat ini.goal
adalah objek denganx
dany
properti. Ini adalah koordinat sasaran. Mereka diberikan bahkan jika tujuannya keluar dari FOV Anda.grid
adalah fungsi yang mengambil argumen x dan y, misgrid(x,y)
. Ia mengembalikan:
-1
untuk 'tidak dikenal' jika argumennya bukan dua bilangan bulat atau jikax,y
tidak ada dalam FOV Anda.0
untuk 'udara' jika dix,y
luar batas atau jika sel dix,y
udara.1
untuk 'dinding' jika sel dix,y
adalah dinding.
bots
adalah array dari 8 bot Anda. Unsur-unsurnya adalah obyek dengan sifatx
,y
danhasWall
:
x
dany
merupakan koordinat bot.hasWall
adalahtrue
jika bot membawa dinding danfalse
jika tidak.
bots
selalu dipesan secara normal, indeks Nth sesuai dengan nomor bot N.ebots
adalah array dari objek denganx
,y
, danhasWall
sifat sepertibots
. Hanya bot musuh di FOV Anda yang masukebots
. Jadi itu akan memiliki panjang 0 jika jika tidak ada bot musuh di FOV Anda. Ini dipesan secara acak.getMem
adalah fungsi tanpa argumen yang mengembalikan memori Anda.setMem
adalah fungsi yang mengambil satu argumen M. Jika M adalah string 256 karakter atau kurang, memori Anda diperbarui ke M, jika tidak, tidak ada yang terjadi.
console
Objek browser tersedia untuk Tes Masuk saja.
Nilai Pengembalian
Fungsi Anda perlu mengembalikan array yang persis 8 bilangan bulat, masing-masing berkisar dari 0 hingga 24. Nilai pada indeks N adalah tindakan yang akan diambil oleh nomor bot N.
Semua bot Anda tidak akan melakukan apa pun jika fungsi Anda:
- Melempar kesalahan apa pun. ( kesalahan )
- Perlu waktu lebih dari 20 milidetik untuk dieksekusi. ( batas waktu )
- Tidak mengembalikan array 8 bilangan bulat mulai dari 0 hingga 24. ( salah format )
Untuk kenyamanan, jumlah kesalahan, batas waktu, dan tindakan salah ditampilkan saat permainan berakhir.
Masing-masing angka dari 0 hingga 24 sesuai dengan tindakan bot tertentu:
- 0 untuk tidak melakukan apa pun.
- 1-8 untuk bergerak.
- 9-16 untuk diraih.
- 17-24 untuk penempatan.
Masing-masing dari 8 nilai untuk memindahkan, meraih, dan menempatkan berkorespondensi dengan salah satu sel tetangga bot, seperti yang ditunjukkan di sini:
Jadi, misalnya, 15
adalah tindakan untuk meraih sel di bawah bot.
Tindakan bot ditangani dalam urutan bot 0 ke bot 7. Misalnya, jika selama satu gerakan bot 0 disuruh menempatkan dinding di sel udara yang sama bot 1 disuruh pindah, sel udara akan menjadi dinding sebelum bot Tindakan 1 ditangani dan bot 1 tidak akan berhasil.
Tindakan yang gagal menjadi tidak berguna dan dikatakan gagal . Penghitung tindakan yang gagal juga ditampilkan saat permainan berakhir.
Aturan
Saya mungkin untuk sementara waktu atau secara permanen mendiskualifikasi pengguna atau jawaban yang tidak mengikuti aturan ini. Entri yang didiskualifikasi tidak memenuhi syarat untuk menang.
Saat mendeklarasikan variabel atau fungsi, Anda harus menggunakan
var
kata kunci.
egvar x = 10
atauvar sum = function(a, b){ return a + b }
Hal dinyatakan tanpavar
menjadi global dan dapat mengganggu pengontrol. Langkah-langkah telah diambil sehingga gangguan ini seharusnya tidak mungkin, tetapi lakukan ini untuk memastikan.Kode Anda seharusnya tidak berjalan lambat atau membuang waktu.
Tidak mungkin untuk menghentikan fungsi JavaScript saat eksekusi, sehingga kode setiap pemain dijalankan hingga selesai. Jika kode Anda membutuhkan waktu lama untuk dijalankan, semua orang yang menjalankan pemutar Anda akan memperhatikan dan merasa terganggu. Idealnya, entri akan selalu berjalan dengan baik dalam batas 20 ms.- Anda harus menggunakan kode yang kompatibel dengan ECMAScript 5 di versi terbaru Firefox karena di sinilah saya akan menjalankannya. Jangan gunakan fitur dari ECMAScript 6 karena belum didukung di banyak browser.
- Anda dapat menjawab hingga 3 kali, tetapi hanya jika masing-masing strategi Anda sangat berbeda. Anda dapat mengedit jawaban sebanyak yang diinginkan.
- Anda tidak boleh mencoba memiliki memori apa pun kecuali melalui penggunaan
getMem
dansetMem
. - Anda tidak boleh mencoba mengakses atau memodifikasi controller, kode pemain lain, atau sumber daya eksternal.
- Anda tidak boleh mencoba mengubah apa pun yang ada di dalam JavaScript.
- Jawaban tidak harus bersifat deterministik. Anda bisa menggunakan
Math.random
.
Format Jawaban
#EntryName
Notes, etc.
<!-- language: lang-js -->
//function body
//probably on multiple lines
More notes, etc.
Blok kode multiline pertama harus berisi fungsi tubuh Anda.
Nama entri dibatasi hingga 20 karakter.
Entri Anda akan muncul di controller dengan judul EntryName - Username [answer ID]
, ditambah [DQ]
jika itu didiskualifikasi.
Kemenangan
Ketika pertanyaan telah muncul setidaknya selama 3 minggu dan setelah jawaban telah selesai, saya akan memahkotai juara.
Saya akan menggunakan fitur autorun controller . Dalam satu ronde autorun, setiap pemain yang tidak didiskualifikasi memainkan dua game satu sama lain, satu sebagai P1, satu sebagai P2 (sebuah round-robin ganda).
Saya akan autorun sebanyak mungkin putaran dalam jangka waktu beberapa jam. Ini akan tergantung pada berapa banyak pengiriman yang ada dan seberapa intensif waktu mereka. Tapi yakinlah, saya berkomitmen untuk mendapatkan leaderboard akhir yang akurat. Pemain dengan kemenangan terbanyak adalah sang juara dan jawaban mereka akan diterima.
Saya akan menggunakan Firefox pada laptop dengan Windows 8.1 64-bit, ram 4 GB, dan prosesor quad-core 1.6GHz.
Hadiah
Saya akan menulis dan memposting tantangan PPCG yang didedikasikan khusus untuk sang juara. Entah bagaimana itu akan melibatkan nama pengguna atau avatar mereka atau sesuatu tentang mereka. Saya akan memutuskan secara pribadi apa tantangannya ketika kontes ini selesai. Saya akan menuliskannya dengan kemampuan terbaik saya dan mencoba memastikan itu menjadi Pertanyaan Jaringan Panas.
Pengendali
Jalankan cuplikan ini atau buka JSFiddle ini untuk menggunakan pengontrol. Dimulai dengan pemain acak yang dipilih. Saya hanya mengujinya secara menyeluruh di Firefox dan 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>
Pertanyaan ini memiliki ruang obrolan sendiri. Saya akan memposting papan peringkat di sana setiap beberapa hari.