Emacs Literate Programming - Advent of Code
Tags: javascript, typescript, emacs, literateprogramming
Published: 2023-06-07 17:53:08


### Table of Contents

1.  [First step](#org805bf2a)
2.  [The Problem](#org86b16b0)
3.  [Solution - Part 1](#orgd410e4d)
4.  [Solution - Part 2](#org43d42e9)
5.  [Conclusion](#org47a4ad3)

Literate programming is a cool way to intergrate natural language into the source code for the explanation rather than using comments.
It was introuduced by [Donald Knuth](https://en.wikipedia.org/wiki/Donald_Knuth). 

Emacs has an interesting way to achieve this, I haven't really seen it being used anywhere else than for configuring emacs itself,
so as an example let's solve [Advent of Code 2022 (Day 2)](https://adventofcode.com/2022/day/2), using emacs org literate programming, for this the language of my choice is typescript.

I am not really good at typescript, so bear in mind that my code might not be follwing the standards.


<a id="org805bf2a"></a>

## First step

Let's create a file named "day2.ts" and initialize the neccessary configs for the typescript file,

``` 
npm init -y
tsc -init
```

Create a file with ".org" extension, this will be recognized as an standard emacs org doc, and add this line below,

``` emacs-lisp
#+begin_src :tangle day2.ts 
  console.log("Hello Literate !"); 
#+end_src
```

invoke the command "org-babel-tangle" using the "alt-x" or "C-c C-v t", and when you open the "day2.ts" file you should see the codeblock written from the org file into it.

if everything goes well then, we are set to solve the problem.


<a id="org86b16b0"></a>

## The Problem

The gist of the problem is that we are competing with a elf on a rock-paper-scissors match,

    A -> Rock
    B -> Paper
    C -> Scissors
    
    X -> Rock
    Y -> Paper
    Z -> Scissors 

the points for the match is calculated on the basis of the shape you select,

    Rock -> 1
    Paper -> 2
    Scissors -> 3
    
    and the outcome,
    
    Draw -> 3
    Lost -> 0
    Win -> 6


<a id="orgd410e4d"></a>

## Solution - Part 1

let's import the fs module to read the "input.txt" file and store the data into a variable,

``` typescript
    import fs from "fs";
    
    const data = fs.readFileSync("./input.txt", "utf8").toString();
```

we can use enums to define the points and the hand, and pattern matching object to use later on,

``` typescript
    enum HAND {
      X = "rock",
      Y = "paper",
      Z = "scissors",
      A = "rock",
      B = "paper",
      C = "scissors"
    }
    
    enum HAND_POINTS {
      rock = 1,
      paper = 2,
      scissors = 3
    }
    
    enum GAME_POINTS {
      WIN = 6,
      DRAW = 3,
      LOST = 0
    }
    
    const pattern = {
     "rock paper": "win",
     "paper scissors": "win",
     "scissors rock": "win",
     "scissors scissors": "draw",
     "paper paper": "draw",
     "rock rock": "draw",
     "paper rock": "lose",
     "scissors paper": "lose",
     "rock scissors": "lose",
    }
```

now that we have the data, let's split the string into a list,

``` typescript
    const games = data.split("\n").map((str) => str.replace(/\r/g, "")).filter(Boolean);
```

The pointReturn function takes a single game match and returns the
point that the player wins,

``` typescript
    function pointReturn(games: string[]): number {
      let counter = 0;
      for(const match of games){
        const game = match.split(" ");
        const opponentHand = HAND[game[0] as keyof typeof HAND];
        const playerHand = HAND[game[1] as keyof typeof HAND];
        const playerPoint = HAND_POINTS[playerHand as keyof typeof HAND_POINTS];
        const opponentPoint = HAND_POINTS[opponentHand as keyof typeof HAND_POINTS]
        const moveset: string = [opponentHand, playerHand].join(" ");
    
        if (pattern[moveset] == "win") {
          counter += GAME_POINTS.WIN + playerPoint;
        } else if (pattern[moveset] == "draw") {
          counter += GAME_POINTS.DRAW + playerPoint;
        } else if(pattern[moveset] == "lose") {
          counter += GAME_POINTS.LOST + playerPoint;
        }
       }
    
      return counter;
     }
```

finally we can return the data and log it,

``` typescript
    const points = pointReturn(games);
    console.log(points)
```

<a id="org43d42e9"></a>

## Solution - Part 2

In part two of the problem, we need to make sure that we lose and win
in only particluar situaions.

if "X" then lose, "Y" Draw and "Z" is win, this ensures that we don't
get found out as a cheater.

The function below takes the input data and accoriding to the rules
changes the player input i.e our turn data into the one that is according
to the strategy.

``` typescript
    function strategizeInput(game: string[]){
      let newInput = [];
      for(const match of game){
        const [opponent, player] = match.split(" ");
        if(player == "X" && opponent == "A"){
         newInput.push([opponent, "Z"].join(" ")); 
        } else if(player == "X" && opponent == "B") {
          newInput.push([opponent, "X"].join(" ")); 
        } else if(player == "X" && opponent == "C") {
          newInput.push([opponent, "Y"].join(" "));
        }else if(player == "Y" && opponent == "A") {
          newInput.push([opponent, "X"].join(" "));
        } else if(player == "Y" && opponent == "B") {
          newInput.push([opponent, "Y"].join(" "));
        } else if(player == "Y" && opponent == "C") {
          newInput.push([opponent, "Z"].join(" "));
        } else if(player == "Z" && opponent == "A") {
          newInput.push([opponent, "Y"].join(" "));
        } else if(player == "Z" && opponent == "B") {
          newInput.push([opponent, "Z"].join(" "));
        } else if(player == "Z" && opponent == "C") {
          newInput.push([opponent, "X"].join(" "));
        }
      }
    
      return newInput;
    }
    
    console.log(pointReturn(strategizeInput(games)));
```

<a id="org47a4ad3"></a>


## Conclusion

Emacs org babel is a fun way to do literate programming, especially
for documenting the emacs configuration, other than that I am not
very sure how to use it rather than maybe for learning a topic
while writing the code and documenting your thougths at the same time.

A few things I found annoying while doing this exercise is that the
code blocks typically don't have "warnings" to indicate if you're
doing something wrong and I had to keep reviweing the code in the
"day2.ts" file, other than that it was a really interesting way to
solve this problem, it allowed me to express my ideas more while writing, more than the feeling of coding, it felt like I was writing an explanation for someone else to learn.

If you are viewing it in my [blog](https://andrew-lc-blog.vercel.app/post/emacs-literate-programming) this means that the entire document is the actual source code for the "problem" and for [dev.to](https://dev.to/) I used the org to markdown plugin in emacs to post it here.

[Github Repo](https://github.com/Andrew-LC/advent-of-code-solutions/)