aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--7_2/Makefile16
-rw-r--r--7_2/data4
-rw-r--r--7_2/include/common.h32
-rw-r--r--7_2/include/drawable.h55
-rw-r--r--7_2/include/figure.h56
-rw-r--r--7_2/include/input.h24
-rw-r--r--7_2/main.c44
-rw-r--r--7_2/src/drawable.c113
-rw-r--r--7_2/src/figure.c139
-rw-r--r--7_2/src/input.c116
-rw-r--r--Makefile37
-rw-r--r--README.md50
-rw-r--r--check.c36
-rw-r--r--include/diffeq.h22
-rw-r--r--include/equations.h10
-rw-r--r--include/types.h29
-rw-r--r--main.c89
-rw-r--r--src/diffeq.c117
-rw-r--r--src/equations.c8
19 files changed, 359 insertions, 638 deletions
diff --git a/7_2/Makefile b/7_2/Makefile
deleted file mode 100644
index 7c29431..0000000
--- a/7_2/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-
-all: main
-
-build:
- mkdir -p build
-
-build/%.o: src/%.c include/%.h build
- $(CC) -c -g -ggdb -o $@ $< -Iinclude
-
-main: main.c build/drawable.o build/figure.o build/input.o
- $(CC) -o $@ $^ -lm -lX11 -Iinclude
-
-.PHONY: clean
-
-clean:
- $(RM) *.o main build/*
diff --git a/7_2/data b/7_2/data
deleted file mode 100644
index 9d831b7..0000000
--- a/7_2/data
+++ /dev/null
@@ -1,4 +0,0 @@
-l {0, 1} {1, 2};
-r {2, 2} {40, 18};
-
-c {20, 20} 10;
diff --git a/7_2/include/common.h b/7_2/include/common.h
deleted file mode 100644
index 660532f..0000000
--- a/7_2/include/common.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef JAC_COMMON_H
-#define JAC_COMMON_H
-
-/* Для чтающих:
- * чтобы писать
- * `vector2 point = { 10, 20 };`
- * вместо
- * `struct vector2 point = { 10, 20 };`
- * (то есть чтобы писать struct перед vector2 было необязательно)
- * надо объявлять структуру так:
- * ```
- * typedef struct {
- * long x, y;
- * } vector2;
- * ```
- * Таким образом мы объявляем структуру без официального названия,
- * но присваиваем ей синоним. Чтобы пользоваться и тем, и тем вариантами,
- * можно сделать так:
- * ```
- * typedef struct vector2 {
- * long x, y;
- * } vector2;
- * ```
- * Так мы и даём ей название, и даём ей синоним.
- */
-
-// координаты точки в 2-мерном пространстве
-typedef struct vector2 {
- long x, y;
-} vector2;
-
-#endif // JAC_COMMON_H
diff --git a/7_2/include/drawable.h b/7_2/include/drawable.h
deleted file mode 100644
index 8986342..0000000
--- a/7_2/include/drawable.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef JCG_DRAWABLE_H
-#define JCG_DRAWABLE_H
-
-#define FILL_CHR '#'
-#define SPACE_CHR ' '
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-extern struct X11context {
- enum {CTX_NO, CTX_INIT, CTX_FAIL} init;
- Display *d;
- Window r, w;
- int s;
- GC gctx;
- XVisualInfo v;
- XImage *i;
- int* data;
-} X11;
-
-// что угодно, на чём можно ''нарисовать''
-// должно иметь размер, размер пикселей, данные
-// функция put записывает пиксель по координатам x, y на поле
-// функция show выводит данные на экран/куда угодно ещё
-struct drawable {
- long x, y, pix_s;
- void *data;
- void (*put)(struct drawable *self, long x, long y);
- void(*show)(const struct drawable *self);
-};
-
-
-// конструктор
-void drawable_init(struct drawable* self,
- void(*put_f)(struct drawable *, long, long),
- void(*show_f)(const struct drawable *),
- long width,
- long height,
- long pix_s);
-// деструктор
-void drawable_destroy(struct drawable *self);
-// конструктор для консольного поля
-struct drawable drawable_plaintxt(long width, long height);
-// конструктор для графического поля
-struct drawable drawable_X11(long width, long height);
-
-// put для консольного drawable
-void put_plaintxt(struct drawable *self, long x, long y);
-// show для консольного drawable
-void show_plaintxt(const struct drawable *self);
-// put для графического drawable
-void put_X11(struct drawable *self, long x, long y);
-// show для графического drawable
-void show_X11(const struct drawable *self);
-
-#endif // JCG_DRAWABLE_H
diff --git a/7_2/include/figure.h b/7_2/include/figure.h
deleted file mode 100644
index 393ca00..0000000
--- a/7_2/include/figure.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef JCG_FIGURE_H
-#define JCG_FIGURE_H
-
-#include "drawable.h"
-#include "common.h"
-
-// любая фигура
-// создаётся функциями figure_point, figure_line и т.д.
-// у каждой фигуры должен быть способ "нарисоваться" на
-// любое "рисовальное" поле, используя функцию drawable.put
-struct figure {
- enum {
- F_NONE, F_POINT, F_RECT, F_LINE, F_CIRCLE
- } type;
- union {
- struct {
- vector2 coords;
- } point;
- struct {
- vector2 upleft, downright;
- } rect;
- struct {
- vector2 start, end;
- } line;
- struct {
- vector2 center;
- long rad;
- } circle;
- };
- void (*draw)(const struct figure *self, struct drawable *d);
-};
-
-// массив функций по типам (lookup table)
-extern void (*const draw_lookup[])(const struct figure *, struct drawable *);
-
-// конструктор 1
-struct figure figure_point(vector2 p);
-// конструктор 2
-struct figure figure_rect(vector2 upleft, vector2 downright);
-// конструктор 3
-struct figure figure_line(vector2 start, vector2 end);
-// конструктор 4
-struct figure figure_circle(vector2 center, long radius);
-
-// draw для F_POINT
-void draw_point(const struct figure *self, struct drawable *d);
-// draw для F_RECT
-void draw_rect(const struct figure *self, struct drawable *d);
-// draw для F_LINE
-void draw_line(const struct figure *self, struct drawable *d);
-// draw для F_CIRCLE
-void draw_circle(const struct figure *self, struct drawable *f);
-
-void print_figure(const struct figure *self);
-
-#endif // JCG_FIGURE_H
diff --git a/7_2/include/input.h b/7_2/include/input.h
deleted file mode 100644
index 24285b8..0000000
--- a/7_2/include/input.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef JAC_INPUT_H
-#define JAC_INPUT_H
-
-#include "common.h"
-#include "figure.h"
-
-extern void(*settings_handler)(const char *sett_string);
-
-// пропустить пробелы
-void skipw(char const **s);
-// проспустит цифры
-void skipd(char const **s);
-// проерить наличие символа
-char chktok(char const **str, char tok);
-// прочитать число
-char parsel(char const **str, long *l);
-// прочитать вектор из 2 чисел
-char parsev(char const **str, vector2 *v);
-// прочитать одну фигуру
-struct figure read_figure(const char *str);
-// прочитать целый файл
-struct figure *read_file(const char *path);
-
-#endif // JAC_INPUT_H
diff --git a/7_2/main.c b/7_2/main.c
deleted file mode 100644
index edb4b76..0000000
--- a/7_2/main.c
+++ /dev/null
@@ -1,44 +0,0 @@
-#include <X11/Xlib.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "input.h"
-#include "drawable.h"
-#include "figure.h"
-
-long fatness = 1; // пока никак не используется
-
-int sx = 100, sy = 100;
-
-int main(int argc, char *argv[]) {
- char file[256] = {};
- if (argc >= 2) {
- size_t len = strlen(argv[1]);
- memcpy(file, argv[1], len > 255 ? 255 : len);
- } else {
- printf("введите файл: ");
- scanf("%255s", file);
- }
- char x11 = 0;
- for (int i = 0; i < argc; ++i) {
- if (!strcmp("-X", argv[i])) x11 = 1;
- }
- struct figure *fs = read_file(file);
- struct drawable d = x11 ? drawable_X11(sx, sy) : drawable_plaintxt(sx, sy);
- if (!fs) {
- fprintf(stderr, "ERROR: errno %i: %s\n", errno, strerror(errno));
- return 1;
- }
- for (struct figure *i = fs; i->type != F_NONE; ++i)
- i->draw(i, &d);
-
- d.show(&d);
- free(fs);
- drawable_destroy(&d);
- return 0;
-}
-
diff --git a/7_2/src/drawable.c b/7_2/src/drawable.c
deleted file mode 100644
index ab4bf27..0000000
--- a/7_2/src/drawable.c
+++ /dev/null
@@ -1,113 +0,0 @@
-#include "drawable.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-struct X11context X11 = { .init=CTX_NO };
-
-struct drawable drawable_plaintxt(long width, long height) {
- struct drawable ret;
- // with, height +1 because inclusive
- drawable_init(&ret, put_plaintxt, show_plaintxt, width + 1, height + 1, sizeof (char));
- memset(ret.data, 0, height*width*1);
- return ret;
-}
-struct drawable drawable_X11(long width, long height) {
- struct drawable ret;
- drawable_init(&ret, put_X11, show_X11, width, height, sizeof (int));
- int* data = ret.data;
- for (size_t i = 0; i < width*height; ++i)
- data[i] = 0xFFFFFFFF;
- return ret;
-}
-
-void drawable_init(struct drawable* self,
- void(*put_f)(struct drawable *, long, long),
- void(*show_f)(const struct drawable *),
- long width,
- long height,
- long pix_s)
-{
- self->x = width;
- self->y = height;
- self->pix_s = pix_s;
- self->data = malloc(height*width*pix_s);
- self->put = put_f;
- self->show = show_f;
-}
-
-void drawable_destroy(struct drawable *self) {
- free(self->data);
-}
-
-/// plaintxt methods ///
-
-void put_plaintxt(struct drawable *self, long x, long y) {
- if (x >= self->x || y >= self->y || x < 0 || y < 0) return;
- char *data = self->data;
- data[self->x * y + x] = 1;
-}
-
-void show_plaintxt(const struct drawable *self) {
- char map[2] = {SPACE_CHR, FILL_CHR};
- for (int i = 0; i < self->y; ++i) {
- for (int j = 0; j < self->x; ++j) {
- char *d = self->data;
- putchar(map[d[i*self->x + j]]);
- }
- putchar('\n');
- }
-}
-
-
-/// X11 from now on ///
-
-void init_X11(const struct drawable *self) {
- X11.d = XOpenDisplay(NULL);
- if (X11.d == NULL) {
- X11.init = CTX_FAIL;
- printf("why tho???\n");
- return;
- }
- X11.s = DefaultScreen(X11.d);
- X11.r = RootWindow(X11.d, X11.s);
- X11.gctx = DefaultGC(X11.d, X11.s);
- if (!XMatchVisualInfo(X11.d, X11.s, 24, TrueColor, &X11.v)) {
- XDestroyWindow(X11.d, X11.w);
- XCloseDisplay(X11.d);
- X11.init = CTX_FAIL;
- return;
- };
- X11.w = XCreateSimpleWindow(X11.d, X11.r, 0, 0, self->x, self->y, 0, 0, 0x00FFFFFF);
- XSelectInput(X11.d, X11.w, ExposureMask);
- XMapWindow(X11.d, X11.w);
- X11.data = self->data;
- X11.i = XCreateImage(X11.d, X11.v.visual, X11.v.depth, ZPixmap, 0, (void*)X11.data, self->x, self->y, 32, 0);
- X11.init = CTX_INIT;
-}
-
-void put_X11(struct drawable *self, long x, long y) {
- if (x >= self->x || y >= self->y || x < 0 || y < 0) return;
- int *data = self->data;
- data[self->x * y + x] = 0x00000000;
-}
-
-void show_X11(const struct drawable *self) {
-start:
- switch (X11.init) {
- case CTX_NO: init_X11(self); goto start;
- case CTX_INIT: break;
- case CTX_FAIL:
- fprintf(stderr, "Error: Could not initialize Xlib\n");
- return;
- }
- XEvent e = {};
- while (!XNextEvent(X11.d, &e)) {
- XPutImage(X11.d, X11.w, X11.gctx, X11.i, 0, 0, 0, 0, self->x, self->y);
- }
-}
-
diff --git a/7_2/src/figure.c b/7_2/src/figure.c
deleted file mode 100644
index 290d4af..0000000
--- a/7_2/src/figure.c
+++ /dev/null
@@ -1,139 +0,0 @@
-
-#include "figure.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-
-void (*const draw_lookup[])(const struct figure *, struct drawable *) = {
- [F_NONE] = NULL,
- [F_POINT] = draw_point,
- [F_RECT] = draw_rect,
- [F_LINE] = draw_line,
- [F_CIRCLE] = draw_circle
-};
-
-void swapl(long *x, long *y) {
- long tmp = *x;
- *x = *y;
- *y = tmp;
-}
-
-struct figure figure_point(vector2 p) {
- return (struct figure) {
- .type = F_POINT,
- .point.coords = p,
- .draw = draw_point
- };
-}
-
-struct figure figure_rect(vector2 upleft, vector2 downright) {
- return (struct figure) {
- .type = F_RECT,
- .rect = {upleft, downright},
- .draw = draw_rect
- };
-}
-
-struct figure figure_line(vector2 start, vector2 end) {
- return (struct figure) {
- .type = F_LINE,
- .line = {start, end},
- .draw = draw_line
- };
-}
-
-struct figure figure_circle(vector2 center, long radius) {
- return (struct figure) {
- .type = F_CIRCLE,
- .circle = {center, radius},
- .draw = draw_circle
- };
-}
-
-
-void draw_point(const struct figure *self, struct drawable *d) {
- d->put(d, self->point.coords.x, self->point.coords.y);
-}
-
-void draw_rect(const struct figure *self, struct drawable *d) {
- vector2 upleft = self->rect.upleft;
- vector2 downright = self->rect.downright;
- for (long i = upleft.x; i < downright.x + 1; ++i) {
- d->put(d, i, upleft.y);
- d->put(d, i, downright.y);
- }
- for (long j = upleft.y + 1; j < downright.y; ++j) {
- d->put(d, upleft.x, j);
- d->put(d, downright.x, j);
- }
-}
-
-void draw_line(const struct figure *self, struct drawable *d) {
- vector2 start = self->line.start;
- vector2 end = self->line.end;
- char gt45 = labs(end.y - start.y) > labs(end.x - start.x);
- long x0 = start.x, y0 = start.y,
- x1 = end.x, y1 = end.y;
- if (gt45) {
- swapl(&x0, &y0);
- swapl(&x1, &y1);
- }
- if (x0 > x1) {
- swapl(&x0, &x1);
- swapl(&y0, &y1);
- }
- long dy = labs(y1-y0),
- dx = x1 - x0,
- err = dx >> 1, // *2
- yinc = (y1 > y0 ? 1 : -1);
-
- for (long x = x0, y = y0; x <= x1; ++x) {
- if (gt45) d->put(d, y, x);
- else d->put(d, x, y);
- err -= dy;
- if (err < 0) {
- y += yinc;
- err += dx;
- }
- }
-}
-
-void draw_circle(const struct figure *self, struct drawable *f) {
- const vector2 p = self->circle.center;
- const long rad = self->circle.rad - 1;
- const long pi4 = ceil(M_SQRT1_2 * rad);
- long x0 = 0, y0 = rad;
- do {
- // выглядит коряво, зато в 8 раз меньше повторений цикла
- f->put(f, p.x-x0, p.y-y0); // 3 четверть
- f->put(f, p.x-x0, p.y+y0); // 2 чет.
- f->put(f, p.x+x0, p.y-y0); // 4 ч.
- f->put(f, p.x+x0, p.y+y0); // 1 ч
- f->put(f, p.x-y0, p.y-x0);
- f->put(f, p.x-y0, p.y+x0);
- f->put(f, p.x+y0, p.y-x0);
- f->put(f, p.x+y0, p.y+x0);
- ++x0;
- // вычисляем x^2 + (y+1/2)^2 - r^2
- // раскрыли скобки и умножили на 4, чтобы не иметь дело
- // с дробными числами (они медленные)
- long func = 4*x0*x0 + 4*y0*y0 - 4*y0 + 1 - 4*rad*rad;
- y0 = (func >= 0 ? y0 - 1 : y0);
- } while (x0 < pi4);
-}
-
-void print_figure(const struct figure *self) {
- printf("figure {\n\t.type = %i\n\t{%li, %li},\n\t", self->type, self->line.start.x, self->line.start.y);
- switch (self->type) {
- case F_LINE:
- case F_RECT:
- printf("{%li, %li}\n\t", self->line.end.x, self->line.end.y);
- break;
- case F_CIRCLE:
- printf("%li\n\t", self->circle.rad);
- // fallthrough
- case F_NONE:
- case F_POINT:;
- }
- printf(".draw = %p\n}\n", self->draw);
-}
diff --git a/7_2/src/input.c b/7_2/src/input.c
deleted file mode 100644
index d2dca7c..0000000
--- a/7_2/src/input.c
+++ /dev/null
@@ -1,116 +0,0 @@
-#include "input.h"
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-const char *const unexpchtok = "Unexpected token: %c\n";
-const char *const invalidint = "Invalid integer: %s\n";
-
-#define error(fmt, ...) do { \
- fprintf(stderr, fmt, __VA_ARGS__); \
- return 0; \
-} while(0)
-
-#define maybe_realloc(size, cap, pointer, type) do { \
- if (size >= cap) { \
- cap <<= 1; \
- pointer = realloc(pointer, cap * sizeof (type));\
- } \
-} while(0)
-
-void(*settings_handler)(const char*) = NULL;
-
-void skipw(char const **s) { while(isspace(**s)) ++*s; }
-void skipd(char const **s) { while(isdigit(**s)) ++*s; }
-
-char chktok(char const **str, char tok) {
- skipw(str);
- long tmp = atol(*str);
- if (**str != tok) error(unexpchtok, **str);
- ++*str;
- return 1;
-}
-
-char parsel(char const **str, long *l) {
- skipw(str);
- long tmp = atoi(*str);
- if (tmp == 0 && **str != '0') error(invalidint, *str);
- *l = tmp;
- skipd(str);
- return 1;
-}
-
-char parsev(char const **str, vector2 *v) {
- long x, y;
- // я ща кончу на этот код
- char suc = chktok(str, '{')
- && parsel(str, &x)
- && chktok(str, ',')
- && parsel(str, &y)
- && chktok(str, '}');
- if (suc) {
- v->x = x;
- v->y = y;
- return 1;
- } else return 0;
-}
-
-struct figure read_figure(const char *str) {
- struct figure ret = {.type = F_NONE};
- const char *strp = str;
- skipw(&strp);
- ++strp;
- switch(strp[-1]) {
- case '.': {
- if (settings_handler != NULL) settings_handler(strp);
- } break;
- case 'p': {
- if (parsev(&strp, &ret.point.coords)
- && chktok(&strp, ';')) ret.type = F_POINT;
- } break;
- case 'r': {
- if (parsev(&strp, &ret.rect.upleft)
- && parsev(&strp, &ret.rect.downright)
- && chktok(&strp, ';')) ret.type = F_RECT;
- } break;
- case 'l': {
- if (parsev(&strp, &ret.line.start)
- && parsev(&strp, &ret.line.end)
- && chktok(&strp, ';')) ret.type = F_LINE;
- } break;
- case 'c': {
- if (parsev(&strp, &ret.circle.center)
- && parsel(&strp, &ret.circle.rad)
- && chktok(&strp, ';')) ret.type = F_CIRCLE;
- } break;
- default:;
- }
- ret.draw = draw_lookup[ret.type];
- return ret;
-}
-
-struct figure *read_file(const char *path) {
- FILE *f = fopen(path, "r");
- if (!f) return NULL;
- size_t bs = 1024;
- size_t fs = -1, fcap = 16;
- char *buf = malloc(fcap * sizeof(struct figure));
- struct figure *figures = malloc(fcap * sizeof (struct figure));
- while (!feof(f)) {
- if (getdelim(&buf, &bs, ';', f) < 0) break;
- struct figure f = read_figure(buf);
- if (f.type == F_NONE) continue;
- ++fs;
- maybe_realloc(fs, fcap, figures, struct figure);
- memcpy(figures + fs, &f, sizeof (struct figure));
- }
- ++fs;
- maybe_realloc(fs, fcap, figures, struct figure);
- struct figure END = {.type = F_NONE, 0};
- memcpy(figures + fs, &END, sizeof (struct figure));
- free(buf);
- return figures;
-}
-
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..993582c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,37 @@
+
+CFLAGS += -std=c89 -g -ggdb -Iinclude
+TASK_ARGS += -t 0.1
+
+.PHONY: clean all euler rk4 run tests
+
+all:
+ echo "either make euler or make rk4"
+
+euler: task8
+ ./$< $(TASK_ARGS) -m euler
+
+rk4: task8
+ ./$< $(TASK_ARGS) -m rk4
+
+tests: task8 check
+ ./check f1.data f2.data f3.data f4.data out.data
+ echo "plot 'out.data' with lines" | gnuplot - -p
+ echo "plot 'f1.data','f2.data','f3.data','f4.data'" | gnuplot - -p
+
+run: task8
+ ./$< $(TASK_ARGS)
+
+build:
+ mkdir -p build
+
+build/%.o: src/%.c include/%.h build
+ $(CC) -c -o $@ $(CFLAGS) $< -lm
+
+task8: main.c build/diffeq.o build/equations.o
+ $(CC) -o $@ $(CFLAGS) $^ -lm
+
+check: check.c
+ $(CC) -o check $(CFLAGS) check.c -lm
+
+clean:
+ $(RM) *.o task8 check build/* *.data
diff --git a/README.md b/README.md
index 4f29fd3..c255d48 100644
--- a/README.md
+++ b/README.md
@@ -1,42 +1,14 @@
-# Задания 7.1 и 7.2
+# Задание 8
+
+Это финальное задание потрясающего курса информатики Андрея Александровича Ангелуца.
+
+Он придрался к тому, что у меня функции решения ДУ реализованы полноценно, а не как "сделать один шаг", но задание принял
+
+Сборка:
+* `make euler`: решить 4 дифура эйлером
+* `make rk4`: решить рунгекуттой
+* `make tests`: построить графики уравнений и суммы уравнений
+* `make task8 && ./task8 --help`: показать опции, которые принимает task8
-## 7.1:
-пока не сделал
-## 7.2:
-### Запуск
-кросс-платформенный, система сборки GNU make
-### идея
-### формат входного файлыа:
-Каждая строка соответствует шаблону:
-```
-ФИГУРА <параметры...>;
-```
-Параметры разделяются пробелом. Возможные параметры: число и точка. Формат точки: `{A, B}`, где A, B - неотрицательные числа.
-Файл не чувствителен к пробелам, переносам на другую строку и т.п.
-Вместо фигуры могут указываться дополнительные параметры, например `.fld_size` (TODO: ЗАКОНЧИТЬ И ЗАДОКУМЕНТИРОВАТЬ)
-#### Фигуры:
-* p - точка
-* l - линия
-* r - прямоугольник
-* c - круг
-#### Дополнительные параметры:
-* Пока ничего...
-#### Пример файла:
-```
-p {
- 0, 1
-};
-l {0, 1} {1, 2};
-r {2, 2} {40, 18};
-c
- {20, 20}
- 1000;
-```
-### файлы исходников
-В файле [main.c](7_2/main.c) почти ничего нет. Как всегда, файлы .h и .c разбиты по папками [include](7_2/include) и [src](7_2/src) соответстенно.
-* `common.h`: только определение структуры точки. Там есть один довольно важный комментарий!
-* `drawable`: определяет функции поля (показать, нарисовать точку).
-* `figure`: определяет структуру figure и алгоритмы, которые позволяют рисовать их на любом поле типа drawable.
-* `input`: определяет функции для чтения входного файла в формате, описанном выше
diff --git a/check.c b/check.c
new file mode 100644
index 0000000..58e31ab
--- /dev/null
+++ b/check.c
@@ -0,0 +1,36 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[]) {
+ FILE ** files;
+ FILE * output;
+ size_t i;
+ double t, sum, tmp1, tmp2;
+
+ if (argc < 3) return 1;
+ files = calloc(argc - 2, sizeof(FILE*));
+ for (i = 1; i < argc - 1; ++i) {
+ if (!(files[i-1] = fopen(argv[i], "r"))) {
+ perror("opening files");
+ return 1;
+ }
+ }
+
+ output = fopen(argv[argc-1], "w+");
+ for(;;) {
+ t = 0;
+ sum = 0;
+ for (i = 0; i < argc - 2; ++i) {
+ if (2 != fscanf(files[i], "%lf %lf", &tmp1, &tmp2)) goto end;
+ t += tmp1;
+ sum += tmp2;
+ }
+ t /= (argc-2);
+ fprintf(output, "%f %f\n", t, sum);
+ }
+end:
+ fclose(output);
+ for (i = 0; i < argc - 2; ++i) fclose(files[i]);
+ free(files);
+ return 0;
+}
diff --git a/include/diffeq.h b/include/diffeq.h
new file mode 100644
index 0000000..51f85e6
--- /dev/null
+++ b/include/diffeq.h
@@ -0,0 +1,22 @@
+#ifndef T8_DIFFEQ_H
+#define T8_DIFFEQ_H
+#include <types.h>
+
+/*
+ * `eqfs` - Массив функций
+ * `init` - массив начальных условий f_n(a) = init[n] (значение функций в начале интервала!)
+ * `files` = массив файлов, в который записывать получившиеся приближения
+ * `n` - количество уравнений ( и начальных условий ) ( и переменных )
+ * `a` - начало интервала решения ( по t? )
+ * `b` - конец интервала решения ( по t? )
+ * `dt` - шаг по времени
+ */
+void difeq_solve_euler(eqf_t *eqfs, f64 *init, const char **files, usz n, f64 a, f64 b, f64 dt);
+
+/*
+ * То же самое, что и прошлая функция, только использует не метод эйлера, а метод рунге-кутты.
+ * Аргументы все точно такие же
+ */
+ void difeq_solve_RK(eqf_t *eqfs, f64 *init, const char **files, usz n, f64 a, f64 b, f64 dt);
+
+#endif /* T8_DIFFEQ_H */
diff --git a/include/equations.h b/include/equations.h
new file mode 100644
index 0000000..48936fb
--- /dev/null
+++ b/include/equations.h
@@ -0,0 +1,10 @@
+#ifndef T8_EQUATIONS_H
+#define T8_EQUATIONS_H
+#include <types.h>
+
+f64 f1(f64* argv, usz argc, f64 t);
+f64 f2(f64* argv, usz argc, f64 t);
+f64 f3(f64* argv, usz argc, f64 t);
+f64 f4(f64* argv, usz argc, f64 t);
+
+#endif /* T8_EQUATIONS_H */
diff --git a/include/types.h b/include/types.h
new file mode 100644
index 0000000..c83c9bd
--- /dev/null
+++ b/include/types.h
@@ -0,0 +1,29 @@
+#ifndef T8_TYPES_H
+#define T8_TYPES_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+
+typedef int8_t i8;
+typedef int16_t i16;
+typedef int32_t i32;
+typedef int64_t i64;
+
+typedef float f32;
+typedef double f64;
+
+typedef size_t usz;
+typedef ptrdiff_t isz;
+
+#if __SIZEOF_LONG_DOUBLE__ == 16
+typedef long double f128;
+#endif
+
+typedef f64(*eqf_t)(f64*, usz, f64);
+
+#endif
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..01e5ef7
--- /dev/null
+++ b/main.c
@@ -0,0 +1,89 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <diffeq.h>
+#include <equations.h>
+#include <types.h>
+
+#define neqs 4
+eqf_t eqfs[] = {f1, f2, f3, f4};
+
+void help(const char *program, int exit_code) {
+ printf("Usage:\n%s --method euler|rk4 [--equations <integer>] [--files <f1 f2 ... fn>] [--dt <number>] [--interval <start> <end>] [--init <num1 num2 ... num_n>]\n", program);
+ puts( "\t--method, -m:\twhich method to use, euler's method or 4th order Runge-Kutta method. Default: euler\n"
+ "\t--equations, -e:\tAmount of equations. Optional, default 4\n"
+ "\t--files, -f:\tSpecifies output files for approximations. Default: f1.data, f2.data, ...\n"
+ "\t--dt, -t:\tApproximation step. default 0.1\n"
+ "\t--range, -r:\tInterval of an approximation. defaults to '0 40'\n"
+ "\t--init, -i:\tInitial conditions for problem at the start of an interval. Default: '0.1 -0.1 0.1 -0.1' ...\n"
+ "\t--help, -h:\tThis message\n\n"
+ "Note: -e MUST come before -f and -i. If not done so, amount of files will be determined incorrectly"
+ );
+ if (exit_code < 0) return;
+ else exit(exit_code);
+}
+
+int main(int argc, char *argv[]) {
+ i32 i, j, numeq = 4;
+ f64 dt = 0.1, start = 0, end = 40;
+ f64 * init = NULL;
+ const char **files = NULL;
+ void (*solver)(eqf_t*, f64*, const char**, usz, f64, f64, f64) = difeq_solve_euler;
+
+ for (i = 1; i < argc; ++i) {
+ if (!strcmp("-h", argv[i]) || !strcmp("--help", argv[i]))
+ help(*argv, 0);
+ if (!strcmp("-e", argv[i]) || !strcmp("--equations", argv[i]))
+ numeq = atoi(argv[++i]);
+ if (!strcmp("-t", argv[i]) || !strcmp("--dt", argv[i]))
+ dt = atof(argv[++i]);
+ if (!strcmp("-r", argv[i]) || !strcmp("--range", argv[i])) {
+ start = atof(argv[++i]);
+ end = atof(argv[++i]);
+ }
+ if (!strcmp("-i", argv[i]) || !strcmp("--init", argv[i])) {
+ init = calloc(numeq, sizeof(f64));
+ for (j = 0; j < numeq; ++j) init[j] = atof(argv[++i]);
+ }
+ if (!strcmp("-f", argv[i]) || !strcmp("--files", argv[i])) {
+ files = calloc(numeq, sizeof(char*));
+ for (j = 0; j < numeq; ++j) files[j] = argv[++i];
+ }
+ if (!strcmp("-m", argv[i]) || !strcmp("--method", argv[i])) {
+ ++i;
+ if (!strcmp(argv[i], "euler")) {
+ solver = difeq_solve_euler;
+ continue;
+ }
+ if (!strcmp(argv[i], "rk4")) {
+ solver = difeq_solve_RK;
+ continue;
+ }
+ printf("\x1b[91mError:\x1b[0mNo such method \"%s\". Available methods: \"euler\"\"rk4\". see --help for details.\n", argv[i]);
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (numeq != neqs) {
+ printf("\x1b[91mError:\x1b[0mCan not solve more than 4 equations without changing source code of main.");
+ return EXIT_FAILURE;
+ }
+ if (files == NULL) {
+ files = calloc(4, sizeof(char*));
+ files[0] = "f1.data", files[1] = "f2.data",
+ files[2] = "f3.data", files[3] = "f4.data";
+ }
+ if (init == NULL) {
+ init = calloc(4, sizeof (double));
+ init[0] = init[2] = 0.1,
+ init[1] = init[3] = -0.1;
+ }
+
+ solver(eqfs, init, files, neqs, start, end, dt);
+ puts("Done");
+
+ free(init);
+ free(files);
+ return EXIT_SUCCESS;
+}
diff --git a/src/diffeq.c b/src/diffeq.c
new file mode 100644
index 0000000..47b231c
--- /dev/null
+++ b/src/diffeq.c
@@ -0,0 +1,117 @@
+#include "diffeq.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+/* Calling:
+ * if data is non-null, t is used. if data is null, t is not used.
+ *
+ * 1. Initializing files: files = [array of files], data = NULL, n = sizeof [array of files]
+ * 2. Updating files: files = anything non-NULL [unused], data = [array of data], n = sizeof [array of data].
+ * n may be 0, then saved n from init is used
+ * 3. Closing files: files = NULL, data = NULL, n = anything
+ *
+ * returns: whether the operation was successful
+ */
+char flush_approx(const char ** files, f64 t, f64 * data, usz n) {
+ static FILE ** handlers;
+ static usz size;
+ usz i;
+
+ if (data == NULL && files == NULL) {
+ for (i = 0; i < n; ++i) {
+ if (fclose(handlers[i]) != 0)
+ perror("closing files");
+ }
+ free(handlers);
+ return 1;
+ }
+ if (data == NULL) {
+ size = n;
+ handlers = calloc(n, sizeof (FILE*));
+ for (i = 0; i < n; ++i) {
+ handlers[i] = fopen(files[i], "w+");
+ if (handlers[i] == NULL) {
+ perror(files[i]);
+ return 0;
+ }
+ }
+ return 1;
+ }
+ if (files == NULL) {
+ for (i = 0; i < (n == 0 ? size : n); ++i)
+ fprintf(handlers[i], "%f %f\n", t, data[i]);
+ return 1;
+ }
+ return 0;
+}
+
+void difeq_solve_euler(eqf_t *eqfs, f64 *init, const char **files, usz n, f64 a, f64 b, f64 dt) {
+ f64 *guesses1 = calloc(n, sizeof(f64));
+ f64 *guesses2 = calloc(n, sizeof(f64));
+ f64 cur = a;
+ size_t i;
+
+ flush_approx(files, 0, NULL, n);
+
+ memcpy(guesses1, init, n * sizeof(f64));
+ memcpy(guesses2, init, n * sizeof(f64));
+
+ for(cur = a; cur < b; cur += dt) {
+ for (i = 0; i < n; ++i)
+ guesses2[i] += dt * eqfs[i](guesses1, n, cur);
+ memcpy(guesses1, guesses2, n * sizeof(f64));
+ flush_approx(NULL, cur, guesses1, n);
+ }
+ flush_approx(NULL, 0, NULL, 0);
+ free(guesses1);
+ free(guesses2);
+}
+
+void difeq_solve_RK(eqf_t *eqfs, f64 *init, const char **files, usz n, f64 a, f64 b, f64 dt) {
+ f64 *guesses1 = calloc(n, sizeof(f64));
+ f64 *guesses2 = calloc(n, sizeof(f64));
+ f64 cur = a;
+ f64 *k1s = calloc(n, sizeof(f64)),
+ *k2s = calloc(n, sizeof(f64)),
+ *k3s = calloc(n, sizeof(f64)),
+ *k4s = calloc(n, sizeof(f64));
+ size_t step, i;
+
+ flush_approx(files, 0, NULL, n);
+
+ memcpy(guesses2, init, n * sizeof(f64));
+ memcpy(guesses1, init, n * sizeof(f64));
+
+ for(step = 0; step < (b-a)/dt; cur = a + ++step*dt) {
+ for (i = 0; i < n; ++i)
+ k1s[i] = eqfs[i](guesses1, n, cur);
+ for (i = 0; i < n; ++i)
+ guesses2[i] = guesses1[i] + dt/2 * k1s[i];
+ for (i = 0; i < n; ++i)
+ k2s[i] = eqfs[i](guesses2, n, cur + dt/2);
+ for (i = 0; i < n; ++i)
+ guesses2[i] = guesses1[i] + dt/2 * k2s[i];
+ for (i = 0; i < n; ++i)
+ k3s[i] = eqfs[i](guesses2, n, cur + dt/2);
+ for (i = 0; i < n; ++i)
+ guesses2[i] = guesses1[i] + dt * k3s[i];
+ for (i = 0; i < n; ++i)
+ k4s[i] = eqfs[i](guesses2, n, cur + dt);
+
+ for (i = 0; i < n; ++i)
+ guesses2[i] += dt/6 * (k1s[i] + 2*k2s[i] +2*k3s[i] + k4s[i]);
+
+ memcpy(guesses1, guesses2, n * sizeof(f64));
+ flush_approx(NULL, cur, guesses1, n);
+ }
+ flush_approx(NULL, 0, NULL, 0);
+ free(guesses1);
+ free(guesses2);
+ free(k1s);
+ free(k2s);
+ free(k3s);
+ free(k4s);
+}
diff --git a/src/equations.c b/src/equations.c
new file mode 100644
index 0000000..efe176e
--- /dev/null
+++ b/src/equations.c
@@ -0,0 +1,8 @@
+#include <equations.h>
+#include <types.h>
+
+f64 f1(f64* argv, usz argc, f64 t) { return -argv[0] + argv[1] - argv[2] + argv[3]; }
+f64 f2(f64* argv, usz argc, f64 t) { return -argv[0] + argv[2] - argv[3]; }
+f64 f3(f64* argv, usz argc, f64 t) { return argv[0] - argv[1] + argv[3] + t/10; }
+f64 f4(f64* argv, usz argc, f64 t) { return argv[0] - argv[3] - t/10; }
+