--- /dev/null
+
+#include "libft.h"
+#include <stdlib.h>
+
+// zkrat means short circuit in my language. I opted for this because
+// C does not permit short (it is type) and short_circuit was too long
+typedef enum e_state
+{
+ off,
+ on,
+ pull_down,
+ pull_up,
+ floating,
+ zkrat,
+ unknown,
+} t_state;
+
+typedef enum e_terminal
+{
+ source,
+ drain,
+ gate,
+} t_terminal;
+
+typedef struct s_node
+{
+ int checked;
+ t_state state;
+ t_state set_state;
+ t_vec connected;
+} t_node;
+
+typedef enum e_type
+{
+ p = 'p',
+ n = 'n',
+} t_type;
+
+typedef struct s_mosfet
+{
+ int is_opened;
+ t_type type;
+ t_node *gate;
+ t_node *source;
+ t_node *drain;
+} t_mosfet;
+
+/* Monospace table of state resolution
+ * s2 \ s1 | short | off | on | pull_d | pull_u | float | unknown
+ * --------|-------|-------|-------|--------|--------|--------|---------
+ * short | short | short | short | short | short | short | short
+ * --------|-------|-------|-------|--------|--------|--------|---------
+ * off | short | off | short | off | off | off | off
+ * --------|-------|-------|-------|--------|--------|--------|---------
+ * on | short | short | on | on | on | on | on
+ * --------|-------|-------|-------|--------|--------|--------|---------
+ * pull_d | short | off | on | pull_d | pull_d | pull_d | pull_d
+ * --------|-------|-------|-------|--------|--------|--------|---------
+ * pull_u | short | off | on | pull_d | pull_u | pull_u | pull_u
+ * --------|-------|-------|-------|--------|--------|--------|---------
+ * float | short | off | on | pull_d | pull_u | float | float
+ * --------|-------|-------|-------|--------|--------|--------|---------
+ * unknown | short | off | on | pull_d | pull_u | float | unknown
+ *
+ * It may be possible to construct the enum e_state in such a way that
+ * this function is easy arithmetics.
+ */
+t_state simple_resolve_state(t_state s1, t_state s2)
+{
+ if (s1 == s2)
+ return (s1);
+ if (s1 == zkrat || s2 == zkrat)
+ return (zkrat);
+ if ((s1 == off && s2 == on) || (s1 == on && s2 == off))
+ return (zkrat);
+ if (s1 == on || s2 == on)
+ return (on);
+ if (s1 == off || s2 == off)
+ return (off);
+ if (s1 == pull_down || s2 == pull_down)
+ return (pull_down);
+ if (s1 == pull_up || s2 == pull_up)
+ return (pull_up);
+ if (s1 == floating || s2 == floating)
+ return (floating);
+ return (unknown);
+}
+
+t_state resolve_state(t_vec *connected_nodes)
+{
+ size_t i;
+ t_state state;
+ t_node *node;
+
+ i = 0;
+ state = unknown;
+ while (i < connected_nodes->size)
+ {
+ node = *(t_node **)ft_vec_access(connected_nodes, i);
+ state = simple_resolve_state(state, node->set_state);
+ ++i;
+ }
+ return (state);
+}
+
+t_node *get_neighbour_node(const t_mosfet *mosfet, const t_node *start)
+{
+ if (mosfet->source == start)
+ return (mosfet->drain);
+ return (mosfet->source);
+}
+
+void find_connected(t_node *node, t_vec *connected_nodes)
+{
+ size_t i;
+ t_node *neigh_node;
+ t_mosfet *mosfet;
+
+ if (node->checked)
+ return ;
+ node->checked = 1;
+ ft_vec_append(connected_nodes, &node);
+ i = 0;
+ while (i < node->connected.size)
+ {
+ mosfet = *(t_mosfet **)ft_vec_access(&node->connected, i);
+ if (mosfet->is_opened)
+ {
+ neigh_node = get_neighbour_node(mosfet, node);
+ find_connected(neigh_node, connected_nodes);
+ }
+ ++i;
+ }
+ return ;
+}
+
+void apply_state(t_state state, t_vec *connected_nodes)
+{
+ size_t i;
+ t_node *node;
+
+ i = 0;
+ while (i < connected_nodes->size)
+ {
+ node = *(t_node **)ft_vec_access(connected_nodes, i);
+ node->state = state;
+ ++i;
+ }
+ return ;
+}
+
+t_state reduce_state(t_state state)
+{
+ if (state == pull_down)
+ return (off);
+ if (state == pull_up)
+ return (on);
+ if (state == unknown)
+ return (floating);
+ return (state);
+}
+
+void update_nodes(t_vec *nodes)
+{
+ size_t i;
+ t_state state;
+ t_node *cur_node;
+ t_vec connected_nodes;
+
+ ft_vec_init(&connected_nodes, sizeof(t_node *));
+ i = 0;
+ while (i < nodes->size)
+ {
+ cur_node = ft_vec_access(nodes, i);
+ if (!cur_node->checked)
+ {
+ find_connected(cur_node, &connected_nodes);
+ state = resolve_state(&connected_nodes);
+ apply_state(reduce_state(state), &connected_nodes);
+ ft_vec_forget_range(&connected_nodes, connected_nodes.size, 0);
+ }
+ ++i;
+ }
+ ft_vec_free(&connected_nodes, NULL);
+ return ;
+}
+
+void update_mosfet(t_mosfet *mosfet)
+{
+ t_state state;
+
+ state = mosfet->gate->state;
+ if (mosfet->type == p && state == on)
+ mosfet->is_opened = 1;
+ else if (mosfet->type == n && state == off)
+ mosfet->is_opened = 1;
+ else
+ mosfet->is_opened = 0;
+ return ;
+}
+
+void update_mosfets(t_vec *mosfets)
+{
+ size_t i;
+ t_mosfet *mosfet;
+
+ i = 0;
+ while (i < mosfets->size)
+ {
+ mosfet = ft_vec_access(mosfets, i);
+ update_mosfet(mosfet);
+ ++i;
+ }
+ return ;
+}
+
+void reset_nodes(t_vec *nodes)
+{
+ size_t i;
+ t_node *node;
+
+ i = 0;
+ while (i < nodes->size)
+ {
+ node = ft_vec_access(nodes, i);
+ node->checked = 0;
+ ++i;
+ }
+ return ;
+}
+
+// memset is used to initialize struct padding
+void add_node(t_vec *nodes, t_state set_state)
+{
+ t_node node;
+
+ ft_memset(&node, 0, sizeof(node));
+ node.checked = 0;
+ node.state = set_state;
+ node.set_state = set_state;
+ ft_vec_init(&node.connected, sizeof(t_mosfet *));
+ ft_vec_append(nodes, &node);
+ return ;
+}
+
+void add_mosfet(t_vec *mosfets, t_type type)
+{
+ t_mosfet mosfet;
+
+ mosfet.is_opened = 0;
+ mosfet.type = type;
+ mosfet.gate = NULL;
+ mosfet.drain = NULL;
+ mosfet.source = NULL;
+ ft_vec_append(mosfets, &mosfet);
+ return ;
+}
+
+void bind_fet_node(t_mosfet *mosfet, t_node *node, t_terminal terminal)
+{
+ t_node *old;
+ size_t index;
+
+ old = NULL;
+ if (terminal == source)
+ {
+ old = mosfet->source;
+ mosfet->source = node;
+ ft_vec_append(&node->connected, &mosfet);
+ }
+ else if (terminal == drain)
+ {
+ old = mosfet->drain;
+ mosfet->drain = node;
+ ft_vec_append(&node->connected, &mosfet);
+ }
+ else
+ {
+ mosfet->gate = node;
+ }
+ if (old && ft_vec_find_index(&old->connected, &mosfet, &index) == success)
+ {
+ ft_vec_forget(&old->connected, index);
+ }
+ return ;
+}
+
+void build_graph(__attribute__((unused)) const char *filename, t_vec *nodes, t_vec *mosfets)
+{
+ add_node(nodes, off);
+ add_node(nodes, off);
+ add_node(nodes, pull_up);
+ add_mosfet(mosfets, p);
+ bind_fet_node(ft_vec_access(mosfets, 0), ft_vec_access(nodes, 0), gate);
+ bind_fet_node(ft_vec_access(mosfets, 0), ft_vec_access(nodes, 1), drain);
+ bind_fet_node(ft_vec_access(mosfets, 0), ft_vec_access(nodes, 2), source);
+ return ;
+}
+
+void free_node(void *node)
+{
+ ft_vec_free(&((t_node *)node)->connected, NULL);
+ return ;
+}
+
+const char *state_color_escape(t_state state)
+{
+ if (state == on)
+ return ("\033[32m");
+ if (state == off)
+ return ("\033[39m");
+ if (state == floating)
+ return ("\033[34m");
+ return ("\033[31m");
+}
+
+void draw(t_vec *nodes, t_vec *mosfets)
+{
+ size_t i;
+ size_t index;
+ t_mosfet *mosfet;
+ const char default_color[] = "\033[39m";
+
+ i = 0;
+ ft_printf("\n");
+ while (i < mosfets->size)
+ {
+ mosfet = ft_vec_access(mosfets, i);
+ ft_vec_find_index(nodes, mosfet->source, &index);
+ ft_printf(" %u\n", index);
+ ft_printf(" %s|%s\n", state_color_escape(mosfet->source->state), default_color);
+ ft_vec_find_index(nodes, mosfet->gate, &index);
+ ft_printf("%u%s--%s%c\n", index, state_color_escape(mosfet->gate->state), default_color, mosfet->type);
+ ft_printf(" %s|%s\n", state_color_escape(mosfet->drain->state), default_color);
+ ft_vec_find_index(nodes, mosfet->drain, &index);
+ ft_printf(" %u\n\n", index);
+ ++i;
+ }
+ return ;
+}
+
+int take_input(__attribute__((unused)) t_vec *nodes,__attribute__((unused)) t_vec *mosfets)
+{
+ int res;
+ char *input;
+
+ ft_printf("FET_sim>");
+ input = get_next_line(0);
+ res = 0;
+ if (input && (input[0] == n || (!ft_strncmp(input, "next", 4))))
+ res = 1;
+ free(input);
+ return (res);
+}
+
+int main(__attribute__((unused)) int argc, char **argv)
+{
+ int run;
+ t_vec nodes;
+ t_vec mosfets;
+
+ ft_vec_init(&nodes, sizeof(t_node));
+ ft_vec_init(&mosfets, sizeof(t_mosfet));
+ build_graph(argv[1], &nodes, &mosfets);
+ run = 1;
+ while (run)
+ {
+ update_nodes(&nodes);
+ draw(&nodes, &mosfets);
+ update_mosfets(&mosfets);
+ reset_nodes(&nodes);
+ ((t_node *)ft_vec_access(&nodes, 0))->set_state = on;
+ run = take_input(&nodes, &mosfets);
+ }
+ ft_vec_free(&nodes, free_node);
+ ft_vec_free(&mosfets, NULL);
+ return (0);
+}