Skip to content

frustigor/gomoku-game

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Gomoku Game

五子棋游戏。

How to run?

Clone this repo to your own computer. Then run:

npm install
npm start

And open your browser to visit https://localhost:3988.

Demo: http://www.tangshuang.net/trunk/gomoku/

Implemenet

该游戏的实现很简单,主要包含如下部分:

事件系统

位于core/Events.js中的Events是所有带事件系统的基类,大部分其他类都extends于这个类。主要有on off trigger三个方法。和jquery的用法差不多。

Gomoku游戏规则类

位于core/Gomoku.js, 这个类处理游戏的过程和规则,只实现了最简单的核心规则,控制着游戏的开始、着棋、胜负判定、结束几个过程,保存着棋盘、复盘信息、玩家实例引用、下一位玩家等信息。使用也很简单:

let gomoku = new Gomoku(playerA, playerB) // playerA为先手玩家
gomoku.start() // 开始游戏,保存了nextPlayer信息
...
gomoku.put(x, y, palyerB) // 以棋盘左上角顶点为(0, 0)的坐标系统,第三个参数是玩家实例引用

在调用.put方法时,会自动触发胜负判定。如果发现一方已胜,会调用end方法,抛出一个gameover事件,外部可以监听这个事件来确定接下来怎么做。

gomoku.on('gameover', e => {
  // 可以通过复盘信息找到最后的赢家
  let winner = gomoku.process[gomoku.process.length - 2].player // 因为process保存的最后一个元素是结束时间,所以这里减2
})

通过复盘信息gomoku.process,你还可以复盘对弈过程(含时间信息)。利用这个信息,也可以实现悔棋功能。

Player玩家基类

位于core/Player.js,这个类主要提供一个玩家的基类,它的实例主要有三个方法:think, put, stopThinking.

think方法返回一个promise,表示玩家在思考下一步怎么走。当promise resolve的时候,表示玩家想到了怎么走,得到一个{ x, y }信息,这个信息可以用来传给gomoku实例和画布。

put方法表示玩家下决心给出行棋信息。这个方法主要在和画布交互时调用,当用户作为玩家,点击画布上的一个点时,画布会抛出一个被点击事件,并且返回点击的位置处于棋盘的什么位置,在这个点击事件的回调函数中,调用player.put方法,就可以使think方法resolve。

stopThinking主要是在用户悔棋的时候调用,它可以放弃掉当前的think行为。

玩家思考过程采用promise的好处是,我们甚至可以将单机游戏扩展为在线游戏。只需要在服务端同步棋盘信息,或者用户点击之后的落子信息即可。

Robot机器人类

位于core/Robot.js,主要用于实现一个机器人和玩家对战。该类也有一个think方法,表示机器人也在“思考”,和上述玩家的过程是一样的,也是一个promise。机器人没有和画布交互的需要,因此不提供put方法,也没有stopThinking的必要。

机器人算法是从网上抄的,主要分为三个部分: 1.总共有几种赢法。五子棋五颗棋子连在一起就算赢,标准棋盘15x15,因此,五颗棋子出现的情况全部可以枚举出来。总共500多种。把这些信息记录下来,就是赢法集合。 2.当前棋盘两边玩家在每种赢法上的得分。通过对棋盘信息进行遍历,可以知道当前棋盘上,每一种赢法,每位玩家都到了什么状况,比如有一种赢法要求五颗棋子横线a1-e1排列,此时玩家A在a2上有一颗棋子,那么他在这个赢法上的得分就是1. 3.下一步棋在每一个位置上的得分。对棋盘遍历之后,在没有棋子的点上,如果玩家下在这个位置上,可能赢的得分是多少。计算这个得分,首先要考虑玩家如果下这个位置,所以哪几种赢法,然后再去看玩家在这个赢法上已有的得分,如果玩家在这个赢法上得分很高了,那么下这步棋的得分就会更高。最后通过对每个位置上的得分进行比较,把得分最高的那个位置x,y信息返回。

这个算法是从网上学来的,稍做了封装,可以通过传入棋盘信息,得到下一步应该下哪一步棋。它没有和任何ui或外部操作绑定在一起,因此,可以作为函数,对任何棋局进行计算(当然,还是有一定的规则要求,棋盘格子内容必须保存当前实例)。通过这个类,我们甚至可以让两个机器人下棋,看看谁能赢。

Canvas画布类

位于ui/Canvas.js,包含了一个.scss样式文件。它主要实现在给定的DOM节点画出棋盘、落子信息。它是DOM实现的,如果想用canvas或svg实现,需要实现如下方法:

1.draw(x, y, isBlack) // 落子,isBlack表示是否是黑子,黑方总是先手 2.remove(x, y) // 移除该棋子,悔棋时用 3.clean() // 清空棋盘上所有棋子 4.handle(fn) // 设置用户点击棋盘时的回调,fn = (x, y) => player.put({ x, y }),这样就可以把点击事件传出去

只要实现了上述接口,主类就可以调用canvas实例,无论canvas内部是通过什么技术实现的,都不重要了。

GomokuGame主类

这个类位于GomokuGame.js,通过对上面这些类的组装,为外部实现一个五子棋游戏提供了基础。由于我们要做的是一款人机对战单机版,所以它主要提供:

1.createPlayer(name) // 设置玩家姓名,这样可以增加游戏互动性,当然,如果为了快速游戏,也可以屏蔽掉玩家输入name这块 2.pickSide(bool) // 玩家是否先手,如果传入的是true,则表示玩家先着,玩家为黑方 3.start() // 游戏开始,先手玩家的think方法被调用(把机器人当玩家),游戏开始后无需调用其他方法,直到游戏结束,会抛出gameover事件 4.regret() // 悔棋一步,玩家自己的回合才可以调用,机器人思考时,这个方法无效,悔棋后进入玩家的think过程 5.redo() // 撤销悔棋,继续游戏,玩家回合才可以调用,之后进入玩家think阶段 6.restart() // 重新开始游戏,(可在中途或结束后),调用后需要重新调用pickSide(可选)和start方法 7.mount(selector) // 将画布DOM挂载到对应的html标签,这个方法必须在start之前调用

主类主要是实现封装目的,增加控制流程,如果要对游戏进行改造,很大程度上就是对GomokuGame类进行改造,例如可以增加计时功能。例如两边玩家每步棋只有1分钟思考时间,如果到时间没有下棋直接跳过自己回合,由对方着棋,那么可以在think方法调用时增加一个计时器,到时后,调用player.stopThinking和gomoku.skip,再调用主类的.process方法继续游戏。

交互界面

游戏的界面交互靠三个index文件完成。index.js里面实例化了主类得到一个game实例,调用game的上述方法来控制游戏进程,并且监听游戏过程中抛出的一些事件做相应的处理。同时,监听用户在页面上的一些点击动作,在回调中执行game的方法,实现用户通过界面控制游戏。

About

A simple gomoku game implemented with JS.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 83.8%
  • CSS 11.7%
  • HTML 4.5%