Triples / assign3 / TileModel.swift
TileModel.swift
Raw
//
//  TileModel.swift
//  assign3
//
//  Created by Jason Kim on 4/7/22.
//


import Foundation

struct Tile: Equatable {
    var val : Int
    var id : Int
    var row: Int    // recommended
    var col: Int    // recommended
}

struct Score: Hashable {
    var score: Int
    var time: Date
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(time)
    }
    
    init(score: Int, time: Date) {
        self.score = score
        self.time = time
    }
}

enum Tdirection { //find how to make an enum
    case left
    case right
    case up
    case down
}

class TTriples: ObservableObject {
    @Published var board: [[Tile?]] = []
    @Published var score: Int = 0
    var seededGenerator: SeededGenerator
    var tile = Tile(val: 0, id: 0, row: 0, col: 0)
    @Published var scores:[Score] = [Score(score: 300, time: Date.now), Score(score: 400, time: Date.now)]

    init(){
        board = [[Tile(val: 0, id: 0, row: 0, col: 0), Tile(val: 0, id: 1, row: 0, col: 1), Tile(val: 0, id: 2, row: 0, col: 2), Tile(val: 0, id: 3, row: 0, col: 3)],
                         [Tile(val: 0, id: 4, row: 1, col: 0), Tile(val: 0, id: 5, row: 1, col: 1), Tile(val: 0, id: 6, row: 1, col: 2),Tile(val: 0, id: 7, row: 1, col: 3)],
                         [Tile(val: 0, id: 8, row: 2, col: 0), Tile(val: 0, id: 9, row: 2, col: 1), Tile(val: 0, id: 10, row: 2, col: 2), Tile(val: 0, id: 11, row: 2, col: 3)],
                         [Tile(val: 0, id: 12, row: 3, col: 0),Tile(val: 0, id: 13, row: 3, col: 1),Tile(val: 0, id: 14, row: 3, col: 2), Tile(val: 0, id: 15, row: 3, col: 3) ]]
                
        seededGenerator = SeededGenerator(seed: 14)
        score = 0
    }
    
    func newgame(rand: Bool){
        if rand{ //randomized
            for i in 0..<board.count{
                for j in 0..<board.count{
                    board[i][j]?.val = 0
                }
            }
            score = 0
            seededGenerator = SeededGenerator(seed: UInt64(Int.random(in:1...1000)))
        } else { //deterministic
            for i in 0..<board.count{
                for j in 0..<board.count{
                    board[i][j]?.val = 0
                }
            }
            score = 0
            seededGenerator = SeededGenerator(seed: 14)
        }
    }
    
    func spawn() {
        let newval = Int.random(in: 1...2, using: &seededGenerator)
        var open: [[Int]] = []
        let len = board.count
        for row in 0..<len{
            for col in 0..<len{
                if board[row][col]?.val == 0 {
                    open.append([row, col])
                }
            }
        }
        
        if open.count != 0{
            //board is not full
            let loc:Int = Int.random(in: 0..<open.count, using: &seededGenerator) //randomly choose which idx to spawn
            let row = open[loc][0]
            let col = open[loc][1]
            board[row][col]?.val = newval
            score += newval
        } else {
            //board is full
        }
    }
    
    func rotate() {
        board = Trotate2DInts(input: board)
    } // rotate a square 2D Int array clockwise
    
    func shift() {
        let n = board.count
        for row in 0..<n {
            for cell in 0..<n - 1 {
                if board[row][cell]?.val == 0{ //if cell is 0
                    for cell2 in cell..<n - 1{
                            board[row][cell2] = board[row][cell2 + 1] //shift them up by one
                        }
                    board[row][n-1]?.val = 0 //insert 0 at the end
                    break
                } else if board[row][cell]?.val == 1 || board[row][cell]?.val == 2 {
                    if board[row][cell+1]?.val == 1 || board[row][cell+1]?.val == 2{
                        if board[row][cell+1]?.val == 2 && board[row][cell]?.val == 1{
                            board[row][cell]?.val = 3
                            let id = board[row][cell]?.id
                            score += 3
                            for cell3 in cell+1..<n - 1{
                                board[row][cell3] = board[row][cell3 + 1]
                               // board[row][cell3 + 1]?.id = ((board[row][cell3 + 1]?.id ?? 0) - 1)
                            }
                            board[row][n-1]?.val = 0 //insert 0 at the end
                            board[row][n-1]?.id = id ?? 0
                            break
                        } else if board[row][cell+1]?.val == 1 && board[row][cell]?.val == 2{
                            board[row][cell]?.val = 3
                            let id = board[row][cell]?.id
                            score += 3
                            for cell3 in cell+1..<n - 1{
                                board[row][cell3] = board[row][cell3 + 1]
                              //  board[row][cell3 + 1]?.id = ((board[row][cell3 + 1]?.id ?? 0) - 1)
                            }
                            board[row][n-1]?.val = 0 //insert 0 at the end
                            board[row][n-1]?.id = id ?? 0
                            break
                        }
                    }
                } else {
                    if board[row][cell]?.val == board[row][cell + 1]?.val { //if number in the cell is >= 3 and the next number == curr
                        board[row][cell]?.val = (board[row][cell]?.val ?? 0) * 2 //add them
                        score += board[row][cell]?.val ?? 0
                        let id = board[row][cell]?.id
                        for cell4 in cell+1..<n - 1{
                            board[row][cell4] = board[row][cell4 + 1] //pull the rest of the board by 1
                           // board[row][cell4 + 1]?.id = ((board[row][cell4 + 1]?.id ?? 0) - 1)
                        }
                        board[row][n-1]?.val = 0 //insert 0 at the end
                        board[row][n-1]?.id = id ?? 0
                        break
                    }
                }
            }
        }
    } // collapse to the left
    
    //this func returns true if it moved
    func collapse(dir: Tdirection) -> Bool {
        let copy = TTriples()
        copy.board = self.board
        
        if dir == Tdirection.left {
            self.shift()
            if copy.board == self.board {
                return false
            } else {
                return true
            }
        } else if dir == Tdirection.right {
            self.rotate()
            self.rotate()
            self.shift()
            self.rotate()
            self.rotate()
            if copy.board == self.board {
                return false
            } else {
                return true
            }
        } else if dir == Tdirection.up {
            self.rotate()
            self.rotate()
            self.rotate()
            self.shift()
            self.rotate()
            if copy.board == self.board {
                return false
            } else {
                return true
            }
        } else {
            self.rotate()
            self.shift()
            self.rotate()
            self.rotate()
            self.rotate()
            if copy.board == self.board {
                return false
            } else {
                return true
            }
        }
    }// collapse in specified direction using shift() and rotate()
} //end of class Triples

// class-less function that will return of any square 2D Int array rotated clockwise
func Trotate2DInts(input: [[Tile?]]) -> [[Tile?]] {
    let n = input.count
    let tile = Tile(val: 0, id: 0, row: 0, col: 0)
    var newArr:[[Tile?]] = Array(repeating: Array(repeating: tile, count: n), count: n)
    for i in 0..<input.count {
        for j in 0..<input[0].count{
            let newRow = j+n % n
            let newCol = (n-1)-i;
            newArr[newRow][newCol] = input[i][j]
        }
    }
    return newArr
}




/*
func Trotate2D<T> (input: [[T]]) -> [[T]] {
    let n = 4
    var newArr = input
    for i in 0..<n {
        for j in 0..<input[0].count{
            let newRow = j+n % n
            let newCol = (n-1)-i;
            newArr[newRow][newCol] = input[i][j]
            newArr[newRow][newCol]?.id = ((newRow * 4) + newCol)
        }
    }
    return newArr
}

*/