diff --git a/doc/api.org b/doc/api.org index cd7dec3..25eb9a0 100644 --- a/doc/api.org +++ b/doc/api.org @@ -22,8 +22,8 @@ "syn": 1, "game-id": 1, "game-over": false, - "snake": [(1,2),(1,3)], - "food": [(6,7)] + "snake": [[1,2],[1,3]], + "food": [[6,7]] } #+END_SRC Note that, syn entry is used to keep packet ordering consistent and detecting packet inversion on the network. Thus, @@ -46,8 +46,8 @@ "syn": 2, "game-id": 1, "game-over": false, - "snake": [(0,2),(1,2)], - "food": [(6,7)] + "snake": [[0,2],[1,2]], + "food": [[6,7]] } #+END_SRC *** Refresh Screen @@ -67,8 +67,8 @@ "syn": 3, "game-id": 1, "game-over": false, - "snake": [(1,2),(0,2)], - "food": [(6,7)] + "snake": [[1,2],[0,2]], + "food": [[6,7]] } #+END_SRC *** End Game @@ -79,8 +79,8 @@ "syn": null, "game-id": 1, "game-over": true, - "snake": [(0,2),(1,2)], - "food": [(6,7)] + "snake": [[0,2],[1,2]], + "food": [[6,7]] } #+END_SRC - No reply is expected from the client and server will be in charge to free local memory. Note that syn=null. diff --git a/doc/api.pdf b/doc/api.pdf index a02a350..b2b5cc9 100644 Binary files a/doc/api.pdf and b/doc/api.pdf differ diff --git a/server/api/api.lisp b/server/api/api.lisp index 186076c..3bd7e49 100644 --- a/server/api/api.lisp +++ b/server/api/api.lisp @@ -4,6 +4,68 @@ (defclass api () ((gm - :initform (make-instance 'game-manager)))) + :initform (make-instance 'game-manager)) + (games-syn + :initform '()))) + + +(defmethod create-syn ((api api) game-id &optional (initial-value 0)) + (unless (eq nil (get-syn api game-id)) (error "This game ~a already have a syn !" game-id)) + (with-slots (games-syn) api + (push (list :game-id game-id :syn initial-value) games-syn) + initial-value)) + +(defmethod refresh-syn ((api api) game-id) + (with-slots (games-syn) api + (incf (getf (first (remove-if-not #'(lambda (entry) (eql game-id (getf entry :game-id))) games-syn)) :syn)))) + +(defmethod get-syn ((api api) game-id) + (with-slots (games-syn) api + (getf (first (remove-if-not #'(lambda (entry) (eql game-id (getf entry :game-id))) games-syn)) :syn))) + + + +;;; TODO: Handle errors (valid json etc..) +(defun parse-request (request) + (flet ((normalizer (key) + (string-upcase key))) + (let ((p-request (parse request :normalize-all t :keyword-normalizer #'normalizer ))) + p-request))) + +(defmethod handle-new-game ((api api) data) + (with-slots (gm) api + (let* ((game-id (create-game gm)) + (game-syn (create-syn api game-id 1))) ; Create syn with 1 (since first packet already receive) + (let ((game-dump (dump gm game-id))) + (setf (getf game-dump :game-over) :null) ; Define nil as null (for json) + (to-json + (append (list :type "state" :syn game-syn) game-dump)))))) + +;;; TODO: RETURN JSON !!!! +(defmethod handle-update ((api api) data) + (with-slots (gm) api + (let* ((dir (getf data :direction)) + (game-id (getf data :game-id)) + (game (get-game gm game-id))) + (cond + ((equal dir "up") (setf dir :up)) + ((equal dir "down") (setf dir :down)) + ((equal dir "left") (setf dir :left)) + ((equal dir "right") (setf dir :right)) + (t (setf dir nil))) + (if dir + (refresh game :dir dir) + (refresh game))))) + + + +(defmethod handle-request ((api api) request) + (let* ((data (parse-request request)) + (type (getf data :type))) + (cond + ((equal type "new-game") (handle-new-game api data)) + ((equal type "update") (handle-update api data)) + (t (format t "Unknow type"))))) + diff --git a/server/api/game-manager.lisp b/server/api/game-manager.lisp index e5355d1..751aae1 100644 --- a/server/api/game-manager.lisp +++ b/server/api/game-manager.lisp @@ -24,6 +24,14 @@ (with-slots (games) gm (setf games (remove-if #'(lambda (entry) (eql game-id (getf entry :id))) games)))) +(defgeneric dump (g game-id) + (:documentation "Dump a game in the Game manager. Return a plist.")) + +(defmethod dump ((g game-manager) game-id) + (with-slots (games) g + (append (list :id game-id) (remote-snake-server-game:dump (get-game g game-id))))) + + (defmethod get-game ((gm game-manager) game-id) (with-slots (games) gm (let ((game (remove-if-not #'(lambda (entry) (eql game-id (getf entry :id))) games))) diff --git a/server/game/game.lisp b/server/game/game.lisp index f909f36..9ea2029 100644 --- a/server/game/game.lisp +++ b/server/game/game.lisp @@ -39,6 +39,13 @@ (format t "~%Direction: ~a" dir) (format t "~%Food: ~a" food))) +(defgeneric dump (g) + (:documentation "Dump a game. Return a plist.")) + +(defmethod dump ((g game)) + (with-slots (snake food game-over) g + (list :snake snake :food food :game-over game-over))) + ;;; Note that there is no waranty that nb food are added (ex: if food position collide with snake position) (defgeneric add-food (g nb) (:documentation "Add food on the game grid.")) diff --git a/server/packages.lisp b/server/packages.lisp index 788083d..3f3788d 100644 --- a/server/packages.lisp +++ b/server/packages.lisp @@ -2,10 +2,13 @@ (:nicknames :rsg) (:use :common-lisp) (:export - #:game)) + #:game + #:dump + #:refresh)) (defpackage :remote-snake-server-api (:nicknames :rsapi) - (:use :common-lisp :jonathan) + (:use :common-lisp :jonathan :remote-snake-server-game) + (:shadow #:dump) ; Because game-manager also has a dump method (:export #:api))