├── LICENSE
├── README.md
├── card-game-client
├── .gitignore
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
└── src
│ ├── App.vue
│ ├── assets
│ ├── dedication.png
│ ├── hurt.png
│ ├── logo.png
│ └── strong.png
│ ├── components
│ └── Card.vue
│ ├── main.js
│ ├── pages
│ ├── GameTable.vue
│ └── Login.vue
│ ├── router.js
│ ├── store.js
│ └── utils.js
└── card-game-server
├── .gitignore
├── app.js
├── constants.js
├── handler.js
├── package-lock.json
├── package.json
└── utils.js
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Xie Jingyang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # card-game
2 | 这是一个网页端的卡牌游戏
3 |
4 | [线上地址](http://cardgame.xiejingyang.com)
5 |
6 | ## 技术栈
7 | * vue全家桶
8 | * velocity.js
9 | * socketio
10 | * nodejs
11 | * express
12 | * mongodb
13 |
14 | ## 源码查看方式
15 | 如果你是看了我的博客过来的,那么你可以通过切换tag来和文章进行同步
16 |
17 | [博客地址](http://blog.xiejingyang.com)
18 |
19 |
--------------------------------------------------------------------------------
/card-game-client/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw*
22 |
--------------------------------------------------------------------------------
/card-game-client/README.md:
--------------------------------------------------------------------------------
1 | # card-game-client
2 |
3 | ## Project setup
4 | ```
5 | npm install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | npm run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | npm run build
16 | ```
17 |
18 | ### Run your tests
19 | ```
20 | npm run test
21 | ```
22 |
23 | ### Lints and fixes files
24 | ```
25 | npm run lint
26 | ```
27 |
28 | ### Customize configuration
29 | See [Configuration Reference](https://cli.vuejs.org/config/).
30 |
--------------------------------------------------------------------------------
/card-game-client/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/card-game-client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "card-game-client",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "socket.io-client": "^2.2.0",
12 | "velocity-animate": "^1.5.2",
13 | "vue": "^2.5.21",
14 | "vue-router": "^3.0.1",
15 | "vuex": "^3.0.1"
16 | },
17 | "devDependencies": {
18 | "@vue/cli-plugin-babel": "^3.2.0",
19 | "@vue/cli-plugin-eslint": "^3.2.0",
20 | "@vue/cli-service": "^3.2.0",
21 | "babel-eslint": "^10.0.1",
22 | "eslint": "^5.8.0",
23 | "eslint-plugin-vue": "^5.0.0",
24 | "vue-template-compiler": "^2.5.21"
25 | },
26 | "eslintConfig": {
27 | "root": true,
28 | "env": {
29 | "node": true
30 | },
31 | "extends": [
32 | "plugin:vue/essential",
33 | "eslint:recommended"
34 | ],
35 | "rules": {},
36 | "parserOptions": {
37 | "parser": "babel-eslint"
38 | }
39 | },
40 | "postcss": {
41 | "plugins": {
42 | "autoprefixer": {}
43 | }
44 | },
45 | "browserslist": [
46 | "> 1%",
47 | "last 2 versions",
48 | "not ie <= 8"
49 | ]
50 | }
51 |
--------------------------------------------------------------------------------
/card-game-client/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xieisabug/card-game/a97a633a453b576ab7ea90984cb44abc2bfcd31f/card-game-client/public/favicon.ico
--------------------------------------------------------------------------------
/card-game-client/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 程序员大战
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/card-game-client/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
18 |
--------------------------------------------------------------------------------
/card-game-client/src/assets/dedication.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xieisabug/card-game/a97a633a453b576ab7ea90984cb44abc2bfcd31f/card-game-client/src/assets/dedication.png
--------------------------------------------------------------------------------
/card-game-client/src/assets/hurt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xieisabug/card-game/a97a633a453b576ab7ea90984cb44abc2bfcd31f/card-game-client/src/assets/hurt.png
--------------------------------------------------------------------------------
/card-game-client/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xieisabug/card-game/a97a633a453b576ab7ea90984cb44abc2bfcd31f/card-game-client/src/assets/logo.png
--------------------------------------------------------------------------------
/card-game-client/src/assets/strong.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xieisabug/card-game/a97a633a453b576ab7ea90984cb44abc2bfcd31f/card-game-client/src/assets/strong.png
--------------------------------------------------------------------------------
/card-game-client/src/components/Card.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
{{name}}
7 |
{{cost}}
8 |
9 |
{{content}}
10 |
11 |
12 |
13 |
14 |
{{attack}}
15 |
16 |
17 |
21 |
22 |
23 |
24 | {{hurtNumber > 0 ? `+${hurtNumber}` : hurtNumber}}
25 |
26 |
27 |
28 |
29 |
184 |
185 |
298 |
--------------------------------------------------------------------------------
/card-game-client/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | import store from './store'
5 |
6 | Vue.config.productionTip = false
7 |
8 | new Vue({
9 | router,
10 | store,
11 | render: h => h(App)
12 | }).$mount('#app')
13 |
--------------------------------------------------------------------------------
/card-game-client/src/pages/GameTable.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
18 |
19 |
27 |
36 |
37 |
38 |
39 |
40 |
48 |
49 |
50 |
51 | 正在匹配,请等待
52 |
53 |
54 |
55 |
56 |
57 |
58 |
342 |
343 |
413 |
--------------------------------------------------------------------------------
/card-game-client/src/pages/Login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 你的文字
7 |
8 |
9 | 你的文字
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
114 |
115 |
--------------------------------------------------------------------------------
/card-game-client/src/router.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import GameTable from './pages/GameTable.vue'
4 | import Login from './pages/Login.vue'
5 |
6 | Vue.use(Router)
7 |
8 | export default new Router({
9 | routes: [
10 | {
11 | path: '/',
12 | name: 'gameTable',
13 | component: GameTable
14 | },
15 | {
16 | path: '/login',
17 | name: 'login',
18 | component: Login
19 | }
20 | ]
21 | })
22 |
--------------------------------------------------------------------------------
/card-game-client/src/store.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | Vue.use(Vuex)
5 |
6 | export default new Vuex.Store({
7 | state: {
8 |
9 | },
10 | mutations: {
11 |
12 | },
13 | actions: {
14 |
15 | }
16 | })
17 |
--------------------------------------------------------------------------------
/card-game-client/src/utils.js:
--------------------------------------------------------------------------------
1 | export function buildClassName(obj) {
2 | let className = [];
3 |
4 | Object.keys(obj).forEach(i => {
5 | obj[i] && className.push(i)
6 | });
7 |
8 | return className.join(" ");
9 | }
10 |
11 | export const AttackType = {
12 | ATTACK: 1,
13 | BE_ATTACKED: 2
14 | };
--------------------------------------------------------------------------------
/card-game-server/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/card-game-server/app.js:
--------------------------------------------------------------------------------
1 | let http = require('http');
2 | let express = require('express');
3 | let cors = require('cors');
4 | let bodyParser = require('body-parser');
5 | let socket = require("socket.io");
6 |
7 | let app = express();
8 |
9 | let handleSynchronousClient = require('./handler');
10 |
11 | app.use(cors());
12 | app.use(bodyParser.json());
13 | app.use(bodyParser.urlencoded({extended: false}));
14 |
15 | let server = http.createServer(app);
16 | let socketServer = socket(server);
17 |
18 | server.listen(4001, function () {
19 | console.log("listen");
20 | });
21 | socketServer.on('connection', function (socket) {
22 | console.log("connect one on :" + new Date().toLocaleString());
23 |
24 | socket.on('COMMAND', function () {
25 | let args = Array.prototype.slice.call(arguments);
26 | args.push(socket, socketServer);
27 | handleSynchronousClient.apply(this, args);
28 | });
29 |
30 |
31 |
32 | socket.on('disconnect', function () {
33 | console.log("disconnect one on :" + new Date().toLocaleString());
34 | });
35 |
36 | socket.on("ADD", function() {
37 | console.log(arguments);
38 | let args = Array.prototype.slice.call(arguments);
39 | let roomNumber = existUserGameRoomMap[args.userId];
40 | memoryData[roomNumber].count += 1;
41 | memoryData[roomNumber]["one"].socket.emit("UPDATE", {
42 | count: memoryData[roomNumber].count
43 | });
44 | memoryData[roomNumber]["two"].socket.emit("UPDATE", {
45 | count: memoryData[roomNumber].count
46 | });
47 | })
48 |
49 | });
50 |
51 |
--------------------------------------------------------------------------------
/card-game-server/constants.js:
--------------------------------------------------------------------------------
1 | // {
2 | // id: 0,
3 | // name: "xxxxxx",
4 | // cardType: CardType.CHARACTER,
5 | // cost: 3,
6 | // content: `xxxxxxxxxx`,
7 | // attack: 2,
8 | // life: 1,
9 | // attackBase: 2,
10 | // lifeBase: 1,
11 | // type: [""],
12 | // isStrong: true,
13 | // isFullOfEnergy: true,
14 | // isDedication: true,
15 | // onStart: function() {},
16 | // onOtherCardStart: function() {},
17 | // onMyTurnStart: function() {},
18 | // onMyTurnEnd: function() {},
19 | // onChooseTarget: function() {},
20 | // onEnd: function() {},
21 | // onTableCardChange: function() {},
22 | // }
23 |
24 | const CardType = {
25 | EFFECT: 1, // 效果牌
26 | CHARACTER: 2, // 人物牌
27 | };
28 |
29 | const CardList = [
30 | {
31 | id: 1,
32 | name: "励志的演说家",
33 | cardType: CardType.CHARACTER,
34 | cost: 2,
35 | content: ``,
36 | attack: 1,
37 | life: 2,
38 | attackBase: 1,
39 | lifeBase: 2,
40 | type: [""]
41 | },
42 | {
43 | id: 5,
44 | name: "高级程序员",
45 | cardType: CardType.CHARACTER,
46 | cost: 7,
47 | content: ``,
48 | attack: 7,
49 | life: 7,
50 | attackBase: 7,
51 | lifeBase: 7,
52 | type: [""],
53 | isStrong: true
54 | },
55 | {
56 | id: 6,
57 | name: "开发助理",
58 | cardType: CardType.CHARACTER,
59 | cost: 1,
60 | content: ``,
61 | attack: 1,
62 | life: 1,
63 | attackBase: 1,
64 | lifeBase: 1,
65 | type: [""]
66 | },
67 | {
68 | id: 8,
69 | name: "丑陋的开发鼓励师",
70 | cardType: CardType.CHARACTER,
71 | cost: 1,
72 | content: `精力充沛`,
73 | attack: 1,
74 | life: 1,
75 | attackBase: 1,
76 | lifeBase: 1,
77 | type: [""],
78 | isFullOfEnergy: true
79 | }
80 | ];
81 |
82 | const AttackType = {
83 | ATTACK: 1,
84 | BE_ATTACKED: 2
85 | };
86 |
87 | const AttackAnimationType = {
88 | NORMAL: 1
89 | };
90 |
91 | module.exports = {
92 | CardType,
93 | Cards: CardList,
94 | AttackType,
95 | AttackAnimationType
96 | }
--------------------------------------------------------------------------------
/card-game-server/handler.js:
--------------------------------------------------------------------------------
1 | const {
2 | Cards,
3 | CardType,
4 | AttackType,
5 | AttackAnimationType
6 | } = require("./constants");
7 |
8 | const {shuffle} = require("./utils");
9 |
10 | const uuidv4 = require('uuid/v4');
11 | const seedrandom = require("seedrandom");
12 |
13 | const waitPairQueue = []; // 等待排序的队列
14 | const memoryData = {}; // 缓存的房间游戏数据,key => 房间号,value => 游戏数据
15 | const existUserGameRoomMap = {}; // 缓存用户的房间号, key => 用户标识,value => 房间号
16 |
17 |
18 | module.exports = function handleSynchronousClient(args, socket, socketServer) {
19 | switch (args.type) {
20 | case "CONNECT":
21 | connect(args, socket, socketServer);
22 | break;
23 | case "ATTACK_CARD":
24 | attackCard(args, socket);
25 | break;
26 | case "OUT_CARD":
27 | outCard(args, socket);
28 | break;
29 | }
30 | };
31 |
32 | function connect(args, socket, socketServer) {
33 | const {userId} = args;
34 | if (existUserGameRoomMap[userId]) { // 如果存在已经加入的对局,则直接进入之前的对战
35 | let roomNumber = existUserGameRoomMap[userId];
36 | let identity = memoryData[roomNumber]["one"].userId === userId ? "one" : "two";
37 | memoryData[roomNumber][identity].socket = socket;
38 | memoryData[roomNumber][identity].socket.emit("RECONNECT", {
39 | roomNumber: roomNumber,
40 | memberId: identity
41 | });
42 |
43 | sendCards(roomNumber, identity); // 把牌发送给玩家
44 |
45 | } else {
46 | socket.emit("WAITE"); // 不管三七二十一,先给老子等起
47 |
48 | if (waitPairQueue.length === 0) {
49 | waitPairQueue.push({
50 | userId, socket
51 | });
52 |
53 | socket.emit("WAITE");
54 | } else {
55 | let waitPlayer = waitPairQueue.splice(0, 1)[0]; // 随便拉个小伙干一架
56 | let roomNumber = uuidv4(); // 生成房间号码
57 |
58 | let seed = Math.floor(Math.random() * 10000);
59 |
60 | // 初始化游戏数据
61 | waitPlayer.roomNumber = roomNumber;
62 | memoryData[roomNumber] = {
63 | "one": waitPlayer,
64 | "two": {
65 | userId, socket, roomNumber
66 | },
67 | seed, // 随机数种子
68 | rand: seedrandom(seed), // 随机方法
69 | };
70 | existUserGameRoomMap[userId] = roomNumber;
71 | existUserGameRoomMap[waitPlayer.userId] = roomNumber;
72 |
73 | // 进入房间
74 | socket.join(roomNumber);
75 | waitPlayer.socket.join(roomNumber);
76 |
77 | // 游戏初始化完成,发送游戏初始化数据
78 | waitPlayer.socket.emit("START", {
79 | roomNumber,
80 | memberId: "one"
81 | });
82 | socket.emit("START", {
83 | roomNumber,
84 | memberId: "two"
85 | });
86 |
87 | initCard(roomNumber);
88 | }
89 | }
90 | }
91 |
92 | function initCard(roomNumber) {
93 | let random = memoryData[roomNumber].rand() * 2;
94 |
95 | let first = random >= 1 ? "one" : "two"; // 判断当前是哪个玩家出牌
96 | let second = random < 1 ? "one" : "two";
97 |
98 | memoryData[roomNumber]["one"]["remainingCards"] = shuffle(memoryData[roomNumber].rand, Cards.map((c, index) => Object.assign({k : `one-${index}`}, c)));
99 | memoryData[roomNumber]["two"]["remainingCards"] = shuffle(memoryData[roomNumber].rand, Cards.map((c, index) => Object.assign({k : `two-${index}`}, c)));
100 |
101 | let firstRemainingCards = memoryData[roomNumber][first]["remainingCards"];
102 | let secondRemainingCards = memoryData[roomNumber][second]["remainingCards"];
103 |
104 | Object.assign(memoryData[roomNumber][first], {
105 | tableCards:[
106 | getNextCard(firstRemainingCards),
107 | ],
108 | cards: [
109 | getNextCard(firstRemainingCards),
110 | getNextCard(firstRemainingCards),
111 | ],
112 | fee: 10
113 | });
114 |
115 | Object.assign(memoryData[roomNumber][second], {
116 | tableCards:[
117 | getNextCard(secondRemainingCards),
118 | ],
119 | cards: [
120 | getNextCard(secondRemainingCards),
121 | ],
122 | fee: 10
123 | });
124 |
125 | sendCards(roomNumber);
126 |
127 | }
128 |
129 |
130 |
131 | function attackCard(args, socket) {
132 | let roomNumber = args.r, myK = args.myK, attackK = args.attackK, card, attackCard;
133 |
134 | if (!memoryData[roomNumber]) {
135 | return
136 | }
137 |
138 | let belong = memoryData[roomNumber]["one"].socket.id === socket.id ? "one" : "two"; // 判断当前是哪个玩家出牌
139 | let other = memoryData[roomNumber]["one"].socket.id !== socket.id ? "one" : "two";
140 |
141 | let index = memoryData[roomNumber][belong]["tableCards"].findIndex(c => c.k === myK);
142 | let attackIndex = memoryData[roomNumber][other]["tableCards"].findIndex(c => c.k === attackK);
143 |
144 | if (index !== -1 && attackIndex !== -1
145 | && memoryData[roomNumber][belong]["tableCards"].length > index
146 | && memoryData[roomNumber][other]["tableCards"].length > attackIndex) {
147 | card = memoryData[roomNumber][belong]["tableCards"][index];
148 | attackCard = memoryData[roomNumber][other]["tableCards"][attackIndex];
149 |
150 | // 奉献处理
151 | let hasDedication = memoryData[roomNumber][other]["tableCards"].some(c => c.isDedication);
152 |
153 | if (attackCard.isDedication || !hasDedication) {
154 | // 符合奉献的条件
155 | if (attackCard.isStrong) { // 强壮
156 | attackCard.isStrong = false;
157 | } else {
158 | attackCard.life -= card.attack;
159 | }
160 |
161 | if (card.isStrong) { // 强壮
162 | card.isStrong = false;
163 | } else {
164 | card.life -= attackCard.attack;
165 | }
166 |
167 | if (card.onAttack) {
168 | card.onAttack({
169 | myGameData: memoryData[roomNumber][belong],
170 | otherGameData: memoryData[roomNumber][other],
171 | thisCard: card,
172 | beAttackCard: attackCard,
173 | })
174 | }
175 |
176 | if (attackCard.onBeAttacked) {
177 | attackCard.onBeAttacked({
178 | myGameData: memoryData[roomNumber][other],
179 | otherGameData: memoryData[roomNumber][belong],
180 | thisCard: attackCard,
181 | beAttackCard: card,
182 | })
183 | }
184 |
185 | memoryData[roomNumber][belong].socket.emit("ATTACK_CARD", {
186 | index,
187 | attackIndex,
188 | attackType: AttackType.ATTACK,
189 | animationType: AttackAnimationType.NORMAL,
190 | card,
191 | attackCard
192 | });
193 |
194 | memoryData[roomNumber][other].socket.emit("ATTACK_CARD", {
195 | index,
196 | attackIndex,
197 | attackType: AttackType.BE_ATTACKED,
198 | animationType: AttackAnimationType.NORMAL,
199 | card,
200 | attackCard
201 | });
202 |
203 | checkCardDieEvent(roomNumber);
204 | } else {
205 | // error 您必须攻击带有奉献的单位
206 | }
207 | }
208 |
209 | }
210 |
211 | function outCard(args, socket) {
212 | let roomNumber = args.r, index = args.index, card;
213 |
214 | if (!memoryData[roomNumber]) {
215 | return
216 | }
217 |
218 | let belong = memoryData[roomNumber]["one"].socket.id === socket.id ? "one" : "two"; // 判断当前是哪个玩家出牌
219 | let other = memoryData[roomNumber]["one"].socket.id !== socket.id ? "one" : "two";
220 |
221 | // 判断费用和位置是否已经满了
222 | if (index !== -1 && memoryData[roomNumber][belong]['cards'][index].cost <= memoryData[roomNumber][belong]["fee"]) {
223 | card = memoryData[roomNumber][belong]["cards"].splice(index, 1)[0];
224 | if (card.cardType === CardType.CHARACTER && memoryData[roomNumber][belong]["tableCards"].length >= 10) {
225 | // error 场上怪物满了
226 | return;
227 | }
228 |
229 | memoryData[roomNumber][belong]["fee"] -= card.cost;
230 |
231 | memoryData[roomNumber][belong]["tableCards"].push(card);
232 | memoryData[roomNumber][belong].socket.emit("OUT_CARD", {
233 | index,
234 | card,
235 | isMine: true
236 | });
237 | memoryData[roomNumber][other].socket.emit("OUT_CARD", {
238 | index,
239 | card,
240 | isMine: false
241 | });
242 |
243 | let mySpecialMethod = getSpecialMethod(belong, roomNumber);
244 | if (card && card.onStart) {
245 | card.onStart({
246 | myGameData: memoryData[roomNumber][belong],
247 | otherGameData: memoryData[roomNumber][other],
248 | thisCard: card,
249 | specialMethod: mySpecialMethod
250 | })
251 | }
252 |
253 | checkCardDieEvent(roomNumber);
254 | } else {
255 | // error 费用不足
256 | }
257 | }
258 |
259 |
260 | function checkCardDieEvent(roomNumber, level, myKList, otherKList) {
261 | if (!level) {
262 | level = 1;
263 | myKList = [];
264 | otherKList = [];
265 | }
266 |
267 | if (memoryData[roomNumber]["one"]["tableCards"].some(c => c.life <= 0) || memoryData[roomNumber]["two"]["tableCards"].some(c => c.life <= 0)) {
268 | let oneSpecialMethod = getSpecialMethod("one", roomNumber),
269 | twoSpecialMethod = getSpecialMethod("two", roomNumber);
270 |
271 | for (let i = memoryData[roomNumber]["one"]["tableCards"].length - 1; i >= 0; i--) {
272 | let c = memoryData[roomNumber]["one"]["tableCards"][i];
273 |
274 | if (c.life <= 0) {
275 | if (c.onEnd) { // 亡语
276 | c.onEnd({
277 | myGameData: memoryData[roomNumber]["one"],
278 | otherGameData: memoryData[roomNumber]["two"],
279 | thisCard: card,
280 | specialMethod: oneSpecialMethod
281 | })
282 | }
283 | myKList.push(c.k);
284 | memoryData[roomNumber]["one"]["tableCards"].splice(i, 1);
285 | }
286 | }
287 |
288 | for (let i = memoryData[roomNumber]["two"]["tableCards"].length - 1; i >= 0; i--) {
289 | let c = memoryData[roomNumber]["two"]["tableCards"][i];
290 |
291 | if (c.life <= 0) {
292 | if (c.onEnd) { // 亡语
293 | c.onEnd({
294 | myGameData: memoryData[roomNumber]["two"],
295 | otherGameData: memoryData[roomNumber]["one"],
296 | thisCard: card,
297 | specialMethod: twoSpecialMethod
298 | })
299 | }
300 | otherKList.push(c.k);
301 | memoryData[roomNumber]["two"]["tableCards"].splice(i, 1);
302 | }
303 | }
304 |
305 | checkCardDieEvent(roomNumber, level + 1, myKList, otherKList);
306 | }
307 |
308 | if (level === 1 && (myKList.length !== 0 || otherKList.length !== 0)) {
309 | getSpecialMethod("one", roomNumber).dieCardAnimation(true, myKList, otherKList);
310 | }
311 | }
312 |
313 | function getSpecialMethod(identity, roomNumber) {
314 | let otherIdentity = identity === "one" ? "two": "one";
315 |
316 | return {
317 | dieCardAnimation(isMine, myKList, otherKList) {
318 | memoryData[roomNumber][identity].socket.emit("DIE_CARD", {
319 | isMine,
320 | myKList,
321 | otherKList
322 | });
323 |
324 | memoryData[roomNumber][otherIdentity].socket.emit("DIE_CARD", {
325 | isMine: !isMine,
326 | myKList,
327 | otherKList
328 | });
329 | }
330 | }
331 | }
332 |
333 |
334 | function getNextCard(remainingCards) {
335 | if (remainingCards.length > 0) {
336 | return remainingCards.splice(0, 1)[0]
337 | } else {
338 | return null
339 | }
340 | }
341 |
342 | function sendCards(roomNumber, identity) {
343 | if (identity) {
344 | let otherIdentity = identity === "one" ? "two" : "one";
345 |
346 | memoryData[roomNumber][identity].socket.emit("SEND_CARD", {
347 | myCard: memoryData[roomNumber][identity]["cards"],
348 | myTableCard: memoryData[roomNumber][identity]["tableCards"],
349 | otherTableCard: memoryData[roomNumber][otherIdentity]["tableCards"],
350 | })
351 | } else {
352 | sendCards(roomNumber, "one");
353 | sendCards(roomNumber, "two");
354 | }
355 | }
--------------------------------------------------------------------------------
/card-game-server/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "card-game-server",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "accepts": {
8 | "version": "1.3.5",
9 | "resolved": "http://registry.npm.taobao.org/accepts/download/accepts-1.3.5.tgz",
10 | "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
11 | "requires": {
12 | "mime-types": "~2.1.18",
13 | "negotiator": "0.6.1"
14 | }
15 | },
16 | "after": {
17 | "version": "0.8.2",
18 | "resolved": "http://registry.npm.taobao.org/after/download/after-0.8.2.tgz",
19 | "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="
20 | },
21 | "array-flatten": {
22 | "version": "1.1.1",
23 | "resolved": "http://registry.npm.taobao.org/array-flatten/download/array-flatten-1.1.1.tgz",
24 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
25 | },
26 | "arraybuffer.slice": {
27 | "version": "0.0.7",
28 | "resolved": "http://registry.npm.taobao.org/arraybuffer.slice/download/arraybuffer.slice-0.0.7.tgz",
29 | "integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU="
30 | },
31 | "async-limiter": {
32 | "version": "1.0.0",
33 | "resolved": "http://registry.npm.taobao.org/async-limiter/download/async-limiter-1.0.0.tgz",
34 | "integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg="
35 | },
36 | "backo2": {
37 | "version": "1.0.2",
38 | "resolved": "http://registry.npm.taobao.org/backo2/download/backo2-1.0.2.tgz",
39 | "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
40 | },
41 | "base64-arraybuffer": {
42 | "version": "0.1.5",
43 | "resolved": "http://registry.npm.taobao.org/base64-arraybuffer/download/base64-arraybuffer-0.1.5.tgz",
44 | "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
45 | },
46 | "base64id": {
47 | "version": "1.0.0",
48 | "resolved": "http://registry.npm.taobao.org/base64id/download/base64id-1.0.0.tgz",
49 | "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY="
50 | },
51 | "better-assert": {
52 | "version": "1.0.2",
53 | "resolved": "http://registry.npm.taobao.org/better-assert/download/better-assert-1.0.2.tgz",
54 | "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
55 | "requires": {
56 | "callsite": "1.0.0"
57 | }
58 | },
59 | "blob": {
60 | "version": "0.0.5",
61 | "resolved": "http://registry.npm.taobao.org/blob/download/blob-0.0.5.tgz",
62 | "integrity": "sha1-1oDu7yX4zZGtUz9bAe7UjmTK9oM="
63 | },
64 | "body-parser": {
65 | "version": "1.18.3",
66 | "resolved": "http://registry.npm.taobao.org/body-parser/download/body-parser-1.18.3.tgz",
67 | "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=",
68 | "requires": {
69 | "bytes": "3.0.0",
70 | "content-type": "~1.0.4",
71 | "debug": "2.6.9",
72 | "depd": "~1.1.2",
73 | "http-errors": "~1.6.3",
74 | "iconv-lite": "0.4.23",
75 | "on-finished": "~2.3.0",
76 | "qs": "6.5.2",
77 | "raw-body": "2.3.3",
78 | "type-is": "~1.6.16"
79 | }
80 | },
81 | "bytes": {
82 | "version": "3.0.0",
83 | "resolved": "http://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz",
84 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
85 | },
86 | "callsite": {
87 | "version": "1.0.0",
88 | "resolved": "http://registry.npm.taobao.org/callsite/download/callsite-1.0.0.tgz",
89 | "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
90 | },
91 | "circular-json": {
92 | "version": "0.5.9",
93 | "resolved": "http://registry.npm.taobao.org/circular-json/download/circular-json-0.5.9.tgz",
94 | "integrity": "sha1-kydjroj0996teg0JyKUaR0OlOx0="
95 | },
96 | "component-bind": {
97 | "version": "1.0.0",
98 | "resolved": "http://registry.npm.taobao.org/component-bind/download/component-bind-1.0.0.tgz",
99 | "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="
100 | },
101 | "component-emitter": {
102 | "version": "1.2.1",
103 | "resolved": "http://registry.npm.taobao.org/component-emitter/download/component-emitter-1.2.1.tgz",
104 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
105 | },
106 | "component-inherit": {
107 | "version": "0.0.3",
108 | "resolved": "http://registry.npm.taobao.org/component-inherit/download/component-inherit-0.0.3.tgz",
109 | "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="
110 | },
111 | "content-disposition": {
112 | "version": "0.5.2",
113 | "resolved": "http://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.2.tgz",
114 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
115 | },
116 | "content-type": {
117 | "version": "1.0.4",
118 | "resolved": "http://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz",
119 | "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js="
120 | },
121 | "cookie": {
122 | "version": "0.3.1",
123 | "resolved": "http://registry.npm.taobao.org/cookie/download/cookie-0.3.1.tgz",
124 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
125 | },
126 | "cookie-signature": {
127 | "version": "1.0.6",
128 | "resolved": "http://registry.npm.taobao.org/cookie-signature/download/cookie-signature-1.0.6.tgz",
129 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
130 | },
131 | "core-util-is": {
132 | "version": "1.0.2",
133 | "resolved": "http://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz",
134 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
135 | },
136 | "cors": {
137 | "version": "2.8.5",
138 | "resolved": "http://registry.npm.taobao.org/cors/download/cors-2.8.5.tgz",
139 | "integrity": "sha1-6sEdpRWS3Ya58G9uesKTs9+HXSk=",
140 | "requires": {
141 | "object-assign": "^4",
142 | "vary": "^1"
143 | }
144 | },
145 | "date-format": {
146 | "version": "1.2.0",
147 | "resolved": "http://registry.npm.taobao.org/date-format/download/date-format-1.2.0.tgz",
148 | "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg="
149 | },
150 | "debug": {
151 | "version": "2.6.9",
152 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz",
153 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
154 | "requires": {
155 | "ms": "2.0.0"
156 | }
157 | },
158 | "depd": {
159 | "version": "1.1.2",
160 | "resolved": "http://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz",
161 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
162 | },
163 | "destroy": {
164 | "version": "1.0.4",
165 | "resolved": "http://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz",
166 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
167 | },
168 | "ee-first": {
169 | "version": "1.1.1",
170 | "resolved": "http://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz",
171 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
172 | },
173 | "encodeurl": {
174 | "version": "1.0.2",
175 | "resolved": "http://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz",
176 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
177 | },
178 | "engine.io": {
179 | "version": "3.3.2",
180 | "resolved": "http://registry.npm.taobao.org/engine.io/download/engine.io-3.3.2.tgz",
181 | "integrity": "sha1-GMvItvNulGHFwPgd8rgw3hYFilk=",
182 | "requires": {
183 | "accepts": "~1.3.4",
184 | "base64id": "1.0.0",
185 | "cookie": "0.3.1",
186 | "debug": "~3.1.0",
187 | "engine.io-parser": "~2.1.0",
188 | "ws": "~6.1.0"
189 | },
190 | "dependencies": {
191 | "debug": {
192 | "version": "3.1.0",
193 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz",
194 | "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
195 | "requires": {
196 | "ms": "2.0.0"
197 | }
198 | }
199 | }
200 | },
201 | "engine.io-client": {
202 | "version": "3.3.1",
203 | "resolved": "http://registry.npm.taobao.org/engine.io-client/download/engine.io-client-3.3.1.tgz",
204 | "integrity": "sha1-r+20oHsupItxkMMTa/6pj91PDwM=",
205 | "requires": {
206 | "component-emitter": "1.2.1",
207 | "component-inherit": "0.0.3",
208 | "debug": "~3.1.0",
209 | "engine.io-parser": "~2.1.1",
210 | "has-cors": "1.1.0",
211 | "indexof": "0.0.1",
212 | "parseqs": "0.0.5",
213 | "parseuri": "0.0.5",
214 | "ws": "~6.1.0",
215 | "xmlhttprequest-ssl": "~1.5.4",
216 | "yeast": "0.1.2"
217 | },
218 | "dependencies": {
219 | "debug": {
220 | "version": "3.1.0",
221 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz",
222 | "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
223 | "requires": {
224 | "ms": "2.0.0"
225 | }
226 | }
227 | }
228 | },
229 | "engine.io-parser": {
230 | "version": "2.1.3",
231 | "resolved": "http://registry.npm.taobao.org/engine.io-parser/download/engine.io-parser-2.1.3.tgz",
232 | "integrity": "sha1-dXq5cPvy37Mse3SwMyFtVznveaY=",
233 | "requires": {
234 | "after": "0.8.2",
235 | "arraybuffer.slice": "~0.0.7",
236 | "base64-arraybuffer": "0.1.5",
237 | "blob": "0.0.5",
238 | "has-binary2": "~1.0.2"
239 | }
240 | },
241 | "escape-html": {
242 | "version": "1.0.3",
243 | "resolved": "http://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz",
244 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
245 | },
246 | "etag": {
247 | "version": "1.8.1",
248 | "resolved": "http://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz",
249 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
250 | },
251 | "express": {
252 | "version": "4.16.4",
253 | "resolved": "http://registry.npm.taobao.org/express/download/express-4.16.4.tgz",
254 | "integrity": "sha1-/d72GSYQniTFFeqX/S8b2/Yt8S4=",
255 | "requires": {
256 | "accepts": "~1.3.5",
257 | "array-flatten": "1.1.1",
258 | "body-parser": "1.18.3",
259 | "content-disposition": "0.5.2",
260 | "content-type": "~1.0.4",
261 | "cookie": "0.3.1",
262 | "cookie-signature": "1.0.6",
263 | "debug": "2.6.9",
264 | "depd": "~1.1.2",
265 | "encodeurl": "~1.0.2",
266 | "escape-html": "~1.0.3",
267 | "etag": "~1.8.1",
268 | "finalhandler": "1.1.1",
269 | "fresh": "0.5.2",
270 | "merge-descriptors": "1.0.1",
271 | "methods": "~1.1.2",
272 | "on-finished": "~2.3.0",
273 | "parseurl": "~1.3.2",
274 | "path-to-regexp": "0.1.7",
275 | "proxy-addr": "~2.0.4",
276 | "qs": "6.5.2",
277 | "range-parser": "~1.2.0",
278 | "safe-buffer": "5.1.2",
279 | "send": "0.16.2",
280 | "serve-static": "1.13.2",
281 | "setprototypeof": "1.1.0",
282 | "statuses": "~1.4.0",
283 | "type-is": "~1.6.16",
284 | "utils-merge": "1.0.1",
285 | "vary": "~1.1.2"
286 | },
287 | "dependencies": {
288 | "statuses": {
289 | "version": "1.4.0",
290 | "resolved": "http://registry.npm.taobao.org/statuses/download/statuses-1.4.0.tgz",
291 | "integrity": "sha1-u3PURtonlhBu/MG2AaJT1sRr0Ic="
292 | }
293 | }
294 | },
295 | "finalhandler": {
296 | "version": "1.1.1",
297 | "resolved": "http://registry.npm.taobao.org/finalhandler/download/finalhandler-1.1.1.tgz",
298 | "integrity": "sha1-7r9O2EAHnIP0JJA4ydcDAIMBsQU=",
299 | "requires": {
300 | "debug": "2.6.9",
301 | "encodeurl": "~1.0.2",
302 | "escape-html": "~1.0.3",
303 | "on-finished": "~2.3.0",
304 | "parseurl": "~1.3.2",
305 | "statuses": "~1.4.0",
306 | "unpipe": "~1.0.0"
307 | },
308 | "dependencies": {
309 | "statuses": {
310 | "version": "1.4.0",
311 | "resolved": "http://registry.npm.taobao.org/statuses/download/statuses-1.4.0.tgz",
312 | "integrity": "sha1-u3PURtonlhBu/MG2AaJT1sRr0Ic="
313 | }
314 | }
315 | },
316 | "forwarded": {
317 | "version": "0.1.2",
318 | "resolved": "http://registry.npm.taobao.org/forwarded/download/forwarded-0.1.2.tgz",
319 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
320 | },
321 | "fresh": {
322 | "version": "0.5.2",
323 | "resolved": "http://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz",
324 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
325 | },
326 | "has-binary2": {
327 | "version": "1.0.3",
328 | "resolved": "http://registry.npm.taobao.org/has-binary2/download/has-binary2-1.0.3.tgz",
329 | "integrity": "sha1-d3asYn8+p3JQz8My2rfd9eT10R0=",
330 | "requires": {
331 | "isarray": "2.0.1"
332 | },
333 | "dependencies": {
334 | "isarray": {
335 | "version": "2.0.1",
336 | "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-2.0.1.tgz",
337 | "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
338 | }
339 | }
340 | },
341 | "has-cors": {
342 | "version": "1.1.0",
343 | "resolved": "http://registry.npm.taobao.org/has-cors/download/has-cors-1.1.0.tgz",
344 | "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk="
345 | },
346 | "http-errors": {
347 | "version": "1.6.3",
348 | "resolved": "http://registry.npm.taobao.org/http-errors/download/http-errors-1.6.3.tgz",
349 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
350 | "requires": {
351 | "depd": "~1.1.2",
352 | "inherits": "2.0.3",
353 | "setprototypeof": "1.1.0",
354 | "statuses": ">= 1.4.0 < 2"
355 | }
356 | },
357 | "iconv-lite": {
358 | "version": "0.4.23",
359 | "resolved": "http://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.23.tgz",
360 | "integrity": "sha1-KXhx9jvlB63Pv8pxXQzQ7thOmmM=",
361 | "requires": {
362 | "safer-buffer": ">= 2.1.2 < 3"
363 | }
364 | },
365 | "indexof": {
366 | "version": "0.0.1",
367 | "resolved": "http://registry.npm.taobao.org/indexof/download/indexof-0.0.1.tgz",
368 | "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
369 | },
370 | "inherits": {
371 | "version": "2.0.3",
372 | "resolved": "http://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz",
373 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
374 | },
375 | "ipaddr.js": {
376 | "version": "1.8.0",
377 | "resolved": "http://registry.npm.taobao.org/ipaddr.js/download/ipaddr.js-1.8.0.tgz",
378 | "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4="
379 | },
380 | "isarray": {
381 | "version": "1.0.0",
382 | "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz",
383 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
384 | },
385 | "log4js": {
386 | "version": "3.0.6",
387 | "resolved": "http://registry.npm.taobao.org/log4js/download/log4js-3.0.6.tgz",
388 | "integrity": "sha1-5srO2Uln7uuc45n5+GgqSysoyP8=",
389 | "requires": {
390 | "circular-json": "^0.5.5",
391 | "date-format": "^1.2.0",
392 | "debug": "^3.1.0",
393 | "rfdc": "^1.1.2",
394 | "streamroller": "0.7.0"
395 | },
396 | "dependencies": {
397 | "debug": {
398 | "version": "3.2.6",
399 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.2.6.tgz",
400 | "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=",
401 | "requires": {
402 | "ms": "^2.1.1"
403 | }
404 | },
405 | "ms": {
406 | "version": "2.1.1",
407 | "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz",
408 | "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo="
409 | }
410 | }
411 | },
412 | "media-typer": {
413 | "version": "0.3.0",
414 | "resolved": "http://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz",
415 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
416 | },
417 | "merge-descriptors": {
418 | "version": "1.0.1",
419 | "resolved": "http://registry.npm.taobao.org/merge-descriptors/download/merge-descriptors-1.0.1.tgz",
420 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
421 | },
422 | "methods": {
423 | "version": "1.1.2",
424 | "resolved": "http://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz",
425 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
426 | },
427 | "mime": {
428 | "version": "1.4.1",
429 | "resolved": "http://registry.npm.taobao.org/mime/download/mime-1.4.1.tgz",
430 | "integrity": "sha1-Eh+evEnjdm8xGnbh+hyAA8SwOqY="
431 | },
432 | "mime-db": {
433 | "version": "1.37.0",
434 | "resolved": "http://registry.npm.taobao.org/mime-db/download/mime-db-1.37.0.tgz",
435 | "integrity": "sha1-C2oM5v2+lXbiXx8tL96IMNwK0Ng="
436 | },
437 | "mime-types": {
438 | "version": "2.1.21",
439 | "resolved": "http://registry.npm.taobao.org/mime-types/download/mime-types-2.1.21.tgz",
440 | "integrity": "sha1-KJlaoey3cHQv5q5+WPkYHHRLP5Y=",
441 | "requires": {
442 | "mime-db": "~1.37.0"
443 | }
444 | },
445 | "minimist": {
446 | "version": "0.0.8",
447 | "resolved": "http://registry.npm.taobao.org/minimist/download/minimist-0.0.8.tgz",
448 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
449 | },
450 | "mkdirp": {
451 | "version": "0.5.1",
452 | "resolved": "http://registry.npm.taobao.org/mkdirp/download/mkdirp-0.5.1.tgz",
453 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
454 | "requires": {
455 | "minimist": "0.0.8"
456 | }
457 | },
458 | "ms": {
459 | "version": "2.0.0",
460 | "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz",
461 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
462 | },
463 | "negotiator": {
464 | "version": "0.6.1",
465 | "resolved": "http://registry.npm.taobao.org/negotiator/download/negotiator-0.6.1.tgz",
466 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
467 | },
468 | "object-assign": {
469 | "version": "4.1.1",
470 | "resolved": "http://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz",
471 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
472 | },
473 | "object-component": {
474 | "version": "0.0.3",
475 | "resolved": "http://registry.npm.taobao.org/object-component/download/object-component-0.0.3.tgz",
476 | "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE="
477 | },
478 | "on-finished": {
479 | "version": "2.3.0",
480 | "resolved": "http://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz",
481 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
482 | "requires": {
483 | "ee-first": "1.1.1"
484 | }
485 | },
486 | "parseqs": {
487 | "version": "0.0.5",
488 | "resolved": "http://registry.npm.taobao.org/parseqs/download/parseqs-0.0.5.tgz",
489 | "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
490 | "requires": {
491 | "better-assert": "~1.0.0"
492 | }
493 | },
494 | "parseuri": {
495 | "version": "0.0.5",
496 | "resolved": "http://registry.npm.taobao.org/parseuri/download/parseuri-0.0.5.tgz",
497 | "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
498 | "requires": {
499 | "better-assert": "~1.0.0"
500 | }
501 | },
502 | "parseurl": {
503 | "version": "1.3.2",
504 | "resolved": "http://registry.npm.taobao.org/parseurl/download/parseurl-1.3.2.tgz",
505 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
506 | },
507 | "path-to-regexp": {
508 | "version": "0.1.7",
509 | "resolved": "http://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-0.1.7.tgz",
510 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
511 | },
512 | "process-nextick-args": {
513 | "version": "2.0.0",
514 | "resolved": "http://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.0.tgz",
515 | "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o="
516 | },
517 | "proxy-addr": {
518 | "version": "2.0.4",
519 | "resolved": "http://registry.npm.taobao.org/proxy-addr/download/proxy-addr-2.0.4.tgz",
520 | "integrity": "sha1-7PxzO/Iv+Mb0B/onUye5q2fki5M=",
521 | "requires": {
522 | "forwarded": "~0.1.2",
523 | "ipaddr.js": "1.8.0"
524 | }
525 | },
526 | "qs": {
527 | "version": "6.5.2",
528 | "resolved": "http://registry.npm.taobao.org/qs/download/qs-6.5.2.tgz",
529 | "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY="
530 | },
531 | "range-parser": {
532 | "version": "1.2.0",
533 | "resolved": "http://registry.npm.taobao.org/range-parser/download/range-parser-1.2.0.tgz",
534 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
535 | },
536 | "raw-body": {
537 | "version": "2.3.3",
538 | "resolved": "http://registry.npm.taobao.org/raw-body/download/raw-body-2.3.3.tgz",
539 | "integrity": "sha1-GzJOzmtXBuFThVvBFIxlu39uoMM=",
540 | "requires": {
541 | "bytes": "3.0.0",
542 | "http-errors": "1.6.3",
543 | "iconv-lite": "0.4.23",
544 | "unpipe": "1.0.0"
545 | }
546 | },
547 | "readable-stream": {
548 | "version": "2.3.6",
549 | "resolved": "http://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.6.tgz",
550 | "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=",
551 | "requires": {
552 | "core-util-is": "~1.0.0",
553 | "inherits": "~2.0.3",
554 | "isarray": "~1.0.0",
555 | "process-nextick-args": "~2.0.0",
556 | "safe-buffer": "~5.1.1",
557 | "string_decoder": "~1.1.1",
558 | "util-deprecate": "~1.0.1"
559 | }
560 | },
561 | "rfdc": {
562 | "version": "1.1.2",
563 | "resolved": "http://registry.npm.taobao.org/rfdc/download/rfdc-1.1.2.tgz",
564 | "integrity": "sha1-5uctdPXcOd6PU49l4Aw2wYAY40k="
565 | },
566 | "safe-buffer": {
567 | "version": "5.1.2",
568 | "resolved": "http://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz",
569 | "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0="
570 | },
571 | "safer-buffer": {
572 | "version": "2.1.2",
573 | "resolved": "http://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz",
574 | "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo="
575 | },
576 | "send": {
577 | "version": "0.16.2",
578 | "resolved": "http://registry.npm.taobao.org/send/download/send-0.16.2.tgz",
579 | "integrity": "sha1-bsyh4PjBVtFBWXVZhI32RzCmu8E=",
580 | "requires": {
581 | "debug": "2.6.9",
582 | "depd": "~1.1.2",
583 | "destroy": "~1.0.4",
584 | "encodeurl": "~1.0.2",
585 | "escape-html": "~1.0.3",
586 | "etag": "~1.8.1",
587 | "fresh": "0.5.2",
588 | "http-errors": "~1.6.2",
589 | "mime": "1.4.1",
590 | "ms": "2.0.0",
591 | "on-finished": "~2.3.0",
592 | "range-parser": "~1.2.0",
593 | "statuses": "~1.4.0"
594 | },
595 | "dependencies": {
596 | "statuses": {
597 | "version": "1.4.0",
598 | "resolved": "http://registry.npm.taobao.org/statuses/download/statuses-1.4.0.tgz",
599 | "integrity": "sha1-u3PURtonlhBu/MG2AaJT1sRr0Ic="
600 | }
601 | }
602 | },
603 | "serve-static": {
604 | "version": "1.13.2",
605 | "resolved": "http://registry.npm.taobao.org/serve-static/download/serve-static-1.13.2.tgz",
606 | "integrity": "sha1-CV6Ecv1bRiN9tQzkhqQ/S4bGzsE=",
607 | "requires": {
608 | "encodeurl": "~1.0.2",
609 | "escape-html": "~1.0.3",
610 | "parseurl": "~1.3.2",
611 | "send": "0.16.2"
612 | }
613 | },
614 | "setprototypeof": {
615 | "version": "1.1.0",
616 | "resolved": "http://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.0.tgz",
617 | "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY="
618 | },
619 | "socket.io": {
620 | "version": "2.2.0",
621 | "resolved": "http://registry.npm.taobao.org/socket.io/download/socket.io-2.2.0.tgz",
622 | "integrity": "sha1-8PYzFh72cSyXKzB1mOzQjJsbTVs=",
623 | "requires": {
624 | "debug": "~4.1.0",
625 | "engine.io": "~3.3.1",
626 | "has-binary2": "~1.0.2",
627 | "socket.io-adapter": "~1.1.0",
628 | "socket.io-client": "2.2.0",
629 | "socket.io-parser": "~3.3.0"
630 | },
631 | "dependencies": {
632 | "debug": {
633 | "version": "4.1.1",
634 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz",
635 | "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=",
636 | "requires": {
637 | "ms": "^2.1.1"
638 | }
639 | },
640 | "ms": {
641 | "version": "2.1.1",
642 | "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz",
643 | "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo="
644 | }
645 | }
646 | },
647 | "socket.io-adapter": {
648 | "version": "1.1.1",
649 | "resolved": "http://registry.npm.taobao.org/socket.io-adapter/download/socket.io-adapter-1.1.1.tgz",
650 | "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs="
651 | },
652 | "socket.io-client": {
653 | "version": "2.2.0",
654 | "resolved": "http://registry.npm.taobao.org/socket.io-client/download/socket.io-client-2.2.0.tgz",
655 | "integrity": "sha1-hOc+48Q9UCDMwaJY+u65rsJyOvc=",
656 | "requires": {
657 | "backo2": "1.0.2",
658 | "base64-arraybuffer": "0.1.5",
659 | "component-bind": "1.0.0",
660 | "component-emitter": "1.2.1",
661 | "debug": "~3.1.0",
662 | "engine.io-client": "~3.3.1",
663 | "has-binary2": "~1.0.2",
664 | "has-cors": "1.1.0",
665 | "indexof": "0.0.1",
666 | "object-component": "0.0.3",
667 | "parseqs": "0.0.5",
668 | "parseuri": "0.0.5",
669 | "socket.io-parser": "~3.3.0",
670 | "to-array": "0.1.4"
671 | },
672 | "dependencies": {
673 | "debug": {
674 | "version": "3.1.0",
675 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz",
676 | "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
677 | "requires": {
678 | "ms": "2.0.0"
679 | }
680 | }
681 | }
682 | },
683 | "socket.io-parser": {
684 | "version": "3.3.0",
685 | "resolved": "http://registry.npm.taobao.org/socket.io-parser/download/socket.io-parser-3.3.0.tgz",
686 | "integrity": "sha1-K1KpalCf3zFEC6QP7WCUx9TxJi8=",
687 | "requires": {
688 | "component-emitter": "1.2.1",
689 | "debug": "~3.1.0",
690 | "isarray": "2.0.1"
691 | },
692 | "dependencies": {
693 | "debug": {
694 | "version": "3.1.0",
695 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz",
696 | "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
697 | "requires": {
698 | "ms": "2.0.0"
699 | }
700 | },
701 | "isarray": {
702 | "version": "2.0.1",
703 | "resolved": "http://registry.npm.taobao.org/isarray/download/isarray-2.0.1.tgz",
704 | "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
705 | }
706 | }
707 | },
708 | "statuses": {
709 | "version": "1.5.0",
710 | "resolved": "http://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz",
711 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
712 | },
713 | "streamroller": {
714 | "version": "0.7.0",
715 | "resolved": "http://registry.npm.taobao.org/streamroller/download/streamroller-0.7.0.tgz",
716 | "integrity": "sha1-odG3z4PTmvsNYwSaWsv5NJO99ks=",
717 | "requires": {
718 | "date-format": "^1.2.0",
719 | "debug": "^3.1.0",
720 | "mkdirp": "^0.5.1",
721 | "readable-stream": "^2.3.0"
722 | },
723 | "dependencies": {
724 | "debug": {
725 | "version": "3.2.6",
726 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.2.6.tgz",
727 | "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=",
728 | "requires": {
729 | "ms": "^2.1.1"
730 | }
731 | },
732 | "ms": {
733 | "version": "2.1.1",
734 | "resolved": "http://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz",
735 | "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo="
736 | }
737 | }
738 | },
739 | "string_decoder": {
740 | "version": "1.1.1",
741 | "resolved": "http://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz",
742 | "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=",
743 | "requires": {
744 | "safe-buffer": "~5.1.0"
745 | }
746 | },
747 | "to-array": {
748 | "version": "0.1.4",
749 | "resolved": "http://registry.npm.taobao.org/to-array/download/to-array-0.1.4.tgz",
750 | "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA="
751 | },
752 | "type-is": {
753 | "version": "1.6.16",
754 | "resolved": "http://registry.npm.taobao.org/type-is/download/type-is-1.6.16.tgz",
755 | "integrity": "sha1-+JzjQVQcZysl7nrjxz3uOyvlAZQ=",
756 | "requires": {
757 | "media-typer": "0.3.0",
758 | "mime-types": "~2.1.18"
759 | }
760 | },
761 | "unpipe": {
762 | "version": "1.0.0",
763 | "resolved": "http://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz",
764 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
765 | },
766 | "util-deprecate": {
767 | "version": "1.0.2",
768 | "resolved": "http://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz",
769 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
770 | },
771 | "utils-merge": {
772 | "version": "1.0.1",
773 | "resolved": "http://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.1.tgz",
774 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
775 | },
776 | "uuid": {
777 | "version": "3.3.2",
778 | "resolved": "http://registry.npm.taobao.org/uuid/download/uuid-3.3.2.tgz",
779 | "integrity": "sha1-G0r0lV6zB3xQHCOHL8ZROBFYcTE="
780 | },
781 | "vary": {
782 | "version": "1.1.2",
783 | "resolved": "http://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz",
784 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
785 | },
786 | "ws": {
787 | "version": "6.1.2",
788 | "resolved": "http://registry.npm.taobao.org/ws/download/ws-6.1.2.tgz",
789 | "integrity": "sha1-PMdGLph5LwrGeUJBSJA97TucOtg=",
790 | "requires": {
791 | "async-limiter": "~1.0.0"
792 | }
793 | },
794 | "xmlhttprequest-ssl": {
795 | "version": "1.5.5",
796 | "resolved": "http://registry.npm.taobao.org/xmlhttprequest-ssl/download/xmlhttprequest-ssl-1.5.5.tgz",
797 | "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4="
798 | },
799 | "yeast": {
800 | "version": "0.1.2",
801 | "resolved": "http://registry.npm.taobao.org/yeast/download/yeast-0.1.2.tgz",
802 | "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
803 | }
804 | }
805 | }
806 |
--------------------------------------------------------------------------------
/card-game-server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "card-game-server",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "body-parser": "^1.18.3",
13 | "cors": "^2.8.5",
14 | "express": "^4.16.4",
15 | "log4js": "^3.0.6",
16 | "seedrandom": "^3.0.5",
17 | "socket.io": "^2.2.0",
18 | "uuid": "^3.3.2"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/card-game-server/utils.js:
--------------------------------------------------------------------------------
1 | function shuffle(rand, a) {
2 | for (let i = a.length - 1; i > 0; i--) {
3 | const j = Math.floor(rand() * (i + 1));
4 | [a[i], a[j]] = [a[j], a[i]]
5 | }
6 |
7 | return a;
8 | }
9 |
10 | module.exports = {
11 | shuffle
12 | }
--------------------------------------------------------------------------------