# Solutions

## Lunar lander control

:::{solution} which-are-statements
1. [x] `air_conditioner = 1;`
1. [x] `if (...) else ...`
1. [ ] `a > b`
1. [ ] `5`
1. [x] `success = a > b;`
:::

::::{solution} lunar-lander-control-code
:::{literalinclude} code/lunar_lander_control.c
:language: c
:::
::::

## Conveyor belt capacity check
::::{solution} conveyor-belt-capacity-check-code
:::{literalinclude} code/conveyor_belt_capacity_check.c
:language: c
:::
::::

## Spare parts inventory assistant

:::{solution} array-or-not
1. [ ] `int array[];`{l=c}
1. [ ] `int array;`{l=c}
1. [ ] `char[] choices = {"black bird", "great tit", "falcon"};`{l=c}
1. [x] `char names[] = {"ird", "grea", "con"};`{l=c}
1. [x] `int part_ids[]= {3093, -49318, 3092.812};`{l=c}

        You will get a warning about implicit type conversion of 3092.812.
1. [ ] `string names[] = [];`{l=c}

        1. We need curly brackets 2. `string` does not exist
1. [x] `double intensity[X][Y][Z];`{l=c}

:::

::::{solution} spare-parts-inventory-assistant-code
:::{literalinclude} code-wi/spare_parts_inventory_assistant.c
:language: c
:::
::::

## Rock paper scissors lizard Spock

:::{solution} rps-resolution-logic
```{literalinclude} code/rps_resolution_logic_if_else.c
:language: c
```
```{literalinclude} code/rps_resolution_logic_switch.c
:language: c
```
```{literalinclude} code/rps_resolution_logic_lookup_table.c
:language: c
```
:::
:::

:::{solution} rpssl-flowchart-overview
```{mermaid} img/rock-paper-scissors-lizard-Spock-overview.mmd
```
:::

:::{solution} rpssl-resolution-logic-using-difference-switch
```{literalinclude} code/rpssl_resolution_logic_switch.c
:language: c
```
:::

Refinement for the *Game* process:

:::{mermaid} img/rock-paper-scissors-lizard-Spock-game.mmd
:::

:::{literalinclude} code-wi/rock_paper_scissors_spock_lizard.c
:language: c
:::

## Knight's tour

:::{solution} knights-tour-4x4
Here is a solution with 15 squares generated by ChatGPT after thinking ~40s. It is not a closed-loop, so it applies only to starts from corners.
```text
10  7 12  3
13  4  9  6
 8 11  2 15
 1 14  5  .
```
:::

## Maze

::::{solution} meaning-of-pointer-operators

1. [ ] `a == 42`{l=c}
1. [x] `*a == 42`{l=c}
1. [ ] `&a == 42`{l=c}
1. [ ] `&*b == 42`{l=c}
1. [x] `*&b == 42`{l=c}

Output of the last two expressions and repeated dereferencing:

:::{literalinclude} code/a_points_to_b_reference_and_dereference_again.c
:language: c
:::
:::{literalinclude} code/a_points_to_b_reference_and_dereference_again.txt
:::
::::

:::{solution} advantage-of-pointers
Advantages of 1

1. Only one poster exists
1. No synchronization needed
1. You save space
1. Each friend must be cautious when they work with the poster. They will be stressed about breaking something.

Disadvantages of 1
1. Your friends must come to your room 
1. You have to recreate the poster for each friend
:::

:::{solution} pointer-arithmetic-with-char-vs-int
If we increment a pointer, then it points to the start of the next data. The start of the next data is dependent on the size, in our case `sizeof(int)`.

So pointer arithmetic scales automatically based on the size of the type.
:::

::::{solution} calculating-pointer-plus-n
address + index * size_of(datatype)

:::{warning}
Following code scales twice: we have to convert the pointer to a number to make it work:

```c
double arr[] = {100.1, 2, 3.43};

double *target_addr(double *base_addr, size_t index) {
  return base_addr + index * sizeof(double);
}
```
::::

:::{solution} pass-by-address-vs-value-using-scalars-and-array

```{literalinclude} code/call_by_address_and_value.c
:language: c
```
:::

## Filter CSV by age

::::{solution} processing-temperature-data
:::{literalinclude} code/processing-temperature-data.c
:language: c
:::
::::

:::{solution} an-error-in-a-file-processing-program
1. Using the `call stack` or iteratively placing breakpoints from bottom to the top.

   Looking at the values of variables
   
1. Problem: `fp` is `nullptr`, so the `FILE` struct does not exist.

`fopen` returns a `nullptr` if the file cannot be opened. 
   
`perror()` is useful for printing the last happened error.

Error handling code:
```{literalinclude} code-error/file-opening-error-with-error-check.c
:language: c
:diff: code-error/file-opening-error.c
```
Output:
```{literalinclude} code-error/file-opening-error-with-error-check.stderr.txt
:language: text
```
:::

## Data structures

:::{solution} appropriate-data-structure-for-frankentext
1. According to:

   ```{literalinclude} code/frankentext.c
   :language: c
   :start-at: define
   :end-at: size_t succs_sizes
   ```
   
   - `book`
     - file explorer: 448.9 kB
     - or can be obtained in `Debug Console` after starting the program in debugging mode: `p sizeof(book)` 448930 byte
   - `tokens`
     - (`MAX_WORD_COUNT`) 15,000 pointers = 8 byte (64 bit) * 15,000 = 120,000 byte = 120 kB
   - `succs`
     - 15,000 * 7,500 pointers = 900,000,000 bytes = 900 MB
   - `succs_sizes`
     - 15,000 * 8 = 120,000 byte = 120 kB
     
   In total, our program will use about 1 GB of memory. The actual memory usage can be visualized using `htop` and searching for the process id. Process id can be found on the `Debug Console`.
1. This memory is placed mostly on the RAM. OS may put part of the memory to the virtual memory. Typically hard drive is used as virtual memory.

   If one program uses large amount of memory, then memory may become scarce. This could make the program self or other programs slower or even stop them.
1. We could reduce `MAX_WORD_COUNT` and `MAX_SUCCESSOR_COUNT`, but especially the word `the` requires many successors.

   The largest memory is used by `succs`, which we should focus on.
   
   In FrankenText, we reserve fixed amount of successors for each word, but most words have probably much less successors than `the`. Having dynamic size for each word would decrease the memory consumption.

   The same idea could be applied also to `tokens`.
   
   Two viable options and their trade-offs:
   
   1. Linked list
   2. Arrays that grow in chunks, e.g., each array starts with 16 elements, and grow by 16 elements if needed.

   Linked list is good for dynamic scenarios where deletions occur, but is slow to access elements. Dynamically grown arrays are much faster, but do not support deletion in the middle of an array, which we don't need in FrankenText.

   All in all option 2 will be probably the best performance-wise.
:::

:::{solution} implementing-a-singly-linked-list
```c
// TODO this code is not complete. I just copy pasted from the lecture.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node {
  int data;
  struct node *next;
} Node;

struct node b, c;
struct node a = {12, &b}, b = {99, &c}, c = {37, nullptr};

struct node *head = &a;

void print_elements() {
  auto address = head;
  while (address) {
    printf("%d ", address->data);
    address = address->next;
  }
}

void add_first_node(Node **head, int val) {
  //   Node n = {43, nullptr};
  Node *node_ptr = malloc(sizeof(Node));
  node_ptr->data = val;

  *head = node_ptr;
}

void insert(Node **head, size_t index, Node *nodeptr) {
  Node *current = *head;

  // for navigating to the node where we want to insert
  for (size_t i = 0; i < index; ++i)
    current = current->next;

  // We insert the node
  nodeptr->next = current->next;
  current->next = nodeptr;
}

int main() {
  print_elements();
  Node n = {10, nullptr};
  insert(&head, 2, &n);
  ;
}
```
:::

## Review problems

:::{solution} suitable-datatype-for-states-of-a-state-machine
all
:::
:::{solution} typical-layout-of-a-c-program
1. included libraries, constants, global variable & function declarations (and initialization & definitions), main, [function definitions]
1. Definition: we set the type of an identifier and allocate space for the [object](object) it represents.

   Initialization: the value stored in the storage when a program a starts.
1. Using `include` we can include functionality implemented by others. Technically `#include` includes the content of a file, i.e., function declarations (and sometimes definitions) in case of a header file.
1. It iterates over the elements of `arr` and prints each character; finally a newline at the end.
1. - `tmp` is not meaningful
   - What is `4`? 
   - `int` => `size_t`, because it is used to iterate over an array
   - `int i` can be directly declared inside the `for` below
   - `#include` should be used on the top of the file. This is a wide convention.
1. ```{mermaid}
   flowchart LR
   s( ) --> init[i = 0] --> condition{i < array size} --> body[print array i]
   body --> condition --> n[print newline] --> e( )
   ```
:::

:::{solution} flowchart-to-statement
1
:::
:::{solution} flowchart-to-statement2
2
:::

:::{solution} implementable-flowcharts
1. Contains a process that leads to two processing blocks as follows:

   ```{mermaid} img/multiprocessing.mmd
   ```
   
   Even this is possible to implement in C, it is not part of structured programming rules, which only contains (1) sequence (concatenation) (2) selection (branching), and (3) iteration (loops).
2. Contains a decision that branches to the parent decision as follows:

   ```{mermaid} img/if-branches-to-parent-if.mmd
   ```
   This can only be implemented with a `goto`
   ```c
   #include <stdlib.h>
   
   int main() {
   if1:
     if (rand() % 2) {
       if (rand() % 2)
         ;
       else
         goto if1;
     }
   }
   ```
   
3. Contains a process that has two output branches as follows:

   ```{mermaid} img/process-with-two-branches.mmd
   ```

   Output branches are only possible in decisions.
   
4. is an `if-else`
5. is an `if-else-if`
:::

:::{solution} two-dice-sum-distribution
Idea for the analytical solution:
```text
The unit occurrences for the sums:

1x 2: 11
2x 3: 12 21
3x 4: 13 22 31
..
6x 7: 16 .. 61
5x 8: 26 35 44 53 62
..
1x 12: 66

Total: 36x units
```
50000 / 36x should equal to the occurrence count of 2 or 12 in the long run. If we increase the the number of simulation, we will almost reach this number.

```{literalinclude} code/two-dice-sum-distribution.c
:language: c
```
:::

## Review problems 2

:::{solution} substitute-words-in-a-dictionary
```{literalinclude} code-wi/substitute-strings-in-dict.c
:language: c
```
:::

:::{solution} is-there-a-bug
1. `&` => `&&`.

   `&` is a bitwise operation. If `length` is 2, 4 or even in general, then the result cannot be `true`.
1. Correct. For lunch and and dinner, you eat the same
1. - There is no memory reserved for `line`.
   - `stdout` => `stdin`.
1. `puts(a > b ? "yes!" : "no!")`
1. There is no bug, just the code style is not readable. `putc`s should be better in the body of the `for` loop.
:::

## Additional exercises

:::{solution} fizzbuzz
```{literalinclude} code/fizzbuzz.c
:language: c
```
:::


:::{solution} is-there-a-bug2
1. 0-indexing, `strlen` should be used
2. `sizeof` => `strlen`, `"a"` => `'a'`
:::