summaryrefslogtreecommitdiff
path: root/base/src/main/java/bjc/utils/misc/Direction.java
blob: 2026349185358f6944f7607488978917ee17e6fc (plain)
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
package bjc.utils.misc;

import java.util.Random;
import java.util.function.Consumer;

import org.apache.commons.lang3.text.WordUtils;

import bjc.utils.exceptions.DirectionInvalid;
import bjc.funcdata.FunctionalList;
import bjc.funcdata.ListEx;

/**
 * A set of cardinal directions
 *
 * The particular axis assigned to the coordinates are based off of x being the
 * bottom left axis on a conventional 3D plot
 *
 * @author ben
 *
 */
public enum Direction {
	/**
	 * Negative z-axis
	 */
	DOWN,
	/**
	 * Positive y-axis
	 */
	EAST,
	/**
	 * Positive x-axis
	 */
	NORTH,
	/**
	 * Negative x-axis
	 */
	SOUTH,
	/**
	 * Positive z-axis
	 */
	UP,
	/**
	 * Negative y-axis
	 */
	WEST;

	/**
	 * The source of randomness for picking random directions
	 */
	private static final Random RNG = new Random();

	/**
	 * Get a list of all the cardinal directions
	 *
	 * @return A list of all the cardinal directions
	 */
	public static ListEx<Direction> cardinals() {
		return new FunctionalList<>(NORTH, SOUTH, EAST, WEST);
	}

	/**
	 * Perform the specified action once with each of the cardinal directions
	 *
	 * @param act
	 *            The action to perform for each cardinal direction
	 */
	public static void forCardinalDirections(Consumer<Direction> act) {
		cardinals().forEach(act);
	}

	/**
	 * Perform a specified action for a random number of cardinals.
	 *
	 * @param nCardinals
	 *                   The number of cardinal directions to act on. Must be
	 *                   greater than 0 and less then 5
	 * @param act
	 *                   The action to perform for each of the cardinals
	 */
	public static void forRandomCardinals(int nCardinals, Consumer<Direction> act) {
		if (nCardinals <= 0 || nCardinals > 4) {
			throw new IllegalArgumentException(
					"Tried to do things with incorrect number of cardinal directions. Tried with "
							+ nCardinals);
		}

		ListEx<Direction> cards = cardinals();

		for (int i = 0; i <= 4 - nCardinals; i++) {
			Direction rDir = cards.randItem(RNG::nextInt);

			cards.removeMatching(rDir);
		}

		cards.forEach(act);
	}

	/**
	 * Create a value of the enumeration from a string
	 *
	 * @param value
	 *              The string to turn into a value
	 * @return The direction corresponding to the given value
	 */
	public static Direction properValueOf(String value) {
		return valueOf(value.toUpperCase());
	}

	/**
	 * Test if this direction is a cardinal direction
	 *
	 * @return If the direction is cardinal or not
	 */
	public boolean isCardinal() {
		switch (this) {
		case EAST:
		case NORTH:
		case SOUTH:
		case WEST:
			return true;
		case DOWN:
		case UP:
			return false;
		default:
			throw new DirectionInvalid(
					"WAT. Somehow ended up with an invalid direction " + this);
		}
	}

	/**
	 * Get the direction that opposes the current one
	 *
	 * @return The direction that is in the opposite direction of the current one
	 */
	public Direction opposing() {
		switch (this) {
		case NORTH:
			return SOUTH;
		case EAST:
			return WEST;
		case SOUTH:
			return NORTH;
		case WEST:
			return WEST;
		case UP:
			return DOWN;
		case DOWN:
			return UP;
		default:
			throw new IllegalStateException("Enumeration got into a invalid state. WAT");
		}
	}

	/**
	 * Get the direction that is clockwise on the compass from this one.
	 *
	 * Only works on cardinals.
	 *
	 * @return The cardinal clockwise from this one
	 */
	public Direction rotateClockwise() {
		switch (this) {
		case NORTH:
			return EAST;
		case EAST:
			return SOUTH;
		case SOUTH:
			return WEST;
		case WEST:
			return NORTH;
		case UP:
		case DOWN:
		default:
			throw new DirectionInvalid(
					"Can't rotate non-cardinal direction clockwise: " + this);

		}
	}

	/**
	 * Get the direction that is counter-clockwise on the compass from this one.
	 *
	 * Only works on cardinals.
	 *
	 * @return The cardinal counter-clockwise from this one
	 */
	public Direction rotateCounterClockwise() {
		switch (this) {
		case NORTH:
			return WEST;
		case EAST:
			return NORTH;
		case SOUTH:
			return EAST;
		case WEST:
			return SOUTH;
		case UP:
		case DOWN:
		default:
			throw new DirectionInvalid(
					"Can't rotate non-cardinal direction counterclockwise: " + this);

		}
	}

	@Override
	public String toString() {
		/*
		 * Make sure the word is properly capitalized for english
		 */
		return WordUtils.capitalize(super.toString().toLowerCase());
	}
}