Remote agent/Simulation/C: Difference between revisions

From Rosetta Code
Content added Content deleted
m (formatting)
(bug fix)
Line 145: Line 145:
#include <err.h>
#include <err.h>
#include "common.c"
#include "common.c"

typedef struct task_node_t {
typedef struct task_node_t {
int x, y;
int x, y;
struct task_node_t *prev, *sibling, *chain;
struct task_node_t *prev, *sibling, *chain;
} task_node_t, *task;
} task_node_t, *task;

task pool = 0, used = 0;
task pool = 0, used = 0;
task find_place_to_go(byte **f);
task find_place_to_go(byte **f);
Line 165: Line 165:
return used;
return used;
}
}

void remove_tasks()
void remove_tasks()
{
{
Line 176: Line 176:
}
}
}
}

int w, h;
int w, h;
int do_client_stuff(int);
int do_client_stuff(int);

int main(int c, char *v[])
int main(int c, char *v[])
{
{
Line 185: Line 185:
struct sockaddr_in peer;
struct sockaddr_in peer;
struct hostent *server;
struct hostent *server;

if (c < 3) err(1, "Usage: %s host port\n", v[0]);
if (c < 3) err(1, "Usage: %s host port\n", v[0]);

port = atoi(v[2]);
port = atoi(v[2]);
if (port <= 0) err(1, "bad port: %d\n", port);
if (port <= 0) err(1, "bad port: %d\n", port);

server = gethostbyname(v[1]);
server = gethostbyname(v[1]);
if (!server) err(1, "Unknown server %s", v[1]);
if (!server) err(1, "Unknown server %s", v[1]);

if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
err(1, "Can't open socket");
err(1, "Can't open socket");

memset(&peer, 0, sizeof(peer));
memset(&peer, 0, sizeof(peer));
peer.sin_family = AF_INET;
peer.sin_family = AF_INET;
memcpy(server->h_addr, &peer.sin_addr.s_addr, server->h_length);
memcpy(&peer.sin_addr.s_addr, server->h_addr, server->h_length);
peer.sin_port = htons(port);
peer.sin_port = htons(port);

if (connect(sfd, (struct sockaddr *)&peer, sizeof(peer)) < 0)
if (connect(sfd, (struct sockaddr *)&peer, sizeof(peer)) < 0)
err(1, "Can't connect to %s port %d", v[1], port);
err(1, "Can't connect to %s port %d", v[1], port);

puts("\033[H\033[J");
puts("\033[H\033[J");
do_client_stuff(sfd);
do_client_stuff(sfd);
close(sfd);
close(sfd);

return 0;
return 0;
}
}

byte ** init_map()
byte ** init_map()
{
{
Line 220: Line 220:
return f;
return f;
}
}

byte **f;
byte **f;
int try_forward(int);
int try_forward(int);
void say_and_listen(int, int, int*);
void say_and_listen(int, int, int*);

int do_client_stuff(int fd)
int do_client_stuff(int fd)
{
{
Line 230: Line 230:
int response[MAX_CMD];
int response[MAX_CMD];
task tgt;
task tgt;

if (c != 'A') {
if (c != 'A') {
fprintf(stderr, "Bad handshake: %c\n", c);
fprintf(stderr, "Bad handshake: %c\n", c);
Line 238: Line 238:
f = init_map();
f = init_map();
c = 0;
c = 0;

while (c != -1) {
while (c != -1) {
x = agent.x, y = agent.y;
x = agent.x, y = agent.y;
show_field(f, w, h);
show_field(f, w, h);

if (agent.ball == -1 && cell_ball(f, x, y) >= 0
if (agent.ball == -1 && cell_ball(f, x, y) >= 0
&& cell_ball(f, x, y) != cell_color(f, x, y))
&& cell_ball(f, x, y) != cell_color(f, x, y))
Line 252: Line 252:
continue;
continue;
}
}

if (agent.ball == cell_color(f, x, y) && cell_ball(f, x, y) == -1) {
if (agent.ball == cell_color(f, x, y) && cell_ball(f, x, y) == -1) {
say_and_listen(fd, c_drop, response);
say_and_listen(fd, c_drop, response);
Line 261: Line 261:
continue;
continue;
}
}

goto_place(fd, f, tgt = find_place_to_go(f));
goto_place(fd, f, tgt = find_place_to_go(f));
continue;
continue;
Line 267: Line 267:
return 0;
return 0;
}
}

void expand_map()
void expand_map()
{
{
Line 273: Line 273:
int dx, dy;
int dx, dy;
byte **nf;
byte **nf;

switch(d) {
switch(d) {
case 0: case 2: w2++; break;
case 0: case 2: w2++; break;
default: h2++; break;
default: h2++; break;
}
}

nf = byte_array(w2, h2);
nf = byte_array(w2, h2);
FOR(i, h2) FOR(j, w2) nf[i][j] = unknown;
FOR(i, h2) FOR(j, w2) nf[i][j] = unknown;

dx = agent.x == 0;
dx = agent.x == 0;
dy = agent.y == 0;
dy = agent.y == 0;

FOR(i, h) FOR(j, w) nf[i + dy][j + dx] = f[i][j];
FOR(i, h) FOR(j, w) nf[i + dy][j + dx] = f[i][j];

if (!agent.x) agent.x = 1;
if (!agent.x) agent.x = 1;
if (!agent.y) agent.y = 1;
if (!agent.y) agent.y = 1;

w = w2, h = h2;
w = w2, h = h2;
printf("expand: %d %d\n", w, h);
printf("expand: %d %d\n", w, h);
Line 295: Line 295:
f = nf;
f = nf;
}
}

int try_forward(int fd)
int try_forward(int fd)
{
{
Line 327: Line 327:
return 1;
return 1;
}
}

void say_and_listen(int fd, int cmd, int *resp)
void say_and_listen(int fd, int cmd, int *resp)
{
{
Line 340: Line 340:
}
}
}
}

int is_interesting(byte **f, task t)
int is_interesting(byte **f, task t)
{
{
Line 346: Line 346:
if ((f[y][x] & unknown))
if ((f[y][x] & unknown))
return y != agent.y || x != agent.x;
return y != agent.y || x != agent.x;

c = cell_color(f, x, y);
c = cell_color(f, x, y);
b = cell_ball(f, x, y);
b = cell_ball(f, x, y);
a = agent.ball;
a = agent.ball;

if (a >= 0)
if (a >= 0)
return a == c && b == -1;
return a == c && b == -1;
else if (b >= 0 && b != c)
else if (b >= 0 && b != c)
return 1;
return 1;

return 0;
return 0;
}
}

task find_place_to_go(byte **f)
task find_place_to_go(byte **f)
{
{
Line 368: Line 368:
current->x = agent.x, current->y = agent.y;
current->x = agent.x, current->y = agent.y;
f[current->y][current->x] |= marked;
f[current->y][current->x] |= marked;

if (is_interesting(f, current)) return current;
if (is_interesting(f, current)) return current;

while (current) {
while (current) {
while (current) {
while (current) {
Line 390: Line 390:
next = 0;
next = 0;
}
}
puts("nowhere to go");
abort();
abort();
}
}

void goto_place(int fd, byte **f, task t)
void goto_place(int fd, byte **f, task t)
{
{
Line 399: Line 400:
usleep(50000);
usleep(50000);
t->prev = 0;
t->prev = 0;

if (agent.x == t->x && agent.y == t->y) return;
if (agent.x == t->x && agent.y == t->y) return;
while ( t->x != agent.x + dirs[agent.facing][0] ||
while ( t->x != agent.x + dirs[agent.facing][0] ||

Revision as of 01:00, 29 June 2012

Remote agent/Simulation/C is part of Remote agent/Simulation. You may find other members of Remote agent/Simulation at Category:Remote agent/Simulation.

Server/client programs share a lot of code, so they are all lumped together here. To compile, dump all three files in the same dir, and compile server.c and client.c separately. The server binds to port 11111. Both server and client display the current map, though only the server has the whole world, the client only knows cells the agent has been to.

server.c:

<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <unistd.h>
  3. include <sys/types.h>
  4. include <sys/socket.h>
  5. include <netinet/in.h>
  6. include <netdb.h>
  7. include <arpa/inet.h>
  8. include <err.h>
  9. include "common.c"
  1. define W 30
  2. define H 30

int do_server_stuff(int);

int main() { int one = 1, client_fd, port = 11111; struct sockaddr_in svr_addr, cli_addr; socklen_t sin_len = sizeof(cli_addr);

int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) err(1, "can't open socket");

setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));

svr_addr.sin_family = AF_INET; svr_addr.sin_addr.s_addr = INADDR_ANY; svr_addr.sin_port = htons(port);

if (bind(sock, (struct sockaddr *) &svr_addr, sizeof(svr_addr)) == -1) { close(sock); err(1, "Can't bind"); }

listen(sock, 5); while (1) { client_fd = accept(sock, (struct sockaddr *) &cli_addr, &sin_len);

if (client_fd == -1) { perror("Can't accept"); continue; }

		puts("\033[H\033[J");
		do_server_stuff(client_fd);

close(client_fd); } }

int work_done(byte **f) { int x, y, b; FOR(y, H) FOR(x, W) { b = cell_ball(f, x, y); if (b < 0) continue; if (b != cell_color(f, x, y)) return 0; } return 1; }

byte **f = 0; int do_server_stuff(int fd) { int c, x, y, b; agent.ball = -1;

say_l('A');

if (f) free(f); f = make_field(W, H); c = hear_l(); if (c != 'A') { fprintf(stderr, "Bad hand shake: %c\n", c); return 0; }

while (1) { show_field(f, W, H); c = hear(); x = agent.x; y = agent.y;

if (c == -1) break; switch(c) { case c_fwd: if (!agent_forward(f)) { say(a_bump); say(c_stop); continue; } say(s_red + cell_color(f, agent.x, agent.y));

c = cell_ball(f, agent.x, agent.y); if (c >= 0) say(b_red + c);

say(c_stop); continue; case c_cw: turn(c_cw), say(c_stop); continue; case c_ccw: turn(c_ccw), say(c_stop);continue; case c_get: b = cell_ball(f, agent.x, agent.y); if (b == -1) say(s_empty); if (agent.ball >= 0) b = -1, say(a_full); if (b >= 0) { agent.ball = b; f[y][x] &= ~ball; } say(c_stop); continue; case c_drop: if ((b = agent.ball) == -1) say(a_empty); if (cell_ball(f, x, y) >= 0) b = -1, say(s_full); if (b >= 0) { agent.ball = -1; f[y][x] &= ~12; f[y][x] |= ball | (b * 4); } if (work_done(f)) say(c_over); say(c_stop); continue; } }

return 1; }</lang>

client.c:

<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <unistd.h>
  3. include <string.h>
  4. include <sys/types.h>
  5. include <sys/socket.h>
  6. include <netinet/in.h>
  7. include <netdb.h>
  8. include <arpa/inet.h>
  9. include <err.h>
  10. include "common.c"

typedef struct task_node_t { int x, y; struct task_node_t *prev, *sibling, *chain; } task_node_t, *task;

task pool = 0, used = 0; task find_place_to_go(byte **f); int is_interesting(byte **f, task t); void goto_place(int fd, byte **f, task t); task new_task_node() { task t; if (!pool) pool = calloc(1, sizeof(task_node_t)); t = pool->chain; pool->chain = used; used = pool; pool = t; return used; }

void remove_tasks() { task t; while (used) { t = used; used = used->chain; t->chain = pool; pool = t; } }

int w, h; int do_client_stuff(int);

int main(int c, char *v[]) { int sfd, port; struct sockaddr_in peer; struct hostent *server;

if (c < 3) err(1, "Usage: %s host port\n", v[0]);

port = atoi(v[2]); if (port <= 0) err(1, "bad port: %d\n", port);

server = gethostbyname(v[1]); if (!server) err(1, "Unknown server %s", v[1]);

if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) err(1, "Can't open socket");

memset(&peer, 0, sizeof(peer)); peer.sin_family = AF_INET; memcpy(&peer.sin_addr.s_addr, server->h_addr, server->h_length); peer.sin_port = htons(port);

if (connect(sfd, (struct sockaddr *)&peer, sizeof(peer)) < 0) err(1, "Can't connect to %s port %d", v[1], port);

puts("\033[H\033[J"); do_client_stuff(sfd); close(sfd);

return 0; }

byte ** init_map() { int i, j; byte **f = byte_array(w = 3, h = 3); FOR (i, h) FOR(j, w) f[i][j] = unknown; agent.x = agent.y = 1; return f; }

byte **f; int try_forward(int); void say_and_listen(int, int, int*);

int do_client_stuff(int fd) { int c = hear_l(), x, y; int response[MAX_CMD]; task tgt;

if (c != 'A') { fprintf(stderr, "Bad handshake: %c\n", c); return 0; } say_l('A'); f = init_map(); c = 0;

while (c != -1) { x = agent.x, y = agent.y; show_field(f, w, h);

if (agent.ball == -1 && cell_ball(f, x, y) >= 0 && cell_ball(f, x, y) != cell_color(f, x, y)) { say_and_listen(fd, c_get, response); if (response[a_full] || response[s_empty]) continue; agent.ball = cell_ball(f, x, y); f[y][x] &= ~ball; continue; }

if (agent.ball == cell_color(f, x, y) && cell_ball(f, x, y) == -1) { say_and_listen(fd, c_drop, response); if (response[s_full] || response[a_empty]) continue; f[y][x] |= ball | (agent.ball << 2); agent.ball = -1; if (response[c_over]) return 1; continue; }

goto_place(fd, f, tgt = find_place_to_go(f)); continue; } return 0; }

void expand_map() { int w2 = w, h2 = h, i, j, d = agent.facing; int dx, dy; byte **nf;

switch(d) { case 0: case 2: w2++; break; default: h2++; break; }

nf = byte_array(w2, h2); FOR(i, h2) FOR(j, w2) nf[i][j] = unknown;

dx = agent.x == 0; dy = agent.y == 0;

FOR(i, h) FOR(j, w) nf[i + dy][j + dx] = f[i][j];

if (!agent.x) agent.x = 1; if (!agent.y) agent.y = 1;

w = w2, h = h2; printf("expand: %d %d\n", w, h); free(f); f = nf; }

int try_forward(int fd) { int c, x, y, response[MAX_CMD] = {0}; say(c_fwd); while (1) { c = hear(); if (c == -1) return 0; if (c == c_stop) break; response[c] = 1; } x = agent.x + dirs[agent.facing][0]; y = agent.y + dirs[agent.facing][1]; if (response[a_bump]) { f[y][x] = wall; return 1; } agent.x = x, agent.y = y; for (c = s_red; c <= s_blue; c++) { if (!response[c]) continue; f[y][x] = (c - s_red); break; } for (c = b_red; c <= b_blue; c++) { if (!response[c]) continue; f[y][x] |= ball | ((c - b_red) * 4); break; } if (y == h - 1 || y == 0 || x == w - 1 || x == 0) expand_map(); return 1; }

void say_and_listen(int fd, int cmd, int *resp) { int c; memset(resp, 0, sizeof(int) * MAX_CMD); say(cmd); while (1) { c = hear(); if (c == -1) exit(1); resp[c] = 1; if (c == c_stop) return; } }

int is_interesting(byte **f, task t) { int x = t->x, y = t->y, a, b, c; if ((f[y][x] & unknown)) return y != agent.y || x != agent.x;

c = cell_color(f, x, y); b = cell_ball(f, x, y); a = agent.ball;

if (a >= 0) return a == c && b == -1; else if (b >= 0 && b != c) return 1;

return 0; }

task find_place_to_go(byte **f) { int d, x, y; task current = 0, next = 0, t; remove_tasks(); FOR(y, h) FOR(x, w) f[y][x] &= ~marked; current = new_task_node(); current->x = agent.x, current->y = agent.y; f[current->y][current->x] |= marked;

if (is_interesting(f, current)) return current;

while (current) { while (current) { FOR(d, 4) { x = current->x + dirs[d][0]; y = current->y + dirs[d][1]; if (x < 0 || x >= w || y < 0 || y >= h) continue; if (f[y][x] & (wall | marked)) continue; f[y][x] |= marked; t = new_task_node(); t->x = x, t->y = y, t->prev = current; t->sibling = next; next = t; if (is_interesting(f, t)) return t; } current = current->sibling; } current = next; next = 0; } puts("nowhere to go"); abort(); }

void goto_place(int fd, byte **f, task t) { show_field(f, w, h); if (t->prev) goto_place(fd, f, t->prev); usleep(50000); t->prev = 0;

if (agent.x == t->x && agent.y == t->y) return; while ( t->x != agent.x + dirs[agent.facing][0] || t->y != agent.y + dirs[agent.facing][1]) turn(c_cw), say(c_cw), hear(); try_forward(fd); }</lang>

common.c:

<lang c>struct agent_t{ int x, y, facing, ball; } agent = { 0, 0, 0, -1 }; enum { c_fwd, c_cw, c_ccw, c_get, c_drop, c_over, c_stop, s_red, s_green, s_yellow, s_blue, b_red, b_green, b_yellow, b_blue, a_bump, s_full, a_full, s_empty, a_empty, MAX_CMD };

char *cmds = "^><@!+.RGYBrgyb|SAsa"; inline int cmd_to_char(int c) { return cmds[c]; } inline int char_to_cmd(int c) { int i; for (i = 0; cmds[i] && cmds[i] != c; i++); return cmds[i] ? i : -1; }

  1. define say_l(x) send_cmd(fd, x)
  2. define hear_l() read_cmd(fd)
  3. define say(x) send_cmd(fd, cmd_to_char(x))
  4. define hear() char_to_cmd(read_cmd(fd))

int irand(int n) { int r, rand_max = RAND_MAX - RAND_MAX % n; while ((r = rand()) >= rand_max); return r / (rand_max / n); }

int wrand(int *x, int l) { int i, sum = 0; for (i = 0; i < l; i++) sum += x[i]; sum = irand(sum); for (i = 0; i < l; sum -= x[i++]) if (sum < x[i]) break; return i; }

int read_fd(int fd, char *buf, int len) { int l; l = read(fd, buf, len); if (l < 0) return 0; buf[l] = 0; return l; }

int write_fd(int fd, char *buf, int len) { int l = write(fd, buf, len); if (l != len) return 0; return 1; }

int read_cmd(int fd) { char buf[2]; if (read_fd(fd, buf, 1) <= 0) return -1; return buf[0]; }

int send_cmd(int fd, char cmd) { char c = cmd; return write_fd(fd, &c, 1); }

typedef unsigned char byte; enum { red, green, yellow, blue, ball = 16, wall = 32, unknown = 64, marked = 128 };

  1. define FOR(a, x) for (a = 0; a < x; a++)

byte **byte_array(int w, int h) { int i; byte **f = calloc(1, sizeof(byte *) * h + w * h); f[0] = (byte*)(f + h); FOR(i, h - 1) f[i + 1] = f[i] + w; return f; }

void shuffle(int *x, int len) { int i, j, t; for (i = len - 1; i > 0; i--) { j = irand(i + 1); t = x[i], x[i] = x[j], x[j] = t; } }

int dirs[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; int randomize(byte **f, int w, int h, int x, int y, int rem) { int d[4] = {0, 1, 2, 3}, i; if (x <= 0 || x >= w - 1 || y <= 0 || y >= h - 1) return rem; if (f[y][x] != wall) return rem;

f[y][x] = 0; --rem;

shuffle(d, 4); for (i = 0; i < 4 && rem; i++) { rem = randomize(f, w, h, x + dirs[d[i]][0], y + dirs[d[i]][1], rem); } return rem; }

byte **make_field(int w, int h) { int i, j, c, x, cells[4] = {0}; byte **f = byte_array(w, h); FOR(i, w) FOR(j, h) f[i][j] = wall; randomize(f, w, h, irand(w - 2) + 1, irand(h - 2) + 1, (h - 2) * (w - 2) * 1 / 2);

FOR(i, w) FOR(j, h) { if (f[i][j] == wall) continue; cells[ f[i][j] = irand(4) ] ++; }

x = 0; FOR(i, w) FOR(j, h) { if (f[i][j] == wall) continue; if (irand(4)) { /* 1 in 4 chance to place a ball, else try place agent */ if (!irand(++x)) agent.x = j, agent.y = i; continue; } c = wrand(cells, 4); cells[c] --; f[i][j] |= ball | c * 4; }

agent.facing = irand(3);

return f; }

char *colors[] = { "31", "32", "33", "34" }; char ag[] = { "<V>A" };

inline int cell_color(byte **f, int x, int y) { return f[y][x] & 3; }

inline int cell_ball(byte **f, int x, int y) { if (!(f[y][x] & ball) || (f[y][x] == unknown)) return -1; return (f[y][x] >> 2) & 3; }

void show_field(byte **f, int w, int h) { int i, j;

printf("\033[H"); FOR(i, h) { FOR(j, w) { if (f[i][j] == wall) { printf("## "); continue; } if (f[i][j] == unknown) { printf("-- "); continue; }

printf("\033[7;%sm", colors[cell_color(f, j, i)]); putchar(j == agent.x && i == agent.y ? ag[agent.facing] : ' ');

if (cell_ball(f, j, i) >= 0) printf("\033[%smO\033[m ", colors[cell_ball(f, j, i)]); else printf(" \033[m ");

		}

putchar('\n'); } printf("agent carry: %d\n", agent.ball); fflush(stdout); }

int agent_forward(byte **f) { int x, y; x = agent.x + dirs[agent.facing][0]; y = agent.y + dirs[agent.facing][1]; if (f[y][x] == wall) return 0; agent.x = x; agent.y = y; return 1; }

void turn(int dir) { if (dir == c_ccw) if (--agent.facing < 0) agent.facing = 3; if (dir == c_cw) if (++agent.facing > 3) agent.facing = 0; }</lang>