Playground

В файле Lines.swift создаем (описание функции dropBall в Playground)

struct Lines {
    var cells = Array(repeating: Array(repeating: 0, count:9), count: 9)
    var test = Array(repeating: Array(repeating: -1, count:11), count: 11)
    mutating func dropBall(row: Int, column: Int, color: Int) -> Int {
        var c = [-1,  0,  1, 1, 1, 0, -1, -1]
        var r = [-1, -1, -1, 0, 1, 1,  1,  0]
        var n = [0, 0, 0, 0, 0, 0, 0, 0]
        var total = 0
        for i in 0..<9 {
            for j in 0..<9 {
                test[i+1][j+1] = cells[i][j]
            }
        }
        for i in 0..<8 {
            while test[(row + 1) + r[i] * (n[i] + 1)][(column + 1) + c[i] * (n[i] + 1)] == color {
                n[i] += 1
            }
        }
        for i in 0..<4 {
            if n[i] + n[i+4] < 4 {
                n[i] = 0
                n[i+4] = 0
            } else {
                total += n[i] + n[i+4]
            }
        }
        if total > 0 {
            total += 1
            for i in 0..<8 {
                for j in 0..<n[i] {
                    cells[row + (1 + j) * r[i]][column + (1 + j) * c[i]] = 2
                }
            }
            cells[row][column] = 2
        } else {
            cells[row][column] = color
        }
        return total
    }
}

В файле ViewController.swift

добавляем переменную lines и изменяем код tapGameField

    var lines = Lines()
...        
        _ = lines.dropBall(row: row, column: column, color: 1)
        gameFieldView.cells = lines.cells

Запускаем, расставляем шарики для проверки и последний ставим:

Убираем из кода строчку cells[row][column] = 2 и меняем 2 на 0 в строке: cells[row + (1 + j) * r[i]][column + (1 + j) * c[i]] = 2

struct Balls {
    var row: Int
    var column: Int
    var color: Int
}

func makeWays

А теперь про зайцев….

За один ход игрок может передвинуть один шарик, выделив его и указав его новое местоположение. Для совершения хода необходимо, чтобы между начальной и конечной клетками существовал путь из свободных клеток.

Предположим, что нам захотелось переместить зайца

Заяц, как ладья на шахматной доске, может двигаться либо по вертикали, либо по горизонтали. За один шаг он может переместиться на соседнюю клетку. Предположим, что у нас есть фишки, с числами. Разложим фишки с цифрой 1 на соседние с зайцем клетки, получим все клетки, на которые можно переместить зайца за один шаг. Разложим фишки с цифрой 2 на оставшиеся пустые клетки (не занятые ни фишками, ни фигурками) на которые можно переместиться с клетки с фишкой 1 за один шаг. Продолжая раскладывать фишки таким образом, мы закроем все пустые клетки в которые существует путь из клетки с зайцем. В оставшиеся свободные клетки переместиться нельзя, так путь к ним прегражден фигурками. В итоге мы получили алгоритм, по которому на этапе выбора фигурки для перемещения, мы уже сможем определить на какую клетку можно переместиться и за сколько ходов, а на какую нельзя.


    var selectedBall = Balls(row: 0, column: 0, color: 0)
    
    mutating func makeWays(row: Int, column: Int) {
        selectedBall.row = row
        selectedBall.column = column
        selectedBall.color = cells[row][column]
        for i in 0..<9 {
            for j in 0..<9 {
                test[i+1][j+1] = (cells[i][j] == 0) ? -2 : -1
            }
        }
        test[row+1][column+1] = 0
        var k = 0
        var flag = false
        repeat {
            flag = false
            for i in 1..<10 {
                for j in 1..<10 {
                    if test[i][j] == -2 {
                        if  (test[i-1][j] == k) ||
                            (test[i][j-1] == k) ||
                            (test[i+1][j] == k) ||
                            (test[i][j+1] == k) {
                            
                            test[i][j] = k + 1
                            flag = true
                        }
                    }
                }
            }
            if flag {
                k += 1
            }
        } while flag
    }

в файле ViewController:

    var ballSelected = false
    
    @IBAction func tapGameField(_ sender: UITapGestureRecognizer) {
        let point = sender.location(in: gameFieldView)
        let column = Int(point.x/(gameFieldView.frame.width/9))
        let row = Int(point.y/(gameFieldView.frame.height/9))
        var line = 0
        if ballSelected {
            switch lines.test[row + 1][column + 1] {
            case 0:
                //Передумал
                ballSelected = false
                gameFieldView.cells[row][column] = 1
                gameFieldView.setNeedsDisplay()
            case -1:
                //Выбрал другой шарик
                gameFieldView.cells[lines.selectedBall.row][lines.selectedBall.column] = 1
                lines.makeWays(row: row, column: column)
                gameFieldView.cells[row][column] = 7
                gameFieldView.setNeedsDisplay()
            case -2:
                //Хода нет
                print("Хода нет")
            default:
                //Перейти на новую клетку
                ballSelected = false
                lines.cells[lines.selectedBall.row][lines.selectedBall.column] = 0
                line = lines.dropBall(row: row, column: column, color: lines.selectedBall.color)
                if line > 4 {
                    print("Вау! Супер! \(line)")
                } else {
                    //Выбросить три случайных шарика
                }
                gameFieldView.cells = lines.cells
                gameFieldView.setNeedsDisplay()
            }
        } else {
            if lines.cells[row][column] > 0 {
                ballSelected = true
                lines.makeWays(row: row, column: column)
                gameFieldView.cells[row][column] = 7
                gameFieldView.setNeedsDisplay()
            } else {
                line = lines.dropBall(row: row, column: column, color: 1)
                if line > 4 {
                    print("\(line)")
                }
                gameFieldView.cells = lines.cells
                gameFieldView.setNeedsDisplay()
            }
        }
    }

проверяем


makeNextBalls }

var colorsInGame = 5
var nextBalls = [Balls]()

func makeNextBalls(count: Int) {
    var emptyCells = [Balls]()
    for i in 0..<9 {
        for j in 0..<9 {
            if cells[i][j]==0 {
                emptyCells.append(Balls(row: i, column: j, color: Int(arc4random()) % colorsInGame + 1))
            }
        }
    }
    if !nextBalls.isEmpty {
        nextBalls.removeAll()
    }
    for _ in 0..<count {
        if !emptyCells.isEmpty {
            nextBalls.append(emptyCells.remove(at: Int(arc4random()) % emptyCells.count))
        }
    }
}

func dropThreeBalls() {
    var c = 0
    for _ in 0..<3 {
        if !nextBalls.isEmpty {
            if cells[nextBalls[0].row][nextBalls[0].column] > 0 {
                c = nextBalls[0].color
            } else {
                _ = dropBall(row: nextBalls[0].row, column: nextBalls[0].column, color: nextBalls[0].color)
            }
            nextBalls.remove(at: 0)
        } else {
            makeNextBalls(count: 3)
            if !nextBalls.isEmpty {
                _ = dropBall(row: nextBalls[0].row, column: nextBalls[0].column, color: nextBalls[0].color)
                nextBalls.remove(at: 0)
            }
        }
    }
    makeNextBalls(count: 3)
    if (c > 0) && (!nextBalls.isEmpty) {
        _ = dropBall(row: nextBalls[0].row, column: nextBalls[0].column, color: c)
        nextBalls.remove(at: 0)
        makeNextBalls(count: 3)
    }
}

var ballsInGame = 7
func newGame() {
    for i in 0..<9 {
        for j in 0..<9 {
            cells[i][j] = 0
        }
    }
    makeNextBalls(count: ballsInGame)
    for _ in 0..<ballsInGame {
        
        if !nextBalls.isEmpty {
            _ = dropBall(row: nextBalls[0].row, column: nextBalls[0].column, color: nextBalls[0].color)
            nextBalls.remove(at: 0)
        }
    }
    makeNextBalls(count: 3)
}
class ViewController: UIViewController {

    @IBOutlet weak var gameFieldView: GameFieldView!
    var lines = Lines()
    var ballSelected = false
    var score = 0
    var highScore = 100

    @IBAction func tapGameField(_ sender: UITapGestureRecognizer) {
        let point = sender.location(in: gameFieldView)
        let column = Int(point.x/(gameFieldView.frame.width/9))
        let row = Int(point.y/(gameFieldView.frame.height/9))
        var line = 0
        if ballSelected {
            switch lines.test[row + 1][column + 1] {
            case 0:
                //Передумал
                ballSelected = false
            case -1:
                //Выбрал другой шарик
                lines.makeWays(row: row, column: column)
            case -2:
                //Хода нет
                print("Хода нет")
            default:
                //Перейти на новую клетку
                ballSelected = false
                lines.cells[lines.selectedBall.row][lines.selectedBall.column] = 0
                line = lines.dropBall(row: row, column: column, color: lines.selectedBall.color)
                if line > 4 {
                    score += 2 * line
                } else {
                    lines.dropThreeBalls()
                    if lines.nextBalls.isEmpty {
                        print("Game Over")
                    }
                }
                gameFieldView.cells = lines.cells
                gameFieldView.setNeedsDisplay()
            }
        } else {
            if lines.cells[row][column] > 0 {
                ballSelected = true
                lines.makeWays(row: row, column: column)
            } else {
                //пустая клетка
            }
        }
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        lines.newGame()
        gameFieldView.cells = lines.cells
        gameFieldView.setNeedsDisplay()
    }
}


Запускаем Xcode и нажимаем Get started with a playground 

Выбираем шаблон Blank

Даем название Lines и сохраняем

создадим массив cells

индексация в массивах с нуля

Давайте посчитаем сколько единиц находится справа от cells[0]

 

изменим

перепишем условие

Для того чтоб посчитать количество единиц правее cells[0] мы к нулю прибавляли сначала 1, потом 2 до тех пор, пока выполнялось условие. А как нам посчитать число единиц левее cells[7]? Заменим 0 на 7, 1 на (-1)

перепишем

изменим массив cells

Мы вышли за пределы допустимого диапазона. А почему раньше такого не было? Раньше на преграждало выход за пределы число 0. А что если добавить по одному элементу в начале и конце, которые будут преграждать выход за пределы?

Теперь мы можем смело считать не беспокоясь за выход за пределы.

Перейдем на двухмерные массивы

в каждой отдельной строчке мы можем посчитать число единиц. В игре нам понадобится считать шарики и справа и слева и сверху и снизу и по дагонали

Всего получается в восьми направлениях

Переделаем:

Теперь мы можем считать единицы в любых направлениях, к примеру посчитаем от cells[4][4] по диагонали влево вверх.

row = 4, column = 4, r = -1, c = -1

Мы можем посчитать в любом направлении от любого шарика соответствующим образом меняя значения r и с, всего 8 направлений, перепишем наш код следующим образом,

Посчитаем сразу во всех направлениях

посчитаем сколько шариков удалять

обнулим найденные единицы

И оформим виде функции dropBall

var cells = [[1, 1, 1, 1, 1, 1, 1, 0, 0],
             [1, 1, 1, 1, 1, 1, 1, 0, 0],
             [1, 1, 1, 1, 1, 1, 1, 0, 0],
             [1, 1, 1, 1, 1, 1, 1, 0, 0],
             [1, 1, 1, 1, 1, 1, 1, 0, 0],
             [1, 1, 1, 1, 1, 1, 1, 0, 0],
             [1, 1, 1, 1, 1, 1, 1, 0, 0],
             [1, 1, 1, 1, 1, 1, 1, 0, 0],
             [1, 1, 1, 1, 1, 1, 1, 0, 0]]
var test = Array(repeating: Array(repeating: -1, count:11), count: 11)
func dropBall(row: Int, column: Int, color: Int) -> Int {
    var c = [-1,  0,  1, 1, 1, 0, -1, -1]
    var r = [-1, -1, -1, 0, 1, 1,  1,  0]
    var n = [0, 0, 0, 0, 0, 0, 0, 0]
    var total = 0
    for i in 0..<9 {
        for j in 0..<9 {
            test[i+1][j+1] = cells[i][j]
        }
    }
    for i in 0..<8 {
        while test[(row + 1) + r[i] * (n[i] + 1)][(column + 1) + c[i] * (n[i] + 1)] == color {
            n[i] += 1
        }
    }
    for i in 0..<4 {
        if n[i] + n[i+4] < 4 {
            n[i] = 0
            n[i+4] = 0
        } else {
            total += n[i] + n[i+4]
        }
    }
    if total > 0 {
        total += 1
        for i in 0..<8 {
            for j in 0..<n[i] {
                cells[row + (1 + j) * r[i]][column + (1 + j) * c[i]] = 0
            }
        }
    } else {
        cells[row][column] = color
    }
    return total
}
dropBall(row: 4, column: 4, color: 1)