/* apply_rule.h  -bds 10/02 */
#ifndef __APPLY_RULE__
#define __APPLY_RULE__
/* Toos for the one dimensional cellular automata project */

/******
 * apply_rule(rule, l, c, r) tells what the new value for c should be, 
 * given the current values of c and it's neighbors l and r.
 * Requires 0 <= rule < 256, and l,c,r must each be 0 or 1.
 * Example:  apply_rule( 32, 1, 0, 1) is 1.
 ******/ 
int apply_rule(int rule, int left, int center, int right)
{   
    //int instance = 4*left + 2*center + right;
    int instance = (left << 2) ^ (center << 1) ^ right;
    int key = 1 << instance; // key = expt(2,instance);
    return key & rule ? 1 : 0;
}

/******
 * display_cells() displays a range of cells on one line
 * For x in *[b..e) writes char n if x is zero, else writes char y. 
 * Finally writes a '\n'.
 ******/
template<class Ptr> 
void display_cells(Ptr b, Ptr e, char y = '+', char n = ' ', ostream& out = std::cout)
{   for (Ptr i = b; i < e; ++i) out << (*i ? y : n); 
    out << std::endl;    
}

/******
 * areEqual(b, e, b2) is true if data at range [ b .. e ) 
 * are same as data at range [ b2 .. b2+(e-b) ).
 ******/
template<class Ptr> 
bool areEqual(Ptr b1, Ptr e1, Ptr b2)
{   Ptr i, j;
    for (i = b1, j = b2; i < e1; ++i, ++j) 
	if (*i != *j) return false;
    return true;
}

// a little widget to print rules as 8 0-1 chars.
char* binstring(int rule)
{   char* b = new char[9] ; // don't use this much: memory leak.
    for (int i = 7; i >= 0; --i )
	{ b[i] = '0' + rule%2; rule = rule/2; }
    b[8] = 0;
    return b;
}
#endif

#if 0 // apply_rule's  testing code 
#include <iostream>
using namespace std;
// test to check that apply_rule is working correctly.
void test_apply_rule(int rule)
{
    char* binstring(int rule);

    cout << "apply_rule(" << binstring(rule) << ", 0,0,0) yields " 
	 << apply_rule(rule, 0, 0, 0) << endl;

    cout << "apply_rule(" << binstring(rule) << ", 0,0,1) yields " 
	 << apply_rule(rule, 0, 0, 1) << endl;

    cout << "apply_rule(" << binstring(rule) << ", 0,1,0) yields " 
	 << apply_rule(rule, 0, 1, 0) << endl;

    cout << "apply_rule(" << binstring(rule) << ", 0,1,1) yields " 
	 << apply_rule(rule, 0, 1, 1) << endl;

    cout << "apply_rule(" << binstring(rule) << ", 1,0,0) yields " 
	 << apply_rule(rule, 1, 0, 0) << endl;

    cout << "apply_rule(" << binstring(rule) << ", 1,0,1) yields " 
	 << apply_rule(rule, 1, 0, 1) << endl;

    cout << "apply_rule(" << binstring(rule) << ", 1,1,0) yields " 
	 << apply_rule(rule, 1, 1, 0) << endl;

    cout << "apply_rule(" << binstring(rule) << ", 1,1,1) yields " 
	 << apply_rule(rule, 1, 1, 1) << endl;
}

int main()
{   
    test_apply_rule(0);
    test_apply_rule(3);
    test_apply_rule(4);
    test_apply_rule(7);
    test_apply_rule(127);
    test_apply_rule(128);
    test_apply_rule(255);
}
#endif // apply_rule's  testing code 

