├── 2048.gif
├── README.md
├── LICENSE
├── index.html
├── 2048.css
├── normalize.css
├── 2048.js
└── 2048lib.js
/2048.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/banana255/2048/HEAD/2048.gif
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 2048
2 |
3 | > 本页面目前仅适合在移动端使用
4 | > 兼容性主要考虑 chrome 内核 和 safari 内核 的浏览器
5 |
6 | demo: http://www.bananaSS.cc/2048/
7 |
8 | 
9 |
10 | 17/2/2
11 |
12 | - 运用面向过程完成 2048 的逻辑部分 (./2048lib.js)
13 |
14 | 17/2/3
15 |
16 | - 引入 Normalize.css, 提供了跨浏览器的高度一致性
17 |
18 | - 实现界面 & 移动触发 & 阻塞页面滚动
19 |
20 | - 添加 新增元素 动画
21 |
22 | 17/2/4
23 | - 无移动时,不添加新元素
24 |
25 | - 添加记分数功能
26 |
27 | - 界面上的调整
28 |
29 | - 逻辑添加了判断 成功 和 失败
30 |
31 | - 界面上添加了 成功 和 失败 的动画
32 |
33 | 17/2/5
34 |
35 | - 采用面向对象方法,改写 2048lib.js
36 |
37 | - 添加游戏数据本地存储功能
38 |
39 | 17/2/7
40 |
41 | - 添加悔棋功能
42 |
43 | - 改进算法,80% 概率生成 2, 20% 概率生成 4
44 |
45 | - 添加合并 css3 动画
46 |
47 | - 保存动画效果
48 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 大香蕉
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 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 大香蕉的 2048
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
115 |
116 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/2048.css:
--------------------------------------------------------------------------------
1 | .t2048-game {
2 | height: 100vh;
3 | background: #fbf8ee;
4 | }
5 |
6 | * {
7 | box-sizing: border-box;
8 | user-select: none;
9 | -webkit-user-select: none;
10 | }
11 |
12 | /* header */
13 | .t2048-header {
14 | height: 25%;
15 | }
16 |
17 | logo {
18 | display: inline-block;
19 | height: 6rem;
20 | width: 6rem;
21 | background: #ecc835;
22 | margin-left: 1.5rem;
23 | border-radius: 0.5rem;
24 | color: #ffffff;
25 | font-weight: bold;
26 | float: left;
27 | }
28 |
29 | .logo-title {
30 | display: block;
31 | text-align: center;
32 | font-size: 2rem;
33 | line-height: 7vh;
34 | margin-top: 1rem;
35 | }
36 |
37 | .logo-info {
38 | display: block;
39 | text-align: center;
40 | }
41 |
42 | .feature-group {
43 | margin-left: 26vh;
44 | font-size: 0;
45 | color: #ffffff;
46 | }
47 |
48 | score {
49 | display: block;
50 | }
51 |
52 | score > span {
53 | background: #b7a99e;
54 | box-sizing: border-box;
55 | width: 5rem;
56 | height: 3rem;
57 | border-radius: 0.3rem;
58 | text-align: center;
59 | font-size: 0.9rem;
60 | }
61 |
62 | .score-now {
63 | display: inline-block;
64 | /*height: calc(7vh + 3vh + 1vh);*/
65 | }
66 |
67 | .score-max > span,
68 | .score-now > span {
69 | display: block;
70 | }
71 |
72 | .score-max {
73 | display: inline-block;
74 | margin-left: 7vw;
75 | }
76 |
77 | .score-info {
78 | margin-top: 0.2rem
79 | }
80 |
81 | #id-score-now,
82 | #id-score-max {
83 | font-size: 1.4rem;
84 | }
85 |
86 | feature {
87 | display: block;
88 | margin-top: 0.5rem;
89 | }
90 |
91 | feature > span {
92 | background: #f5965f;
93 | width: 5rem;
94 | height: 2rem;
95 | line-height: 2rem;
96 | border-radius: 0.3rem;
97 | text-align: center;
98 | font-size: 0.9rem;
99 | }
100 |
101 | .feature-undo {
102 | display: inline-block;
103 | }
104 |
105 | .new-game {
106 | display: inline-block;
107 | margin-left: 7vw;
108 | }
109 |
110 | /* footer */
111 | .t2048-footer {
112 | height: 15%;
113 | }
114 |
115 | /* 2048 main */
116 | .t2048-main {
117 | height: 60%;
118 | }
119 |
120 | table {
121 | width: 90vw;
122 | height: 90vw;
123 | background: #b9ac9f;
124 | margin: auto;
125 | overflow: hidden;
126 | }
127 |
128 | td {
129 | background: #cabeb1;
130 | border-radius: 0.2rem;
131 | width: 25%;
132 | height: 25%;
133 | text-align: center;
134 | font-size: 3rem;
135 | font-weight: 800;
136 | }
137 |
138 | td > span {
139 | display: inline-block;
140 | width: 100%;
141 | height: 100%;
142 | /* 算出行高的实际值 */
143 | line-height: 20vw;
144 | border-radius: 0.5rem;
145 | }
146 |
147 | /* 垂直居中 */
148 | .vertical-align {
149 | position: relative;
150 | top: 50%;
151 | transform: translateY(-50%);
152 | }
153 |
154 | .t2 {
155 | background: #ebe2d8;
156 | color: #756d63;
157 | }
158 |
159 | .t4 {
160 | background: #eaddc6;
161 | color: #756d63;
162 | }
163 |
164 | .t8 {
165 | background: #efaf77;
166 | color: #f8f5f1;
167 | }
168 |
169 | .t16 {
170 | background: #f39463;
171 | color: #f8f5f1;
172 | }
173 |
174 | .t32 {
175 | background: #f37a5e;
176 | color: #f8f5f1;
177 | }
178 |
179 | .t64 {
180 | background: #f45d3a;
181 | color: #f8f5f0;
182 | }
183 |
184 | .t128 {
185 | background: #edcf72;
186 | color: #f8f5f0;
187 | font-size: 2.8rem;
188 | }
189 |
190 | .t256 {
191 | background: #edcb5f;
192 | color: #f9f6f3;
193 | font-size: 2.8rem;
194 | }
195 |
196 | .t512 {
197 | background: #edc850;
198 | color: #f8f5f1;
199 | font-size: 2.8rem;
200 | }
201 |
202 | .t1024 {
203 | background: #edc53f;
204 | color: #f8f5f3;
205 | font-size: 2rem;
206 | }
207 |
208 | .t2048 {
209 | background: #3e3c31;
210 | color: #f8f5f0;
211 | font-size: 2rem;
212 | }
213 |
214 | .t4096 {
215 | background: #2b2a23;
216 | color: #f8f5f0;
217 | font-size: 2rem;
218 | }
219 |
220 | .t8192 {
221 | background: #21201b;
222 | color: #f8f5f0;
223 | font-size: 2rem;
224 | }
225 |
226 | /* 新添加的元素添加放大效果 */
227 | .new-one {
228 | transform: scale(0);
229 | animation: shine 0.5s 0.25s;
230 | -webkit-animation: shine 0.5s 0.25s;
231 | }
232 |
233 | @keyframes shine {
234 | from {
235 | transform: scale(0.2);
236 | -webkit-transform: scale(0.2);
237 | }
238 | to {
239 | transform: scale(1);
240 | -webkit-transform: scale(1);
241 | }
242 | }
243 |
244 | /* 合并的元素添加缩小效果 */
245 | .merge-one {
246 | animation: suo 0.5s;
247 | -webkit-animation: suo 0.5s;
248 | }
249 |
250 | @keyframes suo {
251 | from {
252 | transform: scale(2);
253 | -webkit-transform: scale(2);
254 | }
255 | to {
256 | transform: scale(1);
257 | -webkit-transform: scale(1);
258 | }
259 | }
260 |
261 | .none {
262 | font-size: 0 !important;
263 | }
264 |
265 | .success-eff,
266 | .false-eff {
267 | text-align: center;
268 | font-size: 2rem;
269 | margin: 0 1rem;
270 | font-weight: bolder;
271 | color: #f54444;
272 | }
273 |
274 | /* warning 动画 */
275 | .warning {
276 | color: #f54444;
277 | -webkit-animation: 0.1s warn 4 alternate;
278 | animation: 0.1s warn 4 alternate;
279 | text-align: center;
280 | }
281 |
282 | @keyframes warn {
283 | 0% {
284 | transform: translate(-5%, 0%);
285 | }
286 | 50% {
287 | transform: translate(5%, 0%);
288 | }
289 | }
290 |
--------------------------------------------------------------------------------
/normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */
2 |
3 | /**
4 | * 1. Change the default font family in all browsers (opinionated).
5 | * 2. Correct the line height in all browsers.
6 | * 3. Prevent adjustments of font size after orientation changes in
7 | * IE on Windows Phone and in iOS.
8 | */
9 |
10 | /* Document
11 | ========================================================================== */
12 |
13 | html {
14 | font-family: sans-serif; /* 1 */
15 | line-height: 1.15; /* 2 */
16 | -ms-text-size-adjust: 100%; /* 3 */
17 | -webkit-text-size-adjust: 100%; /* 3 */
18 | }
19 |
20 | /* Sections
21 | ========================================================================== */
22 |
23 | /**
24 | * Remove the margin in all browsers (opinionated).
25 | */
26 |
27 | body {
28 | margin: 0;
29 | }
30 |
31 | /**
32 | * Add the correct display in IE 9-.
33 | */
34 |
35 | article,
36 | aside,
37 | footer,
38 | header,
39 | nav,
40 | section {
41 | display: block;
42 | }
43 |
44 | /**
45 | * Correct the font size and margin on `h1` elements within `section` and
46 | * `article` contexts in Chrome, Firefox, and Safari.
47 | */
48 |
49 | h1 {
50 | font-size: 2em;
51 | margin: 0.67em 0;
52 | }
53 |
54 | /* Grouping content
55 | ========================================================================== */
56 |
57 | /**
58 | * Add the correct display in IE 9-.
59 | * 1. Add the correct display in IE.
60 | */
61 |
62 | figcaption,
63 | figure,
64 | main { /* 1 */
65 | display: block;
66 | }
67 |
68 | /**
69 | * Add the correct margin in IE 8.
70 | */
71 |
72 | figure {
73 | margin: 1em 40px;
74 | }
75 |
76 | /**
77 | * 1. Add the correct box sizing in Firefox.
78 | * 2. Show the overflow in Edge and IE.
79 | */
80 |
81 | hr {
82 | box-sizing: content-box; /* 1 */
83 | height: 0; /* 1 */
84 | overflow: visible; /* 2 */
85 | }
86 |
87 | /**
88 | * 1. Correct the inheritance and scaling of font size in all browsers.
89 | * 2. Correct the odd `em` font sizing in all browsers.
90 | */
91 |
92 | pre {
93 | font-family: monospace, monospace; /* 1 */
94 | font-size: 1em; /* 2 */
95 | }
96 |
97 | /* Text-level semantics
98 | ========================================================================== */
99 |
100 | /**
101 | * 1. Remove the gray background on active links in IE 10.
102 | * 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
103 | */
104 |
105 | a {
106 | background-color: transparent; /* 1 */
107 | -webkit-text-decoration-skip: objects; /* 2 */
108 | }
109 |
110 | /**
111 | * Remove the outline on focused links when they are also active or hovered
112 | * in all browsers (opinionated).
113 | */
114 |
115 | a:active,
116 | a:hover {
117 | outline-width: 0;
118 | }
119 |
120 | /**
121 | * 1. Remove the bottom border in Firefox 39-.
122 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
123 | */
124 |
125 | abbr[title] {
126 | border-bottom: none; /* 1 */
127 | text-decoration: underline; /* 2 */
128 | text-decoration: underline dotted; /* 2 */
129 | }
130 |
131 | /**
132 | * Prevent the duplicate application of `bolder` by the next rule in Safari 6.
133 | */
134 |
135 | b,
136 | strong {
137 | font-weight: inherit;
138 | }
139 |
140 | /**
141 | * Add the correct font weight in Chrome, Edge, and Safari.
142 | */
143 |
144 | b,
145 | strong {
146 | font-weight: bolder;
147 | }
148 |
149 | /**
150 | * 1. Correct the inheritance and scaling of font size in all browsers.
151 | * 2. Correct the odd `em` font sizing in all browsers.
152 | */
153 |
154 | code,
155 | kbd,
156 | samp {
157 | font-family: monospace, monospace; /* 1 */
158 | font-size: 1em; /* 2 */
159 | }
160 |
161 | /**
162 | * Add the correct font style in Android 4.3-.
163 | */
164 |
165 | dfn {
166 | font-style: italic;
167 | }
168 |
169 | /**
170 | * Add the correct background and color in IE 9-.
171 | */
172 |
173 | mark {
174 | background-color: #ff0;
175 | color: #000;
176 | }
177 |
178 | /**
179 | * Add the correct font size in all browsers.
180 | */
181 |
182 | small {
183 | font-size: 80%;
184 | }
185 |
186 | /**
187 | * Prevent `sub` and `sup` elements from affecting the line height in
188 | * all browsers.
189 | */
190 |
191 | sub,
192 | sup {
193 | font-size: 75%;
194 | line-height: 0;
195 | position: relative;
196 | vertical-align: baseline;
197 | }
198 |
199 | sub {
200 | bottom: -0.25em;
201 | }
202 |
203 | sup {
204 | top: -0.5em;
205 | }
206 |
207 | /* Embedded content
208 | ========================================================================== */
209 |
210 | /**
211 | * Add the correct display in IE 9-.
212 | */
213 |
214 | audio,
215 | video {
216 | display: inline-block;
217 | }
218 |
219 | /**
220 | * Add the correct display in iOS 4-7.
221 | */
222 |
223 | audio:not([controls]) {
224 | display: none;
225 | height: 0;
226 | }
227 |
228 | /**
229 | * Remove the border on images inside links in IE 10-.
230 | */
231 |
232 | img {
233 | border-style: none;
234 | }
235 |
236 | /**
237 | * Hide the overflow in IE.
238 | */
239 |
240 | svg:not(:root) {
241 | overflow: hidden;
242 | }
243 |
244 | /* Forms
245 | ========================================================================== */
246 |
247 | /**
248 | * 1. Change the font styles in all browsers (opinionated).
249 | * 2. Remove the margin in Firefox and Safari.
250 | */
251 |
252 | button,
253 | input,
254 | optgroup,
255 | select,
256 | textarea {
257 | font-family: sans-serif; /* 1 */
258 | font-size: 100%; /* 1 */
259 | line-height: 1.15; /* 1 */
260 | margin: 0; /* 2 */
261 | }
262 |
263 | /**
264 | * Show the overflow in IE.
265 | * 1. Show the overflow in Edge.
266 | */
267 |
268 | button,
269 | input { /* 1 */
270 | overflow: visible;
271 | }
272 |
273 | /**
274 | * Remove the inheritance of text transform in Edge, Firefox, and IE.
275 | * 1. Remove the inheritance of text transform in Firefox.
276 | */
277 |
278 | button,
279 | select { /* 1 */
280 | text-transform: none;
281 | }
282 |
283 | /**
284 | * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
285 | * controls in Android 4.
286 | * 2. Correct the inability to style clickable types in iOS and Safari.
287 | */
288 |
289 | button,
290 | html [type="button"], /* 1 */
291 | [type="reset"],
292 | [type="submit"] {
293 | -webkit-appearance: button; /* 2 */
294 | }
295 |
296 | /**
297 | * Remove the inner border and padding in Firefox.
298 | */
299 |
300 | button::-moz-focus-inner,
301 | [type="button"]::-moz-focus-inner,
302 | [type="reset"]::-moz-focus-inner,
303 | [type="submit"]::-moz-focus-inner {
304 | border-style: none;
305 | padding: 0;
306 | }
307 |
308 | /**
309 | * Restore the focus styles unset by the previous rule.
310 | */
311 |
312 | button:-moz-focusring,
313 | [type="button"]:-moz-focusring,
314 | [type="reset"]:-moz-focusring,
315 | [type="submit"]:-moz-focusring {
316 | outline: 1px dotted ButtonText;
317 | }
318 |
319 | /**
320 | * Change the border, margin, and padding in all browsers (opinionated).
321 | */
322 |
323 | fieldset {
324 | border: 1px solid #c0c0c0;
325 | margin: 0 2px;
326 | padding: 0.35em 0.625em 0.75em;
327 | }
328 |
329 | /**
330 | * 1. Correct the text wrapping in Edge and IE.
331 | * 2. Correct the color inheritance from `fieldset` elements in IE.
332 | * 3. Remove the padding so developers are not caught out when they zero out
333 | * `fieldset` elements in all browsers.
334 | */
335 |
336 | legend {
337 | box-sizing: border-box; /* 1 */
338 | color: inherit; /* 2 */
339 | display: table; /* 1 */
340 | max-width: 100%; /* 1 */
341 | padding: 0; /* 3 */
342 | white-space: normal; /* 1 */
343 | }
344 |
345 | /**
346 | * 1. Add the correct display in IE 9-.
347 | * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
348 | */
349 |
350 | progress {
351 | display: inline-block; /* 1 */
352 | vertical-align: baseline; /* 2 */
353 | }
354 |
355 | /**
356 | * Remove the default vertical scrollbar in IE.
357 | */
358 |
359 | textarea {
360 | overflow: auto;
361 | }
362 |
363 | /**
364 | * 1. Add the correct box sizing in IE 10-.
365 | * 2. Remove the padding in IE 10-.
366 | */
367 |
368 | [type="checkbox"],
369 | [type="radio"] {
370 | box-sizing: border-box; /* 1 */
371 | padding: 0; /* 2 */
372 | }
373 |
374 | /**
375 | * Correct the cursor style of increment and decrement buttons in Chrome.
376 | */
377 |
378 | [type="number"]::-webkit-inner-spin-button,
379 | [type="number"]::-webkit-outer-spin-button {
380 | height: auto;
381 | }
382 |
383 | /**
384 | * 1. Correct the odd appearance in Chrome and Safari.
385 | * 2. Correct the outline style in Safari.
386 | */
387 |
388 | [type="search"] {
389 | -webkit-appearance: textfield; /* 1 */
390 | outline-offset: -2px; /* 2 */
391 | }
392 |
393 | /**
394 | * Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
395 | */
396 |
397 | [type="search"]::-webkit-search-cancel-button,
398 | [type="search"]::-webkit-search-decoration {
399 | -webkit-appearance: none;
400 | }
401 |
402 | /**
403 | * 1. Correct the inability to style clickable types in iOS and Safari.
404 | * 2. Change font properties to `inherit` in Safari.
405 | */
406 |
407 | ::-webkit-file-upload-button {
408 | -webkit-appearance: button; /* 1 */
409 | font: inherit; /* 2 */
410 | }
411 |
412 | /* Interactive
413 | ========================================================================== */
414 |
415 | /*
416 | * Add the correct display in IE 9-.
417 | * 1. Add the correct display in Edge, IE, and Firefox.
418 | */
419 |
420 | details, /* 1 */
421 | menu {
422 | display: block;
423 | }
424 |
425 | /*
426 | * Add the correct display in all browsers.
427 | */
428 |
429 | summary {
430 | display: list-item;
431 | }
432 |
433 | /* Scripting
434 | ========================================================================== */
435 |
436 | /**
437 | * Add the correct display in IE 9-.
438 | */
439 |
440 | canvas {
441 | display: inline-block;
442 | }
443 |
444 | /**
445 | * Add the correct display in IE.
446 | */
447 |
448 | template {
449 | display: none;
450 | }
451 |
452 | /* Hidden
453 | ========================================================================== */
454 |
455 | /**
456 | * Add the correct display in IE 10-.
457 | */
458 |
459 | [hidden] {
460 | display: none;
461 | }
462 |
--------------------------------------------------------------------------------
/2048.js:
--------------------------------------------------------------------------------
1 | const e = (sel) => document.querySelector(sel)
2 |
3 | const es = (sel) => document.querySelectorAll(sel)
4 |
5 | const arrayFormatByTds = function(table) {
6 | /*
7 | 传入一个 table 标签,将 table 里 的 tds > span 生成一个 二维数组
8 | */
9 | var tds = es(table+' td > span')
10 | var trs = es(table+' tr')
11 | // console.log(tds, trs);
12 | var t = t2048.arrayInit(trs.length)
13 | for (var i = 0; i < trs.length; i++) {
14 | for (var j = 0; j < trs[i].children.length; j++) {
15 | t[i][j] = tds[i * trs.length + j]
16 | }
17 | }
18 | return t
19 | }
20 |
21 | const changeSingleView = function(td, value) {
22 | /*
23 | 改变单个单元格 td 的 view
24 | */
25 | td.setAttribute('class', '')
26 | if (value != 0) {
27 | var className = 't' + value
28 | td.classList.add(className)
29 | td.innerHTML = value
30 | } else {
31 | td.innerHTML = ''
32 | }
33 | }
34 |
35 | const changeViewByArray = function(table, array) {
36 | /*
37 | table 是 包括 tds 的二维素组
38 | 将 View 的 value 变成 array 中的值
39 | */
40 | for (var i = 0; i < array.length; i++) {
41 | for (var j = 0; j < array[i].length; j++) {
42 | var value = array[i][j]
43 | var td = table[i][j]
44 | changeSingleView(td, value)
45 | }
46 | }
47 | }
48 |
49 | const showisSuccess = function(status) {
50 | // console.log('vix', status);
51 | if(status.false) {
52 | // console.log('game false');
53 | e('.false-eff').classList.remove('none')
54 | e('.false-eff').classList.add('warning')
55 | setTimeout.call(this, function(){
56 | e('.false-eff').classList.remove('warning')
57 | }, 400)
58 | } else {
59 | e('.false-eff').classList.add('none')
60 | }
61 | if(status.success) {
62 | e('.success-eff').classList.remove('none')
63 | e('.success-eff').classList.add('warning')
64 | setTimeout.call(this, function(){
65 | e('.success-eff').classList.remove('warning')
66 | }, 400)
67 | } else {
68 | e('.success-eff').classList.add('none')
69 | }
70 | }
71 |
72 | const showScore = function(score) {
73 | e('#id-score-now').innerHTML = score.now
74 | var nowMax = e('#id-score-max').innerHTML
75 | // if (score.now > nowMax) {
76 | // e('#id-score-max').innerHTML = score.max
77 | // }
78 | e('#id-score-max').innerHTML = score.max
79 |
80 | }
81 |
82 | const showMerge = function(array) {
83 | /*
84 | 给合并元素添加 merge-one css 动画
85 | */
86 | var table = arrayFormatByTds('table')
87 | for (var i = 0; i < array.length; i++) {
88 | var x = array[i][0]
89 | var y = array[i][1]
90 | table[x][y].classList.add('merge-one')
91 | setTimeout.call(this, function(){
92 | table[x][y].classList.remove('merge-one')
93 | }, 500)
94 | }
95 | }
96 |
97 | const showView = function(TZFE) {
98 | /*
99 | 把 array 二维数组 和 分数 和 成功/失败 渲染成页面,并备份
100 | */
101 | var a = TZFE.copyArray(TZFE.value)
102 | var table = arrayFormatByTds('table')
103 | changeViewByArray(table, a)
104 | // console.log('show view', TZFE);
105 | showScore(TZFE.score)
106 | showisSuccess(TZFE.status)
107 | showMerge(TZFE.merge)
108 | showNew(TZFE.new)
109 | }
110 |
111 | // const showNew = function(i, j) {
112 | // // console.log('new one', i, j);
113 | // var t = arrayFormatByTds('table')
114 | // // t[i][j].classList.remove('new-one')
115 | // t[i][j].classList.add('new-one')
116 | // setTimeout.call(this, function(){
117 | // t[i][j].classList.remove('new-one')
118 | // }, 500)
119 | // }
120 |
121 | const showNew = function(array) {
122 | /*
123 | array 格式 [[x1, y1], [x2, y2]...]
124 | */
125 | // console.log('showNew', array);
126 | var t = arrayFormatByTds('table')
127 | for (var i = 0; i < array.length; i++) {
128 | var x = array[i][0]
129 | var y = array[i][1]
130 | if (x !== false) {
131 | t[x][y].classList.add('new-one')
132 | setTimeout.call(this, function(){
133 | t[x][y].classList.remove('new-one')
134 | }, 500)
135 | }
136 | }
137 | }
138 |
139 | const leftActionToView = function() {
140 | /*
141 | 向左滑动时视图的变化,并返回新元素的坐标
142 | */
143 | var r = t2048.handleLeftArray(t2048.value)
144 | t2048.value = r.value
145 | showView(t2048)
146 | // console.log(value2048);
147 | return r
148 | }
149 |
150 | const rightActionToView = function() {
151 | /*
152 | 向右滑动时视图的变化,并返回新元素的坐标
153 | */
154 | var r = t2048.handleRightArray(t2048.value)
155 | t2048.value = r.value
156 | showView(t2048)
157 | // console.log(value2048);
158 | return r
159 | }
160 |
161 | const upActionToView = function() {
162 | /*
163 | 向上滑动时视图的变化,并返回新元素的坐标
164 | */
165 | var r = t2048.handleUpArray(t2048.value)
166 | t2048.value = r.value
167 | showView(t2048)
168 | // console.log(value2048);
169 | return r
170 | }
171 |
172 | const downActionToView = function() {
173 | /*
174 | 向下滑动时视图的变化,并返回新元素的坐标
175 | */
176 | var r = t2048.handleDownArray(t2048.value)
177 | // console.log(r);
178 | t2048.value = r.value
179 | showView(t2048)
180 | // console.log(value2048);
181 | return r
182 | }
183 |
184 | const undo = function(TZFE) {
185 | var length = TZFE.backupData.length
186 | // console.log(length);
187 | if (length <= 1) {
188 | // console.log('<=1');
189 | var b = undefined
190 | } else {
191 | TZFE.backupData.pop()
192 | var b = TZFE.backupData[length-2]
193 | }
194 | // console.log('backupData is', b, TZFE.score.now);
195 | if (b != undefined) {
196 | TZFE.score = {
197 | now: b.score.now,
198 | max: b.score.max,
199 | }
200 | TZFE.status = {
201 | success: b.status.success,
202 | false: b.status.false,
203 | }
204 | TZFE.value = b.value
205 | TZFE.length = b.length
206 | TZFE.merge = (b.merge == undefined) ? [] : b.merge
207 | TZFE.new = (b.new == undefined) ? [] : b.new
208 | // console.log('TZFE score now', TZFE.score.now);
209 | save2048(TZFE)
210 | showView(TZFE)
211 | }
212 | }
213 |
214 | const resetData = function(length) {
215 | var max = t2048.score.max
216 | t2048 = new TZFE(length)
217 | t2048.score.max = max
218 | t2048.value = false
219 | save2048(t2048)
220 | }
221 |
222 | const save2048 = function(TZFE) {
223 | var t = {
224 | score: TZFE.score,
225 | status: TZFE.status,
226 | value: TZFE.value,
227 | length: TZFE.length,
228 | backupData: TZFE.backupData,
229 | merge: TZFE.merge,
230 | new: TZFE.new
231 | }
232 | var data = JSON.stringify(t)
233 | localStorage.t2048 = data
234 | }
235 |
236 | const load2048 = function(TZFE) {
237 | var t = localStorage.t2048
238 | if (t) {
239 | data = JSON.parse(t)
240 | TZFE.score = data.score
241 | TZFE.status = data.status
242 | TZFE.value = data.value
243 | TZFE.length = data.length
244 | TZFE.backupData = (data.backupData == undefined) ? [] : data.backupData
245 | return true
246 | } else {
247 | console.log('无储存数据');
248 | return false
249 | }
250 | }
251 |
252 | const init2048 = function(TZFE) {
253 | // console.log(TZFE);
254 | var flat = false
255 | if (!load2048(TZFE) || !TZFE.value) {
256 | flat = true
257 | var n = TZFE.init2048Array(TZFE.length)
258 | TZFE.value = n.initArray
259 | }
260 | // console.log(TZFE);
261 | showView(TZFE)
262 | if (flat) {
263 | TZFE.backup()
264 | // showNew(n.f.i, n.f.j)
265 | // showNew(n.s.i, n.s.j)
266 | }
267 | }
268 |
269 | const angleBySlide = function(dx, dy) {
270 | return Math.atan2(dy,dx) * 180 / Math.PI
271 | }
272 |
273 | const judgeDirection = function(sX, sY, eX, eY) {
274 | /*
275 | 根据坐标判断 方向
276 | return: false 为判断不出
277 | 'up' 为上
278 | 'down'
279 | 'right'
280 | 'left'
281 | */
282 | var dx = eX - sX
283 | var dy = sY - eY
284 | var angle = angleBySlide(dx, dy);
285 | // 滑动距离太短 的情况
286 | if (Math.abs(dx) < 30 && Math.abs(dy) < 30) {
287 | return false
288 | } else if (angle >= -45 && angle < 45) {
289 | return 'right'
290 | } else if (angle >= 45 && angle < 135) {
291 | return 'up'
292 | }else if (angle >= -135 && angle < -45) {
293 | return 'down'
294 | }else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) {
295 | return 'left'
296 | }
297 | }
298 |
299 | const bindSlideEvent = function() {
300 | var startX, startY
301 |
302 | e('table').addEventListener('touchstart', function(event){
303 | // console.log('touchstart', event);
304 | startX = event.touches[0].pageX
305 | startY = event.touches[0].pageY
306 | })
307 |
308 | e('.t2048-main').addEventListener('touchmove', function(event){
309 | // console.log('touchmove', event);
310 | // var endX = event.changedTouches[0].pageX;
311 | // var endY = event.changedTouches[0].pageY;
312 | event.preventDefault()
313 | })
314 |
315 | e('table').addEventListener('touchend', function(event){
316 | // console.log('touchend', event);
317 | var endX = event.changedTouches[0].pageX;
318 | var endY = event.changedTouches[0].pageY;
319 |
320 | var dire = judgeDirection(startX, startY, endX, endY)
321 |
322 | if (dire == 'up') {
323 | var r = upActionToView()
324 | } else if (dire == 'down') {
325 | var r = downActionToView()
326 | } else if (dire == 'left') {
327 | var r = leftActionToView()
328 | } else if (dire == 'right') {
329 | var r = rightActionToView()
330 | } else if (!dire) {
331 | return false
332 | }
333 | if (r.i !== false) {
334 | t2048.backup()
335 | // 给 新增加的元素 添加 放大 的动画
336 | save2048(t2048)
337 | // showNew(r.i, r.j)
338 | // console.log(t2048.merge);
339 | }
340 | })
341 | }
342 |
343 | const newGame = function(length) {
344 | // value2048 = arrayInit(4)
345 | // score.now = 0
346 | // statusSuc.success = false
347 | // statusSuc.false = false
348 | resetData(length)
349 | e('.false-eff').classList.add('none')
350 | e('.success-eff').classList.add('none')
351 | init2048(t2048)
352 | }
353 |
354 | const bindNewGame = function() {
355 | e('.new-game').addEventListener('touchend', function(event){
356 | newGame(t2048.length)
357 | })
358 | }
359 |
360 | const bindUndo = function() {
361 | e('.feature-undo').addEventListener('touchend', function(event){
362 | undo(t2048)
363 | })
364 | }
365 |
366 | const bindEvents = function() {
367 | bindSlideEvent()
368 |
369 | bindNewGame()
370 |
371 | bindUndo()
372 | }
373 |
374 | var t2048 = new TZFE(4)
375 |
376 | const __main2048 = function() {
377 | init2048(t2048)
378 |
379 | bindEvents()
380 | }
381 |
--------------------------------------------------------------------------------
/2048lib.js:
--------------------------------------------------------------------------------
1 | var TZFE = function(length) {
2 | this.score = {
3 | now: 0,
4 | max: 0,
5 | }
6 | this.status = {
7 | success: false,
8 | false: false,
9 | }
10 | this.value = this.arrayInit(length)
11 | this.length = length
12 | this.backupData = []
13 | this.merge = []
14 | this.new = []
15 | }
16 |
17 | TZFE.prototype.saveScore = function(s) {
18 | /*
19 | 记录 分数
20 | */
21 | this.score.now += s
22 | if (this.score.now > this.score.max) {
23 | this.score.max = this.score.now
24 | }
25 | // console.log(this.score.now, this.score.max);
26 | }
27 |
28 | TZFE.prototype.backup = function() {
29 | var data = {
30 | // score: new Object(this.score),
31 | score: {
32 | now: this.score.now,
33 | max: this.score.max,
34 | },
35 | // status: new Object(this.status),
36 | status: {
37 | success: this.status.success,
38 | false: this.status.false,
39 | },
40 | value: this.value,
41 | length: this.length,
42 | merge: this.merge,
43 | new: this.new,
44 | }
45 | // console.log('backup', data, data.score);
46 | // console.log(data.score === this.score);
47 | // console.log(data.status === this.status);
48 | // console.log(data.value === this.value);
49 | this.backupData.push(data)
50 | }
51 |
52 | TZFE.prototype.supplementZero = function(array, direction, num) {
53 | /*
54 | 给 array 补充 num 个 0
55 | direction 参数: begin 表示在头部补 0
56 | end 表示在尾部补 0
57 | */
58 | var a = array.slice(0)
59 | if (direction == 'begin') {
60 | for (var i = 0; i < num; i++) {
61 | a.unshift(0)
62 | }
63 | return a
64 | } else if (direction == 'end') {
65 | for (var i = 0; i < num; i++) {
66 | a.push(0)
67 | }
68 | return a
69 | }
70 | }
71 |
72 | TZFE.prototype.rejectByIndex = function(array, index, direction='end') {
73 | /*
74 | 将 array[index] 剔除,并在头/尾补充 0,保持长度
75 | direction 参数: begin 表示在头部补 0
76 | end 表示在尾部补 0
77 | */
78 | var a = array.slice(0)
79 | a.splice(index, 1)
80 | a = this.supplementZero(a, direction, 1)
81 | return a
82 | // if (index == 0) {
83 | // a = a.slice(1)
84 | // } else if (index == a.length - 1) {
85 | // a.pop()
86 | // } else if(index > 0 && index < a.length - 1) {
87 | // var qian = a.slice(0, index)
88 | // var hou = a.slice(index+1)
89 | // a = qian.concat(hou)
90 | // }
91 | // if (direction == 'begin') {
92 | // a.unshift(0)
93 | // } else if (direction == 'end') {
94 | // a.push(0)
95 | // }
96 | }
97 |
98 | TZFE.prototype.moveArray = function(array, direction) {
99 | /*
100 | 移动数组: 根据 direction 让 array 清除 左/右 边的 0 ,
101 | 并在另一边用补 0 的方式保持 array 原来的长度
102 | direction 参数: left 表示清除 左 边的 0 ,
103 | right 表示清除 右 边的 0 ,
104 | */
105 | var a = array.slice(0)
106 | var length = a.length
107 | var index = 0
108 | if (direction == 'left') {
109 | for (var i = 0; i < length; i++) {
110 | if(a[i] != 0) {
111 | index = i
112 | // console.log(index);
113 | a = a.slice(index)
114 | var num = length - a.length
115 | a = this.supplementZero(a, 'end', num)
116 | return a
117 | }
118 | }
119 | } else if(direction == 'right') {
120 | for (var i = 0; i < length; i++) {
121 | if(a[length - 1 - i] != 0) {
122 | index = length - 1 - i
123 | a = a.slice(0, index+1)
124 | // console.log(a, index);
125 | var num = length - a.length
126 | a = this.supplementZero(a, 'begin', num)
127 | return a
128 | }
129 | }
130 | }
131 | return a
132 | }
133 |
134 | TZFE.prototype.arrayByClearZero = function(array) {
135 | var a = array.slice(0)
136 | for (var i = 0; i < a.length; i++) {
137 | if(a[i] == 0) {
138 | a.splice(i, 1)
139 | i--
140 | }
141 | }
142 | a = this.supplementZero(a, 'end', array.length-a.length)
143 | return a
144 | }
145 |
146 | TZFE.prototype.handleOneLine = function(array, direction) {
147 | /*
148 | 处理一行
149 | direction 参数: left 表示在向左滑动处理
150 | right 表示在向右滑动处理
151 | 返回处理好的数据 a & 合并位置的坐标 is
152 | */
153 | var a = array.slice(0)
154 | a = this.arrayByClearZero(a)
155 | var is = []
156 | var length = a.length
157 | a = this.moveArray(a, direction)
158 | for (var i = 0; i < length; i++) {
159 | // if (a[i] == a[i+1] && a[i] != 0) {
160 | // a[i] *= 2
161 | // if (direction == 'left') {
162 | // a = rejectByIndex(a, i+1, 'end')
163 | // } else if (direction == 'right') {
164 | // a = rejectByIndex(a, i+1, 'begin')
165 | // }
166 | // }
167 | if (direction == 'left') {
168 | if (a[i] == a[i+1] && a[i] != 0) {
169 | a[i] *= 2
170 | is.push(i)
171 | this.saveScore(a[i])
172 | a = this.rejectByIndex(a, i+1, 'end')
173 | }
174 | } else if (direction == 'right') {
175 | if (a[length-1-i] == a[length-i-2] && a[length-1-i] != 0) {
176 | a[length-1-i] *= 2
177 | is.push(length-1-i)
178 | this.saveScore(a[length-1-i])
179 | a = this.rejectByIndex(a, length-i-2, 'begin')
180 | }
181 | }
182 | }
183 | // console.log(a);
184 | // a = this.moveArray(a, direction)
185 | return {
186 | a: a,
187 | is: is,
188 | }
189 | }
190 |
191 | TZFE.prototype.encodeArray = function(array) {
192 | /*
193 | 旋转 array
194 | 使得 上下 变 左右
195 | */
196 | // console.log('encodeArray');
197 | var a = this.copyArray(array)
198 | var length = a.length
199 | var r = this.arrayInit(length)
200 | for (var i = 0; i < length; i++) {
201 | for (var j = 0; j < a[i].length; j++) {
202 | r[i][j] = array[j][i]
203 | }
204 | }
205 | return r
206 | }
207 |
208 | TZFE.prototype.decodeArray = function(array) {
209 | /*
210 | 复原 array
211 | 让 左右 回复成 上下
212 | */
213 | // console.log('decodeArray');
214 | return this.encodeArray(array)
215 | }
216 |
217 | TZFE.prototype.compareArray = function(a1, a2) {
218 | /*
219 | 比较两个 二维数组 是否相等
220 | */
221 | for (var i = 0; i < a1.length; i++) {
222 | for (var j = 0; j < a1[i].length; j++) {
223 | if(a1[i][j] != a2[i][j]) {
224 | // console.log('不相等');
225 | return false
226 | }
227 | }
228 | }
229 | // console.log('相等');
230 | return true
231 | }
232 |
233 | TZFE.prototype.newOneOfArray = function(result, array) {
234 | /*
235 | 判断是否需要添加一个新元素,需要则添加 并 备份数据,不需要则返回{i:false, j:false}
236 | */
237 | if(!this.compareArray(array, result)) {
238 | result = this.arrayByCreateZero(result)
239 | return result
240 | } else {
241 | return {
242 | value: result,
243 | i: false,
244 | j: false,
245 | }
246 | }
247 | }
248 |
249 | TZFE.prototype.isSameLine = function(array) {
250 | /*
251 | 判断 一维数组 是否有相邻 两个 是相等的,如果有则返回 true
252 | */
253 | for (var i = 0; i < array.length-1; i++) {
254 | if(array[i] == array[i+1]) {
255 | return true
256 | }
257 | }
258 | return false
259 | }
260 |
261 | TZFE.prototype.isSuccess = function(array) {
262 | /*
263 | 判断 成功 还是 失败, 从而改变全局变量 status
264 | */
265 | // 判断是否 成功
266 | for (var i = 0; i < array.length; i++) {
267 | for (var j = 0; j < array[i].length; j++) {
268 | if(array[i][j] == 2048) {
269 | this.status.success = true
270 | console.log('成功');
271 | return 1
272 | }
273 | }
274 | }
275 |
276 | // 判断是否有有 空格 存在
277 | for (var i = 0; i < array.length; i++) {
278 | for (var j = 0; j < array[i].length; j++) {
279 | if(array[i][j] == 0) {
280 | return 1
281 | }
282 | }
283 | }
284 |
285 | // 判断每行相邻是否有相同的值
286 | for (var i = 0; i < array.length; i++) {
287 | if (this.isSameLine(array[i])) {
288 | return 1
289 | }
290 | }
291 |
292 | // 判断每列相邻是否有相同的值
293 | var a = this.encodeArray(array)
294 | for (var i = 0; i < a.length; i++) {
295 | if (this.isSameLine(a[i])) {
296 | return 1
297 | }
298 | }
299 |
300 | this.status.false = true
301 | console.log('失败');
302 | }
303 |
304 | TZFE.prototype.saveMerge = function(i, js) {
305 | /*
306 | 将 js 拆成 j1 j2 ...,并和 i 组合成 [i, j] 保存到 this.merge
307 | */
308 | for (var x = 0; x < js.length; x++) {
309 | var r = []
310 | r.push(i)
311 | r.push(js[x])
312 | this.merge.push(r)
313 | }
314 | }
315 |
316 | TZFE.prototype.handleLeftArray = function(array) {
317 | /*
318 | 向左滑动时 array 合并 & 移动 & 添加一个新元素 (2)
319 | 返回 r [value, i, j] (其中 i j 是增加的新元素的坐标)
320 | 并将 合并的坐标 保存到 this.merge
321 | */
322 | this.merge = []
323 | this.new = []
324 | var a = this.copyArray(array)
325 | var r = []
326 | for (var i = 0; i < a.length; i++) {
327 | var restlt = this.handleOneLine(a[i], 'left')
328 | r.push(restlt.a)
329 | this.saveMerge(i, restlt.is)
330 | }
331 | this.isSuccess(r)
332 | var restlt = this.newOneOfArray(r, array)
333 | var zuobiao = [restlt.i, restlt.j]
334 | this.new.push(zuobiao)
335 | return restlt
336 | }
337 |
338 | TZFE.prototype.handleRightArray = function(array) {
339 | /*
340 | 向右滑动时 array 合并 & 移动 & 添加一个新元素 (2)
341 | 返回 r [value, i, j] (其中 i j 是增加的新元素的坐标)
342 | 并将 合并的坐标 保存到 this.merge
343 | 将 新加的坐标 保存到 this.new
344 | */
345 | // console.log('handleRightArray', array);
346 | this.merge = []
347 | this.new = []
348 | var a = this.copyArray(array)
349 | var r = []
350 | for (var i = 0; i < a.length; i++) {
351 | var restlt = this.handleOneLine(a[i], 'right')
352 | r.push(restlt.a)
353 | this.saveMerge(i, restlt.is)
354 | // r.push(this.handleOneLine(a[i], 'right'))
355 | }
356 | this.isSuccess(r)
357 | var restlt = this.newOneOfArray(r, array)
358 | var zuobiao = [restlt.i, restlt.j]
359 | this.new.push(zuobiao)
360 | return restlt
361 | }
362 |
363 | // TZFE.prototype.encodeMerge = function() {
364 | // var a = this.merge
365 | // for (var i = 0; i < a.length; i++) {
366 | // var x = a[i][0]
367 | // var y = a[i][1]
368 | // a[i][0] = y
369 | // a[i][1] = x
370 | // }
371 | // }
372 |
373 | TZFE.prototype.encodeZuobiao = function(zuobiaoArrray) {
374 | var a = zuobiaoArrray
375 | for (var i = 0; i < a.length; i++) {
376 | var x = a[i][0]
377 | var y = a[i][1]
378 | a[i][0] = y
379 | a[i][1] = x
380 | }
381 | }
382 |
383 | TZFE.prototype.handleUpArray = function(array) {
384 | /*
385 | 向上滑动时 array 合并 & 移动 & 添加一个新元素 (2)
386 | 返回 r {value, i, j} (其中 i j 是增加的新元素的坐标)
387 | */
388 | var a = this.copyArray(array)
389 | a = this.encodeArray(a)
390 | a = this.handleLeftArray(a)
391 | var r = {}
392 | r.value = this.decodeArray(a.value)
393 | r.i = a.j
394 | r.j = a.i
395 | this.encodeZuobiao(this.merge)
396 | this.encodeZuobiao(this.new)
397 | return r
398 | }
399 |
400 | TZFE.prototype.handleDownArray = function(array) {
401 | /*
402 | 向下滑动时 array 合并 & 移动 & 添加一个新元素 (2)
403 | 返回 r {value, i, j} (其中 i j 是增加的新元素的坐标)
404 | */
405 | // console.log('handleDownArray');
406 | var a = this.copyArray(array)
407 | a = this.encodeArray(a)
408 | a = this.handleRightArray(a)
409 | var r = {}
410 | r.value = this.decodeArray(a.value)
411 | r.i = a.j
412 | r.j = a.i
413 | this.encodeZuobiao(this.merge)
414 | this.encodeZuobiao(this.new)
415 | return r
416 | }
417 |
418 | TZFE.prototype.arrayLine = function(length) {
419 | // 制造一行 0
420 | var array = []
421 | for (var i = 0; i < length; i++) {
422 | array.push(0)
423 | }
424 | return array
425 | }
426 |
427 | TZFE.prototype.arrayInit = function(length) {
428 | /*
429 | 制造一个 length * length 的矩阵数组, 矩阵数值为 0
430 | */
431 | var array = []
432 | for (var i = 0; i < length; i++) {
433 | array.push(this.arrayLine(length))
434 | }
435 | return array
436 | }
437 |
438 | TZFE.prototype.numOfZeroFromArray = function(array) {
439 | /*
440 | 返回: 二维数组中 0 的个数
441 | */
442 | var num = 0
443 | for (var i = 0; i < array.length; i++) {
444 | for (var j = 0; j < array[i].length; j++) {
445 | if(array[i][j] == 0) {
446 | num++
447 | }
448 | }
449 | }
450 | return num
451 | }
452 |
453 | TZFE.prototype.numberRandom = function(count) {
454 | /*
455 | 在 0 ~ count 内,产生一个 随机数
456 | */
457 | var r = Math.random() * count
458 | return Math.ceil(r)
459 | }
460 |
461 | TZFE.prototype.copyArray = function(array) {
462 | /*
463 | 复制二维数组
464 | */
465 | // console.log('copyArray');
466 | var r = []
467 | for (var i = 0; i < array.length; i++) {
468 | r.push(array[i].slice(0))
469 | }
470 | return r
471 | }
472 |
473 | TZFE.prototype.randomInitValue = function() {
474 | var a = Math.random() * 10
475 | if (a < 8) {
476 | return 2
477 | } else {
478 | return 4
479 | }
480 | }
481 |
482 | TZFE.prototype.arrayByCreateZero = function(array) {
483 | /*
484 | 随机挑选 二维数组 中的其中一个 0 位置赋值为 2,并返回这个 二维数组 & 坐标
485 | */
486 | var a = this.copyArray(array)
487 | var count = this.numOfZeroFromArray(a)
488 | var num = this.numberRandom(count)
489 | var n = 0
490 | var initNum = this.randomInitValue()
491 | for (var i = 0; i < a.length; i++) {
492 | for (var j = 0; j < a[i].length; j++) {
493 | if(a[i][j] == 0) {
494 | n++
495 | }
496 | if(num == n) {
497 | a[i][j] = initNum
498 | // console.log('lib new', i, j);
499 | return {
500 | value: a,
501 | i: i,
502 | j: j,
503 | }
504 | }
505 | }
506 | }
507 | }
508 |
509 | TZFE.prototype.init2048Array = function(length) {
510 | /*
511 | 初始化 2048,即生成一个二维数组,随机数组中有两个 2 ,返回 二维数组 & 坐标
512 | */
513 | var initaArray = this.arrayInit(length)
514 | var r = this.arrayByCreateZero(initaArray)
515 | initArray = r.value
516 | var result = {
517 | f: {
518 | i: r.i,
519 | j: r.j,
520 | }
521 | }
522 | r = this.arrayByCreateZero(initArray)
523 | result.initArray = r.value
524 | result.s = {
525 | i: r.i,
526 | j: r.j,
527 | }
528 | return result
529 | }
530 |
--------------------------------------------------------------------------------