aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/java/coffee/liz/ecs/math/Mat2.java
blob: 9975227eb5f0a458e1a53bee556efa3eb62cf1d9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package coffee.liz.ecs.math;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

public final class Mat2 {
	private Mat2() {
	}

	/**
	 * Initializes a mutable 2d matrix of given type.
	 *
	 * @param dimensions
	 *            the dimensions
	 * @param constructor
	 *            the constructor
	 * @return row-indexed 2d matrix of {@param dimensions}
	 */
	public static <T> List<List<T>> init(final Vec2<Integer> dimensions, final Function<Vec2<Integer>, T> constructor) {
		final List<List<T>> rows = new ArrayList<>();
		for (int y = 0; y < dimensions.getY(); y++) {
			final List<T> row = new ArrayList<>(dimensions.getX());
			for (int x = 0; x < dimensions.getX(); x++)
				row.add(constructor.apply(Vec2i.builder().y(y).x(x).build()));
			rows.add(row);
		}
		return rows;
	}

	/**
	 * Convolves a {@link Convolver} across a matrix reaching neighbors around the
	 * grid like a torus.
	 *
	 * @param mat
	 *            is the row-indexed 2d matrix to convolve.
	 * @param axes
	 *            are the x/y major/minor axes.
	 * @param init
	 *            is the initial value of the convolution.
	 * @param convolver
	 *            is the {@link Convolver}.
	 * @param finalReduction
	 *            to apply after {@param convolver}.
	 * @return result of {@param convolver} applied along axes at each cell.
	 * @param <T>
	 *            is the type of the matrix to convolve.
	 * @param <R>
	 *            is the type of the resulting type of each convolution.
	 */
	public static <T, R, U> List<List<U>> convolveTorus(final List<List<T>> mat, final Vec2<Integer> axes,
			final Supplier<R> init, final Convolver<T, R> convolver, final BiFunction<T, R, U> finalReduction) {
		final List<List<R>> rows = new ArrayList<>();
		for (int y = 0; y < mat.size(); y++) {
			final List<R> row = new ArrayList<>(mat.get(y).size());
			for (int x = 0; x < mat.get(y).size(); x++) {
				final T center = mat.get(y).get(x);
				R result = init.get();
				for (int dy = -axes.getY(); dy <= axes.getY(); dy++) {
					final int ry = Math.floorMod(y + dy, mat.size());
					for (int dx = -axes.getX(); dx <= axes.getX(); dx++) {
						final int rx = Math.floorMod(x + dx, mat.get(ry).size());
						result = convolver.convolve(mat.get(ry).get(rx), Vec2i.builder().x(dx).y(dy).build(), result);
					}
				}
				row.add(result);
			}
			rows.add(row);
		}

		final List<List<U>> reductions = new ArrayList<>();
		for (int y = 0; y < mat.size(); y++) {
			final List<U> reduction = new ArrayList<>(mat.get(y).size());
			for (int x = 0; x < mat.get(y).size(); x++) {
				reduction.add(finalReduction.apply(mat.get(y).get(x), rows.get(y).get(x)));
			}
			reductions.add(reduction);
		}
		return reductions;
	}

	@FunctionalInterface
	public interface Convolver<T, R> {
		R convolve(final T center, final Vec2<Integer> rel, final R reduction);
	}
}