#include "IdanStringPointersLib.h"
#include <stdio.h>

#define ROW 5
#define COL 5

unsigned short SumValuesInPointers(BOOLEAN * ptr_start, BOOLEAN * ptr_end) 
{
    unsigned short sum;
    for (sum = ZERO; ptr_start <= ptr_end; sum += *(ptr_start++));

    return (sum);
}

unsigned short CountNeighbors(BOOLEAN *ptr_mat, BOOLEAN *ptr_player)
{
    unsigned short neighbords_count = ZERO;
    unsigned short player_row = (ptr_player - ptr_mat) / ROW;
    unsigned short player_col = (ptr_player - ptr_mat) % COL;

    // Add the sum of the vector above the cell
    neighbords_count += (player_row > ZERO) * SumValuesInPointers(ptr_mat + (MAX(player_row - ONE, ZERO)) * ROW + (MAX(player_col - ONE, ZERO)), 
                                            ptr_mat + (MAX(player_row - ONE, ZERO)) * ROW + (MIN(player_col + ONE, COL - ONE)));

    // Add the sum of the vector middle the cell
    neighbords_count += SumValuesInPointers(ptr_mat + (player_row) * ROW + (MAX(player_col - ONE, ZERO)), 
                                            ptr_mat + (player_row) * ROW + (MIN(player_col + ONE, COL - ONE))) - *ptr_player;

    // Add the sum of the vector below the cell
    neighbords_count += (player_row < ROW) * SumValuesInPointers(ptr_mat + (MIN(player_row + ONE, ROW - ONE)) * ROW + (MAX(player_col - ONE, ZERO)), 
                                            ptr_mat + (MIN(player_row + ONE, ROW - ONE)) * ROW + (MIN(player_col + ONE, COL - ONE)));

    return (neighbords_count);
}

void OneLive(BOOLEAN *ptr_mat)
{
    BOOLEAN *ptr_mat_start = ptr_mat;
    BOOLEAN *ptr_mat_end = ptr_mat_start + (ROW * COL);
    for (; ptr_mat_start < ptr_mat_end; *(ptr_mat_start++) = (CountNeighbors(ptr_mat, ptr_mat_start) == TWO));
}

void GameLife(BOOLEAN *ptr_mat, unsigned short lives)
{
    for (; lives; lives--)
    {
        OneLive(ptr_mat);
        PrintMatrix(ptr_mat);
        printf("\n");
    } 
}

void ResetMatrix(BOOLEAN *ptr_mat)
{
    BOOLEAN *end_mat = ptr_mat + (ROW * COL);
    for (; ptr_mat < end_mat; *(ptr_mat++) %= TWO);
}

void PrintVector(BOOLEAN *ptr_vec) // Lenght = COL
{
    BOOLEAN *end_vec = ptr_vec + COL;
    for (; ptr_vec < end_vec; ptr_vec++)
    {
        printf("%hu, ", *ptr_vec);
    }
}

void PrintMatrix(BOOLEAN *ptr_mat) // Lenght = ROW
{
    BOOLEAN *end_mat = ptr_mat + (ROW * COL);
    for (; ptr_mat < end_mat; ptr_mat += COL)
    {
        PrintVector(ptr_mat);
        printf("\n");
    }
}

void main(void)
{
    BOOLEAN mat[ROW][COL] = {{1,1,1,0,1}, {1,1,1,1,1}, {1,1,1,1,1}, {1,0,1,0,1}, {1,0,1,0,1}};
    PrintMatrix(mat);
    printf("\n");
    GameLife(mat, THREE);
}