组易揭棋--组易象棋揭棋版简介

组易揭棋是组易象棋的揭棋版, 是一种变体中国象棋游戏, 是混合了揭棋玩法的组易象棋.

组易揭棋组易象棋揭棋版, 是一种变体中国象棋游戏, 是混合了揭棋玩法的组易象棋.

组易揭棋示意图 组合易位中国象棋 揭棋版

在线试玩

在线试玩主页网址: http://zyxq.xiaogd.net/jie-qi/

目前支持单人摆棋自弈和邀请对战两种模式.

继续阅读

组合易位中国象棋(组易象棋)--简介

一种变体中国象棋游戏

组合易位中国象棋, 简称组易象棋, 是一种在中国象棋玩法的基础上增加了组合以及易位两种特性的变体象棋游戏.

游戏简易演示主页: https://zyxq.xiaogd.net/

下面简要介绍一下这两种特性.

组合

所谓组合, 指己方的两个或多个棋子可以通过走动合并到一起, 形成一个棋子组或者说组合体, 简称组合.

组合的想法受国际象棋里的这个棋子的特性启发.

如果你会玩国际象棋, 你应该知道, 这个威力强大的棋子相当于国际象棋里的的组合.

继续阅读

技术呆子们有时还是过于天真乐观了

以下内容均摘自<<科技想要什么>>一书.

  1. 1917 年, 奥维尔·莱特预言: "飞机将对和平有所帮助, 尤其我认为飞机很有可能会让战争消逝."

  2. 同一年, 凡尔纳宣布: "潜水艇有可能变成让战争完全停止的因素, 因为舰队将变得无用, 随着其它战争工具继续进步, 战争将不再可能发生."

  3. 诺贝尔真心相信他的炸药会遏制战争: "我发明的炸药会超越一千次的世界会议, 更快带来和平."

  4. 发明机关枪的海勒姆·马克西姆在 1893 年被问到: "这把枪会不会让战争变得可怕?" 他回答: "不会, 机关枪让战争不可能出现."

  5. 发明无线电的列尔莫·马可尼在 1912 年对世界宣告: "无线时代来临后, 战争就不可能发生了, 因为战争会变得很可笑."

  6. 美国无线电公司的董事长詹姆斯·哈博德将军在 1925 年宣扬他的信念: "无线电能够实现'世界得太平, 人间持善意'的概念."

  7. 19 世纪 90 年代, 电话变成商品后不久, 美国电话电报公司的总工程师约翰·丁·卡蒂预言: "有一天, 我们会造出全球电话系统, 让所有人都使用共通的语言, 或对不同的语言有共同的了解, 如此一来, 四海之内皆兄弟. 地球上不论何处, 都会听到苍穹中发出宏亮的声音对我们宣告:'世界得太平, 人间持善意'."

  8. 尼古拉·特斯拉认为发明了"不需要电线, 符合经济效益的电力传输...就能为地球带来和平与融洽". 那时是 1905 年, 而既然现在无线的电力传输还没有发明出来, 世界和平仍有希望.

  9. 科技史学家戴维·奈伊列出了更多的发明物, 想象着这些东西能永久废除战争, 引领我们进入宇宙和平: 鱼雷, 热气球, 毒气, 地雷, 飞弹和镭射枪. 他说: "每一种新的沟通方式, 从电报和电话到无线电, 电影, 电视和互联网, 都让人期待能保证言论自由, 想法也能自由流通."

  10. 1971 年, 乔治·金特在<<纽约时报>>发表了关于交互式有线电视的文章, 他说: "支持的人认为这个节目...向政治哲学家的参与式民主梦想踏出了一大步."

最后谈谈自己的一点感想, 总的来说, 我们现在还是比以往好了不少, 虽然没有他们想象的那么乐观, 但他们的许多发明确确实实给我们人类带来了切实的利益, 向他们致敬.

继续阅读

记一次自动升级的"事故"--活夜见鬼, 深更半夜里关掉的电脑突然自己播放起视频来了

深更半夜, 你躺在被窝睡得正香, 关掉的电脑突然自己播放起视频来了, 活夜见鬼, 这样的事你碰到过吗? 我昨晚就遇到了.

事情是这样的, 电脑昨晚又自己升级了, 我临睡前只是让电脑睡眠了, 结果这家伙或许是有自动任务吧, 又把自己唤醒点亮了. 你可以想象一下, 一个漆黑的房间, 屏幕突然亮起来, 那是什么感觉.

不过话说回来, 如果你已经闭着眼睛, 你也许不会注意到, 可问题在于, 居然还有声音!

说实在的, 我当时迷迷糊糊应该是恰好处于快要睡过去的状态, 结果传来了那些声音, 我也是半天才反应过来, 我没有在做梦, 声音是真实存在的, 然后睁开眼睛, 发现一片亮堂堂的, 我心里立刻就明白了, 准又是这电脑的自动升级在搞事情!

说实话, 半夜升级屏幕突然亮起来的这种情形我碰到多了, 都已经见怪不怪了, 可为啥还有声音呢? "半夜鸡叫"这种情形还真是大姑娘上花轿--头一回, 于是我仔细听了一下, 听出了是我白天看过的一个视频, 然后我就大概明白了是怎么回事.

我当时很多程序都是开着的, 包括浏览器, 有 Edge, 有 Chrome, 还有 Firefox, 这家伙升级完后, 又很"贴心"地重启了 Edge 浏览器,

可我早上起来检查时, 发现 Chrome 和 Firefox 好像没重启呢, 想不到这浓眉大眼的也挺鸡贼的嘛~

这还不够, 它还把 Edge 浏览器所有标签页上的网页又重新打开了, 这下这一"贴心"可就贴坏事了, 有个标签页上是一个视频, 本来是播放完了停止了的, 它这一重新打开相当于一刷新, 好家伙, 视频又播放起来了!

正想着这么个冷天还要爬出温暖的被窝去关掉它, 心里正烦闷, 转念忽然又想到, 这只是个几分钟的短视频, 另外不幸中的万幸是, 我当时电脑的音量设置得很小, 虽然它还是吵醒了我, 但我很确信它应该不会吵到别人, 甚至也不会妨碍我再次入睡, 于是我就心安理得地继续躺着了, 果然, 我很快又睡过去了, 我甚至不确定当时它到底播完了没有.

意外的声音会让人醒来, 但当你确认了它不是意外也不构成威胁或麻烦时, 它就不再妨碍你了.

幸亏那个视频不是一个恐怖片, 要不还真能把自己吓着...

也辛亏不是那种"无病呻吟"的视频, 也幸亏音量设置得也不是特别大, 要不隔壁邻居的单身汉听到又要睡不着了...

继续阅读

外语学习与刻意练习

关于外语学习的一个误区, 以及什么是刻意练习及为什么要刻意练习

在 youtube 上听到一个会中文的外国哥们吐槽国人学英语时的一些问题, 有些启发, 就此展开聊聊.

他说国人学英语时有个误区, 比如通过看剧来学英语吧, 不是说看剧这个方式就不行, 但具体的操作方法值得商榷.

比如以看美剧 <<老友记>> 练听力为例吧, 很多人是这样的, 一天看一集, 甚至看好几集, 这样就算听了, 学了.

然而这样是不对的! 学习语言很关键的一点是 重复重复再重复, 你绝不应该一天看一集, 甚至看好几集; 相反, 你应该是在这一天里把这一集反复地看好几遍, 甚至好几天都是反复地看这一集! 把这一集看到滚瓜烂熟为止!

为什么呢? 其实严格地说起来, 我觉得关键可能还不在于重复, 重复只是一个必要的手段, 真正的关键我觉得是要理解 有效输入刻意练习 这两个概念.

继续阅读

mysql SQL_CALC_FOUND_ROWS 特性: 一条 sql 语句同时查出总数及分页结果

介绍了如何通过利用 mysql SQL_CALC_FOUND_ROWS 特性, 在一条 sql 语句里同时查出总数及分页结果

展示分页列表是一个常见的开发需求, 需要查询出总数及分页数据.

传统分页查询做法

传统上, 这个一般是通过两条 sql 去实现. 先是查询总数, 比如这样:

select count(*) from programmer where age >= 35;

然后再查分页结果:

select * from programmer where age >= 35 limit 0, 10;

如果是简单的查询还好, 但对于一些复杂的涉及很多条件的查询, 往往需要重复那些条件.

注: 在 mybatis 中, 你可以把公共的条件抽取出来做成一个可复用模块, 不过这样一来结构就相对复杂了, 也不是那么直观.

那么, 是否有方式可以避免上述麻烦, 一条语句就可以查出总数及分页结果呢? 那就要用到 mysql 里的 SQL_CALC_FOUND_ROWS 特性了.

继续阅读

几率相同的游戏, 你为什么还是输给了庄家?

为什么看似公平的游戏, 其实并不公平?

假设你跟庄家玩一个纯粹靠运气的骰子游戏, 请问谁会赢?

一个容易陷入的误区就是, 既然这是一个纯粹靠运气的游戏, 你可能会想, 那赢的几率应该是五五分, 也是一个纯粹靠运气的问题.

运气好, 你可能赢了庄家; 运气不好, 你则可能输给庄家. 我曾经也是这么想的, 直到后来我在 github 里看到李笑来老师在他的 别做“险盲” 里提到, 其实庄家赢的概率要高, 看了他的分析, 并认真想了想, 确实有道理.

下面就来说说为什么.

继续阅读

勾股定理的一个简单证明

勾股定理的一个图形式的直观证明

勾股定律, 也即直角三角形, 斜边的平方等于另外两条直角边平方之和.

西方称为毕达哥拉斯定理(Pythagorean Theorem), 归功于古希腊数学家毕达哥拉斯(Pythagoras).

如图:

勾股定理的简单证明 a simple proof of pythagorean theroem

红色直角三角形两直角边长为 a 和 b, 斜边长为 c.

正方形 ABCD 与正方形 EFGH 边长相等, 均为 a + b, 因此两者面积相等.

正方形 EFGH 面积 = c2 + 4 × 红色三角形 = 正方形 ABCD 面积 = a2 + b2 + 4 × 红色三角形

约去四个红色三角形面积, 可得 c2 = a2 + b2 .

证毕.

继续阅读

配置 p6spy log 输出应用最终执行的 sql 语句

介绍了如何使用 p6spy log 输出应用最终执行的 sql 语句, 以方便调试

在上一篇的 配置 mybatis 打印出执行的 sql 及返回的结果集 中, 说到了在 mybatis 中如何打印出执行的 sql, 但是还是遗留了一个问题, 也即是它的输出的 sql 并不是最终可执行的, 而是类似于 jdbc 那种 PrepareStatement 的形式, 参数的值是用问号代替的, 如下:

select * from user where username = ? and password = ?

虽然其参数值通常也会一起输出, 但如果我们对查询的结果有疑问, 想去数据库里自己执行看看, 就不得不自己去拼凑那些最终的 sql:

select * from user where username = 'admin' and password = '123456';

如果参数特别多的查询, 这会成为一个麻烦. 那么, 是否有方式可以直接输出最终的 sql 呢? 一种方式就是下面将要介绍的 p6spy log.

p6spy log 输出效果

先看其输出的效果:

26:33 #1607390793732 | took 7ms | statement | connection 0| url jdbc:p6spy:mysql://localhost:3306/code_sample?serverTimezone=GMT%2B8
select * from user where username = ? and password = ?
select * from user where username = 'admin' and password = '123456';
26:33 list size: 1

可以看到, 除了那种 PrepareStatement 的形式, 还有最终的 sql. 那么, 要如何去实现这样的效果呢?

另注: 这里的日志布局我启用了一种极简的风格, 只有"分钟:秒数", 具体见 配置简化开发阶段日志输出布局 的介绍.

继续阅读

兰切斯特方程启示录

通过具体的例子, 介绍了兰切斯特方程及其带来的启示, 同时与马太效应作了对比.

兰切斯特方程(Lanchester equation) 是一位英国工程师弗雷德里克·兰切斯特(Frederick Lanchester)在一战期间(1916)发展出的一系列用于描述对战双方战斗力的微分方程.

又称兰切斯特定律(Lanchester's Law), 其中, 兰切斯特有时也翻译为兰彻斯特.

那么这个方程到底讲了什么, 它又能带给我们什么启示呢?

继续阅读

配置 mybatis 打印出执行的 sql 及返回的结果集

介绍了如果配置 mybatis 以打印出执行的 sql 及返回的结果集, 从而方便开发阶段的调试

在开发过程中, 经常会遇到想要看到应用所执行的 sql 这样的需求.

比如你写了一个查询的功能, 但查询出来的结果与你预期的不符合, 你想搞清楚到底哪里出了问题, 你自然需要看看所执行的 sql 语句, 必要的话甚至还要亲自拷贝到数据库里去查查.

自然, 这就要求应用要能把执行的 sql 输出出来. 以常用的 mybatis 框架为例, 来看一个最终的效果:

14:48 ==>  Preparing: select * from user where id = ? 
14:48 ==> Parameters: 1(Integer)
14:48 <==      Total: 1

另注: 这里的日志布局我启用了一种极简的风格, 只有"分钟:秒数", 具体见 配置简化开发阶段日志输出布局 的介绍.

那么, 在 mybatis 里, 这个要怎么做到呢?

继续阅读

将锻炼融入日常例程中

怎么把锻炼融入到日常例程中去从而得到坚持?

很多人都知道锻炼的重要性, 特别是对于时不时要加下班甚至要熬夜的程序员来说, 一副健康的身体尤为重要.

要想拥有健康的躯体, 锻炼是必不可少的. 虽然很多人认同锻炼的重要性, 但他们经常面临的一个问题是没有时间以及难以坚持下去.

如果你想锻炼又面临上述的问题, 我的建议是把锻炼融入到日常例程中, 这是时间成本最低且容易坚持下去的方式.

所谓日常例程, 就是那些我们几乎天天都会做的事, 比如早上起床, 晚上睡觉, 到点了吃饭, 每个工作日去上班等等. 这些都是一些固定的活动, 很多都已经固化成了习惯.

那么, 怎么把锻炼融入日常例程呢?

继续阅读

边际收益原理

什么是边际收益原理及带给我们的做事启示.

所谓的 边际收益原理(Theory of Marginal Gains), 这个概念来自于商业实践, 指的是通过简单改进一项业务的各个方面, 每一个细枝末节, 都提高一点点, 整体上你将得到一个巨大的提升.

比如, 将产品生产速率仅仅增加 1%, 将产品生产的质量仅仅增加 1%, 将生产的成本仅仅降低 1%, 那么, 整体上会怎样呢? 是仅仅提升 3% 吗? 不是的! 整体上的提升将远远超过 3% ! 而这样的效应就是所谓的 边际收益原理.

来看一个英国自行车队的故事, 它的名字叫天空车队, 曾经是世界最烂的车队之一, 几乎没取得过什么像样的成绩.

后来一个叫布雷斯福德(Dave Brailsford)的接手了车队, 他是一位前职业自行车手, 兼修了一个 MBA 学位, 他把商业领域的这个理念带到了他的车队管理实践中.

他对英国车队做了什么呢? 你要说有什么大的操作那倒也没有, 下面是一些他引入的改进:

继续阅读

配置简化开发阶段日志输出布局

介绍了如何通过简化配置以解决开发阶段日志输出布局过长导致的不易查看的问题, 提供了一种极简的配置及一种适中的配置.

现在的很多应用默认情况下就带了很多的日志输出, 比如下面的 java spring-boot 框架启动时的日志:

{spring.web.resources.chain.cache=false, spring.web.resources.cache.period=0}

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.0)

2020-11-28 10:54:18.418  INFO 16144 --- [  restartedMain] n.x.sample.boot.basicweb.AppApplication  : Starting AppApplication using Java 11.0.8 on DESKTOP-CGD1N1Q with PID 16144 (C:\dev\proj\my\code-sample\be\java\fw\spring-boot\basic-web\target\classes started by xiaog in C:\dev\proj\my\code-sample\be\java\fw\spring-boot\basic-web)
2020-11-28 10:54:18.423  INFO 16144 --- [  restartedMain] n.x.sample.boot.basicweb.AppApplication  : No active profile set, falling back to default profiles: default
2020-11-28 10:54:18.453  INFO 16144 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2020-11-28 10:54:18.453  INFO 16144 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2020-11-28 10:54:19.024  INFO 16144 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2020-11-28 10:54:19.031  INFO 16144 --- [  restartedMain] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-11-28 10:54:19.032  INFO 16144 --- [  restartedMain] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.39]
2020-11-28 10:54:19.096  INFO 16144 --- [  restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-11-28 10:54:19.098  INFO 16144 --- [  restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 644 ms
2020-11-28 10:54:19.208  INFO 16144 --- [  restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-11-28 10:54:19.254  INFO 16144 --- [  restartedMain] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page: class path resource [static/index.html]
2020-11-28 10:54:19.314  INFO 16144 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2020-11-28 10:54:19.337  INFO 16144 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-11-28 10:54:19.346  INFO 16144 --- [  restartedMain] n.x.sample.boot.basicweb.AppApplication  : Started AppApplication in 1.216 seconds (JVM running for 1.887)

日志信息非常丰富当然是有助于我们理解应用运行的各个方面, 但经常地, 我们也不难发现一些不方便的地方, 比如就以上述的输出为例, 前面一大堆的 布局(layout) 相关的输出就极为冗长, 而真正关心的信息却被挤在了后面, 如果你的显示屏不够宽, 这些关键的信息常常反而看不到, 需要横向滚动, 非常繁琐.

下面将介绍一种极简的日志布局方案, 如下所示:

{spring.web.resources.chain.cache=false, spring.web.resources.cache.period=0}

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.0)

49:20 Starting AppApplication using Java 11.0.8 on DESKTOP-CGD1N1Q with PID 11800 (C:\dev\proj\my\code-sample\be\java\fw\spring-boot\basic-web\target\classes started by xiaog in C:\dev\proj\my\code-sample\be\java\fw\spring-boot\basic-web)
49:20 No active profile set, falling back to default profiles: default
49:20 Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
49:20 For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
49:20 Tomcat initialized with port(s): 8080 (http)
49:21 Starting service [Tomcat]
49:21 Starting Servlet engine: [Apache Tomcat/9.0.39]
49:21 Initializing Spring embedded WebApplicationContext
49:21 Root WebApplicationContext: initialization completed in 636 ms
49:21 Initializing ExecutorService 'applicationTaskExecutor'
49:21 Adding welcome page: class path resource [static/index.html]
49:21 LiveReload server is running on port 35729
49:21 Tomcat started on port(s): 8080 (http) with context path ''
49:21 Started AppApplication in 1.219 seconds (JVM running for 1.945)

可以看到, 仅仅输出了一个时间(分别是分钟数和秒数, 小时, 毫秒什么的都省略了), 然后就是关键的日志信息, 非常简洁, 一目了然, 基本不需要各种拓宽或横向拖动来显示.

下面说说怎么配置以达到上述效果.

继续阅读

使用 log 占位符便利日志输出

介绍了如何使用日志的占位符来简化日志字符串的拼接输出

在开发活动中, 记日志是一个很常见的操作. 记日志经常涉及到拼接字符串, 因为我们常常需要把参数的值输出出来, 同时拼上字样的提示, 这样后续查看时才好知道发生了什么.

比如这样:

package net.xiaogd.sample.mybatis.controller;

import lombok.extern.slf4j.Slf4j;
import net.xiaogd.sample.mybatis.entity.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class LogController {

    @GetMapping("/hello")
    public String hello(@ModelAttribute User user) {
        log.info("username: " + user.getUsername() + " , age: " + user.getAge());
        return "hello there";
    }
}

注: 如果对这里 @Slf4j 式注入 log 变量的写法有疑问, 请参考: 使用 lombok @Slf4j 注解简化日志功能的引入

这样的方式一旦参数多了, 就会显得很凌乱, 写起来也不方便, 看上去也是支离破碎的.

很多人可能因此就不去记日志了, 或者只记很少的变量的值, 给后续的排查问题就带来了麻烦.

继续阅读