HarmonyOS NEXT Development Case: Encircle the Neuro Cat
zhongcx

zhongcx @zhongcx

About: The best time to plant a tree was 10 years ago, the second-best time is now.

Joined:
Mar 6, 2025

HarmonyOS NEXT Development Case: Encircle the Neuro Cat

Publish Date: May 11
0 0

Image description

This article demonstrates how to implement a "Neuro Cat" game using HarmonyOS NEXT and ArkUI. The goal is to trap the cat within a hexagonal grid by placing walls strategically. Below is the code implementation with detailed explanations and translated annotations.


Core Code Implementation

1. Import Dependencies

import { promptAction } from '@kit.ArkUI'; // Import prompt dialog component
Enter fullscreen mode Exit fullscreen mode

2. Define the Cell Class

@ObservedV2 // Observer decorator to monitor state changes
class Cell {
  @Trace value: number = 0; // Cell value: 0 (empty), 1 (wall)
  x: number = 0; // X-coordinate of the cell
  y: number = 0; // Y-coordinate of the cell
  leftNeighborIndex: number | undefined = undefined; // Left neighbor index
  rightNeighborIndex: number | undefined = undefined; // Right neighbor index
  leftTopNeighborIndex: number | undefined = undefined; // Left-top neighbor index
  rightTopNeighborIndex: number | undefined = undefined; // Right-top neighbor index
  leftBottomNeighborIndex: number | undefined = undefined; // Left-bottom neighbor index
  rightBottomNeighborIndex: number | undefined = undefined; // Right-bottom neighbor index

  constructor(value: number, x: number, y: number) {
    this.value = value; // Initialize cell value
    this.x = x; // Initialize X-coordinate
    this.y = y; // Initialize Y-coordinate
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Main Component Implementation

@Entry // Entry decorator for the root component
@Component // Component decorator
struct Index {
  @State gridCells: Cell[] = []; // Array storing all cells
  cellWidth: number = 70; // Cell width
  borderPieceWidth: number = -10; // Border piece width
  pieceSize: number = 65; // Piece size
  @State catPositionIndex: number = 40; // Cat's current position index

  // Initialize the game board
  aboutToAppear(): void {
    this.initializeBoard();
    this.startGame();
  }

  // Find movable neighbors for a cell
  findNeighbors(cell: Cell): Cell[] {
    let neighbors: Cell[] = [];
    if (cell.leftNeighborIndex !== undefined && this.gridCells[cell.leftNeighborIndex].value === 0) {
      neighbors.push(this.gridCells[cell.leftNeighborIndex]); // Left neighbor
    }
    if (cell.rightNeighborIndex !== undefined && this.gridCells[cell.rightNeighborIndex].value === 0) {
      neighbors.push(this.gridCells[cell.rightNeighborIndex]); // Right neighbor
    }
    if (cell.leftTopNeighborIndex !== undefined && this.gridCells[cell.leftTopNeighborIndex].value === 0) {
      neighbors.push(this.gridCells[cell.leftTopNeighborIndex]); // Left-top neighbor
    }
    if (cell.rightTopNeighborIndex !== undefined && this.gridCells[cell.rightTopNeighborIndex].value === 0) {
      neighbors.push(this.gridCells[cell.rightTopNeighborIndex]); // Right-top neighbor
    }
    if (cell.leftBottomNeighborIndex !== undefined && this.gridCells[cell.leftBottomNeighborIndex].value === 0) {
      neighbors.push(this.gridCells[cell.leftBottomNeighborIndex]); // Left-bottom neighbor
    }
    if (cell.rightBottomNeighborIndex !== undefined && this.gridCells[cell.rightBottomNeighborIndex].value === 0) {
      neighbors.push(this.gridCells[cell.rightBottomNeighborIndex]); // Right-bottom neighbor
    }
    return neighbors;
  }

  // Initialize the 9x9 hexagonal grid
  initializeBoard() {
    this.gridCells = [];
    for (let rowIndex = 0; rowIndex < 9; rowIndex++) {
      for (let columnIndex = 0; columnIndex < 9; columnIndex++) {
        this.gridCells.push(new Cell(0, rowIndex, columnIndex));
      }
    }
    // Configure neighbor indices based on hexagonal grid logic
    for (let rowIndex = 0; rowIndex < 9; rowIndex++) {
      for (let columnIndex = 0; columnIndex < 9; columnIndex++) {
        const cellIndex = rowIndex * 9 + columnIndex;
        const cell = this.gridCells[cellIndex];
        // Logic for setting neighbor indices...
        // (Omitted for brevity; see original code for details)
      }
    }
  }

  // Start or reset the game
  startGame() {
    let availableIndices: number[] = [];
    for (let i = 0; i < 81; i++) {
      this.gridCells[i].value = 0;
      if (i === 39 || i === 40 || i === 41) continue; // Exclude center cells
      availableIndices.push(i);
    }
    // Generate random walls
    for (let i = 0; i < 8; i++) {
      const randomIndex = Math.floor(Math.random() * availableIndices.length);
      this.gridCells[availableIndices[randomIndex]].value = 1;
      availableIndices.splice(randomIndex, 1);
    }
    this.catPositionIndex = 40; // Reset cat position
  }

  // Move the cat based on AI logic
  moveCat(): void {
    const neighbors = this.findNeighbors(this.gridCells[this.catPositionIndex]);
    const emptyNeighbors = neighbors.filter(neighbor => neighbor.value === 0);
    if (emptyNeighbors.length === 0) {
      promptAction.showDialog({
        title: "'You Win!',"
        buttons: [{ text: 'Restart', color: '#ffa500' }]
      }).then(() => this.startGame());
    } else {
      const nextMove = this.selectNextMove(emptyNeighbors);
      this.catPositionIndex = nextMove.x * 9 + nextMove.y;
      if (nextMove.x === 0 || nextMove.x === 8 || nextMove.y === 0 || nextMove.y === 8) {
        promptAction.showDialog({
          title: "'You Lose!',"
          buttons: [{ text: 'Restart', color: '#ffa500' }]
        }).then(() => this.startGame());
      }
    }
  }

  // Select the next move using a heuristic approach
  selectNextMove(emptyNeighbors: Cell[]): Cell {
    let closestToEdge: Cell | null = null;
    let minDistanceToEdge = Number.MAX_VALUE;
    for (const neighbor of emptyNeighbors) {
      const distance = Math.min(neighbor.x, 8 - neighbor.x, neighbor.y, 8 - neighbor.y);
      if (distance < minDistanceToEdge) {
        minDistanceToEdge = distance;
        closestToEdge = neighbor;
      }
    }
    return closestToEdge || emptyNeighbors[0];
  }

  // Build UI components
  build() {
    Column({ space: 20 }) {
      Stack() {
        // Background grid
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.gridCells, (item: Cell, index: number) => {
            Stack() {
              Text().width(`${this.pieceSize}lpx`).height(`${this.pieceSize}lpx`)
                .backgroundColor(item.value === 0 ? "#b4b4b4" : "#ff8d5a")
                .borderRadius('50%')
            }
            .margin({ left: `${(index + 9) % 18 === 0 ? this.cellWidth / 2 : 0}lpx` })
          })
        }

        // Cat and interactive elements
        Flex({ wrap: FlexWrap.Wrap }) {
          ForEach(this.gridCells, (item: Cell, index: number) => {
            Stack() {
              Text('Cat')
                .width(`${this.pieceSize}lpx`)
                .fontColor(Color.White)
                .visibility(this.catPositionIndex === index ? Visibility.Visible : Visibility.None)
            }
            .onClick(() => {
              if (item.value === 0 && index !== this.catPositionIndex) {
                item.value = 1; // Place a wall
                this.moveCat(); // Trigger cat movement
              }
            })
          })
        }
      }

      // Restart button
      Button('Restart').onClick(() => this.startGame())
    }
    .backgroundColor("#666666")
  }
}
Enter fullscreen mode Exit fullscreen mode

Key Features

  1. Hexagonal Grid Logic: The grid uses a 9x9 hexagonal layout, with neighbor indices calculated based on row parity.
  2. Cat Movement AI: The cat moves toward the edge using a Manhattan distance heuristic to escape.
  3. State Management: Leverages @ObservedV2 and @State decorators for reactive UI updates.
  4. User Interaction: Players click empty cells to place walls, triggering the cat's movement.

This implementation showcases HarmonyOS NEXT's declarative UI capabilities and reactive programming model. Developers can extend this logic to create more complex games or interactive applications.

Comments 0 total

    Add comment