Skip to content

Commit

Permalink
Swift version migration, add more documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Oleksii Oliinyk committed Jun 27, 2023
1 parent 947d5f5 commit 2675829
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objectVersion = 54;
objects = {

/* Begin PBXBuildFile section */
Expand Down Expand Up @@ -112,8 +112,9 @@
8AC9989A2461C35F0079A690 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 1140;
LastUpgradeCheck = 1140;
LastUpgradeCheck = 1500;
ORGANIZATIONNAME = Alexey;
TargetAttributes = {
8AC998A12461C35F0079A690 = {
Expand Down Expand Up @@ -186,6 +187,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
Expand All @@ -208,6 +210,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
Expand All @@ -218,6 +221,7 @@
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
Expand Down Expand Up @@ -246,6 +250,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
Expand All @@ -268,6 +273,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
Expand All @@ -278,6 +284,7 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
Expand Down Expand Up @@ -305,6 +312,7 @@
DEVELOPMENT_TEAM = 5CWYRH8P25;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = "SwiftUI-Match3Kit/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand All @@ -325,6 +333,7 @@
DEVELOPMENT_TEAM = 5CWYRH8P25;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = "SwiftUI-Match3Kit/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down
14 changes: 10 additions & 4 deletions Example/SwiftUI-Match3Kit/SwiftUI-Match3Kit/GridCellView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,22 @@ struct Triangle: SwiftUI.Shape {
}

struct GridCellView: View {
let cell: Grid<Shape>.Cell
let cell: Match3Kit.Grid<Shape>.Cell

var body: some View {
switch cell.filling {
case .square:
return AnyView(Rectangle().fill(Color.red).frame(width: 30.0, height: 30.0))
Rectangle()
.fill(Color.red)
.frame(width: 30.0, height: 30.0)
case .circle:
return AnyView(Circle().fill(Color.green).frame(width: 30.0, height: 30.0))
Circle()
.fill(Color.green)
.frame(width: 30.0, height: 30.0)
case .triangle:
return AnyView(Triangle().fill(Color.blue).frame(width: 30.0, height: 30.0))
Triangle()
.fill(Color.blue)
.frame(width: 30.0, height: 30.0)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ final class GridModel: ObservableObject {
bonuse: [],
obstacles: [])

var grid: Grid<Shape> {
var grid: Match3Kit.Grid<Shape> {
controller.grid
}

Expand Down
3 changes: 1 addition & 2 deletions Example/SwiftUI-Match3Kit/SwiftUI-Match3Kit/GridView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ struct GridView: View {

var body: some View {
HStack {
ForEach(model.grid.columns.indices) { column in
ForEach(model.grid.columns.indices, id: \.self) { column in
VStack {
ForEach(self.model.grid.columns[column].indices.reversed(), id: \.self) { row in
self.buildCell(at: Index(column: column, row: row))
Expand All @@ -33,7 +33,6 @@ struct GridView: View {

return GridCellView(cell: cell)
.scaleEffect(isSelected ? 1.2 : 1.0)
.animation(.easeOut)
.gesture(tapGesture(index: index, isSelected: isSelected))
}

Expand Down
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// swift-tools-version:5.2
// swift-tools-version:5.6
import PackageDescription

let package = Package(
name: "Match3Kit",
platforms: [.iOS(.v13), .macOS(.v10_14), .tvOS(.v12)],
products: [
.library(name: "Match3Kit", targets: ["Match3Kit"])
],
Expand Down
2 changes: 1 addition & 1 deletion Sources/Match3Kit/Controller.swift
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public final class Controller<Filling: GridFilling, GeneratorType: Generator<Fil
matcher.findMatched(on: grid, indices: indices)
}

public func swapAndMatchCell( at index: Index, with target: Index) -> Set<Index> {
public func swapAndMatchCell(at index: Index, with target: Index) -> Set<Index> {
grid.swapCell(at: index, with: target)
return matcher.findMatches(on: grid, at: index)
.union(matcher.findMatches(on: grid, at: target))
Expand Down
88 changes: 83 additions & 5 deletions Sources/Match3Kit/Grid.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@

import Foundation

/// `Size` represents the size of a two-dimensional grid in terms of columns and rows.
///
/// It provides useful properties and methods related to grid dimensions, including:
/// - A method `isOnBounds(_:)` that checks if a given `Index` falls within the grid bounds.
/// - Computed properties `lowerBound`, `upperBound`, `leftBound`, and `rightBound` which define the grid boundaries.
///
/// This struct conforms to `Hashable` and `Codable`, enabling instances to be compared, hashed, encoded, and decoded.
///
/// Example usage:
/// ```
/// var gridSize = Size(columns: 5, rows: 5)
/// var index = Index(column: 2, row: 2)
/// print(gridSize.isOnBounds(index)) // Prints: "true"
/// ```
///
/// - Note: This struct considers `-1` as lower and left bounds, which implies it supports negative indexing.
/// Make sure this aligns with your grid indexing requirements.
public struct Size: Hashable, Codable {
public let columns: Int
public let rows: Int
Expand Down Expand Up @@ -36,6 +53,24 @@ public struct Size: Hashable, Codable {
public var rightBound: Int { columns }
}

/// `Index` represents a location in a two-dimensional grid using `column` and `row` properties.
///
/// It provides methods and properties that facilitate grid navigation:
/// - Computed properties for neighboring locations: `upper`, `lower`, `right`, `left`.
/// - Computed properties for sequences of neighboring locations: `upperSequence`, `lowerSequence`, `rightSequence`, `leftSequence`.
/// - A method `isNeighboring(with:)` that checks if a given index is neighboring the current index.
/// - A static property `zero` which represents the origin (0,0) index.
///
/// Additionally, it provides arrays of immediate `neighbors` and diagonal `crossNeighbors`.
///
/// The struct also conforms to `Hashable`, `Codable`, and `CustomStringConvertible`.
/// This allows for instances to be compared, hashed, encoded, decoded, and converted to a readable string format.
///
/// Example usage:
/// ```
/// var index = Index(column: 2, row: 2)
/// print(index.upper) // Prints: "(2, 3)"
/// ```
public struct Index: Hashable, Codable, CustomStringConvertible {
public let column: Int
public let row: Int
Expand All @@ -46,7 +81,7 @@ public struct Index: Hashable, Codable, CustomStringConvertible {
}

@inlinable
public var zero: Index {
public static var zero: Index {
Index(column: 0, row: 0)
}

Expand Down Expand Up @@ -91,22 +126,22 @@ public struct Index: Hashable, Codable, CustomStringConvertible {

// MARK: - Sequences
@inlinable
public func upperSequence() -> UnfoldFirstSequence<Index> {
public func upperSequence() -> some Sequence<Index> {
sequence(first: upper) { $0.upper }
}

@inlinable
public func lowerSequence() -> UnfoldFirstSequence<Index> {
public func lowerSequence() -> some Sequence<Index> {
sequence(first: lower) { $0.lower }
}

@inlinable
public func rightSequence() -> UnfoldFirstSequence<Index> {
public func rightSequence() -> some Sequence<Index> {
sequence(first: right) { $0.right }
}

@inlinable
public func leftSequence() -> UnfoldFirstSequence<Index> {
public func leftSequence() -> some Sequence<Index> {
sequence(first: left) { $0.left }
}

Expand All @@ -116,10 +151,53 @@ public struct Index: Hashable, Codable, CustomStringConvertible {
}
}

/// `GridFilling` defines a protocol for items that can fill the cells of a `Grid`.
///
/// Conforming types must provide a `pattern` property, which could represent the visual pattern,
/// value pattern or any other attributes that describe how this object fills a grid cell.
///
/// Example usage:
/// ```
/// struct MyFilling: PatternedGridFilling {
/// var pattern: Pattern {
/// // Define the pattern here
/// }
/// }
///
/// var myFilling = MyFilling()
/// var grid = Grid<MyFilling>(size: Size(columns: 5, rows: 5), fill: myFilling)
/// ```
public protocol GridFilling: Hashable, Codable {
var pattern: Pattern { get }
}

/// `Grid` represents the game field in a match-3 game, populated with items that conform to `GridFilling`.
///
/// Each cell in the `Grid` can hold a single `Cell` instance. A `Cell` holds an instance of `GridFilling`, which can represent a gem, bomb, or other game piece.
///
/// The `Grid` also provides methods for manipulating its contents, such as:
/// - `setCell(_:at:)` for replacing the content of a cell.
/// - `remove(cells:)` for removing multiple cells from the grid.
/// - `swapCell(at:with:)` for swapping the contents of two cells.
/// - `cell(at:)` for retrieving the content of a specific cell.
///
/// Other useful properties and methods include:
/// - `size` for getting the size of the grid.
/// - `allIndices()` and `allIndices(of:)` for retrieving all indices, or all indices containing a specific filling.
///
/// Example usage:
/// ```
/// typealias GridController = Controller<Shape, Generator<Shape>, Matcher<Shape>>
/// private let controller = GridController(
/// size: Size(columns: 6, rows: 6),
/// basic: [.square, .circle, .triangle],
/// bonuse: [],
/// obstacles: []
/// )
/// controller.grid.setCell(.init(id: UUID(), filling: .square), at: .init(column: 0, row: 0))
/// ```
///
/// The `Grid` structure is `Codable` which means it can be serialized and deserialized, allowing for the saving/loading of game states.
public struct Grid<Filling>: Codable where Filling: GridFilling {

public let size: Size
Expand Down
2 changes: 1 addition & 1 deletion Sources/Match3Kit/Matcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ open class Matcher<Filling: GridFilling> {
return Set()
}

func matchCellsInRow(sequence: UnfoldFirstSequence<Index>) -> [Index] {
func matchCellsInRow(sequence: some Sequence<Index>) -> [Index] {
sequence.prefix {
grid.size.isOnBounds($0) && match(cell: grid.cell(at: $0),
with: cell)
Expand Down

0 comments on commit 2675829

Please sign in to comment.