Order and Chaos and Codegolf

10

1

Order and Chaos is a variant of Tic-Tac-Toe played on a 6x6 board. What makes the game unique, however, is that both players can place either an X or an O! Each turn (starting with Order), a player places an X or O in any unoccupied square.
Winning is simple. Order wins if there are 5 Xs or Os (vertically, horizontally, or diagonally) in a row on the board. Chaos wins if the board is filled and there are no strings of 5 Xs or Os on the board. Your job? Well, since this is Programming Puzzles and Code Golf, you're going to program the game, and golf it.

The Rules

  • You must accept input as x y t, where x and y are coordinates, and t is the tile type (X or O). Coordinates start with 0 0 in the upper-left corner and increase up to 5 5 (the lower-right corner).
  • You must accept q to quit, and print INVALID if the user enters invalid coordinates, tiles, any input not in the form of x y t, or tries to place a tile where there already is one. (The only exception is q, as this quits the program.)
  • If Order wins, you will output P1 WINS. If Chaos wins, you will output P2 WINS.
  • Order must go first.
  • A blank space is represented by ..
  • Tiles are X and O (uppercase). You do not have to accept lowercase, but uppercase is required.
  • Your board must only consist of .XO.
  • You're actually simulating both players playing the game, not being given a board and checking who wins. It accepts a move as input, then prints the board, accepts another move, and so on, until one player wins.

The starting board looks like this:

......
...... 
......
......
......
...... 

And after the first player (Order) inputs 1 2 X, it should look like this:

......
...... 
.X....
......
......
......  

Likewise, when the next player (Chaos) inputs 3 3 O, it will look like this:

......
...... 
.X....
...O..
......
......  

And this continues until one player wins.

As always, Standard loopholes which take the fun out of everything are forbidden.

The winner is the one with the shortest code on June 15, 00:00 UTC (about one month from when this challenge was posted.)

ASCIIThenANSI

Posted 2015-05-15T19:00:39.183

Reputation: 1 935

What if a player types in a position that is already taken? – Loovjo – 2015-05-15T19:29:08.860

@Loovjo It returns INVALID. I've edited that in now, thanks. – ASCIIThenANSI – 2015-05-15T19:30:26.177

1Should the game exit once 5 tiles are in a row are detected? – Kyle Kanos – 2015-05-15T23:55:23.117

1Maybe I overlooked it but does it have to print the board to the screen or just check the state of the board and output which player wins? – Kodos Johnson – 2015-05-16T00:18:17.510

@Andrew I actually meant to simulate the game. You accept each player's input, one turn at a time, and then check if a player has won each turn. Is the description unclear? – ASCIIThenANSI – 2015-05-16T02:48:52.923

@KyleKanos Yes. Once 5 tiles are in a row, it quits and prints ORDER WINS. – ASCIIThenANSI – 2015-05-16T03:02:06.107

@ASCIIThenANSI ORDER WINS or P1 WINS? – xebtl – 2015-05-16T09:42:57.360

@xebtl Sorry, messed that up. It prints P1 WINS if there are 5 tiles in a row, and P2 WINS if the board is full with no chains of 5 tiles in a row. – ASCIIThenANSI – 2015-05-16T13:24:25.633

Yes the description is unclear. The board have to be printed at each turn or not? – edc65 – 2015-05-16T13:59:56.313

@edc65 Yes, it does. I'll make sure it's clearer. – ASCIIThenANSI – 2015-05-16T14:01:00.460

Answers

1

PHP, 316

Here is my submission. It has to be executed by php in the command line.

Note that this code produces notices because of some shortcuts I made. Let me know if this is ok. I can fix it by adding a few more characters. I checked this page and the top answer says to assume that error reporting is turned off if there is no mention about it.

<?for(;$i++<6;)$b.='......|';while(($a=trim(fgets(STDIN)))!='q'){preg_match('/^([0-5]) ([0-5]) ([XO])$/',$a,$d)&($b[$c=$d[2]*7+$d[1]]=='.')?$b[$c]=$d[3]:print"INVALID\n";echo str_replace("|","\n",$b); foreach([0,5,6,7]as$e)preg_match('/(X|O)(.{'.$e.'}\1){4}/',$b)-1?:die("P1 Wins");strstr($b,'.')?'':die("P2 Wins");}

And here is the un-golfed version of the code:

<?php
error_reporting(E_ALL & ~E_NOTICE);

for(;$i++<6;)$b.='......|';
while(($a=trim(fgets(STDIN)))!='q'){

    #Validate and assign 
    preg_match('/^([0-5]) ([0-5]) ([XO])$/',$a,$d)&($b[$c=$d[2]*7+$d[1]]=='.')?$b[$c]=$d[3]:print"INVALID\n";

    #Output
    echo str_replace("|","\n",$b); 

    #Check if Order wins
    foreach([0,5,6,7]as$e) {
        preg_match('/(X|O)(.{'.$e.'}\1){4}/',$b)-1?:die("P1 Wins");
    }

    #Check if Chaos wins
    strstr($b,'.')?'':die("P2 Wins");
}

Kodos Johnson

Posted 2015-05-15T19:00:39.183

Reputation: 776

Yes, notices are OK. – ASCIIThenANSI – 2015-05-29T15:09:10.903

4

JavaScript, 360

Edit Modified interactive game, should run even in MSIE

As requested, text based game, input via popup, output in console (so to have a monospaced font).

Quit game with 'q' or clicking 'cancel' at prompt.

Not using ES5 features, it should run on any moder browser (where you can have a JS console panel)

b='\n......'.repeat(6).split('');
for(h=t=0;!h&t<36;)
{
  i=prompt();
  if(i=='q')i=null;
  i=i.match(/([0-5]) ([0-5]) ([XO])/);
  m='INVALID';
  if(b[p=i?i[2]*7-~i[1]:0]=='.')
  {
    ++t;
    b[p]=i[3];
    m=b.join('');
    for(x=z='',c=0;c++<6;)
      for(x+='_',z+='_',r=0;r<6;r++)
        x+=b[c+r*7],z+=b[c<4?c-1+r*8:c+1+r*6];
    h=(/X{5}|O{5}/.test(b.join('')+x+z))
  }
  console.log(m);
}
console.log("P"+(2-h)+" WINS")

Now, some more fun Interactive and graphic version, run snippet to play.

function start() {
  b=Array(7).join('\n......').split('');
  t=0;
  $('#O').text('');
  $('table')[0].className='';
  show();
  $('th').eq(1).html('Left-click: O<br>Right-click: X');
  $('#B')
  .off('mouseup')
  .on('mouseup','td.F',function(ev){
    var x,y, p=~~this.id.slice(1)
    x=p%7-1
    y=p/7|0
    b[p]=ev.which > 1 ?'X':'O';
    ++t
    for(x=z='',c=0;c++<6;)
      for(x+='_',z+='_',r=0;r<6;r++)
        x+=b[c+r*7],z+=b[c<4?c-1+r*8:c+1+r*6];
    show()
    if (/X{5}|O{5}/.test(b.join('')+x+z))
      end(1)
    else if(t==6*6) 
      end(2)
    return false
  })
}

function end(w) {
  var n=['Order','Chaos'][w-1]
  $('th').eq(0).text('P'+w+' '+n+' Wins')
  $('th').eq(1).text('Click to play again')
  
  $('table')[0].className=$('tr')[0].className =n[0];
  $('#B').off('mouseup').on('mouseup', start)
}
function show() {
  var w,p
  p=t&1
  $('tr')[0].className=$('#B')[0].className='OC'[p];
  w=b.map(function(c,i){
    return c>' '?'<td class='+(c=='.'?'F':'X')+' id=C'+i+'>'+c+'</td>':'</tr><tr>'
  }).join('');
  $('th').eq(0).text('Playing: '+['Order','Chaos'][p]);
  $('#B').html('<tr>' + w +'</tr>');
}

start()
th { 
  font-size: 12px;
}
.C th { color: #807; }
.O th { color: #047; }
.C td.F:hover { background: #f0e; }
.O td.F:hover { background: #0fe; }
table.C td { background: #f0e; }
table.O td { background: #0fe; }

td {
  font-family: monospace;
  font-size: 12px;
  width: 1.2em;
  height: 1em;
  text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table>
  <tr><th colspan=6></th></tr>
  <tbody id=B></tbody>
  <tr><th colspan=6></th></tr>
</table>
<p id=O></p>

edc65

Posted 2015-05-15T19:00:39.183

Reputation: 31 086

Nice clickable version! (Minor suggestion: you could use right/left click instead of the radio buttons.) – xebtl – 2015-05-17T08:40:42.737

@xebtl I'll give it a try – edc65 – 2015-05-17T08:45:35.160

1

Octave, 453

format plus 'XO.'
disp(F=zeros(6))
r=@()fread(0,1);R=@()r()-47;q=@(m)printf(m)&&quit;e=@()q("INVALID");l=@(n)n<1||n>6&&e();s=@()r()==32||e();w="P1 WINS";f=@(v)abs(sum(v))==22.5&&q(w);g=@(m)any(abs(sum(m))==22.5)&&q(w);d=@diag;while 1
i=R();i==66&&quit;l(i);s();l(j=R());s();F(j,i)&&e();abs(v=R()-36.5)==4.5||e();F(j,i)=v;disp(F)
r();f(d(F,-1));f(d(F,0)(2:6));f(d(F,0)(1:5));f(d(F,1));g(F(1:5,:));g(F(2:6,:));g(F(:,1:5)');g(F(:,2:6)');F&&q("P2 WINS");end

The implementation is quite straightforward, the only real “trick” to use format plus to take care of printing. Here is a commented version:

format plus 'XO.'               # this is where the magic happens

## initialize and print empty board
disp(F=zeros(6))

## shortcuts
r=@()fread(0,1);
R=@()r()-47;
q=@(m)printf(m)&&quit;
e=@()q("INVALID");
l=@(n)n<1||n>6&&e();
s=@()r()==32||e();
w="P1 WINS";
f=@(v)abs(sum(v))==22.5&&q(w);
g=@(m)any(abs(sum(m))==22.5)&&q(w);
d=@diag;

while 1
  i=R();                        # read index 1
  i==66&&quit;                  # ‘q’?
  l(i);                         # check bounds
  s();                          # read and check space
  l(j=R());                     # read and check index 2
  s();                          # read and check space
  F(j,i)&&e();                  # square already filled?
  abs(v=R()-36.5)==4.5||e();    # valid mark?
  F(j,i)=v;                     # assign …
  disp(F)                       # and print board
  r();                          # read off newline

  ## check diagonals
  f(d(F,-1));
  f(d(F,0)(2:6));
  f(d(F,0)(1:5));
  f(d(F,1));

  ## check rows
  g(F(1:5,:));
  g(F(2:6,:));

  ## check columns
  g(F(:,1:5)');
  g(F(:,2:6)');

  ## check chaos
  F&&q("P2 WINS");
end

Because of the requirement to check input syntax and validity, the code uses fread() to read one character at a time.

I took care to output the board and messages in a tidy manner. If some extra output is acceptable, I could shave off a couple of bytes. For example, using automatic printing (no disp(F)), the board would be shown as

F =

......
......
......
......
......
......

Also, I interpreted that each move is given on a separate line.


Sample interaction (the -q switch is just to suppress Octave's header):

$ octave -q order_chaos.m 
......
......
......
......
......
......
3 3 X
......
......
......
...X..
......
......
2 3 O
......
......
......
..OX..
......
......
3 3 O
INVALID

The invalid move caused the program to exit (not sure if that was intended).

xebtl

Posted 2015-05-15T19:00:39.183

Reputation: 941

Just to make sure (because there was some confusion earlier), this takes input from both players, and actually simulates the game, rather than just checking if a given board wins? – ASCIIThenANSI – 2015-05-16T13:27:06.587

@ASCIIThenANSI Just so. It expects each move of the form x y t on a separate line (and no other input). – xebtl – 2015-05-16T13:55:06.460

And it prints the board after every input? – ASCIIThenANSI – 2015-05-16T13:56:12.823

@ASCIIThenANSI Yes, see edited answer. – xebtl – 2015-05-16T14:01:10.127

1

Java, 565 chars D:

public class M{public static void main(String[]r){int[]p=new int[36];int u=0;for(;;){String l=new java.util.Scanner(System.in).nextLine();if(l == "q")break;int a=l.charAt(0)-'0'+(l.charAt(2)-'0')*6,i=p[a]==0?1:0;if(i>0)p[a]=l.charAt(4);u+=i;r(i==0?"INVALID\n":"");if(u==36){r("P2 WINS");break;}for(int x=0;x<6;x++)for(int y=0;y<6;y++)for(int d=0;d<3;d++)try{int e=1,c=p[x+y*6],z=x,h=y;if(c=='X'||c=='Y'){for(;e<6;e++){if(d%2==0)z++;if(d>0)h++;if(p[z+h*6]!=c)break;}if(e==5){r("P1 WINS");return;}}}catch(Exception e){}}}static void r(Object o){System.out.print(o);}}

This is probably the longest code-golf ever. I'm really not good at this.

Loovjo

Posted 2015-05-15T19:00:39.183

Reputation: 7 357