Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

48.帮学弟做题--WebSocket和Vue的五子棋 #51

Open
ccforward opened this issue Dec 18, 2016 · 29 comments
Open

48.帮学弟做题--WebSocket和Vue的五子棋 #51

ccforward opened this issue Dec 18, 2016 · 29 comments
Assignees

Comments

@ccforward
Copy link
Owner

ccforward commented Dec 18, 2016

socket.io 和 Vue.js 的五子棋

群里有个同学要做个五子棋的面试题,于是拿出了以前写的代码,但是有bug,所以重做了一遍。

代码只是做了简单实现,但是去面试足够了,顺便写篇文章对思路和代码详细解释下。

Demo & 源码

单机Demo

单机Demo源码
可联机Demo源码

单机版详解

1、棋盘布局

棋盘(正方形)是由一个个的方块构成,棋子可落在横竖线的交点处,棋盘基本都是这种样子

那就用一个空的 <i></i> 标签作为一个方块,伪元素 before after 作为横竖中心线形成一个十字

然后一行的 <i> 标签排列下去,在需要换行处加一个 <br> 标签, 伪代码如下,

// 长宽为 11 的正方形棋盘
<template v-for="x in 11">
    <template v-for="y in 11">
        <i></i>
        <br v-if="x == 11">
    </template>
</template> 

棋盘样式代码

2、坐标初始化

对于后面每一步下棋落子,都需要知道具体棋子的位置,所以要把棋盘所有位置都添加坐标

因为是二维棋盘,所以只需要用长和宽两个嵌套循环初始化每个位置的坐标信息,并存储在 pieces 对象中,而且可以初始化中间棋子的为黑棋子。

每个坐标对象的key为 (x,y) 坐标值, value 为当前坐标的棋子信息 (w:白棋 b:黑棋)

3.1、落子

这一步很简单,因为每一个坐标初始化了数据,所以加上监听 tick 方法即可

<i :class="pieces[_cover(x)+_cover(y)]" @click="tick(x,y)"></i>

3.2、悔棋

这算是额外的功能,加个状态 last 用来存储每一步的坐标, 想悔棋,直接把上一步坐标的数据置空即可。

4、判断输赢

这是五子棋的核心,相对也最麻烦,每次落子(坐标 x,y ), 都需要从 ** 横向、竖向、\向、/向 ** 四个方向的其他棋子来判断结果。

横向 竖向

这两个方向很简单,从落子坐标的最左处和最上处挨个判断是否和当前落子的颜色是否相同,连续5个即为获胜。

\ 方向

先计算 \ 方向上从当前落子点往左上方后退x(最大5)个位置后的坐标(_x,_y)

然后从 (_x,_y) 开始往右下角方向用 for 循环逐一的比较每个坐标,循环长度为该方向最多棋子数(其实这里判断五次即可,用最多棋子数会有多余的超出棋盘的坐标进入循环中,小细节,暂时不修改)

/ 方向

/ 方向 相当于 \ 方向的镜像

同样计算出从当前落子点往左下方后退x (最大5) 个位置后的坐标, 然后往右上角方向逐一的比较,据该方向上是否有连续5个相同的棋子判断结果,这里涉及到镜像坐标的计算,算法有点绕,具体的判断可以参考代码

联机版

每个联机的用户都可以做主机,也都可以输入其他主机的 socket.id 来配对

这里 WebSocket 用了 socket.io 来做通信。

服务端

const players = {} // sid和socket对象映射关系 id:socket
const relations = {} // 每个玩家和对手的对应关系  id1:id2   id2:id1

players 对象存储每个玩家的 sid和socket 对象映射关系
relations 对象存储每个玩家和对手的对应关系

这里只用了两个事件 link 和 tick

  • link
    用于监听用户连接一个主机,连接成功后存储用户关系并通知双方连接成功
  • tick
    监听任意用户下棋落子事件,接收所有坐标和落子信息,并通知给对手

客户端

客户端监听 连接事件 和 落子事件(tick-back)

客户端发送 link事件 来连接主机
发送 tick事件 来同步落子和坐标信息 (为了方便没有添加websocket通信失败的处理)

整个客户端的代码都比较简单,直接贴出来了

const socket = io.connect('http://127.0.0.1:8888')
socket.on('connect', () => {
  this.socket = socket
})

socket.on('linked', () => {
    alert('有主机连接成功,等待对方下棋')
})
socket.on('linkOK', () => {
    alert('连接主机成功,开始下棋')
    // 连接其他主机 成为白棋子 可以落子
    this.player = 0
    this.canPlay = true
})

// 对手落子后数据返回
socket.on('tick-back', d => {
  const data = JSON.parse(d)
  this.pieces = data.pieces;
  this.canPlay = true
  if(data.gameOver){
    alert('game over')
  }
})

最后

这是给群里的学弟提供面试题的demo,主要看思路,难免很多细节没处理,bug多点。。。

@ccforward ccforward self-assigned this Dec 18, 2016
@codedart2018
Copy link

牛逼

@Diamondsiron
Copy link

厉害了我的哥

@juglans
Copy link

juglans commented Dec 19, 2016

厉害了office哥,不过还有优化空间,棋子加上渐变、棋盘四周搞上跑马灯、出棋发出拔剑的声音基本就差不多了。

@DoYouZz
Copy link

DoYouZz commented Dec 19, 2016

厉害了我的天

@zjhr
Copy link

zjhr commented Dec 19, 2016

吊炸天!!

@DuckDeck
Copy link

一个字,吊

@splinfengwang
Copy link

好玩好玩

@caiyongmin
Copy link

相当6,咳咳

@Arrray
Copy link

Arrray commented Dec 21, 2016

厉害厉害,学习了!

@luzemin
Copy link

luzemin commented Dec 21, 2016

献上膝盖

@cangku
Copy link
Contributor

cangku commented Dec 22, 2016

你好,仔细学习了一下你的源码,感觉你的思路好清晰。我自己实现的时候,我发觉对于斜线的分析还是有一些吃力,这种思维方面的训练有好的推荐吗?基础不是很好,这是我的弱项。还有一个小疑问就是这种判断的算法其实不是最优的对吗?比如说,我现在把棋盘扩大,其实我只是需要判断以落子的位置以最大可能为5的范围来判断就行,是吗?

@ccforward
Copy link
Owner Author

@cangku
训练的话 建议你去做做 leetcode 上面的题目 绝大多数都可用js实现 顺带着去看看算法和数据结构,算法的思维还是个长时间慢慢的积累的东西

关于落子的判断范围,其实可以做到5次最少判断的,就是需要考虑更多的情况,尤其是在边界上的判断,这就需要更详细的算法了。因为实际情况下棋盘也不是很大,以现在的算法对性能影响微乎其微,所以也没做优化了。

@cangku
Copy link
Contributor

cangku commented Dec 22, 2016

@ccforward 好的,谢谢

@narco001
Copy link

厉害了我的哥,献上膝盖的同时,推荐其它vue的实例,http://www.17shulihua.com/archives/category/frontend-demo/vue-demo

@layne92
Copy link

layne92 commented Dec 23, 2016

66

@yujihu
Copy link

yujihu commented Dec 27, 2016

PS:你的判断输赢逻辑有bug吧,[2][4],[3][3],[4][2],[5][1],[6][0]不会判断为赢

@ghost
Copy link

ghost commented Jan 14, 2017

厉害,值得学习。

@ryu2gaku
Copy link

厉害了我的哥

@hejingscu
Copy link

demo挂了

@ccforward
Copy link
Owner Author

@hejingscu

demo地址是 http://ccforward.github.io/game/chess/chess.html

我这没问题 能给个截图看看嘛

@unknwon
Copy link

unknwon commented Feb 15, 2017

厉害了我的哥!

@shacai
Copy link

shacai commented Feb 18, 2017

可联机demo 4个文件拷到本地文件夹 然后npm install下载之后 再node socket.js 发现跑不起来啊 题主能说说怎么在本地跑吗 漏了什么 http://localhost:8888/ 打不开无法运行啊

@ccforward
Copy link
Owner Author

@shacai

不要访问 http://localhost:8888/

应该访问 chess-connect.html

@shacai
Copy link

shacai commented Feb 19, 2017

@ccforward 但是访问 chess-connect.html 打开这个页面是一片空白啊...
111

@ccforward
Copy link
Owner Author

@shacai

你看看源码 里面两个外部js文件的引用方式没有加 schema

你改成自己本地的服务器访问或者给两个外部的js 加上 http:

@shacai
Copy link

shacai commented Feb 19, 2017

@ccforward 真的是 谢谢大神指点 原来是没有加 http: 难怪空白

@maicong
Copy link

maicong commented Mar 24, 2017

大神很厉害啊!不过有 BUG:
qq20170324-171846

@Anshiii
Copy link

Anshiii commented Jun 13, 2017

厉害,思路好清晰...自己的五子棋拖了很久也没把联机功能加上,不过这里的五子棋是用canvas画的,当时还用了vue,然后用canvas画的话..基本也展现不出vue的优点了...

@plh97
Copy link

plh97 commented Apr 30, 2018

既然vue提供了mvvm的思路,
那么维护 一个vue数组就好,数据模型同步到view上面,

const map = [
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
];

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests