Bubble Sort in Erlang

Bubble sort is pretty boring, but it becomes more interesting if you try to implement it in a functional language for telecom – Erlang.

We have a list of numbers, we need to sort it. The bubble sort algorithm goes through the entire list, iterating and comparing numbers in pairs. During the check, the following happens: the smaller number is added to the output list, or the numbers are swapped in the current list; if there is less on the right, the iteration continues with the next number in the iteration. This iteration is repeated until there are no more replacements in the list.

In practice, it is not worth using because of the high time complexity of the algorithm – O(n^2); I implemented it in Erlang, in an imperative style, but if you are interested, you can look for better options:

-module(bubbleSort).
-export([main/1]).

startBubbleSort([CurrentHead|Tail]) ->
    compareHeads(CurrentHead, Tail, [], [CurrentHead|Tail]).

compareHeads(CurrentHead, [NextHead|Tail], [], OriginalList) ->   
    if
        CurrentHead < NextHead ->
            compareHeads(NextHead, Tail, [CurrentHead], OriginalList);
        true ->
            compareHeads(CurrentHead, Tail, [NextHead], OriginalList)
    end;
    
compareHeads(CurrentHead, [NextHead|Tail], OriginalOutputList, OriginalList) ->
    if
        CurrentHead < NextHead ->
            OutputList = OriginalOutputList ++ [CurrentHead],
            compareHeads(NextHead, Tail, OutputList, OriginalList);
        true ->
            OutputList = OriginalOutputList ++ [NextHead],
            compareHeads(CurrentHead, Tail, OutputList, OriginalList)
    end;
  
compareHeads(CurrentHead, [], OriginalOutputList, OriginalList) ->
    OutputList = OriginalOutputList ++ [CurrentHead],
    if
        OriginalList == OutputList ->
            io:format("OutputList: ~w~n", [OutputList]);
        true ->
            startBubbleSort(OutputList)
    end.
  
main(_) ->
    UnsortedList = [69,7,4,44,2,9,10,6,26,1],
    startBubbleSort(UnsortedList).

Installation and launch

In Ubuntu, Erlang is very easy to install, just type sudo apt install erlang in the terminal. In this language, each file must be a module, with a list of functions that can be used from the outside – export. Interesting features of the language include the absence of variables, only constants, the absence of standard syntax for OOP (which does not prevent the use of OOP techniques), and of course parallel computations without locks based on the actor model.

You can launch the module either through the interactive console erl, running one command after another, or more simply through escript bubbleSort.erl; The file will look different for different cases, for example, for escript you need to make a main function from which it will start.

Sources

https://www.erlang.org/
https://habr.com/ru/post/197364/

Source code

https://gitlab.com/ demensdeum/algorithms/blob/master/bubbleSort/bubbleSort.erl

Lexicographic comparison algorithm

The lexicographic string comparison algorithm works very simply, in a loop the character codes are compared and the result is returned if the characters are not equal.

An example for the C language can be found here:
https://github.com/gcc-mirror/gcc/blob/master/libiberty/memcmp.c

It should be taken into account that the characters need to be compared in a single static encoding, for example, in Swift I used character-by-character comparison on UTF-32. The option of sorting an array using memcmp will work exactly for single-byte characters, in other cases (variable-length encodings) the order may be incorrect. I do not exclude the possibility of implementation based on variable-length encodings, but most likely it will be an order of magnitude more complicated.

Time complexity of the algorithm is O(1) in the best case, O(n) in the average and worst case

Sources

https://ru.wikipedia.org/wiki/Лексикографические_порядок

Sources

https://gitlab.com/demensdeum /algorithms/blob/master/lexiCompare/lexiCompare.swift

ZX Spectrum Game Development in C

This is a silly post about developing a game for an old ZX Spectrum computer in C. Let’s take a look at the beauty:

It began production in 1982 and was produced until 1992. Technical characteristics of the machine: 8-bit Z80 processor, 16-128 KB of memory and other extensions, such as the AY-3-8910 sound chip.

As part of the Yandex Retro Games Battle 2019 competition, I wrote a game called Interceptor 2020 for this machine. Since I didn’t have time to learn assembler for the Z80, I decided to develop it in C. As a toolchain, I chose the ready-made set – z88dk, which contains C compilers and many auxiliary libraries to speed up the implementation of applications for the Spectrum. It also supports many other Z80 machines, such as MSX, Texas Instruments calculators.

Next I will describe my superficial flight over the computer architecture, the z88dk toolchain, and show how I managed to implement the OOP approach and use design patterns.

Installation Features

Installation of z88dk should be carried out according to the manual from the repository, however for Ubuntu users I would like to note a feature – if you already have compilers for Z80 installed from deb packages, then you should remove them, since z88dk will access them from the bin folder by default, due to incompatibility of the toolchain compiler versions you most likely will not be able to build anything.

Hello World

Writing Hello World is very simple:

#include 

void main()
{
    printf("Hello World");
}

It’s even easier to assemble a tap file:

zcc +zx -lndos -create-app -o helloworld helloworld.c

To run, use any ZX Spectrum emulator with tap file support, for example online:
http://jsspeccy.zxdemo.org/

Draw on the picture on the whole screen

tl;dr Pictures are drawn in tiles, tiles of size 8×8 pixels, the tiles themselves are embedded in the spectrum font, then the picture is printed in a line of indices.

The sprite and tile output library sp1 outputs tiles using UDG. The image is translated into a set of individual UDGs (tiles), then assembled on the screen using indices. It should be remembered that UDG is used to output text, and if your image contains a very large set of tiles (for example, more than 128 tiles), then you will have to go beyond the set boundaries and erase the default Spectrum font. To get around this limitation, I used a base of 128 – 255 by simplifying the images, leaving the original font in place. About simplifying the images below.

To draw full-screen images, you need to arm yourself with three utilities:
Gimp
img2spec
png2c-z88dk

There is a way for real ZX men, real retro warriors: open a graphic editor using the spectrum palette, knowing the features of image output, prepare it manually and upload it using png2c-z88dk or png2scr.

The simpler way is to take a 32-bit image, switch the number of colors to 3-4 in Gimp, edit it a little, then import it into img2spec so as not to work with color restrictions manually, export png and convert it to a C array using png2c-z88dk.

Please remember that for successful export each tile cannot contain more than two colors.

As a result, you will receive an h file that contains the number of unique tiles. If there are more than ~128, then simplify the image in Gimp (increase the repeatability) and perform the export procedure again.

After exporting, you literally load the “font” from the tiles and print the “text” from the tile indices on the screen. Here is an example from the render “class”:

// грузим шрифт в память
    unsigned char *pt = fullscreenImage->tiles;

    for (i = 0; i < fullscreenImage->tilesLength; i++, pt += 8) {
            sp1_TileEntry(fullscreenImage->tilesBase + i, pt);
    }

    // ставим курсор в 0,0
    sp1_SetPrintPos(&ps0, 0, 0);

    // печатаем строку
    sp1_PrintString(&ps0, fullscreenImage->ptiles);

Drawing sprites on the screen

Next I will describe the method of drawing 16-16 pixel sprites on the screen. I did not get to animation and color changes, because at this stage, as I suppose, I simply ran out of memory. Therefore, the game contains only transparent monochrome sprites.

Draw a monochrome png image 16×16 in Gimp, then use png2sp1sprite to translate it into an asm assembler file, declare arrays from the assembler file in C code, and add the file at the build stage.

After the stage of declaring the sprite resource, it must be added to the screen in the desired position, here is an example of the code for the “class” of the game object:

    struct sp1_ss *bubble_sprite = sp1_CreateSpr(SP1_DRAW_MASK2LB, SP1_TYPE_2BYTE, 3, 0, 0);
    sp1_AddColSpr(bubble_sprite, SP1_DRAW_MASK2,    SP1_TYPE_2BYTE, col2-col1, 0);
    sp1_AddColSpr(bubble_sprite, SP1_DRAW_MASK2RB,  SP1_TYPE_2BYTE, 0, 0);
    sp1_IterateSprChar(bubble_sprite, initialiseColour);

From the names of the functions you can roughly understand the meaning – we allocate memory for the sprite, add two columns 8-8, add color for the sprite.

In each frame the position of the sprite is set:

sp1_MoveSprPix(gameObject->gameObjectSprite, Renderer_fullScreenRect, gameObject->sprite_col, gameObject->x, gameObject->y);

Emulating OOP

There is no syntax for OOP in C, what to do if you still really want it? You need to connect your mind and be enlightened by the thought that such a thing as OOP equipment does not exist, everything ultimately comes to one of the machine architectures, in which there is simply no concept of an object and other related abstractions.

This fact for a long time prevented me from understanding why OOP is needed at all, why it should be used if in the end everything comes to machine code.

However, having worked in product development, I discovered the charms of this programming paradigm, mainly, of course, the flexibility of development, protective mechanisms of the code, with the right approach, reducing entropy, simplifying work in a team. All the listed advantages follow from the three pillars – polymorphism, encapsulation, inheritance.

It is also worth noting the simplification of solving issues related to application architecture, because 80% of architectural problems were solved by computer scientists in the last century and described in the literature on design patterns. Next, I will describe ways to add OOP-like syntax to C.

It is more convenient to use C structures as a basis for storing class instance data. Of course, you can use a byte buffer, create your own structure for classes, methods, but why reinvent the wheel? After all, we are already reinventing the syntax.

Class data

Example of GameObject “class” data fields:

struct GameObjectStruct {
    struct sp1_ss *gameObjectSprite;
    unsigned char *sprite_col;
    unsigned char x;
    unsigned char y;
    unsigned char referenceCount;
    unsigned char beforeHideX;
    unsigned char beforeHideY;
};
typedef struct GameObjectStruct GameObject;

We save our class as “GameObject.h”, #include “GameObject.h” in the right place and use it.

Class Methods

Let’s take the experience of Objective-C language developers into account, the class method signature will be functions in the global scope, the first argument will always be the data structure, then the method arguments. Below is an example of a “method” of the “class” GameObject:

void GameObject_hide(GameObject *gameObject) {
    gameObject->beforeHideX = gameObject->x;
    gameObject->beforeHideY = gameObject->y;
    gameObject->y = 200;
}

The method call looks like this:

GameObject_hide(gameObject);

Constructors and destructors are implemented in the same way. It is possible to implement a constructor as an allocator and field initializer, but I prefer to control object allocation and initialization separately.

Working with memory

Manual memory management of the form using malloc and free wrapped in new and delete macros to match C++:

#define new(X) (X*)malloc(sizeof(X))
#define delete(X) free(X)

For objects that are used by several classes at once, semi-manual memory management is implemented based on reference counting, in the image and likeness of the old Objective-C Runtime ARC mechanism:

void GameObject_retain(GameObject *gameObject) {
    gameObject->referenceCount++;
}

void GameObject_release(GameObject *gameObject) {
    gameObject->referenceCount--;

    if (gameObject->referenceCount < 1) { sp1_MoveSprAbs(gameObject->gameObjectSprite, &Renderer_fullScreenRect, NULL, 0, 34, 0, 0);
        sp1_DeleteSpr(gameObject->gameObjectSprite);
        delete(gameObject);
    }
}

Thus, each class must declare the use of a shared object with retain, and release ownership with release. Modern ARC uses automatic placement of retain/release calls.

We’re making noise!

The Spectrum has a tweeter capable of playing 1-bit music; composers of that time were able to play up to 4 sound channels on it simultaneously.

Spectrum 128k contains a separate sound chip AY-3-8910, which can play tracker music.

A library is provided for using the buzzer in z88dk

What is yet to be discovered

I was interested in getting acquainted with the Spectrum, implementing the game using z88dk, learning many interesting things. I still have a lot to learn, for example, the Z80 assembler, since it allows you to use the full power of the Spectrum, working with memory banks, working with the AY-3-8910 sound chip. I hope to participate in the contest next year!

Links

https://rgb.yandex
https://vk.com/sinc_lair
https://www.z88dk.org/forum/

Source code

https://gitlab.com/demensdeum/ zx-projects/tree/master/interceptor2020

Binary search

Let’s say we need to find out whether the email address “demensdeum@gmail.com” is on the list of email addresses allowed to receive emails.

We’ll go through the entire list from the first to the last element, checking whether the element is equal to the specified address – we’ll implement a linear search algorithm. But it will take a long time, won’t it?

To answer this question, we use the “Time complexity of algorithms”, “O” notation. The worst-case linear search time is equal to the n-th number of array elements, we write this in “O” notation – O(n). Next, we need to explain that for any known algorithm, there are three performance indicators – the best-case, worst-case, and average-case execution time. For example, the email address “demensdeum@gmail.com” is in the first index of the array, then it will be found in the first step of the algorithm, which means that the best-case execution time is – O(1); and if it is at the end of the list, then this is the worst case – O(n)

But what about the software implementation details, hardware performance, they should influence big O, right? Now take a deep breath and imagine that the calculation of time complexity is calculated for some abstract ideal machine, which has only this algorithm and nothing else.

Algorithm

Okay, it turns out that linear search is quite slow, let’s try using Binary Search. First, it should be explained that we will not be working with binary data, this name was given to this method due to the peculiarities of its operation. Initially, we sort the array in lexicographic order, then the algorithm takes the range of the entire array, gets the middle element of the range, compares it lexicographically, and depending on the comparison result decides which range to take for further search – the upper half of the current one or the lower one. That is, at each step of the search a decision is made from two possible ones – binary logic. This step is repeated until either the word is found or not found (the lower and upper indices of the range intersect).

The performance of this algorithm is – the best case when an element in the middle of the array is immediately found is O(1), the worst case of enumeration is O(log n)

Pitfalls

When implementing binary search, I encountered not only an interesting problem of lack of standardization of lexicographic comparison in programming language libraries, but even discovered the absence of a single standard for implementing localeCompare within JavaScript. The ECMAScript standard allows for different implementations of this function, which is why when sorting using localeCompare, completely different results can be observed on different JavaScript engines.

Therefore, for the algorithm to work correctly, it is necessary to sort and use only the same lexicographic comparison algorithm in the work, otherwise nothing will work. But if, for example, you try to sort an array in Scala, and search using nodejs, without implementing your own sorting/sorting of one implementation, then nothing awaits you except disappointment in humanity.

Sources

What is lexicographic comparison and what does it represent?
Почему для вычисления сложности алгоритмов используется log N вместо lb N?
Двоичный поиск
Знай сложности алгоритмов
https://stackoverflow.com/questions/52941016/sorting-in-localecompare-in-javascript

Source code

https://gitlab.com/demensdeum/algorithms

Pattern Facade


Facade is a structural design pattern. It provides a single interface to work with complex systems, allowing clients to not have implementation details about these systems, thus simplifying their code, implementing weak coupling between clients and lower-level systems. GoF has a good example of Facade – a compiler of programming languages, providing different clients pursuing different goals with the ability to build code through a single facade-compiler interface.

Sources

https://refactoring.guru/ru/design-patterns/facade
https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612

Abstract Factory Pattern

Abstract factory– provides an interface for creating related objects without specifying specific classes.

I really like the alternative name of this pattern – Kit

It is very similar to Factory Method, however Abstract Factories must describe the relationship between the objects being created, otherwise it is simply an anti-pattern God Object, which creates everything in a row in a haphazard manner.

Let’s imagine developing an AR framework for glasses, we display indoor navigation arrows, icons of stores, interesting places, windows and buttons with information about a place where the user is currently located on the screen.

At the same time, we need the ability to customize the appearance and behavior of AR environment controls. This is exactly the case where we need to use the Set pattern.

Let’s write the interface of the Abstract Factory and Abstract Products – parent protocols, elements of the AR environment:

protocol ARFactory {
    func arrow() -> ARArrow
    func icon() -> ARIcon
    func button() -> ARButton
    func window() -> ARWindow
}

protocol ARArrow {
    var image: { get }
    func handleSelection()
}

protocol ARIcon {
    var image: { get }
    var title: String
}

protocol ARButton {
    var title: String
    func handleSelection()
}

protocol ARWindow {
    var title: String
    var draw(canvas: Canvas)
}

Now, set developers will need to implement a Concrete Factory based on the Abstract Factory interface, and all elements will have to be implemented together; other parts of the application will be able to work with the factory without changing their code.

Sources

https://refactoring.guru/ru/design-patterns /abstract-factory
https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612

Factory Method

The Factory Method pattern is a creational design pattern.
This pattern describes the creation of an interface for creating an object of a specific class. Seems simple, right?

In theory

Let’s say we are developing a framework for working with AR glasses. When tilting the head to the side, a menu of available applications should appear before the user’s eyes. Applications will be developed by third-party companies, clients of our framework. Naturally, we do not know which applications, icons, names should appear, so we must provide an interface for implementing the icon and related information about the application. Let’s call it Product:

protocol Product {
 var name: String { get }
 var image: Image { get }
 var executablePath: String { get }
}

Next, we need to provide an interface for our clients to implement the issuance of an array of applications of their Specific Product – an array of application icons with names, which we will already draw in the framework.

Let’s write this interface – a Creator interface containing a Factory Method that returns an array of Products.

protocol Creator {
 func factoryMethod() -> [Product]
}

In practice

The first client of our AR framework was 7B, a leading supplier of coffee maker software in Honduras. They want to sell augmented reality glasses with the ability to brew coffee, check the water/beans level, and show the way to their nearest coffee maker in indoor map mode.

They take on the development of the software, all we need to do is provide documentation on the Creator and Product interfaces, for the correct display of the list of applications and their subsequent launch.

After the documentation is transferred, the 7B company, using the Creator interface, implements the Concrete Creator class that returns an array of icon applications. The icon applications themselves are Concrete Product classes implementing the Product interface.

Example Code Specific Products:

class CoffeeMachineLocator: implements Product {
 let name = “7B Coffee Machine Locator v.3000”
 let image = Image.atPath(“images/locator.tga”)
 let executablePath = “CoffeeMachineLocator.wasm”
}

class iPuchinno: implements Product {
 let name = “iPuchinno 1.0.3”
 let image = Image.atPath(“images/puchino.pvrtc”)
 let executablePath = “neutron/ipuchBugFixFinalNoFreezeFixAlpha4.js”
}

A Concrete Creator class that returns an array of two applications:

class 7BAppsCreator: implements Creator {
 func factoryMethod() -> [Product] {
  return [CoffeeMachineLocator(), iPuchinno()]
 }
}

After that, the 7B company compiles the library of Specific Products, Specific Creator and combines it with our framework, starts selling AR glasses for their coffee makers, no modifications are required on our part.

Sources

https://refactoring.guru/ru/design-patterns/command
https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612

Pattern Team

The Command pattern is a behavioral design pattern.

This is the pattern I’ve been sitting with the longest, it’s so simple it’s very complex. But personally, I find the beauty of self-study is that you have all the time in the world to explore a particular issue from all angles.

So, in GoF the applicability is described quite concisely and clearly:
Encapsulates a request as an object, allowing you to parameterize clients with different requests, use queues, log requests, and perform cancellation operations.

Now we will implement a simple version of the command from the description:

string fakeTrumpsRequest = “SELECT * from Users where name beginsWith DonaldTrump”

We encapsulated the request in a string class object, it can configure clients, add commands to the queue, log, cancel (using the “Snapshot” pattern)

I think this is quite enough to implement SQL queries and the like, but then the implementation details begin, different application options, the pattern code base, client roles also vary greatly, and auxiliary classes are added.

Material

The Command pattern begins with the Command protocol, which contains a single execute() method. Next comes the Specific Command and the Receiver. The CC implements the operation on the Receiver, describes the connection between the Receiver and the action. Is anything unclear? Me too, but let’s move on. The Client creates an instance of the Specific Command, associates it with the Receiver. Invoker is an object that carries out the process of launching the Command.

Now let’s try to understand it with an example, let’s say we want to update myOS on a myPhone phone, to do this we launch the myOS_Update! application, in it we press the Update Now! button, after 10 seconds the system will report a successful update.

The client in the example above is the myOS_Update! application, the Invoker is the “Update Now!” button, it runs the Specific Command of updating the system using the execute() method, which calls the Receiver – the operating system update daemon.

Example of use

Let’s say the UI of the myOS_Update! application is so good that they decided to sell it as a separate product to provide an interface for updating other operating systems. In this case, we will implement the application with support for extension via libraries, the libraries will contain implementations of Specific Commands, Receivers, we will leave static/immutable Invoker, Client, protocol Commands.

This eliminates the need to support mutable code, since our code will remain unchanged, problems can only arise during implementation on the client side, due to errors in the code of their Specific Commands and Receivers. Also, in such an implementation, there is no need to transfer the source code of the main application, that is, we have implemented the encapsulation of commands and UI interactions using the Command pattern.

Sources

https://refactoring.guru/ru/design-patterns/command
https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612

Building macOS applications under Ubuntu OSXCross CMake

In this post I will describe building cross-platform C++ applications for macOS on an Ubuntu build machine using CMake and osxcross.
First, install the osxcross toolchain:
https://github.com/tpoechtrager/osxcross
Installation occurs in 3 stages, downloading dependencies:

cd tools
./get_dependencies.sh

Download XCode.xip from the official Apple website, then unload the SDK from XCode:

./gen_sdk_package_pbzx.sh /media/demensdeum/2CE62A79E62A4404/LinuxSupportStorage/xcode111.xip

I hope you read the XCode license agreement in the previous step? Next, build the toolchain with the required prefix:

INSTALLPREFIX=/home/demensdeum/Apps/osxcross ./build.sh 

Now you can use osxcross from the prefix directory of the previous step. Let’s add a new build macro for CMake, write everything you need:

if (OSXCROSS)
SET(CMAKE_SYSTEM_NAME Darwin)
SET(CMAKE_C_COMPILER o64-clang)
SET(CMAKE_CXX_COMPILER o64-clang++)
SET(CMAKE_C_COMPILER_AR x86_64-apple-darwin19-ar)
SET(CMAKE_CXX_COMPILER_AR x86_64-apple-darwin19-ar)
SET(CMAKE_LINKER x86_64-apple-darwin19-ld)
SET(ENV{OSXCROSS_MP_INC} 1)
endif()

Dynamic linking didn’t work for me, so we export the libraries statically:

if (OSXCROSS)
add_library(FlameSteelCore STATIC ${SOURCE_FILES})
else()

Next you may encounter the fact that you do not have the necessary libraries for osxcross, I encountered this when using SDL2. osxcross supports ready-made library packages – macports. For example, installing SDL2-mixer:

osxcross-macports -v install libsdl2_mixer

After this, you can start assembling libraries/applications as usual in the cmake-make bundle, do not forget to register static linking of libraries if necessary.

Manual assembly of libraries

At the moment I encountered the problem of incorrect archiving of libraries during static linking, when assembling the final application I get an error:

file was built for archive which is not the architecture being linked (x86_64)

Very similar to this ticket, managed to implement a workaround as a result of which the build completes correctly. Let’s unzip the static library and rebuild it using the osxcross archiver:

ar x ../libFlameSteelCore.a
rm ../libFlameSteelCore.a
x86_64-apple-darwin19-ar rcs ../libFlameSteelCore.a *.o

Also, I personally think that one of the problems is the lack of the ability to run macOS applications directly on Ubuntu (at least with some of the functionality), of course there is the darling project, but the support leaves much to be desired.

Sources

https://github.com/tpoechtrager/osxcross

Build for Windows under Ubuntu MinGW CMake

In this note I will describe the process of building libraries and applications for Windows using the MinGW32 toolchain on Ubuntu.
Install wine, mingw:

sudo apt-get install wine mingw-w64

After this, you can already compile C/C++ applications for Windows:

# C
i686-w64-mingw32-gcc helloWorld.c -o helloWorld32.exe      # 32-bit
x86_64-w64-mingw32-gcc helloWorld.c -o helloWorld64.exe    # 64-bit
 
# C++
i686-w64-mingw32-g++ helloWorld.cc -o helloWorld32.exe     # 32-bit
x86_64-w64-mingw32-g++ helloWorld.cc -o helloWorld64.exe   # 64-bit

The compiled exe can be checked using wine.

Next, let’s look at the changes to the CMake build, the CMakeLists.txt file, and add MinGW-specific things to the build file:

if (MINGW32)
set(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_C_COMPILER i686-w64-mingw32-gcc)
SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
SET(CMAKE_RC_COMPILER i686-w64-mingw32-windres)
set(CMAKE_RANLIB i686-w64-mingw32-ranlib)
endif()

// для сборки shared dll
elseif (MINGW32)
add_library(FlameSteelEngineGameToolkit.dll SHARED ${SOURCE_FILES})
else()

// обязательно линкуем со всеми зависимостями
if (MINGW32)
target_link_libraries(
                        FlameSteelEngineGameToolkit.dll 
                        -static-libgcc
                        -static-libstdc++
                        SDL2 
                        SDL2_mixer 
                        /home/demensdeum/Sources/cube-art-project-bootstrap/FlameSteelFramework/FlameSteelCore/FlameSteelCore.dll
                        /home/demensdeum/Sources/cube-art-project-bootstrap/FlameSteelFramework/FlameSteelBattleHorn/FlameSteelBattleHorn.dll
                        /home/demensdeum/Sources/cube-art-project-bootstrap/FlameSteelFramework/FlameSteelCommonTraits/FlameSteelCommonTraits.dll)

set_target_properties(FlameSteelEngineGameToolkit.dll PROPERTIES
        PREFIX ""
        SUFFIX ""
        LINK_FLAGS "-Wl,--add-stdcall-alias"
        POSITION_INDEPENDENT_CODE 0 # this is to avoid MinGW warning; 
        # MinGW generates position-independent-code for DLL by default
)
else()

We collect:

cmake -DMINGW32=1 .
make

The output will be dll or exe, depending on what you are building. For a working example, you can look at the repository of the new Cube-Art-Project and its libraries:
https://gitlab.com/demensdeum/cube-art-project
https://gitlab.com/demensdeum/FlameSteelEngineGameToolkitFSGL
https://gitlab.com/demensdeum/cube-art-project-bootstrap

Sources
https://arrayfire.com/cross-compile-to-windows-from-linux/

Simple Emscripten Autotest for ChromeDriver

In this note, I will describe the implementation of launching an autotest for the ChromeDriver browser Chrome, which launches an autotest module translated from C++ using Emscripten, reads the console output and returns the test result.
First you need to install selenium, for python3-ubuntu it is done like this:

pip3 install selenium

Next, download ChromeDriver from the official website, put chromedriver, for example, in /usr/local/bin, after that you can start implementing the autotest.
Below I will provide the code of the autotest, which launches the Chrome browser with the Emscripten autotest page open, checks for the presence of the text “Window test succeded”:

import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

capabilities = DesiredCapabilities.CHROME
capabilities['goog:loggingPrefs'] = { 'browser':'ALL' }
driver = webdriver.Chrome()
driver.get("http://localhost/windowInitializeTest/indexFullscreen.html")

time.sleep(2)

exitCode = 1

for entry in driver.get_log('browser'):
    if entry["source"] == "console-api":
        message = entry["message"]
        if "Window test succeded" in message:
            print("Test succeded")
            exitCode = 0

driver.close()
exit(exitCode)

Save the test as main.py and run python3 main.py

Building a project with dependencies for Emscripten

In this note I will describe the assembly of a project consisting of several libraries using Emscripten.
At the moment Emscripten does not support building shared libraries, so the first thing we do is convert all libraries from Shared to Static. Emscripten works with its own include files, so we need to solve the issue with the visibility of header files, I solved this by forwarding a symlink from the system directory to the Emscripten toolchain:

ln -s /usr/local/include/FlameSteelFramework $EMSDK/fastcomp/emscripten/system/include/FlameSteelFramework

If you use CMake, you need to change SHARED->STATIC in the CMakeLists.txt file of the add_library method. You can build a library/application for further static linking using the commands:

emcmake cmake .
emmake make

Next, you will need to build the main application specifying *.a library files at the linking stage. I was unable to specify a relative path, the build completed correctly only after specifying the full paths in the CMakeLists.txt file:

elseif(EMSCRIPTEN)
target_link_libraries(${FSEGT_PROJECT_NAME} GL GLEW 
/home/demensdeum/Sources/cube-art-project-bootstrap/cube-art-project/sharedLib/libCubeArtProject.a 
/home/demensdeum/Sources/cube-art-project-bootstrap/FlameSteelFramework/FlameSteelEngineGameToolkitFSGL/libFlameSteelEngineGameToolkitFSGL.a 
/home/demensdeum/Sources/cube-art-project-bootstrap/FlameSteelFramework/FlameSteelEngineGameToolkit/libFlameSteelEngineGameToolkit.a 
/home/demensdeum/Sources/cube-art-project-bootstrap/FlameSteelFramework/FlameSteelCore/libFlameSteelCore.a 
/home/demensdeum/Sources/cube-art-project-bootstrap/FlameSteelFramework/FlameSteelBattleHorn/libFlameSteelBattleHorn.a 
/home/demensdeum/Sources/cube-art-project-bootstrap/FlameSteelFramework/FSGL/libFSGL.a 
/home/demensdeum/Sources/cube-art-project-bootstrap/FlameSteelFramework/FlameSteelCommonTraits/libFlameSteelCommonTraits.a)
else()

Sources

https://emscripten.org/ docs/compiling/Building-Projects.html#using-libraries

Shared Library CMake C++

Recently I decided to make all parts of FlameSteelFramework separate shared libraries, below I will show an example of CMakeLists.txt file for FlameSteelCore:

cmake_minimum_required(VERSION 3.5)

project (FlameSteelCore)
set(CMAKE_BUILD_TYPE Release)

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)

file(GLOB_RECURSE SOURCE_FILES
    "src/FlameSteelCore/*.cpp"
)

add_library(FlameSteelCore SHARED ${SOURCE_FILES})

install(DIRECTORY "${CMAKE_SOURCE_DIR}/src/FlameSteelCore"
        DESTINATION include/FlameSteelFramework
        FILES_MATCHING
        PATTERN "*.h"
)

install(TARGETS FlameSteelCore DESTINATION lib)

Commands that CMake executes: compiles all files with the *.cpp extension from the src/FlameSteelCore/ directory into a shared library, copies all headers with the *.h extension from src/FlameSteelCore to include/FlameSteelFramework (in my case it is /usr/local/include/FlameSteelFramework), copies shared lib to the lib directory (/usr/local/lib)
After installation, you may need to update the LD cache – sudo ldconfig.
To build and install on Ubuntu (if you have the correct build toolchain), just run the commands:

cmake . && make && sudo make install

To test the installation process, I pass make prefix to the local folder makeInstallTestPlayground:

cmake -DCMAKE_INSTALL_PREFIX:PATH=/home/demensdeum/makeInstallTestPlayground . && make && make install

References

https: //stackoverflow.com/questions/17511496/how-to-create-a-shared-library-with-cmake
https://stackoverflow.com/questions/6003374/what-is-cmake-equivalent-of-configure-prefix-dir-make-all-install

C++ language interpreter – Cling

Not long ago I came across an interesting project called Cling, a C++ interpreter that can work interactively from the console, among other things. You can get acquainted with the project at the link: https://github.com/root-project/cling
Installation for Ubuntu is very simple – download the archive for the required version, unpack it, go to the bin folder and run cling in the terminal.
Below is an example of loading the library FlameSteelCore, initializing the object, printing the id:

Emscripten’s Lost Exceptions and Regex Issues

Lost exception

An interesting feature of Emscripten is that when starting a game loop via emscripten_set_main_loop, you should remember that exception handling must be re-added via try catch directly in the loop method, since the runtime loses the try catch block from the outside.
The easiest way to display the error text is through the browser, using javascript alert:

            catch (const std::exception &exc)
            {
                const char *errorText = exc.what();
                cout << "Exception: " << errorText << "; Stop execution" << endl;

                EM_ASM_(
                {
                    var errorText = UTF8ToString($0);
                    alert(errorText);

                }, errorText);

                abort();

Too complex regexp

The std implementation of regex may throw an error_complexity exception if it finds the regular expression too complex. This happens in the current emscripten implementation, so I suggest you implement tests for parsing via regular expressions, or use third-party regex implementations.

Pattern Builder

The Builder pattern belongs to a group of patterns, the existence of which is not particularly clear to me, I note the obvious redundancy of this. Belongs to the group of generative design patterns. It is used to implement a simple interface for creating complex objects.

Applicability

Simplification of the interface. It can make it easier to create an object in constructors with a large number of arguments, objectively improving the readability of the code.

Example in C++ without a builder:

auto weapon = new Weapon(“Claws”);
monster->weapon = weapon;
auto health = new MonsterHealth(100);
monster->health = health;

Пример со строителем на C++:

                  .addWeapon(“Claws”)
                  .addHealth(100)
                  .build();

Однако в языках поддерживающих именованные аргументы (named arguments), необходимость использовать именно для этого случая отпадает.

Пример на Swift с использованием named arguments:

let monster = Monster(weapon: “Claws”, health: 100)

Immutability. Using the builder, you can ensure the encapsulation of the created object until the final assembly stage. Here you need to think carefully whether the use of the pattern will save you from the high dynamics of the environment in which you work, perhaps the use of the pattern will not give anything, due to the simple lack of a culture of using encapsulation in the development team.

Interaction with components at different stages of object creation. Also, using the pattern, it is possible to provide step-by-step creation of an object when interacting with other components of the system. Most likely, this is very useful (?)

Criticism

Of course, you need to *carefully* think about whether it is worth setting up widespread use of the pattern in your project. Languages ​​with modern syntax and advanced IDEs eliminate the need to use the Builder, in terms of improving code readability (see the point about named arguments)
Was this pattern necessary in 1994, when the GoF book was published? Most likely yes, but judging by the open source code base of those years, few people used it.

Sources

https://refactoring.guru/ru/design-patterns/builder

Pattern Composite

The Composite pattern is a structural design pattern; in domestic sources it is known as the “Composer”.
Let’s say we are developing an application – a photo album. The user can create folders, add photos there, and perform other manipulations. It is necessary to be able to show the number of files in folders, the total number of all files and folders.
It is obvious that you need to use a tree, but how to implement the tree architecture, with a simple and convenient interface? The Composite pattern comes to the rescue.

Sheila in Moonducks

Next, in Directory we implement the dataCount() method – by going through all the elements in the component array, adding up all their dataCount’s.
Everything is ready!
Below is an example in Go:
package main

import "fmt"

type component interface {

dataCount() int

}

type file struct {

}

type directory struct {

c []component

}

func (f file) dataCount() int {

return 1

}

func (d directory) dataCount() int {

var outputDataCount int = 0

for _, v := range d.c {
outputDataCount += v.dataCount()
}

return outputDataCount

}

func (d *directory) addComponent(c component) {

d.c = append(d.c, c)

}

func main() {

var f file
var rd directory
rd.addComponent(f)
rd.addComponent(f)
rd.addComponent(f)
rd.addComponent(f)

fmt.Println(rd.dataCount())

var sd directory
sd.addComponent(f)

rd.addComponent(sd)
rd.addComponent(sd)
rd.addComponent(sd)

fmt.Println(sd.dataCount())
fmt.Println(rd.dataCount())

}

Sources

https://refactoring.guru/ru/design-patterns/ composite

Pattern Adapter

Benjamín Núñez González

The Adapter pattern is a structural design pattern.

An adapter provides data/interface conversion between two classes/interfaces.

Let’s say we are developing a system for determining the buyer’s goal in a store based on neural networks. The system receives a video stream from the store’s camera, identifies buyers by their behavior, and classifies them into groups. Types of groups: came to buy (potential buyer), just to look (gaper), came to steal something (thief), came to return goods (dissatisfied buyer), came drunk/high (potential troublemaker).

Like all experienced developers, we find a ready-made neural network that can classify monkey species in a cage based on a video stream, which was kindly made freely available by the Zoological Institute of the Berlin Zoo, we retrain it on a video stream from the store and get a working state-of-the-art system.

There is only one small problem – the video stream is encoded in mpeg2 format, and our system only supports OGG Theora. We do not have the source code of the system, the only thing we can do is change the dataset and train the neural network. What to do? Write an adapter class that will translate the stream from mpeg2 -> OGG Theora and give it to the neural network.

According to the classic scheme, the pattern involves client, target, adaptee and adapter. The client in this case is a neural network receiving a video stream in OGG Theora, target is the interface with which it interacts, adaptee is the interface that outputs the video stream in mpeg2, the adapter converts mpeg2 to OGG Theora and outputs it via the target interface.

It seems simple, doesn’t it?

Sources

https://ru.wikipedia.org/wiki/Адтер_(проектированный)
https://refactoring.guru/ru/design-patterns/adapter

Delegate Pattern

The delegate pattern is one of the basic design patterns.
Let’s say we are developing a barbershop app. The app has a calendar for choosing a day for an appointment, and when you tap on a date, a list of barbers should open with the option to choose from.
We will implement a naive binding of system components, we will combine the calendar and the screen using pointers to each other, to implement the list output:


// псевдокод

class BarbershopScreen {
   let calendar: Calendar

   func showBarbersList(date: Date) {
      showSelectionSheet(barbers(forDate: date))
   }
}

class Calendar {
    let screen: BarbershopScreen

    func handleTap(on date: Date) {
        screen.showBarbersList(date: date)
    }
}

After a few days the requirements change, before displaying the list you need to show offers with a choice of services (beard trimming, etc.) but not always, on all days except Saturday.
We add a check to the calendar whether it is Saturday today or not, depending on it we call the method of the list of barbers or the list of services, for clarity I will demonstrate:


// псевдокод

class BarbershopScreen {
   let calendar: Calendar

   func showBarbersList(date: Date) {
      showSelectionSheet(barbers(forDate: date))
   }

   func showOffersList() {
      showSelectionSheet(offers)
   }
}

class Calendar {
    let screen: BarbershopScreen

    func handleTap(on date: Date)  {
        if date.day != .saturday {
             screen.showOffersList()
        }
        else {
             screen.showBarbersList(date: date)
        }
    }
}

A week later we are asked to add a calendar to the feedback screen, and at this point the first architectural ouch happens!
What should I do? The calendar is tightly linked to the haircut appointment screen.
oh! oof! oh-oh
If you continue to work with such a crazy application architecture, you should make a copy of the entire calendar class and link this copy to the feedback screen.
Ok, so it seems good, then we added a few more screens and a few copies of the calendar, and then the X-moment came. We were asked to change the calendar design, that is, now we need to find all the copies of the calendar and add the same changes to all of them. This “approach” greatly affects the speed of development, increases the chance of making a mistake. As a result, such projects end up in a broken trough state, when even the author of the original architecture does not understand how the copies of his classes work, other hacks added along the way fall apart on the fly.
What should have been done, or better yet, what is not too late to start doing? Use the delegation pattern!
Delegation is a way to pass class events through a common interface. Here is an example of a delegate for a calendar:

protocol CalendarDelegate {
   func calendar(_ calendar: Calendar, didSelect date: Date)
}

Now let’s add code to work with the delegate to the example code:


// псевдокод

class BarbershopScreen: CalendarDelegate {
   let calendar: Calendar

   init() {
       calendar.delegate = self
   }

   func calendar(_ calendar: Calendar, didSelect date: Date) {
        if date.day != .saturday {
            showOffersList()
        }
        else {
             showBarbersList(date: date)
        }
   }

   func showBarbersList(date: Date) {
      showSelectionSheet(barbers(forDate: date))
   }

   func showOffersList() {
      showSelectionSheet(offers)
   }
}

class Calendar {
    weak var delegate: CalendarDelegate

    func handleTap(on date: Date)  {
        delegate?.calendar(self, didSelect: date)
    }
}

As a result, we completely untied the calendar from the screen; when selecting a date from the calendar, it passes the date selection event – *delegates* the event processing to the subscriber; the subscriber is the screen.
What advantages do we get in this approach? Now we can change the calendar and screen logic independently of each other, without duplicating classes, simplifying further support; thus, the “single responsibility principle” of implementing system components is implemented, the DRY principle is observed.
When using delegation, you can add, change the logic of displaying windows, the order of anything on the screen, and this will not affect the calendar and other classes that objectively should not participate in processes not directly related to them.
Alternatively, programmers who don’t bother themselves much use sending messages via a common bus, without writing a separate protocol/delegate interface, where it would be better to use delegation. I wrote about the disadvantages of this approach in the previous note – “Observer Pattern”.

Sources

https://refactoring.guru/ru/replace-inheritance -with-delegation

Observer Pattern

The Observer pattern is a behavioral design pattern.
The pattern allows sending a change in the state of an object to subscribers using a common interface.
Let’s say we are developing a messenger for programmers, we have a chat screen in our application. When receiving a message with the text “problem” and “error” or “something is wrong”, we need to paint the error list screen and the settings screen red.
Next I will describe 2 options for solving the problem, the first is simple but extremely difficult to support, and the second is much more stable in support, but requires turning on the brain during the initial implementation.

Common Bus

All implementations of the pattern contain sending messages when data changes, subscribing to messages, and further processing in methods. The variant with a common bus contains a single object (usually a singleton is used) that provides dispatching of messages to recipients.
The simplicity of implementation is as follows:

  1. The object sends an abstract message to the shared bus
  2. Another object subscribed to the common bus catches the message and decides whether to process it or not.

One of the implementation options available from Apple (NSNotificationCenter subsystem) adds matching of the message header to the name of the method that is called on the recipient upon delivery.
The biggest disadvantage of this approach is that when changing the message further, you will first need to remember and then manually edit all the places where it is processed and sent. This is a case of quick initial implementation, followed by long, complex support that requires a knowledge base for correct operation.

Multicast delegate

In this implementation, we will make a final class of multicast delegate, to which, as in the case of a common bus, objects can subscribe to receive “messages” or “events”, but the objects are not assigned the work of parsing and filtering messages. Instead, subscriber classes must implement the methods of the multicast delegate, with the help of which it notifies them.
This is implemented by using delegate interfaces/protocols; when the general interface changes, the application will stop assembling, at which point it will be necessary to redo all the places where this message is processed, without the need to maintain a separate knowledge base to remember these places. The compiler is your friend.
This approach increases team productivity, since there is no need to write or store documentation, there is no need for a new developer to try to understand how a message is processed, its arguments, instead, work occurs with a convenient and understandable interface, thus implementing the paradigm of documentation through code.
The multicast delegate itself is based on the delegate pattern, which I will write about in the next post.

Sources

https://refactoring.gu/ru/design-patterns/observer

Proxy Pattern

The Proxy pattern is a structural design pattern.
The pattern describes the technique of working with a class through a class interlayer – a proxy. The proxy allows you to change the functionality of the original class, with the ability to preserve the original behavior, while maintaining the original interface of the class.
Let’s imagine a situation – in 2015, one of the countries of Western Europe decides to record all requests to the websites of the country’s users, in order to improve statistics and gain a deeper understanding of the political moods of citizens.
Let’s present a pseudo-code of a naive implementation of a gateway that citizens use to access the Internet:

class InternetRouter {

    private let internet: Internet

    init(internet: Internet) {
        self.internet = internet
    }

    func handle(request: Request, from client: Client) -> Data {
        return self.internet.handle(request)
    }

}

In the code above, we create an Internet router class, with a pointer to an object providing access to the Internet. When a client requests a site, we return a response from the Internet.

Using the Proxy pattern and the singleton anti-pattern, we will add the functionality of logging the client name and URL:

class InternetRouterProxy {

    private let internetRouter: InternetRouter

    init(internet: Internet) {
        self.internetRouter = InternetRouter(internet: internet)
    }

    func handle(request: Request, from client: Client) -> Data {

        Logger.shared.log(“Client name: \(client.name), requested URL: \(request.URL)”)

        return self.internetRouter.handle(request: request, from: client)
    }

}

Due to the preservation of the original InternetRouter interface in the InternetRouterProxy proxy class, it is enough to replace the initialization class from InternetRouter to its proxy, no further changes to the code base are required.

Sources

https://refactoring.guru/ru/design-patterns/ proxy

Pattern Prototype

The prototype pattern belongs to the group of generative design patterns.
Let’s say we are developing a dating app Tender, according to the business model we have a paid option to make copies of your own profile, changing the name automatically, and the order of the photos in some places. This is done so that the user can have the opportunity to manage several profiles with different sets of friends in the app.
By clicking on the button to create a copy of the profile, we need to implement copying of the profile, automatic name generation and re-sorting of photos.
Naive pseudocode implementation:

fun didPressOnCopyProfileButton() {
    let profileCopy = new Profile()
    profileCopy.name = generateRandomName()
    profileCopy.age = profile.age
    profileCopy.photos = profile.photos.randomize()
    storage.save(profileCopy)
}

Now let’s imagine that other team members copy-pasted the copy code or came up with it from scratch, and after that a new field was added – likes. This field stores the number of profile likes, now you need to update *all* places where copying occurs manually, adding the new field. This is very long and difficult to maintain the code, as well as to test.
To solve this problem, the Prototype design pattern was invented. Let’s create a common Copying protocol, with a copy() method that returns a copy of the object with the necessary fields. After changing the entity fields, you will only need to update one copy() method, instead of manually searching and updating all the places containing the copy code.

Sources

https://refactoring.guru/ru/design-patterns/prototype

State Machine and Pattern State

In this note I will describe the use of a state machine (State Machine), show a simple implementation, implementation using the State pattern. It is worth mentioning that it is undesirable to use the State pattern if there are less than three states, since this usually leads to unnecessary complication of code readability, associated problems in support – everything should be in moderation.

MEAACT PHOTO / STUART PRICE.

Lord of the Flags

Let’s say we are developing a video player screen for a media system of a civil aircraft. The player should be able to load a video stream, play it, allow the user to stop the loading process, rewind, and perform other operations common to a player.
Let’s say the player cached the next chunk of the video stream, checked that there are enough chunks for playback, started playing the fragment to the user and simultaneously continues downloading the next one.
At this point, the user rewinds to the middle of the video, i.e. now you need to stop playing the current fragment and start loading from a new position. However, there are situations in which this cannot be done – the user cannot control the playback of the video stream while he is shown a video about air safety. Let’s create a flag isSafetyVideoPlaying to check this situation.
The system should also be able to pause the current video and broadcast an announcement from the ship’s captain and crew via the player. Let’s create another flag, isAnnouncementPlaying. Plus, there is a requirement not to pause playback while displaying help on how to use the player, another flag, isHelpPresenting.

Pseudocode of a media player example:

class MediaPlayer {

    public var isHelpPresenting = false
    public var isCaching = false
    public var isMediaPlaying: Bool = false
    public var isAnnouncementPlaying = false
    public var isSafetyVideoPlaying = false

    public var currentMedia: Media = null

    fun play(media: Media) {

        if isMediaPlaying == false, isAnnouncementPlaying == false, isSafetyVideoPlaying == false {

            if isCaching == false {
                if isHelpPresenting == false {
                    media.playAfterHelpClosed()
                }
                else {
                    media.playAfterCaching()
                }
            }
    }

    fun pause() {
        if isAnnouncementPlaying == false, isSafetyVideoPlaying == false {
            currentMedia.pause()
        }
    }
}

The above example is hard to read, and hard to maintain due to high variability (entropy). This example is based on my experience working with the codebase of *many* projects that did not use a state machine.
Each checkbox should “manage” the interface elements and business logic of the application in a special way; the developer, adding another checkbox, should be able to juggle them, checking and rechecking everything several times with all possible options.
Substituting into the formula “2 ^ number of flags” we can get 2 ^ 6 = 64 variants of application behavior for only 6 flags, all these combinations of flags will need to be checked and supported manually.
From the developer’s side, adding new functionality with such a system looks like this:
– We need to add the ability to show the airline’s browser page, and it should collapse like with movies if the crew members announce something.
– Ok, I’ll do it. (Oh, shit, I’ll have to add another flag and double-check all the places where the flags intersect, that’s a lot to change!)

Also the weak point of the flag system is making changes to the application behavior. It is very difficult to imagine how to quickly/flexibly change behavior based on flags, if after changing just one flag you have to recheck everything. This approach to development leads to a lot of problems, loss of time and money.

Enter The Machine

If you look closely at the flags, you can see that we are actually trying to process specific processes that occur in the real world. Let’s list them: normal mode, showing a safety video, broadcasting a message from the captain or crew members. Each process has a set of rules that change the behavior of the application.
According to the rules of the state machine pattern, we list all processes as states in enum, add such a concept as state to the player code, implement behavior based on the state, removing combinations on the flags. In this way, we reduce the options for testing exactly to the number of states.

Pseudocode:

enum MediaPlayerState {
	mediaPlaying,
	mediaCaching,
	crewSpeaking,
	safetyVideoPlaying,
	presentingHelp
}

class MediaPlayer {
	fun play(media: Media) {
		media.play()
	}

	func pause() {
		media.pause()
	}
}

class MediaPlayerStateMachine {
	public state: MediaPlayerState
	public mediaPlayer: MediaPlayer
	public currentMedia: Media

	//.. init (mediaPlayer) etc

	public fun set(state: MediaPlayerState) {
		switch state {
			case mediaPlaying:
				mediaPlayer.play(currentMedia)
			case mediaCaching, crewSpeaking,
			safetyVideoPlaying, presentingHelp:
				mediaPlayer.pause()
		}
	}
}

The big difference between a flag system and a state machine is the logical state switching funnel in the set(state: ..) method, which allows us to translate the human understanding of state into program code, without having to play logic games of converting flags into states in the future code maintenance.

State Pattern

Next I will show the difference between a naive implementation of a state machine and the state pattern. Let’s imagine that it was necessary to add 10 states, as a result the state machine class will grow to the size of a godobject, it will be difficult and expensive to maintain. Of course, this implementation is better than the flag system (with a flag system the developer will shoot himself first, and if not, then seeing 2 ^ 10 = 1024 variations the QA will hang himself, however if both of them *don’t notice* the complexity of the task, then the user will notice it, for whom the application will simply refuse to work with a certain combination of flags)
When there are a large number of states, it is necessary to use the State pattern.
Let’s put the set of rules into the State protocol:

protocol State {
    func playMedia(media: Media, context: MediaPlayerContext)
    func shouldCacheMedia(context: MediaPlayerContext)
    func crewSpeaking(context: MediaPlayerContext)
    func safetyVideoPlaying(context:MediaPlayerContext)
    func presentHelp(context: MediaPlayerContext)
}

Let’s take the implementation of the set of rules into separate states, for example, the code of one state:

class CrewSpeakingState: State {
	func playMedia(context: MediaPlayerContext) {
		showWarning(“Can’ t play media - listen to announce!”)
	}

	func mediaCaching(context: MediaPlayerContext) {
		showActivityIndicator()
	}

	func crewSpeaking(context: MediaPlayerContext) {
		set(volume: 100)
	}

	func safetyVideoPlaying(context: MediaPlayerContext) {
		set(volume: 100)
	}

	func presentHelp(context: MediaPlayerContext) {
		showWarning(“Can’ t present help - listen to announce!”)
	}
}

Next, we will create a context with which each state will work, and integrate the state machine:

final class MediaPlayerContext {
	private
	var state: State

	public fun set(state: State) {
		self.state = state
	}

	public fun play(media: Media) {
		state.play(media: media, context: this)
	}

	…
	остальные возможные события
}

Application components work with the context through public methods, state objects themselves decide from which state to which to make the transition using the state machine inside the context.
In this way, we have implemented the decomposition of the God Object, maintaining the changing state will be much easier, thanks to the compiler tracking changes in the protocol, reducing the complexity of understanding states due to the reduction in the number of lines of code and focusing on solving a specific problem of the state. Also, now it is possible to divide the work in the team, giving the implementation of a specific state to team members, without worrying about the need to “resolve” conflicts, which happens when working with one large class of state machine.

Sources

https://refactoring.guru/ru/design-patterns/state

Skeletal Animation (Part 1 – Shader)

In this article I will describe my understanding of skeletal animation, which is used in all modern 3D engines for animating characters, game environments, etc.
I’ll start the description with the most tangible part – the vertex shader, because the entire calculation path, no matter how complex it is, ends with the transfer of prepared data for display in the vertex shader.

After calculation on the CPU, skeletal animation goes into the vertex shader.
Let me remind you of the vertex formula without skeletal animation:
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vertex;
For those who do not understand how this formula came about, you can read my article describing the principle of working with matrices for displaying 3D content in the context of OpenGL.
For the rest – the formula for implementing skeletal animation:
” vec4 animatedVertex = bone0matrix * vertex * bone0weight +”
“bone1matrix * vertex * bone1weight +”
“bone2matrix * vertex * bone2weight +”
“bone3matrix * vertex * bone3weight;\n”
” gl_Position = projectionMatrix * viewMatrix * modelMatrix * animatedVertex;\n”

That is, we multiply the final matrix of bone transformation by the vertex and by the weight of this matrix relative to the vertex. Each vertex can be animated by 4 bones, the force of the impact is regulated by the bone weight parameter, the sum of the impacts must be equal to one.
What to do if the vertex is affected by less than 4 bones? You need to divide the weight between them, and make the impact of the rest equal to zero.
Mathematically, multiplying a weight by a matrix is ​​called “Matrix-Scalar Multiplication”. Multiplying by a scalar allows you to sum the effects of matrices on the resulting vertex.

The bone transformation matrices themselves are transmitted as an array.Moreover, the array contains matrices for the entire model as a whole, and not for each mesh separately.

But for each vertex the following information is transmitted separately:
– Index of the matrix that affects the vertex
–The weight of the matrix that acts on the vertex
It is not just one bone that is transmitted, usually the effect of 4 bones on the vertex is used.
Also, the sum of the weights of 4 dice must always be equal to one.
Next, let’s look at how this looks in the shader.
Array of matrices:
“uniform mat4 bonesMatrices[kMaxBones];”

Information about the impact of the 4 bones on each vertex:
“attribute vec2 bone0info;”
“attribute vec2 bone1info;”
“attribute vec2 bone2info;”
“attribute vec2 bone3info;”

vec2 – in the X coordinate we store the bone index (and convert it to int in the shader), in the Y coordinate the weight of the bone’s impact on the vertex. Why do we have to pass this data in a two-dimensional vector? Because GLSL does not support passing readable C structures with correct fields to the shader.

Below is an example of obtaining the necessary information from a vector for further substitution into the animatedVertex formula:

“int bone0Index = int(bone0info.x);”
“float bone0weight = bone0info.y;”
“mat4 bone0matrix = bonesMatrices[bone0Index];”

“int bone1Index = int(bone1info.x);”
“float bone1weight = bone1info.y;”
“mat4 bone1matrix = bonesMatrices[bone1Index];”

“int bone2Index = int(bone2info.x);”
“float bone2weight = bone2info.y;”
“mat4 bone2matrix = bonesMatrices[bone2Index];”

“int bone3Index = int(bone3info.x);”
“float bone3weight = bone3info.y;”
“mat4 bone3matrix = bonesMatrices[bone3Index];”

Now the vertex structure that is filled on the CPU should look like this:
x, y, z, u, v, bone0index, bone0weight, bone1index, bone1weight, bone2index, bone2weight, bone3index, bone3weight

The vertex buffer structure is filled once during model loading, but the transformation matrices are transferred from the CPU to the shader at each rendering frame.

In the remaining parts I will describe the principle of calculating animation on the CPU, before passing it to the vertex shader, I will describe the tree of bone nodes, the passage through the hierarchy animation-model-nodes-mesh, matrix interpolation.

Sources

http://ogldev.atspace.co. uk/www/tutorial38/tutorial38.html

Source code

https://gitlab.com/demensdeum/skeletal-animation

Template method

The template method is a behavioral design pattern. The pattern describes a way to replace part of a class’s logic on demand, while leaving the common part unchanged for descendants.

Cuban Cars

Let’s say we are developing a bank client, let’s consider the task of developing an authorization module – the user should be able to log in to the application using abstract login data.
The authorization module must be cross-platform, support different authorization technologies and storage of encrypted data of different platforms. To implement the module, we choose the cross-platform language Kotlin, using the abstract class (protocol) of the authorization module, we will write an implementation for the MyPhone phone:

class MyPhoneSuperDuperSecretMyPhoneAuthorizationStorage {
    fun loginAndPassword() : Pair {
        return Pair("admin", "qwerty65435")
    }
}

class ServerApiClient {
    fun authorize(authorizationData: AuthorizationData) : Unit {
        println(authorizationData.login)
        println(authorizationData.password)
        println("Authorized")
    }
}

class AuthorizationData {
    var login: String? = null
    var password: String? = null
}

interface AuthorizationModule {
    abstract fun fetchAuthorizationData() : AuthorizationData
    abstract fun authorize(authorizationData: AuthorizationData)
}

class MyPhoneAuthorizationModule: AuthorizationModule {
    
    override fun fetchAuthorizationData() : AuthorizationData {
        val loginAndPassword = MyPhoneSuperDuperSecretMyPhoneAuthorizationStorage().loginAndPassword()
        val authorizationData = AuthorizationData()
        authorizationData.login = loginAndPassword.first
        authorizationData.password = loginAndPassword.second
        
        return authorizationData
    }
    
    override fun authorize(authorizationData: AuthorizationData) {
        ServerApiClient().authorize(authorizationData)
    }
    
}

fun main() {
    val authorizationModule = MyPhoneAuthorizationModule()
    val authorizationData = authorizationModule.fetchAuthorizationData()
    authorizationModule.authorize(authorizationData)
}

Now for each phone/platform we will have to duplicate the code for sending authorization to the server, there is a violation of the DRY principle. The example above is very simple, in more complex classes there will be even more duplication. To eliminate code duplication, you should use the Template Method pattern.
We will move the common parts of the module into immutable methods, and transfer the functionality of transmitting encrypted data to specific platform classes:

class MyPhoneSuperDuperSecretMyPhoneAuthorizationStorage {
    fun loginAndPassword() : Pair {
        return Pair("admin", "qwerty65435")
    }
}

class ServerApiClient {
    fun authorize(authorizationData: AuthorizationData) : Unit {
        println(authorizationData.login)
        println(authorizationData.password)
        println("Authorized")
    }
}

class AuthorizationData {
    var login: String? = null
    var password: String? = null
}

interface AuthorizationModule {
    abstract fun fetchAuthorizationData() : AuthorizationData
    
    fun authorize(authorizationData: AuthorizationData) {
        ServerApiClient().authorize(authorizationData)
    }
}

class MyPhoneAuthorizationModule: AuthorizationModule {
    
    override fun fetchAuthorizationData() : AuthorizationData {
        val loginAndPassword = MyPhoneSuperDuperSecretMyPhoneAuthorizationStorage().loginAndPassword()
        val authorizationData = AuthorizationData()
        authorizationData.login = loginAndPassword.first
        authorizationData.password = loginAndPassword.second
        
        return authorizationData
    }
    
}

fun main() {
    val authorizationModule = MyPhoneAuthorizationModule()
    val authorizationData = authorizationModule.fetchAuthorizationData()
    authorizationModule.authorize(authorizationData)
}

Sources

https://refactoring.guru/ru/design- patterns/template-method

Source code

https://gitlab.com/demensdeum/patterns/< /p>

Pattern Bridge

The Bridge pattern is a structural design pattern. It allows you to abstract the implementation of class logic by moving the logic into a separate abstract class. Sounds simple, right?

Let’s say we are implementing a spam bot that should be able to send messages to different types of messengers.
We implement it using a common protocol:

protocol User {
    let token: String
    let username: String
}

protocol Messenger {
    var authorize(login: String, password: String)
    var send(message: String, to user: User)
}

class iSeekUUser: User {
    let token: String
    let username: String
}

class iSeekU: Messenger {

    var authorizedUser: User?
    var requestSender: RequestSender?
    var requestFactory: RequestFactory?

    func authorize(login: String, password: String) {
        authorizedUser = requestSender?.perform(requestFactory.loginRequest(login: login, password: password))
    }
    
    func send(message: String, to user: User) {
        requestSender?.perform(requestFactory.messageRequest(message: message, to: user)
    }
}

class SpamBot {
    func start(usersList: [User]) {
        let iSeekUMessenger = iSeekU()
        iSeekUMessenger.authorize(login: "SpamBot", password: "SpamPassword")
        
        for user in usersList {
            iSeekUMessennger.send(message: "Hey checkout demensdeum blog! http://demensdeum.com", to: user)
        }
    }
}

Now let’s imagine a situation where a new, faster messaging protocol for the iSekU messenger is released. To add a new protocol, you will need to duplicate the iSekU bot implementation, changing only a small part of it. It is unclear why this should be done if only a small part of the class logic has changed. This approach violates the DRY principle; with further development of the product, the lack of flexibility will make itself known through errors and delays in the implementation of new features.
Let’s move the protocol logic into an abstract class, thus implementing the Bridge pattern:

protocol User {
    let token: String
    let username: String
}

protocol Messenger {
    var authorize(login: String, password: String)
    var send(message: String, to user: User)
}

protocol MessagesSender {
    func send(message: String, to user: User)
}

class iSeekUUser: User {
    let token: String
    let username: String
}

class iSeekUFastMessengerSender: MessagesSender {
    func send(message: String, to user: User) {
        requestSender?.perform(requestFactory.messageRequest(message: message, to: user)
    }
}

class iSeekU: Messenger {

    var authorizedUser: User?
    var requestSender: RequestSender?
    var requestFactory: RequestFactory?
    var messagesSender: MessengerMessagesSender?

    func authorize(login: String, password: String) {
        authorizedUser = requestSender?.perform(requestFactory.loginRequest(login: login, password: password))
    }
    
    func send(message: String, to user: User) {
        messagesSender?.send(message: message, to: user)
    }
}

class SpamBot {

    var messagesSender: MessagesSender?

    func start(usersList: [User]) {
        let iSeekUMessenger = iSeekU()
        iSeekUMessenger.authorize(login: "SpamBot", password: "SpamPassword")
        
        for user in usersList {
            messagesSender.send(message: "Hey checkout demensdeum blog! http://demensdeum.com", to: user)
        }
    }
}

One of the advantages of this approach is undoubtedly the ability to expand the functionality of the application by writing plugins/libraries that implement abstracted logic without changing the code of the main application.
What’s the difference with the Strategy pattern? Both patterns are very similar, but Strategy describes switching *algorithms*, while Bridge allows switching large parts of *any logic, no matter how complex*.

Sources

https://refactoring.guru/ru/design-patterns/bridge

Source code

https://gitlab.com/demensdeum/patterns/ p>

Chain of Responsibilities Pattern

Chain of responsibility refers to behavioral design patterns.


Ganna Dolbieva

The film company Ja-pictures shot a documentary about communist Rastafarians from Liberia called “Red Dawn of Marley”. The film is very long (8 hours), interesting, but before sending it to distribution, it turned out that in some countries, frames and phrases from the film may be considered heresy and not give a distribution license. The producers of the film decide to cut out moments containing questionable phrases from the film, manually and automatically. Double checking is necessary so that the distributor’s representatives are not simply shot in some countries, in case of an error during manual viewing and editing.
Countries are divided into four groups – countries without censorship, with moderate, medium and very strict censorship. A decision is made to use neural networks to classify the level of heresy in the review fragment of the film. Very expensive state-of-art neural networks trained for different levels of censorship are purchased for the project, the developer’s task is to break the film into fragments and pass them along a chain of neural networks, from free to strict, until one of them detects heresy, then the fragment is transferred for manual review for further editing. It is impossible to go through all the neural networks, since too much computing power is spent on their work (we still have to pay for electricity), it is enough to stop at the first one that worked.
Naive pseudocode implementation:

import StateOfArtCensorshipHLNNClassifiers

protocol MovieCensorshipClassifier {
    func shouldBeCensored(movieChunk: MovieChunk) -> Bool
}

class CensorshipClassifier: MovieCensorshipClassifier {

    let hnnclassifier: StateOfArtCensorshipHLNNClassifier

    init(_ hnnclassifier: StateOfArtCensorshipHLNNClassifier) {
        self.hnnclassifier = hnnclassifier
    }
    
    func shouldBeCensored(_ movieChunk: MovieChunk) -> Bool {
        return hnnclassifier.shouldBeCensored(movieChunk)
    }
}

let lightCensorshipClassifier = CensorshipClassifier(StateOfArtCensorshipHLNNClassifier("light"))
let normalCensorshipClassifier = CensorshipClassifier(StateOfArtCensorshipHLNNClassifier("normal"))
let hardCensorshipClassifier = CensorshipClassifier(StateOfArtCensorshipHLNNClassifier("hard"))

let classifiers = [lightCensorshipClassifier, normalCensorshipClassifier, hardCensorshipClassifier]

let movie = Movie("Red Jah rising")
for chunk in movie.chunks {
    for classifier in classifiers {
        if classifier.shouldBeCensored(chunk) == true {
            print("Should censor movie chunk: \(chunk), reported by \(classifier)")
        }
   }
}

In general, the solution with an array of classifiers is not so bad, However! Let’s imagine that we cannot create an array, we have the ability to create only one classifier entity, which already determines the type of censorship for a fragment of the film. Such restrictions are possible when developing a library that extends the functionality of the application (plugin).
Let’s use the decorator pattern – add a reference to the next classifier in the chain to the classifier class, and stop the verification process at the first successful classification.
This way we implement the Chain of Responsibility pattern:

import StateOfArtCensorshipHLNNClassifiers

protocol MovieCensorshipClassifier {
    func shouldBeCensored(movieChunk: MovieChunk) -> Bool
}

class CensorshipClassifier: MovieCensorshipClassifier {

    let nextClassifier: CensorshipClassifier?
    let hnnclassifier: StateOfArtCensorshipHLNNClassifier

    init(_ hnnclassifier: StateOfArtCensorshipHLNNClassifier, nextClassifier: CensorshipClassifiers?) {
            self.nextClassifier = nextClassifier
            self.hnnclassifier = hnnclassifier
    }
    
    func shouldBeCensored(_ movieChunk: MovieChunk) -> Bool {
        let result = hnnclassifier.shouldBeCensored(movieChunk)
        
        print("Should censor movie chunk: \(movieChunk), reported by \(self)")
        
        if result == true {
                return true
        }
        else {
                return nextClassifier?.shouldBeCensored(movieChunk) ?? false
        }
    }
}

let censorshipClassifier = CensorshipClassifier(StateOfArtCensorshipHLNNClassifier("light"), nextClassifier: CensorshipClassifier(StateOfArtCensorshipHLNNClassifier("normal", nextClassifier: CensorshipClassifier(StateOfArtCensorshipHLNNClassifier("hard")))))

let movie = Movie("Red Jah rising")
for chunk in movie.chunks {
    censorshipClassifier.shouldBeCensored(chunk)
}

References

https://refactoring.guru/ru/ design-patterns/chain-of-responsibility

Source Code

https://gitlab.com/demensdeum/patterns/< /p>

Pattern Decorator

The Decorator pattern is a structural design pattern.

Decorator is used as an alternative to inheritance to extend the functionality of classes.
There is a task to expand the functionality of the application depending on the type of product. The customer needs three types of product – Basic, Professional, Ultimate.
Basic – counts the number of characters, Professional – Basic + capabilities prints text in capital letters, Ultimate – Basic + Professional + prints text with the inscription ULTIMATE.
We implement it using inheritance:

protocol Feature {
	func textOperation(text: String)
}

class BasicVersionFeature: Feature {
	func textOperation(text: String) {
		print("\(text.count)")
	}
}

class ProfessionalVersionFeature: BasicVersionFeature {
	override func textOperation(text: String) {
		super.textOperation(text: text)
		print("\(text.uppercased())")
	}
}

class UltimateVersionFeature: ProfessionalVersionFeature {
	override func textOperation(text: String) {
		super.textOperation(text: text)
		print("ULTIMATE: \(text)")
	}
}

let textToFormat = "Hello Decorator"

let basicProduct = BasicVersionFeature()
basicProduct.textOperation(text: textToFormat)

let professionalProduct = ProfessionalVersionFeature()
professionalProduct.textOperation(text: textToFormat)

let ultimateProduct = UltimateVersionFeature()
ultimateProduct.textOperation(text: textToFormat)

Now there is a requirement to implement the product “Ultimate Light” – Basic + Ultimate but without the capabilities of the Professional version. The first OUCH! happens, because you will have to create a separate class for such a simple task, duplicate the code.
Let’s continue the implementation using inheritance:

protocol Feature {
	func textOperation(text: String)
}

class BasicVersionFeature: Feature {
	func textOperation(text: String) {
		print("\(text.count)")
	}
}

class ProfessionalVersionFeature: BasicVersionFeature {
	override func textOperation(text: String) {
		super.textOperation(text: text)
		print("\(text.uppercased())")
	}
}

class UltimateVersionFeature: ProfessionalVersionFeature {
	override func textOperation(text: String) {
		super.textOperation(text: text)
		print("ULTIMATE: \(text)")
	}
}

class UltimateLightVersionFeature: BasicVersionFeature {
	override func textOperation(text: String) {
		super.textOperation(text: text)
		print("ULTIMATE: \(text)")	
	}
}

let textToFormat = "Hello Decorator"

let basicProduct = BasicVersionFeature()
basicProduct.textOperation(text: textToFormat)

let professionalProduct = ProfessionalVersionFeature()
professionalProduct.textOperation(text: textToFormat)

let ultimateProduct = UltimateVersionFeature()
ultimateProduct.textOperation(text: textToFormat)

let ultimateLightProduct = UltimateLightVersionFeature()
ultimateLightProduct.textOperation(text: textToFormat)

The example can be developed further for clarity, but even now the complexity of supporting a system based on inheritance is visible – it is cumbersome and lacks flexibility.
A decorator is a set of protocols describing functionality, an abstract class containing a reference to a child concrete instance of the decorator class that extends the functionality.
Let’s rewrite the example above using the pattern:

protocol Feature {
	func textOperation(text: String)
}

class FeatureDecorator: Feature {
	private var feature: Feature?
	
	init(feature: Feature? = nil) {
		self.feature = feature
	}
	
	func textOperation(text: String) {
		feature?.textOperation(text: text)
	}
}

class BasicVersionFeature: FeatureDecorator {
	override func textOperation(text: String) {
		super.textOperation(text: text)
		print("\(text.count)")
	}
}

class ProfessionalVersionFeature: FeatureDecorator {
	override func textOperation(text: String) {
		super.textOperation(text: text)
		print("\(text.uppercased())")
	}
}

class UltimateVersionFeature: FeatureDecorator {
	override func textOperation(text: String) {
		super.textOperation(text: text)
		print("ULTIMATE: \(text)")
	}
}

let textToFormat = "Hello Decorator"

let basicProduct = BasicVersionFeature(feature: UltimateVersionFeature())
basicProduct.textOperation(text: textToFormat)

let professionalProduct = ProfessionalVersionFeature(feature: UltimateVersionFeature())
professionalProduct.textOperation(text: textToFormat)

let ultimateProduct = BasicVersionFeature(feature: UltimateVersionFeature(feature: ProfessionalVersionFeature()))
ultimateProduct.textOperation(text: textToFormat)

let ultimateLightProduct = BasicVersionFeature(feature: UltimateVersionFeature())
ultimateLightProduct.textOperation(text: textToFormat)

Now we can create variations of any type of product – it is enough to initialize the combined types at the stage of application launch, the example below is the creation of the Ultimate + Professional version:

ultimateProfessionalProduct.textOperation(text: textToFormat)

Sources

https://refactoring.guru/ru/design-patterns/decorator

Source code

https://gitlab.com/demensdeum/patterns

Pattern Mediator

The Mediator pattern is a behavioral design pattern.

One day you receive an order to develop a joke app – the user presses a button in the middle of the screen and a funny duck quacking sound is heard.
After uploading to the app store, the app becomes a hit: everyone quacks through your app, Elon Musk quacks on his Instagram at the latest launch of a super-high-speed tunnel on Mars, Hillary Clinton quacks Donald Trump at the debates and wins the elections in Ukraine, success!
A naive implementation of the application looks like this:

class DuckButton {
    func didPress() {
        print("quack!")
    }
}

let duckButton = DuckButton()
duckButton.didPress()

Next you decide to add the sound of a dog barking, for this you need to show two buttons for selecting the sound – with a duck and a dog. Create two button classes DuckButton and DogButton.
Change the code:

class DuckButton {
    func didPress() {
        print("quack!")
    }
}

class DogButton {
    func didPress() {
        print("bark!")
    }
}

let duckButton = DuckButton()
duckButton.didPress()

let dogButton = DogButton()
dogButton.didPress()

After another success, we add the sound of a pig squeal, now three classes of buttons:

class DuckButton {
    func didPress() {
        print("quack!")
    }
}

class DogButton {
    func didPress() {
        print("bark!")
    }
}

class PigButton {
    func didPress() {
        print("oink!")
    }
}

let duckButton = DuckButton()
duckButton.didPress()

let dogButton = DogButton()
dogButton.didPress()

let pigButton = PigButton()
pigButton.didPress()

Users complain that sounds overlap each other.
We add a check to prevent this from happening, and at the same time introduce the classes to each other:

class DuckButton {
    var isMakingSound = false
    var dogButton: DogButton?
    var pigButton: PigButton?
    func didPress() {
        guard dogButton?.isMakingSound ?? false == false &&
                pigButton?.isMakingSound ?? false == false else { return }
        isMakingSound = true
        print("quack!")
        isMakingSound = false
    }
}

class DogButton {
    var isMakingSound = false
    var duckButton: DuckButton?
    var pigButton: PigButton?
    func didPress() {
        guard duckButton?.isMakingSound ?? false == false &&
                pigButton?.isMakingSound ?? false == false else { return }
        isMakingSound = true
        print("bark!")
        isMakingSound = false
    }
}

class PigButton {
    var isMakingSound = false
    var duckButton: DuckButton?
    var dogButton: DogButton?
    func didPress() {
        guard duckButton?.isMakingSound ?? false == false && 
                dogButton?.isMakingSound ?? false == false else { return }
        isMakingSound = true
        print("oink!")
        isMakingSound = false
    }
}

let duckButton = DuckButton()
duckButton.didPress()

let dogButton = DogButton()
dogButton.didPress()

let pigButton = PigButton()
pigButton.didPress()

Based on the success of your app, the government decides to make a law that allows quack, bark and grunt on mobile devices only from 9:00 am to 3:00 pm on weekdays; at other times, the user of your app risks going to prison for 5 years for indecent sound production using personal electronic devices.
Change the code:

import Foundation

extension Date {
    func mobileDeviceAllowedSoundTime() -> Bool {
        let hour = Calendar.current.component(.hour, from: self)
        let weekend = Calendar.current.isDateInWeekend(self)
        
        let result = hour >= 9 && hour <= 14 && weekend == false
        
        return result
    }
}

class DuckButton {
    var isMakingSound = false
    var dogButton: DogButton?
    var pigButton: PigButton?
    func didPress() {
        guard dogButton?.isMakingSound ?? false == false &&
                pigButton?.isMakingSound ?? false == false &&
                 Date().mobileDeviceAllowedSoundTime() == true else { return }
        isMakingSound = true
        print("quack!")
        isMakingSound = false
    }
}

class DogButton {
    var isMakingSound = false
    var duckButton: DuckButton?
    var pigButton: PigButton?
    func didPress() {
        guard duckButton?.isMakingSound ?? false == false &&
                pigButton?.isMakingSound ?? false == false &&
                 Date().mobileDeviceAllowedSoundTime() == true else { return }
        isMakingSound = true
        print("bark!")
        isMakingSound = false
    }
}

class PigButton {
    var isMakingSound = false
    var duckButton: DuckButton?
    var dogButton: DogButton?
    func didPress() {
        guard duckButton?.isMakingSound ?? false == false && 
                dogButton?.isMakingSound ?? false == false &&
                 Date().mobileDeviceAllowedSoundTime() == true else { return }
        isMakingSound = true
        print("oink!")
        isMakingSound = false
    }
}

let duckButton = DuckButton()
let dogButton = DogButton()
let pigButton = PigButton()

duckButton.dogButton = dogButton
duckButton.pigButton = pigButton

dogButton.duckButton = duckButton
dogButton.pigButton = pigButton

pigButton.duckButton = duckButton
pigButton.dogButton = dogButton

duckButton.didPress()
dogButton.didPress()
pigButton.didPress()

Suddenly a flashlight app starts to push ours out of the market, let's not let it defeat us and add a flashlight by pressing the "oink-oink" button, and so-no to the other buttons:

import Foundation

extension Date {
    func mobileDeviceAllowedSoundTime() -> Bool {
        let hour = Calendar.current.component(.hour, from: self)
        let weekend = Calendar.current.isDateInWeekend(self)
        
        let result = hour >= 9 && hour <= 14 && weekend == false
        
        return result
    }
}

class Flashlight {

    var isOn = false

    func turn(on: Bool) {
        isOn = on
    }
}

class DuckButton {
    var isMakingSound = false
    var dogButton: DogButton?
    var pigButton: PigButton?
    var flashlight: Flashlight?
    func didPress() {
        flashlight?.turn(on: true)
        guard dogButton?.isMakingSound ?? false == false &&
                pigButton?.isMakingSound ?? false == false &&
                 Date().mobileDeviceAllowedSoundTime() == true else { return }
        isMakingSound = true
        print("quack!")
        isMakingSound = false
    }
}

class DogButton {
    var isMakingSound = false
    var duckButton: DuckButton?
    var pigButton: PigButton?
    var flashlight: Flashlight?
    func didPress() {
        flashlight?.turn(on: true)
        guard duckButton?.isMakingSound ?? false == false &&
                pigButton?.isMakingSound ?? false == false &&
                 Date().mobileDeviceAllowedSoundTime() == true else { return }
        isMakingSound = true
        print("bark!")
        isMakingSound = false
    }
}

class PigButton {
    var isMakingSound = false
    var duckButton: DuckButton?
    var dogButton: DogButton?
    var flashlight: Flashlight?
    func didPress() {
        flashlight?.turn(on: true)
        guard duckButton?.isMakingSound ?? false == false && 
                dogButton?.isMakingSound ?? false == false &&
                 Date().mobileDeviceAllowedSoundTime() == true else { return }
        isMakingSound = true
        print("oink!")
        isMakingSound = false
    }
}

let flashlight = Flashlight()
let duckButton = DuckButton()
let dogButton = DogButton()
let pigButton = PigButton()

duckButton.dogButton = dogButton
duckButton.pigButton = pigButton
duckButton.flashlight = flashlight

dogButton.duckButton = duckButton
dogButton.pigButton = pigButton
dogButton.flashlight = flashlight

pigButton.duckButton = duckButton
pigButton.dogButton = dogButton
pigButton.flashlight = flashlight

duckButton.didPress()
dogButton.didPress()
pigButton.didPress()

As a result, we have a huge application that contains a lot of copy-paste code, the classes inside are connected to each other by a dead link - there is no weak coupling, such a miracle is very difficult to maintain and change in the future due to the high chances of making a mistake.

Using Mediator

Let's add an intermediate class mediator - ApplicationController. This class will provide weak coupling of objects, ensure separation of class responsibilities, and eliminate duplicate code.
Let's rewrite:

import Foundation

class ApplicationController {

    private var isMakingSound = false
    private let flashlight = Flashlight()
    private var soundButtons: [SoundButton] = []

    func add(soundButton: SoundButton) {
        soundButtons.append(soundButton)
    }
    
    func didPress(soundButton: SoundButton) {
        flashlight.turn(on: true)
        guard Date().mobileDeviceAllowedSoundTime() && 
                isMakingSound == false else { return }
        isMakingSound = true
        soundButton.didPress()
        isMakingSound = false
    }
}

class SoundButton {
    let soundText: String
    
    init(soundText: String) {
        self.soundText = soundText
    }
    
    func didPress() {
        print(soundText)
    }
}

class Flashlight {
    var isOn = false

    func turn(on: Bool) {
        isOn = on
    }
}

extension Date {
    func mobileDeviceAllowedSoundTime() -> Bool {
        let hour = Calendar.current.component(.hour, from: self)
        let weekend = Calendar.current.isDateInWeekend(self)
        
        let result = hour >= 9 && hour <= 14 && weekend == false
        
        return result
    }
}

let applicationController = ApplicationController()
let pigButton = SoundButton(soundText: "oink!")
let dogButton = SoundButton(soundText: "bark!")
let duckButton = SoundButton(soundText: "quack!")

applicationController.add(soundButton: pigButton)
applicationController.add(soundButton: dogButton)
applicationController.add(soundButton: duckButton)

pigButton.didPress()
dogButton.didPress()
duckButton.didPress()

Many articles devoted to the architecture of applications with a user interface describe the MVC pattern and its derivatives. The model is used to work with business logic data, the view or presentation shows information to the user in the interface/provides interaction with the user, the controller is a mediator providing interaction between system components.

Sources

https://refactoring.guru/ru/design-patterns/ mediator

Source code

https://gitlab.com/demensdeum/patterns/< /p>

Strategy pattern

The Strategy pattern allows you to select the type of algorithm that implements a common interface, right while the application is running. This pattern refers to the behavioral design patterns.

Sun Tzu

Suppose we are developing a music player with embedded codecs. The built-in codecs imply reading music formats without using external sources of the operating system (codecs), the player should be able to read tracks of different formats and play them. VLC player has such capabilities, it supports various types of video and audio formats, it runs on popular and not very operating systems.

Imagine what a naive player implementation looks like:

var player: MusicPlayer?

func play(filePath: String) {
    let extension = filePath.pathExtension

    if extension == "mp3" {
        playMp3(filePath)
    }
    else if extension == "ogg" {
        playOgg(filePath)
    }
}

func playMp3(_ filePath: String) {
    player = MpegPlayer()
    player?.playMp3(filePath)
}

func playOgg(_ filePath: String) {
    player = VorbisPlayer()
    player?.playMusic(filePath)
}

Next, we add several formats, which leads to the need to write additional methods. Plus, the player must support plug-in libraries, with new audio formats that will appear later. There is a need to switch the music playback algorithm, the Strategy pattern is used to solve this problem.

Let’s create a common protocol MusicPlayerCodecAlgorithm, write the implementation of the protocol in two classes MpegMusicPlayerCodecAlgorithm and VorbisMusicPlayerCodecAlgorithm, to play mp3 and ogg files with-but. Create a class MusicPlayer, which will contain a reference for the algorithm that needs to be switched, then by the file extension we implement codec type switching:

import Foundation

class MusicPlayer {
    var playerCodecAlgorithm: MusicPlayerCodecAlgorithm?
    
	func play(_ filePath: String) {
            playerCodecAlgorithm?.play(filePath)
	}
}

protocol MusicPlayerCodecAlgorithm {
    func play(_ filePath: String)
}

class MpegMusicPlayerCodecAlgorithm: MusicPlayerCodecAlgorithm {
	func play(_ filePath: String) {
		debugPrint("mpeg codec - play")
	}
}

class VorbisMusicPlayerCodecAlgorithm: MusicPlayerCodecAlgorithm {
	func play(_ filePath: String) {
		debugPrint("vorbis codec - play")	
	}
}

func play(fileAtPath path: String) {
	guard let url = URL(string: path) else { return }
	let fileExtension = url.pathExtension
		
	let musicPlayer = MusicPlayer()
	var playerCodecAlgorithm: MusicPlayerCodecAlgorithm? 
		
	if fileExtension == "mp3" {
                playerCodecAlgorithm = MpegMusicPlayerCodecAlgorithm()
	}
	else if fileExtension == "ogg" {
                playerCodecAlgorithm = VorbisMusicPlayerCodecAlgorithm()
	}
		
	musicPlayer.playerCodecAlgorithm = playerCodecAlgorithm
	musicPlayer.playerCodecAlgorithm?.play(path)
}

play(fileAtPath: "Djentuggah.mp3")
play(fileAtPath: "Procrastinallica.ogg")

The above example also shows the simplest example of a factory (switching the codec type from the file extension) It is important to note that the Strategy strategy does not create objects, it only describes how to create a common interface for switching the family of algorithms.

Documentation

https://refactoring.guru/en/design-patterns/strategy

Source code

https://gitlab.com/demensdeum/patterns/