class FOLD_GRID

(source code)

Description

Fold grid

note
	description: "Fold grid"

	author: "Finnian Reilly"
	copyright: "Copyright (C) 2016-2017  Gerrit Leder, Finnian Reilly"
	contact: "finnian at eiffel hyphen loop dot com; gerrit.leder@gmail.com"

	license: "[https://www.gnu.org/licenses/gpl-3.0.en.html GNU General Public License]"
	date: "2022-02-08 15:50:01 GMT (Tuesday 8th February 2022)"
	revision: "3"

class
	FOLD_GRID

inherit
	SE_ARRAY2 [NATURAL_8]
		rename
			item as row_col_item
		export
			{NONE} all
			{ANY} has, initialize, count
		end

	POINT_SET_CONSTANTS
		undefine
			is_equal, copy
		end

	DIRECTION_CONSTANTS
		undefine
			is_equal, copy
		end

create
	make, make_filled

feature -- Status query

	is_item_one_and_used: BOOLEAN
		do
			Result := item = One_and_used
		end

	is_item_used: BOOLEAN
		do
			Result := item & Item_mask > 0
		end

	is_item_zero: BOOLEAN
		do
			Result := item & Used_mask = 0
		end

	some_item_is_not_used: BOOLEAN
		local
			l_area: like area; i, l_count: INTEGER
		do
			l_area := area; l_count := count
			from i := 0 until Result or else i = l_count loop
				Result := l_area.item (i) & Item_mask = 0
				i := i + 1
			end
		end

feature -- Access

	fold_losses (a_x, a_y: INTEGER; a_fold: FOLD_ARRAY): INTEGER
		local
			i, y, x, l_upper, l_width: INTEGER
			l_area: like area
		do
			l_area := area; l_width := width
			x := a_x; y := a_y
			l_upper := a_fold.count + 1
			from i := 2 until i = l_upper loop
				go_to (y, x)
				if is_item_one_and_used then
					inspect a_fold [i - 1]
						when N then
							inspect a_fold [i]
								when E then
									Result := Result + internal_losses (l_area, zero_index, l_width, Points_N_W)
									x := x + 1
								when N then
									Result := Result + losses (Points_E_W)
									y := y - 1
								when W then
									Result := Result + losses (Points_N_E)
									x := x - 1
						else end
						when S then
							inspect a_fold [i]
								when E then
									Result := Result + losses (Points_S_W)
									x := x + 1
								when S then
									Result := Result + losses (Points_E_W)
									y := y + 1
								when W then
									Result := Result + losses (Points_E_S)
									x := x - 1
						else end
						when E then
							inspect a_fold [i]
								when E then
									Result := Result + losses (Points_N_S)
									x := x + 1
								when N then
									Result := Result + losses (Points_E_S)
									y := y - 1
								when S then
									Result := Result + losses (Points_N_E)
									y := y + 1
						else end
						when W then
							inspect a_fold [i]
								when N then
									Result := Result + losses (Points_S_W)
									y := y - 1
								when S then
									Result := Result + losses (Points_N_W)
									y := y + 1
								when W then
									Result := Result + losses (Points_N_S)
									x := x - 1
						else end
					else end

				elseif is_item_zero then
					inspect a_fold [i]
						when N then
							y := y - 1
						when S then
							y := y + 1
						when E then
							x := x + 1
					else
						x := x - 1
					end
				end
				i := i + 1
			end
		end

feature -- Element change

	reset
		do
			initialize (0)
		end

	set_all_used
		local
			l_area: like area; i, l_count: INTEGER
		do
			l_area := area; l_count := count
			from i := 0 until i = l_count loop
				l_area.put (l_area.item (i) | Item_mask, i)
				i := i + 1
			end
		end

	set_item (b: BOOLEAN)
		-- set item to `b' and used bit to True
		do
			item := Item_mask | (b.to_integer.to_natural_8)
			area [zero_index] := item
		end

feature -- Cursor movement

	go_to (row, column: INTEGER)
		local
			i: INTEGER
		do
			i := (row - row_offset - 1) * width + (column - column_offset) - 1
			item := area [i]
			zero_index := i
		end

	losses (point_set: NATURAL): INTEGER
		do
			Result := internal_losses (area, zero_index, width, point_set)
		end

feature {NONE} -- Implementation

	internal_losses (a_area: like area; a_index, a_width: INTEGER; point_set: NATURAL): INTEGER
		local
			i, j: INTEGER; direction_bit: NATURAL
		do
			direction_bit := Point_N
			from i := 1 until i > 4 loop
				if (point_set & direction_bit).to_boolean then
					inspect i
						when 1 then
							j := a_index - a_width -- N
						when 2 then
							j := a_index + 1 -- E
						when 3 then
							j := a_index + a_width -- S
						when 4 then
							j := a_index - 1 -- W
					else end
					if a_area.item (j) & Used_mask = 0 then
						Result := Result + 1
					end
				end
				direction_bit := direction_bit |>> 1
				i := i + 1
			end
		end

feature {NONE} -- Internal attributes

	item: NATURAL_8

	zero_index: INTEGER

feature {NONE} -- Constants

	Item_mask: NATURAL_8 = 0b10

	One_and_used: NATURAL_8 = 0b11

	Used_mask: NATURAL_8 = 0b01;

end