百科问答小站 logo
百科问答小站 font logo



把围棋棋盘上下边和左右边连起来,变成面包圈,下棋策略会有什么变化? 第1页

  

user avatar   pandanokungfu 网友的相关建议: 
      

大开脑洞:完美的棋盘是什么样的

潘达按:本文作者 @萤-时光灯 ,写这篇文章的灵感来自于一次阅读刘慈欣小说时候突发的畅想。本文首发于微信公众号:奇略研究所。潘达参与编辑本文。

————————————————————————————————————————

从AIphaGo到超现实数,围棋始终是工程师们的沙盘,数学宝宝们的游乐场。不过,这些科学家研究的对象都是下棋的策略。今天就让我们来返璞归真一下,站在巨人的肩上,从数学的角度来解读一下承载这种美丽游戏的背景——棋盘吧。

围棋的棋盘是一个19x19的正方形,我们叫它19路棋盘。古代的时候也有用17路棋盘的。小朋友在刚学棋的时候也会用到13路和9路的棋盘。我们日常会用到的围棋盘都是这些正方形的。也有些人创造性地使用地图形状的棋盘,但是在我看来,这些都不是最完美的棋盘。

完美的棋盘,首先应该没有“特殊”的交叉点——每个交叉点都应该恰好与另外四个交叉点相邻,不多不少。下面这张同心圆的棋盘就可以满足此要求。

那么,可以更给力一点吗?

当然是可以的 。

上面那张同心圆的棋盘,虽然每个点确实只有四个邻点,而且没有了“角”,但还有里、外两条“边”,仍不够对称。更完美的棋盘,在没有棋子的时候,应该是混沌一片,处处都是对称的。无论第一手下在哪里,都是一样的。第一手过后才有了两极,有了策略,有了胜负。

想要这样的棋盘其实很容易。只需要把这个正方形的棋盘卷一卷,卷成一个圆柱型,然后再折一折,折成一个甜甜圈就可以了。这里我们定义1=19, A=T,这样一个19路的普通棋盘就变成了18路的甜甜圈棋盘。

当然,已经有会玩的棋友想在我前面了。在LittleGolem这个网站上(感谢 @龚渠成 的推荐),就有一场正在进行的甜甜圈围棋锦标赛,有几十位棋友参加。(littlegolem.net/jsp/in/)上图的这张棋谱是两位高水平的爱好者在甜甜圈棋谱上的实战。请读者注意,这张棋盘实际上只有中间橙色的11路,周边灰色的部分只是辅助对弈者直观理解甜甜圈棋盘的。

可以看到,如果棋子下在了某一个角上,棋盘的灰色部分也对应地放上三枚棋子。假设棋子下在了边上,我们要同时在对面的边上也放上一样颜色的棋子。当然还有计算边上和角上的棋子的气的时候,要把对面的那一气也算进去。在网络围棋的时代,要实现这样一个棋盘太容易了,只需要用上面的定义,就可以把一个看上去方方正正的棋盘卷成一个甜甜圈棋盘。当然,这样还有很多不足,比如很多人会习惯性的忽略对手从棋盘的另一面搞突袭。这都是棋子间的距离不够直观导致的。也许正是因为这样的不足,所以这种理论上完美的棋盘只有少数人在玩。

(潘达按:别吐槽我离题啊,这段已经点题了!具体的甜甜圈围棋战略,可以看LittleGolem上的棋谱。)

那么,可以更更给力一点吗?

当然是可以的。

有没有可能把甜甜圈围棋盘搬到现实中来呢?有一位不愿意透露姓名的西方围棋爱好者,兼能工巧匠,就做出了一个真正的甜甜圈棋盘。

三十八条交叉的圆形铁丝,组成了纵横十九道的甜甜圈棋盘。这里的棋子也是特制的,在中心划了十字槽,可以嵌在交叉点上。

可惜,如此漂亮的实物甜甜圈棋盘,仍有几处瑕疵。在这个甜甜圈棋盘上,里圈的格子特别小,而棋盘的纵线也会比横线短很多,因此每个格子都不再是正方形的了。棋盘格子大小不相等,给棋手直观理解棋局带来了困难。比如离某颗棋子最远的地方在哪里,这种简单的策略也需要额外的思考时间。

那么,可以更更更给力一点吗?

当然还是可以的。

数学上已经有前辈把我们所遇到的这些难题通通解决了。这个人就是约翰·纳什(John Nash)。你可能在经济学领域或者是在他对博弈论的贡献里听说过他的名字。你也可能看过以他的传记拍成的电影《美丽心灵》。电影里有他和好基友在校园里下围棋的场景。纳什就是这样,润物细无声地帮我们解决了上文提到的所有问题,但是却没有向大家透露,他解决的这些问题与围棋有什么关系。不过我想,懂一点围棋和数学的人看到他的嵌入理论(Nash Embedding Theorems)的时候,不难联想到围棋的棋盘。

纳什的嵌入理论就是做了两件事(为了不引入更多术语,我们只讨论甜甜圈棋盘这一种情况。嵌入理论可以应用在更广泛的领域上)。第一件事,嵌入理论可以把平面的正方形棋盘‘折’成一个类似甜甜圈的形状,使得棋盘上的每一个格子仍然保持相等的大小。这一步用到的具体定理又叫Nash-Kuiper定理,它保证了这种折叠的存在。而近年,一个法国数学家团队完成了这种折叠的具体构造,像是一个螺纹装饰的甜甜圈,见下图。

实现螺纹甜甜圈的技术挺难的,需要在普通甜甜圈的基础上做数次名为“起皱”的迭代,相当于一层层地给甜甜圈刻上螺纹。甜甜圈上螺纹的作用是,使得甜甜圈棋盘上每一格的长宽都相等。像这样保持原有图形距离关系的折叠,数学术语叫做等距映射(isometry)。

下图给出了折叠前的正方形棋盘,与折叠后螺纹甜甜圈棋盘上曲线的对应关系。正方形棋盘上原本的纵线(下图左方黑色纵线),在折叠后变成了螺纹甜甜圈上的一个截面的边缘(下图右方黑色的“雪花形”曲线)。熟悉数学的读者可能已经看出来,这条雪花形曲线是一种分形(fractal)。

那么,可以更更更更给力一点吗?

当然仍然是可以的。

我们历经艰险做出了螺纹甜甜圈形棋盘,但它仍有一个明显的缺陷:不够光滑。光滑在数学上的含义是,这个曲面上每个点的切面都是可以算出来的。但是螺纹甜甜圈棋盘,首先它视觉上皱皱巴巴的我们人类不太可能用它下棋。其次,它数学上也不完美,虽然它每个点的切面都能算出来,但是某些局部的弯曲程度却是不连续的。用数学语言说,这些局部的二次导数是无法定义的。综上所述,我们必须通过第二步来完善这个棋盘。当然,得到这个结果已经很厉害了,手残党如我折出的棋盘有棱有角,切面都不能保证存在的呀。

第二步,把甜甜圈上任意多的点放到一个高维度的欧几里得空间,并且保留了原有的甜甜圈上每个点之间的距离关系。在这个新的高维的棋盘上,棋盘的面确实是平滑的,你可以对每个点算导数算到地老天荒。而且视觉上,我们上一步被折的皱皱巴巴的棋盘,在这一步重新得以平展开了。纳什证明了对于甜甜圈这样的m=2曲面来说,寻找嵌入所需要的维度数不会超过 m^2+5m+3=17维。不要被这么高的维度吓到,这只是一个上限。可以作用于任何形状的甜甜圈上任意的点。而我们的棋盘可能更特殊,所以幸运的话可能不需要那么多维度就可以解决问题了。

光说不练假把式。下面就让我们从4路开始,来体验一下这个高(维度)大(脑洞)上(档次)的甜甜圈棋盘吧。那我们先从5x5的正方形棋盘开始,给每个点都标上坐标。注意边和角的坐标都是重复的。一共有16个坐标。

然后,我们算一下每两个点之间的距离,从白色方块开始我们有可能走出并,尖,单关跳,小飞和象步。但是大飞和拆二就不行了。

然后,我们拿出一个四维的立方体。把立方体的 16个顶点依次标上原来的坐标。一个闪闪发光的四维甜甜圈棋盘就做好了。

验证一下,在四维立方体上,同样任意两点之间的距离,同样起于白色方块我们可以得到和平面上一样的结果。

那么,还可以更更更更更给力一点吗?

额…… 这个问题,我也遇到困难了。刚才我示范的是四路棋盘,但更高路数的棋盘,我也不知道答案。

3路棋盘在三维里的光滑嵌入我猜测是行不通的。如果4路棋盘需要4维空间实现嵌入,那么5路棋盘需要几维空间呢?17路,19路棋盘,是不是就需要用到最高的17维才能嵌入了呢?我在这里抛砖引玉,希望读者中有大牛能完美地解答这个开放性问题。

不过,无论是这个完美的棋盘是需要嵌入四维空间,还是十七维空间,想在这个棋盘上下棋,首先我们得进入高维空间呢。读者朋友们,如果做出了这张完美棋盘,那我们就在高维空间见面下棋吧!


user avatar   liu-yang-zhou-23 网友的相关建议: 
      

最后附上福利——

先看具体的例子感受一下:

例 1

上图局面在正常棋盘下,黑棋总是差一气,最终被提吃,但是在环面 的情况又是如何呢?

黑长,我们看到黑棋实际上有三口气,

我们知道白棋暂时提子无望。不过我想让白棋强杀一下黑棋:

  • 如果打吃在右(左)边(其实这个时候已经没有左右之分,但是限制在局部而言是可以这么说的,上下也是同理),那么黑棋容易逃脱;
  • 如果打吃在下方(实际上是上方),

这个时候,白棋被叫吃,只好反叫吃,黑棋弃子逃跑,

这个时候出现了奇观,黑棋出路太多,跑得太快,白棋吃子失败。

例 2

至于征吃:



黑棋沿着 上同胚于 的闭合曲线逃跑,这当然回魂乏术了。

分析

正如上一位网友回答,是紧致无边流形,所以每一个点都属于环面的内点,由于环面高度对称性,所以“战略要点”就失去了意义,因为每一个点都是一样的。

反观我们通常的棋盘,正是由于角部、边界的特殊性,所以在吃子、围空提供了普通内点不具有的先天优势,于是变成了“兵家必争”。

回到环面。所以,单纯地吃子恐怕是很困难的,因为逃跑太容易了,这个与我们在通常棋盘打吃中腹的子一样困难。所以策略是围空优先,顺便侵消对方的实地。这个时候考验的是玩家对中腹能力的掌控。

最后说贴目,这个时候先手优势太小了,肯定不能贴七目半了,我感觉先手价值应该是两子。

福利

我之前写过一个围棋程序,在那个基础上稍加改动即可得到环面上的围棋(R 语言)——

       GoT2 <- function(n=19) {     ###初始设置     ##构造棋盘     if (!interactive()) return()     par(mar = rep(0, 4),bg = rgb(0.9296875, 0.6757812, 0.0546875))     plot(1:n, type = "n", xlim = c(1, n), ylim = c(0, n), axes = FALSE, xlab = "",          ylab = "", bty = "o", lab = c(n, n, 1))     text( 3,0,"落子无悔",cex=1)     text(17,0,"一生好走",cex=1)     segments(1, 1:n, n, 1:n)     segments(1:n, 1, 1:n, n)     points(rep(c(4, 10, 16), 3), rep(c(4, 10, 16), each = 3),           pch = 19, cex = 1.2)        box()      ##四大列表初始设置     playedlist <- list(c(),c())    #当前盘面     vplay <-c()     history <- list(list())    #历史记录     re <- 0    #悔棋指标     conset <- list(list(),list())    #连通分支列表,是二重嵌套列表,第一子列表属黑棋,第二属白棋     bouset <- list(list(0+0i),list(0+0i))    #连通分支边界列表,同上     hiscon <- list(list())     hisbou <- list(list())     ncb=c(0,0)    #分支数     ntake <- c(0,0);eat <- 0     hisncb <- list()     hisntake <- list()            ##棋盘特殊位置     SW<-1+1i    #棋盘四角     SE<-19+1i     NE<-19+19i     NW<-1+19i     S<- 2:18+1i    #棋盘四边(不含角)     E<- complex(0,19,2:18)     N<- 2:18+19i     W<- complex(0,1,2:18)     dire<-c(1i,-1i,-1,1)    #棋盘四合      ##边界函数Bd(从中去掉历史位置即可得到“气”)     Bd<-function(A)     {          B=c()          for(a in A)          {              pa <- a+dire                pa <- complex(0, Re(pa)%%19, Im(pa)%%19)              for(i in 1:4)              {                  if(Re(pa[i])==0)pa[i]<-complex(0,19,Im(pa[i]))                  if(Im(pa[i])==0)pa[i]<-complex(0,Re(pa[i]),19)              }              for(i in pa) if(!is.element(i,A)) B=c(B,i)          }          B     }      ##提子     take <- function(A)     {         if(is.element(SE,A))         {             points(19,1, cex = 3, pch = 19, col = rgb(0.9296875, 0.6757812, 0.0546875))             segments(18.5,1,19,1)             segments(19,1,19,1.5)             A <- setdiff(A,SE)         }         if(is.element(SW,A))         {             points(1,1, cex = 3, pch = 19, col = rgb(0.9296875, 0.6757812, 0.0546875))             segments(1,1,1.5,1)             segments(1,1,1,1.5)             A <- setdiff(A,SW)         }         if(is.element(NE,A))         {             points(19,19, cex = 3, pch = 19, col = rgb(0.9296875, 0.6757812, 0.0546875))             segments(18.5,19,19,19)             segments(19,18.5,19,19)             A <- setdiff(A,NE)         }         if(is.element(NW,A))         {             points(1,19, cex = 3, pch = 19, col = rgb(0.9296875, 0.6757812, 0.0546875))             segments(1,19,1.5,19)             segments(1,18.5,1,19)             A <- setdiff(A,NW)         }         EE <- intersect(E,A);WW <- intersect(W,A)         SS <- intersect(S,A);NN <- intersect(N,A)         A <- setdiff(A,c(EE,WW,SS,NN))         if(length(A)>0)         {             x <- Re(A);y <- Im(A)             points(x,y, cex = 3, pch = 19, col = rgb(0.9296875, 0.6757812, 0.0546875))             segments(x-0.5,y,x+0.5,y)             segments(x,y-0.5,x,y+0.5)         }         if(length(EE)>0)         {             x <- Re(EE);y <- Im(EE)             points(x,y, cex = 3, pch = 19, col = rgb(0.9296875, 0.6757812, 0.0546875))             segments(x-0.5,y,x,y)             segments(x,y-0.5,x,y+0.5)         }         if(length(WW)>0)         {             x <- Re(WW);y <- Im(WW)             points(x,y, cex = 3, pch = 19, col = rgb(0.9296875, 0.6757812, 0.0546875))             segments(x,y,x+0.5,y)             segments(x,y-0.5,x,y+0.5)         }         if(length(SS)>0)         {             x <- Re(SS);y <- Im(SS)             points(x,y, cex = 3, pch = 19, col = rgb(0.9296875, 0.6757812, 0.0546875))             segments(x-0.5,y,x+0.5,y)             segments(x,y,x,y+0.5)         }         if(length(NN)>0)         {             x <- Re(NN);y <- Im(NN)             points(x,y, cex = 3, pch = 19, col = rgb(0.9296875, 0.6757812, 0.0546875))             segments(x-0.5,y,x+0.5,y)             segments(x,y-0.5,x,y)         }         if(is.element(4+4i,A))points(4+4i, cex = 1.2, pch = 19)         if(is.element(4+10i,A))points(4+10i, cex = 1.2, pch = 19)         if(is.element(4+16i,A))points(4+16i, cex = 1.2, pch = 19)         if(is.element(10+4i,A))points(10+4i, cex = 1.2, pch = 19)         if(is.element(10+10i,A))points(10+10i, cex = 1.2, pch = 19)         if(is.element(10+16i,A))points(10+16i, cex = 1.2, pch = 19)         if(is.element(16+4i,A))points(16+4i, cex = 1.2, pch = 19)         if(is.element(16+10i,A))points(16+10i, cex = 1.2, pch = 19)         if(is.element(16+16i,A))points(16+16i, cex = 1.2, pch = 19)     }     ##气的提示     qi <- function()     {         tp1 <- matrix(,ncb[1],2)         for(i in 1:ncb[1]) tp1[i,] <- c(length(bouset[[1]][[i]]),conset[[1]][[i]][1])         d1 <- tp1[order(tp1[,1]),]         d1 <- data.frame(黑方气数=Re(d1[,1]),分支位置=d1[,2])         print(d1)         tp2 <- matrix(,ncb[2],2)         for(i in 1:ncb[2]) tp2[i,] <- c(length(bouset[[2]][[i]]),conset[[2]][[i]][1])         d2 <- tp2[order(tp2[,1]),]         d2 <- data.frame(白方气数=Re(d2[,1]),分支位置=d2[,2])         print(d2)      }       ###进入对弈     k <- 0     repeat         {         for (j in 1:2)    ##黑白交替落子         {             repeat             {                 l <- locator(1)    #获得落子坐标                 l$x <- round(l$x)                 l$y <- round(l$y)                 xy <- complex(0,l$x,l$y)                 if (!is.element(xy, vplay))break    #禁走历史位置             }              ##悔棋             Cex <- 1             if(k>99)Cex <- 0.8             if(l$y<0.5)             {                 take(vplay)                 history[[k]] <- NULL                 k <- k-1                 playedlist <- history[[k]]                 vplay <- unlist(playedlist)                 conset <- hiscon[[k]]                 bouset <- hisbou[[k]]                 ncb <- hisncb[[k]]                 ntake <- hisntake[[k]]                 Bx <- Re(history[[k]][[1]]);By <- Im(history[[k]][[1]])                 Wx <- Re(history[[k]][[2]]);Wy <- Im(history[[k]][[2]])                 points(Bx, By, cex = 3, pch = 19, bg = "black")                 points(Wx, Wy, cex = 3, pch = 21, bg = "white")                 text(Bx,By+0.06,seq(1,k,2),cex=Cex,col="white")                 text(Wx,Wy+0.06,seq(2,k,2),cex=Cex,col="black")                 if(min(ncb)>2)qi()                 re <- 1             }             if(re == 1){re <- 0;next}              #落子             k <- k+1             points(l, cex = 3, pch = c(19, 21)[j], bg = c("black", "white")[j])             text(l$x,l$y+0.06,k,cex=Cex,col=c("white","black")[j])                                  ##损气提吃             s=1             while(s<=ncb[3-j])             {                   opp <- bouset[[3-j]][[s]]                               if(is.element(xy,opp))                 {                     if(length(opp)==1)                     {                         playedlist[[3-j]] <- setdiff(playedlist[[3-j]],conset[[3-j]][[s]])                         vplay <-unlist(playedlist)                         take(conset[[3-j]][[s]])    #提子                         ntake[j] <- ntake[j]+length(conset[[3-j]][[s]]);eat <- 1                         bouset[[3-j]][[s]] <- NULL                             conset[[3-j]][[s]]<-NULL                         ncb[3-j] <- ncb[3-j]-1    #对方分支数减少                         for(t in 1:ncb[j])                         {                             bouset[[j]][[t]] <- setdiff(Bd(conset[[j]][[t]]),vplay)                         }                         s <- s-1                     }else{                     bouset[[3-j]][[s]] <- setdiff(opp,xy)                                }                 }                 s <- s+1             }                          ###构造三大列表(历史、连通分支、边界)             p=0    #分支构建指标(p>0分支合并、p=0新建分支)             U <- c()    #合并分支             i <- 1;r<- c()             while(i<=ncb[j])              {                 if(ncb[j]==0) break                 if(is.element(xy, bouset[[j]][[i]]))    #新下的棋属于哪个连通分支                 {                     p <- p+1                     if(p==1)                     {                         q <- i                         U <- conset[[j]][[i]]                         conset[[j]][[i]]<-NULL                         bouset[[j]][[i]]<-NULL                         ncb[[j]] <- ncb[[j]]-1                         i <- i-1                     }                     if(p>1)                     {                         U <- union(U,conset[[j]][[i]])                         conset[[j]][[i]]<-NULL                         bouset[[j]][[i]]<-NULL                         i=i-1                         ncb[j] <- ncb[j]-1                      }                 }                 i <- i+1             }              ncb[j] <- ncb[j]+1             if(p==0){                 if(ncb[j]==0)                 {                     conset[[j]] <- list(xy)    #孤子建新支                     bouset[[j]] <- list(setdiff(Bd(xy),vplay))                 }else{                     conset[[j]][[ncb[j]]] <- xy                         bouset[[j]][[ncb[j]]] <- setdiff(Bd(xy),vplay)                      }             }else if(p==1){                 if(ncb[j]>0)                 {                     conset[[j]][[ncb[j]]] <- c(U,xy)                     bouset[[j]][[ncb[j]]] <- setdiff(Bd(c(U,xy)),vplay)                 }else{                     conset[[j]] <- list(c(U,xy))                     bouset[[j]] <- list(setdiff(Bd(c(U,xy)),vplay))                 }             }else{                 conset[[j]][[ncb[j]]] <- c(U,xy)                 bouset[[j]][[ncb[j]]] <- setdiff(Bd(c(U,xy)),vplay)             }              playedlist[[j]] <- c(playedlist[[j]], xy)             vplay <-unlist(playedlist)             history[[k]] <- playedlist             hiscon[[k]] <- conset             hisbou[[k]] <- bouset             hisncb[[k]] <- ncb             hisntake[[k]] <- ntake              if(min(ncb)>2)qi()              if(eat>0)             {                 print(list(黑方提子数=ntake[1],白方提子数=ntake[2]));eat <- 0             }              if (k >= n^2)break    ###满盘结束(满盘皆输555~)         }     if(k >= n^2) break     } } GoT2()       

为了表现环面的特征,下了一个智障的棋谱,大家可以品一品。另外,点击“落子无悔”可以悔棋哦~




  

相关话题

  为什么 AI 发展到今天,围棋能下过李世石、柯洁,仍不能完成帮人类洗衣物、做饭这种简单的事? 
  这个猜实数的游戏有没有必胜策略? 
  如何通过卫星图判断这架飞机距离地面的高度? 
  为什么 Google 翻译只重算法不重语言学的语法结构和规则? 
  为什么在脸部打马赛克的时候通常选择在眼部? 
  矩阵A和矩阵B相乘,AxB为什么不等于BxA? 
  如何看待 2020 届校招算法工程师岗位求职人数远大于招聘岗位的现象? 
  这个围棋棋局怎么解? 
  请问下面这个命题成立吗? 
  AlphaGo 战胜了李世石,人工智能突破了围棋领域,这意味着什么? 

前一个讨论
歌德,巴赫和哥德巴赫有什么联系?
下一个讨论
数学家 John Horton Conway 或因感染新型冠状病毒逝世,如何评价他一生的经历与贡献?





© 2024-05-15 - tinynew.org. All Rights Reserved.
© 2024-05-15 - tinynew.org. 保留所有权利