Search code examples
lispcommon-lisplispworks

validate moves and move pieces on the board in Lisp


I have this board [10,10] for this project below and I can't move the piece on the board

this question is part of the other questions about Lisp, you can see on my profile

(defun board ()
  "T in position x=0 and y=0"
  '(
    (T 25 54 89 21 8 36 14 41 96) 
    (78 47 56 23 5 NIL 13 12 26 60) 
    (0 27 17 83 34 93 74 52 45 80) 
    (69 9 77 95 55 39 91 73 57 30) 
    (24 15 22 86 1 11 68 79 76 72) 
    (81 48 32 2 64 16 50 37 29 71) 
    (99 51 6 18 53 28 7 63 10 88) 
    (59 42 46 85 90 75 87 43 20 31) 
    (3 61 58 44 65 82 19 4 35 62) 
    (33 70 84 40 66 38 92 67 98 97)
    )
)

not the same but similar here the rows begin at 1 but in project is start by 0

enter image description here

and this function to print the board

(defun print-board (board)
    (format T "~%")
    (mapcar (lambda (x) (format T " ~A ~%" x)) board)
    (format nil ""))

I have 8 movements implemented but I only put 4 examples for the question not to get too much code

(defun UP-LEFT (x y board)
  "Function that receives 2 indexes and board, validate movement and move piece up and left"
    (cond
        ((equal (validate-movements (- x 1) (- y 2) board) 0) 
         (move-piece x y -1 -2 board))
        (T nil)))

(defun UP-RIGHT (x y board)
  "receive 2 indexes and board, validate movement and move piece up and right"
    (cond
        ((equal (validate-movements (+ x 1) (- y 2) board) 0) 
         (move-piece x y 1 -2 board))
        (T nil)))

(defun LEFT-DOWN (x y board)
   "Function that receives 2 indexes and board, validate movement and move piece left and down"
    (cond
        ((equal (validate-movements (- x 2) (+ y 1) board) 0)
         (move-piece x y -2 1 board))
        (T nil)))

(defun LEFT-UP (x y board)
   "Function that receives 2 indexes and board, validate movement and move piece left and up"
    (cond
        ((equal (validate-movements (- x 2) (- y 1) board) 0) 
         (move-piece x y -2 -1 board))
        (T nil)))

(defun DOWN-RIGHT (x y board)
   "Function that receives 2 indexes and board, validate movement and move piece down and right"
    (cond
        ((equal (validate-movements (+ x 1) (+ y 2) board) 0)
         (move-piece x y 1 2 board))
        (T nil)))

my doubt is in this move piece in board in axis (x,y)

(defun move-piece (x y dx dy board)
 "Function that receives two indexes and board to move the piece on the board"
  (mapcar 
    (lambda (L) 
        (cond
            ((atom L) L)
            ((and 
             (equal (nth 0 L) x) 
             (equal (nth 1 L) y)) 
             (list (+ (nth 0 L) dx) (+ (nth 1 L) dy) (nth 2 L) 
                   (nth 3 L) (nth 4 L) (nth 5 L) (nth 6 L) 
                   (nth 7 L) (nth 8 L) (nth 9 L)))
    (T L))) board))

and this function to validate movements

(defun validate-movements (x y board)   
 "Function that receives two indexes and board to validate movement"
  (cond 
      ((and 
           ;; validation of rows and columns
           (>= x 0) 
           (>= y 0) 
           (<= x 9) 
           (<= y 9) 
           (= (apply '+ (mapcar (lambda (L) 
                                       (cond 
                                           ((atom L) 0)
                                           ((or (not(equal (nth 0 L ) x)) (not (equal (nth 1 L) y))) 0) 
                                           (T 1))) board)) 0)) 0)
    (T nil )))

when I try to test the movements https://ideone.com/jaeCLu it's not move, because don´t return nothing and show nothing

what I´m doing wrong?


Solution

  • Let's take a look at the validation function. First, make sensible limebreaks: when a multiline form is closed, break the line.

    (defun validate-movements (x y board)
      "Function that receives two indexes and board to validate movement"
      (cond ((and
              ;; validation of rows and columns
              (>= x 0)
              (>= y 0)
              (<= x 9)
              (<= y 9)
              (= (apply '+
                        (mapcar (lambda (L)
                                  (cond ((atom L) 0)
                                        ((or (not (equal (nth 0 L ) x))
                                             (not (equal (nth 1 L) y)))
                                         0)
                                        (T 1)))
                                board))
                 0))
             0)
            (T nil )))
    

    A condition that has only two possible outcomes is better handled through if:

    (defun validate-movements (x y board)
      "Function that receives two indexes and board to validate movement"
      (if (and
           ;; validation of rows and columns
           (>= x 0)
           (>= y 0)
           (<= x 9)
           (<= y 9)
           (= (apply '+
                     (mapcar (lambda (L)
                               (cond ((atom L) 0)
                                     ((or (not (equal (nth 0 L ) x))
                                          (not (equal (nth 1 L) y)))
                                      0)
                                     (T 1)))
                             board))
              0))
          0
          nil))
    

    Comparators like <= can take more arguments:

    (defun validate-movements (x y board)
      "Function that receives two indexes and board to validate movement"
      (if (and (<= 0 x 9)
               (<= 0 y 9)
               (= (apply '+
                         (mapcar (lambda (L)
                                   (cond ((atom L) 0)
                                         ((or (not (equal (nth 0 L) x))
                                              (not (equal (nth 1 L) y)))
                                          0)
                                         (T 1)))
                                 board))
                  0))
          0
          nil))
    

    Since your board is a list of lists (one 10-element sublist per line), a line will never be an atom:

    (defun validate-movements (x y board)
      "Function that receives two indexes and board to validate movement"
      (if (and (<= 0 x 9)
               (<= 0 y 9)
               (= (apply '+
                         (mapcar (lambda (L)
                                   (cond ((or (not (equal (nth 0 L) x))
                                              (not (equal (nth 1 L) y)))
                                          0)
                                         (T 1)))
                                 board))
                  0))
          0
          nil))
    

    Again, a two-clause conditional is better an if:

    (defun validate-movements (x y board)
      "Function that receives two indexes and board to validate movement"
      (if (and (<= 0 x 9)
               (<= 0 y 9)
               (= (apply '+
                         (mapcar (lambda (L)
                                   (if (or (not (equal (nth 0 L) x))
                                           (not (equal (nth 1 L) y)))
                                       0
                                       1))
                                 board))
                  0))
          0
          nil))
    

    Now, I wanted to tell you how booleans are much easier to express logic with. However, that condition makes no sense to me: you seem to check that there is some line on the board that carries the x coordinate in its first field and the y coordinate in the second.

    Maybe you wanted to check that the target coordinate is empty?

    (defun target-valid-p (x y board)
      (and (<= 0 x 9)
           (<= 0 y 9)
           (null (nth x (nth y board)))))
    

    Next, the move function. Again, linebreaks:

    (defun move-piece (x y dx dy board)
      "Function that receives two indexes and board to move the piece on the board"
      (mapcar (lambda (L) 
                (cond
                  ((atom L) L)
                  ((and (equal (nth 0 L) x) 
                        (equal (nth 1 L) y)) 
                   (list (+ (nth 0 L) dx) (+ (nth 1 L) dy) (nth 2 L) 
                         (nth 3 L) (nth 4 L) (nth 5 L) (nth 6 L) 
                         (nth 7 L) (nth 8 L) (nth 9 L)))
                  (T L)))
              board))
    

    Your lines are never atoms:

    (defun move-piece (x y dx dy board)
      "Function that receives two indexes and board to move the piece on the board"
      (mapcar (lambda (L) 
                (cond
                  ((and (equal (nth 0 L) x) 
                        (equal (nth 1 L) y)) 
                   (list (+ (nth 0 L) dx) (+ (nth 1 L) dy) (nth 2 L) 
                         (nth 3 L) (nth 4 L) (nth 5 L) (nth 6 L) 
                         (nth 7 L) (nth 8 L) (nth 9 L)))
                  (T L)))
              board))
    

    Two-branch conditional is if:

    (defun move-piece (x y dx dy board)
      "Function that receives two indexes and board to move the piece on the board"
      (mapcar (lambda (L) 
                (if (and (equal (nth 0 L) x) 
                         (equal (nth 1 L) y)) 
                    (list (+ (nth 0 L) dx) (+ (nth 1 L) dy) (nth 2 L) 
                          (nth 3 L) (nth 4 L) (nth 5 L) (nth 6 L) 
                          (nth 7 L) (nth 8 L) (nth 9 L))
                    L))
              board))
    

    Use list* and nthcdr to update part of a list:

    (defun move-piece (x y dx dy board)
      "Function that receives two indexes and board to move the piece on the board"
      (mapcar (lambda (L) 
                (if (and (equal (nth 0 L) x) 
                         (equal (nth 1 L) y)) 
                    (list* (+ (nth 0 L) dx)
                           (+ (nth 1 L) dy)
                           (nthcdr 2 L))
                    L))
              board))
    

    Now it seems that you again just update the first two cells of the line. Maybe I didn't understand your data model, but I would have thought that you just want to update the cells at the given coordinates:

    (defun move-piece (x y dx dy board)
      (let ((new-board (copy-tree board))
            (new-x (+ x dx))
            (new-y (+ y dy))
            (piece (nth x (nth y board))))
        (setf (nth x (nth y new-board)) nil
              (nth new-x (nth new-y new-board)) piece)
        new-board))