Read the original article:🎮Let’s Build XoX with ArkTS🎮
Hey there, fellow developers! In this article, we’re going to build a simple Tic Tac Toe (XoX) game using ArkTS, Huawei’s modern TypeScript-based declarative UI framework.
Our goal is to learn the fundamentals of ArkTS while creating something fun and visual.
🧩 Step 1: The Model
Each box on our 3x3 grid is represented by a simple model class:
@Observed
export class Box {
value: string
constructor(value: string) {
this.value = value;
}
}
🧠Step 2: Utility Functions
Let’s define a utility class to handle basic helper methods:
import { Box } from "./model/Box";
export class Utils {
//initializes 9 empty boxes.
static generateBoxes(): Box[] {
const list: Box[] = [];
for (let index = 0; index < 9; index++) {
list.push(new Box(''))
}
return list;
}
//assigns a color based on whether it’s 'X' or 'O'
static generateColor(value: string): ResourceColor {
if (value == 'X') {
return Color.Blue
} else {
return Color.Red
}
}
}
🧱 Step 3: Creating the Game Component
Now we build the core logic of the game inside a GameBox component.
import { Box } from "../model/Box";
import { Utils } from "../Utils";
@Component
export struct GameBox{
@State boxes: Box[] = Utils.generateBoxes()
//with each change in pen's value checkWin method is being called
@State @Watch('checkWin') pen: string = 'X';
@State winner: string = '';
@State isShow: boolean = false;
// in any of win pattern is works, winner is being assigned and
// the builder showResult is called
checkWin(){
const winPatterns = [
// rows
[0, 1, 2], [3, 4, 5], [6, 7, 8],
// columns
[0, 3, 6], [1, 4, 7], [2, 5, 8],
// cross
[0, 4, 8], [2, 4, 6]
];
for (let i = 0; i < winPatterns.length; i++) {
const a = winPatterns[i][0];
const b = winPatterns[i][1];
const c = winPatterns[i][2];
if (
this.boxes[a].value !== '' &&
this.boxes[a].value === this.boxes[b].value &&
this.boxes[a].value === this.boxes[c].value
) {
this.winner = this.boxes[a].value;
this.isShow = true;
return;
}
}
let isDraw = true;
for (let i = 0; i < this.boxes.length; i++) {
if (this.boxes[i].value === '') {
isDraw = false;
break;
}
}
// if there is no winner, this logic works and refresh the game
if (isDraw) {
this.refresh()
}
}
// pen starts as a X and boxes are being generated from stratch winner is no one
refresh(){
this.pen = 'X';
this.boxes = Utils.generateBoxes()
this.winner = '';
this.isShow = false;
}
//shows the winner with popup
@Builder
ShowResult(){
Column(){
Text(this.winner + ' is winner!').fontSize(24).fontWeight(FontWeight.Bold).padding(8)
Button('Restart')
.backgroundColor(Color.White)
.fontColor(Utils.generateColor(this.winner))
.borderColor(Utils.generateColor(this.winner))
.borderWidth(1)
.fontSize(24)
.onClick(() => {
this.refresh()
})
}
}
build() {
RelativeContainer() {
Column() {
GridRow({ columns: 3 }) {
ForEach(this.boxes, (item:Box, index: number) => {
GridCol() {
Row() {
Text(item.value)
.fontWeight(FontWeight.Bold)
.fontColor(Utils.generateColor(item.value))
.fontSize(28)
}.onClick(() =>{
if (!item.value && !this.winner) {
this.boxes[index] = new Box(this.pen)
this.pen = this.pen == 'X' ? 'O' : 'X';
}
})
.height('33%').width('33%').justifyContent(FlexAlign.Center)
}.border( { 'color': Color.Gray, 'width': 1 })
}, (item: Box, index: number) => `${index}${JSON.stringify(item)}`)
}
.width('100%').height('100%')
}
//call popup with .bindhSheet
.bindSheet(this.isShow, this.ShowResult(), {height: '50%', onDisappear: () => this.refresh(), showClose:false})
.justifyContent(FlexAlign.Center)
.border( { 'color': Color.Gray, 'width': 2 })
.width('70%')
.height('70%')
.margin('15%')
}
.height('100%')
.width('100%')
}
}
🚀 Step 4: Calling our main component in Index.ets
import { GameBox } from '../components/GameBox'
@Entry
@Component
struct Index {
build() {
Column(){
GameBox()
}
}
}
The final result is something like this:
✅We’ve built a fully functional Tic Tac Toe game using ArkTS, all in under 150 lines of code!
Through this small project, you learned how to:
- Work with
@Stateand@Watchfor reactivity - Use
@Observedto track model changes - Create layouts with
GridRow,Column, andRelativeContainer - Show modals with
bindSheet - Write clean reusable code using utilities
Thank you for reading and let me know in the comments section if you have any questions. Happy coding!

Top comments (0)