Skip to content

Chapter 2

Informations presented on this page may be incomplete or outdated. You can find the most up-to-date version reading my book Learn Swift by examples. Beginner level

What we will do:
In this part we will implement a method for game board printing. We will also add a class to represent a single ship as well as method checking if ship can be placed in a given "place".

We will learn new things:

  • extension,
  • guard,
  • instance methods and type methods,
  • optional,
  • string interpolation,
  • switch statement,
  • ternary conditional operator,
  • tuple.

In this part we cover the following topics

Source code for this chapter.


Game board printing method

In the Board class an empty printBoard() method was created

In this chapter we will implement this method. Before we do this, some printing rules should be explained.

As we know, our game board is divided on rows and columns. Both number are not limited so in consequence it would be hard to use as coordinates both letters and digits -- we will use only digits.

As it was stated in the previous chapter, to simplify our further considerations we will add around our game board a one-cell width border of type notAllowed. Other cells are filled with empty value. This border is not a part of a normal game board so we don't index any of its cells.

Because there may be a lot of rows, we have to know in advance how many digits are needed to print the last index of it. If for example we decide to have 1234 rows, then we need 4 digits to print it. It means that all of our row indexes should be printed on 4 characters right shifted and left-padded with spaces if needed. Rows number 5, 17, 324 should be printed as

Because there may be a lot of columns, we have to know in advance how many digits are needed to print the last index of it. To simplify a little bit our code, let's assume that we will use less than 100 columns. So numbers used as indexes have at most two digits. We will print every digit in separate row. Column number 5 should be printed as

while number 17 should be printed as

Putting all the rules together, our game board, in case of 12 rows and 15 columns, should be printed as


Type methods

To make it, we need a method determining the number of digits needed to print the largest row number. Such a method is not directly connected with a board -- it is rather universal method which may be used by many other classes or methods. This is why we will put its code in separate class where we will "collect" all helper or useful method. Create the EngineGameBattleshipUtils class with the frame of our method

This code looks almost familiar except class keyword precedings function. All the functions implemented so far were an examples of instance methods. Intance because to use them an instance of a class is needed. We have to create an object and than call an (instance) method on this object. Other words, this kind of methods need object because they operate directly on the objects. With class keyword precedings function we define type methods that is a method which "belongs" to rather a whole type of objects than particular object. In consequence, no object of this type is needed to use this method. The need to determine the number of digits may occur in many different types and is not something typical for Board, Ship or any other batleship game class but rather for integer numbers, no mather where they are used. That is why separate code of this method in a versatile class collecting different utility methods seems to be resonable.

Body of this method may looks like below

We require in our implementation that number argument is a positive integer (as coordinates in our case are always positive integers). To verify this requirement the code like below is typicaly used

As we can see, the whole block of code

is embraced by if only to prevent them beeing executed in case of required conditions are not fulfilled. In this short snippet it looks acceptable but for longer code, maybe with more nested conditions of this type, we will get few level of code indentation and set of closing curly brackets which may make the code less readable. The main idea of such an if is to check if some required conditions are fulfilled. If not, in most cases further code execution doesn't make any sense. That is why in Swift we gave guards which check all necessary conditions. With guard code looks more natural and let us keep the code that handles a violated requirement next to the requirement.


guard statement

A guard statement, like an if statement, executes statements depending on the logic value of an expression. Unlike an if statement, a guard statement always has an else clause. If the guard statement’s condition is met, code execution continues after the guard statement’s closing brace. Any variables or constants that were assigned values using an optional binding as part of the condition are available for the rest of the code block that the guard statement appears in. If that condition is not met, the code inside the else branch is executed. That branch must transfer control to exit the code block in which the guard statement appears. Other words, if guard statement’s condition is false then execution of the current block code must be aborted.

Equiped with determineNumberOfdigits(number:) function, we may start implement printBoard() method.

For a game board with 12 rows and 15 columns this should print

where instead of characters s, # and * spaces are printed -- above this characters are used to clarify how this line is created. Character

  • s is a part of leadingPaddingString -- in this case this variable is a two-space length string and is created by
  • # is printed in place of border sorrounding game board and is created by
  • * is printed in one-digit column numbers as for them there is no tens digit; this part is created by

Notice underscore _ usage in place of a variable name

We do this every time the value from the set we iterate over is not important for us. In this case we simply want to concatenate space leadingPadding times. Underscore _ is the way we say: I don't care about this value.


String interpolation

The "\(digit)" is how we create "interpretable" strings in Swift, that is strings whose contents depends on some values evaluated during execution. String interpolation is a way to construct such a new string value from a mix of constants, variables, literals, and expressions by including their values inside a string literal. Each item inserted into the string literal and wrapped in a pair of parentheses, prefixed by a backslash \(ITEM) is interpreted and result of interpretation substitutes its call place

In the example above, the value of age (number 12) is inserted into a string literal in place of \(age). The value of age is also part of a compound expression later in the string where ternary conditional operator is used.

The ternary conditional operator use above is a special operator with three parts, which takes the form question ? answer1 : answer2. It’s a shortcut for evaluating one of two expressions based on whether question is true or false. If question is true, it evaluates answer1 and returns its value; otherwise, it evaluates answer2 and returns its value. The ternary conditional operator is shorthand for the code below:


Expression used in message string returns either young or middle-aged string depending on age variable value. Finally this short three-line code shoud print

Read Strings and Characters for complete information about strings in Swift.

Very similar code prints second line with unity digits

For a game board with 12 rows and 15 columns this should print

so at this moment we should have

Remember that characters s, # and * are not realy visible -- here they are used in places of spaces to clarify how both lines are created.


Extensions

Using type method like determineNumberOfdigits(number:) to separate common code which "belongs" to rather a whole type of objects than particular object is one possible option how we can solve this issue. If we pay a lot more attention to it, we discover that in this example determining a number of digits is something we do on particular integer object. Saying the truth we made it as a type method for didactic reasons to describe what a type method is. Now we will show how this type on problems could be acomplish in more swifty style with extensions.

Extensions add new functionality to an existing class, structure, enumeration, or protocol type. What is very important, this includes the ability to extend types for which we do not have access to the original source code. Extensions are declared with the extension keyword:

Let's use this concept to implement another helpful method. This method should enlarge specified string to a given length left padding it with spaces by default or any other character if specified. For example, if string 12 should be transformed into four-character string, this method should return ..12 where dots . are used in a place of spaces to make it visible. Create the EngineGameBattleshipExtensions.swift file and put inside the following code

Notice how padding string is created. In determineNumberOfdigits(number:) function a variable leadingPaddingString is created as leadingPadding spaces concatenated together in for loop

More swifty way is to use initializator with repeating argument. We have seen this in previous chapter in array subsection where for example one-dimensional array containing 5 empty strings was created

or in Board initializer where two-dimensional array was created

Because we extend functionality of String class, self refers to a given string object. So self.count is about the number of characters in it, while padding + self is a concatenation of sequence of spaces (or other character specified as withPad argument) and string itself (padding and self part respectively).

Now we are ready to complete last part of a game board printing method. The rest of the printBoard() code shouldn't be difficult to follow

This code should print board in the form similar to given below


switch statement

For those who are familiar with C-like programming languages it may appear to be strange that all cases in the last part of a printBoard() method are break-less. In C break is used to break execution after completion matching case. In Swift this is a default "mode" as in most cases this is what we expect to happend in switch statement. There is no need of break usage in switch


Case ONE

If we want to use C-style fall through bahaviour a fallthrought keyword must be used. The fallthrough keyword causes code execution to move to the next case or default block on a case-by-case basis. Other words, this is not "global" behaviour for all cases within a given switch but concers only the case inside which fallthrought is used.


Case ONE
Case TWO

Remember that doing that, the fallthrought does not check the case condition for the switch case that it causes execution to fall into. The fallthrough keyword simply causes code execution to move directly to the statements inside the next case (or default case) block, as in C’s standard switch statement behavior.


1 or 2
3 or 4

Another improvement in Swift is an ability of switch's cases to check if their values are included in an interval.


Range two

Also tuples can be tested by case statement which can be very handy and allows to simplify our code. Tuples are described later in this chapter but this example is given here for completion. Please go back here when you read about tuples.


Point is inside the restricted area

Other things which may be useful is the ability to bind the value a switch matches to temporary constants or variables, to be used in the body of the case.


Point (0, 5.0) is on the OY axis


Eeee...


Create Ship class

Create a new class, as we did it before, and name it Ship. This class at this moment will have only one component: Direction enumeration used to uniquely identify or position a ship on a game board. Three elements are needed to place a ship

  • size so we know how many successive cells the ship occupies;
  • coordinates of the first element so we know when it starts;
  • direction so we know one of the four possible final location option.


Mathod checking if ship can be placed

As it was explained above, to place a ship on a game board three elements are needed: its size, coordinates of the first element which we will name anchor and direction. So, the header of a mathod checking if ship can be placed may look as follw (put this code in Board class)


Tuple

Let's stop for a while and explain what is anchor: (row: Int, col: Int). This is an example of tuple. Tuples is a well known concept from script programming languages and something I always want to have in C. Of course we can live without it and mimic with for example arrays or dictionaries but tuples are more natural. Tuples group multiple values into a single compound value. The values within a tuple can be of any type and do not have to be of the same type as each other.

If we don't care about the first element of a tuple, we can write it as

We can also use index numbers starting at zero to get tuple's element

To make our code more readable, we can name the individual elements in a tuple when the tuple is defined

Tuples are great for temporary usage. They are not suited to being use as a complex data structure persisting for a long time. In such a case structures and classes are better choice.

Going back to our method, and trying to implement mayPlaceShip(size:anchor:direction) it, we will probably write

This code allows to check if ship may be directed up. To chek down direction we will copy existing code, change a little and add to the body of our function

To check all the direction we need such a spaghetti repetitive code

Notice, thet the only thing changed in each repeated part is row/column "modficator" -- sometimes it is equal +1 if coordinate should be increased, sometimes it is equal -1 if coordinates should be decreased and sometimes it is equal 0 is coordinate should stay unchanged. So let's make this element variable and keep the rest of the code constant

Variable modifier allows us correctly change coordinate depending on the direction.

There is one more thing needed explanation -- mysterious exclamation mark ! just after variable declaration.


More details about optionals

As we know from previous chapter, every object must have a value or must be explicitely defined as optional which is a way to indicate that this object may not have a value. We set an optional variable to a valueless state by assigning it the special value nil. In Swift, nil is used in case of the absence of a value of a certain type. We may say, that nil is a value which tell us, that there is no correct value. If it sounds a little bit crazy, recal NaN "number" which is a sequence of bits interpreted not as a number but as incorrect (nonexisting) numeric values. Optionals of any type we want can be set to nil, not just object types. Conversely, nil cannot be used with nonoptionals. If a variable (rather constant) in our code needs to take no value, we have to declare it as an optional value of the appropriate type. Optional is denoted by question mark ? sufixes type name: Int?, Ship? etc. The key queston is: How we can use optionals? And the answer is not so obvious. We have few options

  • Simple guess and try approach

    doesn't work - we have Expression implicitly coerced from Int? to Any Swift compile warning in all of three prints and results are not such as we want (Optional(1) instead of 1)

    nil
    Optional(1)
    nil
  • If we are sure (but we have to be sure if we don't want to crash our application) that optional contains a non-nil value we can force unwrap its value with an exclamation mark added at the end of the optional's name
  • When working with optionals, if-else is something we must use. There is a special syntax we can use in this context. Optional binding is used to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable.

    Notice that for nonempty we don't have to use an exclamation mark.

    We can do even more: we can chain together multiple optional bindings, and the entire chain fails gracefully if any link in the chain is nil.

  • When we are sure that optional has some value every time we will use it, we can "remove" the need to check and unwrap the optional's value every time it is accessed thanks we can assume to have a value all of the time we need it. These kinds of optionals are defined as implicitly unwrapped optionals and we write it by placing an exclamation mark instead of question mark after the type we want to make optional. For example, this code

    in contrast to

    doesn't generate any warning or error and we can use implicitOptional variable without need of any explicit unwraping with an exclamation mark

  • Another handy tool we can use is the nil-coalescing operator ??. When used, for example in expression (a ?? b), it unwraps an optional a if it contains a value, or return a default value b if a is nil. The expression b must match the type that is stored inside a.

    The nil-coalescing operator is a shorthand for


Last step

In the last step we should add test() method to the EngineGameBattleship class and call it in the main file.

In test() method we simply do four tests of our mayPlaceShip(size:anchor:direction) method. To call it, change the main file conrents to the form

Now we can run our code. Just after both boads printed, result of a test() method should be displayed