🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Swift Playground

Swift Playgroundは、Swiftをインタラクティブに習得できるiPad向けのアプリケーション。コーディングの知識は一切必要なく、Swift Playgrounds上でプログラミングしたコードによりドローン・ロボットを自在に動かすことが可能です。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

1回答

804閲覧

swiftで配列を拡張して分岐を作りたい

taro_nii_chan

総合スコア207

Swift Playground

Swift Playgroundは、Swiftをインタラクティブに習得できるiPad向けのアプリケーション。コーディングの知識は一切必要なく、Swift Playgrounds上でプログラミングしたコードによりドローン・ロボットを自在に動かすことが可能です。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2019/11/21 22:56

編集2019/11/25 23:41

環境:

macOS Catalina バージョン 10.15.1
Xcode Version 11.2.1

やりたい事:

Xcode の PlayGround で簡単な囲碁プログラムを作ろうとしています。

下記コードを実行すると

......... ......... ......... .....@... ...@.oo.. ......... ....o.... ......... .........

のように出力されます。

コードのコメント(1)~(5)のように対局が進む間は「着手」を「棋譜」にappendしていけばいいのですが、コメント(6)のように一旦手を戻して(7)のように別の着手をした場合に、現段階では(5)が消えてしまい、(1)(2)(3)(4)(7)と打ったように配列がなってしまいます。

これを、(1)~(5)はそれはそれで取って置き、それを消さずに(7)の変化図も記憶しておきたいのです。

つまり、

(1) -> (2) -> (3) -> (4) -> (5) L> (7)

のような状態を何らかの方法で保持したいのです。

こういった場合にどんなアルゴリズムが用いられるのかをご教授願いたいです。

よろしくお願いします。

swift

1let: String = "@" 2let: String = "o" 3let: String = "." 4let 盤の大きさ: Int = 9 5var 手番: String =6 7struct 着手 { 8 var: String 9 var x: Int 10 var y: Int 11 init(: String, x: Int, y: Int) { 12 self.=13 self.x = x 14 self.y = y 15 } 16} 17 18var 棋譜: [着手] = [] 19var 局面: [[String]] = Array(repeating: Array(repeating:, count: 盤の大きさ), count: 盤の大きさ) 20 21func 着手する(x: Int, y: Int) { 22 棋譜.append(着手(: 手番, x: x - 1, y: y - 1)) 23 手番 = 手番 ==?:24} 25 26func 戻す() { 27 let 最後の着手: 着手 = 棋譜.popLast()! 28 局面[最後の着手.y][最後の着手.x] =29 手番 = 手番 ==?:30} 31 32着手する(x: 6, y: 4) // (1) 33着手する(x: 5, y: 7) // (2) 34着手する(x: 4, y: 5) // (3) 35着手する(x: 7, y: 5) // (4) 36着手する(x: 7, y: 4) // (5) 37戻す() // (6) 38着手する(x: 6, y: 5) // (7) 39 40for i in 0 ..< 棋譜.count { 41 局面[棋譜[i].y][棋譜[i].x] = 棋譜[i].42} 43for y in 0 ..< 盤の大きさ { 44 for x in 0 ..< 盤の大きさ { 45 print(局面[y][x], separator: " ", terminator: "") 46 } 47 print() 48}

追記、masatoUchidaさんの回答を元に考えてみたこと(2019.11.22 19:47)

なるほどと思いました。
で、「何手目か」と「分岐番号」を(何手目か, 分岐番号)で簡略的に表しながら考えてみました。

まずは初期状態から5手まで打ったのが下の0行目です。
ここで(2, 0)に戻って3手目で別の手を打ち5手目まで打ったのが1行目。
更に(1, 0)に戻って別の2手目を打って5手目まで打ったのが2行目。
で、ここからが本題です。

(3, 0)に戻って(4, 0)とは別の4手目を打った場合には(4, 3)と表すことになるのかなと思います。一旦そうします。
今度はに(3, 1)に戻って(4, 1)とは別の4手目を打った場合に(4, 4)と表すこととしたとします。
すると、一見良さそうに見えますが、この図だけから見ると(4, 4)はどこから派生したのかが分からなくなります。
つまり、(4, 4)は(3, 1)の次の手に見えますが、(3, 2)の次の手の可能性もあり得るのではないかという事です。

(0, 0) -> (1, 0) -> (2, 0) -> (3, 0) -> (4, 0) -> (5, 0) // 0行目 L> (3, 1) -> (4, 1) -> (5, 1) // 1行目 L> (2, 2) -> (3, 2) -> (4, 2) -> (5, 2) // 2行目 L> (4, 3) -> (5, 3) // 3行目 L> (4, 4) -> (5, 4) // 4行目

僕の理解力不足であればいいのですが。もしそうでしたらご指摘ください。

で、代案としてstruct着手に自分の通番(id)と前の着手の通番(id)を持っておくといいんじゃないかという気がしています。
まだ見えてる訳ではないのですが、その路線で進めてみようと思っています。
進展があったらご報告します。

引き続き回答、アドバイス等あればお待ちしています。

追記(2019.11.26 8:41)

MasatoUchidaさんのアドバイスを手がかりにデータの持ち方を変えてみました。
簡単のため石の色や座標は省略し、着手番号(id)と次の着手(idの配列)を持たせることにしました。
structだとエラーが出るのでclassにしてみました。
それが下のコードです。

swift

1var 通番: Int = 0 2class 着手 { 3 var 着手番号: Int 4 var 次の着手: [着手] 5 init() { 6 self.着手番号 = 通番 7 self.次の着手 = [] 8 通番 += 1 9 } 10 func append(次の着手: 着手) { 11 self.次の着手.append(次の着手) 12 } 13 func print() { 14 if 次の着手.count == 0 { 15 Swift.print(self.着手番号) 16 } else { 17 for i in 0 ..< 次の着手.count { 18 if 次の着手[i].着手番号 == 4 { 19 } 20 Swift.print(self.着手番号, " - ", separator: "", terminator: "") 21 次の着手[i].print() 22 } 23 } 24 } 25} 26 27let 棋譜 = 着手() 28let A = 着手() 29let B = 着手() 30let C = 着手() 31let D = 着手() 32let E = 着手() 33let F = 着手() 34let G = 着手() 35let H = 着手() 36let I = 着手() 37let J = 着手() 38let K = 着手() 39棋譜.append(次の着手: A) 40A.append(次の着手: B) 41A.append(次の着手: C) 42B.append(次の着手: D) 43D.append(次の着手: G) 44D.append(次の着手: H) 45D.append(次の着手: I) 46C.append(次の着手: E) 47C.append(次の着手: F) 48F.append(次の着手: J) 49F.append(次の着手: K) 50 51棋譜.print()

これを実行すると、

0 - 1 - 2 - 4 - 7 4 - 8 4 - 9 1 - 3 - 5 3 - 6 - 10 6 - 11

と表示されます。
本当は

0 - 1 - 2 - 4 - 7 | L 8 | L 9 L 3 - 5 L 6 - 10 L 11

のように表示させたいのですが、それは本筋とは関係ないので良しとします。

上のコードにはundo()は書いてありませんが、一つ戻るだけじゃなく任意の着手にジャンプできるので基本この形でいいのかなと思ってます。

アドバイス、回答、ありがとうございました。

ソースが汚い、無駄があるなどありましたら是非お知らせください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

t_obara

2019/11/22 01:34

戻す時に、配列からpopするのではなく、戻ることを示す着手を配列に入れれば良いのでは?
taro_nii_chan

2019/11/22 09:32

確かにpopしちゃったら消えちゃいますもんね。我ながら思慮不足だと思いました。 MasatoUchidaさんの回答にも同様のアドバイスがあるので、その方向で考えてみたいと思います。 ありがとうございます。
guest

回答1

0

ベストアンサー

struct着手に何手目かと分岐番号を保持するのはいかがでしょうか。
考慮することが多そうですがそうすれば、戻した時にpopLastさせることなくどこから分岐した盤面なのか管理できるかと思います。

投稿2019/11/22 01:47

MasatoUchida

総合スコア134

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

taro_nii_chan

2019/11/22 10:48

回答ありがとうございます。とても参考になっています。 思ったところがあるのですが、回答へのコメントでは書き表しにくいので質問に追記させていただきました。 よろしければご指摘等お願いします。
taro_nii_chan

2019/11/25 23:43

時間がかかってしまいましたが、おかげさまで何とか先に進めそうです。 質問に追記しましたのでよければご覧ください。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問