]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/galaxy/body.c
games/galaxy: add n-body simulator
[plan9front.git] / sys / src / games / galaxy / body.c
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <bio.h>
5 #include "galaxy.h"
6
7 void
8 glxyinit(void)
9 {
10
11         glxy.a = calloc(5, sizeof(Body));
12         if(glxy.a == nil)
13                 sysfatal("could not allocate glxy: %r");
14         glxy.l = 0;
15         glxy.max = 5;
16 }
17
18 Body*
19 body(void)
20 {
21         Body *b;
22
23         if(glxy.l == glxy.max) {
24                 glxy.max *= 2;
25                 glxy.a = realloc(glxy.a, sizeof(Body) * glxy.max);
26                 if(glxy.a == nil)
27                         sysfatal("could not realloc glxy: %r");
28         }
29         b = glxy.a + glxy.l++;
30         *b = ZB;
31         return b;
32 }
33
34 void
35 drawbody(Body *b)
36 {
37         Point pos, v;
38         int s;
39
40         pos.x = b->x / scale + orig.x;
41         pos.y = b->y / scale + orig.y;
42         s = b->size/scale;
43         fillellipse(screen, pos, s, s, b->col, ZP);
44         v.x = b->v.x/scale*10;
45         v.y = b->v.y/scale*10;
46         if(v.x != 0 || v.y != 0)
47                 line(screen, pos, addpt(pos, v), Enddisc, Endarrow, 0, b->col, ZP);
48         flushimage(display, 1);
49 }
50
51 Vector
52 center(void)
53 {
54         Body *b;
55         Vector gc, gcv;
56         double mass;
57
58         if(glxy.l == 0)
59                 return (Vector){0, 0};
60
61         gc.x = gc.y = gcv.x = gcv.y = mass = 0;
62         for(b = glxy.a; b < glxy.a+glxy.l; b++) {
63                 gc.x += b->x * b->mass;
64                 gc.y += b->y * b->mass;
65                 gcv.x += b->v.x * b->mass;
66                 gcv.y += b->v.y * b->mass;
67                 mass += b->mass;
68         }
69         gc.x /= mass;
70         gc.y /= mass;
71         gcv.x /= mass;
72         gcv.y /= mass;
73         for(b = glxy.a; b < glxy.a+glxy.l; b++) {
74                 b->x -= gc.x;
75                 b->y -= gc.y;
76                 b->v.x -= gcv.x;
77                 b->v.y -= gcv.y;
78         }
79         return gc;
80 }
81
82 int
83 Bfmt(Fmt *f)
84 {
85         Body *b;
86         int r;
87
88         b = va_arg(f->args, Body*);
89
90         r = fmtprint(f, "MKBODY %g %g ", b->x, b->y);
91         if(r < 0)
92                 return -1;
93
94         r = fmtprint(f, "%g %g ", b->v.x, b->v.y);
95         if(r < 0)
96                 return -1;
97
98         return fmtprint(f, "%g", b->size);
99 }
100
101 enum {
102         MKBODY,
103         ORIG,
104         DT,
105         SCALE,
106         GRAV,
107         NOCMD,
108 };
109
110 int
111 getcmd(char *l)
112 {
113         static char *cmds[] = {
114                 [MKBODY]        "MKBODY",
115                 [ORIG]  "ORIG",
116                 [DT]    "DT",
117                 [SCALE] "SCALE",
118                 [GRAV]  "GRAV",
119         };
120         int cmd;
121
122         for(cmd = 0; cmd < nelem(cmds); cmd++) {
123                 if(strcmp(l, cmds[cmd]) == 0)
124                         return cmd;
125         }
126         sysfatal("getcmd: no such command %s", l);
127         return NOCMD;
128 }
129
130 void
131 readglxy(int fd)
132 {
133         static Biobuf bin;
134         char *line;
135         double f;
136         int cmd, len;
137         Body *b;
138
139         glxy.l = 0;
140         Binit(&bin, fd, OREAD);
141         for(;;) {
142                 line = Brdline(&bin, ' ');
143                 len = Blinelen(&bin);
144                 if(line == nil) {
145                         if(len == 0)
146                                 break;
147                         sysfatal("load: malformed command");
148                 }
149
150                 line[len-1] = '\0';
151                 cmd = getcmd(line);
152
153                 line = Brdline(&bin, '\n');
154                 if(line == nil) {
155                         if(len == 0)
156                                 sysfatal("load: malformed command");
157                         sysfatal("load: read error: %r");
158                 }
159                 len = Blinelen(&bin);
160                 line[len-1] = '\0';
161
162                 switch(cmd) {
163                 case MKBODY:
164                         b = body();
165                         b->x = strtod(line, &line);
166                         b->y = strtod(line, &line);
167                         b->v.x = strtod(line, &line);
168                         b->v.y = strtod(line, &line);
169                         b->size = strtod(line, nil);
170                         b->mass = b->size*b->size*b->size;
171                         b->col = randcol();
172                         CHECKLIM(b, f);
173                         break;
174                 case ORIG:
175                         orig.x = strtol(line, &line, 10);
176                         orig.y = strtol(line, nil, 10);
177                         break;
178                 case DT:
179                         dt = strtod(line, nil);
180                         dt² = dt*dt;
181                         break;
182                 case SCALE:
183                         scale = strtod(line, nil);
184                         break;
185                 case GRAV:
186                         G = strtod(line, nil);
187                         break;
188                 }
189         }
190         Bterm(&bin);
191 }
192
193 void
194 writeglxy(int fd)
195 {
196         static Biobuf bout;
197         Body *b;
198
199         Binit(&bout, fd, OWRITE);
200         
201         Bprint(&bout, "ORIG %d %d\n", orig.x, orig.y);
202         Bprint(&bout, "SCALE %g\n", scale);
203         Bprint(&bout, "DT %g\n", dt);
204         Bprint(&bout, "GRAV %g\n", G);
205
206         for(b = glxy.a; b < glxy.a + glxy.l; b++)
207                 Bprint(&bout, "%B\n", b);
208
209         Bterm(&bout);
210 }