Add basic commands and refactor the code
authorLukáš Jiřiště <gymnazium.jiriste@gmail.com>
Sun, 14 Jan 2024 16:34:41 +0000 (17:34 +0100)
committerLukáš Jiřiště <gymnazium.jiriste@gmail.com>
Sun, 14 Jan 2024 16:34:41 +0000 (17:34 +0100)
Implement parsing of basic commands (help, next, add...)
 -Mostly (?) as wrapper around function from previous commit
 -It should be possible to do it in a much better way
Give the project some structure
 -split main.c
 -create src and inc directories

19 files changed:
Libft
Makefile
TODO
inc/FET_sim.h [new file with mode: 0644]
main.c [deleted file]
src/build_helper.c [new file with mode: 0644]
src/c_addfet.c [new file with mode: 0644]
src/c_addnode.c [new file with mode: 0644]
src/c_bind.c [new file with mode: 0644]
src/c_draw.c [new file with mode: 0644]
src/c_help.c [new file with mode: 0644]
src/c_next.c [new file with mode: 0644]
src/c_setnode.c [new file with mode: 0644]
src/colors.c [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/sim_main.c [new file with mode: 0644]
src/sim_node.c [new file with mode: 0644]
src/sim_state.c [new file with mode: 0644]
src/text.c [new file with mode: 0644]

diff --git a/Libft b/Libft
index 2447a14f38be8e2de8f3984dc708800b36f36c98..988bd412d9b3d0681457c4c169d398c273d0c6ff 160000 (submodule)
--- a/Libft
+++ b/Libft
@@ -1 +1 @@
-Subproject commit 2447a14f38be8e2de8f3984dc708800b36f36c98
+Subproject commit 988bd412d9b3d0681457c4c169d398c273d0c6ff
index dbc9185105b7ee702937a9f81a85f182bd3287d4..4267c89c3a4c7f68519d32f95b47a19a53ca4668 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -5,11 +5,33 @@ RM := rm -f
 
 SUBPROJECTS := Libft
 
-INCDIR := .
+INCDIR := inc
 INCDIR += $(addsuffix /inc, $(SUBPROJECTS));
 INCLUDE := $(addprefix -I, $(INCDIR))
 
-SOURCES := main.c
+SRCDIR := src
+
+SOURCES :=     main.c                  \
+                                                       \
+                       sim_main.c              \
+                       sim_node.c              \
+                       sim_state.c             \
+                                                       \
+                       text.c                  \
+                       colors.c                \
+                                                       \
+                       build_helper.c  \
+                                                       \
+                       c_addnode.c             \
+                       c_addfet.c              \
+                       c_setnode.c             \
+                       c_bind.c                \
+                       c_draw.c                \
+                       c_next.c                \
+                       c_help.c                \
+
+SOURCES := $(addprefix $(SRCDIR)/, $(SOURCES))
+
 OBJECTS := $(SOURCES:.c=.o)
 
 NAME := FET_sim
diff --git a/TODO b/TODO
index eb13eec8103f1d0d30fcd73ef71608cd7d49551d..25d04891af32ae7d7a6164c80d42afb0280f39e1 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,10 +1,15 @@
 TODO
+rewrite t_fet and t_node to store indexes insted of pointers to connected parts
+rewrite command parsing (what I've created is just ugly)
+come up with better file structure
 create language to write circuits in (circuit language?) (something like MHRD language?)
 implement circuit builder that converts circuit language to FET_sim representation in order to simulate
-expand simulator commands
+add even more simulation commands(eg. delete node/fet)
 test the project
 improve simulator io (maybe add graphics?)
 optimize
+pass 42 norminette
 
 DONE
 foundations of logic
+expand simulator commands
diff --git a/inc/FET_sim.h b/inc/FET_sim.h
new file mode 100644 (file)
index 0000000..612fc5d
--- /dev/null
@@ -0,0 +1,127 @@
+#ifndef FET_SIM_H
+# define FET_SIM_H
+
+# include "libft.h"
+
+# define MAX_ARGS 3
+
+// 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;
+
+typedef enum e_command
+{
+       none,
+       next,
+       draw,
+       setnode,
+       addfet,
+       addnode,
+       bind,
+       help,
+       exitsim,
+}      t_command;
+
+typedef enum e_arg_type
+{
+       num,
+       terminal,
+       state,
+       type,
+       command,
+}      t_arg_type;
+
+typedef union u_arg_val
+{
+       size_t          num;
+       t_terminal      terminal;
+       t_state         state;
+       t_type          type;
+       t_command       command;
+}                              t_arg_val;
+
+typedef struct s_arg
+{
+       t_arg_type      type;
+       t_arg_val       val;
+}                              t_arg;
+
+typedef struct s_input
+{
+       t_command       command;
+       size_t          argc;
+       t_arg           argv[MAX_ARGS];
+}                              t_input;
+
+
+void   add_node(t_vec *nodes, t_state set_state);
+void   add_mosfet(t_vec *mosfets, t_type type);
+void   bind_fet_node(t_mosfet *mosfet, t_node *node, t_terminal terminal);
+
+void   free_node(void *node);
+int            process_input(t_vec *nodes, t_vec *mosfets);
+int            get_input(t_input *input);
+
+const char     *state_color_escape(t_state state);
+void           draw_single(t_vec *nodes, t_vec *mosfets, size_t i);
+
+void   update_nodes(t_vec *nodes);
+int            sim_step(t_vec *nodes, t_vec *mosfets);
+
+void   print_start(void);
+void   command_not_found(const char *input);
+void   print_help(t_command c);
+void   print_index_error(size_t index, size_t size);
+
+t_state        simple_resolve_state(t_state s1, t_state s2);
+t_state        resolve_state(t_vec *connected_nodes);
+void   apply_state(t_state state, t_vec *connected_nodes);
+t_state        reduce_state(t_state state);
+
+int    c_addfet(t_input input, t_vec *mosfets);
+int    c_addnode(t_input input, t_vec *nodes);
+int    c_bind(t_input input, t_vec *nodes, t_vec *mosfets);
+int    c_draw(t_input input, t_vec *nodes, t_vec *mosfets);
+int    c_help(t_input input);
+int    c_next(t_input input, t_vec *nodes, t_vec *mosfets);
+int    c_setnode(t_input input, t_vec *nodes);
+#endif //FET_SIM_H
diff --git a/main.c b/main.c
deleted file mode 100644 (file)
index aea46bb..0000000
--- a/main.c
+++ /dev/null
@@ -1,378 +0,0 @@
-
-#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);
-}
diff --git a/src/build_helper.c b/src/build_helper.c
new file mode 100644 (file)
index 0000000..20a9f7d
--- /dev/null
@@ -0,0 +1,58 @@
+#include "FET_sim.h"
+#include "libft.h"
+
+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 ;
+}
+
+// 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 ;
+}
diff --git a/src/c_addfet.c b/src/c_addfet.c
new file mode 100644 (file)
index 0000000..6ce663b
--- /dev/null
@@ -0,0 +1,27 @@
+#include "FET_sim.h"
+#include "libft.h"
+
+int    c_addfet(t_input input, t_vec *mosfets)
+{
+       size_t  i;
+
+       if (input.argc == 1 && input.argv[0].type == type)
+       {
+               add_mosfet(mosfets, input.argv[0].val.type);
+               ft_printf("Index of added FET: %u\n", mosfets->size - 1);
+       }
+       else if (input.argc == 2 && input.argv[0].type == type && input.argv[1].type == num)
+       {
+               i = 0;
+               ft_printf("Index of added FETs:\n\t");
+               while (i < input.argv[1].val.num)
+               {
+                       ft_printf("%u ", mosfets->size);
+                       add_mosfet(mosfets, input.argv[0].val.type);
+                       ++i;
+               }
+       }
+       /*else
+               print_wrong_usage(input);*/
+       return (1);
+}
diff --git a/src/c_addnode.c b/src/c_addnode.c
new file mode 100644 (file)
index 0000000..d98efc2
--- /dev/null
@@ -0,0 +1,46 @@
+#include "FET_sim.h"
+#include "libft.h"
+
+static int add_nodes(t_vec *nodes, size_t num, t_state state)
+{
+       size_t  i;
+
+       i = 0;
+       ft_printf("Indexes of added nodes:\n\t");
+       while (i < num)
+       {
+               ft_printf("%u ", nodes->size);
+               add_node(nodes, state);
+               ++i;
+       }
+       ft_printf("\n");
+       return (1);
+}
+
+int    c_addnode(t_input input, t_vec *nodes)
+{
+       size_t  new_nodes_num;
+       t_state set_state;
+
+       /*if (input.argc > 2
+                       || (input.argc == 1
+                               && input.argv[0].type != num && input.argv[0].type != state)
+                       || (input.argc == 2
+                               && (input.argv[0].type != state || input.argv[1].type != num)))
+       {
+               print_wrong_usage(input);
+               return (1);
+       }*/
+       new_nodes_num = 1;
+       set_state = unknown;
+       if (input.argc == 1 && input.argv[0].type == state)
+               set_state = input.argv[0].val.state;
+       else if (input.argc == 1)
+               new_nodes_num= input.argv[0].val.num;
+       else if (input.argc == 2)
+       {
+               set_state = input.argv[0].val.state;
+               new_nodes_num = input.argv[1].val.num;
+       }
+       return (add_nodes(nodes, new_nodes_num, set_state));
+}
diff --git a/src/c_bind.c b/src/c_bind.c
new file mode 100644 (file)
index 0000000..87e412d
--- /dev/null
@@ -0,0 +1,21 @@
+#include "FET_sim.h"
+#include "libft.h"
+
+int    c_bind(t_input input, t_vec *nodes, t_vec *mosfets)
+{
+       t_node          *node;
+       t_mosfet        *mosfet;
+       t_terminal      term;
+
+       /*if (input.argc != 3 || input.argv[0].type != num
+                       || input.argv[1].type != num || input.argv[2].type != terminal)
+       {
+               print_wrong_usage(input);
+               return (1);
+       }*/
+       node = ft_vec_access(nodes, input.argv[0].val.num);
+       mosfet = ft_vec_access(mosfets, input.argv[1].val.num);
+       term = input.argv[2].val.terminal;
+       bind_fet_node(mosfet, node, term);
+       return (1);
+}
diff --git a/src/c_draw.c b/src/c_draw.c
new file mode 100644 (file)
index 0000000..b9d354c
--- /dev/null
@@ -0,0 +1,26 @@
+#include "FET_sim.h"
+#include "libft.h"
+
+int    c_draw(t_input input, t_vec *nodes, t_vec *mosfets)
+{
+       size_t  i;
+
+       if (input.argc == 0)
+       {
+               i = 0;
+               while (i < mosfets->size)
+               {
+                       draw_single(nodes, mosfets, i);
+                       ++i;
+               }
+       }
+       else if (input.argc == 1 && input.argv[0].type == num)
+       {
+               draw_single(nodes, mosfets, input.argv[0].val.num);
+       }
+       /*else
+       {
+               print_wrong_usage(input);
+       }*/
+       return (1);
+}
diff --git a/src/c_help.c b/src/c_help.c
new file mode 100644 (file)
index 0000000..3ebad7f
--- /dev/null
@@ -0,0 +1,12 @@
+#include "FET_sim.h"
+
+int    c_help(t_input input)
+{
+       if (input.argc == 0)
+               print_help(none);
+       else if (input.argc == 1 && input.argv[0].type == command)
+               print_help(input.argv[0].val.command);
+       /*else
+               print_wrong_usage(input);*/
+       return (1);
+}
diff --git a/src/c_next.c b/src/c_next.c
new file mode 100644 (file)
index 0000000..2bf6a81
--- /dev/null
@@ -0,0 +1,28 @@
+#include "FET_sim.h"
+#include "libft.h"
+
+int    c_next(t_input input, t_vec *nodes, t_vec *mosfets)
+{
+       size_t  i;
+
+       if (input.argc == 0)
+       {
+               if (!sim_step(nodes, mosfets))
+                       return (0);
+       }
+       else if (input.argc == 1 && input.argv[0].type == num)
+       {
+               i = 0;
+               while (i < input.argv[0].val.num)
+               {
+                       if (!sim_step(nodes, mosfets))
+                               return (0);
+                       ++i;
+               }
+       }
+       /*else
+       {
+               print_wrong_usage(input);
+       }*/
+       return (1);
+}
diff --git a/src/c_setnode.c b/src/c_setnode.c
new file mode 100644 (file)
index 0000000..ab849b0
--- /dev/null
@@ -0,0 +1,21 @@
+#include "FET_sim.h"
+#include "libft.h"
+
+int    c_setnode(t_input input, t_vec *nodes)
+{
+       t_node *node;
+
+       /*if (input.argc != 2 || input.argv[0].type != num || input.argv[1].type != state)
+       {
+               print_wrong_usage(input);
+               return (1);
+       }*/
+       node = ft_vec_access(nodes, input.argv[0].val.num);
+       if (!node)
+       {
+               print_index_error(input.argv[0].val.num, nodes->size);
+               return (1);
+       }
+       node->set_state = input.argv[1].val.state;
+       return (1);
+}
diff --git a/src/colors.c b/src/colors.c
new file mode 100644 (file)
index 0000000..deb0795
--- /dev/null
@@ -0,0 +1,54 @@
+#include "FET_sim.h"
+#include "libft.h"
+
+// ac stands for ANSI (escape code) color
+const char     g_default_ac[] = "\033[39m";
+
+const char     g_red_ac[] = "\033[31m";
+const char     g_green_ac[] = "\033[32m";
+const char     g_blue_ac[] = "\033[34m";
+const char     g_white_ac[] = "\033[97m";
+
+const char     *state_color_escape(t_state state)
+{
+       if (state == on)
+               return (g_green_ac);
+       if (state == off)
+               return (g_white_ac);
+       if (state == floating)
+               return (g_blue_ac);
+       return (g_red_ac);
+}
+
+void   draw_single(t_vec *nodes, t_vec *mosfets, size_t i)
+{
+       t_mosfet        *mosfet;
+       size_t          index;
+
+       mosfet = ft_vec_access(mosfets, i);
+       if (ft_vec_find_index(nodes, mosfet->source, &index) == success)
+       {
+               ft_printf("      %u\n", index);
+               ft_printf("      %s|%s\n", state_color_escape(mosfet->source->state), g_default_ac);
+       }
+       else
+       {
+               ft_printf("      %sNULL%s\n", g_red_ac, g_default_ac);
+               ft_printf("      %s|%s\n", g_red_ac, g_default_ac);
+       }
+       if (ft_vec_find_index(nodes, mosfet->gate, &index) == success)
+               ft_printf("%4u%s--%s%c\n", index, state_color_escape(mosfet->gate->state), g_default_ac, mosfet->type);
+       else
+               ft_printf("%sNULL--%s%c\n", g_red_ac, g_default_ac, mosfet->type);
+       if (ft_vec_find_index(nodes, mosfet->drain, &index) == success)
+       {
+               ft_printf("      %s|%s\n", state_color_escape(mosfet->drain->state), g_default_ac);
+               ft_printf("      %u\n\n", index);
+       }
+       else
+       {
+               ft_printf("      %s|%s\n", g_red_ac, g_default_ac);
+               ft_printf("      %sNULL%s\n\n", g_red_ac, g_default_ac);
+       }
+       ++i;
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..55a773f
--- /dev/null
@@ -0,0 +1,280 @@
+#include "FET_sim.h"
+#include "libft.h"
+#include <stdlib.h>
+
+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 ;
+}
+
+void   free_split(char **sp)
+{
+       size_t  i;
+
+       i = 0;
+       while (sp[i])
+       {
+               free(sp[i]);
+               ++i;
+       }
+       free(sp);
+       return ;
+}
+
+size_t split_length(char **sp)
+{
+       size_t  i;
+
+       i = 0;
+       while (sp[i])
+               ++i;
+       return (i);
+}
+
+int    parse_command(const char *str, t_command *cmd)
+{
+       if (!ft_strcmp(str, "n") || !ft_strcmp(str, "next"))
+               *cmd = next;
+       else if (!ft_strcmp(str, "d") || !ft_strcmp(str, "draw"))
+               *cmd = draw;
+       else if (!ft_strcmp(str, "s") || !ft_strcmp(str, "set") || !ft_strcmp(str, "setnode"))
+               *cmd = setnode;
+       else if (!ft_strcmp(str, "an") || !ft_strcmp(str, "addn") || !ft_strcmp(str, "addnode"))
+               *cmd = addnode;
+       else if (!ft_strcmp(str, "af") || !ft_strcmp(str, "addf") || !ft_strcmp(str, "addfet"))
+               *cmd = addfet;
+       else if (!ft_strcmp(str, "b") || !ft_strcmp(str, "bind"))
+               *cmd = bind;
+       else if (!ft_strcmp(str, "h") || !ft_strcmp(str, "help"))
+               *cmd = help;
+       else if (!ft_strcmp(str, "e") || !ft_strcmp(str, "exit"))
+               *cmd = exitsim;
+       else
+               return (0);
+       return (1);
+}
+
+int    parse_type(const char *str, t_type *type)
+{
+       if (!ft_strcmp(str, "p"))
+               *type = p;
+       else if (!ft_strcmp(str, "n"))
+               *type = n;
+       else
+               return (0);
+       return (1);
+}
+
+int    parse_terminal(const char *str, t_terminal *term)
+{
+       if (!ft_strcmp(str, "s") || !ft_strcmp(str, "source"))
+               *term = source;
+       else if (!ft_strcmp(str, "d") || !ft_strcmp(str, "drain"))
+               *term = drain;
+       else if (!ft_strcmp(str, "g") || !ft_strcmp(str, "gate"))
+               *term = gate;
+       else
+               return (0);
+       return (1);
+}
+
+int    parse_state(const char *str, t_state *state)
+{
+       if(!ft_strcmp(str, "on"))
+               *state = on;
+       else if (!ft_strcmp(str, "off"))
+               *state = off;
+       else if (!ft_strcmp(str, "pd") || !ft_strcmp(str, "pull_down"))
+               *state = pull_down;
+       else if (!ft_strcmp(str, "pu") || !ft_strcmp(str, "pull_up"))
+               *state = pull_up;
+       else if (!ft_strcmp(str, "f") || !ft_strcmp(str, "float") || !ft_strcmp(str, "floating"))
+               *state = floating;
+       else if (!ft_strcmp(str, "s") || !ft_strcmp(str, "short"))
+               *state = zkrat;
+       else if (!ft_strcmp(str, "u") || !ft_strcmp(str, "unknown"))
+               *state = unknown;
+       else
+               return (0);
+       return (1);
+}
+
+int    has_correct_argc(t_input input)
+{
+       t_command       c;
+       size_t          argc;
+
+       c = input.command;
+       argc = input.argc;
+       if ((c == next || c == draw || c == addfet || c == help) && argc > 1)
+               return (0);
+       if (c == setnode && argc != 2)
+               return (0);
+       if (c == bind && argc != 3)
+               return (0);
+       if (c == addnode && argc > 2)
+               return (0);
+       return (1);
+}
+
+static int     str_is_num(const char *str)
+{
+       size_t  i;
+
+       i = 0;
+       while (ft_isdigit(str[i]))
+               ++i;
+       return (str[i] == '\0');
+}
+
+// maybe atos (alphanum to size_t) should be implemented
+int    parse_arg(t_input *input, const char *str, size_t i)
+{
+       const int               is_num = str_is_num(str);
+       const size_t    num_i = (size_t)ft_atoll(str);
+       const t_command c = input->command;
+       int                             res;
+
+       res = 0;
+       if (is_num != 0 && (c == next || c == draw || (c == setnode && i == 0)
+                       || (c == addfet && i == 1) || (c == addnode && (input->argc == 1 || i == 1))
+                       || (c == bind && i < 2)))
+       {
+               input->argv[i].val.num = num_i;
+               input->argv[i].type = num;
+               res = 1;
+       }
+       else if (!is_num)
+       {
+               if ((c == addnode && i == 0) || (c == setnode && i == 1))
+               {
+                       res = parse_state(str, &input->argv[i].val.state);
+                       input->argv[i].type = state;
+               }
+               else if (c == addfet && i == 0)
+               {
+                       res = parse_type(str, &input->argv[i].val.type);
+                       input->argv[i].type = type;
+               }
+               else if (c == help)
+               {
+                       res = parse_command(str, &input->argv[i].val.command);
+                       input->argv[i].type = command;
+               }
+               else if (c == bind && i == 2)
+               {
+                       res = parse_terminal(str, &input->argv[i].val.terminal);
+                       input->argv[i].type = terminal;
+               }
+       }
+       return (res);
+}
+
+int    construct_input(t_input *input, char **split_inp)
+{
+       size_t  i;
+       t_input tmp;
+
+       tmp.argc = split_length(split_inp) - 1;
+       if (!parse_command(split_inp[0], &tmp.command))
+               return (0);
+       if (!has_correct_argc(tmp))
+               return (0);
+       i = 0;
+       while (i < tmp.argc)
+       {
+               if (!parse_arg(&tmp, split_inp[i + 1], i))
+                       return (0);
+               ++i;
+       }
+       *input = tmp;
+       return (1);
+}
+
+int    get_input(t_input *input)
+{
+       int             res;
+       char    *str_inp;
+       char    **split_inp;
+
+       str_inp = get_next_line(0);
+       if (!str_inp)
+       {
+               input->command = exitsim;
+               input->argc = 0;
+               return (1);
+       }
+       if (str_inp[0] == '\n')
+               return (1);
+       if (str_inp[0] && str_inp[ft_strlen(str_inp) - 1] == '\n')
+               str_inp[ft_strlen(str_inp) - 1] = '\0';
+       split_inp = ft_split(str_inp, ' ');
+       res = construct_input(input, split_inp);
+       if (!res)
+       {
+               command_not_found(str_inp);
+       }
+       free(str_inp);
+       free_split(split_inp);
+       return (res);
+}
+
+int    process_input(t_vec *nodes, t_vec *mosfets)
+{
+       int                             res;
+       static t_input  input = {.command = help, .argc = 0};
+
+       ft_printf("FET_sim>");
+       if (!get_input(&input))
+               return (1);
+       res = 1;
+       if (input.command == next)
+               res = c_next(input, nodes, mosfets);
+       else if (input.command == draw)
+               res = c_draw(input, nodes, mosfets);
+       else if (input.command == setnode)
+               res = c_setnode(input, nodes);
+       else if (input.command == addnode)
+               res = c_addnode(input, nodes);
+       else if (input.command == addfet)
+               res = c_addfet(input, mosfets);
+       else if (input.command == bind)
+               res = c_bind(input, nodes, mosfets);
+       else if (input.command == help)
+               res = c_help(input);
+       else if (input.command == exitsim)
+               res = 0;
+       return (res);
+}
+
+int    main(__attribute__((unused)) int argc, char **argv)
+{
+       t_vec   nodes;
+       t_vec   mosfets;
+
+       print_start();
+       ft_vec_init(&nodes, sizeof(t_node));
+       ft_vec_init(&mosfets, sizeof(t_mosfet));
+       build_graph(argv[1], &nodes, &mosfets);
+       while (process_input(&nodes, &mosfets))
+       {
+               continue ;
+       }
+       update_nodes(NULL);
+       ft_vec_free(&nodes, free_node);
+       ft_vec_free(&mosfets, NULL);
+       return (0);
+}
diff --git a/src/sim_main.c b/src/sim_main.c
new file mode 100644 (file)
index 0000000..14cc9b5
--- /dev/null
@@ -0,0 +1,38 @@
+#include "FET_sim.h"
+#include "libft.h"
+
+static 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 ;
+}
+
+static 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 ;
+}
+
+int    sim_step(t_vec *nodes, t_vec *mosfets)
+{
+       update_nodes(nodes);
+       update_mosfets(mosfets);
+       return (1);
+}
diff --git a/src/sim_node.c b/src/sim_node.c
new file mode 100644 (file)
index 0000000..eee368e
--- /dev/null
@@ -0,0 +1,86 @@
+#include "FET_sim.h"
+#include "libft.h"
+#include <stdlib.h>
+
+static t_node  *get_neighbour_node(const t_mosfet *mosfet, const t_node *start)
+{
+       if (mosfet->source == start)
+               return (mosfet->drain);
+       return (mosfet->source);
+}
+
+static 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 ;
+}
+
+static 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 ;
+}
+
+// passing NULL signals update_nodes should clean connected_nodes
+// and should be called before end
+//
+// I don't know how irresponsible it is to let OS clear those things
+// so I provide this mechanism. It may be removed in the future if
+// it seems to be a reasonable decision.
+
+void   update_nodes(t_vec *nodes)
+{
+       size_t                  i;
+       t_state                 state;
+       t_node                  *cur_node;
+       static t_vec    connected_nodes = VEC_INIT(sizeof(t_node *));
+
+       if (!nodes)
+       {
+               free(connected_nodes.vec);
+               return ;
+       }
+       reset_nodes(nodes);
+       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 ;
+}
diff --git a/src/sim_state.c b/src/sim_state.c
new file mode 100644 (file)
index 0000000..a9effb7
--- /dev/null
@@ -0,0 +1,86 @@
+#include "FET_sim.h"
+#include "libft.h"
+
+// 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);
+}
+
+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);
+}
diff --git a/src/text.c b/src/text.c
new file mode 100644 (file)
index 0000000..086351d
--- /dev/null
@@ -0,0 +1,124 @@
+#include "FET_sim.h"
+#include "libft.h"
+
+static const char      g_version_str[] = "0.0";
+
+static const char      g_next_help_str[] = ""
+       "next [STEPS]\n"
+       "Advances the simulation\n\n"
+       "STEPS\n"
+       "\tAdvances the simulation by STEPS number of steps.\n"
+       "\tDefaults to 1 when not included.\n\n";
+
+static const char      g_draw_help_str[] = ""
+       "draw [IND]\n"
+       "Draws the current state of the simulation.\n"
+       "IND\n"
+       "\tDraws the transistors with the index number IND.\n"
+       "\tDefaults to drawing every transistor.\n\n";
+
+static const char      g_setnode_help_str[] = ""
+       "setnode IND STATE\n"
+       "Sets the \"set_state\" of the node with index IND to state STATE.\n\n";
+
+static const char      g_addnode_help_str[] = ""
+       "addnode [STATE] [NUM]\n"
+       "Adds new nodes.\n"
+       "NUM\n"
+       "\tAdds NUM new nodes.\n"
+       "\tDefaults to 1.\n\n"
+       "STATE\n"
+       "\tSets \"set_state\" of new nodes to STATE.\n"
+       "\tDefaults to unknown state.\n\n";
+
+static const char      g_addfet_help_str[] = ""
+       "addfet TYPE [NUM]\n"
+       "Adds new transistors of type TYPE.\n"
+       "NUM\n"
+       "\tAdds NUM new transistors.\n"
+       "\tDefaults to 1.\n\n";
+
+static const char      g_bind_help_str[] = ""
+       "bind NODE FET TERMINAL\n"
+       "Binds node with index NODE to the TERMINAL of transitor indexed by FET.\n"
+       "Possible values for TERMINAL are gate, source and drain.\n\n";
+
+static const char      g_help_help_str[] = ""
+       "help [COMMAND]\n"
+       "Prints a simple explanation.\n"
+       "COMMAND\n"
+       "\tPrints explanation of COMMAND.\n"
+       "\tWhen no COMMAND is provided, the general help with list of commands is shown.\n\n";
+
+static const char      g_help_exit_str[] = ""
+       "exit [...]\n"
+       "Exits FET_sim. One may also use ctrl-D.\n"
+       "[...]\n"
+       "\tAnything after the command is ignored.\n\n";
+
+static const char      g_general_help_str[] = ""
+       "This is a FET_sim - simulator of FET (Field Effect Transistor) logic.\n"
+       "Version number: %s"
+       "You can use the following commands:\n"
+       "next [STEPS] \t\t- advances the simulation\n"
+       "draw [IND] \t\t- draws the state of the simulation\n"
+       "setnode IND STATE \t- sets the \"set_state\" of the node indexed by IND to STATE\n"
+       "addnode [STATE] [NUM] \t- adds new nodes\n"
+       "addfet TYPE [NUM] \t- adds new FETs\n"
+       "bind NODE FET TERMINAL \t- binds node indexed by NODE to TERMINAL\n \
+               \t\t\t  of transistor indexed by FET\n"
+       "help [COMMAND] \t\t- shows this help or help for COMMAND\n"
+       "exit [...] \t\t- exits this program\n\n";
+
+void   print_help(t_command c)
+{
+       if (c == next)
+               ft_printf(g_next_help_str);
+       else if (c == draw)
+               ft_printf(g_draw_help_str);
+       else if (c == setnode)
+               ft_printf(g_setnode_help_str);
+       else if (c == addnode)
+               ft_printf(g_addnode_help_str);
+       else if (c == addfet)
+               ft_printf(g_addfet_help_str);
+       else if (c == bind)
+               ft_printf(g_bind_help_str);
+       else if (c == help)
+               ft_printf(g_help_help_str);
+       else if (c == exitsim)
+               ft_printf(g_help_exit_str);
+       else
+               ft_printf(g_general_help_str, g_version_str);
+       return ;
+}
+
+void   command_not_found(const char *input)
+{
+       ft_printf("The command \"%s\" is not a proper FET_sim command.\n", input);
+       return ;
+}
+
+void   print_start(void)
+{
+       ft_printf("FET_sim, version %s\n"
+                       "FET_sim is a simulator of FET logic.\n"
+                       "If you need some guidence, use the \"help\" command.\n",
+                       g_version_str);
+       return ;
+}
+
+void   print_index_error(size_t index, size_t size)
+{
+       if (size > 0)
+       {
+               ft_printf("This action is invalid as given index %u "
+                       "is larger then the highest index present %u.\n",
+                       index, size - 1);
+       }
+       else
+       {
+               ft_printf("This action is invalid as there is no element yet.\n");
+       }
+       return ;
+}