fr.arakne.utils.maps.sight.CellSight   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 171
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 45
c 1
b 0
f 0
dl 0
loc 171
ccs 40
cts 40
cp 1
rs 10
wmc 18

9 Methods

Rating   Name   Duplication   Size   Complexity  
A to(C) 0 2 1
A isFree(C) 0 2 1
A isFree(CoordinateCell) 0 16 5
A CellSight(CoordinateCell) 0 2 1
A to(CoordinateCell) 0 8 3
A CellSight(BattlefieldSight,CoordinateCell) 0 3 1
A blocked() 0 10 2
A forEach(BiConsumer) 0 8 2
A accessible() 0 10 2
1
/*
2
 * This file is part of ArakneUtils.
3
 *
4
 * ArakneUtils is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU Lesser General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * ArakneUtils is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public License
15
 * along with ArakneUtils.  If not, see <https://www.gnu.org/licenses/>.
16
 *
17
 * Copyright (c) 2017-2021 Vincent Quatrevieux
18
 */
19
20
package fr.arakne.utils.maps.sight;
21
22
import fr.arakne.utils.maps.BattlefieldCell;
23
import fr.arakne.utils.maps.CoordinateCell;
24
import fr.arakne.utils.maps.DofusMap;
25
import org.checkerframework.checker.nullness.qual.NonNull;
26
27
import java.util.ArrayList;
28
import java.util.Collection;
29
import java.util.Collections;
30
import java.util.Iterator;
31
import java.util.function.BiConsumer;
32
33
/**
34
 * Handle the line of sight from a given cell
35
 *
36
 * @param <C> The cell type
37
 */
38
public final class CellSight<C extends @NonNull BattlefieldCell> {
39
    private final BattlefieldSight<C> battlefield;
40
    private final CoordinateCell<C> source;
41
42 1
    public CellSight(BattlefieldSight<C> battlefield, CoordinateCell<C> source) {
43 1
        this.battlefield = battlefield;
44 1
        this.source = source;
45 1
    }
46
47
    public CellSight(CoordinateCell<C> source) {
48 1
        this(new BattlefieldSight<>(source.cell().map()), source);
49 1
    }
50
51
    /**
52
     * Check if the line of sight is free towards the target
53
     *
54
     * Usage:
55
     * <pre>{@code
56
     * final CellSight<FightCell> sight = fighter.cell().sight();
57
     *
58
     * if (!sight.isFree(target.cell().coordinate())) {
59
     *     throw new Exception("Target is no reachable");
60
     * }
61
     * }</pre>
62
     *
63
     * @param target The target cell
64
     *
65
     * @return true if line sight of sight is free
66
     */
67
    public boolean isFree(CoordinateCell<C> target) {
68 1
        if (source.equals(target)) {
69 1
            return true;
70
        }
71
72 1
        final Iterator<C> sight = to(target);
73
74 1
        while (sight.hasNext()) {
75 1
            final C cell = sight.next();
76
77 1
            if (cell.sightBlocking() && !cell.equals(target.cell())) {
78 1
                return false;
79
            }
80 1
        }
81
82 1
        return true;
83
    }
84
85
    /**
86
     * Check if the line of sight is free towards the target
87
     *
88
     * Usage:
89
     * <pre>{@code
90
     * final CellSight<FightCell> sight = fighter.cell().sight();
91
     *
92
     * if (!sight.isFree(target.cell())) {
93
     *     throw new Exception("Target is no reachable");
94
     * }
95
     * }</pre>
96
     *
97
     * @param target The target cell
98
     * @return true if line sight of sight is free
99
     */
100
    public boolean isFree(C target) {
101 1
        return isFree(target.coordinate());
102
    }
103
104
    /**
105
     * Iterator of cells between current one and the target
106
     * Note: the current cell is excluded from the iterator, but not the target. If the source and the target are same cells, an empty iterator is returned
107
     *
108
     * Usage:
109
     * <pre>{@code
110
     * // Iterate over all cells between fighter.cell() and target.cell()
111
     * fighter.cell().sight().to(target.cell()).forEachRemaining(cell -> {
112
     *     // cell is on the line of sight
113
     * });
114
     * }</pre>
115
     *
116
     * @param target The target cell
117
     *
118
     * @return The cells iterator
119
     */
120
    public Iterator<C> to(C target) {
121 1
        return to(target.coordinate());
122
    }
123
124
    /**
125
     * Iterator of cells between current one and the target
126
     * Note: the current cell is excluded from the iterator, but not the target. If the source and the target are same cells, an empty iterator is returned
127
     *
128
     * Usage:
129
     * <pre>{@code
130
     * // Iterate over all cells between fighter.cell() and target.cell()
131
     * fighter.cell().sight().to(target.cell()).forEachRemaining(cell -> {
132
     *     // cell is on the line of sight
133
     * });
134
     * }</pre>
135
     *
136
     * @param target The target cell
137
     *
138
     * @return The cells iterator
139
     */
140
    public Iterator<C> to(CoordinateCell<C> target) {
141 1
        if (source.equals(target)) {
142 1
            return Collections.emptyIterator();
143
        }
144
145 1
        return source.x() == target.x()
146 1
            ? new SameXLineOfSightIterator<>(battlefield, source, target)
147 1
            : new NotAlignedLineOfSightIterator<>(battlefield, source, target)
148
        ;
149
    }
150
151
    /**
152
     * Iterate over all map cells, and check for each cells is the line of sight is free
153
     *
154
     * <pre>{@code
155
     * final CellSight<FightCell> sight = fighter.cell().sight();
156
     * final CoordinateCell<FightCell> to = new CoordinateCell<>(target.cell());
157
     *
158
     * sight.forEach((cell, free) -> {
159
     *     if (free) {
160
     *         performActionOnAccessibleCell(cell);
161
     *     }
162
     * });
163
     * }</pre>
164
     *
165
     * @param cellViewConsumer The cell consumer. Takes as first parameter the cell and at second the sight status (true if free)
166
     *
167
     * @see CellSight#accessible() For dump accessible cells
168
     * @see CellSight#blocked() For dump blocked cells
169
     */
170
    public void forEach(BiConsumer<C, Boolean> cellViewConsumer) {
171 1
        final DofusMap<C> map = source.cell().map();
172 1
        final int size = map.size();
173
174 1
        for (int id = 0; id < size; ++id) {
175 1
            final C target = map.get(id);
176
177 1
            cellViewConsumer.accept(target, isFree(target));
178
        }
179 1
    }
180
181
    /**
182
     * @return Get all accessible cells from the current cell
183
     */
184
    public Collection<C> accessible() {
185 1
        final Collection<C> cells = new ArrayList<>();
186
187 1
        forEach((cell, free) -> {
188 1
            if (free) {
189 1
                cells.add(cell);
190
            }
191 1
        });
192
193 1
        return cells;
194
    }
195
196
    /**
197
     * @return Get all blocked cells from the current cell
198
     */
199
    public Collection<C> blocked() {
200 1
        final Collection<C> cells = new ArrayList<>();
201
202 1
        forEach((cell, free) -> {
203 1
            if (!free) {
204 1
                cells.add(cell);
205
            }
206 1
        });
207
208 1
        return cells;
209
    }
210
}
211