9.4 C
London
Wednesday, April 24, 2024

ios – Weak var in Swift Tree implementation


I’m making an attempt to construct a tree implementation in Swift to characterize a chess sport.

A sport consists of a sequence of strikes however various strikes for a given board place are legitimate. I need to traverse the tree in my GUI which is why I added strategies to go to a particular node within the tree.

Nevertheless I’m combating getting the reminiscence mannequin proper. For my activity I need to hold a reference to the subsequent node and its dad or mum node for a given node. In my understanding these must be weak with a purpose to not introduce retain cycles. Nevertheless in doing so my implementation falls aside (as a result of I assume i don’t maintain a reference to the given node?).

Can any individual enlighten me on find out how to change my current implementation to make this work accurately? Once I take away the weak key phrase my take a look at succeeds nonetheless I don’t suppose that is proper as a result of once more due to potential retain cycles.

I eliminated a number of the implementation to make this extra readable:

import Basis

/// GameNode represents a node of a chess sport tree
public remaining class GameNode {
    
    // MARK: - Properties
    
    /// The place of the node
    public let place: Place
    
    /// Uniquely identifies a node
    public let nodeId: UUID
    
    /// Is the node on the prime of the tree
    public let isTopNode: Bool
    
    /// The chess transfer that will get from the dad or mum node to this one
    public let transfer: Transfer?
    
    /// An elective transfer annotation like !!, !?, ??
    public let annotation: String?
    
    /// A remark for the transfer
    public let remark: String?
    
    /// The dad or mum node
    public inside(set) weak var dad or mum: GameNode?
    
    /// Pointer to the principle variation
    public inside(set) weak var subsequent: GameNode?
    
    /// Different potential variations from this node
    public inside(set) var variations: [GameNode]
    
    // MARK: - Init
    
    /// Creates a root node
    public init(place: Place = .preliminary, remark: String? = nil) {
        self.place = place
        self.nodeId = UUID()
        self.isTopNode = true
        self.transfer = nil
        self.annotation = nil
        self.dad or mum = nil
        self.remark = remark
        self.subsequent = nil
        self.variations = []
    }
    
    /// Creates a node which is the results of making a transfer in one other node
    public init(place: Place, transfer: Transfer, dad or mum: GameNode, annotation: String? = nil, remark: String? = nil) {
        self.place = place
        self.nodeId = UUID()
        self.isTopNode = false
        self.transfer = transfer
        self.annotation = annotation
        self.dad or mum = dad or mum
        self.remark = remark
        self.subsequent = nil
        self.variations = []
    }
    
    /// Reconstructs the transfer sequence from the beginning of the sport so far
    public func reconstructMovesFromBeginning() -> [Move] {
        if dad or mum?.isTopNode == true {
            return [move].compactMap({ $0 })
        }
        
        var strikes = dad or mum?.reconstructMovesFromBeginning() ?? []
        if let transfer {
            strikes.append(transfer)
        }
        
        return strikes
    }
}

public remaining class Sport {
    public non-public(set) var present: GameNode
    
    public init(root: GameNode = GameNode()) {
        self.present = root
    }

    var root: GameNode? {
        var tmp: GameNode? = present
        whereas let currentTmp = tmp, !currentTmp.isTopNode {
            tmp = currentTmp.dad or mum
        }
        return tmp
    }
    
    public var isAtEnd: Bool {
        present.subsequent == nil
    }
    
    public func goBackward() {
        guard let dad or mum = present.dad or mum else { return }
        self.present = dad or mum
    }
    
    public func go(to node: GameNode) {
        self.present = node
    }
    
    public func play(transfer: Transfer, remark: String? = nil, annotation: String? = nil) throws {
        let newPosition = strive present.place.play(transfer: transfer)
        let newNode = GameNode(place: newPosition, transfer: transfer, dad or mum: present, annotation: annotation, remark: remark)
        
        if !isAtEnd {
            present.subsequent?.variations.append(newNode)
        } else {
            present.subsequent = newNode
        }
        
        go(to: newNode)
    }
    
    public var uciPath: [String] {
        present.reconstructMovesFromBeginning().map(.uci)
    }
}

And the take a look at:

func testGameToUCIPath() throws {
    let sport = strive Sport(fen: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")
    strive sport.play(transfer: .init(from: Squares.e2, to: Squares.e4))
    strive sport.play(transfer: .init(from: Squares.e7, to: Squares.e5))
    strive sport.play(transfer: .init(from: Squares.g1, to: Squares.f3))
    strive sport.play(transfer: .init(from: Squares.b8, to: Squares.c6))
    strive sport.play(transfer: .init(from: Squares.f1, to: Squares.b5))
    XCTAssertEqual(sport.uciPath, ["e2e4", "e7e5", "g1f3", "b8c6", "f1b5"])

    sport.goBackward()
    XCTAssertEqual(sport.uciPath, ["e2e4", "e7e5", "g1f3", "b8c6"])
    strive sport.play(transfer: .init(from: Squares.f1, to: Squares.c4))
    XCTAssertEqual(sport.uciPath, ["e2e4", "e7e5", "g1f3", "b8c6", "f1c4"])
}

Latest news
Related news

LEAVE A REPLY

Please enter your comment!
Please enter your name here