|
| 1 | +/* |
| 2 | +* Internally, the robot uses a grid based movement and collision system |
| 3 | +*/ |
| 4 | + |
| 5 | +import context from 'js-slang/context'; |
| 6 | + |
| 7 | +let robotPos: Point = {x: 0, y: 0}; |
| 8 | + |
| 9 | +let movePoints: Point[]; |
| 10 | + |
| 11 | +const DIRECTIONS = { |
| 12 | + UP: 0, |
| 13 | + RIGHT: 1, |
| 14 | + DOWN: 2, |
| 15 | + LEFT: 3 |
| 16 | +}; |
| 17 | + |
| 18 | +let robotRotation = 1; |
| 19 | + |
| 20 | +// default grid width and height is 25 |
| 21 | +context.moduleContexts.robot_minigame.state = { |
| 22 | + isInit: false, |
| 23 | + width: 25, |
| 24 | + height: 25, |
| 25 | + walls: [], |
| 26 | + movePoints: [], |
| 27 | + message: "moved successfully", |
| 28 | + success: true |
| 29 | +} |
| 30 | + |
| 31 | +type Point = {x: number, y: number} |
| 32 | +type Wall = {p1: Point, p2: Point} |
| 33 | + |
| 34 | +export function set_pos(x: number, y: number): void { |
| 35 | + robotPos.x = x; |
| 36 | + robotPos.y = y; |
| 37 | +} |
| 38 | + |
| 39 | +export function set_grid_width(width: number) { |
| 40 | + context.moduleContexts.robot_minigame.state.width = width; |
| 41 | +} |
| 42 | + |
| 43 | +export function set_grid_height(height: number) { |
| 44 | + context.moduleContexts.robot_minigame.state.height = height; |
| 45 | +} |
| 46 | + |
| 47 | +export function init(gridWidth: number, gridHeight: number, posX: number, posY: number) { |
| 48 | + set_grid_width(gridWidth); |
| 49 | + set_grid_height(gridHeight); |
| 50 | + set_pos(posX, posY); |
| 51 | + context.moduleContexts.robot_minigame.state.movePoints.push({x: posX, y: posY}); |
| 52 | + context.moduleContexts.robot_minigame.state.isInit = true; |
| 53 | +} |
| 54 | + |
| 55 | +export function turn_left() { |
| 56 | + if (alrCollided()) return; |
| 57 | + |
| 58 | + robotRotation -= 1; |
| 59 | + if (robotRotation < 0) { |
| 60 | + robotRotation = 3; |
| 61 | + } |
| 62 | +} |
| 63 | + |
| 64 | +export function turn_right() { |
| 65 | + if (alrCollided()) return; |
| 66 | + |
| 67 | + robotRotation = (robotRotation + 1) % 4; |
| 68 | +} |
| 69 | + |
| 70 | +// takes the top left and bottom right corners of walls |
| 71 | +// in terms of grid boxes |
| 72 | +// grid starts from (0, 0) at the top left corner btw |
| 73 | +export function set_wall(x1: number, y1: number, x2: number, y2: number) { |
| 74 | + let wall: Wall = {p1: {x: x1, y: y1}, p2: {x: x2, y: y2}}; |
| 75 | + context.moduleContexts.robot_minigame.state.walls.push(wall); |
| 76 | +} |
| 77 | + |
| 78 | +export function move_forward(dist: number): void { |
| 79 | + if (alrCollided()) return; |
| 80 | + |
| 81 | + simulate(dist); |
| 82 | +} |
| 83 | + |
| 84 | +export function getX():number { |
| 85 | + return robotPos.x; |
| 86 | +} |
| 87 | + |
| 88 | +export function getY():number { |
| 89 | + return robotPos.y; |
| 90 | +} |
| 91 | + |
| 92 | +function simulate(moveDist: number) { |
| 93 | + let dx: number = 0; |
| 94 | + let dy: number = 0; |
| 95 | + switch (robotRotation) { |
| 96 | + case DIRECTIONS.UP: |
| 97 | + dy = -1; |
| 98 | + break; |
| 99 | + case DIRECTIONS.RIGHT: |
| 100 | + dx = 1; |
| 101 | + break; |
| 102 | + case DIRECTIONS.DOWN: |
| 103 | + dy = 1; |
| 104 | + break; |
| 105 | + case DIRECTIONS.LEFT: |
| 106 | + dx = -1; |
| 107 | + break; |
| 108 | + } |
| 109 | + |
| 110 | + // moves robot by one grid box and checks collision |
| 111 | + for (var i = 0; i < moveDist; i++) { |
| 112 | + robotPos.x += dx; |
| 113 | + robotPos.y += dy; |
| 114 | + |
| 115 | + var walls = context.moduleContexts.robot_minigame.state.walls; |
| 116 | + for (let j = 0; j < walls.length; j++) { |
| 117 | + if (checkWallCollision(walls[j], robotPos)) { |
| 118 | + context.moduleContexts.robot_minigame.state.success = false; |
| 119 | + context.moduleContexts.robot_minigame.state.message = "collided"; |
| 120 | + context.moduleContexts.robot_minigame.state.movePoints.push({x: robotPos.x, y: robotPos.y}); |
| 121 | + return; |
| 122 | + } |
| 123 | + } |
| 124 | + } |
| 125 | + |
| 126 | + context.moduleContexts.robot_minigame.state.movePoints.push({x: robotPos.x, y: robotPos.y}); |
| 127 | + |
| 128 | + // OLD CODE |
| 129 | + // let destX = robotPos.x + moveDist * Math.cos(robotAngle); |
| 130 | + // let destY = robotPos.y + moveDist * Math.sin(robotAngle); |
| 131 | + // let destPoint: Point = {x: destX, y: destY} |
| 132 | + |
| 133 | + // for (let i = 0; i < steps; i++) { |
| 134 | + // let distX: number = moveSpeed * Math.cos(robotAngle); |
| 135 | + // let distY: number = moveSpeed * Math.sin(robotAngle); |
| 136 | + |
| 137 | + // robotPos.x += distX; |
| 138 | + // robotPos.y += distY; |
| 139 | + |
| 140 | + // for (let j = 0; j < walls.length; j++) { |
| 141 | + // if(checkWallCollision(walls[j], robotPos)) { |
| 142 | + // addMessage("Collided with wall!!"); |
| 143 | + // addMessage(`Position: (${robotPos.x.toFixed(3)}, ${robotPos.y.toFixed(3)}), Rotation: ${robotAngle}\n`); |
| 144 | + // return; |
| 145 | + // } |
| 146 | + // } |
| 147 | + |
| 148 | + // if (distanceBetween(destPoint, robotPos) < robotRadius) { |
| 149 | + // robotPos = destPoint; |
| 150 | + // addMessage(`Robot moved forward by ${moveDist} at angle ${robotAngle} radians\n`); |
| 151 | + // addMessage(`Position: (${robotPos.x.toFixed(3)}, ${robotPos.y.toFixed(3)}), Rotation: ${robotAngle}\n`); |
| 152 | + // return; |
| 153 | + // } |
| 154 | + // } |
| 155 | + |
| 156 | + |
| 157 | +} |
| 158 | + |
| 159 | + |
| 160 | +function checkWallCollision(wall: Wall, pos: Point): boolean { |
| 161 | + // // Apply the distance formula |
| 162 | + // const p1 = wall.p1; |
| 163 | + // const p2 = wall.p2; |
| 164 | + |
| 165 | + // const numerator = Math.abs((p2.y - p1.y) * pos.x - (p2.x - p1.x) * pos.y + p2.x * p1.y - p2.y * p1.x); |
| 166 | + // const denominator = Math.sqrt((p2.y - p1.y) ** 2 + (p2.x - p1.x) ** 2); |
| 167 | + |
| 168 | + // return numerator / denominator < robotRadius; |
| 169 | + |
| 170 | + const p1 = wall.p1; |
| 171 | + const p2 = wall.p2; |
| 172 | + |
| 173 | + const minX = Math.min(p1.x, p2.x); |
| 174 | + const maxX = Math.max(p1.x, p2.x); |
| 175 | + const minY = Math.min(p1.y, p2.y); |
| 176 | + const maxY = Math.max(p1.y, p2.y); |
| 177 | + |
| 178 | + return pos.x >= minX && pos.x <= maxX && pos.y >= minY && pos.y <= maxY; |
| 179 | +} |
| 180 | + |
| 181 | +function alrCollided() { |
| 182 | + return !context.moduleContexts.robot_minigame.state.success; |
| 183 | +} |
0 commit comments