Skip to content

Commit

Permalink
Overhaul documentation
Browse files Browse the repository at this point in the history
Expand on information about grids and the coordinate system, and further
outline how Taiji puzzles work along with better restructuring.
  • Loading branch information
alicerunsonfedora committed Jan 11, 2025
1 parent 67f2e6a commit 4cb07df
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 17 deletions.
3 changes: 3 additions & 0 deletions Sources/PuzzleKit/Generic/PKGrid.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
//

/// A protocol representing a puzzle grid.
///
/// Puzzle grids are typically shaped as a rectangle or square with a determined width and height, and they can be
/// accessed via a specified coordinate (see ``PKGridCoordinate``).
public protocol PKGrid {
/// The type that corresponds to an individual puzzle tile.
associatedtype Tile
Expand Down
53 changes: 53 additions & 0 deletions Sources/PuzzleKit/PuzzleKit.docc/Generic/PKGrid.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# ``PuzzleKit/PKGrid``

The structure of a grid is designed to be flexible, allowing for a variety of ways of representing tiles. For example,
``PKTaijiPuzzle`` stores its tiles in a single array, while other grid types might store their information in a
two-dimensional matrix.

### Coordinate System

Grids will typically start with an origin of (1, 1) and flow from the top left corner. This coordinate system was
chosen for the following reasons:

- Using grid coordinates starting at (1, 1) allows for a more seamless transition between the visual appearance of a
grid and its underlying implementation.
- PKGrid was initially built to support Taiji puzzles, and the original Lua implementation started at (1, 1). This
approach helped ensure parity with the Lua implementation.

> Tip: Some grid types will offer conveniences for converting between indices and coordinates.
## Topics

### Coordinate System

- ``PKGridCoordinate``

### Dimensions

- ``width``
- ``height``

### Fetching Tiles

These methods guarantee a mode of accessing tiles regardless of internal implementations.

- ``tile(at:)``
- ``tile(above:)``
- ``tile(after:)``
- ``tile(below:)``
- ``tile(before:)``

### Regions

Regions can found by running the flood-fill algorithm starting from an origin tile, provided that the grid supports
flood-filling.

- ``PKGridRegion``
- ``PKFloodFillable``
- ``findFloodFilledRegion(startingAt:)``

### Layout Management

Grids can optionally support manipulating its dimensions through the ``PKGridStretchable`` protocol.

- ``PKGridStretchable``
4 changes: 0 additions & 4 deletions Sources/PuzzleKit/PuzzleKit.docc/PuzzleKit.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,3 @@ as Sudoku, The Witness, and Taiji.
}

- ``PKGrid``
- ``PKGridCoordinate``
- ``PKGridRegion``
- ``PKFloodFillable``
- ``PKGridStretchable``
17 changes: 7 additions & 10 deletions Sources/PuzzleKit/PuzzleKit.docc/Puzzles/PKTaijiPuzzle.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
# ``PuzzleKit/PKTaijiPuzzle``

@Metadata {
@TitleHeading("Puzzle")
@PageImage(purpose: card, source: "puzzle-taiji")
}

## Overview

This structure is used to create, edit, and check Taiji puzzles.

> Note: For more information on how Taiji puzzles operate, refer to <doc:Taiji>.
This structure is used to create, edit, and check Taiji puzzles. For more information on how Taiji puzzles operate,
refer to <doc:Taiji>.

### Initializing puzzles

Creating a puzzle can be accomplished by initializing with a size:

Expand All @@ -20,7 +19,7 @@ import PuzzleKit
let puzzle = PKTaijiPuzzle(size: .init(width: 3, height: 3))
```

For a puzzle with a more complex code, use the ``init(decoding:)`` initializer:
For a puzzle with a more complex code, use the ``init(decoding:)`` initializer, which accepts a Taiji puzzle code:

```swift
import PuzzleKit
Expand All @@ -30,8 +29,8 @@ let puzzle = try PKTaijiPuzzle(decoding: "1:Tw0")

### Codable support

Codable support is also offered for cases where puzzles are contained in Codable structs, or for multiwindow support in
SwiftUI.
Codable support is also offered for cases where puzzles are contained in Codable structs, or for multi-window support
in SwiftUI.

For example, you might have a file structure that looks like the following:

Expand Down Expand Up @@ -89,9 +88,6 @@ the various types of manipulations.
let updatedPuzzle = puzzle.flippingTile(at: .one)
```
}
@Column {
@Video(source: "pktaijipuzzle-flip", alt: "A demonstration of flipping a tile.")
}
}
}
@Tab("Changing Symbols") {
Expand Down Expand Up @@ -174,6 +170,7 @@ validating the puzzle.
### Grid Tiles

- ``tiles``
- ``Swift/Int/toCoordinate(wrappingAround:)``
- ``PKTaijiTile``
- ``PKTaijiTileState``
- ``PKTaijiTileSymbol``
Expand Down
Binary file not shown.
42 changes: 39 additions & 3 deletions Sources/PuzzleKit/Taiji/PKTaijiPuzzle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,28 @@ public extension PKTaijiPuzzle {

// MARK: - Codable Conformance

// TODO: How do we test this???

extension PKTaijiPuzzle: Codable {
/// Creates a Taiji puzzle from a decoder, interpreting the input as a puzzle code string.
///
/// This initializer is typically used in scenarios where the puzzle might be decoded from a larger structure, such
/// as JSON or a window declaration in SwiftUI.
///
/// ```swift
/// let json =
/// """
/// {
/// "name": "Geschlossene Erinnerungen",
/// "author": "Lorelei Weiss",
/// "puzzle": "6:644+B26Tw640Uw22644+B2"
/// }
/// """
///
/// let data = json.data(using: .utf8)!
/// let decoder = JSONDecoder()
/// let result = try decoder.decode(MyPuzzleFile.self, from: data)
/// ```
///
/// - Parameter decoder: The decoder to retrieve the puzzle code from.
public init(from decoder: any Decoder) throws {
let container = try decoder.singleValueContainer()
let code = try container.decode(String.self)
Expand All @@ -66,7 +85,24 @@ extension PKTaijiPuzzle: Codable {
self.width = boardWidth
self.mechanics = mechanics
}


/// Encodes the Taiji puzzle into an encoder as a puzzle code string.
///
/// This method is typically called within Codable encoders to encode the data into other formats, such as JSON.
///
/// ```swift
/// struct MyPuzzleFile: Codable {
/// var name: String
/// var author: String
/// var puzzle: PKTaijiPuzzle
/// }
///
/// let pzl = MyPuzzleFile(...)
/// let encoder = JSONEncoder()
/// encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
/// let json = try encoder.encode(pzl)
/// ```
/// - Parameter encoder: The encoder to encode the puzzle into.
public func encode(to encoder: any Encoder) throws {
var container = encoder.singleValueContainer()
let code = PKTaijiEncoder.encode(self)
Expand Down

0 comments on commit 4cb07df

Please sign in to comment.