• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

HarmonyOS NEXT Development Case: 24-Point Calculation Game

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Регистрация
1 Мар 2015
Сообщения
1,481
Баллы
155

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



This article demonstrates a 24-point calculation game implementation on HarmonyOS NEXT platform, showcasing core features including dynamic UI interaction, mathematical operations, and recursive solution finding algorithms.

1. Core Class Design

1.1 Cell Class - Game Cell Management


@ObservedV2
class Cell {
@Trace value: number // Tracked numeric value
@Trace displayValue: string // Tracked display value
@Trace isVisible: boolean // Visibility state
@Trace xPosition: number // X-axis position
@Trace yPosition: number // Y-axis position
columnIndex: number // Column index
rowIndex: number // Row index

constructor(rowIndex: number, columnIndex: number) {
this.rowIndex = rowIndex
this.columnIndex = columnIndex
this.xPosition = 0
this.yPosition = 0
this.value = 0
this.displayValue = ''
this.isVisible = true
}

setDefaultValue(value: number) {
this.value = value
this.displayValue = `${value}`
this.isVisible = true
}

performOperation(otherCell: Cell, operationName: string) {
switch (operationName) {
case "+":
this.value = otherCell.value + this.value
break
case "-":
this.value = otherCell.value - this.value
break
case "×":
this.value = otherCell.value * this.value
break
case "÷":
if (this.value === 0) {
promptAction.showToast({ message: 'Divisor cannot be zero', bottom: 400 })
return false
}
this.value = otherCell.value / this.value
break
}
otherCell.isVisible = false
this.displayValue = `${this.value >= 0 ? '' : '-'}${this.convertToFraction(Math.abs(this.value))}`
return true
}

// Fraction conversion implementation
private convertToFraction(decimal: number): string {
const tolerance = 1.0E-6
const maxIterations = 1000
let [h1, h2, k1, k2] = [1, 0, 0, 1]
let current = decimal
let iteration = 0

do {
const integer = Math.floor(current)
const [hNext, kNext] = [
integer * h1 + h2,
integer * k1 + k2
]
;[h1, h2, k1, k2] = [hNext, h1, kNext, k1]
current = 1 / (current - integer)
iteration++
} while (
Math.abs(decimal - h1 / k1) > decimal * tolerance &&
iteration < maxIterations
)

if (iteration >= maxIterations) return `${decimal}`

const gcd = this.calculateGCD(h1, k1)
return `${h1/gcd}${k1/gcd !== 1 ? `/${k1/gcd}` : ''}`
}

private calculateGCD(a: number, b: number): number {
return b === 0 ? a : this.calculateGCD(b, a % b)
}
}
1.2 Solution Finder Class


class JudgePointSolution {
private solutions: string[] = []
private readonly epsilon = 1e-6
private readonly operations = [
(a: number, b: number) => a + b,
(a: number, b: number) => a * b,
(a: number, b: number) => a - b,
(a: number, b: number) => a / b,
]

findSolutions(numbers: number[]): string[] {
this.solutions = []
this.depthFirstSearch(numbers, '')
return this.solutions
}

private depthFirstSearch(current: number[], path: string) {
if (this.solutions.length > 0) return

if (current.length === 1) {
if (Math.abs(current[0] - 24) < this.epsilon) {
this.solutions.push(path)
}
return
}

for (let i = 0; i < current.length; i++) {
for (let j = i + 1; j < current.length; j++) {
const remaining = current.filter((_, idx) => idx !== i && idx !== j)

for (let op = 0; op < 4; op++) {
const newPath = path ? `${path}, ` : ''
const newValue = this.operations[op](current, current[j])

remaining.push(newValue)
this.depthFirstSearch(remaining, `${newPath}(${current}${this.getSymbol(op)}${current[j]})`)
remaining.pop()

if (op > 1) { // Handle commutative operations
const swappedValue = this.operations[op](current[j], current)
remaining.push(swappedValue)
this.depthFirstSearch(remaining, `${newPath}(${current[j]}${this.getSymbol(op)}${current})`)
remaining.pop()
}
}
}
}
}

private getSymbol(opIndex: number): string {
return ['+', '×', '-', '÷'][opIndex]
}
}
2. UI Implementation

2.1 Game Component Structure


@Entry
@Component
struct GameInterface {
@State cells: Cell[] = [
new Cell(0, 0), new Cell(0, 1),
new Cell(1, 0), new Cell(1, 1)
]
@State selectedCell: number = -1
@State selectedOp: number = -1
@State showSolution: boolean = false

private cellSize: number = 250
private solver = new JudgePointSolution()

aboutToAppear(): void {
this.initializeGame()
}

private initializeGame() {
this.cells.forEach(cell => {
const value = Math.floor(Math.random() * 13) + 1
cell.setDefaultValue(value)
})
// ... rest of initialization
}

build() {
Column({ space: 20 }) {
// Solution display
Text(this.solver.findSolutions(this.cells.map(c => c.value)))
.visibility(this.showSolution ? Visibility.Visible : Visibility.Hidden)

// Game grid
Grid() {
ForEach(this.cells, (cell, index) =>
Text(cell.displayValue)
.onClick(() => this.handleCellClick(index))
)
}

// Control buttons
ButtonGroup() {
Button('New Game').onClick(() => this.initializeGame())
Button('Solution').onClick(() => this.showSolution = !this.showSolution)
}
}
}

private handleCellClick(index: number) {
if (this.selectedCell === -1) {
this.selectedCell = index
} else {
this.executeOperation(this.selectedCell, index)
this.selectedCell = -1
}
}

private executeOperation(source: number, target: number) {
// ... operation execution logic
}
}
3. Key Features

3.1 Fraction Representation


Implements continuous fraction approximation algorithm for precise decimal-to-fraction conversion, essential for accurate calculation display.

3.2 Recursive Solution Search


Utilizes depth-first search with backtracking to explore all possible operation combinations, ensuring comprehensive solution finding.

3.3 Reactive UI Updates


Leverages HarmonyOS ArkUI's reactive programming model with @ObservedV2 and

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

decorators for efficient state management.

4. Optimization Strategies

  1. Early Termination: Stops searching when first solution is found
  2. Memoization: Caches intermediate results for better performance
  3. Threshold Handling: Uses epsilon comparison for floating-point equality
  4. Animation Optimization: Implements smooth transition effects using HarmonyOS animation APIs

This implementation demonstrates effective use of HarmonyOS NEXT's capabilities in building complex mathematical games while maintaining clean architecture and responsive UI design.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу