Khối xây dựng Bot Bot!


42

Cuộc thi đã kết thúc!

Giới thiệu

Đây là một cuộc thi tương tác đó 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ủ, P1P2 . 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đặ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ố

  • p1là một bool đó là truenếu bạn là P1 và falsenếu bạn là P2
  • id 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ì.
  • goallà một đối tượng với xythuộ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.
  • gridlà một hàm lấy các đối số x và y, vd grid(x,y). Nó trở lại:
    • -1cho 'không xác định' nếu các đối số không có hai số nguyên hoặc nếu x,ykhông có trong FOV của bạn.
    • 0cho 'không khí' nếu x,ynằm ngoài giới hạn hoặc nếu tế bào ở x,ylà không khí.
    • 1cho 'tường' nếu ô tại x,ylà một bức tường.
  • botslà 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ính x, yhasWall:

    • xylà tọa độ của bot.
    • hasWalltruenếu bot đang mang một bức tường và falsenế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.

  • ebotslà một mảng của các đối tượng với x, yhasWalltính chất giống như bots. Chỉ có các bot kẻ thù trong FOV của bạn ebots. 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ụ, 15là 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 vartừ khóa.
    ví dụ var x = 10hoặc var sum = function(a, b){ return a + b }
    Những điều được tuyên bố mà không vartrở 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 getMemsetMem.
  • 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>&nbsp;<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&nbsp;=&nbsp;<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>&nbsp;| 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>&nbsp;| 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>&nbsp; <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.



3
Nhờ các nút để điều chỉnh kích thước của lưới, tôi có thể chạy Stack Snippet trên điện thoại của mình :)
trichoplax

3
Rất nhiều tình yêu (codegolf.stackexchange.com/questions/50768/) nhưng điều đó không dễ dàng
edc65

3
Đây là mê hoặc để xem.
DLosc

1
@Stephen Có. Quy tắc 4: "Bạn có thể chỉnh sửa câu trả lời nhiều như mong muốn."
Sở thích của Calvin

Câu trả lời:


13

Hiệp sỹ đen

Tên của bot xuất phát từ một kế hoạch ban đầu để nó có thể di chuyển như một hiệp sĩ cờ vua: trên hai, lên một, v.v., sẽ nhanh hơn trong một số trường hợp.

var moves = new Array(8),
    mem = getMem(), newMem = '';

var decodeMem = function(){
  //mmtxy
  for(var ind = 0; ind < 8; ind++){
    var sub = mem.substr(ind * 5, 5)
    bots[ind].lastMove = parseInt(sub[0], 36);
    bots[ind].last2Move = parseInt(sub[1], 36);
    bots[ind].timesStill = sub.charCodeAt(2) - 48;
    bots[ind].lastX = sub.charCodeAt(3) - 187;
    bots[ind].lastY = sub.charCodeAt(4) - 187;
  }
}
decodeMem();

var distanceTo = function(fromX, fromY, toX, toY){
  // Chebyshev distance
  return Math.max(Math.abs(fromX - toX),
                  Math.abs(fromY - toY));
}

var direction = function(from, to){ // Math.sign()
  var diff = to - from;
  return diff > 0 ? 1 : (diff < 0 ? -1 : 0);
}

var dirs = [
  [1, 2, 3],
  [4, 0, 5],
  [6, 7, 8]
];

var moveTo = function(from, to){
  var prioritiesWall = [
    [0],
    [1, 2, 4, 17, 18, 20, 19, 22, 23, 21, 3, 6, 5, 7, 24, 8],
    [2, 3, 1, 17, 19, 18, 23, 22, 24, 4, 5, 20, 21, 6, 8, 7],
    [3, 2, 5, 19, 18, 21, 17, 24, 23, 20, 1, 8, 4, 7, 22, 6],
    [4, 1, 6, 22, 17, 20, 21, 24, 19, 2, 7, 18, 23, 3, 8, 5],
    [5, 3, 8, 24, 19, 21, 20, 22, 17, 2, 7, 18, 23, 1, 6, 4],
    [6, 4, 7, 22, 20, 23, 17, 24, 18, 21, 1, 8, 2, 5, 19, 3],
    [7, 8, 6, 22, 24, 23, 18, 17, 19, 4, 5, 20, 21, 1, 3, 2],
    [8, 5, 7, 24, 21, 23, 19, 22, 18, 20, 3, 6, 2, 4, 17, 1]
  ];
  var prioritiesNoWall = [
    [9, 10, 11, 12, 13, 14, 15, 16, 0],
    [1, 2, 4, 9, 16, 10, 12, 3, 6, 11, 14, 5, 7, 13, 15, 8],
    [2, 3, 1, 10, 15, 14, 16, 4, 5, 12, 13, 9, 11, 6, 8, 7],
    [3, 2, 5, 11, 14, 10, 13, 1, 8, 9, 16, 4, 7, 12, 15, 6],
    [4, 1, 6, 12, 13, 16, 11, 2, 7, 10, 15, 9, 14, 3, 8, 5],
    [5, 3, 8, 13, 12, 14, 9, 2, 7, 10, 15, 11, 16, 1, 6, 4],
    [6, 4, 7, 14, 11, 12, 15, 1, 8, 9, 16, 2, 5, 10, 13, 3],
    [7, 8, 6, 15, 10, 9, 11, 4, 5, 12, 13, 14, 16, 1, 3, 2],
    [8, 5, 7, 16, 9, 13, 15, 3, 6, 11, 14, 2, 4, 10, 12, 1]
  ];

  var dir = dirs[direction(from.y, to.y) + 1][direction(from.x, to.x) + 1],
      method = from.hasWall ? prioritiesWall[dir] : prioritiesNoWall[dir];

  if(distanceTo(from.x, from.y, goal.x, goal.y) === 1){
    method.splice(1,2);
  }

  for(var i=0; i<method.length; i++){
    var attempt = method[i];
    if(checkMove(from, attempt)) return attempt;
  }
  return 0;
}

var numWalls = function(x, y, indexes){
  var allCoords = [
    [x - 1, y - 1],
    [x,     y - 1],
    [x + 1, y - 1],
    [x - 1, y    ],
    [x + 1, y    ],
    [x - 1, y + 1],
    [x,     y + 1],
    [x + 1, y + 1],
  ];
  var allTypes = allCoords.map(function(e){
    return grid(e[0], e[1]); // air = 0, wall = 1
  });
  var justWalls = allTypes.filter(function(e){
    return e === 1;
  }).length;

  return indexes ? allTypes : justWalls;
}

var checkMove = function(coords, moveCode){
  var x = coords.x, y = coords.y,
      baseX = [0, -1, 0, 1, -1, 1, -1, 0, 1],
      baseY = [0, -1, -1, -1, 0, 0, 1, 1, 1],
      targetX = x + baseX[(moveCode - 1) % 8 + 1],
      targetY = y + baseY[(moveCode - 1) % 8 + 1];

  if((targetX > 127 || targetX < 0 || targetY > 63 || targetY < 0) || // Don't bother if it's out of bounds
     (coords.timesStill > 2 && x == coords.lastX && y == coords.lastY && (moveCode == coords.lastMove || moveCode == coords.last2Move)))
    // Or is doing the same moves and not moving
    return false;

  var targetGrid = grid(targetX, targetY), enemyNear = false, couldStrandEnemy = false,
      eWallDirMove, hasNeighbor = numWalls(targetX, targetY) > 0;

  ebots.forEach(function(ebot){
    // Don't place a wall where an enemy can take it
    if(distanceTo(targetX, targetY, ebot.x, ebot.y) === 1 && !ebot.hasWall && (y != ebot.y || x != ebot.x))
      enemyNear = true;

    // Don't move if you can strand an enemy
    var eWallDir = numWalls(ebot.x, ebot.y, true).indexOf(1) + 1,
        wallX = ebot.x + baseX[eWallDir], wallY = ebot.y + baseY[eWallDir];

    if(!coords.hasWall && numWalls(ebot.x, ebot.y) === 1 &&
       distanceTo(x, y, wallX, wallY) === 1){
      eWallDirMove = dirs[direction(y, wallY) + 1][direction(x, wallX) + 1] + 8;
      couldStrandEnemy = true;
    }
  })

  if(targetX == goal.x && targetY == goal.y && targetGrid === 0){
    targetGrid = 2 // Don't place a wall in the goal
  } else {
    ebots.concat(bots).forEach(function(bot){
      // Ensure target cell doesn't have a bot in it
      if(bot.x == targetX && bot.y == targetY) targetGrid = 2;
    });
  }

  return ((moveCode < 9 && targetGrid !== 1 && hasNeighbor && !couldStrandEnemy) || // Move
          (moveCode > 8 && moveCode < 17 && targetGrid === 1 && !coords.hasWall && (!couldStrandEnemy || (couldStrandEnemy && eWallDirMove == moveCode))) || // Grab
          (moveCode > 16 && targetGrid === 0 && coords.hasWall && !enemyNear)) // Place
}

var goalClosest = {dist: Infinity}, rescuers = {};
bots.forEach(function(bot, index){

  // Check if bot is stranded
  bot.stranded = false;
  if(numWalls(bot.x, bot.y) / 8 == bot.hasWall){
    bot.stranded = true;
    rescuers[index] = -1;
  }
});

bots.forEach(function(bot, index){
  if(!bot.stranded){
    // Find which bot is closest to the goal
    var goalDist = distanceTo(bot.x, bot.y, goal.x, goal.y);

    if(goalDist < goalClosest.dist){
      goalClosest.dist = goalDist;
      goalClosest.index = index;
    }
  }
});

bots.forEach(function(bot, index){
  var destination = {
    x: 14 + (index % 4) * 32 + 3 * (index > 3),
    y: index > 3 ? 55 : 27
  }
  if(index == goalClosest.index){
    destination = goal;
  }

  moves[index] = moveTo(bot, destination);

  if(moves[index] == bot.lastMove || moves[index] == bot.last2Move) bot.timesStill++;

  newMem += moves[index].toString(36) +
    bot.lastMove.toString(36) +
    String.fromCharCode(bot.timesStill + 48) +
    String.fromCharCode(bot.x + 187) +
    String.fromCharCode(bot.y + 187);
});

setMem(newMem);

return moves;

Giải trình

Xác định di chuyển nào để thực hiện cho mỗi bot có thể được chia thành hai nhiệm vụ chính: tìm ra nơi để đi và làm thế nào để đến đó.

Đi đâu

Nhiệm vụ cơ bản của việc tìm ra nơi để đi thật dễ dàng: đi tới mục tiêu nếu bạn ở gần nhất, hoặc nếu không thì cố gắng đặt mình cách xa đồng đội. Đầu tiên, nó đi qua từng bot và xác định xem nó có bị mắc kẹt không (tức là nó không có khối bao quanh và không giữ một bức tường, hoặc nó được bao quanh bởi các bức tường và giữ một bức tường). Sau đó, nó lặp lại các bot một lần nữa để tìm bot không bị mắc kẹt gần nhất với mục tiêu. Tất cả các bot khác thực hiện theo cách của chúng được sắp xếp ra, với hàng dưới cùng trên bề mặt của các khối ( y=55) và hàng trên cùng tại y=27. Một khi nó biết nơi để đi, nó đưa nó ra moveTochức năng.

Làm sao để tới đó

Quyết định làm thế nào để đến đích là khó khăn hơn nhiều vì các bot phải luôn liền kề với một bức tường để di chuyển. Đầu tiên, nó chỉ ra mã hướng (1 Hàng8) của điểm đến so với vị trí hiện tại của nó. Ví dụ: nếu một bot ở góc dưới bên trái và nó muốn đi lên trên cùng bên phải, nó sẽ sử dụng mã hướng 3. Đối với mỗi hướng, tôi đã mã hóa một danh sách các bước di chuyển, với đầu tiên là lý tưởng, trên cùng di chuyển chiến binh, và cuối cùng là phương sách cuối cùng. Điều này được phân tách bằng việc bot có tường hay không, bởi vì bạn không thể sử dụng di chuyển địa điểm mà không có tường hoặc sử dụng di chuyển lấy trong khi đã có tường.

Tất nhiên, sử dụng di chuyển lý tưởng không phải lúc nào cũng hoạt động và nó sẽ dẫn đến rất nhiều hành động thất bại. Đây là nơi checkMoveđến. Chức năng này kiểm tra di chuyển tiềm năng chống lại mọi yêu cầu, để ngăn bot di chuyển ra khỏi giới hạn hoặc vào tường, ví dụ. Nếu một bot kẻ thù gần đó có thể bị mắc kẹt (nó chỉ có một bức tường liền kề có thể bị bot chiếm lấy), đó sẽ trở thành ưu tiên của nó, vì vậy chức năng sẽ quay trở lại falsecho một động thái hợp pháp khác để nó có thể bỏ qua các bước di chuyển và lấy ra kẻ thù. Chức năng ngăn chặn một số di chuyển ngu ngốc khác như đặt một bức tường trong mục tiêu hoặc bot khác.

Chuỗi bộ nhớ

Đôi khi bot sẽ không thực sự bị mắc kẹt nhưng sẽ tiếp tục thử cùng một động tác và không kết thúc di chuyển (thường là nhặt một bức tường và đặt nó xuống, nhặt nó lên và đặt nó xuống, v.v.). Để ngăn chặn điều này, nó sử dụng chuỗi bộ nhớ để ghi nhớ hai lần di chuyển cuối cùng của nó, vị trí x và y cuối cùng của nó và số lần nó vẫn còn. Mỗi mốc được mã hóa thành một ký tự đơn để dễ dàng phân tách. (Chuỗi phải có 256 ký tự , không phải byte, do đó, sử dụng các ký tự Unicode đa chuỗi không phải là vấn đề, vì đó là với các thử thách chơi gôn thông thường.)

Ví dụ, giả sử một bot đã lấy bức tường ở bên trái (mã 12) của nó trong lượt này, thay thế nó sang bên trái (mã 20) trong lượt trước đó và đã ở tọa độ ( 107, 3) cho các 16lượt trước . Chuỗi bộ nhớ cho trường hợp này sẽ được mã hóa như sau:

  • ck: Hai mã hành động mới nhất được chuyển đổi thành cơ sở36 để biến các số có hai chữ số thành một chữ cái.
  • @: Số lần nó vẫn được biểu thị dưới dạng ký tự ASCII với mã đó + 48 để bỏ qua các ký tự không thể in được và do đó chín lần đầu tiên vẫn hiển thị số thực ( String.fromCharCode(0 + 48)0).
  • Ħ¾: Các tọa độ x và y cũng được biểu diễn dưới dạng ký tự có giá trị đó, lần này được bù bằng giá trị hơi tùy ý là 187 để tránh các ký tự có vấn đề.

Một chuỗi bộ nhớ điển hình trong trò chơi có thể là 53äÇØb7¼ðÌ00ßĉÖ7m±ĪÚ00ĝÌò00Ĝìò00ĖČò00ĈĬò, với một nhóm năm ký tự cho mỗi tám bot.


1
Nếu một người chơi đang ở trong một trò chơi với chính nó, thì Người chơi 1 hoặc Người chơi 2 có thể giành chiến thắng, không có sự thiên vị rõ ràng. Câu trả lời này là ngoại lệ, vì Người chơi 1 gần như luôn thắng với tỷ lệ chênh lệch lớn. Tôi không thể thấy một lý do tại sao - nó hấp dẫn.
trichoplax

@trichoplax Tôi tưởng tượng đó là vì P1 di chuyển trước P2, vì vậy P1 sẽ mắc P2 trước khi nó có thể làm điều tương tự.
NinjaBearMonkey

4
Thử thách đã qua và kết quả đã có ! Sau 30 vòng, Black Knight đã có 204 trận thắng và mục tiếp theo hay nhất, Seekers , chỉ có 147. Xin chúc mừng NinjaBearMonkey ! Các thách thức cụ thể bạn đang trên đường.
Sở thích của Calvin

Tuyệt đối ninja! Cảm ơn bạn
edc65

12

Tiền đồn

8 con bot mỗi con lấy một hình vuông 32 x 32 và chạy đến trung tâm của nó (tôi bù lại các trung tâm một chút nếu không cuối cùng chúng sẽ ghép đôi và di chuyển thẳng đứng với một khối tường giữa chúng, vì vậy một trong số chúng bị mắc kẹt).

Mỗi bot sẽ ở giữa trung tâm của nó trừ khi mục tiêu nằm trong 32 ô của trung tâm tương ứng, trong trường hợp đó, nó sẽ chạy đến mục tiêu và sau đó quay lại trung tâm của nó.

Điều này vẫn sử dụng phương pháp Đường cơ sở để đạt được mục tiêu (mục tiêu hoặc trung tâm) để không di chuyển theo đường chéo. Chỉ là một điểm khởi đầu ...

var encodeAction = function(type, dx, dy) {
    var d
    if (dx === -1 && dy === -1) d = 1
    else if (dx === 0 && dy === -1) d = 2
    else if (dx === 1 && dy === -1) d = 3
    else if (dx === -1 && dy === 0) d = 4
    else if (dx === 1 && dy === 0) d = 5
    else if (dx === -1 && dy === 1) d = 6
    else if (dx === 0 && dy === 1) d = 7
    else if (dx === 1 && dy === 1) d = 8
    else return 0
    return 8 * type + d
}

var getNeighborCell = function(x, y, wallState) {
    if (x > 0 && y > 0 && grid(x - 1, y - 1) === wallState) return { x: x - 1, y: y - 1 }
    if (y > 0 && grid(x, y - 1) === wallState) return { x: x, y: y - 1 }
    if (x < 127 && y > 0 && grid(x + 1, y - 1) === wallState) return { x: x + 1, y: y - 1 }
    if (x > 0 && grid(x - 1, y) === wallState) return { x: x - 1, y: y }
    if (x < 127 && grid(x + 1, y) === wallState) return { x: x + 1, y: y }
    if (x > 0 && y < 63 && grid(x - 1, y + 1) === wallState) return { x: x - 1, y: y + 1 }
    if (y < 63 && grid(x, y + 1) === wallState) return { x: x, y: y + 1 }
    if (x < 127 && y < 63 && grid(x + 1, y + 1) === wallState) return { x: x + 1, y: y + 1 }
    return null
}

var moveBot = function(n) {
    var assignedX = (n % 4) * 32 + 14 + Math.floor(n/4) * 4
    var assignedY = (Math.floor(n / 4)) * 32 + 16
    if (Math.abs(goal.x - assignedX) < 33 && Math.abs(goal.y - assignedY) < 33) {
        assignedX = goal.x
        assignedY = goal.y
    }
    var b = bots[n], moveX = b.x !== assignedX, x = b.x, y = b.y, type
    if (moveX) {
        x += b.x < assignedX ? 1 : -1
    } else {
        y += b.y < assignedY ? 1 : -1
    }
    if (grid(x, y) === 1) {
        if (b.hasWall) {
            type = 2 //place
            var c = getNeighborCell(b.x, b.y, 0)
            if (!c) { //stuck holding wall with walls all around
                return 0
            }
            x = c.x
            y = c.y
        } else {
            type = 1 //grab
        }
    } else if (grid(x, y) === 0) {
        if (getNeighborCell(x, y, 1)) {
            type = 0 //move
        } else {
            if (b.hasWall) {
                type = 2 //place
                if (moveX) {
                    y += y > 0 ? -1 : 1
                } else {
                    x += x > 0 ? -1 : 1
                }
            } else {
                type = 1 //grab
                var c = getNeighborCell(b.x, b.y, 1)
                if (!c) { //stuck without wall in midair
                    return 0
                }
                x = c.x
                y = c.y
            }
        }
    } else {
        return 0 //should never get here
    }
    return encodeAction(type, x - b.x, y - b.y)
}

var actions = []
for (var i = 0; i < 8; i++) {
    actions[i] = moveBot(i)
}

return actions

1
Tôi biết đây mới chỉ là khởi đầu, nhưng có một điều tôi nhận thấy khi xem trận chiến (không đồng đều) với đường cơ sở: Nếu mục tiêu nằm trong tầm tay của nhiều trung tâm, tất cả đều chạy về phía mục tiêu. Có thể tốt hơn khi chỉ chọn người gần nhất và giữ những người khác ở vị trí "lý tưởng" của họ? Thú vị để xem, btw.
Reto Koradi

Cảm ơn! Vâng, đó chắc chắn sẽ là một cải tiến. Có một danh sách dài những người khác cũng nghĩ về, và một loạt các chiến lược khác nhau để sử dụng. Tôi mong muốn được xem những chiến lược nào mà người khác chọn và cách họ tương tác ...
trichoplax

9

Đường cơ sở

Đây là bộ điều khiển bot bot hoạt động đơn giản nhất mà tôi có thể nghĩ ra. Nó sẽ là câu trả lời không đủ tiêu chuẩn duy nhất của tôi và sẽ dùng làm cơ sở để đánh giá các câu trả lời khác bằng cách. Đó là về mặt kỹ thuật để chạy để giành chiến thắng trong cuộc thi, nhưng đánh bại nó không phải là khó khăn.

Bất kỳ mã nào ở đây có thể được sao chép và sử dụng trong câu trả lời khác, không yêu cầu ghi công.

var encodeAction = function(type, dx, dy) {
    var d
    if (dx === -1 && dy === -1) d = 1
    else if (dx === 0 && dy === -1) d = 2
    else if (dx === 1 && dy === -1) d = 3
    else if (dx === -1 && dy === 0) d = 4
    else if (dx === 1 && dy === 0) d = 5
    else if (dx === -1 && dy === 1) d = 6
    else if (dx === 0 && dy === 1) d = 7
    else if (dx === 1 && dy === 1) d = 8
    else return 0
    return 8 * type + d
}

var getNeighborCell = function(x, y, wallState) {
    if (x > 0 && y > 0 && grid(x - 1, y - 1) === wallState) return { x: x - 1, y: y - 1 }
    if (y > 0 && grid(x, y - 1) === wallState) return { x: x, y: y - 1 }
    if (x < 127 && y > 0 && grid(x + 1, y - 1) === wallState) return { x: x + 1, y: y - 1 }
    if (x > 0 && grid(x - 1, y) === wallState) return { x: x - 1, y: y }
    if (x < 127 && grid(x + 1, y) === wallState) return { x: x + 1, y: y }
    if (x > 0 && y < 63 && grid(x - 1, y + 1) === wallState) return { x: x - 1, y: y + 1 }
    if (y < 63 && grid(x, y + 1) === wallState) return { x: x, y: y + 1 }
    if (x < 127 && y < 63 && grid(x + 1, y + 1) === wallState) return { x: x + 1, y: y + 1 }
    return null
}

var moveBot = function(n) {
    var b = bots[n], moveX = b.x !== goal.x, x = b.x, y = b.y, type
    if (moveX) {
        x += b.x < goal.x ? 1 : -1
    } else {
        y += b.y < goal.y ? 1 : -1
    }
    if (grid(x, y) === 1) {
        if (b.hasWall) {
            type = 2 //place
            var c = getNeighborCell(b.x, b.y, 0)
            if (!c) { //stuck holding wall with walls all around
                return 0
            }
            x = c.x
            y = c.y
        } else {
            type = 1 //grab
        }
    } else if (grid(x, y) === 0) {
        if (getNeighborCell(x, y, 1)) {
            type = 0 //move
        } else {
            if (b.hasWall) {
                type = 2 //place
                if (moveX) {
                    y += y > 0 ? -1 : 1
                } else {
                    x += x > 0 ? -1 : 1
                }
            } else {
                type = 1 //grab
                var c = getNeighborCell(b.x, b.y, 1)
                if (!c) { //stuck without wall in midair
                    return 0
                }
                x = c.x
                y = c.y
            }
        }
    } else {
        return 0 //should never get here
    }
    return encodeAction(type, x - b.x, y - b.y)
}

var actions = []
for (var i = 0; i < 8; i++) {
    actions[i] = moveBot(i)
}

return actions

Mỗi trong số 8 bot độc lập theo cùng một phương pháp cơ bản. Họ có xu hướng co cụm lại vì điều này, trừ khi họ bị ngăn cách bởi một cái gì đó bên ngoài. Các bot không bao giờ quan tâm đến nơi đồng đội hoặc kẻ thù, họ chỉ cố gắng tiến về phía mục tiêu. Họ chỉ di chuyển trực giao, đầu tiên khớp x của họ với mục tiêu x, sau đó là y. Không bao giờ di chuyển theo đường chéo có nghĩa là họ lãng phí rất nhiều thời gian trong du lịch.

Thuật toán chuyển động của mỗi bot như sau:

If my X is not equal to the goal's X
    P = position to my left or right that is closer to the goal  
    Make a note that I'm trying to move horizontal  
Else  
    P = position above or below me that is closer to the goal  
    Make a note that I'm trying to move vertical  

If P is a wall  
    If I'm holding a wall  
        Place my wall in any neighboring air cell  
    Else  
        Grab the wall at P  
Else if P is air  
    If P has a wall neighboring it (i.e. if I can move to P)  
        Move to P  
    Else  
        If I'm holding a wall  
            If I'm trying to move horizontal  
                Place my wall above or below P  
            Else if I'm trying to move vertical  
                Place my wall to the left or right of P  
        Else  
            Grab wall from any neighboring wall cell   

6

Đồng đội

Tại thời điểm này, trình này là xa hoàn hảo. Nó có một chiến lược tương tự như Outposts, nhưng chỉ có 6 bot là "trên không". 2 bot còn lại cung cấp cho chúng những bức tường nếu chúng bị đánh cắp. Chỉnh sửa: Các bot hỗ trợ thực hiện tốt hơn nhiều bây giờ.

var outside = function(x,y) {
    return x < 0 || x > 127 || y < 0 || y > 127
}

var distance = function(x1, y1, x2, y2){
  return Math.sqrt(Math.pow(x1-x2, 2) + Math.pow(y1-y2, 2));
}

var isStuck = function(bot) {
    if (bot.hasWall) {
        for (var i=-1; i<=1; i++) {
            for (var j=-1; j<=1; j++) {
                if ((i != 0 || j != 0) && grid(bot.x+i,bot.y+j) == 0 && !outside(bot.x+i,bot.y+j))
                    return false
            }
        }
        return true
    }
    for (var i=-1; i<=1; i++) {
        for (var j=-1; j<=1; j++) {
            if (grid(bot.x+i, bot.y+j) == 1)
                return false
        }
    }
    return true
}

var isPlayer = function(x,y) {
    for (var i = 0; i < bots.length; i++) {
        if (bots[i].x == x && bots[i].y == y)
            return true
    }
    for (var i = 0; i < ebots.length; i++) {
        if (ebots[i].x == x && ebots[i].y == y)
            return true
    }
    return false
}

var encodeAction = function(type, dx, dy) {
    var d
    if (dx === -1 && dy === -1) d = 1
    else if (dx === 0 && dy === -1) d = 2
    else if (dx === 1 && dy === -1) d = 3
    else if (dx === -1 && dy === 0) d = 4
    else if (dx === 1 && dy === 0) d = 5
    else if (dx === -1 && dy === 1) d = 6
    else if (dx === 0 && dy === 1) d = 7
    else if (dx === 1 && dy === 1) d = 8
    else return 0
    return 8 * type + d
}

var surrounding = function(x,y) {
    var cell = {hasStone:false, cells: []}
    for (var i=-1; i<=1; i++) {
        for(var j=-1; j<=1; j++) {
            if ((i != 0 || j != 0) && !outside(x+i,y+j)) {
                cell.cells.push({x:x+i, y:y+j})
                if (grid(x+i,y+j) == 1) {
                    cell.hasStone = true
                }
            }
        }
    }
    return cell
}


var hunt = function(i, destination) {
    destination = destination || {x: 31+((i-2)%3)*32, y: 20+((i-2)%2)*21}, bot = bots[i]
    if (i < 5 && i > 1) {
        destination.x -= 2
    }
    if (bot.isStuck) {
        return 0
    }
    if ((p1 && destination.x >= move + i) || (!p1 && 127 - destination.x > move - i)) {
        destination.y = bot.y
    }
    if (i == bestBotId && move > 50) {
        destination.x = goal.x
        destination.y = goal.y
    }
    var dx = destination.x > bot.x ? 1 : destination.x == bot.x ? 0 : -1, newX = bot.x + dx
    var dy = destination.y > bot.y ? 1 : destination.y == bot.y ? 0 : -1, newY = bot.y + dy
    var surr = surrounding(newX, newY), botSurr = surrounding(bot.x, bot.y)
    if (grid(newX, newY) == 0) {
        if (surr.hasStone) {
            return encodeAction(0, dx, dy)
        } else {
            if (bot.hasWall) {
                for (var i=0; i<surr.cells.length; i++) {
                    var cell = surr.cells[i];
                    if (Math.abs(cell.x - bot.x) <= 1 && Math.abs(cell.y - bot.y) <= 1 && grid(cell.x, cell.y) == 0 && !isPlayer(cell.x, cell.y)) {
                        return encodeAction(2, cell.x - bot.x, cell.y - bot.y)
                    }
                }
            } else {
                if (bot.walls.length == 1) {
                    return encodeAction(1, bot.walls[0].x - bot.x, bot.walls[0].y - bot.y)
                } else {
                    for (var i=0; i<bot.walls.length; i++) {
                        var wall = bot.walls[i], canUseWall = true
                        for (var j=0; j<bots.length; j++) {
                            if (bots[j].walls.length == 1 && bots[j].walls[0].x == wall.x && bots[j].walls[0].y == wall.y) {
                                canUseWall = false
                            }
                        }
                        if (canUseWall) {
                            return encodeAction(1, wall.x - bot.x, wall.y - bot.y)
                        }
                    }
                }
            }
        }
    } else {
        if (bot.hasWall) {
            for (var i=0; i<botSurr.cells.length; i++) {
                var cell = botSurr.cells[i];
                if (grid(cell.x, cell.y) == 0 && !isPlayer(cell.x, cell.y) && !outside(cell.x, cell.y)) {
                    return encodeAction(2, cell.x - bot.x, cell.y - bot.y)
                }
            }
        } else {
            return encodeAction(1, dx, dy)
        }
    }
    return 0 //hopefully never happens
}

var help = function(i) {
    if (bots[i].isStuck) {
        return 0
    }
    var bot = bots[i], destination = helpDestinations[i]
    if (destination.stuckBot == -1) {
        if (bot.walls.length >= 2 || (bot.hasWall && bot.walls.length == 1)) {
            var stuckId = -1
            for (var j = 0; j < bots.length; j++) {
                if (j != helpDestinations[(i+1)%2].stuckBot && bots[j].isStuck)
                    stuckId = j
            }
            if (stuckId != -1) {
                destination.stuckBot = stuckId
                destination.x = bots[stuckId].x
                destination.y = bots[stuckId].y
                return 0
            } else {
                return hunt(i, destination)
            }
        } else if (bot.x == destination.x && bot.y == destination.y) {
            if (move % 2 == 0)
                destination.y += 1
            else
                destination.x -= 1
            return hunt(i, destination)
        } else {
            return hunt(i, destination)
        }
    } else if (bots[destination.stuckBot].isStuck) {
        if (bot.walls.length < 2 && !(bot.hasWall && bot.walls.length == 1)) {
            destination.stuckBot = -1
            destination.x = i == 0 ? 42 : 85
            destination.y = 55
            return hunt(i, destination)
        }
        var dx = destination.x > bot.x ? 1 : destination.x == bot.x ? 0 : -1, newX = bot.x + dx
        var dy = destination.y > bot.y ? 1 : destination.y == bot.y ? 0 : -1, newY = bot.y + dy
        var surr = surrounding(newX, newY), botSurr = surrounding(bot.x, bot.y), surrWalls = 0
        for (var i = 0; i < surr.cells.length; i++) {
            var cell = surr.cells[i]
            if (grid(cell.x,cell.y) == 1)
                surrWalls++
        }
        if (grid(newX, newY) == 0) {
            if (surrWalls >= 2 || (surr.hasWall && bot.hasWall)) {
                return encodeAction(0, dx, dy)
            } else {
                if (bot.hasWall) {
                    for (var i=0; i<surr.cells.length; i++) {
                        var cell = surr.cells[i];
                        if (Math.abs(cell.x - bot.x) <= 1 && Math.abs(cell.y - bot.y) <= 1 && grid(cell.x, cell.y) == 0 && !isPlayer(cell.x, cell.y)) {
                            return encodeAction(2, cell.x - bot.x, cell.y - bot.y)
                        }
                    }
                } else {
                    if (bot.walls.length == 1) {
                        return encodeAction(1, bot.walls[0].x - bot.x, bot.walls[0].y - bot.y)
                    } else {
                        for (var i=0; i<bot.walls.length; i++) {
                            var wall = bot.walls[i], canUseWall = true
                            for (var j=0; j<bots.length; j++) {
                                if (bots[j].walls.length == 1 && bots[j].walls[0].x == wall.x && bots[j].walls[0].y == wall.y) {
                                    canUseWall = false
                                }
                            }
                            for (var j=0; j<surr.cells.length; j++) {
                                if (surr.cells[j].x == wall.x && surr.cells[j].y == wall.y)
                                    canUseWall = false
                            }
                            if (canUseWall) {
                                return encodeAction(1, wall.x - bot.x, wall.y - bot.y)
                            }
                        }
                    }
                }
            }
        } else {
            if (bot.hasWall) {
                for (var i=0; i<botSurr.cells.length; i++) {
                    var cell = botSurr.cells[i];
                    if (grid(cell.x, cell.y) == 0 && !isPlayer(cell.x, cell.y)) {
                        return encodeAction(2, cell.x - bot.x, cell.y - bot.y)
                    }
                }
            } else {
                return encodeAction(1, dx, dy)
            }
        }
    } else {
        destination.stuckBot = -1
        destination.x = i == 0 ? 42 : 85
        destination.y = 55
        return hunt(i, destination)
    }
    return 0 //hopefully never happens
}

var moves = new Array(8)    
var mem = getMem(), helpDestinations = []
if (mem.length == 0) {
    mem = "42,55,-1 85,55,-1"
}
mem = mem.split(" ")
for (var i = 0; i < mem.length; i++) {
    var cell = mem[i].split(",")
    helpDestinations.push({x: parseInt(cell[0]), y: parseInt(cell[1]), stuckBot: parseInt(cell[2])})
}

for (var i = 0; i < 8; i++) {
    var bot = bots[i]
    var surr = surrounding(bot.x, bot.y)
    bot.walls = []
    for (var j = 0; j < surr.cells.length; j++) {
        if (grid(surr.cells[j].x, surr.cells[j].y) == 1) {
            bot.walls.push(surr.cells[j])
        }
    }
}

bots.forEach(function(bot, index) {
    if(isStuck(bot)) {
        bot.isStuck = true
    }
})

var bestDistance = 1000
var bestBotId = -1
for (var i=2; i<8; i++) {
    var dist = distance(bots[i].x, bots[i].y, goal.x, goal.y)
    if (dist < bestDistance && !bots[i].isStuck) {
        bestDistance = dist
        bestBotId = i
    }
}

for (var i=0; i<8; i++) {
    if (i < 2) {
        moves[i] = help(i)
    } else {
        moves[i] = hunt(i)  
    }
}

setMem(helpDestinations[0].x + "," + helpDestinations[0].y + "," + helpDestinations[0].stuckBot + " " + helpDestinations[1].x + "," + helpDestinations[1].y + "," + helpDestinations[1].stuckBot)

return moves

Ý tưởng hỗ trợ (tốt đẹp) có vẻ khó thực hiện.
edc65

@ edc65 Về cơ bản, nó chỉ di chuyển với 2 bức tường thay vì một. Nhưng giao tiếp giữa hai bot hỗ trợ và tìm kiếm những bức tường mới khá khó thực hiện :)
CommonGuy

6

Người tìm kiếm

Stll làm việc trong tiến trình. Tôi có nhiều ý tưởng, nhưng hầu như không ai trong số họ làm việc.

Trên hết, vấn đề lớn với những hành động thất bại. Đã giải quyết!

var action=[], myGrid=[], goalSort=[], i, j, curBot, curAction, goalSeek;

var check = function(x,y) {
  return (myGrid[[x,y]] || (myGrid[[x,y]] = grid(x,y)))|0;
};

var setGrid = function(x,y,v) {
  myGrid[[x,y]] = v + '';
};

var orGrid = function(x,y,v) {
  myGrid[[x,y]] |= v;
};

var encodeDir = function(dx, dy) {
    return dx < 0 && dy < 0 ? 1
    : dx === 0 && dy < 0 ? 2
    : dx > 0 && dy < 0 ? 3
    : dx < 0 && dy === 0 ? 4
    : dx > 0 && dy === 0 ? 5
    : dx < 0 && dy > 0 ? 6
    : dx === 0 && dy > 0 ? 7
    : dx > 0 && dy > 0 ? 8
    : 0;
};

var distance = function(p1, p2) {
  return Math.max(Math.abs(p1.x-p2.x),Math.abs(p1.y-p2.y));
};

var cellNearWall = function(x,y)
{
  var r = check(x,y) == 1 ? 0
  : check(x-1,y-1) == 1 ? 1
  : check(x,y-1) == 1 ? 2
  : check(x+1,y-1) == 1 ? 3
  : check(x-1,y) == 1 ? 4
  : check(x+1,y) == 1 ? 5
  : check(x-1,y+1) == 1 ? 6
  : check(x,y+1) == 1 ? 7
  : check(x+1,y+1) == 1 ? 8
  : 0;
  return r;
};

var cellNearBot = function(x,y,m)
{
  return check(x-1,y-1) & m ? 1
  : check(x,y-1) & m ? 2
  : check(x+1,y-1) & m ? 3
  : check(x-1,y) & m ? 4
  : check(x+1,y) & m ? 5
  : check(x-1,y+1) & m ? 6
  : check(x,y+1) & m ? 7
  : check(x+1,y+1) & m ? 8
  : 0;
};


var tryGrabWall = function(x, y)
{
  var dx, dy, r = 8;
  for(dy = -1; dy < 2; ++dy)
  {
    for(dx = -1; dx < 2; ++dx)
    {
      if (dx|dy)
      {
        ++r;
        if (check(x+dx, y+dy) == 1)
        {
          setGrid(x+dx, y+dy, 0); // remember that the wall is not there anymore
          return r;
        }
      }
    }
  }
  return 0;
};

var tryDropWall= function(x, y)
{
  var dx, dy, r = 16;
  for(dy = -1; dy < 2; ++dy)
  {
    for(dx = -1; dx < 2; ++dx)
    {
      if (dx|dy)
      {
        ++r;
        if (x+dx>=0 & x+dx < 128 & y+dy >= 0 & y+dy < 64 && check(x+dx, y+dy) == 0)
        {
          setGrid(x+dx, y+dy, 1); // remember that the wall is there 
          return r;
        }
      }
    }
  }
  return 0;
};


var approach = function(bot, target)
{
  var dx, dy, tx, ty, r = 0, wallPos;

  var checkDrop = function(dx,dy)
  {
    var x = bot.x+dx, y = bot.y+dy;
    if (check(x,y) == 0 && cellNearBot(x,y,8) == 0)
    {
      setGrid(x, y, 1);
      return 16 + encodeDir(dx, dy);
    }
  };

  dy = target.y - bot.y;
  dy = dy < 0 ? -1 : dy > 0 ? 1 : 0;
  dx = target.x - bot.x;
  dx = dx < 0 ? -1 : dx > 0 ? 1 : 0;
  tx = bot.x+dx;
  ty = bot.y+dy;

  if ((dx|dy) === 0)
  {
    if (!bot.hasWall) {
      return tryGrabWall(bot.x, bot.y);
    }
    return 0;
  }


  if (cellNearWall(tx,ty))
  {
    setGrid(tx, ty, 2);
    return encodeDir(dx, dy);
  }

  if (dx === 0)
  {
    if (cellNearWall(bot.x-1,ty))
    {
      setGrid(bot.x-1, ty, 2);
      return encodeDir(-1, dy);
    }
    if (cellNearWall(bot.x+1,ty))
    {
      setGrid(bot.x+1, ty, 2);
      return encodeDir(1, dy);
    }
    if (bot.hasWall) 
    {
      if (wallPos = checkDrop(1,dy)) { return wallPos; }
      if (wallPos = checkDrop(-1,dy)) { return wallPos; }
      if (wallPos = checkDrop(1,0)) { return wallPos; }
      if (wallPos = checkDrop(-1,0)) { return wallPos; }
    }
  }
  else if (dy === 0) 
  {
    if (cellNearWall(tx,bot.y-1))
    {
      setGrid(tx, bot.y-1, 2);
      return encodeDir(dx, -1);
    }
    if (cellNearWall(tx,bot.y+1))
    {
      setGrid(tx, bot.y+1, 2);
      return encodeDir(dx, 1);
    }
    if (bot.hasWall) 
    {
      if (wallPos = checkDrop(dx,1)) { return wallPos; }
      if (wallPos = checkDrop(dx,-1)) { return wallPos; }
      if (wallPos = checkDrop(0,1)) { return wallPos; }
      if (wallPos = checkDrop(0,-1)) { return wallPos; }
    }
  }
  else
  {
    if (cellNearWall(tx,bot.y))
    {
      setGrid(tx, bot.y, 2);
      return encodeDir(dx, 0);
    }
    if (cellNearWall(bot.x,ty))
    {
      setGrid(bot.x, ty, 2);
      return encodeDir(0,dy);
    }
    if (bot.hasWall) {
      if (wallPos = checkDrop(dx,0)) { return wallPos; }
      if (wallPos = checkDrop(0,dy)) { return wallPos; }
      if (wallPos = checkDrop(dx,dy)) { return wallPos; }
    }
  }

  if (!bot.hasWall)
  {
  if (check(tx, ty) == 1)
  {
      setGrid(tx, ty, 0); // remember that the wall is not there anymore
      return 8 + encodeDir(dx, dy);
    };
    return tryGrabWall(bot.x, bot.y);
  }
  else
  {
    return tryDropWall(bot.x, bot.y);
  }
};

for (i=0; curBot=ebots[i]; i++)
{
  setGrid(curBot.x, curBot.y, curBot.hasWall ? 4 : 8);
}

var goalDistance=[]

for (i=0; curBot=bots[i]; i++)
{
  orGrid(curBot.x, curBot.y, 2);
  goalDistance[i] = distance(curBot, goal);
}
var sorted = goalDistance.slice().sort(function(a,b){return a-b})
var ranks = goalDistance.slice().map(function(v){ return sorted.indexOf(v)});

var tt = p1 
? [ { x:32, y:20 },{ x:32, y:55 },{ x:64, y:20 },{ x:64, y:55 },
   { x:96, y:20 },{ x:96, y:55 },{ x:16, y:30 },{ x:112, y:30 }]
: [ { x:96, y:20 },{ x:96, y:55 },{ x:64, y:20 },{ x:64, y:55 },
   { x:32, y:20 },{ x:32, y:55 },{ x:112, y:30 },{ x:16, y:30 }]

var goalSeek = 3;

for (i=0; curBot=bots[i]; i++)
{
  if (ranks[i] < goalSeek)
  {
    curAction = approach(curBot, goal);
    if (curAction == 0) goalSeek += 1;
  }
  else
    curAction = approach(curBot, tt[i]);

  action[i] = curAction;
}

return action;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.