从围棋收官到秦楚大战的数据库SQL实现(上)

梁敬彬梁敬弘兄弟出品

前言

在这个万物互联的时代,创新常常源于跨界思维。人工智能的发展启示我们,掌握多领域知识并融会贯通,才能在看似无关的领域之间搭建桥梁,创造新的可能性。

今天,我们将穿越千年,探讨围棋与数据库的交融。围棋是古老智慧的结晶,数据库则是现代技术的象征。当两者相遇,会擦出怎样的火花?

通过模拟秦楚战争,我们将揭示围棋收官与攻城策略的微妙关联,并展示如何用SQL语言实现这一切。准备好了吗?一场跨越时空的智慧碰撞,即将开始。

1. 秦孝公大战商鞅

公元前333年,秦孝公和商鞅下围棋,其儿子嬴驷、嬴华在一旁观战,双方大战333手,最终秦孝公败下阵来。
在这里插入图片描述

商鞅:大王您布局占优,只是输在了收官。主要是一处双先被我给抢了,临近终局又有一处先手您没有及时下到,又被我给逆收了,这才得以幸运小胜。
秦孝公:是啊,这两处失误着实不应该。

这些收官术语让观战的嬴驷、嬴华听的有些云里雾里,于是商鞅当即就给两位少年开启了围棋官子小课堂。

商鞅:围棋顾名思义,围地盘的棋,胜负就取决于谁的地盘围得更大。黑白双方轮番落子,不允许一方连下两手,比如我取得梦寐以求的A点,你就可以占据心心念念的B点。但是有一种特殊的情况,就是我占到A点后你却不敢去占B点,需要跟着我应一手,于是B点又落入我手。符合这种特征的A点,谓之先手
两位公子点点头,商鞅继续解释。

商鞅:不过如果一方走到A点,另一方不搭理也不会出事,可以放心地抢占他处(如B点)。此时在A点落子就被称之为后手

嬴驷:那我们下棋是不是要判断下的是先手还是后手,优先考虑先手。

商鞅:公子聪明。先手更准确的叫单先,如A点对甲是先手,对乙却不是。

嬴华:老师,我猜到你们提到的双先啥意思,是不是无论黑白哪一方行棋,A点对他们而言都是先手,此时在A点的落子就被称之为双先

商鞅:正确!最后还有一个逆收的概念,能猜到啥意思吗?

嬴驷:通过这个“逆”字推测,逆收会不会是A点对某一方(比如黑方)是先手,对另一方(比如白方)是后手,但是黑方没及时下A点,被白方给抢占了。

商鞅:两位公子机智过人,乃我秦之大幸啊。

两位公子:是老师引导得好。
在这里插入图片描述

2. 收官类型与城池特征

商鞅:单先、后手、双先、逆收这四种收官类型你们搞明白了,这里我想问问两位,这四种收官手法的优先级如何,你们行棋中会考虑它们的顺序吗?

嬴驷和嬴华陷入沉思…

秦孝公:驷儿,华儿,围棋和战争很类似,父王和你们探讨接下来的战事规划,把这整明白了,围棋收官顺序也就水落石出了。

两位公子顿时来了精神。

秦孝公:吾儿,咱们秦国即将与楚国展开八大城池的争夺战,一旦能夺其大部分,则天下局势将对秦国极其有利,否则就不好说了。

嬴驷:父王,那胜算几何?

秦孝公:父王和商君研究过,从围棋收官角度来看,我军必取大捷。

接着秦孝公领着众人来到地图前,他飞快的圈出这八座城池,然后继续探讨。

秦孝公:诸位看这八座城池,分别是双先城池两座、单先城池两座,逆收城池两座,还有后手城池两座。

嬴华:父王,您太有趣了,还真将围棋收官搬到战场上来啊。

秦孝公:嗯,双先城池平原地带,分别名为平原1和平原2,两处城池粮食充裕,无论秦楚占得此地都能得到充足的补给,可以此为依托,即刻攻占新的城池。

单先城池地处草原地带,分别名为草原1和草原2,两处城池地域辽阔草木茂盛,这对我们骑兵大军来说非常重要,不过对于楚军来说却并不适应。

逆收城池处于山水地带,分别名为山水1和山水2,这对于擅长水上作业山间种植的楚国人来说是天赐佳境,得到后可立即依托于此继续攻占新城。可惜我秦军对这种环境并不适应,攻占下来需要适应和调整,无法即刻再攻城略地。

最后的两座后手城池地处高原地带,分别名为高原1和高原2,这两处无平原、无河流、无草原,谁占到此处都不能得到充分的补给,无法即刻奔赴新战场。

在这里插入图片描述

听秦孝公将战争与收官术语这么一结合,两位公子恍然大悟,理解的更为深刻了。同时他们都向父王表态,要上阵去和楚国决一死战。

看着两个儿子英勇的样子,秦孝公很是欣慰。

3. 收官顺序与攻城策略

秦孝公:吾儿,现在双方兵力已经各自集结,大战一触即发。我军与楚军实力都很了得,无论哪一方只要拿下的城池能给其充分的补给,都能即刻抢占下一城池,而另一方只能避其锋芒。

嬴驷:那谁能占得先机,率先出击,就显得尤为重要了啊。

秦孝公:放心,秦国骑兵强大,速度所向无敌,先机在我们这。

两位公子面露喜色。

商鞅:两位公子,如果让你们带兵上阵,这八座城池准备依据什么顺序去攻打,最多能下几城。
在这里插入图片描述

秦孝公:哈哈,这和商君刚才提问的收官顺序,是同一个问题哦。

嬴驷:老师,我认为先攻双先城平原1,再灭平原2。随即将单先城草原1拿下,再进军草原2,最后攻占后手城高原1,不过高原1无法提供充足补给,我们只能修生养息,此时轮到楚国出手,会接连拿下山水1、山水2以及最后的高原2。如此一来,我军拿下八座城池中的五座,楚军则取其三。

嬴华:我觉得拿下平原1,平原2,草原1,草原2后接下来攻打的应该是山水1,而非高原1 。虽说山水1不是秦军理想之地,却是楚军的理想之地。夺取之后楚军仅剩山水2可选,即便有充足补给助其继续出征,剩下的也只有高原1和高原2这两个后手之城,若取高原1后修生养息,则高原2就落入我军之手。如此应该是秦军拿下八座城池中的六座,楚军仅取其二,整体过程如表格所示。
在这里插入图片描述
嬴驷:厉害,是愚兄错了。

嬴华:哦,老师,攻城的顺序就是双先、单先、逆手、后手。这也就围棋的收官顺序了。

商鞅:很好!这下你把围棋如何收官的问题也一并回答了,来,各位看看我画的收官的单手棋流程图,理解一下。
在这里插入图片描述

众人看了流程图频频点头。

商鞅:我再出一道围棋题来考考两位,行棋至此,轮白下,请问如何收官?
在这里插入图片描述
嬴华思考片刻,心中有了答案,随即开始边摆棋边回答商鞅。
嬴华:老师,白1抢完双先后立即夺取白7单先,随后走到白11逆收,最后剩下后手官子,如此终局即可半目获胜。
在这里插入图片描述

商鞅点头称是,秦孝公大喜过望,当即准许赢华其随征讨大将军一同出征,此次少年出战,也为将来成就秦国第一猛将打下了铺垫。
此时的嬴驷的脸上闪烁出一丝不易察觉的笑容,却正好被商鞅看在眼里,商鞅心里一颤,似乎明白了什么。而此时的秦孝公却在准备给大家一个惊喜。

4. 秦孝公展示SQL神功

秦孝公:商君、驷儿,华儿,你们会说战国许多国家的语言,不过最近一个奇遇,让寡人学会了一门新语言,可比你们都厉害。
商鞅:哇,恭喜大王,敢问是什么语言?
秦孝公:SQL语言,这语言可不是用来说话,而是能分析预测出各种结果,比如可以告知秦楚争夺城池的结果,甚至比这更复杂的情况也能分析。
众人一脸懵逼 …
秦孝公拿出了他在奇遇中得来之器,一番敲打后,开始了数据库建模和SQL语言的编写过程。
建表和插入数据

-- 创建城池表
CREATE TABLE cities (
    id NUMBER(5) PRIMARY KEY,
    name VARCHAR2(50),
    type VARCHAR2(10)
);

-- 插入城池数据
INSERT INTO cities (id, name, type) VALUES (1, '平原1', '双先');
INSERT INTO cities (id, name, type) VALUES (2, '平原2', '双先');
INSERT INTO cities (id, name, type) VALUES (3, '草原1', '秦先手');
INSERT INTO cities (id, name, type) VALUES (4, '草原2', '秦先手');
INSERT INTO cities (id, name, type) VALUES (5, '山水1', '楚先手');
INSERT INTO cities (id, name, type) VALUES (6, '山水2', '楚先手');
INSERT INTO cities (id, name, type) VALUES (7, '高原1', '后手');
INSERT INTO cities (id, name, type) VALUES (8, '高原2', '后手');

编写SQL如下

WITH type_counts AS (
    SELECT type, COUNT(*) AS type_count
    FROM cities
    GROUP BY type
),
capture_process AS (
    SELECT 
        c.id, c.name, c.type,
CASE
            WHEN c.type = '双先' THEN '秦'
            WHEN c.type = '秦先手' THEN '秦'
            WHEN c.type = '楚先手' THEN
                CASE 
                    WHEN ROW_NUMBER() OVER (PARTITION BY c.type ORDER BY c.id) = 1 THEN '秦' 
                    ELSE '楚' 
                END
            WHEN c.type = '后手' THEN
                CASE 
                    WHEN ROW_NUMBER() OVER (PARTITION BY c.type ORDER BY c.id) <= FLOOR(tc.type_count / 2) THEN '楚' 
                    ELSE '秦' 
                END
        END AS captured_by
    FROM cities c , type_counts tc

where  c.type = tc.type
)
SELECT
    captured_by AS category,
    COUNT(*) AS count,
    LISTAGG(name, ', ') WITHIN GROUP (ORDER BY id) AS cities
FROM capture_process
GROUP BY captured_by
;

关键点说明:
a. 双先和秦先手:直接归秦国所有。

b. 楚先手:

使用 ROW_NUMBER() 函数为每个楚先手城池分配一个序号。

只有第一个(序号为1)的楚先手城池被秦国逆收,其余全部归楚国。

这确保了无论有多少个楚先手城池,秦国只能逆收一个。

c. 后手:

同样使用 ROW_NUMBER() 函数分配序号。

使用 FLOOR(tc.type_count / 2) 判断各自应该占领的城池数量。

执行这个查询,结果是:
在这里插入图片描述
显示秦占领6座城池,而楚仅占领了2座,验证了嬴华的分析思路是正确的。

众人震惊,连呼:SQL语言好厉害,此乃天助大秦一统天下也!

…本集完

四点注意!!!

  1. 古代围棋规则和现代略有不同,为方便大家理解,本文以现代围棋规则为准;

  2. 围棋的收官是很复杂的,双先、单先、逆手、后手的顺序只能确保大致正确,实际收官时要根据棋盘的具体情况具体分析,主要和每手棋的目数有关,甚至后手足够大时,最先考虑后手都是有可能;

  3. 对应的抢夺城池的情况也是如此,不能仅以城池个数做依据,实际战斗中需要结合城池的大小考虑才更合理,这也就是前面说的围棋收官需要结合每一手棋的目数综合考虑类似;

  4. 本文是基于极简围棋收官下的建模与实现,后续会考虑讲述更为复杂的收官,比如什么情况下逆收比后手大,双先就一定要应吗?你抢一个双先,我也抢一个,我不理有损失,那你不理就没损失吗,如何判断?敬请期待!

致谢
此文得到了许多专家的帮忙:有来自点点围棋的胡傲华职业五段,他为本文围棋技术细节给予了专业的指导,受益匪浅;有来自虚谷的数据库专家明玉琢老师,给了我写作的灵感,深受启发。有来自加拿大的SQL大神newkid兄,给了我许多宝贵的建议。非常感谢~!

最后还要感谢能轻松适配Oracle的达梦的数据库云环境,让我随时随地愉快试验。

未完待续…

从围棋收官到秦楚大战的数据库SQL实现(中)

公众号:收获不止数据库

系列回顾

“大白话人工智能” 系列
“数据库拍案惊奇” 系列
“世事洞明皆学问” 系列

从围棋收官到秦楚大战的数据库SQL实现(上)原文链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

收获不止数据库

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值