1

Currently, I am struggling with figuring out a function that can determine if a point is in a square or not given the side length and top left corner of the square.

; tl is a Posn, giving the top-left corner of the square
; side is a Number, giving the side length of the square
(define-struct SQ (tl side))
(define z (make-SQ tl side))
(define x (+ (posn-x SQ-tl z) (SQ-side z)))
(define y (+ (posn-y SQ-tl z) (SQ-side z)))
(define a (make-posn x y))
; Posn, SQ -> Boolean
(define (point-in-square? P S)  (and (<= (posn-x P) (posn-x a) S)
                                     (>= (posn-x P) (posn-x (SQ-tl z)) S)
                                     (<= (posn-y P) (posn-y a) S)
                                     (>= (posn-y P) (posn-y (SQ-tl z)) S)))

I receive the error tl: undefined; cannot reference undefined identifier How would I be able to resolve this error?

  • `(define z (make-SQ tl side))` -- code is calling `make-SQ` on some arguments: what is the value of `tl`? What is the value of `side`? – ad absurdum Oct 21 '21 at 01:53
  • ```tl``` refers to the SQ's ```tl``` and ```side``` is the SQ's ```side``` – Lucky Rabbit Oct 21 '21 at 02:08
  • You are mistaken, and this is the source of the error message which I was trying to hint at. In the call `(make-SQ tl side)` there is an attempt to evaluate `tl`, and the resulting value should be used to construct an `SQ` structure. But, `tl` has not been given any value yet! If you fix this by doing something like `(define my-posn (make-posn 4 2))`, then call `(make-SQ my-posn side)`, you will have fixed the problem for `tl`, but not for `side`. You must provide appropriate _values_ to `make-SQ` in order to construct an `SQ` structure. – ad absurdum Oct 21 '21 at 02:29
  • Yes, if `my-number` evaluates to an appropriate value. Presumably an `SQ` side is just a number representing the side-length; and it looks like `posn` is a struct with numbers for `x` and `y` fields. So, you could do something like `(define my-SQ (make-SQ (make-posn 4 2) 1))` to create an `SQ` with side-length 1 positioned at (4, 2). – ad absurdum Oct 21 '21 at 02:39
  • The main issue I think the code would have is that the square moves randomly per test case. how would I be able to use this without having to use specific numbers(I could be overthinking it tho). – Lucky Rabbit Oct 21 '21 at 02:45
  • The `point-in-square` procedure requires an actual square and an actual point to do its work, i.e., to find out if the point is in the square. But you don't need that to write the procedure (as you have). You only need a concrete square and a concrete point to _use_ the function (or to test it). I initially assumed that the only reason for defining the square `z` was so that you could test the `point-in-square` procedure. You can give any square and any point to your procedure, though. – ad absurdum Oct 21 '21 at 02:48
  • Looking again, there seem to be some problems with you definition of `point-in-square`, too. I may write an answer soon if the hints already given don't help you out. – ad absurdum Oct 21 '21 at 02:51
  • yea I beginning to see some flaws with my code, will also look at it over – Lucky Rabbit Oct 21 '21 at 03:10
  • As you are doing that, consider that everything that `point-in-square?` needs to know is in the point `P` and the square `S` which are passed as arguments; there is no need for `a` or `z` here. – ad absurdum Oct 21 '21 at 03:12
  • I tried doing this and it passes most of the test cases, however some like ```P=(4, 3), S=[(3, 0), 4] produced False, correct is True: fails``` failed – Lucky Rabbit Oct 21 '21 at 03:57
  • here is the code: https://pastebin.com/EShBp7uq – Lucky Rabbit Oct 21 '21 at 04:02
  • Check your parentheses where you are adding in the third test: `(<= (posn-y P) (+ (posn-y (SQ-tl S))) (SQ-side S))` – ad absurdum Oct 21 '21 at 04:05
  • Yes that did it XD. Thank you so much – Lucky Rabbit Oct 21 '21 at 04:08
  • I'm glad that helped; I posted an answer to show a slightly different solution that may be a bit easier to read by taking the structure accesses out of the comparisons and using meaningful names. – ad absurdum Oct 21 '21 at 04:29

1 Answers1

1

The initial problems resulted in errors such as: tl: undefined; cannot reference undefined identifier. In the call to construct a square z, the constructor make-SQ was called with arguments tl and side; but no values had been assigned to these identifiers yet. It seems that OP was using them because those were the slot names; constructors need appropriate values to assign to slots. The solution here was just to recognize that construction of an actual SQ instance requires concrete values.

Getting over the first hurdle made it clear that something was amiss with the definition of the point-in-square? predicate. The definition was attempting to use the globally defined z square and a point. But this procedure also takes P and S arguments, which are a point and a square, respectively. This is all the information that is needed to solve the problem.

Having worked through the issues with OP in the comments, OP has solved the problems to make the code work. Here is an alternate solution that uses let* to make the code a little nicer to read and think about:

#lang racket

(define-struct posn (x y))

(define-struct SQ (tl side))

(define (point-in-square? P S)
  (let* ((top-left (SQ-tl S))
         (side-length (SQ-side S))
         (left (posn-x top-left))
         (right (+ left side-length))
         (top (posn-y top-left))
         (bottom (+ top side-length)))
    (and (<= (posn-x P) right)
         (>= (posn-x P) left)
         (<= (posn-y P) bottom)
         (>= (posn-y P) top))))

And a sample REPL interaction:

point-in-square.rkt> (define test-square (make-SQ (make-posn 4 2) 1))
point-in-square.rkt> (define p1 (make-posn 5 3))  ; in square
point-in-square.rkt> (define p2 (make-posn 5 2))  ; on edge of square
point-in-square.rkt> (define p3 (make-posn 5 1))  ; not in square
point-in-square.rkt> (point-in-square? p1 test-square)
#t
point-in-square.rkt> (point-in-square? p2 test-square)
#t
point-in-square.rkt> (point-in-square? p3 test-square)
#f

Note that let is useful for binding values to be used in a computation to meaningful names; in this case, let* is handy because it lets us use values which were previously bound in the same let* form in subsequent bindings. An alternative would be to nest let forms so that inner lets could use outer bindings.

ad absurdum
  • 19,498
  • 5
  • 37
  • 60