#include "generic_individual.h"
#include "transitions.h"

/* 
 * makes a transition of a CA using a c-matrix
 */
GENE *transitions::matrix_transition(GENE *p_buffer,
    int p_cells, GENE *p_matrix, GENE *p_state) {
  // reset the buffer
  for(int i = 0; i < p_cells; i++)
    p_buffer[i] = 0;

  // sum the neighbourhood of each cell into the buffer
  for(int i = 0; i < p_cells; i++) {
    int index = i;

    for(int j = 0; j < p_cells; j++) {
      if(p_matrix[index]) p_buffer[j] += p_state[i];
      index += p_cells;
    }
  }

  // is there an odd number of 1s in the neighbourhood?
  for(int i = 0; i < p_cells; i++)
    p_buffer[i] &= 1;

  return p_buffer;
}

/**
 * makes a transition of a CA using a rule-table
 */
GENE *transitions::rule_transition(GENE *p_buffer,
    int p_cells, int *p_rules, GENE *p_state, GENE **p_rule_tbl) {
  // reset the buffer
  for(int i = 0; i < p_cells; i++)
    p_buffer[i] = 0;

  int tmp_neigh;

  if(GENE_COUNT == 2) {
    // compute the next state for each cell
    for(int i = 0; i < p_cells; i++) {
      // determine the cell's neighbourhood (loop unroling ahead :))
      tmp_neigh = p_state[(i == 0) ? (p_cells - 1) : (i - 1)];
      tmp_neigh <<= 1;
      tmp_neigh |= p_state[i];
      tmp_neigh <<= 1;
      tmp_neigh |= p_state[(i == (p_cells - 1)) ? 0 : (i + 1)];

      // choose a new state using the rule table
      p_buffer[i] = p_rule_tbl[p_rules[i]][tmp_neigh];
    }
  }
  else {
    // compute the next state for each cell
    for(int i = 0; i < p_cells; i++) {
      // determine the cell's neighbourhood (loop unroling ahead :))
      tmp_neigh = p_state[(i == 0) ? (p_cells - 1) : (i - 1)];
      tmp_neigh *= GENE_COUNT;
      tmp_neigh += p_state[i];
      tmp_neigh *= GENE_COUNT;
      tmp_neigh += p_state[(i == (p_cells - 1)) ? 0 : (i + 1)];

      // choose a new state using the rule table
      p_buffer[i] = p_rule_tbl[p_rules[i]][tmp_neigh];
    }
  }

  return p_buffer;
}

