🗒️Mini Game:Connect four
2023-6-6|2023-6-16
Anthony
type
status
date
slug
summary
tags
category
icon
password
目的:
我们旨在xv6上写一个竖式四子棋(Connect four)
简介
Connect 4 是一款双人游戏,玩家轮流将彩色圆盘放入七列六行垂直悬挂的网格中。
玩家试图成为第一个形成水平、垂直或对角线的四个自己的圆盘。
该游戏简单易学,但要精通可能具有挑战性。 这是一款深受儿童和成人喜爱的游戏。
以下是 Connect 4 的规则:
游戏在 7x6 网格上进行。
每个玩家有 21 张圆盘,红色或者黄色
玩家轮流将他们的光盘放入网格中,一次一个。
第一个连续获得四张棋子的玩家,无论是水平、垂直还是对角线,都将赢得比赛。
如果格子被填满并且没有玩家连续四个,则游戏平局。

在xv6上编写用户程序需要的前期准备
头文件引入
和普通的c程序使用
#include<stdio.h>
不同,xv6需要引入三个基础头文件其中
#include "user/user.h
是使用系统调用时所必须的在Makefile中加入自己的用户程序
在使用
make qemu
之前进入xv6的Makefile
文件,然后在L118行起始的段落加入自己的函数的名字如上图我加入了自己的用户程序
connect4
在xv6中允许使用的系统调用和userLibrary
在xv6中编写c语言程序与普通的编写相比,最大的不同就是xv6只提供了一些现成的用户函数和系统调用。比如xv6没有提供scanf来做输入,而是提供了gets。我们可以在user.h中查看xv6提供的系统调用和用户函数库。
使用ANSI控制码实现清屏和字体颜色
我们需要在priintf中输入响应的控制码,就可以实现对控制台输出的特殊控制
下面是一些基本控制
下面是字体颜色
本小游戏中,我们使用了清屏,闪烁,和字体颜色
字体颜色
清屏
闪烁
正式编写
欢迎界面和游戏说明
首先我们将用户的操作分成两部分,选位置和下棋子。我们提供了两种方式来选择位置,一种是使用A,D键来左有移动一格,一种是直接输入数字1-7选定某一格。接下来用户需要输入J来确定落子。此外我们应该提供悔棋一步,重启游戏和退出游戏的功能。
欢迎页面的书写很简单,只需要不断的printf就可以了。(我还画了一只小兔zi~

棋盘的定义和绘制
我们最终画出来的棋盘应该是这样子的

我们可以把它拆解成4部分。当前落子的用户,当前指针所在的位置,棋盘的分隔栏,棋盘的底座。
除了棋盘的分隔栏之外,其他的都可以无脑暴力输出
printCurrentPlayer
drawCursor
底座
对于棋盘分隔栏,其实也包括之后要放进去的棋子,为了编写方便,我们可以将他们看成一个整体。我们知道原先的connect4游戏是6行7列的,那么我们就应该有8个挡板,7个落子位,所以我们用一个6*15的数组去储存棋盘的信息。
那么落子应该改变数组的哪个地方呢,显然我们落子的地方都只会是数组列的奇数下标,找规律就好了。
initBoard
其中注意一下第一个分隔栏和最后一个分隔栏是双栏。还有要给棋子留下空闲的位置。
循环体和接收用户输入
我们的游戏要运行在一个while(1)循环体中,在系统调用read中使用文件描述符0来读取输入。
在每次用户落子之后,都要改变当前用户,然后渲染棋盘。
接下来就是一些用户输入的处理了
退出游戏
直接系统调用exit(0)
重启游戏
重启游戏记得要将游戏结束标志位变成0,然后重新初始化棋盘。
指针选择
接收用户的输入,A/D 或者0-7。但是在接收这些输入之前,应该判断游戏是否结束。之后做相应的逻辑操作就好。在用户移动光标之后,我们应该直接渲染棋盘,然后continue到下一次循环,因为我们不需要在循环的尾部去切换用户。(当然你有自己的逻辑也可以,各有各的实现)
落子
在讲落子之前要先讲几个帮助的数据结构
其中bars[i]代表的是每一列,bars[i][j]代表的是每一列的棋子
具象出来就是
bars[0][5] bars[1][5] …
bars[0][4]
…
bars[0][0] bars[1][0]…
barsLen则代表了每一列的当前高度
pieceRed 和 pieceYellow 分别是红色和黄色的小圆片。
落子,我们首先要判断有些是否结束,以及该栏是不是满了。如果条件允许,那么久修改board对应的位置为红色或者黄色的圆片。然后也要给bars对应的位置复制,并且增加该Bar的长度。落子之后,我们要检查是否有赢家(稍后讲)。如果没有赢家,并且棋盘满了,那么就是和局,如果有赢家,就输出,然后结束。
检查赢家
一种方法是对于棋盘的每一个有棋子的位置都沿着米字的四个方向检查是否有连续的四个
一种方法是遍历棋盘所有可能连成四个的地方然后检查是否有连续的四个
一种方法是对于刚落子的位置沿着米字的四个方向检查是否有连续的四个
我在这里实现了后面两种
帮助函数 getLongest()
这个函数接收一个列表,然后检查列表里是否有连续4个红色或者连续4个黄色,红色返回1,黄色返回2,没有返回0。
帮助函数resetCheckList()
在接下来的遍历中,我们每一次获取checklist放入getLongest检查过后,都需要重置列表
方法1:遍历棋盘所有可能连成四个的地方然后检查是否有连续的四个
对于直线,我们遍历每一列和每一行,然后拿到棋子,放入getLongest检查。
对于斜线,下图表示了所有可能的情况。我们只需要选择好原点,然后向左下或者右下遍历即可。

右下方向
左下方向
方法2:对于刚落子的位置沿着米字的四个方向检查是否有连续的四个
首先获取落子的位置,然后分别往左下角,右下角,左侧,下侧,然后往右上角,左上角,右侧,上侧获取棋子,把他们装进列表,传递给getLongest检查。
撤回一步
只需要一个变量储存上一次落子的指针位置即可。
为了防止连续撤回两次,还需要一个undoFlag。撤回一次,并且没有落子的话将不允许撤回。
接下来,将上一次指针的bar长度减一,值置为空,并且将board对应的位置也置为空。
最后将当前指针位置改成上一次指针位置即可。
现在开始享受您的游戏叭
启动界面

游戏中…(没有刷新界面)

撤回一步(有刷新界面)

胜利

错误判断

