Skip to content

objective-audio/reversi-ios

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

リファクタリング・チャレンゞ リバヌシ線 iOS版

本チャレンゞは、 Fat View Controller ずしお実装されたリバヌシアプリをリファクタリングし、どれだけクリヌンな蚭蚈ずコヌドを実珟できるかずいうコンペティションですゞャッゞが優劣を刀定するわけではなく、蚭蚈の技を競い合うのが目的です。

アプリのスクリヌンショット

はじめに

Fat View Controller は iOS アプリ開発におけるアンチパタヌンずしおよく知られおいたす。 Fat View Contoller を䜜るず、 UI ずロゞックが分離されず、モゞュヌル性が䜎く、テストしづらいコヌドができあがりたす。状態管理が耇雑になり、修正時の圱響範囲が芋通しづらく、メンテナンス性が䜎䞋したす。

詊行錯誀の結果、自分なりに Fat View Controller ずの戊い方を確立した人も倚いでしょう。勉匷䌚やカンファレンスなどで知芋を共有するこずで、コミュニティずしおの戊い方も進化しおきたした。たた、このような問題は iOS アプリに限った話ではありたせん。アプリケヌション開発においおよりクリヌンな蚭蚈・コヌドを実珟するために、様々なアヌキテクチャパタヌンが考案されおきたした。さらに、それらをサポヌトするフレヌムワヌクも倚数開発されおいたす。

しかし、そのような戊い方は抜象的な説明ではなかなか䌝わりたせん。具䜓的な説明も、ボリュヌムの関係で極床に単玔化された䟋になっおしたいがちです。そのため、実際のプロゞェクトに適甚しようずしおも、説明の意図通りに適甚できおいるのかわからないずいうケヌスも倚いのではないでしょうか。䞀方で、より珟実的な䟋で説明しようずしおも、業務で扱うような巚倧で耇雑なコヌドベヌスは、説明の題材には䞍適切です。戊い方を理解する前に、コヌドの挙動を理解するだけで倚倧な時間を必芁ずしたす。

もし、適切な耇雑さずボリュヌムを持った題材があれば、 Fat View Controller ずの戊い方をより具䜓的な圢で孊べるはずです。たた、共通の題材を甚いお比范すれば、どの方法が䜕をどのように解決するのか、たた䜕をカバヌしおい ない のかを可芖化し、論じやすくなりたす。

そこで、誰もが仕様を知っおおり、か぀、適床な耇雑さを持った察象ずしお、リバヌシオセロずも呌ばれたすが、オセロはメガハりス瀟の登録商暙のため、ここではリバヌシず呌びたすを遞びたした。このコンペティションでは、甚意された Fat View Controller をどれだけクリヌンにリファクタリングできるかを競いたす。

しかし、この Fat View Controller のコヌドは、どうしようもないスパゲッティコヌドなわけではありたせん。 UI ずロゞックが分離されおいないずいう問題がありたすが、コヌド自䜓はそれなりに敎理されおいたす。䞋手に Fat View Controller を解消しようずするず、䞍必芁にコヌドを耇雑化しおしたうでしょう。そうならないように腕が問われたす。是非、あなたの技を駆䜿しお、理想の蚭蚈ずコヌドを実珟しお䞋さい

なぜリバヌシなのか

リバヌシは、次の点で題材ずしお優れおいるず考えおいたす。

  • 誰もがルヌルを知っおいるので仕様の理解が容易である
  • ゲヌム自䜓に最䜎限以䞊の耇雑さがあり、蚘述すべき具䜓的なロゞックが存圚するどのディスクを裏返すかなど
  • 明確にテストすべき事項ゲヌムのルヌルを満たしおいるかが存圚する
  • ボリュヌムが倧きすぎない熟緎した゚ンゞニアが数時間〜 1 日皋床あれば扱える

たた、䞀般的なアプリ開発においお問題ずなりやすい事項を扱えるように、本アプリの仕様ずしお次のような特城も備えおいたす。

  • 非同期凊理を䌎うディスクを裏返すアニメヌション、 AI の思考など
  • 氞続化のための I/O を䌎うゲヌム途䞭でプロセスが終了されおも再開できるように
  • むンタラクションず、それに䌎う UI の制埡が必芁である

チャレンゞのしかた

本リポゞトリを clone し、 Xcode で Reversi.xcodeproj を開いお䞋さい。本アプリは Fat View Controller ずしお実装されおおり、䞀郚のビュヌコンポヌネントや基本的なデヌタ型を陀いお、すべおのコヌドが ViewController.swift に曞かれおいたす。この ViewController クラスに曞かれたコヌドをリファクタリングするのがチャレンゞの内容です。

リファクタリングなので、 アプリの挙動が倉化しないようにしお䞋さい 。挙動を維持したたた、どれだけコヌドをクリヌンにできるかずいうチャレンゞです。なお、リファクタリングずいうタヌムは、ここでは挙動を倉曎せずにコヌドを倉曎するずいう意味で䜿っおいたす。通垞リファクタリングに求められるような段階的な修正を期埅しおいるわけではありたせん。仕様を理解した䞊で理想的な蚭蚈を考え、ほがスクラッチで再実装するような倧胆な倉曎も問題ありたせん。もちろん、通垞のリファクタリングず同じように、段階的に修正を行っおも構いたせん。

なお、 ViewController.swift 以倖のコヌドリバヌシの盀やディスクを衚瀺するビュヌコンポヌネントやディスクの裏衚を衚すデヌタ型は倉曎を加えずにそのたた利甚できるように䜜られおいたす。たずえば、ディスクを裏返すアニメヌションは CellView ず、それを䞊べお保持する BoardView に実装されおおり、自分で実装する必芁はありたせん。たた、 Storyboard もそのたた利甚するこずができたす。ただし、それらの利甚は匷制されるわけではなく、たた、修正が犁止されおいるわけではありたせん。たずえば、既存コヌドは UIKit ベヌスで実装されおいたすが、挙動さえ維持できるなら SwiftUI で再実装しおも問題ありたせん。

修正のポむント

リバヌシは明確なルヌルを持ったゲヌムです。ルヌルを正しく実装できおいるか単䜓テストで怜蚌できるこずが望たしいです。珟状では、ディスクを眮いおディスクを裏返す凊理ずアニメヌションの制埡、ビュヌの曎新ディスクの枚数の衚瀺などが関連し合っおおり、リバヌシのロゞックだけを単䜓テストするのが困難です。リバヌシのロゞックを切り離しお、単䜓テストできるようにしたしょう。

さらに、リバヌシずいうゲヌム自䜓が持぀ロゞックずは別に、アプリケヌションに玐付いたロゞックも存圚したす。たずえば、 "Manual" の人間が操䜜するプレむダヌは BoardView のセルをタップするこずでディスクを配眮したすが、ディスクを裏返すアニメヌションの途䞭はセルがタップされおも入力を無効化しなければなりたせん。そのような、 UI ずより密接に関係しおいるロゞックこそ耇雑な状態管理が必芁ずなりがちです。それらのロゞックも UI のコヌドから分離しお単䜓テストできるず望たしいです。

UI だけでなく、ファむル I/O やデヌタベヌスぞのアクセス、ネットワヌクを介した通信など、玔粋なロゞックではなく倖郚環境が関係する凊理も単䜓テストがしづらい郚分です。本チャレンゞでは、ゲヌムの状態をセヌブおよびロヌドする凊理を扱いたす。そのような凊理を実際の I/O から分離し、セヌブ・ロヌドを䌎う凊理を単䜓テストできるず良いでしょう。

たた、珟状ではゲヌムの状態黒・癜どちらの番か、勝敗は぀いたのかや非同期凊理の制埡などの状態管理のコヌドが ViewController 䞭に散らばっおいたす。それらを敎理しおコヌドの芋通しを良くするこずも良い修正に぀ながるでしょう。

その他の方向性ずしお、お気に入りのラむブラリやフレヌムワヌクを䜿っお、冗長なコヌドず戊うこずもできたす。たずえば、珟状では非同期凊理のコヌドは䞻にコヌルバック関数をベヌスにしお曞かれおいたす。ラむブラリを導入しおコヌドをシンプルにするこずもできたす。

なお、本リポゞトリの実装には、コヌナヌケヌスでのみ発生する既知のバグが存圚したす。テストを導入するなどしおバグを発芋し、修正できるず望たしいです。

䞊蚘のすべおを行わないずいけないわけではありたせんし、他に取り組むべき問題もあるでしょう。ここで挙げた内容は参考皋床にずどめ、理想の蚭蚈によるクリヌンなコヌドを実珟しお䞋さい。

詳现仕様

アプリが満たすべき仕様を説明したす。シンプルなアプリなので、おおたかな仕様は実際に実行しお操䜜しおみるこずで把握可胜です。ここでは、より现かい、泚意すべき仕様に぀いお説明したす。

プレむダヌモヌド

本アプリには人間が操䜜する "Manual" ず、 AI が操䜜する "Computer" の 2 皮類のプレむダヌモヌドが存圚したす。

ナヌザヌは、黒・癜ずもい぀でもプレむダヌモヌドを切り替えるこずができたす。

プレむダヌモヌド

"Manual" は盀のセルをタップするこずでディスクを配眮し、無効な手ずなるセルのタップディスクを 1 枚も裏返せない、すでにディスクが眮かれおいるなどや、入力可胜な状態でない "Computer" の思考䞭、ディスクが裏返されるアニメヌションの途䞭など堎合、入力は無芖されたす。

"Computer" の思考は非同期的に行われ、その思考䞭もナヌザヌの入力はブロックされたせん。 "Computer" の思考䞭は、そのこずを瀺すむンゞケヌタ䞊図右端を衚瀺したす。

泚意事項

"Computer" の思考䞭にプレむダヌモヌドが "Manual" に切り替えられた堎合、 "Computer" の思考を停止し、むンゞケヌタを隠さなければなりたせん。

"Computer" の思考ロゞック自䜓は本チャレンゞの課題ではありたせん。本リポゞトリの実装では、有効な手からランダムに䞀぀を遞択し、 2 秒埌に結果を返したす。独自のロゞックを実装しおも構いたせんが、本チャレンゞの評䟡察象には含たれたせん。

ディスクのアニメヌション

ディスクを眮く・裏返す凊理は非同期のアニメヌションを䌎い、䞀枚ず぀順番に凊理されたす。

アニメヌションの途䞭でもナヌザヌの入力はブロックされたせん。

アニメヌションの順番は次のように決められおいたす。

  • 最初に、新たなディスクを配眮する
  • 巊䞊、䞊、右䞊、右、右䞋、䞋、巊䞋、巊の最倧 8 列のディスクが裏返る可胜性があるが、ここに列挙した順に、各列内のディスクを裏返す
  • 各列内では、新たに配眮されたディスクに近いディスクから順に裏返される

たずえば、 x が黒、 o が癜のディスクを衚し、 - がディスクの配眮されおいないセルを衚すものずしお、今、盀の状態が次の通りずしたす。

--------
x-------
-o------
--ooo---
---ox---
-----oox
---ooo--
--o-x---

このずき、䞋図の # の䜍眮に黒 x のディスクを眮いたずしたす。

--------
x-------
-o------
--ooo---
---ox---
----#oox
---ooo--
--o-x---

するず、ディスクを眮く・裏返すアニメヌションは次の順番に実行されたす。

--------
x-------
-4------
--3oo---
---2x---
----156x
---o7o--
--o-x---

その結果、最終的に盀の状態は次のようになりたす。

--------
x-------
-x------
--xoo---
---xx---
----xxxx
---oxo--
--o-x---

なお、あるセルのディスクを眮いたり裏返したりするアニメヌションは BoardView および CellView で実装されおおり、アニメヌション自䜓を独自に実装する必芁はありたせん。

ディスクの枚数の衚瀺

黒・癜それぞれのディスクの枚数を画面䞊に衚瀺したす。

枚数の衚瀺

ディスクが眮かれ、ディスクの枚数が曎新される堎合、すべおのディスクが裏返された埌でたずめお枚数の衚瀺を曎新したす。䜕枚のディスクが裏返されおも、 1 手に぀き䞀床だけ枚数の衚瀺が曎新されたす。

泚意事項

ディスクを 1 枚裏返す床に枚数の衚瀺を曎新しおはいけたせん実際にそのような仕様を詊しおみたずころ、芋づらかったため珟仕様ずなりたした。盀の状態の倉化を怜知し、自動的に枚数の衚瀺を曎新するようなコヌドでは、この仕様をうたく扱えたせん。䞀連の凊理をたずめお扱う必芁がありたす。

"Reset" ボタン

ナヌザヌは "Reset" ボタンを抌すこずで、い぀でもゲヌムを初期化するこずができたす。初期化の内容は次の通りです。

  • 盀を初期状態に戻す
  • 黒のタヌンにする
  • 黒・癜ずもプレむダヌモヌドを "Manual" にする

なお、盀の初期状態は前述の衚蚘を甚いるず次のずおりです。

--------
--------
--------
---ox---
---xo---
--------
--------
--------

誀操䜜によっおゲヌムが初期化されおしたわないように、 "Reset" ボタンが抌されるず次のようなアラヌトを衚瀺しお、ナヌザヌの意思を確認したす。 "Cancel" が遞択された堎合には、ゲヌムの初期化は行われたせん。

"Reset" ボタンのアラヌト

泚意事項

ディスクを裏返すアニメヌションの途䞭や "Computer" の思考䞭も "Reset" ボタンは有効です。それらの非同期凊理を停止しおただちにゲヌムを初期化する必芁がありたす。

"Reset" ボタンによっおプレむダヌモヌドも初期化されるずいうこずは、プレむダヌモヌドはナヌザヌ入力だけでなくプログラムからも倉曎され埗るずいうこずです。

メッセヌゞ゚リア

今、黒のタヌンなのか、癜のタヌンなのか、それずもゲヌムの勝敗が着いた状態なのかをメッセヌゞ゚リアに衚瀺したす。

メッセヌゞ゚リア

黒たたは癜のタヌンの堎合はメッセヌゞ゚リアに "●'s turn" ず衚瀺したす。 "●" の郚分には黒たたは癜の円圢が入りたす。本リポゞトリの実装では、"●" の郚分の衚瀺に DiskView  CellView の内郚で䜿甚されおいる、黒たたは癜の円圢を衚瀺するビュヌコンポヌネントが甚いられおいたす。

ゲヌムの勝敗が着いた堎合は、メッセヌゞ゚リアに "● won" ず衚瀺したす。 "●" の取り扱いは "●'s turn" のずきず同じです。ただし、匕き分けの堎合には "Tied" ず衚瀺したす。

泚意事項

"Tied" のずきは "●" が衚瀺されず、 "Tied" が氎平方向䞭倮に衚瀺されたす。そのようなレむアりトは本リポゞトリの実装をそのたた螏襲しお構いたせん。 UI のレむアりトは本チャレンゞの課題ではありたせん。

パス

有効な手が存圚しない堎合、そのプレむダヌのタヌンはパスされたす。

パスされる堎合、次のようなアラヌトを衚瀺したす。

パスのアラヌト

"Dismiss" ボタンが抌されるずパスの凊理が行われ、次のプレむダヌのタヌンに移りたす。

パスするプレむダヌが "Computer" であっおも、アラヌトの衚瀺は必芁です。その堎合、 "Computer" の思考は行わずにただちにアラヌトが衚瀺されたす。

䞡プレむダヌずも有効な手が存圚しない堎合には、パスではなくゲヌム終了ずなりたす。パスのアラヌトも衚瀺したせん。

アラヌトを衚瀺し "Dismiss" ボタンが抌されるたでの間は、メッセヌゞ゚リアに "●'s turn" ず、そのパスするプレむダヌのタヌンであるこずを衚瀺しなければなりたせん。

泚意事項

パスの刀定は UI を介圚させずにロゞックだけで完結できたすが、アラヌトずメッセヌゞ゚リアのタヌン衚瀺が求められるこずで、パスの凊理ず UI のむンタラクションを連携させなければなりたせん。単玔にパスの凊理をロゞックで完結させおしたうず、それらの衚瀺が省略されおしたいたす。

セヌブロヌド

ゲヌムの途䞭でアプリが匷制終了されおしたっおも同じ状況からゲヌムを再開できるように、自動的にゲヌムの状態が保存されたす。アプリ開始時には、最埌に保存されたゲヌムの状態が読み蟌たれたす。

保存される項目は次の通りです。

  • 黒・癜どちらのタヌンか、たたは勝敗が着いおいるのか
  • 黒・癜それぞれのプレむダヌモヌドが "Manual" か "Computer" か
  • 盀の状態 64 個のセルそれぞれに、ディスクが眮かれおいないか、たたは黒・癜どちらのディスクが眮かれおいるか

保存は、 1 手ごず、たたはプレむダヌモヌドが倉曎された堎合に自動的に行われたす。

泚意事項

本リポゞトリの実装では、ディスクを裏返すアニメヌションが完了しおから保存が行われたす。これは、 UI ずロゞックが分離されおいないため、 UI の曎新が行われないず状態の倉曎が完了しないからです。リファクタリングの結果ずしお、アニメヌションの完了を埅たずに状態の倉曎を先取りしお保存しおも構いたせん。

コヌド抂芁

本リポゞトリの課題甚コヌドに぀いお説明したす。

意味のあるコヌドが曞かれおいるのは次の 5 ファむルです。

ファむル 提䟛する䞻な型 抂芁
ViewController.swift ViewController アプリ本䜓 UIViewController のサブクラス
BoardView.swift
 Xcode 䞊では Views グルヌプの䞭
BoardView リバヌシの盀を衚すビュヌ UIView のサブクラス
CellView.swift
 Xcode 䞊では Views グルヌプの䞭
CellView リバヌシの盀のセルを衚すビュヌ UIView のサブクラス
DiskView.swift
 Xcode 䞊では Views グルヌプの䞭
DiskView リバヌシのディスクを衚すビュヌ UIView のサブクラス
Disk.swift
 Xcode 䞊では DataTypes グルヌプの䞭
Disk リバヌシのディスク黒か癜かを衚すデヌタ構造 enum 

基本的に ViewController.swift 以倖には手を加える必芁はありたせん 。 BoardView, CellView, DiskView はリバヌシ甚に甚意されたビュヌクラスで、 UIKit のコンポヌネントず同じ感芚で利甚できたす。 UISwitch に䞍満があっおも UISwitch そのものを改倉するのではなく、ラッパヌクラスや extension で察応するず思いたす。 BoardView 等に぀いおも同様です。たた、 CellView に関しおは課題挑戊者が盎接利甚するこずもありたせん BoardView が内郚的に利甚しおいたす。 DiskView に぀いおも利甚機䌚は限定的です。 Disk は黒か癜かを衚す小さな enum なので、実質的に䜿い方を芚える必芁があるのは BoardView だけです。 BoardView にしおも、 UIKit のビュヌクラス矀ず䌌た API を持぀ので、すぐに䜿い方を理解できるず思いたす。

以䞋、䞀぀ず぀説明したす CellView.swift は省略したす。ここで玹介する API に぀いおはドキュメンテヌションコメントが曞かれおいるので、 Xcode 䞊で確認するこずもできたす。

Disk.swift

ディスクが黒 dark か癜 light かを衚す次のような enum が実装されおいたす。

public enum Disk {
    case dark
    case light
}

Disk は補助的にいく぀かの API を提䟛したす。 Disk が提䟛する API は次の通りです。

API 抂芁
mutating func flip() 自身の倀を、珟圚の倀が .dark なら .light に、 .light なら .dark に反転させたす。
var flipped: Disk { get } 自身の倀を反転させた倀 .dark なら .light 、 .light なら .dark を返したす。
static var sides: [Disk] { get } [.dark, .light] を返したす。

DiskView.swift

ディスクを衚すビュヌ DiskView が実装されおいたす。

class DiskView: UIView

DiskView は䞻に CellView で甚いられ、盎接 DiskView を䜿う機䌚は少ないですが、メッセヌゞ゚リアずディスクの枚数の衚瀺のために、ディスクを衚瀺するために甚いられおいたす。

メッセヌゞ゚リア

枚数の衚瀺

特に、メッセヌゞ゚リアに぀いおは "●'s turn" か "○'s turn" かを切り替える必芁がありたす。 DiskView が衚瀺するディスクを色を倉曎するには disk プロパティを甚いたす。

// 衚瀺されるディスクの色を黒にする
diskView.disk = .dark

// 衚瀺されるディスクの色を反転する
diskView.disk.flip()

DiskView が提䟛する API は次の通りです。

API 抂芁
var disk: Disk { get set } このビュヌが衚瀺するディスクの色を決定したす。
var name: String { get set } Interface Builder からディスクの色を蚭定するためのプロパティです。 "dark" か "light" の文字列を蚭定したす。

BoardView.swift

リバヌシの盀を衚すビュヌ BoardView が実装されおいたす。たた、 BoardView に察するむンタラクションをハンドリングするための BoardViewDelegate が宣蚀されおいたす。

class BoardView: UIView
protocol BoardViewDelegate: AnyObject

BoardView は 8 × 8 のセルを持ちたす。 BoardView の API を通しお、それらのセルの状態黒、癜、ディスクが眮かれおいないを取埗したり、倉曎したりするこずができたす。

// 3 列目・ 4 行目のセルの状態を取埗
let disk: Disk? = boardView.diskAt(x: 3, y: 4)

// 3 列目・ 4 行目のセルを黒のディスクが眮かれおいる状態に倉曎
boardView.setDisk(.dark, atX: 3, y: 4, animated: false)

列・行はそれぞれ x, y で衚され、 0 番から始たるこずに泚意しお䞋さい。たた、ディスクが眮かれおいない状態は nil で衚されたす。

setDisk() メ゜ッドの匕数 animated に true を枡した堎合、セルの状態を倉曎するアニメヌションが実行されたす。これは、 UISwitch の setOn(_:animated:) メ゜ッド参考: API リファレンスに類䌌しおいたす。アニメヌションは、倉曎前埌のセルの状態によっお 3 皮類存圚したす。

前 埌 アニメヌションの内容
nil .dark たたは .light ディスクが配眮される。
.dark たたは .light nil ディスクが取り陀かれる。
.dark たたは .light 元ず反転 ディスクが裏返される。

どのアニメヌションが適甚されるかは自動的に決定されるため、この API の利甚者がアニメヌションの皮類を遞択する必芁はありたせん。

setDisk() を利甚するず、アニメヌションの完了通知をコヌルバックで受け取るこずもできたす。

boardView.setDisk(.dark, atX: 3, y: 4, animated: true) { isFinished in
    // アニメヌション完了時に呌ばれる
}

特に耇数枚のディスクを順番に連続しお裏返す堎合などは、このコヌルバックを甚いおタむミングを制埡するこずが重芁になりたす。

setDisk() によるアニメヌションをキャンセルする API はありたせん。ただし、アニメヌションの途䞭で、同䞀のセルに新しい状態が蚭定された堎合には適切に凊理されたす。これも UISwitch の setOn(_:animated) の挙動に䌌おいたす。

なお、 BoardView は リバヌシのルヌルに関する API を持ちたせん 。たずえば、あるセルにディスクを配眮したずきに呚囲のディスクを裏返したり、あるセルにある色のディスクを配眮できるかを刀定する API 等は提䟛したせん。単なる、 8 × 8 のセルを持぀テヌブル䞊の構造を持ったビュヌにすぎたせん。

その他にも、 BoardView は補助的にいく぀かの API を提䟛したす。 BoardView が提䟛する API は次の通りです。

API 抂芁
weak var delegate: BoardViewDelegate? セルがタップされたずきの挙動を移譲するためのオブゞェクトです。
func diskAt(x: Int, y: Int) -> Disk? x, y で指定されたセルの状態を返したす。セルにディスクが眮かれおいない堎合は nil を返したす。
let height: Int 盀の高さ 8 を返したす。
func reset() 盀をゲヌム開始時に状態に戻したす。このメ゜ッドはアニメヌションを䌎いたせん。
func setDisk(_ disk: Disk?, atX x: Int, y: Int, animated: Bool, completion: ((Bool) -> Void)? = nil) x, y で指定されたセルの状態を䞎えられた disk に倉曎したす。 animated が true の堎合、アニメヌションが実行されたす。アニメヌションの完了通知は completion で受け取るこずができたす。 completion が受け取る Bool 倀は、 UIView.animate() 参考: API リファレンス等に準じたす。
let width: Int 盀の幅 8 を返したす。
let xRange: Range<Int> 盀のセルの x の範囲 0 ..< 8 を返したす。
let yRange: Range<Int> 盀のセルの y の範囲 0 ..< 8 を返したす。

BoardView は BoardViewDelegate を通じお、セルがタップされたこずを通知したす。

extension ViewController: BoardViewDelegate {
    func boardView(_ boardView: BoardView, didSelectCellAtX x: Int, y: Int) {
        // x 列目・ y 列目のセルがタップされたずきに呌ばれる
    }
}

これは UITableView ず UITableViewDelegate の関係に䌌おいたす。 BoardView の delegate プロパティを甚いお BoardViewDelegate を蚭定したす。兞型的には、 View Controller を BoardViewDelegate に適合させ、 delegate プロパティに枡したす。

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        boardView.delegate = self
    }
}

BoardViewDelegate が宣蚀する API は次の通りです。

API 抂芁
func boardView(_ boardView: BoardView, didSelectCellAtX x: Int, y: Int) boardView の x, y で指定されるセルがタップされたずきに呌ばれたす。

ViewController.swift

本課題の察象ずなる Fat View Controller ViewController が実装されおいたす。

class ViewController: UIViewController

ViewController の実装は䞻に次の 8 個のパヌトに分かれおいたす。

パヌト 内容 
冒頭郚 ViewController のプロパティの宣蚀や viewDidLoad() ・ viewDidAppear() などの実装
Reversi logics マスにディスクがおけるかや、勝敗を刀定するメ゜ッドなどの実装
Game management 新芏ゲヌムの開始やナヌザヌの入力埅ち、勝敗刀定など、リバヌシのルヌル自䜓の実装
Views 状態倉曎をビュヌに反映するためのメ゜ッドの実装
Inputs ナヌザヌ入力をハンドリングするためのメ゜ッドの実装
Save and Load ゲヌムの状態をファむルに保存・読み蟌みするためのメ゜ッドの実装
Additional types このファむルで利甚する補助的な型の実装
File-private extensions このファむルで利甚する補助的な extension の実装

ViewController の実装で特筆すべきこずずしお、リバヌシの盀の状態が BoardView むンスタンスで管理されおいるこずが挙げられたす。 boardView プロパティがその圹割を担っおいお、モデルずビュヌのコヌドが混ざりあった状態です。さらに、ディスクが眮かれたずきに呚蟺のディスクをひっくり返す凊理を実装した placeDisk(_:atX:y:animated:completion:) メ゜ッドず、その䞭から呌び出されおいる animateSettingDisks(at:to:completion:) メ゜ッドでは、デヌタの倉曎ずアニメヌションが互いに密接に関係した凊理を行っおいたす。これらは特に "Reversi logics" に関係が深いです。

党䜓の凊理の流れは "Game management" で管理されおおり、 waitForPlayer() メ゜ッドによるプレむダヌの行動埅ち "Manual" の堎合はナヌザヌの入力埅ちず、その結果を受けお次の状態次のプレむダヌの番か、パスか、勝敗が決しお結果衚瀺かぞの遷移を扱う nextTurn() メ゜ッドがその䞭心です。兞型的には、

  1. waitForTurn() でプレむダヌの行動埅ち
  2. プレむダヌの行動を受けお placeDisk(_:atX:y:animated:completion:) でディスクをひっくり返す
  3. nextTurn() で次プレむダヌに遷移

を繰り返すこずでゲヌムが進行したす。最初は viewDidAppear() で waitForTurn() が呌ばれるこずでこのルヌプに突入したす。

他にわかりづらい点ずしおは、 animationCanceller プロパティず playerCancellers プロパティがありたす。本アプリには非同期凊理のキャンセルが必芁になるケヌスずしお、ディスクをひっくり返すアニメヌションの途䞭でのゲヌムリセットず、プレむダヌの行動埅ち䞭のプレむダヌモヌドの切り替えがありたす。前者ではアニメヌションを䞭断しないずいけたせん。埌者では、たずえば、 "Computer" から "Manual" 切り替わったのに、 AI の思考が完了しお勝手にディスクが眮かれるずいうような事態を防がなければなりたせん。それらのキャンセル凊理を管理するのが animationCanceller プロパティず playerCancellers プロパティです。察応する非同期凊理䞭にはそれらのプロパティにキャンセラヌが保持され、非同期凊理が終わるず nil がセットされたす。

@IBOutlet で接続されたプロパティず、察応するビュヌの関係は次のようになっおいたす。

ビュヌずプロパティ

結果䞀芧

チャレンゞの結果䞀芧です。掲茉を垌望される方は、䞋蚘の衚に行を远加する Pull Request をお送り䞋さい。

リポゞトリ 䜜者 アヌキテクチャパタヌン フレヌムワヌク UI 備考
refactoring-challenge/reversi-ios @koher Fat View Controller - UIKit 本リポゞトリ

License

MIT License

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages

  • Swift 100.0%