首先,我们熟悉一下五子棋:

两人对弈的策略型棋类游戏,是博弈游戏中较简单的一种玩法:双方分别使用黑白两色的棋子,轮流在棋盘空白交叉点上着子,先形成五子连线的一方获胜。

那么,我们就可以开始做了

制作过程

我们分为如下三个大点

  1. 头文件&变量
  2. sum()
  3. 初始化 主循环
  4. 数据处理
  5. 打印输出

头文件&变量

我们需要用wasd来控制下子的位置,所以我们引入头文件conio.h 和 stdlib.h

#include <stdlib.h>
#include <conio.h>

经过考虑,我们需要定义如下的一些函数(考虑到单词太长问题,所以我将它简写化了)

我们可以修改W棋盘边长来扩大棋盘大小(但是闪烁会越明显,因为字符变多了00)

/* 定义说明
 * W(Width)棋盘边长
 * S(Size)棋盘大小 S=W*W
 * m(map)地图 动态分配,值:0 空地 1 黑子 2 白子
 * z(zuobiao)光标坐标
 * c(char)动作 ,获取字符(也就是键盘输入)
 * r(round)回合 1为白方 2为黑方,同时当r>4时,表示五连
 * i,j临时变量
 */
int W = 13, S, *m, z = 0, c = 1, r = 2, i, j;

sum()

由于下子容易越界(超出棋盘范围),我们定义一下一个sum函数,用于判定

总共分为三种判定:

  1. 范围判定
  2. 越界判定
  3. 是否相同下子
int sum(int v, int l, int s){ //定义函数
    // 判定,判定分为有范围判定,越界判定,是否相同
    return s && (abs(v % W - (v + l) % W) - W + 1 && v + l >= 0 && v + l < S)
        && m[v] == m[v + l] ? 1 + sum(v + l, l, s - 1) : 0;
}

前期工作就已经搞定了,我们进入main

初始化 主循环

我们先使用一个for来进入循环

for (m = calloc(S = W * W, 4); r < 4 && c - 27; c = _getch() & 95){}

说明一下吧,我们先初始化 S = W * W,分配内存空间

我们的循环条件是当达成五连时/按下Esc键时结束循环

  1. 五连时,我们的r是小于4的,也就是r += 4
  2. Esc键ascii码为27

循环的末尾就是获取键盘输入 && 小写转大写

  1. 我们使用c=_getch() 来阻塞获取一个字符
  2. 使用c & 95 进行位运算,大小写中是相差32的
字符ascii码二进制
a971100001
_951011111
A651000001

光标移动处理

我们根据输入adsw来移动光标,实际上,无脑穷举就可

相关变量: W = 8, S = 64,z = 35

c - 68 || ++z, c - 65 || --z, c - 83 || (z += W), c - 87 || (z -= W);

以光标为中心 光标坐标的下标之差,左右移动(A,D) 只需移动一格,而上下移动(W,S)则跟W有关

112

光标越界处理

我们需要处理一下光标触碰边缘的情况(左右越界会换行,所以我就不做左右了)

相关变量:W = 8,S = 64,z = 56

如:z = ( z + S ) % S

z = 64 向下移动越界了

我们对他进行一个处理,z = ( 64 + 64) % 64 = 0

五连判定

相关变量:W = 10,S =100,z = 45

现随机生成一个即将达成五连的棋盘,以光标为中心,8个方向4条轴,每个方向最多4格,每条轴的2个方向相同元素累加起来超过4颗即可达成五连

2

于是我们可以这么写

if (z = (z + S) % S, system("cls"), i = 2, !c && !m[z]){ // 光标越界处理 & 清屏
            for (m[z] = r ^= 3; j = i % 3 - 1 + i / 3 * W, i < 6; ++i){ // 五连判定
                sum(z, j, 4) + sum(z, -j, 4) > 3 && (r ^= 3, i = r += 4);
            }
        }

打印地图

首先,先说一下TUIGUI,TUI是Text-based User Interface 文本用户界面,GUI 是 Graphical User Interface 图形用户界面

GUI目前来说是主流,但是相对来说学习成本有点高,TUI就更适合练手(实际上是一个控制台,黑乎乎的,感觉就很有程序员的那种范😂)

我们先把控制台界面看成一个网格,每个格子2个字符,每个地图值就有对应的格子,根据地图值打印字符。当然光标、行数(+换行符)和列数也需要打印

我们通过两个for来实现打印

for (i = 0; i < S; ++i % W || _cprintf("%d\n", i / W)){
            _cprintf("%c%c", i - z ? 32 : 62, m[i] ? m[i] - 1 ? 64 : 79 : 32);
        }
        for (i = 0; i < W; ++i)_cprintf(" %c", 97 + i);{
        _cprintf("\n%s", r & 1 ? "White" : "Black"), r < 4 || _cputs(" win!");
        }

代码展示

/* 
 * 五子棋
 * Made by RainbowRoad1 & Wibus
 * Date:2020.9.13
 *
 */

#include <stdlib.h>
#include <conio.h>
/* 定义说明
 * W(Width)棋盘边长
 * S(Size)棋盘大小 S=W*W
 * m(map)地图 动态分配,值:0 空地 1 黑子 2 白子
 * z(zuobiao)光标坐标
 * c(char)动作 ,获取字符(也就是键盘输入)
 * r(round)回合 1为白方 2为黑方,同时当r>4时,表示五连
 * i,j临时变量
 */
int W = 13, S, *m, z = 0, c = 1, r = 2, i, j;
int sum(int v, int l, int s){ //定义函数
    // 判定,判定分为有范围判定,越界判定,是否相同
    return s && (abs(v % W - (v + l) % W) - W + 1 && v + l >= 0 && v + l < S)
        && m[v] == m[v + l] ? 1 + sum(v + l, l, s - 1) : 0;
}
int main(){
    for (m = calloc(S = W * W, 4); r < 4 && c - 27; c = _getch() & 95){
        c - 68 || ++z, c - 65 || --z, c - 83 || (z += W), c - 87 || (z -= W);
        if (z = (z + S) % S, system("cls"), i = 2, !c && !m[z]){
            for (m[z] = r ^= 3; j = i % 3 - 1 + i / 3 * W, i < 6; ++i){
                sum(z, j, 4) + sum(z, -j, 4) > 3 && (r ^= 3, i = r += 4);
            }
        }
        for (i = 0; i < S; ++i % W || _cprintf("%d\n", i / W)){
            _cprintf("%c%c", i - z ? 32 : 62, m[i] ? m[i] - 1 ? 64 : 79 : 32);
        }
        for (i = 0; i < W; ++i)_cprintf(" %c", 97 + i);{
        _cprintf("\n%s", r & 1 ? "White" : "Black"), r < 4 || _cputs(" win!");
        }
    }
}
最后修改:2020 年 10 月 05 日 05 : 28 PM
如果觉得我的文章对你有用,请随意赞赏

发表评论

域名代备案/服务器虚拟主机售卖/二级不死域名代制作/
老备案老域名/营业执照代办/QQ互联代申请/
海报宣传图设计/各类程序授权/各类业务

联系QQ:1032066668
点击联系