Xcode の自動ビルドのせいで編集できないのだが - How to disable Automatically Refresh Canvas and background build compile

Xcode の自動ビルドというかコンパイルというか。

手動にしたいんですけど。

自動で裏でなんかしら動いて、

エディターを触るのに詰まる感じ。

ロジックをいじるときには非常にストレス。

 

😩 Settings → General → Show live issues OFF

良くわからない。

ON でも OFFでも何がどう変わるのか。

ググるとやたらヒットする。

👉 xcode 9 how to disable auto build … | Apple Developer Forums hatena-bookmark

 

😩 Editor → Canvas → Automatically Refresh Canvas OFF

You can turn off the auto-compile feature for previews/canvas'. When having a SwiftUI View open in the editor go to the Editor -> Canvas -> Automatically Refresh Canvas.

👉 Stop auto compile on Xcode preview - Stack Overflow hatena-bookmark

欲しかったのはこれかな?

ファイルを編集すると、Canvas 上に


「Preview paused 🔃

と表示される。

🔃 を押さないと、自動でビルドは行われない。

これだわ !

 

😩 まとめ

Xcode が裏で動いてコード編集できないときは、


Editor

  ↓

Canvas 

  ↓

Automatically Refresh Canvas OFF

です。

リフレッシュするときのショートカットは、


⌥ (Option) + ⌘ (Command) + P

のようですです。

しかし、そもそも、

編集操作を妨げてまで

デフォルトで自動でリフレッシュする必要なくね?

初心者はつらい。いちいち詰まる。


【 SwiftUI 】 Pong Wars を SwiftUI に移植してみた

見てて飽きないので Xcode Playground で SwiftUI の練習。

ソースは以下2つあればいけるだろう、と雰囲気で。

👉 vnglst/pong-wars hatena-bookmark
👉 vocdex/pong-wars-python: Python version of Pong Wars with Pygame hatena-bookmark

一つのファイルで終わらせたい。

 

🏓 結果




 

🏓 まとめ

Playground では遅すぎですがソースコード。

import Foundation
@Observable final class Pong {
var squares: [Square] = []
var balls: [Ball] = []
var dayCount = 0
var nightCount = 0
var generation = 0
private var cols = 0
private var rows = 0
private var task: Task<Void, Never>?
func create(cols: Int, rows: Int) {
self.cols = cols
self.rows = rows
createSquares()
createBalls()
}
func start() {
task = Task { @MainActor in // *
do {
while true {
balls.forEach { ball in
updateSquares(ball)
ball.checkBoundary(cols, rows)
ball.avoidSpin() // *
ball.next()
}
dayCount = count(day: true)
nightCount = count(day: false)
generation += 1
try await Task.sleep(for: .seconds(.duration))
}
} catch {
if Task.isCancelled {
print("cancelled.")
}
}
}
}
func stop() {
task?.cancel()
}
private func createSquares() {
(0 ..< rows).forEach { _ in
(0 ..< cols).forEach { i in
squares.append(
Square(day: i < cols / 2)
)
}
}
}
private func createBalls() {
balls.append(
Ball(
x: 0,
y: 0,
dx: .size / 2,
dy: .size / 2,
day: false)
)
balls.append(
Ball(
x: Double(cols - 1) * .size,
y: Double(rows - 1) * .size,
dx: -.size / 2,
dy: -.size / 2,
day: true
)
)
}
private func updateSquares(_ ball: Ball) {
for angle in stride(from: 0, to: Double.pi * 2, by: Double.pi / 4) {
let cos = cos(angle)
let sin = sin(angle)
let checkX = ball.x + cos * .size / 2
let checkY = ball.y + sin * .size / 2
let i = Int(floor(checkX / .size))
let j = Int(floor(checkY / .size))
if (0 ..< cols).contains(i) && (0 ..< rows).contains(j) {
let index = cols * j + i
if squares[index].day == ball.day {
squares[index].day.toggle()
if abs(cos) > abs(sin) {
ball.dx *= -1
}
if abs(cos) < abs(sin) {
ball.dy *= -1
}
}
}
}
}
func count(day: Bool) -> Int {
return squares.compactMap { $0.day }.filter { $0 == day }.count
}
}
@Observable final class Square {
var day: Bool
init(day: Bool) {
self.day = day
}
}
@Observable final class Ball: Identifiable {
var x: Double
var y: Double
var dx: Double
var dy: Double
var day: Bool
var queue: [Double] = []
init(x: Double, y: Double, dx: Double, dy: Double, day: Bool) {
self.x = x
self.y = y
self.dx = dx
self.dy = dy
self.day = day
}
}
extension Ball {
func next() {
x += dx
y += dy
}
func checkBoundary(_ cols: Int, _ rows: Int) {
if !(0...Double(cols - 1) * .size).contains(x + dx) {
dx *= -1
}
if !(0...Double(rows - 1) * .size).contains(y + dy) {
dy *= -1
}
}
func avoidSpin() {
queue.append(x)
if queue.count > 25 { // recent 25 values
queue.removeFirst()
if (queue.max()! - queue.min()! <= .size) {
print(day, x, y, dx, dy, queue)
if day {
dx *= -1
} else {
dy *= -1
}
queue.removeAll()
}
}
}
}
import Foundation
import SwiftUI
struct PongWars: View {
private var pong = Pong()
var body: some View {
VStack(spacing: 0) {
PongLayout(pong: pong)
VStack {
Text("day \(pong.dayCount) | night \(pong.nightCount)").font(.headline)
Text("generation \(pong.generation)").font(.headline)
}
.padding()
}
}
}
struct PongLayout: View {
var pong: Pong
@State private var on = false
var body: some View {
GeometryReader { gp in
ZStack {
ForEach(pong.squares.indices, id: \.self) { index in
SquareView(index: index, cols: gp.cols, day: pong.squares[index].day)
}
ForEach(pong.balls) { ball in
BallView(ball: ball)
}
}
.frame(width: Double(gp.cols) * .size, height: Double(gp.rows) * .size)
.frame(width: gp.width, height: gp.height, alignment: .center)
.onAppear {
pong.create(cols: gp.cols, rows: gp.rows)
}
.onTapGesture {
on.toggle()
if on {
pong.start()
} else {
pong.stop()
}
}
}
}
}
struct SquareView: View {
private var i: Int
private var j: Int
private var color: Color
init(index: Int, cols: Int, day: Bool) {
self.i = index % cols
self.j = index / cols
self.color = day ? .day : .night
}
var body: some View {
color
.frame(width: CGFloat(.size), height: CGFloat(.size))
.position(x: Double(i) * .size + .size / 2, y: Double(j) * .size + .size / 2)
}
}
struct BallView: View {
var ball: Ball
var body: some View {
Circle()
.fill(ball.day ? Color.day : Color.night)
.frame(width: CGFloat(.size))
.position(x: ball.x + .size / 2, y: ball.y + .size / 2)
}
}
extension GeometryProxy {
var width: CGFloat { size.width }
var height: CGFloat { size.height }
var cols: Int { Int(width / .size) }
var rows: Int { Int(height / .size) }
}
extension Double {
static let size = 25.0
static let duration = 0.001
}
extension Color {
static let day = Color(red: 217 / 256, green: 231 / 256, blue: 226 / 256)
static let night = Color(red: 15 / 256, green: 75 / 256, blue: 89 / 256)
}
#Preview {
PongWars()
}

テストプロジェクトなどで Preview や Simulator でみると、

まあ、スピードもそれなりで上の動画の雰囲気でした。

Gist のコードはあれこれ更新されていきます。いってます。

どうぞよろしくお願います。

 

🏓 追記

4100ループ付近で。

残念 !

計算と描画ははっきり区別しないと痛い目に遭いそうな感じ。

→ 修正しました。

→ 2024-02-07 衝突時のロジックを確認、更新しました。


【Swift】2次元配列 で 転置行列 ( transpose matrix )

これやりたくなるときありますよね。

転置行列(てんちぎょうれつ、英: transpose [of a matrix], transposed matrix)とは、m 行 n 列の行列 A に対して A の (i, j) 要素と (j, i) 要素を入れ替えてできる n 行 m 列の行列のことである。転置行列は tA, AT, A⊤, Atr, A′ などと示される。行列の転置行列を与える操作のことを転置(てんち、英: transpose)といい、「A を転置する」などと表現する

👉 転置行列 - Wikipedia hatena-bookmark

これを、変換すると、


[
  [1, 2, 3, 4, 5], 
  ["A", "B", "C", "D", "E"],
  ["あ", "い", "う", "え", "お"],
  ["か", "き", "く", "け", "こ"]
]

こうなるやつ。


[
  [1, "A", "あ", "か"],
  [2, "B", "い", "き"],
  [3, "C", "う", "く"],
  [4, "D", "え", "け"],
  [5, "E", "お", "こ"]
]

Swift で、extension で、やってみます。

 

🔄 配列系のプロトコルは多すぎないか

Xcode の反応をみながら、とりあえずいけた。

縦横インデックスを

きれいに .indecies で取りたかったけど、

うまく取れなかった。


extension Collection where Element: Collection,
                           Self.Index == Int, Element.Index == Int {

  func transposed1() -> [[Element.Element]] {
    let cols = 0 ..< (self.first?.count ?? 0)
    let rows = 0 ..< self.count
    var result: [[Element.Element]] = []
    for col in cols {
      var newRow: [Element.Element] = []
      for row in rows {
        newRow.append(self[row][col])
      }
      result.append(newRow)
    }
    return result
  }

}

// [[1, "A", "あ", "か"], [2, "B", "い", "き"], [3, "C", "う", "く"], [4, "D", "え", "け"], [5, "E", "お", "こ"]]

Array とか Collection。

where 句 や Element。

書きながらでないと、きっと理解できない感じがする。

👉 Collection | Apple Developer Documentation hatena-bookmark

 

🔄 for ループ を map に

「空配列を作成して要素追加」てのがなんとなくだるいので、

map を使います。

入れ子なので「$0」は使いません。


func transposed2() -> [[Element.Element]] {
  let cols = 0 ..< (self.first?.count ?? 0)
  let rows = 0 ..< self.count
  return cols.map { col in
    rows.map { row in
      self[row][col]
    }
  }
}

すぐに、return から始めたいので、

最初の let を省略。


func transposed3() -> [[Element.Element]] {
  return (0 ..< (first?.count ?? 0)).map { col in
    (0 ..< count).map { row in
      self[row][col]
    }
  }
}

ここまででいいか。

 

🔄 まとめ

まとめておきます。

extension Collection where Element: Collection,
Self.Index == Int, Element.Index == Int {
func transposed1() -> [[Element.Element]] {
let cols = 0 ..< (self.first?.count ?? 0)
let rows = 0 ..< self.count
var result: [[Element.Element]] = []
for col in cols {
var newRow: [Element.Element] = []
for row in rows {
newRow.append(self[row][col])
}
result.append(newRow)
}
return result
}
func transposed2() -> [[Element.Element]] {
let cols = 0 ..< (self.first?.count ?? 0)
let rows = 0 ..< self.count
return cols.map { col in
rows.map { row in
self[row][col]
}
}
}
func transposed3() -> [[Element.Element]] {
return (0 ..< (first?.count ?? 0)).map { col in
(0 ..< count).map { row in
self[row][col]
}
}
}
}
let d = [
[ 1, 2, 3, 4, 5],
["A", "B", "C", "D", "E"],
["あ", "い", "う", "え", "お"],
["か", "き", "く", "け", "こ"]
]
print(d)
print(d.transposed1())
print(d.transposed2())
print(d.transposed3())
// [[1, 2, 3, 4, 5], ["A", "B", "C", "D", "E"], ["あ", "い", "う", "え", "お"], ["か", "き", "く", "け", "こ"]]
// [[1, "A", "あ", "か"], [2, "B", "い", "き"], [3, "C", "う", "く"], [4, "D", "え", "け"], [5, "E", "お", "こ"]]
// [[1, "A", "あ", "か"], [2, "B", "い", "き"], [3, "C", "う", "く"], [4, "D", "え", "け"], [5, "E", "お", "こ"]]
// [[1, "A", "あ", "か"], [2, "B", "い", "き"], [3, "C", "う", "く"], [4, "D", "え", "け"], [5, "E", "お", "こ"]]

また、勉強したら更新します。

Swift の「プロトコル」ってなんか高級。

👉 あなたの知らないCollectionの世界 #Swift - Qiita hatena-bookmark