答案出来了.其中细节还需要仔细回味.
http://www.itpub.net/thread-2048956-1-1.html
最自然的解题思路,就是模拟真人下棋的情况,而SQL的优势在于它不会放过每个可能下子的位置,最终自然会得到所有的结局。从空棋盘开始,尝试在每个空位下子,每下一子就查看是否出现胜局,如果胜负已分则不再继续。所有空位已满也不再继续。
递归WITH子查询允许你在递归部分进行很多灵活的判断和计算,我们可以在这个递归部分拼出当前棋局、下子的顺序,以及判断胜负。
为了判断胜负,可以事先把所有获胜的三子连线情况都找出来,然后每下一步都进行匹配。匹配方式也有多种思路,我偏爱用BITAND的方法,即把棋盘的每一个位置用二进制的一位来表示,空位为0, 有子则为1,这样用POWER(2,9)就可以表示整个棋盘的占位情况,而每种获胜的情况则是三个二进制数相加;用BITAND可以得知某一棋局在三个获胜位是否全部都有棋子。
第一步先来生成棋盘布局,按要求把棋盘的位置编号1-9, 同时算出这个位子的二进制表示,及其行列坐标,用如下的子查询实现:
-
WITH
-
cells AS (SELECT LEVEL pos,POWER(2,LEVEL-1) b,CEIL(LEVEL/3) r,MOD(LEVEL-1,3)+1 c FROM DUAL CONNECT BY LEVEL<=9)
-
-
-
-
-
-
-
,w (win_bits,cnt,r,c,direction) as (
-
-
SELECT b,1,r,c,direction FROM cells,(SELECT LEVEL direction FROM DUAL CONNECT BY LEVEL<=4)
-
UNION ALL
-
SELECT w.win_bits+cells.b,w.cnt+1,cells.r,cells.c ,w.direction
-
FROM w,cells
-
WHERE w.cnt<3
-
-
AND (direction=1 AND cells.c=w.c AND cells.r=w.r+1
-
OR direction=2 AND cells.r=w.r AND cells.c=w.c+1
-
OR direction=3 AND cells.r=w.r+1 AND cells.c=w.c+1
-
OR direction=4 AND cells.r=w.r+1 AND cells.c=w.c-1
-
)
-
)
-
,win as (select win_bits from w where cnt=3)
-
-
,t(board
-
,x
-
,o
-
,step
-
,winner
-
,moves
-
)
-
AS (
-
-
SELECT CAST(RPAD('-',pos-1,'-')||'X'||RPAD('-',9-pos,'-') AS VARCHAR2(9)) board
-
,b X
-
,0 O
-
,1
-
,CAST(NULL AS VARCHAR2(1))
-
,CAST(pos AS VARCHAR2(10))
-
FROM cells
-
UNION ALL
-
-
SELECT SUBSTR(t.board,1,cells.pos-1)
-
||CASE WHEN MOD(t.step,2)=0 THEN 'X' ELSE 'O' END
-
||SUBSTR(t.board,cells.pos+1)
-
,CASE WHEN MOD(t.step,2)=0 THEN t.x+cells.b ELSE t.x END
-
,CASE WHEN MOD(t.step,2)=1 THEN t.o+cells.b ELSE t.o END
-
,t.step+1
-
,CASE WHEN MOD(t.step,2)=0
-
THEN (SELECT 'X' FROM win WHERE BITAND(t.x+cells.b,win.win_bits)=win.win_bits AND ROWNUM=1)
-
ELSE (SELECT 'O' FROM win WHERE BITAND(t.o+cells.b,win.win_bits)=win.win_bits AND ROWNUM=1)
-
END
-
,moves||cells.pos
-
FROM t JOIN cells ON BITAND(t.x+t.o,cells.b)=0
-
WHERE t.winner IS NULL
-
)
-
-
SELECT WINNER,COUNT(*) FROM (
-
SELECT moves
-
,board
-
,NVL(winner,'D') AS WINNER
-
FROM T
-
WHERE WINNER IS NOT NULL OR STEP=9
-
-
) GROUP BY WINNER;
-
-
SELECT WINNER,COUNT(*) FROM T WHERE WINNER IS NOT NULL OR STEP=9 GROUP BY WINNER;
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29254281/viewspace-1965923/
,如需转载,请注明出处,否则将追究法律责任。