Task: Wireworld


C++: #include <ggi/ggi.h>
#include <set>
#include <map>
#include <utility>
#include <iostream>
#include <fstream>
#include <string>

#include <unistd.h> 

enum cell_type { none, wire, head, tail };







class display
{
public:
  display(int sizex, int sizey, int pixsizex, int pixsizey,
          ggi_color* colors);
  ~display()
  {
    ggiClose(visual);
    ggiExit();
  }

  void flush();
  bool keypressed() { return ggiKbhit(visual); }
  void clear();
  void putpixel(int x, int y, cell_type c);
private:
  ggi_visual_t visual;
  int size_x, size_y;
  int pixel_size_x, pixel_size_y;
  ggi_pixel pixels[4];
};

display::display(int sizex, int sizey, int pixsizex, int pixsizey,
                 ggi_color* colors):
  pixel_size_x(pixsizex),
  pixel_size_y(pixsizey)
{
  if (ggiInit() < 0)
  {
    std::cerr << "couldn't open ggi\n";
    exit(1);
  }

  visual = ggiOpen(NULL);
  if (!visual)
  {
    ggiPanic("couldn't open visual\n");
  }

  ggi_mode mode;
  if (ggiCheckGraphMode(visual, sizex, sizey,
                        GGI_AUTO, GGI_AUTO, GT_4BIT,
                        &mode) != 0)
  {
    if (GT_DEPTH(mode.graphtype) < 2) 
      ggiPanic("low-color displays are not supported!\n");
  }
  if (ggiSetMode(visual, &mode) != 0)
  {
    ggiPanic("couldn't set graph mode\n");
  }
  ggiAddFlags(visual, GGIFLAG_ASYNC);

  size_x = mode.virt.x;
  size_y = mode.virt.y;

  for (int i = 0; i < 4; ++i)
    pixels[i] = ggiMapColor(visual, colors+i);
}

void display::flush()
{
  
  ggiSetDisplayFrame(visual, ggiGetWriteFrame(visual));

  
  ggiFlush(visual);

  
  
  
  ggiSetWriteFrame(visual, 1-ggiGetDisplayFrame(visual));
}

void display::clear()
{
  ggiSetGCForeground(visual, pixels[0]);
  ggiDrawBox(visual, 0, 0, size_x, size_y);
}

void display::putpixel(int x, int y, cell_type cell)
{
  
  
  ggiSetGCForeground(visual, pixels[cell]);
  ggiDrawBox(visual,
             x*pixel_size_x, y*pixel_size_y,
             pixel_size_x, pixel_size_y);
}






class wireworld
{
public:
  void set(int posx, int posy, cell_type type);
  void draw(display& destination);
  void step();
private:
  typedef std::pair<int, int> position;
  typedef std::set<position> position_set;
  typedef position_set::iterator positer;
  position_set wires, heads, tails;
};

void wireworld::set(int posx, int posy, cell_type type)
{
  position p(posx, posy);
  wires.erase(p);
  heads.erase(p);
  tails.erase(p);
  switch(type)
  {
  case head:
    heads.insert(p);
    break;
  case tail:
    tails.insert(p);
    break;
  case wire:
    wires.insert(p);
    break;
  }
}

void wireworld::draw(display& destination)
{
  destination.clear();
  for (positer i = heads.begin(); i != heads.end(); ++i)
    destination.putpixel(i->first, i->second, head);
  for (positer i = tails.begin(); i != tails.end(); ++i)
    destination.putpixel(i->first, i->second, tail);
  for (positer i = wires.begin(); i != wires.end(); ++i)
    destination.putpixel(i->first, i->second, wire);
  destination.flush();
}

void wireworld::step()
{
  std::map<position, int> new_heads;
  for (positer i = heads.begin(); i != heads.end(); ++i)
    for (int dx = -1; dx <= 1; ++dx)
      for (int dy = -1; dy <= 1; ++dy)
      {
        position pos(i->first + dx, i->second + dy);
        if (wires.count(pos))
          new_heads[pos]++;
      }
  wires.insert(tails.begin(), tails.end());
  tails.swap(heads);
  heads.clear();
  for (std::map<position, int>::iterator i = new_heads.begin();
       i != new_heads.end();
       ++i)
  {

    if (i->second < 3)
    {
      wires.erase(i->first);
      heads.insert(i->first);
    }
  }
}

ggi_color colors[4] =
  {{ 0x0000, 0x0000, 0x0000 },  
   { 0x8000, 0x8000, 0x8000 },  
   { 0xffff, 0xffff, 0x0000 },  
   { 0xffff, 0x0000, 0x0000 }}; 

int main(int argc, char* argv[])
{
  int display_x = 800;
  int display_y = 600;
  int pixel_x = 5;
  int pixel_y = 5;

  if (argc < 2)
  {
    std::cerr << "No file name given!\n";
    return 1;
  }

  
  std::ifstream f(argv[1]);
  wireworld w;
  std::string line;
  int line_number = 0;
  while (std::getline(f, line))
  {
    for (int col = 0; col < line.size(); ++col)
    {
      switch (line[col])
      {
      case 'h': case 'H':
        w.set(col, line_number, head);
        break;
      case 't': case 'T':
        w.set(col, line_number, tail);
        break;
      case 'w': case 'W': case '.':
        w.set(col, line_number, wire);
        break;
      default:
        std::cerr << "unrecognized character: " << line[col] << "\n";
        return 1;
      case ' ':
        ; 
      }
    }
    ++line_number;
  }

  display d(display_x, display_y, pixel_x, pixel_y, colors);

  w.draw(d);

  while (!d.keypressed())
  {
    usleep(100000);
    w.step();
    w.draw(d);
  }
  std::cout << std::endl;
}






Python: 

from io import StringIO
from collections import namedtuple
from pprint import pprint as pp
import copy

WW = namedtuple('WW', 'world, w, h')
head, tail, conductor, empty = allstates = 'Ht. '


infile = StringIO()

def readfile(f):
    
    world  = [row.rstrip('\r\n') for row in f]
    height = len(world)
    width  = max(len(row) for row in world)
    
    nonrow = [ " %*s " % (-width, "") ]
    world  = nonrow + \
               [ " %*s " % (-width, row) for row in world ] + \
               nonrow   
    world = [list(row) for row in world]
    return WW(world, width, height)

def newcell(currentworld, x, y):
    istate = currentworld[y][x]
    assert istate in allstates, 'Wireworld cell set to unknown value "%s"' % istate
    if istate == head:
        ostate = tail
    elif istate == tail:
        ostate = conductor
    elif istate == empty:
        ostate = empty
    else: 
        n = sum( currentworld[y+dy][x+dx] == head
                 for dx,dy in ( (-1,-1), (-1,+0), (-1,+1),
                                (+0,-1),          (+0,+1),
                                (+1,-1), (+1,+0), (+1,+1) ) )
        ostate = head if 1 <= n <= 2 else conductor
    return ostate

def nextgen(ww):
    'compute next generation of wireworld'
    world, width, height = ww
    newworld = copy.deepcopy(world)
    for x in range(1, width+1):
        for y in range(1, height+1):
            newworld[y][x] = newcell(world, x, y)
    return WW(newworld, width, height)

def world2string(ww):
    return '\n'.join( ''.join(row[1:-1]).rstrip() for row in ww.world[1:-1] )

ww = readfile(infile)
infile.close()

for gen in range(10):
    print ( ("\n%3i " % gen) + '=' * (ww.w-4) + '\n' )
    print ( world2string(ww) )
    ww = nextgen(ww)