Commit 5147344f authored by Guilherme Henrique's avatar Guilherme Henrique

vaio improvements now

parent 00efc10d
Pipeline #53223026 failed with stages
in 47 seconds
......@@ -16,31 +16,17 @@ styles:
# When I'm studying a new programming language or library, I always try to make a practical example to learn it.
# These projects can't be so big because they would eventually discourage me
# and not so small to only touch the surface of the tool.
A few years back, I was trying to learn Clojure, had read some books and was looking for an interesting project to apply the knowledge.
Then I remembered the project [[][MetroGit]] which consists of building a Git graph from the metro system of Paris.
In my opinion, this project is so creative and simple that the original idea could see some improvement.
So, the idea for this project is to build the git graph through shell commands with a *generic* input of lines and stations.
The lines will be branches, commit for stations and connections will be merge commits.
# A single station
# Provide the input with the metro connections and the algorithm will generate all the necessary commands to build it.
# It is based on the quote from [[][Nathaniel Borenstein]] (Originally seen it on [[][Coding Horror]]).
So, the idea for this project is to build the git graph through shell commands with some sets of lines, stations and connections.
The lines will be represented as branches, stations as stations and connections as merge commits.
# It should be noted that no ethically-trained software engineer would ever consent to write a *DestroyBaghdad* procedure.
# Basic professional ethics would instead require him to write a *DestroyCity* procedure, to which Baghdad could be given as a parameter.
# -- Nathaniel Borenstein
# Only in this case, I ethically would write the *BuildMetroCity* procedure, not *BuildMetroParis*, passing the metro stations and connections as a parameter.
# Lemme show you the journey of how to do this using Clojure
To make this process more engaging, the psot was splitted into some core sections:
1. Building the graph from the input data
2. Traversing in a way that's easier
3. Generating the git commands
* Illustration of the idea
In a nutshell, we need to transform a bunch of unknown stations and connection to a git graph.
......@@ -344,7 +330,7 @@ The traversal algorithm should make the git graph construction possible and has
It seems complicated, but we'll build each condition step by step, so it'll be easy to swallow.
** Finding the right API
** In search of the correct API
The idea is to have a function that abstracts away all these logic requirements.
Each call of the function will return the current state of the algorithm.
......@@ -492,11 +478,10 @@ Now, it's time to add the condition that, if the current node is visited, it sho
Cool. It worked for a single line, but we're not worried yet with connections
Cool. It worked for a single line for now, but we're not worried yet with connections.
** Multiple lines
Let's try to run the current state of the algorithm in a configuration with multiple lines
What if we execute the current state of the algorithm with multiple lines:
<i id="alg-5-button" class="icon-play fa-play"></i>
......@@ -506,9 +491,9 @@ Let's try to run the current state of the algorithm in a configuration with mult
When we introduce another line, a good point is that, for free, we're handling the case of non visited predecessors.
But, there is a problem that the other lines are not even considered in the algorithm.
But, after all the line is visited, the rest of the stations are not even considered.
We need to have an auxiliary data structure that will hold the nodes that are still waiting to be visited.
We need to add an auxiliary data structure which will hold the pending nodes (stations).
#+BEGIN_SRC clojure :exports result
(defn traverse-subway-graph
......@@ -545,22 +530,68 @@ We need to have an auxiliary data structure that will hold the nodes that are st
** Putting an end to the algorithm
The algorithm still doesn't have a stop case. Which means
If you try to run the algorithm in its current form, this means. We need to check the stop case of the
Let's try to run the current code to verify how it's behaving.
In practice, this would mean
#+BEGIN_EXPORT clojure exports: result
(def config [{:name "Red" :stations ["A" "B" "C"]}])
(def graph (build-graph config))
(def state1 (traverse-subway-graph {:graph graph})
;; {:current-node "A" :current-line "Red" :graph graph-1}
(def state2 (traverse-subway-graph state1))
;; {:current-node "B" :current-line "Red" :graph graph-1}
(def state3 (traverse-subway-graph state2))
;; {:current-node "C" :current-line "Red" :graph graph-1}
(def state4 (traverse-subway-graph state3))
;; {:current-node "C" :current-line "Red" :graph graph-1}
;; Ooops. this is not correct
(def state5 (traverse-subway-graph state4))
;; {:current-node "C" :current-line "Red" :graph graph-1}
;; Is this ever going to end?!
# Introducing the end variable
As with all the recursive algorithms, it still doesn't have a stop case and it will run indefinitely.
When the line doesn't have more stations or no more pending stations, we know it's time to finish the algorithm
#+BEGIN_EXPORT diff exports: result
(defn traverse-subway-graph
- (let [{:keys [graph current-node current-line pending-nodes]} state
+ (let [{:keys [graph current-node current-line pending-nodes end]} state
predecessor (metro.algorithm/find-predecessor graph current-node)
+ end nil
+ (and (empty? successors) (empty? pending-nodes))
+ (assoc state
+ :current-line (metro.graph/lines graph current-node)
+ :graph (attr/add-attr graph current-node :visited true)
+ :end true)
** Improving the interface
Although we have a functional code,
the API of the function seems weird because the "clients" of this function would have to know the concept of ~state~, ~pending-nodes~ and ~graph~.
The ideal case scenario is to encapsulate this logic into a facade function, with only the initial configuration as the input.
# Now that we have a full functional code
# Now that we defined the.
# Algorithm will decide how it should be stored
# We can use the
#+BEGIN_SRC clojure :exports result
(defun initial-state
(let [node (first (graph/nodes graph))]
{:pending-nodes () :current-node node :current-line (metro.graph/lines graph node)}))
(defun traverse-graph
(let [graph (build-subway-graph config)
initial-state (initial-state graph)]
(traverse-subway-graph initial-state)))
Algorithm will decide how it should be stored
We can use the
Check the _code_ of the traversal algorithm
* Git commands
......@@ -116,7 +116,7 @@ document.addEventListener('DOMContentLoaded', function(){
var config10 = [{name: "Green", stations: ["A", "B", "C"]},
{name: "Blue", stations: ["D", "B", "E"]}];
{name: "Red", stations: ["D", "B", "E"]}];
var graph4 = metro.animations.build_animation(containers4, config10)
......@@ -140,7 +140,7 @@ document.addEventListener('DOMContentLoaded', function(){
var config11 = [{name: "Green", stations: ["A", "B", "C"]},
{name: "Blue", stations: ["D", "B", "E"]}];
{name: "Red", stations: ["D", "B", "E"]}];
var graph5 = metro.animations.build_animation(containers5, config11)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment