囲碁AIで有名なモンテカルロ法で円周率を計算できるようなので試してみました。
モンテカルロ法とは、Wikipediaによるとシミュレーションや数値計算を乱数を用いて行う手法の総称とのことです。
実装方法
計算の手順は下の通りです。
- 四角形とそれに内接する円を作成する
- 四角形の中に多数の点を配置する
- 円の内部にある点の数を円の面積だと仮定して円周率を計算する
まずは四角形と内接する円を作成します。
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let v = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200)) v.backgroundColor = UIColor.darkGray view.addSubview(v) let circle = UIView(frame: v.bounds) circle.backgroundColor = UIColor.lightGray circle.layer.cornerRadius = circle.frame.width / 2 v.addSubview(circle) } }
これを実行すると、四角形と円が描画されます。
次は四角形の上に点を配置していきます。
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let v = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200)) v.backgroundColor = UIColor.darkGray view.addSubview(v) let circle = UIView(frame: v.bounds) circle.backgroundColor = UIColor.lightGray circle.layer.cornerRadius = circle.frame.width / 2 v.addSubview(circle) // ここから今回追加 var dots: [UIView] = [] (0...40000).forEach { _ in let x = CGFloat(arc4random_uniform(201)) let y = CGFloat(arc4random_uniform(201)) let dot = UIView(frame: CGRect(x: x, y: y, width: 1, height: 1)) dot.backgroundColor = UIColor.white v.addSubview(dot) dots.append(dot) } } }
実行すると、点が配置されているのが分かります。
次に円の中の点の数を計算します。
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let v = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200)) v.backgroundColor = UIColor.darkGray view.addSubview(v) let circle = UIView(frame: v.bounds) circle.backgroundColor = UIColor.lightGray circle.layer.cornerRadius = circle.frame.width / 2 v.addSubview(circle) var dots: [UIView] = [] (0...40000).forEach { _ in let x = CGFloat(arc4random_uniform(201)) let y = CGFloat(arc4random_uniform(201)) let dot = UIView(frame: CGRect(x: x, y: y, width: 1, height: 1)) dot.backgroundColor = UIColor.white v.addSubview(dot) dots.append(dot) } // ここから今回追加 let count = dots.filter { let dx = $0.frame.origin.x - circle.center.x let dy = $0.frame.origin.y - circle.center.y let radius = circle.frame.size.width / 2 return dx*dx + dy*dy < radius*radius }.count print(count) // → 74 } }
最後に円の中の点(円の面積)を元に円周率を求めます。
結果は、3.1111と3.14に近い数字となりました。
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let v = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200)) v.backgroundColor = UIColor.darkGray view.addSubview(v) let circle = UIView(frame: v.bounds) circle.backgroundColor = UIColor.lightGray circle.layer.cornerRadius = circle.frame.width / 2 v.addSubview(circle) var dots: [UIView] = [] (0...40000).forEach { _ in let x = CGFloat(arc4random_uniform(201)) let y = CGFloat(arc4random_uniform(201)) let dot = UIView(frame: CGRect(x: x, y: y, width: 1, height: 1)) dot.backgroundColor = UIColor.white v.addSubview(dot) dots.append(dot) } let count = dots.filter { let dx = $0.frame.origin.x - circle.center.x let dy = $0.frame.origin.y - circle.center.y let radius = circle.frame.size.width / 2 return dx*dx + dy*dy < radius*radius }.count let radius = circle.frame.size.width / 2 print(CGFloat(count) / radius / radius) // 3.1111 } }