Java 1801 1691 1467
So yeah, this is definitely a revival, but as a new participant on codegolf I hope you won't hold it against me.
Edit: Changed from multidimensional array to single dimension array, also stripped out a bunch of unnecessary parenthesis. Next step will be to write a different "brain" for the computer. Even as it is, although not perfect, it does pretty well. I'm probably going to set up a version that has the computer play itself, for kicks. When I do, you can find it in my github.
Edit2: Replaced q
and b
methods with a single d
method that performs all the work of q
and b
based on a flag passed in that chooses the "mode", 1
for win or block (prior q
method), 0
for future-move-win choice (prior b
method). Saved more than two hundred characters, hurray.
I spent some time golfing in Java, and this is what I came up with:
import java.util.*;class W{public static void main(String[]a){(new W()).t();}void p(String k,int i){System.out.print(k+(i<1?"":"\n"));}int[]M;int P;int c(){int m,a,b,i;for(a=b=i=0;i<3;i++){a=M[i*3];b=M[i];m=a==M[i*3+1]&&M[i*3+1]==M[i*3+2]&&a>0?a:b==M[i+3]&&M[i+3]==M[i+6]&&b>0?b:0;if(m>0){return m;}}m=M[4];return M[0]==m&&m==M[8]||b==m&&m==a?m:0;}void g(){for(int i=0;i<9;)p(w(M[i]),i++%3/2);p("",1);}int x(int i){return(new Random()).nextInt(i);}String w(int i){return(i<1)?".":((2*i-3)*P<0)?"X":"O";}int y(){return(new Scanner(System.in)).nextInt();}void Z(){int i;do{i=x(9);}while(!s(i,1));}int o(int a,int b,int c,int z,int x){return a==b&&c==x&&a==z?2:a==x&&b==c&&b==z?0:a==c&&b==x&&c==z?1:-1;}int d(int z,int y,int k){int i=0,j;for(;i<3;i++){if((j=o(M[i*3],M[i*3+1],M[i*3+2],z*k,z*(1-k)))>=0?s(k>0?i*3+j:i*3+2-j/2,y):(j=o(M[i],M[i+3],M[i+6],z*k,z*(1-k)))>=0?s(k>0?i+3*j:i+(2-j/2)*3,y):0>1)return 1;}if((i=o(M[0],M[4],M[8],z*k,z*(1-k)))>=0?s(k>0?i*4:8-(i/2)*4,y):(i=o(M[2],M[4],M[6],z*k,z*(1-k)))>=0?s(k>0?i*2+2:6-(i/2)*2,y):0>1)return 1;return 0;}void z(){if(!(d(1,1,1)>0||d(2,1,1)>0||s(4,1)||d(1,1,0)>0))Z();}boolean s(int i,int z){if(M[i]<1){p(w(z)+" to "+i%3+","+i/3,1);return(M[i]=z)==z;}return 0>1;}void t(){while(1>0){M=new int[9];int m=9,x;if(x(2)<1){P=1;Z();g();m--;}else P=-1;do{do{p("x?",0);x=y();p("y?",0);}while(!s(y()*3+x,2));m--;g();x=c();if(x>0||m<1)break;z();g();m--;x=c();}while(m>0&&x<1);if(x<1)p("No winner!",1);else p(w(x)+" wins!",1);}}}
Ungolfed, with comments (and perhaps some longer variables/method names):
import java.util.*;
public class TicTacToeGolf {
public static void main(String[] args) {
(new TicTacToeGolf()).start();
}
/** Wrap System.out.print to avoid all that typing */
void p(String k, int i){
System.out.print(k +((i<1)?"":"\n"));
}
/** Game board */
int[][] gg;int P;
/** Check all possibilities for winner, return 0 for no winner, 1 for X, 2 for O */
int c(){
for(int[]i:gg)
if((i[0]==i[1])&&(i[1]==i[2])&&i[0]>0)
return i[0];
for(int i=0;i<3;i++)
if ((gg[0][i]==gg[1][i])&&(gg[1][i]==gg[2][i])&&gg[0][i]>0)
return gg[0][i];
int m=gg[1][1];
return (((gg[0][0]==m)&&(m==gg[2][2])||(gg[0][2]==m)&&(m==gg[2][0]))?m:0);
}
/** Print game board */
void g(){
for(int[]i:gg){
for(int j:i)
p(w(j),0);
p("",1);
}p("",1);
}
/** Generate a random value */
int x(int i) {
return (new Random()).nextInt(i);
}
/** Convert 1 to X, 2 to O */
String w(int i) {
return (i<1)?".":((2*i-3)*P<0)?"X":"O";
}
/** Get a number from the input */
int y() {
return (new Scanner(System.in)).nextInt();
}
/** Pick the next move for the computer */
void Z() {
int i,j;
do{
i=x(3);
j=x(3);
}while(!s(i,j,1));
}
/** Check for win or board condition for player z based on an ordered set of values a,b,c having one space with player x */
int o(int a, int b, int c, int z, int x) {
return (a==b&&c==x&&a==z)?2:(a==x&&b==c&&b==z)?0:(a==c&&b==x&&c==z)?1:-1;
}
/** Check for win over rows, cols, and grids for user z, place for user y based on findings.
* Means will block z if z != y */
int q(int z,int y){
int i=0,j;
// check for win or block
for (;i<3;i++){
j=o(gg[i][0],gg[i][1],gg[i][2],z,0);
if (j>=0){s(i,j,y);return 1;}
j=o(gg[0][i],gg[1][i],gg[2][i],z,0);
if (j>=0){s(j,i,y);return 1;}
}
i=o(gg[0][0],gg[1][1],gg[2][2],z,0);
if (i>=0){s(i,i,y);return 1;}
i=o(gg[0][2],gg[1][1],gg[2][0],z,0);
if (i>=0){s(i,2-i,y);return 1;}
return 0;
}
/** Check for placement options over rows, cols, and grids for user z, place for user y based on findings.
* Means will block z if z != y */
int b(int z,int y){
int i=0,j;
// check for placement or block
for (;i<3;i++){
j=o(gg[i][0],gg[i][1],gg[i][2],0,z);
if (j>=0){s(i,2-j/2,y);return 1;}
j=o(gg[0][i],gg[1][i],gg[2][i],0,z);
if (j>=0){s(2-j/2,i,y);return 1;}
}
i=o(gg[0][0],gg[1][1],gg[2][2],0,z);
if (i>=0){s(2-i/2,2-i/2,y);return 1;}
i=o(gg[0][2],gg[1][1],gg[2][0],0,z);
if (i>=0){s(2-i/2,i/2,y);return 1;}
return 0;
}
/** Pick the next move for the computer, smartly */
void z() {
// Check for win
if (q(1,1)>0)return;
// Check for block
if (q(2,1)>0)return;
// check for best
if (s(1,1,1))return; // try to take center.
// take whatever would win the subsequent turn if the other person is stupid.
if (b(1,1)>0)return;
Z(); // take anything.
}
/** Check if move is possible, if so do it, otherwise return false */
boolean s(int i, int j, int z){
if (gg[i][j]<1){
p(w(z)+" to "+j+","+i,1);
return (gg[i][j]=z)==z;
}
return 0>1;
}
/** Play the game, Computer gets first move. */
void start() {
while(true){
gg = new int[3][3];
int moves=9,x;
if (x(2)<1) { // Computer starts.
P=1;
Z();
g();
moves--;
}else P=-1;
do{
do{
p("x?",0);
x=y();
p("y?",0);
}while(!s(y(),x,2));
moves--;
g();
if (c()>0||moves==0)
break;
z();
g();
moves--;
}while(moves>0&&c()==0);
if(c()<1) p("No winner!",1);
else p(w(c()) + " wins!",1);
}
}
}
Some usage notes:
- 50/50 chance for who takes first turn.
- Move of "X" or "O" announced before displaying the game board.
- Choice of cell is specified as column, then row, indexed from 0.
- Entering something outside
[0,2]
will cause a index exception and end the game.
- If computer goes first, takes a random move (no preference for any board location).
- Computer will take one move wins, block one move losses, plays conservatively (prefers center if available), tries to set up a two-turn win (hope other player doesn't block), and if that fails? Picks a random spot. So doesn't play a perfect game, but plays a great game. I can force a win due to the random start possibilities, but computer will force a win as well if I start badly.
- Wins are detected immediately.
- Impossible-to-win is not detected; you must play every game to the end or let the other player win.
- At the end of each game, a new game begins, again with a randomly chosen starting player.
- Took a few hits to character length by including a usable UI.
- Use
Ctrl+c
to end.
Example game (with computer starting, so first placement is random):
$ java W
X to 1,2
...
...
.X.
x?1
y?1
O to 1,1
...
.O.
.X.
X to 2,2
...
.O.
.XX
x?0
y?2
O to 0,2
...
.O.
OXX
X to 2,0
..X
.O.
OXX
x?2
y?1
O to 2,1
..X
.OO
OXX
X to 0,1
..X
XOO
OXX
x?0
y?0
O to 0,0
O.X
XOO
OXX
X to 1,0
OXX
XOO
OXX
No winner!
There's definitely room for improvement. One place is likely replacing the multi-dimensional array with a one-dimensional array(done), and replacing the more complex decision logic with either a reduced form of the same(done), or a more concise best-choice solver.
Play around with it and let me know what you think. I've got this hosted over on my github so feel free to fork, clone, and create pull requests with improvements.
1I believe it's spelled
tic-tac-toe
ortic-tack-toe
, minor issue but the tag should be properly spelled.... – st0le – 2011-02-19T06:06:59.9971And in en-gb it's Nought's and Crosses. – Peter Taylor – 2011-02-19T08:00:33.130
4@Peter: It's actually Noughts and Crosses, without the apostrophe. – Chris Jester-Young – 2011-02-20T06:43:37.497
@Chris, indeed. I'm not sure where the apostrophe came from. – Peter Taylor – 2011-02-20T08:32:19.057
I wrote Tic Tac Toe in sed for fun, now I'm trying to post it here after I comply with the rules. I'm puzzled about why do you ask for the first computer move to be random? For optimal play it should be either in a corner or in the middle, depending if it's his turn or not. – seshoumara – 2017-02-22T16:31:10.057
Do you want full code version as well? I guess you do since you want to look at algorithm. – philcolbourn – 2014-03-05T13:33:53.817