• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import {DataType } from '../model/GameModuel';
17
18// gameStatus
19enum GameStatus {
20  BEFORE = -1,
21  RUNNING = 1,
22  OVER = 0
23}
24
25export class GameRule {
26  private row: number = 4
27  private column: number = 4
28
29  private index(i: number, j: number): number {
30    return i * this.row + j
31  }
32
33  dataNumbers: Array<number> = []
34  status: number = GameStatus.BEFORE
35  score: number = 0
36
37  constructor(numbers: Array<DataType>) {
38    numbers.forEach((item) => {
39      this.dataNumbers.push(item.data);
40    })
41  }
42
43  // random
44  randomNum(): boolean {
45    do {
46      let a = Math.floor(Math.random() * this.dataNumbers.length)
47      if (this.dataNumbers[a] === 0) {
48        let num = Math.random() > 0.3 ? 2 : 4
49        this.dataNumbers[a] = num
50        break
51      }
52    } while (this.dataNumbers.some((val) => {
53      return val === 0
54    }))
55    return false
56  }
57
58  // init
59  init(): void {
60    this.dataNumbers = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
61    this.status = GameStatus.RUNNING
62    this.score = 0
63    this.randomNum()
64    this.randomNum()
65  }
66
67  // move
68  move(direction: string): void {
69    let before = String(this.dataNumbers)
70    let length = (direction === 'left' || direction === 'right') ? this.row : this.column
71    for (let a = 0;a < length; a++) {
72      this.moveInRow(direction, a)
73    }
74    let after = String(this.dataNumbers)
75    if (before !== after) {
76      this.randomNum()
77      if (this.isGameOver()) {
78        this.status = GameStatus.OVER
79      }
80    }
81  }
82
83  // prepare to move
84  moveInRow(direction: string, a: number) {
85    if (direction === 'left') {
86      for (let b = 0;b < this.column - 1; b++) {
87        let next = this.moveNext(a, b, direction)
88        b = this.dataChange(a, b, next, direction).b
89        if (next === -1) break
90      }
91    } else if (direction === 'right') {
92      for (let b = this.column - 1;b > 0; b--) {
93        let next = this.moveNext(a, b, direction)
94        b = this.dataChange(a, b, next, direction).b
95        if (next === -1) break
96      }
97    } else if (direction === 'up') {
98      for (let b = 0;b < this.row - 1; b++) {
99        let next = this.moveNext(b, a, direction)
100        b = this.dataChange(b, a, next, direction).a
101        if (next === -1) break
102      }
103    } else if (direction === 'down') {
104      for (let b = this.row - 1;b > 0; b--) {
105        let next = this.moveNext(b, a, direction)
106        b = this.dataChange(b, a, next, direction).a
107        if (next === -1) break
108      }
109    }
110  }
111
112  // new number moveStatus
113  moveNext(a: number, b: number, direction: string): number {
114    if (direction === 'left') {
115      for (let i = b + 1;i < this.column; i++) {
116        if (this.dataNumbers[this.index(a, i)] !== 0) {
117          return i
118        }
119      }
120    } else if (direction === 'right') {
121      for (let i = b - 1;i >= 0; i--) {
122        if (this.dataNumbers[this.index(a, i)] !== 0) {
123          return i
124        }
125      }
126    } else if (direction === 'up') {
127      for (let i = a + 1;i < 4; i++) {
128        if (this.dataNumbers[this.index(i, b)] !== 0) {
129          return i
130        }
131      }
132    } else if (direction === 'down') {
133      for (let i = a - 1;i >= 0; i--) {
134        if (this.dataNumbers[this.index(i, b)] !== 0) {
135          return i
136        }
137      }
138    }
139    return -1
140  }
141
142  // get gameStatus
143  isGameOver(): boolean {
144    for (let a = 0;a < this.row; a++) {
145      for (let b = 0;b < this.column; b++) {
146        let tempA = this.index(a, b)
147        if (this.dataNumbers[tempA] === 0) {
148          return false
149        }
150        if (a < this.row - 1) {
151          if (this.dataNumbers[tempA] === this.dataNumbers[this.index(a + 1, b)]) {
152            return false
153          }
154        }
155        if (b < this.column - 1) {
156          if (this.dataNumbers[tempA] === this.dataNumbers[tempA+1]) {
157            return false
158          }
159        }
160      }
161    }
162    return true
163  }
164
165  // move and merge
166  dataChange(a: number, b: number, next: number, direction: string): {
167    a: number,
168    b: number
169  } {
170    let tempA = this.index(a, b)
171    let tempB = 0
172    if (direction === 'left' || direction === 'right') {
173      tempB = this.index(a, next)
174    } else {
175      tempB = this.index(next, b)
176    }
177    if (next !== -1) {
178      if (this.dataNumbers[tempA] === 0) {
179        this.dataNumbers[tempA] = this.dataNumbers[tempB]
180        this.dataNumbers[tempB] = 0
181        direction === 'left' && b--
182        direction === 'right' && b++
183        direction === 'up' && a--
184        direction === 'down' && a++
185      } else if (this.dataNumbers[tempA] === this.dataNumbers[tempB]) {
186        this.dataNumbers[tempA] *= 2
187        this.score += this.dataNumbers[tempA]
188        this.dataNumbers[tempB] = 0
189      }
190    }
191    return {
192      a, b
193    }
194  }
195}