Reputation: 1
I been studing in Scheme for weeks and I ran into a problem that I couldn't solve. I can't find a way to solved it. Here is the problem:
Figure 1
shows an example path, which has a grid layout. In the grid, black cells are simply walls, which
are basically obstacles for you. You can move among the white cells and you cannot pass the boundaries
of the grid. In each path, the starting location will be the square of [0,0]. Additionally, there is also one
white cell labeled with F. This label shows the finish square of the path. So, your aim is to find the
movements from the starting location to the finish location. To this end, you can move in 4 directions;
up, down, left, right. These 4 directions will be represented by characters U, D, L, and R, respectively.
The solution for the path shown in Figure 1 is "D D R R R R D D", which means move down 2 times, then move right 4 times and move down 2 times. The path is not a maze! It is a simple one way road and It has only one solution: there is always one possible next square for each move.
TASKS In Scheme, a path will be represented in the form of a linked-list. Figure 2 shows how the path in Figure 1 is represented in terms of a linked list in Scheme. Starting cell [0,0] has the letter S, the finishing cell has the letter F and empty cells have the letter E. The walls have the letter - (minus)
The following function "buildPath" on the left is given for you which takes a list of lists and creates a path (grid) using the lists. You can use this function to create different paths in order to test your code. On the right the code shows how the path in Figure 2 is created.
Task 1: Define two functions "getHeight" and "getWidth" which takes a path as an input and returns the height and the width of the path.
(getHeight sample-path) → should return 5
(getWidth sample-path) → should return 5
Task 2: Define a function "getLetter" which takes a path, a row number and a column number. Then it returns the letter from the path on the corresponding location [row, column]
(getLetter sample-path 0 0) → should return S
(getLetter sample-path 1 0) → should return E
(getLetter sample-path 1 1) → should return -
(getLetter sample-path 4 4) → should return F
Task 3: Define a function "solvePath" which takes a path and returns the solution for the path.
(solvePath sample-path) → should return (D D R R R R D D)
My codes are:
#lang scheme
(define (buildPath rows)
(cond
((null? rows) null)
(else (cons (buildPath (cdr rows))
(car rows)))))
(define sample-path (buildPath
'(("S" "-" "-" "-" "-")
("E" "-" "-" "-" "-")
("E" "E" "E" "E" "E")
("-" "-" "-" "-" "E")
("-" "-" "-" "-" "F"))))
(define (getHeight mylist)
(define count 0)
(define (height mylist)
(cond
((null? mylist) null)
(else
(if (null? (filter filter-out (cdr mylist))) null (set! count (+ 1 count)))
(height (car mylist))
)))
(height mylist) count)
(define (getWidth mylist)
(define count 0)
(define (width mylist)
(cond
((null? mylist) null)
(else
(define list-length (length(filter filter-out (cdr mylist))))
(if (> list-length count) (set! count (+ 0 list-length)) null)
(width (car mylist))
)))
(width mylist) count)
(define (getLetter mylist rownum columnum)
(define count 0)
(define (letter mylist)
(cond
((eq? count rownum) (list-ref (cdr mylist) columnum))
(else
(set! count (+ 1 count))
(letter (car mylist))
)))
(letter mylist))
(define (filter-out x)
(if (eq? x "-") #f #t))
I solved Task 1 and Task 2 but stuck at Task 3. What logic can i use?
Upvotes: 0
Views: 576
Reputation: 820
This answer shows one way to approach "Task 3" by starting
with simple examples (as check-expect
tests) to direct
development.
First, Tasks 1 and 2, with tests as specified:
#lang scheme
(require test-engine/racket-tests)
(define (buildPath rows)
(cond
[(null? rows) null ]
[else (cons (buildPath (cdr rows))
(car rows))]))
(define sample-path (buildPath
'(("S" "-" "-" "-" "-")
("E" "-" "-" "-" "-")
("E" "E" "E" "E" "E")
("-" "-" "-" "-" "E")
("-" "-" "-" "-" "F"))))
(define (getWidth path) ;; Path -> Natural
;; produce number of columns in path
(length (cdr path)))
(define (getHeight path) ;; Path -> Natural
;; produce number of rows in path
(cond
[(null? (car path)) 1 ]
[else (+ 1 (getHeight (car path))) ]))
(check-expect (getWidth sample-path) 5)
(check-expect (getHeight sample-path) 5)
(define (getLetter path row col) ;; Path Natural Natural -> String
;; produce the string at [row,col] of path
(define (letter path count)
(cond
[(= count row) (list-ref (cdr path) col) ]
[else (letter (car path) (+ 1 count)) ]))
(letter path 0))
(check-expect (getLetter sample-path 0 0) "S")
(check-expect (getLetter sample-path 1 0) "E")
(check-expect (getLetter sample-path 1 1) "-")
(check-expect (getLetter sample-path 4 4) "F")
(test)
Welcome to DrRacket, version 8.4 [cs].
Language: scheme, with debugging.
All 6 tests passed!
>
For Task 3, start with the simplest possible grid, write tests, and construct corresponding functions:
(define minimal-path (buildPath '(("S" "F"))))
(check-expect (step minimal-path 1 (list)) '())
(check-expect (step minimal-path 0 (list)) '(R))
(define (step path col result) ;; Path Natural ListOfSymbol -> ListOfSymbol
;; produce step directions (minimal-path only)
(cond
[(string=? (getLetter path 0 col) "F") result ]
[(string=? (getLetter path 0 (+ col 1)) "F")
(step path (+ col 1) (append result '(R))) ]))
Extend step
to handle the next simplest example
(run after every change to check that all tests pass -
some may need adjustment as functions develop):
(define short-path (buildPath '(("S" "E" "E" "F"))))
(check-expect (step short-path 0 0 (list)) '(R R R))
(define (step path row col result) ;; Path Natural Natural ListOfSymbol -> ListOfSymbol
;; produce step directions (short-path only)
(cond
[(string=? (getLetter path row col) "F") result ]
[(or (string=? (getLetter path 0 (+ col 1)) "E")
(string=? (getLetter path 0 (+ col 1)) "F"))
(step path row (+ col 1) (append result '(R))) ]))
And then (extending getLetter
to produce an appropriate value for row/col outside the boundary of the grid):
(define corner-path (buildPath '(("S" "E" "E")
("-" "-" "F"))))
(check-expect (step corner-path 0 0 (list)) '(R R D))
(define (getLetter path row col) ;; Path Natural Natural -> String
;; produce the string at [row,col] of path, "-" if outside grid
(define (letter path count)
(cond
[(= count row) (list-ref (cdr path) col) ]
[else (letter (car path) (+ 1 count)) ]))
(if (or (negative? row) (>= row (getHeight path))
(negative? col) (>= col (getWidth path)))
"-"
(letter path 0)))
(define (step path row col result) ;; Path Natural Natural ListOfSymbol -> ListOfSymbol
;; produce path from [0,0] to "F"
(cond
[(string=? (getLetter path row col) "F") result ]
[(or (string=? (getLetter path row (+ col 1)) "F")
(string=? (getLetter path row (+ col 1)) "E"))
(step path row (+ col 1) (append result '(R))) ]
[(or (string=? (getLetter path (+ row 1) col) "F")
(string=? (getLetter path (+ row 1) col) "E"))
(step path (+ row 1) col (append result '(D))) ]))
This version works for the sample-path
provided in the question:
(define (solvePath path) ;; Path -> ListOfSymbol
;; produce path from [0,0] to "F"
(step path 0 0 (list)))
(check-expect (solvePath sample-path) '(D D R R R R D D))
Welcome to DrRacket, version 8.4 [cs].
Language: scheme, with debugging.
All 11 tests passed!
>
step
can now be extended for paths with "left" and "up" directions, with an example:
(define (step path row col result) ;; Path Natural Natural ListOfSymbol -> ListOfSymbol
;; produce path from [0,0] to "F"
(define (step? n-row n-col) ;; Natural Natural -> Boolean
;; is [n-row,n-col] a possible next step on path?
(or (string=? (getLetter path n-row n-col) "F")
(string=? (getLetter path n-row n-col) "E")))
(cond
[(string=? (getLetter path row col) "F") result ]
[(step? row (+ col 1))
(step path row (+ col 1) (append result '(R))) ]
[(step? (+ row 1) col)
(step path (+ row 1) col (append result '(D))) ]
[(step? row (- col 1))
(step path row (- col 1) (append result '(L))) ]
[(step? (- row 1) col)
(step path (- row 1) col (append result '(U))) ]))
(define twisty-path (buildPath
'(("S" "-" "E" "E" "E")
("E" "E" "E" "-" "E")
("-" "-" "-" "E" "E")
("-" "E" "E" "E" "-")
("-" "F" "-" "-" "-"))))
But (solvePath twisty-path)
results in the step
above looping (oscillating between right and left).
One way to fix this is to add arguments to step
and step?
to detect and avoid it:
(define (step path row col result back) ;; Path Natural Natural ListOfSymbol -> ListOfSymbol
;; produce path from [0,0] to "F"
(define (step? n-row n-col direction) ;; Natural Natural Symbol -> Boolean
;; is [n-row,n-col] a possible next step on path?
(and (not (eq? direction back))
(or (string=? (getLetter path n-row n-col) "F")
(string=? (getLetter path n-row n-col) "E"))))
(cond
[(string=? (getLetter path row col) "F") result ]
[(step? row (+ col 1) 'R)
(step path row (+ col 1) (append result '(R)) 'L) ]
[(step? (+ row 1) col 'D)
(step path (+ row 1) col (append result '(D)) 'U) ]
[(step? row (- col 1) 'L)
(step path row (- col 1) (append result '(L)) 'R) ]
[(step? (- row 1) col 'U)
(step path (- row 1) col (append result '(U)) 'D) ]))
(define (solvePath path) ;; Path -> ListOfSymbol
;; produce path from [0,0] to "F"
(step path 0 0 (list) '-))
(check-expect (solvePath twisty-path) '(D R R U R R D D L D L L D))
(test)
Upvotes: 1