Newsgroups: comp.sources.misc
From: ijp@doc.ic.ac.uk (Ian Palmer)
Subject:  v26i028:  scamper - Cellular Automata Simulator, Part05/10
Message-ID: <1991Nov20.234002.14530@sparky.imd.sterling.com>
X-Md4-Signature: 4db37dbf636821b53f0328d7fa5886e8
Date: Wed, 20 Nov 1991 23:40:02 GMT
Approved: kent@sparky.imd.sterling.com

Submitted-by: ijp@doc.ic.ac.uk (Ian Palmer)
Posting-number: Volume 26, Issue 28
Archive-name: scamper/part05
Environment: X11R4, SunOS

---- CUT HERE -------- CUT HERE -------- CUT HERE -------- CUT HERE ----
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  calscan.c colour.c
# Wrapped by ijp@swan.doc.ic.ac.uk on Thu Nov  7 10:10:07 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'calscan.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'calscan.c'\"
else
echo shar: Extracting \"'calscan.c'\" \(17755 characters\)
sed "s/^X//" >'calscan.c' <<'END_OF_FILE'
X/*
X
X
X
X   *****                 *****                   *****                 *****
X  *     *               *     *                 *     *               *     *
X  *                     *     *                 *     *               *     *
X   **         *****     *     *    *       *    *     *     ******    *     *
X     *       *     *    *******    **     **    ******     *          ******
X      **     *          *     *    * *   * *    *          *          * *
X        *    *          *     *    *  * *  *    *          *          *  *
X  *     *    *          *     *    *   *   *    *           *****     *   *
X   *****     *          *     *    *       *    *          *          *    *
X             *                     *       *               *
X             *     *               *       *               *
X              *****                *       *                ******
X
X
X
X                                 by Ian Palmer
X
X                                      at
X
X              Imperial College of Science, Technology and Medicine
X                             University of London
X
X
X
X
X--------------------------------------------------------------------------------
X| Scamper is supplied "as is", without express or implied warranty.            |
X|                                                                              |
X| Permission to use, copy, modify and distribute this software, and any        |
X| documentation, for any non-commercial purpose is hereby granted without fee, |
X| provided that all copyright messages, and permission notices, remain intact. |
X|                                                                              |
X| Copyright 1991 by Ian Palmer of Imperial College of Science, Technology      |
X| and Medicine, University of London.                                          |
X--------------------------------------------------------------------------------
X
X   _____
X  /_  _/  Let Total Chaos reign forever !       I.J.Palmer,
X   / /  ___      ______________                 Department of Computing,
X  / /  / __\      |    _                        Imperial College,
X /_/  / /         | <> | /-\ |_                 180 Queen's Gate,
X      \ \__           /             _           London SW7 2BZ.
X       \___/          \ |-| /-\ <> <
X                      ______________>           ijp@doc.ic.ac.uk
X  PANIC NOW
X  and avoid       23. Add to Celt's pub meal and produce utter turmoil. (6,8)
X  the rush.       -----------------------------------------------------------
X
X
X*/
X
X/*
X      Program Segment      : calscan.c
X
X      Task                 : Read a line of text and see if there is a Cal 
X                             rule or a Cal command in it.
X                             Cal rules should be checked and added to the rules
X                             Cal commands should be executed
X                             Errors should be reported if located
X
X*/
X
X#include <stdio.h>
X#include <string.h>
X#include <ctype.h>
X#include "automata.h"
X#include "calscan.h"
X#include "colour.h"
X#include "domain.h"
X#include "rules.h"
X
Xstatic int  Sold, Snew, match, value, mask[8], shift, lineno, shiftstop ;
Xstatic char mtype, vtype, temp[100], input[100] ;
X
X/* ------------------------------------------------------------------------- */
X
Xint DoError( mess ) char *mess ;
X/* Produces an error in the form :
X
X    `(message)' at line (line no)
X    the input line
X
X  Pre : The current line is not valid, mess points to the error message.
X  Post: line not valid, return 0.
X
X*/
X{
X  char total[100] ;
X
X  sprintf(total,"`%s' at line %d",mess,lineno);
X  Error(total,input);
X  return 0 ;
X}
X
X/* ------------------------------------------------------------------------- */
X
Xvoid AddRule()
X/* Adds a rule, calling `NewRule (automata.c)'
X
X  Pre : The rule is valid and complete.
X  Post: Rule(s) added with relevant SHIFTing and STOPping
X*/
X{
Xint count, total, point, temp , shval;
X
X  if (! shift)                                                    /* If no shifting required, then simply add the rule */
X    NewRule(Sold,Sold,Snew,match,mtype,vtype,value,mask);
X  else {
X    total = 2 + 2*shape ;                                         /* Otherwise work out how many rules to add */
X    if (shiftstop)                                                /* Set the SHIFT value for the first rule */
X      shval = -1 ;
X    else
X      shval = Sold ;
X    for(count = 0 ; count<total ; ++count ) {                     /* For each rule to be added */
X      NewRule(Sold,shval,Snew,match,mtype,vtype,value,mask);      /* Add the rule */
X      for(temp=0 ; temp < shift ; ++temp)                         /* Shift the mask the correct number of times */
X        if (shape == 3)
X          Shift8();
X        else
X          Shift4_6();
X      if (shiftstop)                                              /* Set up next SHIFT value */
X        --shval ;
X      };
X    };
X}
X
X/* ------------------------------------------------------------------------- */
X
Xvoid Shift8()
X/* For an eight neighbourhood, produce the mask shifted round once to the left
X
X  Pre : For all x in mask p(x) is it's position
X  Post: For all x in mask' p'(x) = p(x) shifted
X*/
X{
Xint newpos, temp , oldpos, point ;
X
X  temp = mask[0] ;                                  /* Make a note of the first element in the mask */
X  newpos = 0 ;
X  for( point=0 ; point<8 ; ++point) {               /* For the 8 positions in the mask */
X    oldpos = newpos ;                               /* Locate the position of the item to be moved to it */
X    newpos = (oldpos + 4)%8 + (oldpos > 3) ;
X    mask[oldpos] = mask[newpos] ;                   /* And move the item */
X    };
X  mask[7] = temp ;                                  /* Make up for the one lost item */
X}
X
X/* ------------------------------------------------------------------------- */
X
Xvoid Shift4_6()
X/* For a four or six neighbourhood, produce the mask shifted round once to the left
X
X  Pre : For all x in mask p(x) is it's position
X  Post: For all x in mask' p'(x) = p(x) -1 
X*/
X{
Xint point , temp , total ;
X
X  temp = mask[0] ;                                  /* Make a note of the first element */
X  total = 2 + 2*shape ;                             /* Work out the number of mask positions */
X  for( point=1 ; point < total ; ++point)           /* Move each of the elements one to the left */
X    mask[point-1] = mask[point] ;
X  mask[total-1] = temp ;                            /* And place the old first element in the last position */
X}
X
X/* ------------------------------------------------------------------------- */
X
Xint isop(ch) char ch ;
X/* 
X  Post: 1 if ch is a valid operator
X        0 otherwise
X*/
X{
Xif ((ch == '!') || (ch == '=') || (ch == '>') || (ch == '<'))
X  return 1 ;
Xelse
X  return 0 ;
X}
X
X/* ------------------------------------------------------------------------- */
X
Xint read_int( string , ptr , num ) char *string ; int *ptr ; int *num ;
X/* Given a string, try to read a number from it, stripping out white space. If number is read return 1, else return 0.
X*/
X{
Xint done=0 , found =0 , Sold, val,Snew ;
Xchar ch ;
X
X  val=0 ;
X  Snew = *ptr ;
X  while(! done) {
X    Sold = Snew ;                                 /* Read next character */
X    if (isdigit(ch = string[Snew++])) {           /* If a digit add to right of number */
X      val = (val * 10) + (ch - '0') ;
X      found = 1 ;
X      }
X    else
X      if (((ch > ' ') && (ch != ',') && (ch != '{') && (ch != '}')) || found) {
X        Snew = Sold ;
X        done = 1 ;                                /* Else note that we are done (but skip any , { or }'s if nothing so far) */
X        };
X    };
X  *num = val ;
X  *ptr = Snew ;
X  return found ;                                  /* Return what was found */
X}
X
X/* ------------------------------------------------------------------------- */
X
Xint read_other( di, string,ptr,out ) char *string ; int *ptr,di ; char *out ;
X/* Given a string read the first white space bounded non number, returning 1 if read, 0 otherwise */
X{
Xint found = 0 , point , Sold , Snew ;
Xchar ch ;
X
X  point = 0;
X  Snew = *ptr ;
X  while( string[Snew] != 0) {             /* If you havn't reached the end of the line */
X    Sold = Snew ;
X    ch = string[Snew++] ;                 /* Get the next character */
X    if (isdigit(ch) && !di) {             /* If it is a digit, return what was located up until now */
X      *ptr = Sold ;
X      return found ;
X      };
X    if ((ch > ' ') && (ch != ',') && (ch != '{') && (ch != '}')) {
X      out[point++] = ch ;                 /* Add to what was found */
X      found = 1 ;
X      }
X    else
X      if (found) {                        /* If white space terminate found string and exit */
X        *ptr = Sold ;
X        out[point] = 0 ;
X        return found ;
X        };
X    };
X  *ptr = Snew ;
X  return found;
X}
X
X/* ------------------------------------------------------------------------- */
X
Xchar *read_item( line , val , ch ) char *line , *ch ; int *val ;
X/* Given a string, read the first non white space item, either a number (int), or a single character */
X{
Xchar c ;
Xint v ;
X
X  v=-1 ; c=' ' ;
X
X  while( isdigit(c) || (c == ' ')) {    /* While we have a digit, but at least once */
X    c = *(line++) ;                     /* get a character */
X    if (isdigit(c))                     /* if digit, add to number */
X      if (v==-1)
X        v = c - '0' ;
X      else
X        v = (v*10) + (c-'0') ;
X    };
X  *val = v ;                            /* Return number */
X  *ch = c ;                             /* Return last character */
X  return line ;                         /* Return new position in line */
X}
X
X/* ------------------------------------------------------------------------- */
X
Xint scanline( line ) char *line ;
X/* Scans a potential rule, noting any errors, returns 1 if o.k., 0 otherwise. */
X{
Xint num,m ;
Xchar ch ;
X       
X  shift = 0;                                /* Initialize some variables */
X  shiftstop = 0 ;
X  line = read_item(line,&Sold,&ch);         /* Read the `from' state */
X  if (Sold == -1) {
X    DoError("Missing from state");
X    return 0 ;
X    };
X  if (ch != '-') {                          /* Read the `->' */
X    DoError("Missing ->");
X    return 0;
X    };
X  line = read_item(line,&num,&ch);
X  if (ch != '>') {
X    DoError("Missing ->");
X    return 0;
X    };
X  line = read_item(line,&Snew,&ch);         /* Read the `to' state */
X  if (Snew==-1) {
X    DoError("Missing to state");
X    return 0;
X    };
X  if (ch != ':') {                          /* Read the `:' */
X    DoError("Missing :");
X    return 0 ;
X    };
X  
X  do {
X    line = read_item(line,&num,&ch);        /* Read any `>'s or `|'s */
X    if (ch == '>') 
X      if (! shiftstop)
X        ++shift ;
X      else {
X        DoError("Can't SHIFT after a STOP");
X        return 0 ;
X        };
X    if (ch == '|')
X      shiftstop = 1 ;
X  } while ((ch != '{') && (ch != 0));
X  
X  if (ch == 0) {                            /* check there is a start of mask (`{') */
X    DoError("Missing mask");
X    return 0;
X    };
X  
X  for(m=0 ; m<8 ; ++m)                      /* Initialize the mask */
X    mask[m] = -3 ;
X  
X  m = 0 ;
X  do {
X    line = read_item(line,&num,&ch) ;       /* Read mask */
X    if (num != -1)
X      mask[m++] = num ;
X    else {
X      if (ch == '*')
X        mask[m++] = -3 ;
X      else if (ch == '!')
X        mask[m++] = -2 ;
X      else if (ch == 'e')
X        mask[m++] = -4 ;
X      else if (ch == 'o')
X        mask[m++] = -5 ;
X      else if (ch == '?')
X        mask[m++] = -1 ;
X      else if (ch != '}') {
X        sprintf(temp,"Bad mask value in position %d",++m);
X        DoError(temp);
X        return 0 ;
X        };
X      if (ch != '}')
X        line = read_item(line,&num,&ch);
X      };
X    if ((ch != '}') && (ch != ',')) {
X      DoError("Missing , or }");
X      return 0;
X      };
X  } while((ch != '}') && (m < 8));
X  if (ch != '}') {
X    DoError("Mask too big");
X    return 0;
X    };
X  
X  match = 0;
X  value = 0;
X  mtype = '=';
X  vtype = '*';
X  for( m=0 ; m<8 ; ++m )
X    if ((mask[m] != -1) && (mask[m] != -3)) ++match ;
X  
X  line = read_item(line,&num,&ch);          /* Read mask counter operator or state counter operator */
X  if ( ch == '#' ) {
X    line = read_item(line,&num,&ch);
X    if (isop(ch))
X      mtype = ch ;
X    else {
X      sprintf(temp,"Bad counter operation %c",ch);
X      DoError(temp);
X      return 0 ;
X      };
X    line = read_item(line,&num,&ch);
X    if (num != -1)
X      match = num ;
X    else {
X      DoError("Missing mask counter's value");
X      return 0 ;
X      };
X    };
X  if (isop(ch)) {
X    vtype = ch ;
X    line = read_item(line,&num,&ch);
X    if (num != -1)
X      value = num ;
X    else {
X      DoError("Missing state counter's value");
X      return 0 ;
X      };
X    }
X  
X  if (ch > ' ') {
X    sprintf(temp,"Bad counter operation %c",ch);
X    DoError(temp);
X    return 0;
X    };
X  
X  AddRule();
X  return 1 ;
X}
X
X/* ------------------------------------------------------------------------- */
X
Xint read_line( fid , line ) FILE *fid ; int line ;
X/* Read a line from file (fid), and see what is there, return 1 if o.k., 0 otherwise */
X{
Xint ptr , num, num2 , found ;
Xchar string[100],message[100],ch ;
X
X  lineno = line ;
X  ptr = 0;
X  found = 0 ;
X
X  for( num=0 ; num<100 ; ++num)             /* Clear the string */
X    input[num] = 0;
X  fgets( input,100,fid );                   /* Read a line */
X  if (input[0] == 0)                        /* if null, return o.k. */
X    return 1 ;
X  read_item(input,&num,&ch);                /* See if it starts with a number */
X  if (num != -1)                            /* If so, read a Cal rule */
X    return scanline( input );
X  else {
X    read_other(0,input,&ptr,string);        /* Clear */
X    if ( strcmp(string,"clear")==0) {
X      found = 1 ;
X      ClearRules();
X      };
X    if ( strcmp(string,"message")==0) {     /* Message */
X      found = 1 ;
X      if (input[strlen(input)-1] < 32)
X        input[strlen(input)-1] = 0 ;
X      Message( input+ptr );
X      };
X    if ( strcmp(string,"shape")==0) {       /* Shape */
X      found = 1 ;
X      if (read_int(input,&ptr,&num)) {
X        num = (num-2)/2 ;
X        if ((num >0) && (num <4))
X          link_cells(num,1) ;
X        else
X          return DoError("Shape unknown");
X        }
X      else
X        return DoError("Error: shape number");
X      };
X    if ( strcmp(string,"run")==0) {         /* Run */
X      found = 1 ;
X      running = 1 ;
X      StartRun(0);
X      while( running )
X        run();
X      };
X    if (strcmp(string,"step")==0) {         /* Step */
X      found = 1 ;
X      if (! read_int(input,&ptr,&num))
X        num = 1 ;
X      while( num-- )
X        run();
X      };
X    if (strcmp(string,"display")==0) {      /* Display */
X      found = 1 ;
X      if (! read_int(input,&ptr,&num))
X        num = 1 ;
X      if ((num) && !display && displaychange) {
X        display = 1 ;
X        DisplayOn();
X        update = 1 ;
X        updateX = start_x ;
X        updateC = 0;
X        while (update) {
X          display_cells();
X          if (EventPending())
X            service();
X          };
X        };
X      if (display && displaychange && !num) {
X        display = 0 ;
X        DisplayOff();
X        };
X      };
X    if (strcmp(string,"state")==0) {        /* State */
X      found = 1 ;
X      if (read_int(input,&ptr,&num)) {
X        if (read_other(1,input,&ptr,message)) {
X          states[num].colour = AllocColour(GetColourValue(message),states[num].colour);
X          UpdateButtons(num);
X          }
X        else
X          return DoError("Missing colour name");
X        }
X      else
X        return DoError("Missing state number");
X      };
X    if (strcmp(string,"stop")==0) {         /* Stop */
X      found = 1 ;
X      if (read_int(input,&ptr,&num))
X        stopat = num ;
X      };
X    if (strcmp(string,"save")==0) {         /* Save (domain) */
X      found = 1;
X      if (read_other(1,input,&ptr,FileName)) {
X        fnamel = strlen(FileName);
X        SaveScreen(2);
X        };
X      };
X    if (strcmp(string,"load")==0) {         /* Load (domain) */
X      found = 1;
X      if (read_other(1,input,&ptr,FileName)) {
X        fnamel = strlen(FileName);
X        LoadScreen(1);
X        };
X      };
X    if (strcmp(string,"bitmap")==0) {       /* (load) Bitmap */
X      found = 1;
X      if (read_other(1,input,&ptr,FileName)) {
X        fnamel = strlen(FileName);
X        LoadBitmap(1,1,0);
X        };
X      };
X    if (strcmp(string,"bitsave")==0) {      /* Bitsave (save bitmap) */
X      found = 1;
X      if (read_other(1,input,&ptr,FileName)) {
X        fnamel = strlen(FileName);
X        SaveBitmap(2);
X        };
X      };
X    if (strcmp(string,"add")==0) {          /* Add (insert domain by adding) */
X      found = 1;
X      if (read_other(1,input,&ptr,FileName)) {
X        fnamel = strlen(FileName);
X        InsertScreen(1);
X        };
X      };
X    if (strcmp(string,"and")==0) {          /* And (insert domain by anding) */
X      found = 1;
X      if (read_other(1,input,&ptr,FileName)) {
X        fnamel = strlen(FileName);
X        InsertScreen(2);
X        };
X      };
X    if (strcmp(string,"or")==0) {           /* Or (insert domain by oring) */
X      found = 1;
X      if (read_other(1,input,&ptr,FileName)) {
X        fnamel = strlen(FileName);
X        InsertScreen(3);
X        };
X      };
X    if (strcmp(string,"not")==0) {          /* Not (insert domain by not) */
X      found = 1;
X      if (read_other(1,input,&ptr,FileName)) {
X        fnamel = strlen(FileName);
X        InsertScreen(4);
X        };
X      };
X    if (strcmp(string,"torus")==0) {        /* (make domain) Torus */
X      found = 1 ;
X      change_domain(1);
X      };
X    if (strcmp(string,"flat")==0) {         /* (make domain) Flat */
X      found = 1 ;
X      change_domain(0);
X      };
X    };
X  if (found)
X    return 1 ;
X
X  return DoError("Unknown command");        /* Report that no command found */
X}
END_OF_FILE
if test 17755 -ne `wc -c <'calscan.c'`; then
    echo shar: \"'calscan.c'\" unpacked with wrong size!
fi
# end of 'calscan.c'
fi
if test -f 'colour.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'colour.c'\"
else
echo shar: Extracting \"'colour.c'\" \(17068 characters\)
sed "s/^X//" >'colour.c' <<'END_OF_FILE'
X/*
X
X
X
X   *****                 *****                   *****                 *****
X  *     *               *     *                 *     *               *     *
X  *                     *     *                 *     *               *     *
X   **         *****     *     *    *       *    *     *     ******    *     *
X     *       *     *    *******    **     **    ******     *          ******
X      **     *          *     *    * *   * *    *          *          * *
X        *    *          *     *    *  * *  *    *          *          *  *
X  *     *    *          *     *    *   *   *    *           *****     *   *
X   *****     *          *     *    *       *    *          *          *    *
X             *                     *       *               *
X             *     *               *       *               *
X              *****                *       *                ******
X
X
X
X                                 by Ian Palmer
X
X                                      at
X
X              Imperial College of Science, Technology and Medicine
X                             University of London
X
X
X
X
X--------------------------------------------------------------------------------
X| Scamper is supplied "as is", without express or implied warranty.            |
X|                                                                              |
X| Permission to use, copy, modify and distribute this software, and any        |
X| documentation, for any non-commercial purpose is hereby granted without fee, |
X| provided that all copyright messages, and permission notices, remain intact. |
X|                                                                              |
X| Copyright 1991 by Ian Palmer of Imperial College of Science, Technology      |
X| and Medicine, University of London.                                          |
X--------------------------------------------------------------------------------
X
X   _____
X  /_  _/  Let Total Chaos reign forever !       I.J.Palmer,
X   / /  ___      ______________                 Department of Computing,
X  / /  / __\      |    _                        Imperial College,
X /_/  / /         | <> | /-\ |_                 180 Queen's Gate,
X      \ \__           /             _           London SW7 2BZ.
X       \___/          \ |-| /-\ <> <
X                      ______________>           ijp@doc.ic.ac.uk
X  PANIC NOW
X  and avoid       23. Add to Celt's pub meal and produce utter turmoil. (6,8)
X  the rush.       -----------------------------------------------------------
X
X
X*/
X
X/*
X      Program Segment      : colour.c
X
X      Task                 : Allow user selection of colours, domain type, 
X                             title state, updtate small image, size of stats
X                             also perform grey scaling, sharpening, softening, 
X                             editiing of grey scale graph, apply and undo.
X
X*/
X
X#include <X11/Xlib.h>
X#include <math.h>
X#include <stdio.h>
X#include "windows.h"
X#include "automata.h"
X#include "colour.h"
X#include "stats.h"
X
Xint start, low, high , range=2, options, greyX[6] , greyY[6] , moving ;
X
Xvoid ColourOps()
X/* Task : Call up the `Change Colours' window.
X*/
X{
X  int z , scale ;
X
X  display = 4 ;
X  DisplayOn();
X}
X
Xvoid Hex( n ) int n ;
X/* Pre : n >=0 and n<options
X   Post: if n < max_states display a block of the colour of state n
X         else display the setting of one of the following :
X            n = 256 - Domain type (flat torus)
X            n = 257 - Fancy title (on off)
X            n = 258 - Update `View small' image
X            n = 259 - Number of stats displayed for middle statistic
X*/
X{
X  char string[10] ;
X
X  SetWindow(Display_Window);
X  if (n < 256) {
X    SetColour(states[n].colour);
X    FillRectangle(200,7*(DispY / 15),250,8*(DispY/15));
X    }
X  else {
X    SetColour(cols[domainbg]);
X    FillRectangle(200,7*(DispY / 15),250,8*(DispY/15));
X    SetColour(cols[domainfg]);
X    if (n == 256)
X      if (torus)
X        Centre("Torus",200,7*(DispY / 15),250,8*(DispY/15));      /* Domain type */
X      else
X        Centre("Flat",200,7*(DispY / 15),250,8*(DispY/15));
X    if (n == 257)
X      if (greyscale)
X        Centre("On",200,7*(DispY / 15),250,8*(DispY/15));         /* Fancy title */
X      else
X        Centre("Off",200,7*(DispY / 15),250,8*(DispY/15));
X    if (n == 258)
X      if (updatesmall)
X        Centre("On",200,7*(DispY / 15),250,8*(DispY/15));         /* Update small view image */
X      else
X        Centre("Off",200,7*(DispY / 15),250,8*(DispY/15));
X    if (n == 259) {
X      sprintf(string,"%d",mid_stat);
X      Centre(string,200,7*(DispY / 15),250,8*(DispY/15));         /* Number of stats */
X      };
X    };
X}
X
Xvoid ColourScreen()
X/* Display the `Change Colour' screen
X*/
X{
X  int n,c,dy ;
X  char string[100] ;
X
X  SetWindow(Display_Window);
X  SelectFont(Small_Font);
X  SetBackColour(cols[domainbg]);
X  SetColour(cols[domainbg]);
X  FillRectangle(0,0,200,DispY);
X  SetColour(cols[back]);
X
X  dy = DispY / 15 ;
X  FillRectangle(0,7*dy,200,8*dy);
X  SetColour(cols[domainfg]);
X  n = start ;
X  for(c=0 ; c<15 ; ++c ) {
X    if (n < 256) {
X      sprintf(string,"State %d %s",n,ColourName(states[n].colour));
X      Centre(string,0, c*dy , 200,(c+1)*dy);
X      }
X    else {
X      if (n == 256)
X        Centre("Domain Type",0, c*dy , 200,(c+1)*dy);
X      if (n == 257)
X        Centre("Title",0, c*dy , 200,(c+1)*dy);
X      if (n == 258)
X        Centre("Update Small Image",0, c*dy , 200,(c+1)*dy);
X      if (n == 259)
X        Centre("Last n stats =",0, c*dy , 200,(c+1)*dy);
X      };
X    n = (n+1) % options ;
X    };
X  Hex((start+7)%options);
X}
X
Xvoid ColourDown()
X/* Pre : The `Down' option has been selected
X   Post: Move to next option
X*/
X{
X  --start ;
X  if (start < 0)
X    start = options - 1 ;
X  ColourScreen();
X}
X
Xvoid ColourUp()
X/* Pre : The `Up' option has been selected
X   Post: Move to last option
X*/
X{
X  start = (start + 1) % options ;
X  ColourScreen();
X}
X
Xvoid ColourLeft()
X/* Pre : The `Left' option has been selected
X   Post: Change that option (decrement)
X*/
X{
X  int n , c, dy ;
X  char string[100] ;
X
X  dy = DispY / 15 ;
X  n = (start+7)%options ;
X  if (n < 256) {
X    c = ColourNumber(states[n].colour);
X    if (--c == -1)
X      c = NumberOfColours() -1 ;
X    states[n].colour = AllocColour(c,states[n].colour,-1);
X    Hex(n);
X    SetColour(cols[back]);
X    FillRectangle(0,7*dy,200,8*dy);
X    SetColour(cols[domainfg]);
X    sprintf(string,"State %d %s",n,ColourName(states[n].colour));
X    Centre(string,0, 7*dy , 200,8*dy);
X    }
X  else {
X    if (n == 256) {
X      change_domain(! torus);
X      Hex(256);
X      };
X    if (n == 257) {
X      greyscale = ! greyscale ;
X      Hex(257);
X      };
X    if (n == 258) {
X      updatesmall = ! updatesmall ;
X      Hex(258);
X      };
X    if ((n == 259) && (mid_stat > 3)) {
X      --mid_stat ;
X      Hex(259);
X      };
X    };
X}
X
Xvoid ColourRight()
X/* Pre : The `Left' option has been selected
X   Post: Change that option (increment)
X*/
X{
X  int n,c,dy ;
X  char string[100] ;
X
X  dy = DispY / 15 ;
X  n = (start+7)%options ;
X  if (n < 256) {
X    c = ColourNumber(states[n].colour);
X    c = (c+1) % NumberOfColours();
X    states[n].colour = AllocColour(c,states[n].colour,-1);
X    Hex(n);
X    SetColour(cols[back]);
X    FillRectangle(0,7*dy,200,8*dy);
X    SetColour(cols[domainfg]);
X    sprintf(string,"State %d %s",n,ColourName(states[n].colour));
X    Centre(string,0, 7*dy , 200,8*dy);
X    }
X  else {
X    if (n == 256) {
X      change_domain(! torus);
X      Hex(256);
X      };
X    if (n == 257) {
X      greyscale = ! greyscale ;
X      Hex(257);
X      };
X    if (n == 258) {
X      updatesmall = ! updatesmall ;
X      Hex(258);
X      };
X    if (n == 259) {
X      ++mid_stat ;
X      Hex(259);
X      };
X    };
X}
X
Xvoid ColourEvent( ev,ch,x,y,b ) EventType ev ; char ch ; int x,y,b ;
X/* Pre : X Event has occured, we are looking at the `Change Colour' option
X   Post: The event has been handled (only handles Expose events)
X*/
X{
X  if (ev == EventExpose)
X    ColourScreen();
X}
X
Xint CountLevels(where) int where ;
X/* Pre : where is current domain (0 or 1)
X   Post: returns the maximum number of states in existance, ( = max used state + 1)
X*/
X{
X  int n,x,y ;
X
X  n = 0 ;
X  for(x = 0 ; x<max_x ; ++x )
X    for(y=0 ; y<max_y ; ++y )
X      if (array[x][y] -> state[where] > n)
X        n = array[x][y] -> state[where] ;
X
X  return n+1 ;
X}
X
Xvoid GreyScale(n,p) int n,p ;
X/* Pre : n > 2 and n< 256 , p >=0 and p < 256
X   Post: There is an n element grey scale staring at state number p
X*/
X{
Xfloat diff , off ;
Xint grey , c , col , step , *done , last , px , i ;
Xchar name[20];
X
X  if (n < 3) {
X    states[0].colour = AllocColour(GetColourValue("black"),states[0].colour,-1);
X    states[1].colour = AllocColour(GetColourValue("white"),states[1].colour,-1);
X    return ;
X    };
X
X  for(c=p ; c<256 ; ++c)                                                  /* Unallocate previous colours */
X    states[c].colour = AllocColour(c % 2,states[c].colour,-1);            /* by setting all the states to black or white */
X  low = p ;
X  high = p+n-1 ;                                                          /* work out extent of grey scale (from and to) */
X  range = n ;
X  last = -1 ;
X  done = (int * ) malloc( n * sizeof( int ) );                            /* Set up array of boolean values to state if colour */
X  for( c=0 ; c < n ; ++c ) {                                              /* already allocated to that state */
X    done[c] = 0 ;
X    };
X  for( step = 4 ; step > 0 ; step = step / 2 )                            /* Fist pass through in 4's, then 2's then 1's */
X    for(c = 0 ; c<n ; c += step )                                         /* Go through the states to be allocated */
X      if (done[c] == 0) {                                                 /* If not already allocated */
X        px = (int) (( (float) c / (float) n ) * 256.0 );                  /* Calculate the grey level from the Grey Scale Graph */
X        for( i=0 ; px > greyX[i] ; ++i ) ;
X        px -= greyX[i-1] ;
X        diff = ( (float) px) / ( (float) (greyX[i] - greyX[i-1]) ) ;
X        grey = greyY[i-1] + (int) ( diff * ( (float) (greyY[i] - greyY[i-1]))) ;
X        grey = ( grey * 100 ) / 200 ;
X        if (grey > 100)
X          grey = 100 ;
X        grey = 100 - grey ;
X        if (grey > 100)
X          grey = 100 ;
X        sprintf(name,"grey%d",grey);                                      /* And allocate that colour to the state */
X        col = GetColourValue(name);
X        last = states[p+c].colour = AllocColour(col,states[p+c].colour,last);
X        done[c] = 1 ;
X        }
X      else
X        last = states[p+c].colour ;
X}
X
Xvoid DoGreyScale()
X/* Create an expanded grey scale picture */
X{
X  int neigh,x,y,val,n ;
X
X  neigh = 2 + 2*shape ;                 /* Work out the number of neighbours per cell */
X
X  n = CountLevels(old);                 /* Calculate the number of grey levels this will produce */
X  n = (n-1) * (neigh+1) + 1 ;
X  if (n > max_states) {                 /* If more than the max number of states, quit */
X    old = new ;
X    new = 1 - new ;
X    return ;
X    };
X
X  GreyScale(n,0);                       /* Create the correct grey scale */
X
X  for(x=0 ; x<max_x ; ++x) {            /* And calculate the new grey level for each cell */
X    for(y=0 ; y<max_y ; ++y) {
X      val = array[x][y] -> state[old] ;
X      for( n = 0 ; n<neigh ; ++n )
X        val += array[x][y] -> dir[n] -> state[old] ;
X      array[x][y] -> state[new] = val ;
X      if (test_inside(x,y) && (display == 1))
X        draw_cell(x,y);
X      if (updatesmall) {
X        XSetForeground( dpy,smallgc,colours[states[val].colour].mapno) ;
X        XDrawPoint( dpy, small, smallgc, x, y );
X        };
X      };
X    if (EventPending()) {
X      service();
X      SetWindow(Display_Window);
X      };
X    };
X}
X
Xvoid Sharpen()
X/* Sharpens the image */
X{
X  int neigh,x,y,val,n ;
X
X  neigh = 2 + 2*shape ;
X
X  for(x=0 ; x<max_x ; ++x) {
X    for(y=0 ; y<max_y ; ++y) {
X      val = 0 ;
X      for( n = 0 ; n<neigh ; ++n )
X        val += array[x][y] -> dir[n] -> state[old] ;
X      val = array[x][y] -> state[old] - (val / neigh) ;
X      array[x][y] -> state[new] = array[x][y] -> state[old] + val ;
X      if (array[x][y] -> state[new] > high)
X        array[x][y] -> state[new] = high ;
X      if (array[x][y] -> state[new] < low)
X        array[x][y] -> state[new] = low ;
X      if (test_inside(x,y) && (display == 1))
X        draw_cell(x,y);
X      if (updatesmall) {
X        XSetForeground( dpy,smallgc,colours[states[array[x][y] -> state[new]].colour].mapno) ;
X        XDrawPoint( dpy, small, smallgc, x, y );
X        };
X      };
X    if (EventPending()) {
X      service();
X      SetWindow(Display_Window);
X      };
X    };
X}
X
Xvoid Soften()
X/* Softens the image */
X{
X  int neigh,x,y,val,n ;
X
X  neigh = 2 + 2*shape ;
X
X  for(x=0 ; x<max_x ; ++x) {
X    for(y=0 ; y<max_y ; ++y) {
X      val = 0 ;
X      for( n = 0 ; n<neigh ; ++n )
X        val += array[x][y] -> dir[n] -> state[old] ;
X      val /= neigh ;
X      if (abs(val - array[x][y] -> state[old]) > (0.25*range)) {
X        array[x][y] -> state[new] = val ;
X        if (updatesmall) {
X          XSetForeground( dpy,smallgc,colours[states[val].colour].mapno) ;
X          XDrawPoint( dpy, small, smallgc, x, y );
X          };
X        }
X      else
X        array[x][y] -> state[new] = array[x][y] -> state[old] ;
X      if (test_inside(x,y) && (display == 1))
X        draw_cell(x,y);
X      };
X    if (EventPending()) {
X      service();
X      SetWindow(Display_Window);
X      };
X    };
X}
X
Xvoid Apply(colour) int colour ;
X/* Apply the current colours to the `Small View' image. If *colour* = 0 then recreate the grey scale first
X*/
X{
X  int x,y,n,oldmap[max_states] ;
X
X  for(n=0 ; n<max_states ; ++n)                           /* Make a note of old colour map positions */
X    oldmap[n] = colours[states[n].colour].mapno ;
X
X  if (! colour) {                                         /* If not colour, create grey scale */
X    n = CountLevels(new);
X    GreyScale(n,0);
X    };
X  for(x=0 ; x<max_x ; ++x )                               /* Update the `View Small' image */
X    for(y=0 ; y<max_y ; ++y) {
X      n = array[x][y] -> state[new] ;
X      if (colour || (oldmap[n] != colours[states[n].colour].mapno)) { 
X        XSetForeground( dpy,smallgc,colours[states[n].colour].mapno) ;
X        XDrawPoint( dpy, small, smallgc, x, y );
X        };
X      };
X}
X
Xvoid Undo()
X/* Attempt an undo operation */
X/* NOT guarenteed */
X{
X  int x,y ;
X
X  GreyScale(CountLevels(old),0);
X  old = new ;
X  new = 1 - new ;
X
X  for(x=0 ; x<max_x ; ++x)
X    for(y=0 ; y<max_y ; ++y) {
X      XSetForeground( dpy,smallgc,colours[states[array[x][y] -> state[new]].colour].mapno) ;
X      XDrawPoint( dpy, small, smallgc, x, y );
X      };
X}
X
Xvoid AlternateRun(mode) int mode ;
X/* Select the built in Cal program to run */
X{
X  char mess[60];
X  int colour ;
X
X  if (mode == 5) {
X    AskOn(2);
X    Asking = 2 ;
X    DrawGreyScale();
X    return ;
X    };
X  colour = 1 ;
X  if ((mode == 4) && (Asking == 2)) {
X    AskOff();
X    Asking = 0 ;
X    colour = 0 ;
X    };
X
X  if (mode < 4) {
X    old = new ;
X    new = 1 - new ;
X    };
X  switch(mode) {
X  case 1: DoGreyScale(); break ;
X  case 2: Sharpen(); break;
X  case 3: Soften(); break;
X  case 4: Apply(colour); break ;
X  case 6: Undo(); break ;
X  default: break ;
X  };
X  if (display == 2)
X    SmallView();
X  if (display == 3)
X    display_stats(0,0);
X  sprintf(mess,"Generations : %d",++generation);
X  Message(mess);
X}
X
Xvoid DrawGreyScale()
X/* Draws the `Grey Scale Graph */
X{
X  int i ;
X
X  SetWindow(Multi_Window);
X  SetBackColour(cols[filebg]);
X  ClearScreen();
X  SetColour(cols[filefg]);
X
X  for(i=0 ; i<6 ; ++i) {
X    XDrawLine( dpy,win,gc,greyX[i]-5,greyY[i]-5,greyX[i]+5,greyY[i]-5);
X    XDrawLine( dpy,win,gc,greyX[i]+5,greyY[i]-5,greyX[i]+5,greyY[i]+5);
X    XDrawLine( dpy,win,gc,greyX[i]+5,greyY[i]+5,greyX[i]-5,greyY[i]+5);
X    XDrawLine( dpy,win,gc,greyX[i]-5,greyY[i]+5,greyX[i]-5,greyY[i]-5);
X    if (i)
X      XDrawLine(dpy,win,gc,greyX[i-1],greyY[i-1],greyX[i],greyY[i]);
X    };
X}
X
Xvoid InitGreyScale()
X/* Set the Grey Scale graph to initial values, plus initiate some other variables */
X{
X  greyX[0] = 0 ;
X  greyY[0] = 200 ;
X  greyX[1] = 51 ;
X  greyY[1] = 160 ;
X  greyX[2] = 102 ;
X  greyY[2] = 120 ;
X  greyX[3] = 154 ;
X  greyY[3] = 80 ;
X  greyX[4] = 206 ;
X  greyY[4] = 40 ;
X  greyX[5] = 256 ;
X  greyY[5] = 0 ;
X  moving = -1 ;
X  options = max_states + 4 ;
X  start = options - 7 ;
X}
X
Xvoid GreyScaleMouseUp()
X/* Pre : Mouse button released
X*/
X{
X  moving = -1 ;
X}
X
Xvoid GreyScaleMove(x,y) int x,y ;
X/* Pre : Mouse has been moved
X   Post: Grey Scale Graph has been updated
X*/
X{
X  int i ;
X
X  if (moving == -1)
X    for( i=0 ; i<6 ; ++i )
X      if ( (x > (greyX[i]-5)) && (y > (greyY[i]-5)) && (x < (greyX[i]+5)) && (y < (greyY[i]+5)) )
X        moving = i ;
X
X  if (moving == -1)
X    return ;
X
X  if ( moving == 0 )
X    x = 0 ;
X  else if ( moving == 5 )
X    x = 256 ;
X  else if (x <= greyX[moving-1])
X    x = greyX[moving-1] + 1 ;
X  else if (x >= greyX[moving+1])
X    x = greyX[moving+1] - 1 ;
X
X  if (y > 200)
X    y = 200 ;
X  if (y < 0)
X    y=0 ;
X
X  greyX[moving] = x ;
X  greyY[moving] = y ;
X  DrawGreyScale();
X}
END_OF_FILE
if test 17068 -ne `wc -c <'colour.c'`; then
    echo shar: \"'colour.c'\" unpacked with wrong size!
fi
# end of 'colour.c'
fi
echo shar: End of shell archive.
exit 0
---- CUT HERE -------- CUT HERE -------- CUT HERE -------- CUT HERE ----


-- 
   _____            _____________________        Ian Palmer
  /_  _/           |                     |       Department of Computing,
   / /  ___        |                     |       Imperial College, 
  / /  / __\       | This space for rent |       180 Queen's Gate,
 /_/  / /          |                     |       London SW7 2BZ.
      \ \__        |_____________________|       
       \___/                 | |                 ijp@doc.ic.ac.uk
                            \|_|/                ijp=ack@doc.ic.ac.uk
  PANIC NOW
  and avoid       23. Add to Celt's pub meal and produce utter turmoil. (6,8)
  the rush.       -----------------------------------------------------------
Anybody can win, unless there happens to be a second entry.

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.
