summaryrefslogtreecommitdiff
path: root/core/src/main/java/coffee/liz/ecs/math/Mat2.java
blob: ed9493c1f9f58786b5eb145689d40911f838b9fc (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);
    }
}