代码高尔夫:井字游戏

根据人物数量发布最短代码,以检查玩家是否赢了,如果是,哪个。

假设你在一个variablesb (棋盘)中有一个整数数组,这个variables保存井字棋板,以及玩家的移动位置:

  • 0 =没有设置
  • 1 =玩家1(X)
  • 2 =玩家2(O)

所以,给定数组b = [ 1, 2, 1, 0, 1, 2, 1, 0, 2 ]代表板

 X|O|X -+-+- |X|O -+-+- X| |O 

对于这种情况,你的代码应该输出1来表示玩家1赢了。 如果没有人赢了,你可以输出0false

我自己的(Ruby)解决scheme即将推出。

编辑 :对不起,忘记标记为社区维基。 你可以假设input是正确的,不需要检查错误。


更新 :请以function的forms发布您的解决scheme。 大多数人已经这样做了,但有些人没有,这不完全公平。 该板作为参数提供给您的function。 结果应该由函数返回。 该function可以有你select的名称。

C,77(83)个字符

这是dmckee解决scheme的一个变体,除了紧凑编码中的每一对数字现在都是ASCII字符的9位数字。

77 -char版本,无法在MSVC上工作:

 // "J)9\t8\r=,\0" == 82,45,63,10,62,14,67,48,00 in base 9. char*k="J)9 8\r=,",c;f(int*b){return(c=*k++)?b[c/9]&b[c%9]&b[*k--%9]|f(b):0;} 

这个83 -char版本,应该在每个C编译器上工作:

 f(int*b){char*k="J)9 8\r=,",s=0,c;while(c=*k++)s|=b[c%9]&b[c/9]&b[*k%9];return s;} 

(请注意,9和8之间的空格应该是一个选项卡,StackOverflow将所有选项卡转换为空格。)


testing用例:

 #include <stdio.h> void check(int* b) { int h0 = b[0]&b[1]&b[2]; int h1 = b[3]&b[4]&b[5]; int h2 = b[6]&b[7]&b[8]; int h3 = b[0]&b[3]&b[6]; int h4 = b[1]&b[4]&b[7]; int h5 = b[2]&b[5]&b[8]; int h6 = b[0]&b[4]&b[8]; int h7 = b[2]&b[4]&b[6]; int res = h0|h1|h2|h3|h4|h5|h6|h7; int value = f(b); if (value != res) printf("Assuming f({%d,%d,%d, %d,%d,%d, %d,%d,%d}) == %d; got %d instead.\n", b[0],b[1],b[2], b[3],b[4],b[5], b[6],b[7],b[8], res, value); } #define MAKEFOR(i) for(b[(i)]=0;b[(i)]<=2;++b[(i)]) int main() { int b[9]; MAKEFOR(0) MAKEFOR(1) MAKEFOR(2) MAKEFOR(3) MAKEFOR(4) MAKEFOR(5) MAKEFOR(6) MAKEFOR(7) MAKEFOR(8) check(b); return 0; } 

疯狂的Python解决scheme – 79个字符

 max([b[x] for x in range(9) for y in range(x) for z in range(y) if x+y+z==12 and b[x]==b[y]==b[z]] + [0]) 

然而,这个假设在b:

  5 | 0 | 7 ---+---+--- 6 | 4 | 2 ---+---+--- 1 | 8 | 3 

也就是说, b[5]代表左上angular,依此类推。

为了最小化以上:

 r=range max([b[x]for x in r(9)for y in r(x)for z in r(y)if x+y+z==12and b[x]==b[y]==b[z]]+[0]) 

93个字符和一个换行符。

更新:使用按位AND技巧,最多为79个字符和一个换行符:

 r=range max([b[x]&b[y]&b[z]for x in r(9)for y in r(x)for z in r(y)if x+y+z==12]) 

Python 80(69)char

不是最短的Python解决scheme,但我喜欢它如何将“DICE”引入井字游戏:

 W=lambda b:max([b[c/5-9]&b[c/5+c%5-9]&b[c/5-c%5-9]for c in map(ord,"DICE>3BQ")]) 

69个简单的expression方式:

 max([b[c/5-9]&b[c/5+c%5-9]&b[c/5-c%5-9]for c in map(ord,"DICE>3BQ")]) 

Perl,87 85 人物

一个函数返回0,1或2,当然使用一个正则expression式(换行符仅用于避免滚动条):

 sub V{$"='';$x='(1|2)';"@_"=~ /^(...)*$x\2\2|^..$x.\3.\3|$x..\4..\4|$x...\5...\5/?$^N:0} 

例如,它可以被称为V(@b)

J,50个字

 w=:3 : '{.>:I.+./"1*./"1]1 2=/y{~2 4 6,0 4 8,i,|:i=.i.3 3' 

我不喜欢重复自己(水平/垂直和对angular线),但我认为这是一个公平的开始。

C#w / LINQ:

 public static int GetVictor(int[] b) { var r = Enumerable.Range(0, 3); return r.Select(i => r.Aggregate(3, (s, j) => s & b[i * 3 + j])).Concat( r.Select(i => r.Aggregate(3, (s, j) => s & b[j * 3 + i]))).Aggregate( r.Aggregate(3, (s, i) => s & b[i * 3 + i]) | r.Aggregate(3, (s, i) => s & b[i * 3 + (2 - i)]), (s, i) => s | i); } 

策略:按行与其他元素(以3作为种子)的行/列/对angular线的每个元素进行比较,以获得该子集的胜利者,并且将它们全部结合在一起。

ruby,115个字符

哎呀:不知何故,我错了很多。 这实际上是115个字符,而不是79个。

 def t(b)[1,2].find{|p|[448,56,7,292,146,73,273,84].any?{|k|(k^b.inject(0){|m,i|m*2+((i==p)?1:0)})&k==0}}||false end # Usage: b = [ 1, 2, 1, 0, 1, 2, 1, 0, 2 ] t(b) # => 1 b = [ 1, 1, 0, 2, 2, 2, 0, 2, 1 ] t(b) # => 2 b = [ 0, 0, 1, 2, 2, 0, 0, 1, 1 ] t(b) # => false 

而扩展的代码,用于教育目的:

 def tic(board) # all the winning board positions for a player as bitmasks wins = [ 0b111_000_000, # 448 0b000_111_000, # 56 0b000_000_111, # 7 0b100_100_100, # 292 0b010_010_010, # 146 0b001_001_001, # 73 0b100_010_001, # 273 0b001_010_100 ] # 84 [1, 2].find do |player| # find the player who's won # for the winning player, one of the win positions will be true for : wins.any? do |win| # make a bitmask from the current player's moves moves = board.inject(0) { |acc, square| # shift it to the left and add one if this square matches the player number (acc * 2) + ((square == player) ? 1 : 0) } # some logic evaluates to 0 if the moves match the win mask (win ^ moves) & win == 0 end end || false # return false if the find returns nil (no winner) end 

我相信这个可能会缩短,特别是大阵容,还有可能是让玩家的动作有点掩盖的代码 – 那个三重的BUG我 – 但是我觉得现在这样很好。

Perl,76个字符

 sub W{$n=$u=0;map{$n++;$u|=$_[$_-$n]&$_[$_]&$_[$_+$n]for/./g}147,4,345,4;$u} 

有三种方法可以水平取胜:

 0,1,2 ==> 1-1, 1, 1+1 3,4,5 ==> 4-1, 4, 4+1 6,7,8 ==> 7-1, 7, 7+1 

从左下angular到右上angular对angular线的一种方法:

 2,4,6 ==> 4-2, 4, 4+2 

垂直赢得三种方法:

 0,3,6 ==> 3-3, 3, 3+3 1,4,7 ==> 4-3, 4, 4+3 2,5,8 ==> 5-3, 5, 5+3 

一种从左上angular向右下angular赢得胜利的方法:

 0,4,8 ==> 4-4, 4, 4+4 

阅读中间的列来获取魔术数字。

Octave / Matlab,97个字符,包括空格和换行符。 如果没有赢家,则输出0;如果玩家1赢了,则输出1;如果玩家2赢了,则输出2;如果两个玩家都“赢了”,则输出为2.0801:

 function r=d(b) a=reshape(b,3,3) s=prod([diag(a) diag(fliplr(a)) a a']) r=sum(s(s==1|s==8))^(1/3) 

如果我们改变规格并从头开始将b作为3x3matrix传递,我们可以删除重塑线,将其重新降低到80个字符。

因为没有人在tictactoe胜出时,我认为这是最短的代码

 echo 0; 

7个字符

更新:一个更好的条目是这样的:

86个字符或81个不包括函数定义(win())。

 win()for q in 1 28 55 3 12 21 4 20;{ [[ 3*w -eq B[f=q/8]+B[g=q%8]+B[g+gf] ]]&&break;} 

但是,这是在bash中由tic-tac-toe程序编写的代码,所以它不太符合规范。

 # player is passed in caller's w variable. I use O=0 and X=2 and empty=8 or 9 # if a winner is found, last result is true (and loop halts) else false # since biggest test position is 7 I'll use base 8. could use 9 as well but 10 adds 2 characters to code length # test cases are integers made from first 2 positions of each row # eg. first row (0 1 2) is 0*8+1 = 1 # eg. diagonal (2 4 6) is 2*8+4 = 20 # to convert test cases to board positions use X/8, X%8, and X%8+(X%8-X/8) # for each test case, test that sum of each tuplet is 3*player value 

ruby,85个字符

 def X(b) u=0 [2,6,7,8,9,13,21,-9].each do|c|u|=b[n=c/5+3]&b[n+c%5]&b[nc%5]end u end 

如果input有双方获胜,例如

      X |  O |  X
     --- + --- + ---
      X |  O |  Ø
     --- + --- + ---
      X |  O |  X

那么输出是3。

哈斯克尔,假设上面的魔方。 77个字符

77不包括import和定义b。

 import Data.Bits import Data.Array b = listArray (0,8) [2,1,0,1,1,1,2,2,0] wb = maximum[b!x.&.b!y.&.b!z|x<-[0..8],y<-[x+1..8],z<-[12-xy],z<8,z>=0,z/=y] 

或者82假设正常的sorting:

 {-# LANGUAGE NoMonomorphismRestriction #-} import Data.Bits import Data.Array b = listArray (0,8) [1,2,1,0,1,2,1,0,2] wb = maximum[b!x.&.b!y.&.b!z|x<-[0..8],d<-[1..4],y<-[x+d],z<-[y+d],d/=2||x==2,z<9] 

C,99个字符

不是赢家,但也许有改进的余地。 从来没有这样做过。 原始的概念,初稿。

 #define lw|=*b&b[s]&b[2*s];b+=3/s;s f(int*b){int s=4,w=0;l=3;l;l;l=2;--b;l=1;b-=3;l;l;return l;} 

感谢KennyTM的一些想法和testing工具。

“发展版”:

 #define lw|=*b&b[s]&b[2*s];b+=3/s;s // check one possible win f( int *b ) { int s=4,w=0; // s = stride, w = winner l=3; // check stride 4 and set to 3 l;l;l=2; // check stride 3, set to 2 --b;l=1; // check stride 2, set to 1 b-=3;l;l; return l; // check stride 1 } 

(铁)python,75个字符

全function75个字符

 T=lambda a:max(a[b/6]&a[b/6+b%6]&a[b/6+b%6*2]for b in[1,3,4,9,14,15,19,37]) 

如果你像其他一些人所做的那样忽略了这个函数定义,那么就有66个字符

 r=max(a[b/6]&a[b/6+b%6]&a[b/6+b%6*2]for b in[1,3,4,9,14,15,19,37]) 

8个不同的方向由起始值+增量值表示,压缩成可以使用除法和模块提取的单个数字。 例如2,5,8 = 2 * 6 + 3 = 15。

使用&运算符检查一行是否包含三个相等的值。 (如果不相等,结果为零)。 最大值是用来find可能的赢家。

C中的解决scheme(162个字符):

这利用了玩家一个值(1)和玩家两个值(2)具有独立的比特集的事实。 因此,可以将三个testing框的值按位进行AND运算 – 如果值不为零,则所有三个值必须相同。 另外,由此产生的价值==赢得的玩家。

目前还不是最短的解决scheme,但我可以做的最好:

 void fn(){ int L[]={1,0,1,3,1,6,3,0,3,1,3,2,4,0,2,2,0}; int s,t,p,j,i=0; while (s=L[i++]){ p=L[i++],t=3; for(j=0;j<3;p+=s,j++)t&=b[p]; if(t)putc(t+'0',stdout);} } 

更可读的版本:

 void fn2(void) { // Lines[] defines the 8 lines that must be tested // The first value is the "Skip Count" for forming the line // The second value is the starting position for the line int Lines[] = { 1,0, 1,3, 1,6, 3,0, 3,1, 3,2, 4,0, 2,2, 0 }; int Skip, Test, Pos, j, i = 0; while (Skip = Lines[i++]) { Pos = Lines[i++]; // get starting position Test = 3; // pre-set to 0x03 (player 1 & 2 values bitwise OR'd together) // search each of the three boxes in this line for (j = 0; j < 3; Pos+= Skip, j++) { // Bitwise AND the square with the previous value // We make use of the fact that player 1 is 0x01 and 2 is 0x02 // Therefore, if any bits are set in the result, it must be all 1's or all 2's Test &= b[Pos]; } // All three squares same (and non-zero)? if (Test) putc(Test+'0',stdout); } } 

Python,102个字符

由于您没有真正指定如何获取input和输出,因此这是可能必须封装到函数中的“原始”版本。 b是input表; r是输出(0,1或2)。

 r=0 for a,c in zip("03601202","11133342"):s=set(b[int(a):9:int(c)][:3]);q=s.pop();r=r if s or r else q 

Lua,130个字符

130个字符只是function大小。 如果找不到匹配,函数将返回任何内容,在Lua中类似于返回false。

 function f(t)z={7,1,4,1,1,3,2,3,3}for b=1,#z-1 do i=z[b]x=t[i]n=z[b+1]if 0<x and x==t[i+n]and x==t[i+n+n]then return x end end end assert(f{1,2,1,0,1,2,1,0,2}==1) assert(f{1,2,1,0,0,2,1,0,2}==nil) assert(f{1,1,2,0,1,2,1,0,2}==2) assert(f{2,1,2,1,2,1,2,1,2}==2) assert(f{2,1,2,1,0,2,2,2,1}==nil) assert(f{1,2,0,1,2,0,1,2,0}~=nil) assert(f{0,2,0,0,2,0,0,2,0}==2) assert(f{0,2,2,0,0,0,0,2,0}==nil) assert(f{0,0,0,0,0,0,0,0,0}==nil) assert(f{1,1,1,0,0,0,0,0,0}==1) assert(f{0,0,0,1,1,1,0,0,0}==1) assert(f{0,0,0,0,0,0,1,1,1}==1) assert(f{1,0,0,1,0,0,1,0,0}==1) assert(f{0,1,0,0,1,0,0,1,0}==1) assert(f{0,0,1,0,0,1,0,0,1}==1) assert(f{1,0,0,0,1,0,0,0,1}==1) assert(f{0,0,1,0,1,0,1,0,0}==1) 

Visual Basic 275 254(带宽松打字)字符

  Function W(ByVal b()) Dim r For p = 1 To 2 If b(0) = b(1) = b(2) = p Then r = p If b(3) = b(4) = b(5) = p Then r = p If b(6) = b(7) = b(8) = p Then r = p If b(0) = b(3) = b(6) = p Then r = p If b(1) = b(4) = b(7) = p Then r = p If b(2) = b(5) = b(8) = p Then r = p If b(0) = b(4) = b(8) = p Then r = p If b(6) = b(4) = b(2) = p Then r = p Next Return r End Function 

下面的JavaScript函数“w”是114个字符

 <html> <body> <script type="text/javascript"> var t = [0,0,2,0,2,0,2,0,0]; function w(b){ i = '012345678036147258048642'; for (l=0;l<=21;l+=3){ v = b[i[l]]; if (v == b[i[l+1]]) if (v == b[i[l+2]]) return v; } } alert(w(t)); </script> </body> </html> 

J,97个字符。

 1+1 i.~,+./"2>>(0 4 8,2 4 6,(],|:)3 3$i.9)&(e.~)&.>&.>(]<@:#"1~[:#:[:i.2^#)&.>(I.@(1&=);I.@(2&=)) 

我打算发表解释如何工作,但那是昨天,现在我不能读这个代码。

这个想法是我们创build一个所有可能的获胜三元组(048,246,012,345,678,036,147,258)的列表,然后使每个玩家拥有的正方形的幂,然后相交这两个列表。 如果有一场比赛,那就是胜利者。

Python – 75个字​​符(64)

我想出了2个expression式,每个64个expression式:

 max(a[c/8]&a[c/8+c%8]&a[c/8-c%8]for c in map(ord,'\t\33$#"!+9')) 

 max(a[c/5]&a[c/5+c%5]&a[c/5+c%5*2]for c in[1,3,4,8,12,13,16,31]) 

当你添加“W = lambda b:”来使它成为一个函数时,这使得75chars。 到目前为止最短的Python?

Python,285字节

 b,p,q,r=["."]*9,"1","2",range while"."in b: w=[b[i*3:i*3+3]for i in r(3)]+[b[i::3]for i in r(3)]+[b[::4],b[2:8:2]] for i in w[:3]:print i if["o"]*3 in w or["x"]*3 in w:exit(q) while 1: m=map(lambda x:x%3-x+x%3+7,r(9)).index(input()) if"."==b[m]:b[m]=".xo"[int(p)];p,q=q,p;break 

…哦,当你说“Code Golf:Tic Tac Toe”时,这不是你的意思吗? ;)(input数字键盘的数字来放置x的或o的,即7是西北)

长版本

 board = ["."]*9 # the board currentname = "1" # the current player othername = "2" # the other player numpad_dict = {7:0, 8:1, 9:2, # the lambda function really does this! 4:3, 5:4, 6:5, 1:6, 2:7, 3:8} while "." in board: # Create an array of possible wins: horizontal, vertical, diagonal wins = [board[i*3:i*3+3] for i in range(3)] + \ # horizontal [board[i::3] for i in range(3)] + \ # vertical [board[::4], board[2:8:2]] # diagonal for i in wins[:3]: # wins contains the horizontals first, print i # so we use it to print the current board if ["o"]*3 in wins or ["x"]*3 in wins: # somebody won! exit(othername) # print the name of the winner # (we changed player), and exit while True: # wait for the player to make a valid move position = numpad_dict[input()] if board[position] == ".": # still empty -> change board if currentname == "1": board[position] = "x" else: board[position] = "o" currentname, othername = othername, currentname # swap values 

我相信有一个更短的方法来做到这一点,但… Perl,141个字符(函数内的134)

 sub t{$r=0;@b=@_;@w=map{[split//]}split/,/,"012,345,678,036,147,258,048,246";for(@w){@z=map{$b[$_]}@$_;$r=$z[0]if!grep{!$_||$_!=$z[0]}@z;}$r;} 

c – 144个字符

精缩:

 #define A(x) a[b[x%16]] int c,b[]={4,8,0,1,2,4,6,0,3,4,5,2,8,6,7,2};int T(int*a){for(c=0;c<16;c+=2)if(A(c)&A(c+1)&A(c+2))return A(c);return 0;} 

两个回报计数(一个必要的和另一个将需要更换一个空间)。

arrays代码为八个方式赢得三倍从偶数位置开始,并采取国防部16。

从Eric Pi盗取的Bitwise和诡计。


更可读的forms:

 #define A(x) a[b[x%16]] // Compact coding of the ways to win. // // Each possible was starts a position N*2 and runs through N*2+2 all // taken mod 16 int c,b[]={4,8,0,1,2,4,6,0,3,4,5,2,8,6,7,2}; int T(int*a){ // Loop over the ways to win for(c=0;c<16;c+=2) // Test for a win if(A(c)&A(c+1)&A(c+2))return A(c); return 0; } 

testing脚手架:

 #include <stdlib.h> #include <stdio.h> int T(int*); int main(int argc, char**argv){ int input[9]={0}; int i, j; for (i=1; i<argc; ++i){ input[i-1] = atoi(argv[i]); }; for (i=0;i<3;++i){ printf("%1i %1i %1i\n",input[3*i+0],input[3*i+1],input[3*i+2]); }; if (i = T(input)){ printf("%c wins!\n",(i==1)?'X':'O'); } else { printf("No winner.\n"); } return 0; } 

也许可以做得更好,但我现在不是特别聪明。 这只是为了确保Haskell得到代表…

假设b已经存在,这将把结果放在w

 import List al=2*minimum l-maximum l z=take 3$unfoldr(Just .splitAt 3)b w=maximum$0:map a(z++transpose z++[map(b!!)[0,4,8],map(b!!)[2,4,6]]) 

假设从标准input和输出到标准输出,

 import List al=2*minimum l-maximum l wb=maximum$0:map a(z++transpose z++[map(b!!)[0,4,8],map(b!!)[2,4,6]])where z=take 3$unfoldr(Just .splitAt 3)b main=interact$show.w.read 

C#,180个字符:

 var s=new[]{0,0,0,1,2,2,3,6}; var t=new[]{1,3,4,3,2,3,1,1}; return(s.Select((p,i)=>new[]{g[p],g[p+t[i]],g[p+2*t[i]]}).FirstOrDefault(l=>l.Distinct().Count()==1)??new[]{0}).First(); 

g是网格)

可能可以改善…我仍然在努力;)

Python,140个字符

我的第一个代码是高尔夫球,重达140字(import声明,我否认你!):

 import operator as o def c(t):return({1:1,8:2}.get(reduce(o.mul,t[:3]),0)) def g(t):return max([c(t[x::y]) for x,y in zip((0,0,0,1,2,2,3,6),(1,3,4,3,3,2,1,1))]) 

不太模糊的g:

 def g(t):return max([c(t[x::y]) for x,y in [[0,1],[0,3],[0,4],[1,3],[2,3],[2,2],[3,1],[6,1]]]) 

C#解决scheme。

乘以每一行中的值,列和对angular线。 如果结果== 1,X胜。 如果结果== 8,O胜。

 int v(int[] b) { var i = new[] { new[]{0,1,2}, new[]{3,4,5}, new[]{6,7,8}, new[]{0,3,6}, new[]{1,4,7}, new[]{2,5,8}, new[]{0,4,8}, new[]{2,4,6} }; foreach(var a in i) { var n = b[a[0]] * b[a[1]] * b[a[2]]; if(n==1) return 1; if(n==8) return 2; } return 0; } 

C#,154 163 170 177个字符

从其他提交借用一些技术。 (不知道C#让你像这样初始化数组)

 static int V(int[] b) { int[] a={0,1,3,1,6,1,0,3,1,3,2,3,0,4,2,2}; int r=0,i=-2; while((i+=2)<16&&(r|=b[a[i]]&b[a[i]+a[i+1]]&b[a[i]+a[i+1]*2])==0){} return r; } 

C,113个字符

 f(int*b){char*s="012345678036147258048264\0";int r=0;while(!r&&*s){int q=r=3;while(q--)r&=b[*s++-'0'];}return r;} 

我认为它的作品? 我的第一个代码高尔夫,要温柔。

每3位数字编码需要匹配的3个单元。 内在的同时检查一个黑社会。 外面的时候全部检查8。

Interesting Posts