anchor.diff:     (owner nil a)
      (armies nil a)))
   
  +(defclass* game-map ()
  +  ((territories (error "Debe especificar los territorios") ir)
  +   (frontiers (error "Debe especificar las fronteras") ir)))
  +
   (defclass* player ()
     ((name (error "Debe ingresar el nombre del jugador") ir)))
   
   (defclass* game ()
  -  ((territories (error "Debe especificar los territorios") ir)
  -   (frontiers (error "Debe especificar las fronteras") ir)
  +  ((game-map (error "Debe especificar el mapa") ir)
      (players (make-hash-table) r)))
   
   (defgeneric read-map (file &key)
  
positive.code:                               :extra-armies extra-armies))
           (dolist (frontierkey terr-frontiers)
             (add-edge-between-vertexes frontiers key frontierkey))))
       (make-instance 'game :territories territories :frontiers frontiers))) 
  
    (:method ((path pathname) &key)
     (with-open-file (file path) (read-map file))) 
  
    (:method ((path string) &key)
     (read-map
       (parse-namestring
         (if (probe-file path)
           path
           (format nil "~a.map" path)))))) 
  
  (defun territory (game territory-key)
    (gethash territory-key (territories game)))
  
  (defun player (game player-key)
    (gethash player-key (players game)))
  
  (defun territory-keys (game)
    (keys (territories game)))
  
  (defun player-keys (game)
    (keys (players game)))
  
  (defun territories-connected-p (game origin-key destination-key)
    (let ((graph (frontiers game)))
      (vertices-share-edge-p
        (find-vertex graph origin-key)
        (find-vertex graph destination-key))))
  
  (defun add-player (game name &optional (handle name))
    (setf (gethash handle (players game)) (make-instance 'player :name name)))
  
  (defun initialize-territory (territory player)
    (setf (owner territory) player)
    (setf (armies territory) 1))
  
  (defun shuffle-territories (game)
    (unless (territory-keys game)
      (error "El juego debe tener territorios"))
    (unless (player-keys game)
      (error "El juego debe tener jugadores"))
    (let* ((territories (shuffle (territory-keys game)))
          (players (shuffle (player-keys game)))
          (share (floor (/ (length territories) (length players)))))
      (dolist (player players)
        (loop repeat share
              for territory = (first territories) do
              (initialize-territory (territory game territory) (player game player))
              (pop territories)))
      (loop while territories
            for territory = (first territories)
            for player = (first players) do
            (initialize-territory (territory game territory) (player game player))
            (pop players)
            (pop territories))))
  
  (defgeneric move-armies (game from to amount &key))
  
  (defmethod move-armies (game origin-key destination-key amount &key)
    (let ((origin (territory game origin-key))
          (destination (territory game destination-key)))
      (unless (territories-connected-p game origin-key destination-key)
        (error "Los territorios deben estar conectados"))
      (unless (eq (owner origin) (owner destination))
        (error "Los territorios tienen que tener el mismo dueño"))
      (unless (> amount 0)
        (error "No se pueden mover 0 o menos ejércitos"))
      (unless (> (armies origin) amount)
        (error "No hay suficientes ejércitos")) 
      (decf (armies origin) amount) 
      (incf (armies destination) amount)))
  
  (defgeneric place-armies (game where amount &key))
  
  (defmethod place-armies (game territory-key amount &key)
    (let ((territory (territory game territory-key)))
      (unless (> amount 0)
        (error "No se pueden poner 0 o menos ejércitos"))
      (incf (armies territory) amount)))
  
  (defgeneric attack (game from to &key))
  
  (defmethod attack (game origin-key destination-key &key)
    (symbol-macrolet
      ((origin (territory game origin-key))
       (destination (territory game destination-key))
       (attackers (armies origin))
       (defenders (armies destination)))
      (unless (territories-connected-p game origin-key destination-key)
        (error "Los territorios deben estar conectados"))
      (unless (> attackers 2)
        (error "No se puede atacar teniendo 2 o menos ejércitos"))
      (when (equal (owner destination) (owner origin))
        (error "Un jugador no se puede atacar a sí mismo"))
      (let ((decrement (1+ (min defenders (- attackers 2)))))
        (decf attackers (random decrement))
        (decf defenders (random decrement))
        (when (= defenders 0)
          (setf (owner destination) (owner origin))
          (move-armies game origin-key destination-key 1)))
      (eq (owner origin) (owner destination))))
  
  (defun print-game (game)
    (format t "~&Jugadores:")
    (loop for v being the hash-values in (players game) do
          (format t "~&~t~a" (name v)))
    (format t "~&Territorios:")
    (loop for v being the hash-values in (territories game) do
          (format t "~&~a~&~tDueño:~t~a~&~tEjércitos:~a"
                  (name v)
                  (if (owner v) (name (owner v)) "Ninguno")
                  (armies v))))
  
  
negative.code:    (loop for m from (length list) downto 1
           for l = list then (remove v l :count 1)
           for v = (elt l (random m))
           collecting v))
  
  (defclass* territory ()
    ((name (error "Debe ingresar el nombre del territorio") ir)
  