---
# System prepended metadata

title: 10/2 Arcade也能學演算法Ouo!? 演算法遊戲(3)
tags: [2022 iThome 鐵人賽]

---

---
tags: 2022 iThome 鐵人賽 
title: 10/2 Arcade也能學演算法Ouo!? 演算法遊戲(3)
AUTHOR: 鍾佳龍
---
# Arcade再進化
## Arcade也能學演算法Ouo!? 演算法遊戲!(3)
### **第三篇：棋類遊戲-立體四子棋**

> ### 大綱
> * 遊戲內容
> * 創建角色
> * 控制箭頭
> * 放置棋子
> * 顯示結果
> * 尋找連線

> ## 成果預覽
這是一個雙人對戰遊戲
可以利用左右鍵控制箭頭下棋
每次下棋只能選擇欄
選後會落下至作最上方
只要四個連線即為贏得遊戲
[![](https://i.imgur.com/zFA5U0p.gif)](https://arcade.makecode.com/S26763-39501-31310-23616)
點擊上圖可以進入遊戲頁面

> ## 創建角色
這次會有三個角色
* 棋盤本人
* 棋子狀態
* 箭頭
棋盤
```typescript!
let checkerboard = sprites.create(img`
    ........................
    ........................
    .8..8..8..8..8..8..8..8.
    .8.88.88.88.88.88.88.88.
    .8..8..8..8..8..8..8..8.
    .8.88.88.88.88.88.88.88.
    .8..8..8..8..8..8..8..8.
    .8.88.88.88.88.88.88.88.
    .8..8..8..8..8..8..8..8.
    .8.88.88.88.88.88.88.88.
    .8..8..8..8..8..8..8..8.
    .8.88.88.88.88.88.88.88.
    .8..8..8..8..8..8..8..8.
    .8.88.88.88.88.88.88.88.
    888888888888888888888888
    8......................8
`, SpriteKind.Player)
checkerboard.setScale(5, ScaleAnchor.Middle)
```
然後是棋子
因為棋子的部份我們要用圖片的方式顯示
為了可以跟棋盤重疊
所以我們設定都要跟棋盤一樣
```typescript
let bord = sprites.create(img`
    16*24
`, SpriteKind.Player)
bord.setScale(5, ScaleAnchor.Middle)
```
箭頭的部分很簡單就直接宣告就行
```typescript
let arrow = sprites.create(img`
    . . . . . . .
    . . . 2 . . .
    . . . 2 . . .
    . . . 2 . . .
    . . . 2 . . .
    . 2 2 2 2 2 .
    . . 2 2 2 . .
    . . . 2 . . .
    . . . . . . .
`, SpriteKind.Player)
```
然後我將箭頭放置在棋盤的第一欄上方
```typescript
arrow.setPosition(37, 20)
```
> ## 控制箭頭
我們總共有七欄 要讓箭頭左右移動
ㄟ! 這聽起來很像上次同化遊戲的選顏色
沒錯!
所以我們就拿上次的程式碼來改就好

```typescript
let now_number = 0
controller.right.onEvent(ControllerButtonEvent.Pressed, function () {
    now_number = (now_number + 1) % 7
})
controller.left.onEvent(ControllerButtonEvent.Pressed, function () {
    if (now_number == 0) {
        now_number = 7;
    }
    now_number -= 1;
})
```
然後是要讓箭頭移動
我們可以想成 他從我初次設定的地方(37, 20)
數字多少就移動多少像素(15)
然後再放進去就好

```typescript
let now_number = 0
controller.right.onEvent(ControllerButtonEvent.Pressed, function () {
    now_number = (now_number + 1) % 7
    arrow.setPosition(37 + (now_number * 15), 20)
})
controller.left.onEvent(ControllerButtonEvent.Pressed, function () {
    if (now_number == 0) {
        now_number = 7;
    }
    now_number -= 1;
    arrow.setPosition(37 + (now_number * 15), 20)
})
```
> ## 放置棋子
我們要做一個儲存棋盤的地方
方便我們之後要用

```typescript
let Data = [
[" ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " "],
[" ", " ", " ", " ", " ", " ", " "]
]
```
有棋盤了 接下來就是下棋了
因為我們的規則是放到指定行會往下掉
掉到頂端
所以我們思考的方式就是我們要從下面搜尋
找到最下面的" "

```typescript
function play(location:number) {
    for (let i = 5; i > -1; i--) {
        if (Data[i][location] == " ") {
            ...
        }
    }
}
```
然後我要把最下面的那格換成其他記號 我這邊以O X

```typescript!
let tuen = "O"
let row:number
function put(location:number) {
    for (let i = 5; i > -1; i--) {
        if (Data[i][location] == " ") {
            Data[i][location] = turn
            row = i
            break
        }
    }
}
```
這邊先順便拿個row 之後會用到
到此為止 下棋的部分就算告一落了

> ## 顯示結果
下完棋後要顯示出來
這邊我用的方法是讓背景自己改變
改變角色圖片上一次也用過

```typescript
function show_board() {
    let bord_img = image.create(24, 16) // 製造一個空畫板
    for (let R = 0; R < 6; R++) {
        for (let C = 0; C < 7; C++) {// 依序讀取資料
            if (Data[R][C] != " ") {//如果那格有資料
                let color
                if (Data[R][C] == "O") {
                    color = 2
                } else {
                    color = 5
                }
                //將棋子畫上去
                bord_img.setPixel(C * 3 + 3, R * 2+2, color)
                bord_img.setPixel(C * 3 + 2, R * 2+2, color)
                bord_img.setPixel(C * 3 + 2, R * 2+3, color)
            }
        }
    }
    bord.setImage(bord_img) // 改變圖片
}
```

> ## 我怎麼知道他連線了
最後就是判斷連線了
我們的想法就是以我這次下棋的地方為中心
然後往外找是否連線
以橫向來看
```typescript
function check_end(location: number, row: number) {
    // 檢查橫向
    // 左向
    let count = 0
    for (let i = 0; i < 4 && (location + i < 7); i++) {
        if (Data[row][location + i] != turn) {
            break
        }
        count += 1
    }
    console.log(count)
    // 右向
    for (let i = 0; i < 4 && (location - i > -1); i++) {
        if (Data[row][location - i] != turn) {
            break
        }
        count += 1
    }
    if (count > 4) {
        return true
    }
    ...
```
橫向就是左向加右向
剩下的直 斜 向因為篇幅 所以我沒放進來
請自行到我的遊戲頁面看程式碼

---
基礎架構以完畢 最後就是依序呼叫

```typescript
controller.A.onEvent(ControllerButtonEvent.Pressed, function () {
    put(now_number)
    show_board()
    let is_end = check_end(now_number, row))
    if (is_end){
        game.showLongText(`${turn}win`, DialogLayout.Bottom)
        game.over(false) 
    }
    if(turn == "O"){
        turn = "X"
    }else{
        turn = "O"
    }
})
```
---
> ## 下期預告
> **各種棋篇-黑白棋**