LoginSignup
2
0

More than 3 years have passed since last update.

[Golang] ネストしたスライスを使って、○×ゲーム描画部分のみのサンプルコードと解説

Last updated at Posted at 2019-08-23

今日のコード

引用元のコード:A Tour of Go / Slices of slices

○×ゲーム描画サンプル
package main

import (
    "fmt"
    "strings" // ①
)

func main() {
    // デフォルトの盤を準備…②
    board := [][]string{
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
    }

    // ○×を入れていく…③
    board[0][0] = "X"
    board[2][2] = "O"
    board[1][2] = "X"
    board[1][0] = "O"
    board[0][2] = "X"

    // 全体を描画する…④
    for i := 0; i < len(board); i++ {
        fmt.Printf("%s\n", strings.Join(board[i], " "))
    }

}
出力結果
X _ X
O _ X
_ _ O

はじめに

今回は、A Tour of Goを勉強していて、本家の解説が少なくて分かりにくかった部分を共有したいと思います。

解説

サンプルコード内に①〜④の目印をつけています。
1つずつ調べたことを共有します。

1.stringsパッケージ

まず、①のパッケージについて。
これは、大変分かりやすくまとめてくれているサイトがあったので、解説はこちらに任せますが、要はGo言語で文字列操作を、シンプルに行える関数を集めたパッケージのようです。
かなりよく使いそうなものがたくさん並んでいるので、僕と同じ入門者の方はサラッと見ておくと良いかと思います!

2.ネストされたスライスの定義

ネストされたスライスの定義
    board := [][]string{
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
    }

この部分です。ちょっと個人的には、ワケわからなくなったので、整理しておきます。
通常の(ネストしていない)スライスを定義するには、

ネストしていなければ…

ネストしていないスライス例
    x := []string{"a", "b", "c"}
    fmt.Println(x) // => [a b c]

スライスなので…

  • []の中には何も入れず、
  • 格納するデータがstring型なので、それを記述し、
  • 実際に、{"a", "b", "c"}このようにデータを格納している。

という感じです。

これをネストさせると…

ネストしたスライス例
    y := [][]string{
        []string{"a1", "a2", "a3"},
        []string{"b1", "b2", "b3"},
        []string{"c1", "c2", "c3"}
    }
    fmt.Println(y) // => [[a1 a2 a3] [b1 b2 b3] [c1 c2 c3]]

先ほどの

{"a", "b", "c"}

↑この部分が、

{
    []string{"a1", "a2", "a3"},
    []string{"b1", "b2", "b3"},
    []string{"c1", "c2", "c3"}
}

↑こうなります。
ネスト(入れ子構造に)しているだけなので、落ち着いてよく見れば分かるかと思います。
大丈夫!…怖くないから…!!(笑)

ポイントは[][]string{}←ここ

[][]ここで、ネストのスライスだと定義しているのかと思いきや、内側でもしっかり[]で定義。
ここは、もう決まり文句として捉えようと思います(笑)

あと、個人的に意外だった部分ですが、このネスト構造の一番外側の定義部分…
stringなんですね…
個人的には、中に入っているデータはスライスなので、ここは[][]slice{}(←適当)みたいなことになるのかなと考えていたのですが、違いました。

というか、そんな型ないですよね…(笑)

ネストされるスライスの型は一律(?)

そこで予想されるのが、

[["あ", "い", "う"], [1, 2, 3], [true, false, false]]

↑こんな感じの、バラバラの型はネストして格納できなさそう…ということ。

つまり、ネスト格納するデータは、同じ種類の型のもの入れられないのではないかと、予想されます。
(違っていたらすみません。その場合はコメントでご指摘もらえると嬉しいです。)

実際、強引にやってみたら「intは無理っす」的なエラーがでました。

無理やり違う型をネストしてみたスライス
    board := [][]string{
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
        []int{1,2,3},
    }
エラー文
cannot use []int literal (type []int) as type []string in array or slice literal

3.1行ずつ描画させて、ネストしたスライスのどこに格納されていくかを確認してみた

    board[0][0] = "X"
    board[2][2] = "O"
    board[1][2] = "X"
    board[1][0] = "O"
    board[0][2] = "X"

ここの部分です。
1行ずつ結果を出力して描画させることで、どの階層の、どこに値を代入されせているかを、確認しながら見ると理解が深まりましたので、共有しておきます。

(入力前)
_ _ _
_ _ _
_ _ _
1行目
    board[0][0] = "X"
X _ _
_ _ _
_ _ _
2行目
    board[0][0] = "X"
    board[2][2] = "O"
X _ _
_ _ _
_ _ O
3行目
    board[0][0] = "X"
    board[2][2] = "O"
    board[1][2] = "X"
X _ _
_ _ X
_ _ O
4行目
    board[0][0] = "X"
    board[2][2] = "O"
    board[1][2] = "X"
    board[1][0] = "O"
X _ _
O _ X
_ _ O
5行目
    board[0][0] = "X"
    board[2][2] = "O"
    board[1][2] = "X"
    board[1][0] = "O"
    board[0][2] = "X"
X _ X
O _ X
_ _ O

このような感じになります。
分かりやすくなりました。

4.全体strings.Join関数

    for i := 0; i < len(board); i++ {
        fmt.Printf("%s\n", strings.Join(board[i], " "))
    }

最後に、ここの関数についてざっくり解説です。
前提として、今回のスライスは1階層目に3つのスライスが入っています

それらの描画方法として、ここの部分では
fmt.Printf("%s\n", strings.Join(board[i], " "))
この1行だけで、

  • 1つずつのスライスを結合して、
  • 間に(空文字)を入れて、
  • string型として文字列にしています。

strings.Join関数…便利な関数です。

さいごに

最後まで読んでいただき、ありがとうございました。
まだまだ入門者なので、間違いもあるかと思います。
ご指摘頂ければ、幸いです。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0