HarmonyOS NEXT Development Case: 24-Point Calculation Game
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) 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) { 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 @trace decorators for efficient state management. 4. Optimization Strategies Early Termination: Stops searching when first solution is found Memoization: Caches intermediate results for

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[i], current[j])
remaining.push(newValue)
this.depthFirstSearch(remaining, `${newPath}(${current[i]}${this.getSymbol(op)}${current[j]})`)
remaining.pop()
if (op > 1) { // Handle commutative operations
const swappedValue = this.operations[op](current[j], current[i])
remaining.push(swappedValue)
this.depthFirstSearch(remaining, `${newPath}(${current[j]}${this.getSymbol(op)}${current[i]})`)
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 @trace decorators for efficient state management.
4. Optimization Strategies
- Early Termination: Stops searching when first solution is found
- Memoization: Caches intermediate results for better performance
- Threshold Handling: Uses epsilon comparison for floating-point equality
- 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.