# ktane-solver

A JavaScript library to solve the vanilla bomb modules from [Keep Talking and Nobody Explodes](https://keeptalkinggame.com/).


## 📥 Installing

`npm i ktane-solver`


## 📖 Terms

- **Bomb** - the device which holds an amount of modules.
- **Modules** - a device which contains a single, solvable puzzle which needs to be solved by the Defuser.
- **Needy Modules** - a device which contains a single, unsolvable puzzle which needs to be regularly tended to by the Defuser.
- **Stage** - a section or part of a module, indicated by a green LED on the right side of the module.
- **Defuser** - the person that has sole access to the bomb.
- **Expert(s)** - the person/people that has/have sole access to the Bomb Defusal Manual.
- **"bomb check"** - the process of gathering information about the bomb.
- **"display number" or "display letter"** - the big number/letter at the top of some modules.




## 💣 The Bomb object

Some modules require information about the bomb in order to solve.

- `digit: int` - the last digit of the serial code.
- `vowel: boolean` - if the serial code contains a vowel.
- `car: boolean` - if the bomb has a CAR lit indicator.
- `frk: boolean` - if the bomb has a FRK lit indicator.
- `pport: boolean` - if the bomb has a parallel port.
- `batteries: int` - the amount of batteries on the bomb.



**Methods**

- `add_strike()` - Add a strike to the bomb.
- `reset_strikes()` - Reset the bomb's strike count.
- `reset_memory()` - Reset the Memory module. This is called automatically after solving the Memory module. 
- `reset_sequence()` - Reset the Sequence module. This is called automatically after solving the Sequence module. 



**Example**

```js
let bomb = new Bomb(2, true, false, true, true, 1)
```
This creates a bomb instance that has:
- A serial code with a vowel, and an even number as the last digit
  - For example: `AWXYZ2`
- No CAR lit indicator
- A FRK lit indicator
- A parallel port
- 1 battery

---

## 🧩: Modules

More information about the modules, as well as how to solve them, can be found at the [Bomb Defusal Manual](https://www.bombmanual.com/).



### ✂️ Wires

**Input**

- `wires: Array<String>` - a String array with each wire colour.
  - Possible colours: `red`, `blue`, `yellow`, `black`, `white`
- `bomb: Object` - an instance of the bomb object.

**Output**

- `int` - The index of the wire that should be cut based on the array passed, starting from 0.

**Throws**

- If the amount of wires is incorrect.



**Example**

```javascript
import Bomb from "ktane-solver/bomb"
import Wires from "ktane-solver/wires"

let bomb = new Bomb(2, true, false, false, true, 1)

Wires.solve(["red", "blue", "blue"], bomb)

>> 2
```

---

### 🔴 Button

**Input for part 1**

- `button: String` - a String describing the button's colour and text, in that order.
  - Possible colours: `red`, `blue`, `yellow`, `black`, `white`
  - Possible texts: `abort`, `detonate`, `hold`, `press`
- `bomb: Object` - an instance of the bomb object.

**Output for part 1**

- `String` - What the Defuser should with the button after pressing it.
  - `"HOLD"` - the button should be pressed and held.
  - `"RELEASE"` - the button should be pressed and immediately released.

**Throws**

- If either `colour` or `text` are undefined.



**Input for part 2**

- `strip: String` - a String describing the colour of the strip.
  - Possible colours: `red`, `blue`, `yellow`, `white`

**Output for part 2**

- `String` When the button should be released.
  - `"1"` - the button should be released when the countdown timer has a 1 in any position.
  - `"4"` - the button should be released when the countdown timer has a 4 in any position.
  - `"5"` - the button should be released when the countdown timer has a 5 in any position.



**Examples**

*Part 1 example*

```javascript
import Bomb from "ktane-solver/bomb"
import Wires from "ktane-solver/button"

let bomb = new Bomb(2, true, false, false, true, 1)

Button.solvePartOne("red detonate", bomb)

>> "HOLD"
```



*Part 2 example*

```js
import Bomb from "ktane-solver/bomb"
import Wires from "ktane-solver/button"

let bomb = new Bomb(2, true, false, false, true, 1)

Button.solvePartTwo("blue")

>> 4
```

---

### 🔑 Keypad


**Input**
 - `symbols: Array<String>` - a String array with each symbol description
    - A list of [each symbol, and their name, can be found here](./resources/README.md).

**Output**

- `Array<String>` - The order at which the symbols should be pressed.

**Throws**

- If exactly 4 symbols aren't passed.
- If any symbol(s) aren't recognised.
- If a solution for the given symbols isn't found.




**Example**
```javascript
import Keypad from "ktane-solver/keypad"

Keypad.solve(["kitty", "curly h", "at", "reverse c"])

>> ["at", "kitty", "curly h", "reverse c"]
```

---

### 💬 Simon Says

**Input**

- `colours: Array<String>`  - a String array with each colour.
  - Possible colours: `red`, `blue`, `yellow`, `green`
- `bomb: Object` - an instance of the bomb object.

**Output**

- `Array<String>` - The colours that the Defuser should press, in order.



**Example**

```js
import Bomb from "ktane-solver/bomb"
import SimonSays from "ktane-solver/simonsays"

let bomb = new Bomb(2, true, false, false, true, 1)

SimonSays.solve(["red", "red", "blue"], bomb)

>> [ "blue", "blue", "red" ]
```

---

### 🗒️ Who's On First

**Input**

- `word: String` - the display word.

**Output for part 1**

- `String` - The position of the word on the module, that should be the input for part 2.
  - Possible positions: `TL` (top left), `TR` (top right), `ML` (middle left), `MR` (middle right), `BL` (bottom left), `BR` (bottom right)

**Throws**

- If a word is unrecognised.



**Input for part 2**

- `word: String` - the word, based on the position output from part 1.

**Output for part 2**

- `String` - A list of possible words, in order. The first word that both appears on the list, and on the module, should be pressed by the Defuser.

**Throws**

- If a word is unrecognised.



**Examples**

*Part 1 example*

```js
import WhosOnFirst from "ktane-solver/whosonfirst"

WhosOnFirst.solvePartOne("says")

>> "BR"
```



*Part 2 example*

```js
import WhosOnFirst from "ktane-solver/whosonfirst"

WhosOnFirst.solvePartTwo("right")

>> "YES, NOTHING, READY, PRESS, NO, WAIT, WHAT, RIGHT"
```

---

### 🧠 Memory

**Input**

- `numbers: Array<int>` -  an int array of the module's numbers, starting with the display number, and numbers below, in order from left-to-right.
- `bomb: Object` - an instance of the bomb object.

**Output**

- `int` - The label of the button that the Defuser should press.

**Throws**

- If the passed array has more than 5 elements.
- If the passed array contains a number that isn't 1, 2, 3, or 4.



**Notes**

- This module requires knowledge of previous stages, which is held in the bomb object. Make sure to pass the same bomb object in for each stage.
- This module will automatically call `reset_memory()` after the module is solved. You can call this method prematurely if required.


**Example**

```js
import Bomb from "ktane-solver/bomb"
import Memory from "ktane-solver/memory"

let bomb = new Bomb(2, true, false, false, true, 1)

Memory.solve([4,1,3,4,2], bomb)
Memory.solve([3,3,1,2,4], bomb)
Memory.solve([4,3,1,2,4], bomb)
Memory.solve([2,2,4,1,3], bomb)
Memory.solve([2,2,4,1,3], bomb)

>> 2
>> 3
>> 4
>> 2
>> 3
```

 ---

### 💡 Morse Code

**Input**

- `morse: Array<String>` -  a String array of Morse Code characters.

**Output**

- `Array<String>` - A list of the possible words, given the input;
- `String` - OR the frequency that should be selected.

**Throws**

- If the translated word doesn't match to a frequency.



**Example**

```js
import Morse from "ktane-solver/morse"

Morse.solve(["dot dot dot", "dot dot dot dot", "dot", "dot dash dot dot", "dot dash dot dot"])

>> 3.505
```

---

### 🐍 Complicated Wires

**Input**

- `wires: Array<String>` - a String array describing the wire colour(s), if there's a star, and if the light is on.
  - Possible colours, up to 2 at once: `red`, `white`, `blue`
- `bomb: Object` an instance of the bomb object.

**Output**

- `Array<boolean>` - A list of Booleans describing if each wire should be cut.
  - `true` - cut the wire.
  - `false` - don't cut the wire.

**Throws**

- If a colour is unrecognised.



**Notes**

- If there's no star, you don't need to include "star" in the wire description.

- If the light isn't on, you don't need to include "light" in the wire description.

- The order of each wire description doesn't matter. i.e. `light red star`, `red star light`, and `star light red` are all equivalent and valid inputs.

- The order of each wire colour doesn't matter. i.e. `red blue` and `blue red` are the both equivalent and valid inputs.



**Example**

```js
import Bomb from "ktane-solver/bomb"
import Complicated from "ktane-solver/complicated"

let bomb = new Bomb(2, true, false, false, true, 1)

Complicated.solve(["white star", "red star", "red star", "blue star", "light blue star", "light red white star"], bomb)

>> [ true, true, true, false, true, false ]
```

---

### 🌽 Maze

**Input**

- `ind: Array<int>` - an int array of the position of either green indicator.
- `start: Array<int>` - an int array of the position of the white light.
- `end: Array<int>` - an int array of the position of the red triangle.

**Output**

- `Array<String>` - A list of directions that the Defuser should input into the module.
  - Possible directions: `UP`, `DOWN`, `LEFT`, `RIGHT`

**Throws**

- If the green indicator is unrecognised.



**Notes**

- Each position counts from 1.
- The position follows the following notation: across first, then down.
- Only one green indicator is required to identify the correct maze.
- This solution uses a modified version of [this maze-solving algorithm](https://stackoverflow.com/a/52146134/12865020). Thank you trincot.



**Example**

```js
import Maze from "ktane-solver/maze"

Maze.solve([3, 5], [6, 4], [1, 5])

>> ['DOWN', 'LEFT', 'UP', 'UP', 'RIGHT', 'UP', 'UP', 'LEFT', 'DOWN', 'LEFT', 'DOWN', 'DOWN', 'DOWN', 'DOWN', 'LEFT', 'LEFT', 'LEFT', 'UP'
]
```

*Based on this maze configuration:*

![](/resources/mazeexample.png)

---

### 🌈 Wire Sequence

**Input**

- `wires: Array<String>` - a String array describing the wire colour, and the letter it routes to.
  - Possible colours: `red`, `black`, `blue`
  - Possible letters: `A`, `B`, `C`
- `bomb: Object` an instance of the bomb object.

**Output**

- `Array<boolean>` - A list of Booleans describing if each wire should be cut.
  - `true` - cut the wire.
  - `false` - don't cut the wire.

**Throws**

- If a colour is unrecognised.
- If a letter is unrecognised.



**Notes**

- The number on the left side of the module is not required to solve. 
- This module requires knowledge of previous stages, which is held in the bomb object. Make sure to pass the same bomb object in for each stage.
- This module will automatically call `reset_sequence()` after the module is solved. You can call this method prematurely if required.


**Example**

```js
import Bomb from "ktane-solver/bomb"
import Sequence from "ktane-solver/sequence"

let bomb = new Bomb(2, true, false, false, true, 1)

Sequence.solve(["black a", "black b"], bomb)
Sequence.solve(["red c", "red a", "red c"], bomb)
Sequence.solve(["red a"], bomb)
Sequence.solve(["blue b", "red a", "blue b"], bomb)

>> [ true, false ]
>> [ true, false, false ]
>> [ true ]
>> [ true, false, false ]
```

---

### ⌨️ Password

**Input**

- `columns: Array<String>` - a String array describing each letter in each column.

**Output**

- `Array<String>` - A list of the possible passwords

**Throws**

- If the passed array isn't exactly 5 elements long (pad your input with empty strings, if needs be).

**Notes**

- Partial inputs (empty strings) are accepted.
- Check if the returned array's length is 1 to determine the password.

**Examples**

```js
import Password from "ktane-solver/password"

Password.solve(["kqtfhy", "hwjfus", "rinybk", "ynukj", "ipkxvc"])

>> ["THINK"]
```

```js
import Password from "ktane-solver/password"

Password.solve(["tghus", "", "", "", "tnehr"])

>> [ "GREAT", "HOUSE", "THEIR", "THERE", "THESE", "THREE" ]
```

---

## 🍞 Needy Modules

Only one module, Knob, requires any logic. Venting Gas, and Capacitor Discharge can be handled by the Defuser.



### 🎛️ Knob

**Input**

- `lights: String` - the condition of each light.
  - `1` - the light is on.
  - `0` - the light is off.

**Output**

- `String` - The direction that the knob should be pointed.

**Throws**

- If a light sequence is unrecognised.



**Notes**

- Only the left-hand side of the lights are required to solve this module.
- The order should be left-to-right, top-to-bottom.



**Example**

```js
import Knob from "ktane-solver/knob"

Knob.solve("101111")

>> RIGHT
```
