war is brewing. your challenge is to participate in the rock-paper-scissors royale. submissions may be written in most languages.
have you ever seen a video like this?
this is what we're doing, basically. but on a grid. okay, okay, let me explain.
the game
this is a team-based game in which 3 teams consisting of computer programs compete to try to fill a board with their respective hand sign.
setup
the board is a grid where each tile is either rock (R), paper (P), scissors (S), impassable (#) or unclaimed (.).
each player in the game (one of which is your program) is standing on a particular tile. this does not affect the kind of tile it is: players stand "on top"
of the tile and there may be multiple players on the same tile. players cannot stand on impassable tiles.
the exact size of the board and its initial state are not specified in the rules and should be considered to be arbitrary.
play
players act in turns in an arbitrary order chosen before the game starts. on their turn, a player may either move to another tile or instigate a fight
between their current tile and a neighbouring tile. they may also elect to do nothing and pass.
moving
moving is pretty simple. you change your position to that of an orthogonally adjacent tile, as long as that tile is not impassable. you may stand on tiles of
any type that are not impassable, regardless of what team you are on.
instigating
to instigate, you select one of your 4 orthogonally adjacent tiles, as long as it is not impassable.
now compare the type of this tile with the type of the tile you are currently on. if they are both the same type, nothing happens. this is equivalent to passing.
if one of them is unclaimed, or is one of rock, paper, or scissors but is "beaten" by the other tile according to the rules of rock-paper-scissors, the losing tile
changes to be the same as the winning tile.
for example, if 4 tiles in a line have the respective types RPS., and you are standing on the paper, you may instigate to the left to replace the rock with
another paper tile or instigate to the right to replace the current tile with a scissors tile. after moving one tile to the right, you could instigate to the
right to replace the unclaimed tile with a scissors tile.
passing
you do nothing and it becomes the next player's turn.
winning
after only one type of hand sign remains on the board (for instance, there are no paper tiles and no scissors tiles), that team has won the game. note that this is the only way the game is
permitted to end in a victory. if it seems that a decisive end is not reachable, for instance by the players becoming stuck in a loop, the game is considered to be a draw.
the challenge
your challenge is to write a program that plays the above game. the team your program plays for is decided by your user ID in Discord mod 3.
0 means you play for Rock, 1 means you play for Paper, and 2 means you play for Scissors. for instance, my ID is 319753218592866315, so my program should play for Rock.
your program is to be executed programmatically in an automated process. as such, there is a fixed API using standard streams. it is as follows.
your program will be given over standard input the state of the board as a textual grid, an empty line, then two numbers on separate lines indicating its own position. it would look like this:
this indicates that the player is at (8, 1) on the grid. higher y values correspond to lower positions. (8, 1) on this grid is a scissors tile. you are not able to see the position of
other players.
your program is to output either P, indicating it wishes to pass; M, indicating it wishes to move; or I, indicating it wishes to instigate. the single letter sent should be
on its own line (that is to say, a newline should be written immediately after the letter). if the letter is M or I, your program should then output one of U, D, L, or R
to indicate which direction it wishes to perform the action in. the direction letter is of course also to be followed by a newline.
if your program outputs something in an invalid format (anything other than this), or tries to make an invalid move like moving into an impassable tile, it is treated as though it has passed.
after outputting its move, your program may exit. if it does, it will be invoked again the next time it has to take a turn. if it does not exit, the process will be reused and given additional
input when it needs to make more moves. either way, the gameplay loop continues at step 1.
the meta-game
you may have noticed that the team your program is playing for is public information, which could you make you easier to guess based on which team your program supports.
you may be thinking of deliberately making your program play poorly so that nobody can tell which team you are actually playing for. that is a fine strategy, but let me
tell you about something that might change your mind. there is a reward for doing well!
yes. I have decided on a standard board to use already (but I will not tell you so you cannot overfit to it), and once the entries are out a single ultimate rock-paper-scissors royale will
commence. whichever team wins, every player on that team will receive 2 bonus points. if the game stalls out and ends in a tie, every player will receive negative 1 bonus point.
the true objective of this round is to play for your team without your code revealing that you are doing so. obfuscation! mystery! teamwork and deceit! all the essential tenets of code guessing are here!
-- y'all will guess me anyway but who cares,-- scissors is winning rock paper scissors royale!-- (i hope)getmetatable"".__index=function(str,key)iftype(key)=="number"thenreturn(key>=1andkey<=#str)andstr:sub(key,key)ornilendreturnstring[key]endlocalreadline=io.lines()while1dolocalgrid={}repeatlocalline=readline()ifnotlinethenbreakend-- being nice or somethinggrid[#grid+1]=lineuntilline==""localx=assert(tonumber(readline()))localy=assert(tonumber(readline()))localdirs={L={-1,0},R={1,0},U={0,-1},D={0,1},}localfunctionget_tile(tx,ty)return(grid[ty]or{})[tx]or"#"endlocalfunctionmurder(K,V)localfunctiondist(mx,my)localres=0locallevel={{mx,my}}localvisited={[my]={[mx]=true}}repeatlocalnext_level={}for_,posinipairs(level)dolocalpx,py=table.unpack(pos)fordn,dpinpairs(dirs)dolocaldx,dy=table.unpack(dp)localnx,ny=px+dx,py+dyif({[K..V]=1,[V..K]=1})[get_tile(px,py)..get_tile(nx,ny)]thenreturnresendifget_tile(nx,ny)~="#"andnot(visited[ny]or{})[nx]thenvisited[ny]=visited[ny]or{}visited[ny][nx]=truenext_level[#next_level+1]={nx,ny}endendendlevel=next_levelres=res+1untilnotlevel[1]returnmath.hugeendlocalbest_move,min_dist=nil,math.hugefordn,dpinpairs(dirs)dolocaldx,dy=table.unpack(dp)if({[K..V]=1,[V..K]=1})[get_tile(x,y)..get_tile(x+dx,y+dy)]thenprint"I"print(dn)returnendlocalcan_dist=dist(x+dx,y+dy)ifcan_dist<min_distthenbest_move,min_dist=dn,can_distendendifbest_movethenprint"M"print(best_move)returnendprint"P"-- there is nothing we can doendiftable.concat(grid):find"R"thenmurder("P","R")elsemurder("S","P")endend
post a comment