Reputation: 463
I'm currently learning Common Lisp and, as part of the process, am trying to implement a generic tic-tac-toe game where the board can be any odd numbered size (so there's a center square). I got to where I'm checking for winners and am working on this function to check if a row or column have a winner.
(defun straight-winner-p (board start size)
(let ((row-player (aref board start 0))
(row-count 0)
(col-player (aref board 0 start))
(col-count 0))
(loop for step from 0 to (- size 1) do
(if (equal
(aref board start step)
row-player)
(incf row-count))
(if (equal
(aref board step start)
col-player)
(incf col-count))
)
(format t "row ~a, col ~a~%" row-count col-count)))
The format call would eventually be replaced with a check if the player is nil and count equals size. Anyway, I wanted to replace the two ifs with a macro. So, it would be something like
(check row start step)
And the macro would generate the if statement
(if (equal
(aref board start step)
row-player)
(incf row-count))
Then call the same macro with (check col step start). I can't seem to get the macro to generate row-count and row-player from row. How would you do that?
Upvotes: 2
Views: 338
Reputation: 48775
How about using the functionality in the loop macro when you already use the loop macro?:
(defun straight-winner-p (board start size)
(loop :with row-player := (aref board start 0)
:and col-player := (aref board 0 start)
:for step :below size
:count (equal (aref board start step) row-player) :into row-count
:count (equal (aref board step start) col-player) :into col-count
:finally (format t "row ~a, col ~a~%" row-count col-count)
(return (or (= row-count size) (= col-count size)))))
How you do what you want:
(defmacro check (prefix start step)
(let ((player (intern (concatenate 'string (string prefix) (string '-player)) (symbol-package prefix)))
(count (intern (concatenate 'string (string prefix) (string '-count)) (symbol-package prefix))))
`(when (equal (aref board ,start ,step) ,player)
(incf ,count))))
While special care has been taken in case the macro and your code ends up in different packages and use the package of the provided symbol it will not work if the files are reade with different reader settings. If you compile one but not the other it might not work.
Upvotes: 4