Skip to content

Commit

Permalink
Add range concept and exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
meatball133 committed Jan 4, 2025
1 parent fea42a8 commit a7aec52
Show file tree
Hide file tree
Showing 13 changed files with 468 additions and 0 deletions.
7 changes: 7 additions & 0 deletions concepts/ranges/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"blurb": "Optionals can be used to represent the possible absence of a value.",
"authors": [
"meatball133"
],
"contributors": []
}
74 changes: 74 additions & 0 deletions concepts/ranges/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Ranges

[Ranges][range] represent an interval between two values.
The most common types that support ranges are `Int`, `String`, and `Date`.
They can be used for many things, such as quickly creating a collection, slicing an array, checking if a value is in a range, and iteration.
They are created using the range operator `...` or `..<` (inclusive and exclusive, respectively).

```swift
1...5 // A range containing 1, 2, 3, 4, 5
1..<5 // A range containing 1, 2, 3, 4
```

The reason for having two range operators is to create ranges that are inclusive or exclusive of the end value, which can be useful when, for example, working with zero-based indexes.

~~~~exercism/note
When creating a range in Swift using the range operators `...` or `..<`, and wanting to call a method on the range, you need to wrap the range in parentheses.
This is because the otherwise will the method be called on the 2nd argument of the range operator.
```swift
(1...5).contains(3) // Returns true
1...5.contains(3) // => Error: value of type 'Int' has no member 'contains'
```
~~~~

## Convert a range to an array

To convert a range to an array, you can use the `Array` initializer.
This can be useful when you want to create a collection of values, without having to write them out.

```swift
let range = 1...5
let array = Array(range) // Returns [1, 2, 3, 4, 5]
```

## Slice an array

Ranges can be used to slice an array.

```swift
let array = [1, 2, 3, 4, 5]
let slice = array[1...3] // Returns [2, 3, 4]
```

## Range methods

Ranges do have a set of methods that can be used to work with them.
For example, these methods can be used to get the sum of all the values in the range or check if the range includes a value.

| Method                  | Description                                                             | Example                         |
| ----------------------- | ----------------------------------------------------------------------- | ------------------------------------- |
| `count`       | Returns the size of the range                                         | `(1...5).count // returns 5` |
| [`contains`][contains] | Returns `true` if the range includes the given value, otherwise `false` | `(1...5).contains(3) // Returns true` |

## Endless & Beginningless ranges

A range can be endless and beginless.

Using beginless and endless ranges is useful when you want to, for example, slice an array from the beginning or to the end.

~~~~exercism/caution
If not used on a collection, the endless range can cause an endless sequence, if not used with caution.
~~~~

## String ranges

String can be used in ranges and allow you to get an interval of Strings between two Strings.
For example, this can be handy when you want to get the alphabet.

```swift
"a"..."z" // A range containing ["a", "b", "c", ..., "z"]
```

[range]: https://developer.apple.com/documentation/swift/range
[contains]: https://developer.apple.com/documentation/swift/range/contains(_:)
74 changes: 74 additions & 0 deletions concepts/ranges/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Ranges

[Ranges][range] represent an interval between two values.
The most common types that support ranges are `Int`, `String`, and `Date`.
They can be used for many things, such as quickly creating a collection, slicing an array, checking if a value is in a range, and iteration.
They are created using the range operator `...` or `..<` (inclusive and exclusive, respectively).

```swift
1...5 // A range containing 1, 2, 3, 4, 5
1..<5 // A range containing 1, 2, 3, 4
```

The reason for having two range operators is to create ranges that are inclusive or exclusive of the end value, which can be useful when, for example, working with zero-based indexes.

~~~~exercism/note
When creating a range in Swift using the range operators `...` or `..<`, and wanting to call a method on the range, you need to wrap the range in parentheses.
This is because the otherwise will the method be called on the 2nd argument of the range operator.
```swift
(1...5).contains(3) // Returns true
1...5.contains(3) // => Error: value of type 'Int' has no member 'contains'
```
~~~~

## Convert a range to an array

To convert a range to an array, you can use the `Array` initializer.
This can be useful when you want to create a collection of values, without having to write them out.

```swift
let range = 1...5
let array = Array(range) // Returns [1, 2, 3, 4, 5]
```

## Slice an array

Ranges can be used to slice an array.

```swift
let array = [1, 2, 3, 4, 5]
let slice = array[1...3] // Returns [2, 3, 4]
```

## Range methods

Ranges do have a set of methods that can be used to work with them.
For example, these methods can be used to get the sum of all the values in the range or check if the range includes a value.

| Method                  | Description                                                             | Example                         |
| ----------------------- | ----------------------------------------------------------------------- | ------------------------------------- |
| `count`       | Returns the size of the range                                         | `(1...5).count // returns 5` |
| [`contains`][contains] | Returns `true` if the range includes the given value, otherwise `false` | `(1...5).contains(3) // Returns true` |

## Endless & Beginningless ranges

A range can be endless and beginless.

Using beginless and endless ranges is useful when you want to, for example, slice an array from the beginning or to the end.

~~~~exercism/caution
If not used on a collection, the endless range can cause an endless sequence, if not used with caution.
~~~~

## String ranges

String can be used in ranges and allow you to get an interval of Strings between two Strings.
For example, this can be handy when you want to get the alphabet.

```swift
"a"..."z" // A range containing ["a", "b", "c", ..., "z"]
```

[range]: https://developer.apple.com/documentation/swift/range
[contains]: https://developer.apple.com/documentation/swift/range/contains(_:)
6 changes: 6 additions & 0 deletions concepts/ranges/links.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"url": "https://developer.apple.com/documentation/swift/range",
"description": "Swift docs: Range"
}
]
17 changes: 17 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,18 @@
],
"status": "active"
},
{
"slug": "chess-game",
"name": "Chess Game",
"uuid": "162bf709-ed48-438d-9a32-f572099cf42e",
"concepts": [
"ranges"
],
"prerequisites": [
"arrays"
],
"status": "active"
},
{
"slug": "santas-helper",
"name": "Santa's Swifty Helper",
Expand Down Expand Up @@ -1503,6 +1515,11 @@
"slug": "repeat-while",
"name": "repeat while"
},
{
"uuid": "cb0d8166-672c-4bdf-820b-d60531574d73",
"slug": "ranges",
"name": "Ranges"
},
{
"uuid": "a4b7ebd1-28f4-4270-910f-cf511ec4b45a",
"slug": "self",
Expand Down
55 changes: 55 additions & 0 deletions exercises/concept/chess-board/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Instructions

As a chess enthusiast, you want to write your version of the game.
Yes, there may be plenty of implementations of chess available online already, but yours will be unique!

You start with implementing a chess board.

The chess game will be played on an eight-square wide and eight-square long board.
The squares are identified by a letter and a number.

## 1. Define rank & file range

The game will have to store the ranks of the board.
The ranks are the rows of the board, and are numbered from 1 to 8.

The game will also have to store the files on the board.
The files are the board's columns and are identified by the letters A to H.

Define the `ranks` and `files` constants that store the range of ranks and files respectively.

```swift
ranks
// returns 1..8

files
// returns 'A'..'H'
```

## 2. Check if square is valid

The game will have to check if a square is valid.
A square is valid if the rank and file are within the ranges of the ranks and files.

Define the `isValidSquare(rank:file:)` method that takes the arguments `rank` that holds an int of the rank and `file` that holds a char of the file.
The method should return `true` if the rank and file are within the range of ranks and files, and return `false` otherwise.

```swift
isValidSquare(rank: 1, file: "A")
// returns true
```

## 3. Get row

The game will store all the squares of the board in a single dimensional array.
The squares are formed as a string of the rank and file, e.g. "1A", "8B", "4G", etc.
To get the row of a square, the game will have to calculate the index of the first square of the row.

Define the `getRow(rank:)` method that takes the argument `rank` that holds an int of the rank.
The method should return an array of strings that represent the squares of the row.

```swift
let board = ["1A", "1B", "1C", "1D", "1E", "1F", "1G", "1H", "2A", ..., "8H"]
getRow(board, rank: 1)
// returns ["1A", "1B", "1C", "1D", "1E", "1F", "1G", "1H"]
```
74 changes: 74 additions & 0 deletions exercises/concept/chess-board/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Ranges

[Ranges][range] represent an interval between two values.
The most common types that support ranges are `Int`, `String`, and `Date`.
They can be used for many things, such as quickly creating a collection, slicing an array, checking if a value is in a range, and iteration.
They are created using the range operator `...` or `..<` (inclusive and exclusive, respectively).

```swift
1...5 // A range containing 1, 2, 3, 4, 5
1..<5 // A range containing 1, 2, 3, 4
```

The reason for having two range operators is to create ranges that are inclusive or exclusive of the end value, which can be useful when, for example, working with zero-based indexes.

~~~~exercism/note
When creating a range in Swift using the range operators `...` or `..<`, and wanting to call a method on the range, you need to wrap the range in parentheses.
This is because the otherwise will the method be called on the 2nd argument of the range operator.
```swift
(1...5).contains(3) // Returns true
1...5.contains(3) // => Error: value of type 'Int' has no member 'contains'
```
~~~~

## Convert a range to an array

To convert a range to an array, you can use the `Array` initializer.
This can be useful when you want to create a collection of values, without having to write them out.

```swift
let range = 1...5
let array = Array(range) // Returns [1, 2, 3, 4, 5]
```

## Slice an array

Ranges can be used to slice an array.

```swift
let array = [1, 2, 3, 4, 5]
let slice = array[1...3] // Returns [2, 3, 4]
```

## Range methods

Ranges do have a set of methods that can be used to work with them.
For example, these methods can be used to get the sum of all the values in the range or check if the range includes a value.

| Method                  | Description                                                             | Example                         |
| ----------------------- | ----------------------------------------------------------------------- | ------------------------------------- |
| `count`       | Returns the size of the range                                         | `(1...5).count // returns 5` |
| [`contains`][contains] | Returns `true` if the range includes the given value, otherwise `false` | `(1...5).contains(3) // Returns true` |

## Endless & Beginningless ranges

A range can be endless and beginless.

Using beginless and endless ranges is useful when you want to, for example, slice an array from the beginning or to the end.

~~~~exercism/caution
If not used on a collection, the endless range can cause an endless sequence, if not used with caution.
~~~~

## String ranges

String can be used in ranges and allow you to get an interval of Strings between two Strings.
For example, this can be handy when you want to get the alphabet.

```swift
"a"..."z" // A range containing ["a", "b", "c", ..., "z"]
```

[range]: https://developer.apple.com/documentation/swift/range
[contains]: https://developer.apple.com/documentation/swift/range/contains(_:)
5 changes: 5 additions & 0 deletions exercises/concept/chess-board/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
let ranks = 1...8
let files = "A"..."H"

func isVaildSquare(rank: Int, file: String) -> Bool {
return ranks.contains(rank) && files.contains(file)
}

func getRow(_ board : [String], rank: Int) -> [String] {
let startIndex = (rank - 1) * 8
let endIndex = startIndex + 8
return Array(board[startIndex..<endIndex])
}
18 changes: 18 additions & 0 deletions exercises/concept/chess-board/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"authors": [
"meatball133"
],
"files": {
"solution": [
"Sources/ChessBoard/ChessBoard.swift"
],
"test": [
"Tests/ChessBoardTests/ChessBoardTests.swift"
],
"exemplar": [
".meta/Sources/ChessBoard/ChessBoardExemplar.swift"
]
},
"blurb": "Learn about ranges while making a chess board.",
"icon": "chessboard"
}
28 changes: 28 additions & 0 deletions exercises/concept/chess-board/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// swift-tools-version:6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "ChessBoard",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "ChessBoard",
targets: ["ChessBoard"])
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "ChessBoard",
dependencies: []),
.testTarget(
name: "ChessBoardTests",
dependencies: ["ChessBoard"]),
]
)
Loading

0 comments on commit a7aec52

Please sign in to comment.