楼主: newkid

[精华] ITPUB第3届“盛拓传媒杯”SQL数据库编程大赛第2题及附加题参考解题思路

[复制链接]
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
21#
 楼主| 发表于 2015-12-21 22:42 | 只看该作者
Naldonado 发表于 2015-12-21 12:47
BITAND(t.o+cells.b,win.win_bits)=win.win_bits

这里不太懂,大叔能不能仔细讲一下如何用二进制来解决 ...

t.o是指O方到目前总共下了哪些子,是用二进制之和表示。
cells.b是指即将要下的新棋子。t.o+cells.b表示这一手下完O方总共有哪些棋子。
win_bits是指8种胜局之一,它是三个二进制数之和,转换成二进制之后有三个1

BITAND(a,b)=b就是把b作为掩码,过滤后只留下那几位,如果和b完全一致,说明这几位全部是1。

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
22#
 楼主| 发表于 2015-12-21 22:45 | 只看该作者
uc_jmh 发表于 2015-12-21 14:33
如果存在当前棋手能获胜的棋局,那么最终胜者为当前棋手,步数则是各种获胜走法中最少的步数加一。因为当前 ...

不明白你要问啥?
因为这是“军师”给我们的指点,现在轮到我走,军师说走这里能赢,我就选这里。
我改一下文本,把“能获胜”改成"必胜"。

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
23#
 楼主| 发表于 2015-12-21 22:49 | 只看该作者
uc_jmh 发表于 2015-12-21 14:54
能不能用一种更直白的思路呢?
试着往每一处可落子的位置落子,根据一定的游戏规则来给这一处的落子一个分 ...

网上搜到的下棋程序都是靠评分来的,因为完全搜索完代价太大。
你要自己设计一种评分系统也没问题,只要能回答出“谁能赢,最多走几步必定能赢”。
至于如何赢的,题目并不要求回答。

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
24#
 楼主| 发表于 2015-12-21 22:52 | 只看该作者
uc_jmh 发表于 2015-12-21 15:02
还是拿你的443来举例

上帖刚刚说过,题目只是问“谁能赢”,不是问“怎么赢”,获胜方法不是唯一的。
你说的6,7,10,11完全是对称的,这正是我的代码尽力要去除的东西。

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
25#
 楼主| 发表于 2015-12-21 22:56 | 只看该作者
uc_jmh 发表于 2015-12-21 15:20
简单说一下思路:
我们当7 8 5来看问题
当落一个字的时候要判断:

你的心太大了,棋局装不下。
我看你还是好好把3,3,3考虑清楚,再想别的。
你这些推理根本就不够严密。

使用道具 举报

回复
论坛徽章:
12
SQL数据库编程大师
日期:2016-01-13 10:30:43SQL大赛参与纪念
日期:2016-01-13 10:32:19秀才
日期:2016-01-06 14:01:09秀才
日期:2016-01-06 14:06:43秀才
日期:2016-01-06 14:07:02ITPUB社区OCM联盟徽章
日期:2015-04-01 11:16:20举人
日期:2016-01-22 18:01:09秀才
日期:2016-01-22 17:58:00秀才
日期:2016-01-22 17:58:00秀才
日期:2016-01-22 17:58:00
26#
发表于 2015-12-21 23:14 | 只看该作者
newkid 发表于 2015-12-21 22:56
你的心太大了,棋局装不下。
我看你还是好好把3,3,3考虑清楚,再想别的。
你这些推理根本就不够严密。

使用道具 举报

回复
论坛徽章:
6
秀才
日期:2015-07-14 09:44:30秀才
日期:2015-07-28 09:11:43巨蟹座
日期:2015-12-22 23:17:51白羊座
日期:2016-01-17 22:36:152016猴年福章
日期:2016-02-18 09:31:30奥运会纪念徽章:篮球
日期:2016-09-08 22:13:34
27#
发表于 2015-12-22 23:15 | 只看该作者
膜拜大神~

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
28#
 楼主| 发表于 2015-12-23 03:52 | 只看该作者
第二题的副产品是这个会下棋的包,里面只有两个过程,start_game和play
start_game可以带一个参数指定从哪一棋局开始下。不代参数指定从空棋盘开始而且是程序先手。
play带一个参数表明你下一子要下在哪个位置。
程序的应对下子会输出在屏幕上,事先要SET SERVEROUTPUT ON

CREATE OR REPLACE PACKAGE pkg_tictactoe AS

PROCEDURE start_game(p_board IN VARCHAR2 DEFAULT NULL);

PROCEDURE start_game(p_move IN NUMBER);

PROCEDURE play(p_move IN NUMBER);

END pkg_tictactoe;
/

CREATE OR REPLACE PACKAGE BODY pkg_tictactoe AS
     gv_board VARCHAR2(20);
     
     gv_empty VARCHAR2(1):='-';
     
     gv_size NUMBER :=9;
     
     gv_player VARCHAR2(1);

FUNCTION f_get_winner(p_board IN VARCHAR2) RETURN VARCHAR2
AS
  v_x VARCHAR2(1);
  v_o VARCHAR2(1);
BEGIN
  
  WITH
       m AS (SELECT LEVEL m,POWER(2,LEVEL-1) b,CEIL(LEVEL/3) r,MOD(LEVEL-1,3)+1 c FROM DUAL CONNECT BY LEVEL<=9)
       ,w (b,win_bits,cnt,r,c,t) as (
       SELECT b,b,1,r,c,t FROM m,(SELECT LEVEL t FROM DUAL CONNECT BY LEVEL<=4)
       UNION ALL
       SELECT m.b,w.win_bits+m.b,w.cnt+1,m.r,m.c ,w.t
        FROM w,m
       WHERE w.cnt<3
             AND (t=1 AND m.c=w.c AND m.r=w.r+1
                  OR t=2 AND m.r=w.r AND m.c=w.c+1
                  OR t=3 AND m.r=w.r+1 AND m.c=w.c+1
                  OR t=4 AND m.r=w.r+1 AND m.c=w.c-1
                  )
       )
       ,win as (select win_bits from w where cnt=3)
       SELECT (SELECT 'X' FROM win WHERE BITAND(x,win.win_bits)=win.win_bits AND ROWNUM=1) x_win
             ,(SELECT 'O' FROM win WHERE BITAND(o,win.win_bits)=win.win_bits AND ROWNUM=1) o_win
       INTO v_x,v_o
         FROM (SELECT NVL(SUM(CASE WHEN SUBSTR(p_board,m,1)='X' THEN m.b END),0) x
                     ,NVL(SUM(CASE WHEN SUBSTR(p_board,m,1)='O' THEN m.b END),0) o
                FROM m
              )
       ;

   IF v_x IS NOT NULL AND v_o IS NOT NULL THEN
      RAISE_APPLICATION_ERROR(-20001,'invalid winner! '||p_board);
   END IF;

   IF COALESCE(v_x,v_o) IS NULL AND REGEXP_COUNT(p_board,gv_empty)=0 THEN
      RETURN 'D';
   END IF;
   
   RETURN COALESCE(v_x,v_o);
   
END f_get_winner;

PROCEDURE print_board(p_board IN VARCHAR2,p_winner IN VARCHAR2 DEFAULT NULL)
AS
BEGIN
   IF gv_player IS NOT NULL THEN
      DBMS_OUTPUT.PUT_LINE('Your side: '||gv_player);
      DBMS_OUTPUT.PUT_LINE('=============');
   END IF;
   FOR i IN 1..3 LOOP
       DBMS_OUTPUT.PUT_LINE(SUBSTR(p_board,(i-1)*3+1,3));
   END LOOP;
   IF p_winner IS NOT NULL THEN
      DBMS_OUTPUT.PUT_LINE('========= '||CASE WHEN p_winner='D' THEN 'It''s a draw, game over' WHEN p_winner=gv_player THEN 'You win!' ELSE 'You lose!' END||' =========');
   END IF;
END print_board;


PROCEDURE check_valid(p_board IN VARCHAR2)
AS
  v_cell VARCHAR2(1);
  v_cnt_x NUMBER :=0;
  v_cnt_o NUMBER :=0;
  v_winner VARCHAR2(1);
BEGIN
   IF NOT LENGTH(p_board) BETWEEN 1 AND gv_size THEN
      RAISE_APPLICATION_ERROR(-20001,'invalid board! '||p_board||' size should be 1-'||gv_size);
   END IF;
   
   FOR i IN 1..LENGTH(p_board) LOOP
       v_cell := SUBSTR(p_board,i,1);
       IF v_cell NOT IN (gv_empty,'X','O') THEN
          RAISE_APPLICATION_ERROR(-20001,'invalid board! '||p_board||' position:'||i);
       END IF;
      
       IF v_cell='X' THEN
          v_cnt_x := v_cnt_x +1;
       END IF;

       IF v_cell='O' THEN
          v_cnt_o := v_cnt_o +1;
       END IF;
      
   END LOOP;
   
   IF v_cnt_x - v_cnt_o NOT IN (0,1) THEN
      RAISE_APPLICATION_ERROR(-20001,'invalid move count! '||p_board);
   END IF;
   
   v_winner := f_get_winner(p_board);

   IF v_winner='X' AND v_cnt_x = v_cnt_o
         OR v_winner='O' AND v_cnt_x <> v_cnt_o
   THEN
         RAISE_APPLICATION_ERROR(-20001,'invalid board, no move is allowed after game is over '||p_board);
   END IF;
  
END check_valid;


PROCEDURE move(p_board IN VARCHAR2)
AS
  v_winner VARCHAR2(1);
  
BEGIN
  v_winner := f_get_winner(p_board);

-- DBMS_OUTPUT.PUT_LINE('gv_player='||gv_player);
  
  IF v_winner IS NOT NULL THEN
     print_board(p_board,v_winner);
     RETURN;
  END IF;
  
  
WITH
m AS (SELECT LEVEL m,POWER(2,LEVEL-1) b,CEIL(LEVEL/3) r,MOD(LEVEL-1,3)+1 c FROM DUAL CONNECT BY LEVEL<=9)
,w (b,win_bits,cnt,r,c,t) as (
SELECT b,b,1,r,c,t FROM m,(SELECT LEVEL t FROM DUAL CONNECT BY LEVEL<=4)
UNION ALL
SELECT m.b,w.win_bits+m.b,w.cnt+1,m.r,m.c ,w.t
FROM w,m
WHERE w.cnt<3
      AND (t=1 AND m.c=w.c AND m.r=w.r+1
           OR t=2 AND m.r=w.r AND m.c=w.c+1
           OR t=3 AND m.r=w.r+1 AND m.c=w.c+1
           OR t=4 AND m.r=w.r+1 AND m.c=w.c-1
           )
)
,win as (select win_bits from w where cnt=3)
-----------把当前局面当作根节点,生成当前局面往下的游戏树
,t(board  ----- 到目前为止所有X,O的分布
  ,x ------- X下过了哪些位置,用二进制之和表示
  ,o ------- O下过了哪些位置,用二进制之和表示
  ,step ----- 当前走了几步(双方一共下了几子)
  ,winner ----- 如果胜负已分,在这里标出
  ,prior_board ----- 指明当前BOARD是从哪一个变化而来
  ,rn    ------- 利用分析函数ROW_NUMBER()为每一对(prior_board,board)仅仅保留一行数据
  )
AS (
------ 从给定棋局开始生成游戏树
SELECT CAST(p_board AS VARCHAR2(9)) board
      ,x
      ,o
      ,step
      ,CASE WHEN MOD(step,2)=1 THEN (SELECT 'X' FROM win WHERE BITAND(x,win.win_bits)=win.win_bits AND ROWNUM=1) ----看看此棋局是否已分胜负
            ELSE (SELECT 'O' FROM win WHERE BITAND(o,win.win_bits)=win.win_bits AND ROWNUM=1)
       END  AS  winner
      ,CAST('' AS VARCHAR2(9)) prior_board
      ,1
  FROM (------ 从给定棋局计算X,O的二进制的值
        SELECT NVL(SUM(CASE WHEN SUBSTR(p_board,m,1)='X' THEN m.b END),0) x
              ,NVL(SUM(CASE WHEN SUBSTR(p_board,m,1)='O' THEN m.b END),0) o
              ,9-REGEXP_COUNT(p_board,'-') step
         FROM m
       )
UNION ALL
SELECT SUBSTR(t.board,1,m.m-1)  ------ 把选中的下一个棋子按照其位置拼到棋盘中去。其位置即m.m表示的1-9的整数
       ||CASE WHEN MOD(t.step,2)=0 THEN 'X' ELSE 'O' END ----- 根据当前步数算出下一个子应该是X或者O
       ||SUBSTR(t.board,m.m+1)  AS board
      ,CASE WHEN MOD(t.step,2)=0 THEN t.x+m.b ELSE t.x END AS X---- 如果下一子是X, 把其二进制叠加到t.x,否则保持原样
      ,CASE WHEN MOD(t.step,2)=1 THEN t.o+m.b ELSE t.o END AS O---- 对O的处理,方法同上
      ,t.step+1
      ,CASE WHEN MOD(t.step,2)=0
            THEN (SELECT 'X' FROM win WHERE BITAND(t.x+m.b,win.win_bits)=win.win_bits AND ROWNUM=1) ---- 如果轮到X走子,用BITAND判断走后是否出现胜局
            ELSE (SELECT 'O' FROM win WHERE BITAND(t.o+m.b,win.win_bits)=win.win_bits AND ROWNUM=1) ---- 判断O是否获胜,方法同X
       END   AS  winner      
      ,t.board AS prior_board
       ------ 下面的PARTITION BY按照当前棋局以及拼出的下手棋局来分区,保留任意一种都可以,所以ORDER BY 1
      ,ROW_NUMBER() OVER(PARTITION BY t.board,SUBSTR(t.board,1,m.m-1)||CASE WHEN MOD(t.step,2)=0 THEN 'X' ELSE 'O' END||SUBSTR(t.board,m.m+1) ORDER BY 1)
  FROM t JOIN m ON BITAND(t.x+t.o,m.b)=0
WHERE t.winner IS NULL
       AND (t.step=0 AND m.m IN (1,2,5)  ----针对空棋盘的一个优化:起点只需考虑1,2,5,其他都是对称的
            OR t.step>0
            )
       AND rn=1   -----每一对(board,prior_board)只需保留一种,其他都是重复
)
, boards AS (
----- 保留所有的上手棋局与当前棋局的对应关系
SELECT board,prior_board,winner,step
FROM t
WHERE rn=1
)
,s (board,step,winner,rn,iterator,steps_to_win,player) as (
---从所有获胜终局反推, 把winner一步一步带到上层,最终判断是否能带到根
select board
      ,step
      ,winner
      ,1    as rn
      ,max(step) over() AS iterator ---- 推理起点,从最高步数往前倒推,每层递归减 1
      ,0    as steps_to_win
      ,DECODE(MOD(step,2),1,'X','O') player
  from boards
where winner is not null ------ 选取胜负已分的叶子节点作为递归起点
group by board,step,winner  ----- 因为boards里面保存着前后棋局的对应关系,所以board不是唯一的,必须去除重复
union all
select CASE WHEN s.step<>s.iterator THEN s.board ELSE b.prior_board END  as board ---- 递归的下一层,是从boards表得来的上一手棋局
      ,CASE WHEN s.step<>s.iterator THEN s.step ELSE s.step-1 END  as step
      ,case when s.step<>s.iterator THEN s.winner
            ELSE NVL(MAX(CASE when s.player=s.winner THEN s.winner END)
                         OVER(PARTITION BY b.prior_board), ---- 如果这一层的下子的一方(player)有胜局则优先取
                     ------ 当上述MAX取到的值为NULL, 意味着只有平局或者对手胜。
                     ------ 下面的count(distinct b.board)表示对手取胜的数量,REGEXP_COUNT(b.prior_board,'-')则表示有多少空位数,即多少种后续棋局
                     ------ 如果两个数量相等,说明不管怎么走都是对手赢,则把s.winner,即对手带到上层
                     CASE WHEN count(distinct b.board) over(partition by b.prior_board)=REGEXP_COUNT(b.prior_board,'-') --- 等于所有可能的对手走法
                          then s.winner
                     END
                     ---- 如果以上都不满足则WINNER为空,说明双方都没有必胜策略,为和棋
                     )
       END as winner
       ----- 本轮递归结束后,所有同一个prior_board之下的winner都一致,由上述公式推出
       ----- ROW_NUMBER用于取出同一个prior_board之下的其中一行进入下轮递归,如果走子方必胜,则取步数最少的,否则取最多的
      ,ROW_NUMBER() OVER(PARTITION BY case when s.step<>s.iterator THEN s.board ELSE b.prior_board END ---- 分析函数的分区是按照本次递归后的棋局,每个局面保留一行
                         ORDER BY CASE when s.player=s.winner THEN 1 ELSE 2 END ---- 如果这一层的下子的一方(player)有胜局,则优先取
                                 ,s.steps_to_win*CASE when s.player=s.winner THEN 1 ELSE -1 END ---- 如果是对手,要取最坏情况(最多步数),所以乘以-1之后再排序
                        ) AS rn
      ,s.iterator-1
      ,case when s.step<>s.iterator OR s.player<>s.winner  
            THEN s.steps_to_win ---- 如果对手赢,步数不用递增
            else s.steps_to_win+1 ---- 如果当前棋手赢,步数要加1,因为要再走一步才到达那个局面
       end
      ,CASE WHEN s.step<>s.iterator THEN s.player ELSE DECODE(s.player,'X','O','X') END
  from s left join boards b -------------- 为了使得下次递归能看到所有获胜局,必须用外连接带入下层
       on s.step=s.iterator ---- 正在考察的当前步, 只有这一步才需要连接board获取上一手棋局(PRIOR_BOARD)
          and s.board=b.board  ---- 连接boards获得上一步棋局
WHERE s.winner is not null and s.rn=1 and s.iterator>9-REGEXP_COUNT(p_board,'-') and s.step<=s.iterator
)
SELECT board
  INTO gv_board
  FROM (
SELECT b.board
  FROM boards b LEFT JOIN
       (SELECT * FROM s
         where iterator=gv_size-REGEXP_COUNT(p_board,gv_empty)+1
        ) s
       ON b.board=s.board
WHERE b.prior_board = p_board
  ORDER BY CASE when gv_player<>s.winner THEN 1 WHEN s.winner IS NULL THEN 2 ELSE 3 END
          ,s.steps_to_win*CASE when gv_player<>s.winner THEN 1 ELSE -1 END
          ,DBMS_RANDOM.VALUE
)
WHERE ROWNUM=1
;

  v_winner := f_get_winner(gv_board);
  print_board(gv_board,v_winner);
  
  IF v_winner IS NOT NULL THEN
     gv_board :=NULL;
  END IF;

  RETURN;
END move;


PROCEDURE start_game(p_move IN NUMBER)
AS
BEGIN
   IF NOT NVL(p_move,0) BETWEEN 1 AND gv_size THEN
      RAISE_APPLICATION_ERROR(-20001,'invalid position! value should be 1-'||gv_size);
   END IF;
   
   start_game(LPAD(gv_empty,p_move-1,gv_empty)||'X'||LPAD(gv_empty,gv_size-p_move,gv_empty));
END start_game;



PROCEDURE start_game(p_board IN VARCHAR2)
AS
   v_board VARCHAR2(20):=UPPER(COALESCE(p_board,RPAD(gv_empty,gv_size,gv_empty)));
BEGIN
   check_valid(v_board);
   
   gv_board := v_board;

   IF MOD(REGEXP_COUNT(gv_board,gv_empty),2)=0 THEN
      gv_player :='X';
   ELSE
      gv_player :='O';
   END IF;
   
   move(v_board);
   
END start_game;
     
PROCEDURE play(p_move IN NUMBER)
AS
BEGIN
   IF gv_board IS NULL THEN
      DBMS_OUTPUT.PUT_LINE('Please start a new game');
      RETURN;
   END IF;
   IF NOT NVL(p_move,0) BETWEEN 1 AND 9 THEN
      RAISE_APPLICATION_ERROR(-20001,'invalid position! value should be 1-9');
   END IF;
   
   IF SUBSTR(gv_board,p_move,1)<>gv_empty THEN
      RAISE_APPLICATION_ERROR(-20001,'position is already taken by:'||SUBSTR(gv_board,p_move,1));
   END IF;
   
   gv_board := SUBSTR(gv_board,1,p_move-1)||gv_player||SUBSTR(gv_board,p_move+1);
   
   move(gv_board);
END play;


END pkg_tictactoe;
/


/*

SQL> exec pkg_tictactoe.start_game('X-------O');
Your side: O
=============
X--
---
X-O

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.10
SQL> exec pkg_tictactoe.play(4);
Your side: O
=============
X-X
O--
X-O

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.04
SQL> exec pkg_tictactoe.play(2);
Your side: O
=============
XOX
OX-
X-O
========= You lose! =========

PL/SQL procedure successfully completed.
*/

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
29#
发表于 2015-12-23 06:13 | 只看该作者
newkid 发表于 2015-12-23 03:52
第二题的副产品是这个会下棋的包,里面只有两个过程,start_game和play
start_game可以带一个参数指定从哪 ...

它就是完美棋手吧

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
30#
 楼主| 发表于 2015-12-23 09:17 | 只看该作者
它会选择胜负情况、步数最佳的。如果有结果相同的多种选择则随机挑一种。
如果有人做出4,4,4的,可以来一场两个程序之间的对决。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表