Skip to content

Commit 20bd34f

Browse files
committed
Implement entered_colors(); Fix rotation render; Change create_area() flag input
1 parent 544ded9 commit 20bd34f

File tree

4 files changed

+155
-75
lines changed

4 files changed

+155
-75
lines changed

src/bundles/robot_minigame/functions.ts

Lines changed: 144 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -87,55 +87,6 @@ let bounds: Point[];
8787
// sets the context to the state obj, mostly for convenience so i dont have to type context.... everytime
8888
context.moduleContexts.robot_minigame.state = state;
8989

90-
/**
91-
* Teleport the robot
92-
*
93-
* @param x coordinate of the robot
94-
* @param y coordinate of the robot
95-
*/
96-
function set_pos(
97-
x: number,
98-
y: number
99-
) {
100-
// Init functions should not run after initialization
101-
if (state.isInit) return;
102-
103-
robot.x = x;
104-
robot.y = y;
105-
}
106-
107-
/**
108-
* Set the rotation of the robot
109-
*
110-
* @param rotation in radians
111-
*/
112-
function set_rotation(
113-
rotation: number
114-
) {
115-
// Init functions should not run after initialization
116-
if (state.isInit) return;
117-
118-
robot.dx = Math.cos(rotation);
119-
robot.dy = -Math.sin(rotation);
120-
}
121-
122-
/**
123-
* Set the width and height of the map
124-
*
125-
* @param width of the map
126-
* @param height of the map
127-
*/
128-
function set_dimensions(
129-
width: number,
130-
height: number
131-
) {
132-
// Init functions should not run after initialization
133-
if (state.isInit) return;
134-
135-
state.width = width;
136-
state.height = height;
137-
}
138-
13990
// ===== //
14091
// SETUP //
14192
// ===== //
@@ -183,34 +134,80 @@ export function init(
183134
* @param flags any additional flags the area may have
184135
*/
185136
export function create_area(
186-
rawVertices: number[],
137+
vertices: number[],
187138
isObstacle: boolean,
188-
flags: AreaFlags = {}
139+
flags: any[]
189140
) {
190141
// Init functions should not run after initialization
191142
if (state.isInit) return;
192143

193-
if (rawVertices.length % 2 !== 0) throw new Error('Odd number of arguments given (expected even)');
144+
if (vertices.length % 2 !== 0) throw new Error('Odd number of vertice x-y coordinates given (expected even)');
145+
146+
if (flags.length % 2 !== 0) throw new Error('Odd number of flag arguments given (expected even)');
194147

195148
// Store vertices as Point array
196-
const vertices: Point[] = [];
149+
const parsedVertices: Point[] = [];
197150

198151
// Parse x-y pairs into Points
199-
for (let i = 0; i < rawVertices.length / 2; i++) {
200-
vertices[i] = {
201-
x: rawVertices[i * 2],
202-
y: rawVertices[i * 2 + 1]
152+
for (let i = 0; i < vertices.length / 2; i++) {
153+
parsedVertices[i] = {
154+
x: vertices[i * 2],
155+
y: vertices[i * 2 + 1]
203156
};
204157
}
205158

159+
// Store flags as an object
160+
const parsedFlags = {};
161+
162+
// Parse flag-value pairs into flags
163+
for (let i = 0; i < flags.length / 2; i++) {
164+
// Retrieve flag
165+
const flag = flags[i * 2];
166+
167+
// Check flag is string
168+
if (typeof flag !== 'string') throw new Error(`Flag arguments must be strings (${flag} is a ${typeof flag})`);
169+
170+
// Add flag to object
171+
parsedFlags[flag] = flags[i * 2 + 1];
172+
}
173+
206174
// Store the new area
207175
state.areas.push({
208-
vertices,
176+
vertices: parsedVertices,
209177
isObstacle,
210-
flags
178+
flags: parsedFlags
211179
});
212180
}
213181

182+
/**
183+
* Creates a new rectangular, axis-aligned area
184+
*
185+
* @param x top left corner of the rectangle
186+
* @param y top right corner of the rectangle
187+
* @param width of the rectangle
188+
* @param height of the rectangle
189+
* @param isObstacle a boolean indicating if the area is an obstacle or not
190+
* @param flags any additional flags the area may have
191+
*/
192+
export function create_rect_area(
193+
x: number,
194+
y: number,
195+
width: number,
196+
height: number,
197+
isObstacle: boolean,
198+
flags: any[]
199+
) {
200+
// Init functions should not run after initialization
201+
if (state.isInit) return;
202+
203+
create_area([
204+
x, y,
205+
x + width, y,
206+
x + width, y + height,
207+
x, y + height
208+
], isObstacle, flags);
209+
}
210+
214211
/**
215212
* Creates a new obstacle
216213
*
@@ -222,7 +219,7 @@ export function create_obstacle(
222219
// Init functions should not run after initialization
223220
if (state.isInit) return;
224221

225-
create_area(vertices, true);
222+
create_area(vertices, true, []);
226223
}
227224

228225
/**
@@ -242,12 +239,7 @@ export function create_rect_obstacle(
242239
// Init functions should not run after initialization
243240
if (state.isInit) return;
244241

245-
create_obstacle([
246-
x, y,
247-
x + width, y,
248-
x + width, y + height,
249-
x, y + height
250-
]);
242+
create_rect_area(x, y, width, height, true, []);
251243
}
252244

253245
/**
@@ -425,6 +417,15 @@ export function turn_right() {
425417
// TESTING //
426418
// ======= //
427419

420+
/**
421+
* Inform the simulator that the testing phase is starting
422+
*/
423+
export function start_testing() {
424+
if (state.isComplete) throw new Error('May not start testing twice!');
425+
426+
state.isComplete = true;
427+
}
428+
428429
/**
429430
* Checks if the robot's entered areas satisfy the condition
430431
*
@@ -433,9 +434,74 @@ export function turn_right() {
433434
export function entered_areas(
434435
callback : (areas : Area[]) => boolean
435436
) : boolean {
437+
// Testing functions should only run after the simulation is complete
438+
if (!state.isComplete) return false;
439+
436440
return callback(state.areaLog);
437441
}
438442

443+
/**
444+
* Check if the robot has entered different areas with the given colors in order
445+
*
446+
* @param colors in order
447+
* @returns if the robot entered the given colors in order
448+
*/
449+
export function entered_colors(
450+
colors: string[]
451+
) : boolean {
452+
// Testing functions should only run after the simulation is complete
453+
if (!state.isComplete) return false;
454+
455+
return state.areaLog
456+
.filter(area => colors.includes(area.flags.color)) // Filter relevant colors
457+
.filter(filterAdjacentDuplicateAreas) // Filter adjacent duplicates
458+
.every(({ flags: { color } }, i) => color === colors[i]); // Check if each area has the expected color
459+
}
460+
461+
// ================== //
462+
// DATA WRITE HELPERS //
463+
// ================== //
464+
465+
/**
466+
* Teleport the robot
467+
*
468+
* @param x coordinate of the robot
469+
* @param y coordinate of the robot
470+
*/
471+
function set_pos(
472+
x: number,
473+
y: number
474+
) {
475+
robot.x = x;
476+
robot.y = y;
477+
}
478+
479+
/**
480+
* Set the rotation of the robot
481+
*
482+
* @param rotation in radians
483+
*/
484+
function set_rotation(
485+
rotation: number
486+
) {
487+
robot.dx = Math.cos(rotation);
488+
robot.dy = -Math.sin(rotation);
489+
}
490+
491+
/**
492+
* Set the width and height of the map
493+
*
494+
* @param width of the map
495+
* @param height of the map
496+
*/
497+
function set_dimensions(
498+
width: number,
499+
height: number
500+
) {
501+
state.width = width;
502+
state.height = height;
503+
}
504+
439505
// ================= //
440506
// DATA READ HELPERS //
441507
// ================= //
@@ -707,3 +773,15 @@ function areaEquals(a: Area, b: Area) {
707773

708774
return true;
709775
}
776+
777+
/**
778+
* Filter callback to remove adjacent duplicate areas
779+
*
780+
* @param area currently being checked
781+
* @param i index of area
782+
* @param areas the full array being filtered
783+
* @returns if the current area is not a duplicate of the previous area
784+
*/
785+
const filterAdjacentDuplicateAreas = (area : Area, i : number, areas: Area[]) : boolean =>
786+
i === 0 // First one is always correct
787+
|| !areaEquals(area, areas[i - 1]); // Otherwise check for equality against previous area
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
/**
2-
* A single sentence summarising the module (this sentence is displayed larger).
3-
*
4-
* Sentences describing the module. More sentences about the module.
2+
* The robot_minigame module allows us to control a robot to complete various tasks
53
*
64
* @module robot_minigame
75
* @author Koh Wai Kei
86
* @author Justin Cheng
97
*/
108

119
export {
12-
init, create_area, create_obstacle, create_rect_obstacle, complete_init,
10+
init, create_area, create_rect_area, create_obstacle, create_rect_obstacle, complete_init,
1311
get_distance, get_flags, get_color,
1412
move_forward, move_forward_to_wall, rotate, turn_left, turn_right,
15-
entered_areas
13+
start_testing, entered_areas, entered_colors
1614
} from './functions';

src/tabs/RobotMaze/components/RobotSimulation.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,17 @@ const drawBorders = (ctx: CanvasRenderingContext2D, width: number, height: numbe
3939

4040
// Draw the areas of the map
4141
const drawAreas = (ctx: CanvasRenderingContext2D, areas: Area[]) => {
42-
for (const { vertices } of areas) {
42+
for (const { vertices, isObstacle, flags } of areas) {
4343
ctx.beginPath();
4444
ctx.moveTo(vertices[0].x, vertices[0].y);
4545
for (const vertex of vertices.slice(1)) {
4646
ctx.lineTo(vertex.x, vertex.y);
4747
}
4848
ctx.closePath();
4949

50-
ctx.fillStyle = 'rgba(169, 169, 169, 0.5)'; // Set the fill color
50+
ctx.fillStyle = isObstacle // Obstacles are gray
51+
? 'rgba(169, 169, 169, 0.5)'
52+
: flags.color || 'none'; // Areas may have color
5153
ctx.fill(); // Fill the polygon
5254

5355
ctx.strokeStyle = 'rgb(53, 53, 53)'; // Set the stroke color
@@ -225,7 +227,7 @@ const RobotSimulation : React.FC<MapProps> = ({
225227
break;
226228
} case 'rotate':
227229
// If rotation is close to target rotation
228-
if (Math.abs(target.rotation - robot.current.rotation) <= 0.1) {
230+
if (Math.abs((target.rotation - robot.current.rotation) % (2 * Math.PI)) < 0.1) {
229231
// Snap to the target point
230232
robot.current.rotation = target.rotation;
231233

src/tabs/RobotMaze/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ export default {
3434
* @returns {boolean}
3535
*/
3636
toSpawn(context: DebuggerContext) {
37+
// !!! TEMPORARY DEBUGGING FUNCTION, REMOVE ONCE MODULE IS COMPLETE !!!
3738
console.log(context.context?.moduleContexts?.robot_minigame.state);
38-
return context.context?.moduleContexts?.robot_minigame.state.isInit;
39+
40+
return context.context?.moduleContexts?.robot_minigame.state.isComplete;
3941
},
4042

4143
/**

0 commit comments

Comments
 (0)