
let x = 3
let y = 3

protocol Printable{
    var symbol: String { get }
}

class Object: Printable{
    let symbol: String
    let isSolid: Bool
    
    init(symbol: String, isSolid: Bool){
        self.symbol = symbol
        self.isSolid = isSolid
    }
    
    static func Rock() -> Object{
        return Object(symbol: "x", isSolid: true)
    }
    
    static func Space() -> Object{
        return Object(symbol: " ", isSolid: false)
    }
    
    static private func object(from: Character) -> Object{
        if from == "x" { return Rock() }
        if from == " " { return Space() }
        fatalError()
    }
    
    static func objects(from: String) -> [Object]{
        var objects: [Object] = []
        for char in from.characters{
            objects.append(object(from: char))
        }
        return objects
    }
}

class Player: Printable{
    let symbol: String = "@"
    
    let x, y: Int
    
    init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
}

class MapLine{
    let objects: [Object]
    
    init(input: String) {
        objects = Object.objects(from: input)
    }
    
    func printLine(player: Player?){
        var line: [Printable] = objects
        if let player = player{
            line[player.x] = player
        }
        let result = line.reduce("") { res, obj in res + obj.symbol }
        print(result)
    }
}

class Map{
    let lines: [MapLine]
    var player: Player!
    
    init(input: String...) {
        var ls: [MapLine] = []
        for line in input{
            ls.append(MapLine(input: line))
        }
        lines = ls
    }
    
    func printMap(){
        for (y, line) in lines.enumerated(){
            line.printLine(player: player.y == y ? player : nil)
        }
    }
    
    private func objectAt(x: Int, y: Int) -> Object?{
        if y < 0 || y >= lines.count { return nil }
        let line = lines[y]
        if x < 0 || x >= line.objects.count { return nil }
        return line.objects[x]
    }
    
    private func printDirection(direction: String, dx: Int, dy: Int){
        let nx = player.x + dx
        let ny = player.y + dy
        guard let object = objectAt(x: nx, y: ny), !object.isSolid else { return }
        print("\(direction): \nlet x = \(nx)\nlet y = \(ny)")
    }
    
    func printOptions(){
        printDirection(direction: "right", dx: 1, dy: 0)
        printDirection(direction: "left", dx: -1, dy: 0)
        printDirection(direction: "up", dx: 0, dy: -1)
        printDirection(direction: "down", dx: 0, dy: 1)
    }
}

let map = Map(input:
    "xxxxxxxxxxxxxx",
    "x          xxx",
    "xx xx   xx  xx",
    "x            x",
    "xxxxxxxxxxxxxx"
)
map.player = Player(x: x, y: y)
map.printMap()
map.printOptions()



