44*/
55
66import context from 'js-slang/context' ;
7+ import {
8+ accumulate ,
9+ head ,
10+ tail ,
11+ type List
12+ } from 'js-slang/dist/stdlib/list' ;
713
814type Point = { x : number , y : number } ;
15+ type Intersection = { x : number , y : number , dist : number }
916
1017type Polygon = Point [ ] ;
1118
@@ -17,7 +24,8 @@ type StateData = {
1724 movePoints : Point [ ] ,
1825 message : string ,
1926 success : boolean ,
20- messages : string [ ]
27+ messages : string [ ] ,
28+ rotations : Point [ ]
2129} ;
2230
2331type Robot = {
@@ -36,7 +44,8 @@ const stateData: StateData = {
3644 movePoints : [ ] ,
3745 message : 'moved successfully' ,
3846 success : true ,
39- messages : [ ]
47+ messages : [ ] ,
48+ rotations : [ ]
4049} ;
4150
4251const robot : Robot = {
@@ -49,7 +58,6 @@ const robot: Robot = {
4958
5059let bounds : Point [ ] = [ ] ;
5160
52- // default grid width and height is 25
5361context . moduleContexts . robot_minigame . state = stateData ;
5462
5563export function set_pos ( x : number , y : number ) : void {
@@ -82,23 +90,59 @@ export function init(width: number, height: number, posX: number, posY: number)
8290}
8391
8492export function turn_left ( ) {
85- if ( alrCollided ( ) ) return ;
93+ let currentAngle = Math . atan2 ( - robot . dy , robot . dx ) ;
8694
87- let currentAngle = Math . tan ( robot . dy / robot . dx ) ;
88- currentAngle -= Math . PI / 2 ;
95+ currentAngle += Math . PI / 2 ;
8996
9097 robot . dx = Math . cos ( currentAngle ) ;
91- robot . dy = Math . sin ( currentAngle ) ;
98+ robot . dy = - Math . sin ( currentAngle ) ;
99+
100+ if ( robot . dx < 0.00001 && robot . dx > - 0.00001 ) robot . dx = 0 ;
101+ if ( robot . dy < 0.00001 && robot . dy > - 0.00001 ) robot . dy = 0 ;
102+
103+ logCoordinates ( ) ;
92104}
93105
94106export function turn_right ( ) {
95- if ( alrCollided ( ) ) return ;
107+ let currentAngle = Math . atan2 ( - robot . dy , robot . dx ) ;
96108
97- let currentAngle = Math . tan ( robot . dy / robot . dx ) ;
98- currentAngle += Math . PI / 2 ;
109+ currentAngle -= Math . PI / 2 ;
99110
100111 robot . dx = Math . cos ( currentAngle ) ;
101- robot . dy = Math . sin ( currentAngle ) ;
112+ robot . dy = - Math . sin ( currentAngle ) ;
113+
114+ if ( robot . dx < 0.00001 && robot . dx > - 0.00001 ) robot . dx = 0 ;
115+ if ( robot . dy < 0.00001 && robot . dy > - 0.00001 ) robot . dy = 0 ;
116+
117+ logCoordinates ( ) ;
118+ }
119+
120+ export function rotate_right ( angle : number ) {
121+ let currentAngle = Math . atan2 ( - robot . dy , robot . dx ) ;
122+
123+ currentAngle -= angle ;
124+
125+ robot . dx = Math . cos ( currentAngle ) ;
126+ robot . dy = - Math . sin ( currentAngle ) ;
127+
128+ if ( robot . dx < 0.00001 && robot . dx > - 0.00001 ) robot . dx = 0 ;
129+ if ( robot . dy < 0.00001 && robot . dy > - 0.00001 ) robot . dy = 0 ;
130+
131+ logCoordinates ( ) ;
132+ }
133+
134+ export function rotate_left ( angle : number ) {
135+ let currentAngle = Math . atan2 ( - robot . dy , robot . dx ) ;
136+
137+ currentAngle += angle ;
138+
139+ robot . dx = Math . cos ( currentAngle ) ;
140+ robot . dy = - Math . sin ( currentAngle ) ;
141+
142+ if ( robot . dx < 0.00001 && robot . dx > - 0.00001 ) robot . dx = 0 ;
143+ if ( robot . dy < 0.00001 && robot . dy > - 0.00001 ) robot . dy = 0 ;
144+
145+ logCoordinates ( ) ;
102146}
103147
104148export function set_rect_wall ( x : number , y : number , width : number , height : number ) {
@@ -112,20 +156,15 @@ export function set_rect_wall(x: number, y: number, width: number, height: numbe
112156 stateData . walls . push ( polygon ) ;
113157}
114158
115- export function move_forward ( ) : void {
116- if ( alrCollided ( ) ) return ;
117-
118- const collisionPoint : Point | null = raycast ( stateData . walls ) ;
119- if ( collisionPoint !== null ) {
120- const nextPoint : Point = {
121- x : collisionPoint . x - robot . dx * ( robot . radius + 5 ) ,
122- y : collisionPoint . y - robot . dy * ( robot . radius + 5 )
123- } ;
124-
125- robot . x = nextPoint . x ;
126- robot . y = nextPoint . y ;
127- stateData . movePoints . push ( nextPoint ) ;
159+ export function set_polygon_wall ( vertices : List ) {
160+ const polygon : Polygon = [ ]
161+ while ( vertices != null ) {
162+ const p = head ( vertices ) ;
163+ polygon . push ( { x : head ( p ) , y : tail ( p ) } ) ;
164+ vertices = tail ( vertices ) ;
128165 }
166+
167+ stateData . walls . push ( polygon ) ;
129168}
130169
131170export function getX ( ) :number {
@@ -136,77 +175,117 @@ export function getY():number {
136175 return robot . y ;
137176}
138177
139- function raycast ( polygons : Polygon [ ] ) : Point | null {
178+ export function move_forward ( ) : void {
179+ if ( alrCollided ( ) ) return ;
180+
181+ let distance = findCollision ( ) ;
182+ distance = Math . max ( distance - robot . radius - 5 , 0 )
183+
184+ const nextPoint : Point = {
185+ x : robot . x + distance * robot . dx ,
186+ y : robot . y + distance * robot . dy
187+ }
188+
189+
190+ robot . x = nextPoint . x ;
191+ robot . y = nextPoint . y ;
192+ stateData . movePoints . push ( nextPoint ) ;
193+ stateData . messages . push ( `Distance is ${ distance } Collision point at x: ${ nextPoint . x } , y: ${ nextPoint . y } ` ) ;
194+ }
195+
196+ function findCollision ( ) : number {
140197 let nearest : Point | null = null ;
141- let minDist = Infinity ;
198+ let minDist : number = Infinity ;
199+
200+ for ( const wall of stateData . walls ) {
201+ const intersection : Intersection | null = raycast ( wall ) ;
202+ if ( intersection !== null && intersection . dist < minDist ) {
203+ minDist = intersection . dist ;
204+ nearest = { x : intersection . x , y : intersection . y } ;
205+ }
206+ }
142207
143- for ( const polygon of polygons ) {
144- stateData . messages . push ( 'checking polygon' ) ;
145- const numVertices = polygon . length ;
208+ // check outer bounds as well
209+ const intersection : Intersection | null = raycast ( bounds ) ;
210+ if ( intersection !== null && intersection . dist < minDist ) {
211+ minDist = intersection . dist ;
212+ nearest = { x : intersection . x , y : intersection . y } ;
213+ }
214+
215+ return minDist === Infinity ? 0 : minDist ; // Closest intersection point
216+ }
146217
147- for ( let i = 0 ; i < numVertices ; i ++ ) {
148- const x1 = polygon [ i ] . x , y1 = polygon [ i ] . y ;
149- const x2 = polygon [ ( i + 1 ) % numVertices ] . x , y2 = polygon [ ( i + 1 ) % numVertices ] . y ;
218+ function raycast ( polygon : Polygon ) : Intersection | null {
219+ let minDist = Infinity ;
220+ let nearest : Intersection | null = null ;
150221
151- const intersection = getIntersection ( robot . x , robot . y , robot . dx + robot . x , robot . dy + robot . y , x1 , y1 , x2 , y2 ) ;
222+ for ( let i = 0 ; i < polygon . length ; i ++ ) {
223+ const x1 = polygon [ i ] . x , y1 = polygon [ i ] . y ;
224+ const x2 = polygon [ ( i + 1 ) % polygon . length ] . x , y2 = polygon [ ( i + 1 ) % polygon . length ] . y ;
152225
153- if ( intersection . collided && intersection . dist < minDist ) {
154- minDist = intersection . dist ;
155- nearest = { x : intersection . x , y : intersection . y } ;
156- }
157- }
158- }
226+ const topX = robot . x - robot . radius * robot . dy ;
227+ const topY = robot . y - robot . radius * robot . dx ;
159228
160- // if no collisions with obstacles, check the outer bounds of map
161- if ( nearest === null ) {
162- for ( let i = 0 ; i < bounds . length ; i ++ ) {
163- const x1 = bounds [ i ] . x , y1 = bounds [ i ] . y ;
164- const x2 = bounds [ ( i + 1 ) % bounds . length ] . x , y2 = bounds [ ( i + 1 ) % bounds . length ] . y ;
229+ const bottomX = robot . x + robot . radius * robot . dy ;
230+ const bottomY = robot . y + robot . radius * robot . dx ;
165231
166- const intersection = getIntersection ( robot . x , robot . y , robot . dx + robot . x , robot . dy + robot . y , x1 , y1 , x2 , y2 ) ;
232+ const raycast_sources : Point [ ] = [
233+ { x : robot . x , y : robot . y } ,
234+ { x : topX , y : topY } ,
235+ { x : bottomX , y : bottomY }
236+ ]
167237
168- if ( intersection . collided && intersection . dist < minDist ) {
238+ for ( const source of raycast_sources ) {
239+ const intersection = getIntersection ( source . x , source . y , robot . dx + source . x , robot . dy + source . y , x1 , y1 , x2 , y2 ) ;
240+ if ( intersection !== null && intersection . dist < minDist ) {
169241 minDist = intersection . dist ;
170- nearest = { x : intersection . x , y : intersection . y } ;
242+ nearest = intersection ;
171243 }
172244 }
173245 }
174-
175- return nearest ; // Closest intersection point
246+
247+ return nearest ;
176248}
177249
178250// Determine if a ray and a line segment intersect, and if so, determine the collision point
179- function getIntersection ( x1 , y1 , x2 , y2 , x3 , y3 , x4 , y4 ) {
251+ function getIntersection ( x1 , y1 , x2 , y2 , x3 , y3 , x4 , y4 ) : Intersection | null {
180252 const denom = ( ( x2 - x1 ) * ( y4 - y3 ) - ( y2 - y1 ) * ( x4 - x3 ) ) ;
181253 let r ;
182254 let s ;
183255 let x ;
184256 let y ;
185257 let b = false ;
186258
187- // If lines not collinear or parallel
188- if ( denom != 0 ) {
189- // Intersection in ray "local" coordinates
190- r = ( ( ( y1 - y3 ) * ( x4 - x3 ) ) - ( x1 - x3 ) * ( y4 - y3 ) ) / denom ;
191-
192- // Intersection in segment "local" coordinates
193- s = ( ( ( y1 - y3 ) * ( x2 - x1 ) ) - ( x1 - x3 ) * ( y2 - y1 ) ) / denom ;
194-
195- // The algorithm gives the intersection of two infinite lines, determine if it lies on the side that the ray is defined on
196- if ( r >= 0 ) {
197- // If point along the line segment
198- if ( s >= 0 && s <= 1 ) {
199- b = true ;
200- // Get point coordinates (offset by r local units from start of ray)
201- x = x1 + r * ( x2 - x1 ) ;
202- y = y1 + r * ( y2 - y1 ) ;
203- }
259+ // If lines are collinear or parallel
260+ if ( denom === 0 ) return null ;
261+
262+ // Intersection in ray "local" coordinates
263+ r = ( ( ( y1 - y3 ) * ( x4 - x3 ) ) - ( x1 - x3 ) * ( y4 - y3 ) ) / denom ;
264+
265+ // Intersection in segment "local" coordinates
266+ s = ( ( ( y1 - y3 ) * ( x2 - x1 ) ) - ( x1 - x3 ) * ( y2 - y1 ) ) / denom ;
267+
268+ // The algorithm gives the intersection of two infinite lines, determine if it lies on the side that the ray is defined on
269+ if ( r >= 0 ) {
270+ // If point along the line segment
271+ if ( s >= 0 && s <= 1 ) {
272+ b = true ;
273+ // Get point coordinates (offset by r local units from start of ray)
274+ x = x1 + r * ( x2 - x1 ) ;
275+ y = y1 + r * ( y2 - y1 ) ;
204276 }
205277 }
206- const p = { collided : b , x : x , y : y , dist : r } ;
207- return p ;
278+
279+ if ( ! b ) return null
280+
281+ return { x : x , y : y , dist : r }
208282}
209283
210284function alrCollided ( ) {
211285 return ! stateData . success ;
212286}
287+
288+ // debug
289+ function logCoordinates ( ) {
290+ stateData . messages . push ( `x: ${ robot . x } , y: ${ robot . y } , dx: ${ robot . dx } , dy: ${ robot . dy } ` )
291+ }
0 commit comments