module automaton

// ///////////////////////////////////////////////////////////
pub struct A2D {
pub mut:
	maxx int
	maxy int
	data &int
}

fn new_a2d(maxx int, maxy int) &A2D {
	size := int(sizeof(int)) * (maxx * maxy)
	return &A2D{
		maxx: maxx
		maxy: maxy
		data: unsafe { &int(vcalloc(size)) }
	}
}

[inline]
pub fn (a &A2D) set(x int, y int, newval int) {
	unsafe {
		mut e := &int(0)
		e = a.data + y * a.maxx + x
		*e = newval
		_ = e // TODO compiler bug, this is not necessary
	}
}

[inline]
pub fn (a &A2D) get(x int, y int) int {
	unsafe {
		mut e := &int(0)
		e = a.data + y * a.maxx + x
		_ = e
		return *e
	}
}

[inline]
pub fn (a &A2D) clear() {
	for y := 0; y < a.maxy; y++ {
		for x := 0; x < a.maxx; x++ {
			a.set(x, y, 0)
		}
	}
}

// ///////////////////////////////////////////////////////////
pub struct Automaton {
pub mut:
	field     &A2D
	new_field &A2D
}

fn new_automaton(ftext string) Automaton {
	f := ftext.split('\n').map(it.trim_space()).filter(it.len > 0)
	maxy := f.len
	mut maxx := 0
	for y := 0; y < f.len; y++ {
		if maxx < f[y].len {
			maxx = f[y].len
		}
	}
	field := new_a2d(maxx, maxy)
	new_field := new_a2d(maxx, maxy)
	for y in 0 .. field.maxy {
		for x in 0 .. field.maxx {
			val := if x < f[y].len && f[y][x] == `#` { 1 } else { 0 }
			field.set(x, y, val)
		}
	}
	return Automaton{
		field: field
		new_field: new_field
	}
}

pub fn (mut aa Automaton) update() {
	aa.new_field.clear()
	for y := 1; y < aa.field.maxy; y++ {
		for x := 1; x < aa.field.maxx; x++ {
			moore_sum := (0 + aa.field.get(x - 1, y - 1) + aa.field.get(x, y - 1) + aa.field.get(x +
				1, y - 1) + aa.field.get(x - 1, y) + 0 + aa.field.get(x + 1, y) +
				aa.field.get(x - 1, y + 1) + aa.field.get(x, y + 1) + aa.field.get(x + 1, y + 1))
			cell := aa.field.get(x, y)
			v := if cell == 1 { moore_sum in [2, 3] } else { moore_sum == 3 }
			aa.new_field.set(x, y, if v { 1 } else { 0 })
		}
	}
	tmp := aa.field
	aa.field = aa.new_field
	aa.new_field = tmp
}

pub fn gun() Automaton {
	field := '
*******************************************
*                                         *
*  A shooting gun:                        *
*                          #              *
*                        # #              *
*              ##      ##            ##   *
*             #   #    ##            ##   *
*  ##        #     #   ##                 *
*  ##        #   # ##    # #              *
*            #     #       #              *
*             #   #                       *
*              ##                         *
*                                         *
*  Tetris Life:                           *
*                                         *
*  ##       ####                          *
*  ##                                     *
*                                         *
*                                         *
*                                         *
*  #         ##                           *
*  ###      ##                            *
*                                         *
*                                         *
*                                         *
*        #                                *
*       ###                               *
*                                         *
*                                         *
*                                         *
*                                         *
*******************************************
'
	return new_automaton(field)
}