Re [m-dev.] ICFP Contest: simple position reachability inkblot
Peter Moulder
pmoulder at mail.csse.monash.edu.au
Sat Jun 28 19:48:49 AEST 2003
Preprocesses the track to find the reachable bit of finishing line.
(Some maps contain unreachable finishing line squares.)
As a simple correctness check, I've made it output the refined
map along with a path corresponding to some notion of shortest path.
(Not euclidean shortest, as is evident from e.g. 5_Car.xpm.)
You may be pained to learn I wrote it in C++.
For use with something like
mkdir annotated; \
for i in *.trk; do \
b=`basename $i .trk`; \
./reachability < $i | ./ann-trk2xpm.sh > annotated/$b.xpm; \
done
ann-trk2xpm.sh:
#! /bin/sh
cat <<EOF
/* XPM */'
static char *track[] = {
"1024 768 10 1",
". c #333333",
"* c #ffff55",
"! c #884400",
"g c #00ff00",
"r c #ff0000",
"w c #ffffff",
"b c #0000ff",
"^ c #000000",
"| c #ff8800",
"= c #cccc00",
EOF
sed '1,2d;s/^/"/;3,769s/$/",/;770s/$/"};/' $1
reachability.cc appended.
pjm.
/* Read in the track, and preprocess it by doing reachability analysis.
* In particular, get rid of bogus finish lines.
*/
#include <assert.h>
#include <iostream>
#include <vector>
using std::cin;
using std::cout;
using std::vector;
#define HEADER "1024\n768\n"
enum { Y, X, N_DIMS };
typedef unsigned dimT;
static unsigned const height = 768;
static unsigned const width = 1024;
static char const
reachable_road = '^',
reachable_finish = '|',
unseen_road = '.',
unseen_finish = '!';
static char const barriers[] = {'r', 'g', 'b', 'w'};
class unchecked_pt {
private:
unsigned coord[2];
private:
void assert_good() const {
assert(coord[Y] <= height);
assert(coord[X] <= width);
}
public:
explicit unchecked_pt(unsigned i, unsigned j) {
coord[Y] = i;
coord[X] = j;
assert_good();
}
unsigned y() const {
return coord[Y];
}
unsigned x() const {
return coord[X];
}
unsigned get(dimT d) const {
assert((unsigned) d < N_DIMS);
return coord[d];
}
};
static unchecked_pt const len(height, width);
class pt
{
private:
unsigned coords;
explicit pt(unsigned const ix)
: coords(ix)
{
assert(ix < width * height);
}
public:
pt(pt const &o)
: coords(o.coords)
{}
explicit pt(unsigned i, unsigned j) {
assert(i < height);
assert(j < width);
coords = i * width + j;
assert(coords < width * height);
}
static pt from_ix(unsigned const ix) {
return pt(ix);
}
unsigned y() const {
return coords / width;
}
unsigned x() const {
return coords % width;
}
unsigned get(dimT d) const {
assert((unsigned) d < N_DIMS);
return (d == Y ? y() : x());
}
unsigned ix() const {
assert(coords < width * height);
return coords;
}
};
static unsigned travelled[height * width];
static unsigned
get_travelled(pt const p) {
return travelled[p.ix()];
}
static void
set_travelled(pt const p, unsigned t) {
assert(t != ~0u);
unsigned &x = travelled[p.ix()];
assert(x == ~0u);
x = t;
}
static char track[height * width + 2];
static char
get_track(pt const p) {
char const ret = track[p.ix()];
return ret;
}
static void
set_track(pt const &p, char const tr) {
track[p.ix()] = tr;
}
static unsigned arrived_from[width * height];
static pt
find_start()
{
unsigned ret_i, ret_j;
bool found = false;
for(unsigned i = 0; i < height; ++i) {
for(unsigned j = 0; j < width; ++j) {
pt const p(i, j);
if(get_track(p) == '*') {
assert(!found);
ret_i = i; ret_j = j;
found = true;
}
}
}
assert(found);
pt const ret(ret_i, ret_j);
set_track(ret, unseen_road);
return ret;
}
static void
find_next_level(unsigned const t, vector<pt> const &curr,
vector<pt> &next, bool &found_finish, pt &first_finish)
{
assert(!curr.empty());
assert(next.empty());
assert(!found_finish);
for(vector<pt>::const_iterator ci( curr.begin()), ciEnd(curr.end());
ci != ciEnd; ++ci) {
pt const p(*ci);
assert(get_travelled(p) == ~0u);
set_travelled(p, t);
assert(get_track(p) == reachable_road);
int offset[N_DIMS];
/* Iterate over 0,1,-1 so that straight lines are faster. */
for(offset[Y] = 0; offset[Y] <= 1; offset[Y] = 1 - 2*offset[Y]) {
unsigned const p2_y = p.y() + offset[Y];
if(p2_y >= len.y())
continue;
for(offset[X] = 0; offset[X] <= 1; offset[X] = 1 - 2*offset[X]) {
unsigned const p2_x = p.x() + offset[X];
if(p2_x >= len.x())
continue;
pt const p2(p2_y, p2_x);
switch(get_track(p2)) {
case unseen_road:
next.push_back(p2);
set_track(p2, reachable_road);
arrived_from[p2.ix()] = p.ix();
continue;
case 'r': case 'g': case 'b': case 'w':
continue;
case unseen_finish:
if(offset[X] != 1)
continue;
set_track(p2, reachable_finish);
arrived_from[p2.ix()] = p.ix();
if(!found_finish) {
found_finish = true;
first_finish = p2;
}
continue;
case reachable_road:
case reachable_finish:
continue;
default:
fprintf(stderr,
"Unexpected road square `%c'.\n",
get_track(p2));
break;
}
}
}
}
}
/* Change reachable road to '^', and reachable finish to '|'. */
static void
paint_reachable(pt const start, pt &first_finish)
{
for(unsigned i = 0; i < height; ++i) {
for(unsigned j = 0; j < width; ++j) {
pt const p(i, j);
int const x = get_track(p);
assert(x != reachable_road);
assert(x != reachable_finish);
assert((x == unseen_road)
|| (x == unseen_finish)
|| (memchr(barriers, x, sizeof(barriers))
!= NULL));
}
}
vector<pt> level_a, level_b;
level_a.push_back(start);
set_track(start, reachable_road);
assert(level_a.size() == 1);
unsigned t = 0;
memset(travelled, 0xff, sizeof(travelled));
memset(arrived_from, 0xff, sizeof(arrived_from));
bool found_finish = false;
for(;;) {
level_b.clear();
find_next_level(t, level_a, level_b, found_finish, first_finish);
++t;
if(found_finish)
break;
assert(!level_b.empty());
level_a.clear();
find_next_level(t, level_b, level_a, found_finish, first_finish);
++t;
if(found_finish)
break;
assert(!level_b.empty());
}
}
static void
paint_shortest(pt const &first_finish, pt const &start)
{
pt curr(first_finish);
while(curr.ix() != start.ix()) {
set_track(curr, '=');
curr = pt::from_ix(arrived_from[curr.ix()]);
}
}
int main()
{
char smallbuf[sizeof(HEADER)];
cin.read(smallbuf, sizeof(HEADER) - 1);
assert(memcmp(smallbuf, HEADER, sizeof(HEADER) - 1) == 0);
for(unsigned i = 0; i < 768; ++i) {
char *track_row = track + i * width;
assert(track_row + 1025 <= track + sizeof(track));
track_row[1024] = '\0';
cin.read(track_row, 1025);
assert(track_row[1024] == '\n');
}
cin.read(smallbuf, 1);
assert(cin.eof());
pt const start(find_start());
pt first_finish(0,0);
paint_reachable(start, first_finish);
paint_shortest(first_finish, start);
cout << HEADER;
for(unsigned i = 0; i < height; ++i) {
char const *track_row = track + i * width;
cout.write(track_row, width);
cout.put('\n');
}
}
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to: mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions: mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------
More information about the developers
mailing list