logo i-r-genius.com


Introduction

This is some final year coursework for a neural networks course, it may be right, it may be wrong, but I got a decent mark for it and I passed the course. Oh, and it does actually recognise characters - even when you pass near OnDigital levels of interference to it :).

The source code is here : neural.tar.gz (3720 bytes)


Implementing a simple neural network

Figure 1: The network
The network is a single layer feed forward network, which takes sixty-four inputs, one for each pixel in the bit-map character. These feed into a number of neurons, defined by NPATTERNS. There is one neuron for every character to be recognized by the network. Every input is connected to every neuron with a unique weighting.

The activation function f determines if the output from the summer for that neuron is the greatest of all the neurons. If it is then the Boolean return is true, if not the output from the activation function is false.

Learning takes place by feeding each pattern to recognize in turn to the network. The learning rule is activated if the character guessed by the network does not match the actual character that has been fed to it. The sixty-four pixel weightings are then adjusted in both the guessed and actual character weightings. If the pixel in the source character bitmap is set then the weighting for that pixel in the set for the actual character is increased, and the equivalent weighting for the character in the previous best match is decreased. The inverse occurs if the pixel in the source character bitmap is off.

In pseudo-code :

      FOR pixel=0 TO 64
        IF pixellookup(actualchar,pixel) == TRUE THEN
          weightsvector[neuralnetresult][pixel] -= 1;
          weightsvector[actualchar][pixel] += 1;
        ELSE
          weightsvector[neuralnetresult][pixel] += 1;
          weightsvector[actualchar][pixel] -= 1;
        ENDIF
     NEXT

The learning process continues feeding each character pattern in turn to the network until all the patterns are recognized correctly, or a limit of number of learning cycles is reached.

I also considered a network where the sixty-four inputs fed into eight neurons, one for each bit of the ASCII code for any character. When I tried to implement such a network it failed to recognize any characters accurately. There could have been problems with my implementation, but using the method I eventually decided on the implementation started to work much sooner, and with a sufficient level of accuracy.

Implementation

The network is implemented in ANSI C, although it could have been written in pretty well any language. I chose C as it is fairly low-level, and I wanted to implement the network from first principles.

There are two main functions in the implementation, net_train and net_lookup. As you may expect, net_train performs the auto-training and net_lookup attempts to identify a character using the network.

The training procedure works as described in the design, feeding each pattern in to the network and altering the weightings if that character was not recognized correctly.

The bitmap font data is lifted directly from the Linux kernel, and is in the form of an 8x8 bitmap, one byte per line running from top to bottom, with the least significant bit of each byte representing the rightmost pixel on a line. The bitmap data is referenced using the function pixellookup, which returns either a zero or a one depending on whether the nth pixel of character ch is on or not :

  int pixellookup(int ch, int pixel)
  {
    return((fontdata_8x8[(8*ch)+(pixel/8)] & (1<<(pixel%8))) != 0);
  }

Using this function we can treat the bitmap data as a number of arrays of 64 bits. Through this function our bitmap data becomes our input neurons, and so we need no specific array of inputs.

Throughout the code we use pattern numbers in our arrays of weightings and such, whereas the actual character data is indexed by ASCII code. For this reason when referencing our font data, or referencing the equivalent ASCII character we add STARTOFFSET to the value. In the test case STARTOFFSET is defined to the ASCII value of 'a'.

Using these functions we can set about training the network. The code is as follows :

void net_train(void)
{
  float d[NPATTERNS];
  int learncycles=0;
  int correct=0;

  while(!correct && learncycles < MAXITER)
  {
    int i, j, best=0, k;    

    correct=1;
    
    for(i=0; i<NPATTERNS; i++)
    {

This following loop calculates the activation levels for each neuron, by summing the values of each bit in the current learning pattern multiplied by the weighting of each pixel for every pattern known.

      for(j=0;j<NPATTERNS; j++)
      {
        d[j]=0;
        for(k=0; k<64; k++)
	{
          d[j]+=weightsvector[j][k]*pixellookup(i+STARTOFFSET,k);
        }
      }

To find the highest activation we scan through our array of output activation levels :

      /* find the neuron with the highest activation */
      for(j=1;j<NPATTERNS;j++) 
      { 
        if(d[j]>d[best])
          best=j;
      }

      if(best==i)
      {
        printf("Guessed %c correctly\n",best+STARTOFFSET);
        continue; /* we got it right */
      }

You can see the learning code is dropped through to if the best match from the net (best) does not match the actual pattern number (i). If it did match the next pattern is tested.

      correct=0;
      printf("Guessed %c instead of %c\n ",best+STARTOFFSET,i+STARTOFFSET);

      for(j=0; j<64;j++)
      {
        if(pixellookup(i+STARTOFFSET,j))
        {
          weightsvector[best][j] -= 1;
          weightsvector[i][j] += 1;
        } else {
          weightsvector[best][j] += 1;
          weightsvector[i][j] -= 1;
        }
      }
    }

    ++learncycles;  
  }

  if(learncycles == MAXITER)
    printf("Failed to learn!\n");

  printf("Training took %i cycles\n",learncycles);
}

The network is trained in a maximum of MAXITER cycles through all the patterns to be recognized, which I defined as 1000. As it turned out the network was typically trained in less than twenty cycles.

net_lookup is simply net_train minus the training functions. It just sums the weightings for each neuron in response to a pattern and identifies the one with the highest activity on the output. The result is returned to the caller.

The main() function simply clears the weightings array and calls net_train to set up the network. The test code then calls the network feeding in every pattern it should have learnt, first printing a simple rendition of the bitmap using font_plot(). Once this has been completed noise is added to the input bitmaps by the add_noise() function. The corrupted fonts are then fed through the previously trained network as before to determine the resilience of the network when exposed to noisy data.

Evaluation

The network performs well at the specified task, recognising the letters "a" to "z" successfully. When random noise is added to the data the network still performs with a reasonable level of success, in tests recognising 93% of the noisy characters fed to it. Full results from both noisy and clean tests are attached. As can be seen in results for the noisy tests the two noisy characters that do fail are difficult to recognise even by eye, the "c" certainly does look like an "o" and the "u" is heavily corrupted.

We can see from the response levels from the network that letters that are similar inform incite high levels of response in when fed through each other's weightings. It is with these letters that noise is most likely to cause misrecognition. The "c" to "o" in the tests I have done is a case in point. Consider this table of their responses, with "m" included as a entirely dissimilar letter :

Figure 2: Table of neuron responses for two visually similar patterns and one dissimilar pattern

To avoid such problems fonts have been specially designed for use in recognition applications where similar letters are made as visually dissimilar as possible to improve performance.

The program does use floating point numbers where they are not necessary, in computing activation levels and such. The program also does not deal with multiple neurons being the "best" match, selecting one only as a consequence of how the program is written. It should really report these multiple matches, allow the user to select and then train according to their response.

Applications

The implementation forms the most basic form of an optical character recognition system, but it does lack several major parts, namely the ability to scan a document for characters, locate them as well as scaling those extracted images to what the network "knows". The program would also have to deal with such problems as skew of an image, documents are rarely scanned so the characters are exactly straight. There are also other problems associated with image grabbing, problems of image darkness an such, which require image processing to ensure the background and foreground are distinguished from each other. Even when the orientation, darkness and size of an image have been adjusted accordingly the network would have to be considerably more complex, to deal with the increased levels of noise. On top of all this the use of differing fonts can distract and confuse a network (although this problem can be avoided by specifying which fonts are used, and perhaps using a specifically designed font as described earlier).

To increase accuracy in such situations a vector based approach is used, which involves yet more image processing, and an entirely different implementation of a neural network which deals with lines and co-ordinates rather than pixels.

However, as a simple pattern recognizer this program performs effectively, and proves the potential of neural networks in recognizing "fuzzy" patterns.

Test results from neural network fed clean data

For each character the bitmap is printed, followed by the activation levels for each output neuron. If the highest activation level was on the correct neuron the letter is noted as having been guessed correctly.


        
  ####  
     ## 
  ##### 
 ##  ## 
  ##### 
        
a 26.000000
b -2.000000
c 0.000000
d -8.000000
e 8.000000
f -2.000000
g 0.000000
h -2.000000
i 2.000000
j -16.000000
k -2.000000
l -8.000000
m 8.000000
n 16.000000
o 12.000000
p -14.000000
q 0.000000
r -18.000000
s 8.000000
t 0.000000
u 2.000000
v 2.000000
w 6.000000
x -6.000000
y -4.000000
z -8.000000
Guessed a correctly
 ##     
 ##     
 #####  
 ##  ## 
 ##  ## 
 ##  ## 
 #####  
        
a -10.000000
b 36.000000
c 2.000000
d -14.000000
e 8.000000
f 6.000000
g 0.000000
h 24.000000
i -20.000000
j -36.000000
k 16.000000
l -12.000000
m 2.000000
n 8.000000
o 2.000000
p -8.000000
q -4.000000
r -8.000000
s 4.000000
t 0.000000
u 12.000000
v 4.000000
w 4.000000
x -10.000000
y 0.000000
z -6.000000
Guessed b correctly
        
        
  ####  
 ##  ## 
 ##     
 ##  ## 
  ####  
        
a 6.000000
b -4.000000
c 18.000000
d -6.000000
e 8.000000
f 4.000000
g -2.000000
h -10.000000
i -2.000000
j -20.000000
k -4.000000
l -10.000000
m 2.000000
n 4.000000
o 12.000000
p -20.000000
q 0.000000
r 4.000000
s 8.000000
t 2.000000
u 10.000000
v 6.000000
w 8.000000
x -6.000000
y -2.000000
z -6.000000
Guessed c correctly
     ## 
     ## 
  ##### 
 ##  ## 
 ##  ## 
 ##  ## 
  ##### 
        
a 6.000000
b 10.000000
c -10.000000
d 20.000000
e 8.000000
f 6.000000
g 12.000000
h 6.000000
i -18.000000
j -36.000000
k 0.000000
l -18.000000
m 8.000000
n 16.000000
o 8.000000
p -2.000000
q 0.000000
r -18.000000
s 4.000000
t -6.000000
u 14.000000
v 4.000000
w 6.000000
x -10.000000
y -2.000000
z -8.000000
Guessed d correctly
        
        
  ####  
 ##  ## 
 ###### 
 ##     
  ####  
        
a 12.000000
b 0.000000
c 4.000000
d -20.000000
e 20.000000
f 2.000000
g -4.000000
h -12.000000
i 2.000000
j -16.000000
k 2.000000
l -8.000000
m 6.000000
n 2.000000
o 16.000000
p -16.000000
q 0.000000
r 0.000000
s 8.000000
t 2.000000
u 4.000000
v 6.000000
w 6.000000
x -8.000000
y -4.000000
z -4.000000
Guessed e correctly
   ###  
  ##    
  ##    
 #####  
  ##    
  ##    
  ##    
        
a -6.000000
b -12.000000
c -2.000000
d 0.000000
e 4.000000
f 16.000000
g 2.000000
h -8.000000
i 6.000000
j -2.000000
k 4.000000
l 2.000000
m 6.000000
n -8.000000
o 2.000000
p 2.000000
q 2.000000
r -4.000000
s -2.000000
t 6.000000
u 0.000000
v -2.000000
w 0.000000
x 0.000000
y -8.000000
z 2.000000
Guessed f correctly
        
        
  ##### 
 ##  ## 
 ##  ## 
  ##### 
     ## 
  ####  
a 0.000000
b -10.000000
c -8.000000
d 6.000000
e 4.000000
f 4.000000
g 24.000000
h 12.000000
i -24.000000
j -18.000000
k 2.000000
l -18.000000
m 10.000000
n 18.000000
o -6.000000
p 4.000000
q 8.000000
r -22.000000
s 0.000000
t -6.000000
u 6.000000
v 6.000000
w 6.000000
x 0.000000
y 12.000000
z -10.000000
Guessed g correctly
 ##     
 ##     
 #####  
 ##  ## 
 ##  ## 
 ##  ## 
 ##  ## 
        
a -9.000000
b 14.000000
c -3.000000
d -13.000000
e 6.000000
f 8.000000
g 2.000000
h 36.000000
i -26.000000
j -42.000000
k 22.000000
l -15.000000
m 6.000000
n 24.000000
o -6.000000
p -4.000000
q 0.000000
r -8.000000
s 1.000000
t -3.000000
u 14.000000
v 1.000000
w 5.000000
x -3.000000
y 3.000000
z -10.000000
Guessed h correctly

   ##   
        
  ###   
   ##   
   ##   
   ##   
  ####  
        
a 7.000000
b -8.000000
c -1.000000
d -3.000000
e 0.000000
f -10.000000
g -2.000000
h -16.000000
i 36.000000
j 18.000000
k -4.000000
l 9.000000
m 4.000000
n -8.000000
o 6.000000
p -6.000000
q 6.000000
r -16.000000
s 3.000000
t 5.000000
u -8.000000
v -5.000000
w 1.000000
x -1.000000
y -15.000000
z 8.000000
Guessed i correctly
   ##   
        
  ###   
   ##   
   ##   
   ##   
   ##   
 ###    
a 2.000000
b 4.000000
c -6.000000
d 2.000000
e 0.000000
f -8.000000
g 2.000000
h -10.000000
i 16.000000
j 38.000000
k -4.000000
l 4.000000
m 6.000000
n -16.000000
o 4.000000
p 16.000000
q 4.000000
r -20.000000
s -2.000000
t 2.000000
u -12.000000
v -6.000000
w -4.000000
x -6.000000
y -14.000000
z 8.000000
Guessed j correctly
 ##     
 ##     
 ##  ## 
 ## ##  
 ####   
 ## ##  
 ##  ## 
        
a -12.000000
b 2.000000
c -4.000000
d -10.000000
e 2.000000
f 6.000000
g 4.000000
h 14.000000
i -16.000000
j -32.000000
k 40.000000
l -10.000000
m 8.000000
n 12.000000
o -20.000000
p -6.000000
q -6.000000
r -6.000000
s 0.000000
t -4.000000
u 12.000000
v 0.000000
w 8.000000
x 14.000000
y 8.000000
z -4.000000
Guessed k correctly
  ###   
   ##   
   ##   
   ##   
   ##   
   ##   
  ####  
        
a 1.000000
b 6.000000
c -5.000000
d -1.000000
e 0.000000
f -8.000000
g 6.000000
h -6.000000
i 20.000000
j 10.000000
k 0.000000
l 29.000000
m 4.000000
n -10.000000
o 4.000000
p 0.000000
q 6.000000
r -24.000000
s -1.000000
t 5.000000
u -8.000000
v -9.000000
w -3.000000
x -5.000000
y -19.000000
z 8.000000
Guessed l correctly
        
        
  ## ## 
 #######
 ## # ##
 ## # ##
 ##   ##
        
a -3.000000
b 8.000000
c -7.000000
d 1.000000
e 6.000000
f 6.000000
g 8.000000
h -10.000000
i -18.000000
j -28.000000
k 12.000000
l -17.000000
m 36.000000
n 16.000000
o -4.000000
p -8.000000
q 2.000000
r -4.000000
s -3.000000
t -11.000000
u 10.000000
v -1.000000
w 13.000000
x 5.000000
y -1.000000
z -8.000000
Guessed m correctly
        
        
 #####  
 ##  ## 
 ##  ## 
 ##  ## 
 ##  ## 
        
a 3.000000
b -6.000000
c 1.000000
d -9.000000
e 6.000000
f 6.000000
g -6.000000
h 8.000000
i -16.000000
j -34.000000
k 6.000000
l -17.000000
m 6.000000
n 32.000000
o 2.000000
p -10.000000
q 0.000000
r 0.000000
s 5.000000
t -3.000000
u 14.000000
v 5.000000
w 9.000000
x 1.000000
y 7.000000
z -10.000000
Guessed n correctly
        
        
  ####  
 ##  ## 
 ##  ## 
 ##  ## 
  ####  
        
a 8.000000
b 4.000000
c 8.000000
d -8.000000
e 12.000000
f 4.000000
g -2.000000
h -4.000000
i -6.000000
j -24.000000
k -4.000000
l -12.000000
m 4.000000
n 8.000000
o 16.000000
p -16.000000
q 0.000000
r -4.000000
s 8.000000
t 0.000000
u 10.000000
v 8.000000
w 8.000000
x -8.000000
y 0.000000
z -10.000000
Guessed o correctly
        
        
 #####  
 ##  ## 
 ##  ## 
 #####  
 ##     
 ##     
a -6.000000
b 4.000000
c -2.000000
d -10.000000
e 8.000000
f 6.000000
g -12.000000
h 4.000000
i -20.000000
j -14.000000
k 6.000000
l -16.000000
m 4.000000
n 8.000000
o 2.000000
p 18.000000
q 2.000000
r 4.000000
s 0.000000
t -4.000000
u 4.000000
v 8.000000
w 6.000000
x 2.000000
y 6.000000
z -8.000000
Guessed p correctly
        
        
  ##### 
 ##  ## 
 ##  ## 
  ##### 
     ## 
     ###
a 1.000000
b -6.000000
c -7.000000
d 5.000000
e 4.000000
f 4.000000
g 12.000000
h 10.000000
i -18.000000
j -28.000000
k 2.000000
l -17.000000
m 10.000000
n 20.000000
o -10.000000
p 2.000000
q 22.000000
r -20.000000
s 1.000000
t -5.000000
u 6.000000
v 7.000000
w 7.000000
x 1.000000
y 7.000000
z -10.000000
Guessed q correctly







        
        
 ## ##  
 ### ## 
 ##     
 ##     
 ##     
        
a -7.000000
b -2.000000
c 9.000000
d -13.000000
e 8.000000
f 8.000000
g -12.000000
h -8.000000
i -10.000000
j -20.000000
k 6.000000
l -13.000000
m 2.000000
n 6.000000
o 0.000000
p -10.000000
q -4.000000
r 32.000000
s 1.000000
t 1.000000
u 10.000000
v 5.000000
w 5.000000
x 5.000000
y 5.000000
z -4.000000
Guessed r correctly
        
        
  ##### 
 ##     
  ####  
     ## 
 #####  
        
a 8.000000
b 4.000000
c 2.000000
d -4.000000
e 4.000000
f -2.000000
g 2.000000
h -12.000000
i 6.000000
j -12.000000
k 2.000000
l -6.000000
m 6.000000
n 10.000000
o 6.000000
p -24.000000
q 2.000000
r -14.000000
s 18.000000
t 2.000000
u 4.000000
v 2.000000
w 4.000000
x -2.000000
y -6.000000
z 0.000000
Guessed s correctly
  ##    
  ##    
 #####  
  ##    
  ##    
  ##    
   ###  
        
a -4.000000
b 8.000000
c 2.000000
d -8.000000
e 2.000000
f 4.000000
g 2.000000
h -8.000000
i 4.000000
j -2.000000
k 2.000000
l 8.000000
m -4.000000
n -6.000000
o -2.000000
p -6.000000
q 2.000000
r -6.000000
s 2.000000
t 18.000000
u -2.000000
v 0.000000
w -2.000000
x -4.000000
y -6.000000
z 6.000000
Guessed t correctly
        
        
 ##  ## 
 ##  ## 
 ##  ## 
 ##  ## 
  ##### 
        
a 5.000000
b 8.000000
c -1.000000
d 1.000000
e 6.000000
f 6.000000
g 0.000000
h -4.000000
i -16.000000
j -34.000000
k 6.000000
l -17.000000
m 2.000000
n 18.000000
o 0.000000
p -16.000000
q -12.000000
r -6.000000
s 5.000000
t -3.000000
u 20.000000
v 11.000000
w 13.000000
x 1.000000
y 17.000000
z -10.000000
Guessed u correctly
        
        
 ##  ## 
 ##  ## 
 ##  ## 
  ####  
   ##   
        
a -4.000000
b 12.000000
c -4.000000
d 0.000000
e 6.000000
f 6.000000
g -2.000000
h -12.000000
i -14.000000
j -16.000000
k 4.000000
l -14.000000
m 0.000000
n -2.000000
o -4.000000
p -2.000000
q -4.000000
r -2.000000
s 2.000000
t 0.000000
u 6.000000
v 18.000000
w 10.000000
x 4.000000
y 18.000000
z -6.000000
Guessed v correctly
        
        
 ##   ##
 ## # ##
 ## # ##
 #######
  ## ## 
        
a -3.000000
b 16.000000
c -7.000000
d 7.000000
e 2.000000
f 2.000000
g 8.000000
h -6.000000
i -12.000000
j -30.000000
k 12.000000
l -15.000000
m 6.000000
n 16.000000
o -8.000000
p 0.000000
q -6.000000
r -20.000000
s -3.000000
t -9.000000
u 14.000000
v 3.000000
w 25.000000
x 5.000000
y 11.000000
z -8.000000
Guessed w correctly
        
        
 ##  ## 
  ####  
   ##   
  ####  
 ##  ## 
        
a 2.000000
b -18.000000
c -6.000000
d 0.000000
e -8.000000
f 0.000000
g -2.000000
h -14.000000
i 6.000000
j -12.000000
k 12.000000
l -6.000000
m 8.000000
n 16.000000
o -16.000000
p -8.000000
q -2.000000
r -4.000000
s 2.000000
t 0.000000
u 4.000000
v 2.000000
w 8.000000
x 26.000000
y 10.000000
z 0.000000
Guessed x correctly
        
        
 ##  ## 
 ##  ## 
 ##  ## 
  ##### 
     ## 
  ####  
a -5.000000
b 2.000000
c -11.000000
d 7.000000
e 2.000000
f 6.000000
g 20.000000
h 10.000000
i -30.000000
j -24.000000
k 8.000000
l -21.000000
m 4.000000
n 20.000000
o -14.000000
p 6.000000
q -4.000000
r -18.000000
s -3.000000
t -7.000000
u 12.000000
v 9.000000
w 9.000000
x 7.000000
y 27.000000
z -12.000000
Guessed y correctly
        
        
 ###### 
    ##  
   ##   
  ##    
 ###### 
        
a 10.000000
b -6.000000
c -2.000000
d -4.000000
e -8.000000
f -4.000000
g -2.000000
h -16.000000
i 14.000000
j -4.000000
k 4.000000
l -2.000000
m 6.000000
n 12.000000
o -6.000000
p -12.000000
q 0.000000
r -10.000000
s 6.000000
t 4.000000
u 0.000000
v 0.000000
w 4.000000
x 2.000000
y -4.000000
z 18.000000
Guessed z correctly

ImplementationTest results from neural network fed noisy data

For each character the bitmap is printed, followed by the activation levels for each output neuron. If the highest activation level was on the correct neuron the letter is noted as having been guessed correctly.


 #      
        
  ####  
     ## 
  ## ## 
 ##  ## 
  ##### 
        
a 20.000000
b 4.000000
c 0.000000
d -6.000000
e 6.000000
f 0.000000
g 2.000000
h 8.000000
i -2.000000
j -20.000000
k 0.000000
l -10.000000
m 6.000000
n 14.000000
o 10.000000
p -10.000000
q 0.000000
r -18.000000
s 6.000000
t 0.000000
u 4.000000
v 2.000000
w 4.000000
x -8.000000
y -4.000000
z -8.000000
Guessed a correctly
 ##     
 ##     
 #####  
 ##  ## 
 ##  ## 
 ##  ## 
 #####  
        
a -10.000000
b 36.000000
c 2.000000
d -14.000000
e 8.000000
f 6.000000
g 0.000000
h 24.000000
i -20.000000
j -36.000000
k 16.000000
l -12.000000
m 2.000000
n 8.000000
o 2.000000
p -8.000000
q -4.000000
r -8.000000
s 4.000000
t 0.000000
u 12.000000
v 4.000000
w 4.000000
x -10.000000
y 0.000000
z -6.000000
Guessed b correctly
 #    # 
        
  ####  
 ##  ## 
 ##   # 
 ##  ## 
  ####  
        
a 3.000000
b 10.000000
c 9.000000
d -3.000000
e 10.000000
f 4.000000
g 2.000000
h 2.000000
i -8.000000
j -26.000000
k 0.000000
l -13.000000
m 4.000000
n 4.000000
o 12.000000
p -12.000000
q 0.000000
r -4.000000
s 5.000000
t -1.000000
u 10.000000
v 5.000000
w 7.000000
x -9.000000
y -3.000000
z -8.000000
Guessed o instead of c
     ## 
     ## 
  ##### 
 ##  ## 
 ##  ## 
 ##  ## 
  ##### 
        
a 6.000000
b 10.000000
c -10.000000
d 20.000000
e 8.000000
f 6.000000
g 12.000000
h 6.000000
i -18.000000
j -36.000000
k 0.000000
l -18.000000
m 8.000000
n 16.000000
o 8.000000
p -2.000000
q 0.000000
r -18.000000
s 4.000000
t -6.000000
u 14.000000
v 4.000000
w 6.000000
x -10.000000
y -2.000000
z -8.000000
Guessed d correctly
        
        
  ####  
 ##  ## 
 ###### 
 ##     
  ####  
        
a 12.000000
b 0.000000
c 4.000000
d -20.000000
e 20.000000
f 2.000000
g -4.000000
h -12.000000
i 2.000000
j -16.000000
k 2.000000
l -8.000000
m 6.000000
n 2.000000
o 16.000000
p -16.000000
q 0.000000
r 0.000000
s 8.000000
t 2.000000
u 4.000000
v 6.000000
w 6.000000
x -8.000000
y -4.000000
z -4.000000
Guessed e correctly
   ###  
  ##    
  ##    
 #####  
  ##    
  ##    
  ##    
        
a -6.000000
b -12.000000
c -2.000000
d 0.000000
e 4.000000
f 16.000000
g 2.000000
h -8.000000
i 6.000000
j -2.000000
k 4.000000
l 2.000000
m 6.000000
n -8.000000
o 2.000000
p 2.000000
q 2.000000
r -4.000000
s -2.000000
t 6.000000
u 0.000000
v -2.000000
w 0.000000
x 0.000000
y -8.000000
z 2.000000
Guessed f correctly
  #     
        
  ##### 
 ##  ## 
  #  #  
  ##### 
     ## 
  ####  
a -1.000000
b -10.000000
c -5.000000
d 7.000000
e 0.000000
f 4.000000
g 26.000000
h 16.000000
i -24.000000
j -16.000000
k 4.000000
l -11.000000
m 8.000000
n 14.000000
o -10.000000
p 2.000000
q 8.000000
r -22.000000
s 1.000000
t -3.000000
u 4.000000
v 3.000000
w 3.000000
x 1.000000
y 9.000000
z -8.000000
Guessed g correctly
 ##     
 ##     
 #####  
 ##  ## 
 ##  ## 
 ##  ## 
 ##  ## 
        
a -9.000000
b 14.000000
c -3.000000
d -13.000000
e 6.000000
f 8.000000
g 2.000000
h 36.000000
i -26.000000
j -42.000000
k 22.000000
l -15.000000
m 6.000000
n 24.000000
o -6.000000
p -4.000000
q 0.000000
r -8.000000
s 1.000000
t -3.000000
u 14.000000
v 1.000000
w 5.000000
x -3.000000
y 3.000000
z -10.000000
Guessed h correctly
   ##   
        
  ###   
   ##   
   ##   
   ##   
  ####  
        
a 7.000000
b -8.000000
c -1.000000
d -3.000000
e 0.000000
f -10.000000
g -2.000000
h -16.000000
i 36.000000
j 18.000000
k -4.000000
l 9.000000
m 4.000000
n -8.000000
o 6.000000
p -6.000000
q 6.000000
r -16.000000
s 3.000000
t 5.000000
u -8.000000
v -5.000000
w 1.000000
x -1.000000
y -15.000000
z 8.000000
Guessed i correctly
   ##   
        
  ###   
   ##   
   ##   
   ##   
   ##   
 ###    
a 2.000000
b 4.000000
c -6.000000
d 2.000000
e 0.000000
f -8.000000
g 2.000000
h -10.000000
i 16.000000
j 38.000000
k -4.000000
l 4.000000
m 6.000000
n -16.000000
o 4.000000
p 16.000000
q 4.000000
r -20.000000
s -2.000000
t 2.000000
u -12.000000
v -6.000000
w -4.000000
x -6.000000
y -14.000000
z 8.000000
Guessed j correctly


 ##     
 ##     
 ##  ## 
 ## ##  
 ###    
 ## ##  
 ##  ## 
        
a -15.000000
b 2.000000
c -3.000000
d -7.000000
e 0.000000
f 8.000000
g 4.000000
h 16.000000
i -18.000000
j -34.000000
k 38.000000
l -11.000000
m 6.000000
n 12.000000
o -20.000000
p -4.000000
q -6.000000
r -4.000000
s -1.000000
t -3.000000
u 14.000000
v 1.000000
w 7.000000
x 13.000000
y 9.000000
z -4.000000
Guessed k correctly
  ###   
   ##   
   ##   
   ##   
   ##   
   ##   
  ####  
        
a 1.000000
b 6.000000
c -5.000000
d -1.000000
e 0.000000
f -8.000000
g 6.000000
h -6.000000
i 20.000000
j 10.000000
k 0.000000
l 29.000000
m 4.000000
n -10.000000
o 4.000000
p 0.000000
q 6.000000
r -24.000000
s -1.000000
t 5.000000
u -8.000000
v -9.000000
w -3.000000
x -5.000000
y -19.000000
z 8.000000
Guessed l correctly
   #    
        
  ## ## 
 #######
 ## ####
 ## # ##
 ##   ##
        
a -3.000000
b 12.000000
c -13.000000
d 1.000000
e 8.000000
f 6.000000
g 8.000000
h -6.000000
i -18.000000
j -28.000000
k 12.000000
l -17.000000
m 36.000000
n 18.000000
o -2.000000
p -4.000000
q 2.000000
r -10.000000
s -3.000000
t -11.000000
u 10.000000
v -1.000000
w 11.000000
x 3.000000
y -1.000000
z -10.000000
Guessed m correctly
        
        
 #####  
 ##  ## 
 ##  ## 
 ##  ## 
 ##  ## 
        
a 3.000000
b -6.000000
c 1.000000
d -9.000000
e 6.000000
f 6.000000
g -6.000000
h 8.000000
i -16.000000
j -34.000000
k 6.000000
l -17.000000
m 6.000000
n 32.000000
o 2.000000
p -10.000000
q 0.000000
r 0.000000
s 5.000000
t -3.000000
u 14.000000
v 5.000000
w 9.000000
x 1.000000
y 7.000000
z -10.000000
Guessed n correctly
     #  
        
  ####  
 ##  ## 
 ##  ## 
 ##  ## 
  ####  
        
a 7.000000
b 6.000000
c 5.000000
d -3.000000
e 12.000000
f 6.000000
g 0.000000
h -2.000000
i -8.000000
j -26.000000
k -4.000000
l -13.000000
m 4.000000
n 8.000000
o 16.000000
p -12.000000
q 0.000000
r -6.000000
s 7.000000
t -1.000000
u 10.000000
v 7.000000
w 7.000000
x -9.000000
y -1.000000
z -10.000000
Guessed o correctly
        
        
 #####  
 ##  ## 
 ##  ## 
 #####  
 ##     
 ##     
a -6.000000
b 4.000000
c -2.000000
d -10.000000
e 8.000000
f 6.000000
g -12.000000
h 4.000000
i -20.000000
j -14.000000
k 6.000000
l -16.000000
m 4.000000
n 8.000000
o 2.000000
p 18.000000
q 2.000000
r 4.000000
s 0.000000
t -4.000000
u 4.000000
v 8.000000
w 6.000000
x 2.000000
y 6.000000
z -8.000000
Guessed p correctly
        
        
  ##### 
 ##  ## 
 ##  ## 
  ##### 
     ## 
     ###
a 1.000000
b -6.000000
c -7.000000
d 5.000000
e 4.000000
f 4.000000
g 12.000000
h 10.000000
i -18.000000
j -28.000000
k 2.000000
l -17.000000
m 10.000000
n 20.000000
o -10.000000
p 2.000000
q 22.000000
r -20.000000
s 1.000000
t -5.000000
u 6.000000
v 7.000000
w 7.000000
x 1.000000
y 7.000000
z -10.000000
Guessed q correctly
        
        
 ## ##  
 ### ## 
 ##     
 ##     
 ##     
        
a -7.000000
b -2.000000
c 9.000000
d -13.000000
e 8.000000
f 8.000000
g -12.000000
h -8.000000
i -10.000000
j -20.000000
k 6.000000
l -13.000000
m 2.000000
n 6.000000
o 0.000000
p -10.000000
q -4.000000
r 32.000000
s 1.000000
t 1.000000
u 10.000000
v 5.000000
w 5.000000
x 5.000000
y 5.000000
z -4.000000
Guessed r correctly
 #      
        
  ##### 
 ##     
  ## #  
     ## 
 #####  
        
a 2.000000
b 10.000000
c 2.000000
d -2.000000
e 2.000000
f 0.000000
g 4.000000
h -2.000000
i 2.000000
j -16.000000
k 4.000000
l -8.000000
m 4.000000
n 8.000000
o 4.000000
p -20.000000
q 2.000000
r -14.000000
s 16.000000
t 2.000000
u 6.000000
v 2.000000
w 2.000000
x -4.000000
y -6.000000
z 0.000000
Guessed s correctly

  ##    
  ##    
 #####  
  ##    
  ##    
  ##    
   ###  
        
a -4.000000
b 8.000000
c 2.000000
d -8.000000
e 2.000000
f 4.000000
g 2.000000
h -8.000000
i 4.000000
j -2.000000
k 2.000000
l 8.000000
m -4.000000
n -6.000000
o -2.000000
p -6.000000
q 2.000000
r -6.000000
s 2.000000
t 18.000000
u -2.000000
v 0.000000
w -2.000000
x -4.000000
y -6.000000
z 6.000000
Guessed t correctly
  ##    
        
 ##  ## 
 ##  ## 
### ### 
 ##  ## 
  ##### 
        
a 3.000000
b 18.000000
c -5.000000
d -1.000000
e 8.000000
f 4.000000
g 4.000000
h 2.000000
i -18.000000
j -34.000000
k 12.000000
l -11.000000
m 4.000000
n 16.000000
o -2.000000
p -12.000000
q -12.000000
r -14.000000
s 3.000000
t -3.000000
u 18.000000
v 7.000000
w 11.000000
x -1.000000
y 13.000000
z -10.000000
Guessed b instead of u
        
        
 ##  ## 
 ##  ## 
 ##  ## 
  ####  
   ##   
        
a -4.000000
b 12.000000
c -4.000000
d 0.000000
e 6.000000
f 6.000000
g -2.000000
h -12.000000
i -14.000000
j -16.000000
k 4.000000
l -14.000000
m 0.000000
n -2.000000
o -4.000000
p -2.000000
q -4.000000
r -2.000000
s 2.000000
t 0.000000
u 6.000000
v 18.000000
w 10.000000
x 4.000000
y 18.000000
z -6.000000
Guessed v correctly
        
        
 ##   ##
 ## # ##
 ## # ##
 #######
  ## ## 
        
a -3.000000
b 16.000000
c -7.000000
d 7.000000
e 2.000000
f 2.000000
g 8.000000
h -6.000000
i -12.000000
j -30.000000
k 12.000000
l -15.000000
m 6.000000
n 16.000000
o -8.000000
p 0.000000
q -6.000000
r -20.000000
s -3.000000
t -9.000000
u 14.000000
v 3.000000
w 25.000000
x 5.000000
y 11.000000
z -8.000000
Guessed w correctly
        
        
 ##  ## 
  ####  
   ##   
  ####  
 ##  ## 
        
a 2.000000
b -18.000000
c -6.000000
d 0.000000
e -8.000000
f 0.000000
g -2.000000
h -14.000000
i 6.000000
j -12.000000
k 12.000000
l -6.000000
m 8.000000
n 16.000000
o -16.000000
p -8.000000
q -2.000000
r -4.000000
s 2.000000
t 0.000000
u 4.000000
v 2.000000
w 8.000000
x 26.000000
y 10.000000
z 0.000000
Guessed x correctly
   #    
        
 ##  ## 
 ##  ## 
 #   ## 
  ##### 
     ## 
  ####  
a -7.000000
b 4.000000
c -13.000000
d 9.000000
e 0.000000
f 4.000000
g 20.000000
h 12.000000
i -26.000000
j -20.000000
k 6.000000
l -19.000000
m 4.000000
n 20.000000
o -14.000000
p 10.000000
q -4.000000
r -22.000000
s -5.000000
t -7.000000
u 12.000000
v 7.000000
w 7.000000
x 7.000000
y 25.000000
z -10.000000
Guessed y correctly
        
        
 ###### 
    ##  
   ##   
  ##    
 ###### 
        
a 10.000000
b -6.000000
c -2.000000
d -4.000000
e -8.000000
f -4.000000
g -2.000000
h -16.000000
i 14.000000
j -4.000000
k 4.000000
l -2.000000
m 6.000000
n 12.000000
o -6.000000
p -12.000000
q 0.000000
r -10.000000
s 6.000000
t 4.000000
u 0.000000
v 0.000000
w 4.000000
x 2.000000
y -4.000000
z 18.000000
Guessed z correctly



xargle@eh.org
Last modified on: Sat Jan 30 09:55:25 2010
this space left blank intentionally