Passed
Push — master ( 08cd0d...9eabdf )
by Vincent
07:15
created

isFree(CoordinateCell)   A

Complexity

Conditions 5

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 9
c 1
b 0
f 0
dl 0
loc 16
ccs 9
cts 9
cp 1
crap 5
rs 9.3333
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
26
import java.util.ArrayList;
27
import java.util.Collection;
28
import java.util.Collections;
29
import java.util.Iterator;
30
import java.util.function.BiConsumer;
31
32
/**
33
 * Handle the line of sight from a given cell
34
 *
35
 * @param <C> The cell type
36
 */
37
public final class CellSight<C extends BattlefieldCell> {
38
    private final BattlefieldSight<C> battlefield;
39
    private final CoordinateCell<C> source;
40
41 1
    public CellSight(BattlefieldSight<C> battlefield, CoordinateCell<C> source) {
42 1
        this.battlefield = battlefield;
43 1
        this.source = source;
44 1
    }
45
46
    @SuppressWarnings("unchecked")
47
    public CellSight(CoordinateCell<C> source) {
48 1
        this(new BattlefieldSight<>((DofusMap<C>) 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(new CoordinateCell<>(target));
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(new CoordinateCell<>(target));
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
            ? new SameXLineOfSightIterator<>(battlefield, source, target)
147
            : 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
    @SuppressWarnings("unchecked")
171
    public void forEach(BiConsumer<C, Boolean> cellViewConsumer) {
172 1
        final DofusMap<C> map = (DofusMap<C>) source.cell().map();
173 1
        final int size = map.size();
174
175 1
        for (int id = 0; id < size; ++id) {
176 1
            final C target = map.get(id);
177
178 1
            cellViewConsumer.accept(target, isFree(target));
179
        }
180 1
    }
181
182
    /**
183
     * @return Get all accessible cells from the current cell
184
     */
185
    public Collection<C> accessible() {
186 1
        final Collection<C> cells = new ArrayList<>();
187
188 1
        forEach((cell, free) -> {
189 1
            if (free) {
190 1
                cells.add(cell);
191
            }
192 1
        });
193
194 1
        return cells;
195
    }
196
197
    /**
198
     * @return Get all blocked cells from the current cell
199
     */
200
    public Collection<C> blocked() {
201 1
        final Collection<C> cells = new ArrayList<>();
202
203 1
        forEach((cell, free) -> {
204 1
            if (!free) {
205 1
                cells.add(cell);
206
            }
207 1
        });
208
209 1
        return cells;
210
    }
211
}
212