Skip to content

Instantly share code, notes, and snippets.

@hank
Created January 20, 2013 06:36
Show Gist options
  • Save hank/4576989 to your computer and use it in GitHub Desktop.
Save hank/4576989 to your computer and use it in GitHub Desktop.
A little program I wrote for a class.
/* Project: Module 12 Assignment
*
* Program: control_probe
* File Name: control_probe.c
* Purpose: Connect to a shared memory area and a probe guidance server, and
* command a probe to map the given cavern using simple network commands. The
* algorithm at work uses a recursive depth-first search, which uses a fair
* bit of memory for the stack, but usually solves a cavern in 10-13 seconds
* on aplcenmp, and doesn't invoke a single lawsuit in the first 50 caverns
* tested.
*
* Synopsis (Usage and Parameters):
* ./control_probe -m <shared memory key> [-P <server port> -c <cavern id>]
* The port and cavern ID are optional, and are 10000 and 0 respectively by
* default.
*
* Programmer: Erik Gregg
* Organization: JHU EP
* Host System: UNIX
* Language: C
* Date Created: 2012/12/10
*/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include "log_mgr.h"
#include "shmlib.h"
#include "socket_utils.h"
#include "cavern.h"
#define ROWS_SIZE 24
#define COLS_SIZE 80
#define SHM_SIZE (2 * ROWS_SIZE * 2 * COLS_SIZE)
#define CENTER (SHM_SIZE / 2)
#define POS_NORTH (position - 2*COLS_SIZE)
#define POS_EAST (position - 1)
#define POS_WEST (position + 1)
#define POS_SOUTH (position + 2*COLS_SIZE)
/* Default Cavern. 0 for random */
#define CAVERN 0
/* Default server port. */
#define SERVER_PORT 10000
/* typedefs */
typedef char MAPS [2*ROWS_SIZE][2*COLS_SIZE];
/* Globals */
MAPS *Display_map;
static int Move_count = 0;
static int Shm_key = 0;
/* Function Declarations */
static int insert_probe(int, int);
static int move_probe(int, DIRECTIONS);
static int explode_probe(int, time_t);
static int print_results(PROBE_MESSAGES*);
static int print_move_response(PROBE_MESSAGES*);
int probe_explore_recurse(int, char*);
int probe_explore(int, char*, int);
/* signal handler */
void handler(int dum)
{
/* Delete the shared memory */
destroy_shm(Shm_key);
exit(100);
}
int main(int argc, char *argv[])
{
extern int opterr; /* used by getopt(3) */
extern char *optarg; /* used by getopt(3) */
char c;
int shmid;
int port = SERVER_PORT;
int cavern = CAVERN;
int sock;
int status;
char* shm;
time_t start_time, end_time;
/* set up signal handling */
signal(SIGINT, handler);
signal(SIGQUIT, handler);
/* command line option argument processing */
opterr = 0; /* suppress getopt(3) generated messages */
while ((c = getopt(argc, argv, "m:P:c:")) != EOF)
switch (c)
{
case 'm':
Shm_key = atoi(optarg);
break;
case 'P':
port = atoi(optarg);
break;
case 'c':
cavern = atoi(optarg);
break;
default:
break;
}
if (Shm_key <= 0)
{
fprintf (stderr, "%s -m <shm_key> -P <port> -c <cavern>\n", argv[0]);
exit (1);
}
// Connect to shared memory
shm = connect_shm(Shm_key, SHM_SIZE);
if(!shm)
{
log_event(FATAL, "connect_shm() failed");
fprintf(stderr, "connect_shm() failed\n");
exit(-1);
}
log_event(INFO, "connect_shm(%x, %d) success", Shm_key, SHM_SIZE);
/* Connect to stream socket */
sock = setup_client(port);
if(sock < 0)
{
fprintf(stderr, "socket creation failed\n");
log_event(FATAL, "socket creation failed");
exit (3);
}
log_event(INFO, "setup_client(%d) success", port);
/* Insert the probe. */
if(insert_probe(sock, cavern) < 0)
{
fprintf(stderr, "Insert probe failed.\n");
log_event(FATAL, "Insert probe failed");
exit (3);
}
/* Record the start time */
start_time = time(0);
/* Move the probe. */
probe_explore_recurse(sock, shm);
/* Record the end time */
end_time = time(0);
/* Explode the probe. */
if(explode_probe(sock, end_time - start_time) < 0)
{
fprintf(stderr, "Explode probe failed.\n");
log_event(FATAL, "Explode probe failed");
exit (3);
}
/* Kill the display */
shm[CENTER] = ')';
/* Delete the shared memory */
destroy_shm(Shm_key);
/* Close the socket */
close(sock);
exit(0);
}
static int insert_probe(int sock, int cavern)
{
PROBE_MESSAGES pm = {0};
pm.msg_type = MSG_INSERT_PROBE;
pm.msg.insert.cavern = cavern;
send(sock, &pm, sizeof(pm), 0);
return OK;
}
static int move_probe(int sock, DIRECTIONS dir)
{
PROBE_MESSAGES pm = {0};
pm.msg_type = MSG_MOVE;
pm.msg.move.move = dir;
send(sock, &pm, sizeof(pm), 0);
recv(sock, &pm, sizeof(pm), 0);
// Could get MSG_MV_RESPONSE or MSG_RESULTS
// MSG_RESULTS will happen if 5000 moves or 30 minutes are used.
if(pm.msg_type == MSG_MV_RESPONSE)
{
print_move_response(&pm);
return pm.msg.mv_response.success;
}
else
{
print_results(&pm);
return ERROR;
}
}
static int explode_probe(int sock, time_t elapsed)
{
PROBE_MESSAGES pm = {0};
pm.msg_type = MSG_EXPLODE;
send(sock, &pm, sizeof(pm), 0);
recv(sock, &pm, sizeof(pm), 0);
printf("Probe Exploded after %d seconds\n", elapsed);
log_event(INFO, "Probe Exploded after %d seconds", elapsed);
if(print_results(&pm) == OK) return OK;
else return ERROR;
}
static int print_results(PROBE_MESSAGES* pm)
{
if(pm->msg_type == MSG_RESULTS)
{
printf("Cavern Size: %d\n"
"Amount Mapped: %d\n"
"Lawsuits: %d\n"
"Moves: %d\n"
"Move per space ratio: %.3f\n",
pm->msg.results.cavern_size,
pm->msg.results.amt_mapped,
pm->msg.results.lawsuits,
pm->msg.results.moves,
((float)pm->msg.results.moves)/pm->msg.results.cavern_size
);
return OK;
}
else
{
log_event(WARNING, "print_results called on non-results");
return ERROR;
}
}
static int print_move_response(PROBE_MESSAGES* pm)
{
if(pm->msg_type == MSG_MV_RESPONSE)
{
return OK;
}
else
{
log_event(WARNING, "print_move_response called on wrong message type");
return ERROR;
}
}
int probe_explore_recurse(int sock, char* shm)
{
// Initialize state
int position = CENTER;
probe_explore(sock, shm, position);
}
#define PROBE_EXPLORE(comp, bound, pos_dir, move_dir, move_opposite, str_dir) \
if(position comp bound) \
{ \
if(shm[pos_dir] == 0) \
{ \
printf("%d moves\r", ++Move_count); \
status = move_probe(sock, move_dir); \
if(status == YES) \
{ \
log_event(INFO, "Successfully moved " str_dir "!"); \
status = probe_explore(sock, shm, pos_dir); \
if(status == ERROR) \
{ \
return ERROR; \
} \
printf("%d moves\r", ++Move_count); \
if(move_probe(sock, move_opposite) == ERROR) \
{ \
return ERROR; \
} \
} \
else if(status == NO) \
{ \
log_event(INFO, "Failed to move " str_dir "!"); \
shm[pos_dir] = '#'; \
} \
else \
{ \
return ERROR; \
} \
} \
}
int probe_explore(int sock, char* shm, int position)
{
int status;
log_event(INFO, "At position %d", position);
shm[position] = '.';
// First, try to move the probe north if it's possible
PROBE_EXPLORE(>=, 2*COLS_SIZE, POS_NORTH, MOVE_NORTH, MOVE_SOUTH, "north");
// Try to move the probe east if it's possible
PROBE_EXPLORE(>, 0, POS_EAST, MOVE_EAST, MOVE_WEST, "east");
// Try to move the probe south if it's possible
PROBE_EXPLORE(<=, SHM_SIZE - 2*COLS_SIZE - 1, POS_SOUTH, MOVE_SOUTH, MOVE_NORTH, "south");
// Try to move the probe west if it's possible
PROBE_EXPLORE(<, SHM_SIZE - 1, POS_WEST, MOVE_WEST, MOVE_EAST, "west");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment