Você está na página 1de 38

Chandigarh Engineering College, Landran Artificial inteligence

Experiment No.1

AIM: Write A Program for Depth First Search.

S/W Requirement: LispWorks IDE, Emacs Editor and SLIME.

;;; DEPTHFS.CL
;;; Depth-First Search.

;;; the graph to be searched represents roads in France.

;;; Create a hash table ADJACENCY-INFO to store the French


;;; roads data, and define the functions for entering and
;;; retrieving this info.
;;; A second hash table, PATH-PREDECESSOR-INFO, is used
;;; during the search to allow the eventual tracing of
;;; the path back from the goal to the starting node.
(let ((adjacency-info (make-hash-table :size 20))
(path-predecessor-info (make-hash-table :size 20)) )
(defun set-adj (x y)
(setf (gethash x adjacency-info) y) )
(defun get-adj (x)
(gethash x adjacency-info) )
(defun set-predecessor (x y)
(setf (gethash x path-predecessor-info) y) )
(defun get-predecessor (x)
(gethash x path-predecessor-info) )
)

;;; Establish BREST's list of neighbors as (RENNES), etc.


(set-adj 'brest '(rennes))
(set-adj 'rennes '(caen paris brest nantes))
(set-adj 'caen '(calais paris rennes))
(set-adj 'calais '(nancy paris caen))
(set-adj 'nancy '(strasbourg dijon paris calais))
(set-adj 'strasbourg '(dijon nancy))
(set-adj 'dijon '(strasbourg lyon paris nancy))
(set-adj 'lyon '(grenoble avignon limoges dijon))
(set-adj 'grenoble '(avignon lyon))
(set-adj 'avignon '(grenoble marseille montpellier lyon))
(set-adj 'marseille '(nice avignon))
(set-adj 'nice '(marseille))
(set-adj 'montpellier '(avignon toulouse))
(set-adj 'toulouse '(montpellier bordeaux limoges))
(set-adj 'bordeaux '(limoges toulouse nantes))
(set-adj 'limoges '(lyon toulouse bordeaux nantes paris))
(set-adj 'nantes '(limoges bordeaux rennes))
(set-adj 'paris '(calais nancy dijon limoges rennes caen))

;;; DEPTH-FIRST-SEARCH is the main searching procedure.


;;; Note that we use Common Lisp macros PUSH and POP to simplify
;;; adding and removing elements at the front of lists.
(defun depth-first-graph-search (start-node goal-node)
"Performs a depth-first search from START-NODE for GOAL-NODE."
(let ((open (list start-node)) ;step1
(closed nil)
n l)
(loop
(if (null open)(return 'failure)) ;step2
(setf n (pop open)) ;step3
(push n closed)
(increment-count)
(if (eql n goal-node)
(return (extract-path n)) )
(setf l (successors n)) ;step4
(setf l (list-difference l closed))
(setf open
(append l (list-difference open l)));step5
(dolist (x l)
(set-predecessor x n) )
; end of loop -------- this is implicitly step6
)))

;; The supporting functions:

;;; EXTRACT-PATH returns the sequence of cities found.


(defun extract-path (n)
"Returns the path leading to N."
(cond ((null n) nil)
(t (append (extract-path (get-predecessor n))
(list n) )) ) )

;;; SUCCESSORS retrieves the list of cities adjacent


;;; to N from N's property list.
(defun successors (n)
"Returns a list of nodes adjacent to N."
(get-adj n) )

;;; LIST-DIFFERENCE is like the built-in Lisp function


;;; named SET-DIFFERENCE but it preserves the ordering in LST1"
(defun list-difference (lst1 lst2)
"Returns a list of those elements of LST1 that do not
occur on LST2."
(dolist (elt lst2 lst1)
(setf lst1 (remove elt lst1)) ) )

;;; Use a local variable EXPANSION-COUNT for counting


;;; the number of nodes expanded by the algorithm.
(let (expansion-count)
(defun initialize-count () (setf expansion-count 0))
(defun increment-count () (incf expansion-count))
(defun get-count () expansion-count) )

;;; TEST sets the count of nodes expanded to 0 and


;;; begins a search from RENNES to AVIGNON.
(defun test ()
"Tests the function DEPTH-FIRST-SEARCH."
(initialize-count)
(format t "Depth-first-search solution: ~s.~%"
(depth-first-graph-search 'rennes 'avignon) )
(format t "~s nodes expanded.~%"
(get-count))
)

(test)

Output:
Experiment No.2

AIM: Write A Program for Best first Search.

S/W Requirement: LispWorks IDE, Emacs Editor and SLIME.

;;; BESTFS.CL
;;; Best-First Search (Forward-Looking version).
;;; It uses an evaluation function based on the ordering of cities
;;; with respect to longitude. The method does not take into
;;; consideration the length of each partial path found so far.
;;; Thus it considers only the "remaining distance" to the goal
;;; in deciding how to order nodes on OPEN. Hence it is
;;; "forward-looking".

;;; Here is the adjacency data (identical to that used


;;; in DEPTHFS.CL and BREADTH.CL):

;;; Create the hash table ADJACENCY-INFO to store the French


;;; roads data, and define the functions for entering and
;;; retrieving this info.
;;; The second hash table, PATH-PREDECESSOR-INFO, is used
;;; during the search to allow the eventual tracing of
;;; the path back from the goal to the starting node.
(let ((adjacency-info (make-hash-table :size 20))
(path-predecessor-info (make-hash-table :size 20)) )
(defun set-adj (x y)
(setf (gethash x adjacency-info) y) )
(defun get-adj (x)
(gethash x adjacency-info) )
(defun set-predecessor (x y)
(setf (gethash x path-predecessor-info) y) )
(defun get-predecessor (x)
(gethash x path-predecessor-info) )
)

;;; Establish BREST's list of neighbors as (RENNES), etc.


(set-adj 'brest '(rennes))
(set-adj 'rennes '(caen paris brest nantes))
(set-adj 'caen '(calais paris rennes))
(set-adj 'calais '(nancy paris caen))
(set-adj 'nancy '(strasbourg dijon paris calais))
(set-adj 'strasbourg '(dijon nancy))
(set-adj 'dijon '(strasbourg lyon paris nancy))
(set-adj 'lyon '(grenoble avignon limoges dijon))
(set-adj 'grenoble '(avignon lyon))
(set-adj 'avignon '(grenoble marseille montpellier lyon))
(set-adj 'marseille '(nice avignon))
(set-adj 'nice '(marseille))
(set-adj 'montpellier '(avignon toulouse))
(set-adj 'toulouse '(montpellier bordeaux limoges))
(set-adj 'bordeaux '(limoges toulouse nantes))
(set-adj 'limoges '(lyon toulouse bordeaux nantes paris))
(set-adj 'nantes '(limoges bordeaux rennes))
(set-adj 'paris '(calais nancy dijon limoges rennes caen))

;;; Now we create a new hash table LONGITUDE-INFO to


;;; support the heuristic ordering mechanism.
(let ((longitude-info (make-hash-table :size 20)))
(defun set-longitude (x y)
(setf (gethash x longitude-info) y) )
(defun get-longitude (x)
(gethash x longitude-info) )
)

;;; The longitude of each city is stored in tenths of a degree.


;;; We use a local function with a LAMBDA form, since
;;; SET-LONGITUDE takes two arguments but we want a
;;; function that takes one argument for this use with MAPCAR.
(mapcar #'(lambda (pair) (apply #'set-longitude pair))

'((avignon 48)(bordeaux -6)(brest -45)(caen -4)


(calais 18)(dijon 51)(grenoble 57)(limoges 12)

(lyon 48)(marseille 53)(montpellier 36)

(nantes -16)(nancy 62)(nice 73)(paris 23)

(rennes -17)(strasbourg 77)(toulouse 14) ) )


;;; We need one more hash table F-VALUE to
;;; remember the heuristic value at each node visited.
(let ((f-values (make-hash-table :size 20)))
(defun set-f-value (x y)
(setf (gethash x f-values) y) )
(defun get-f-value (x)
(gethash x f-values) )
)

;;; BEST-FIRST-SEARCH is the main searching procedure.


(defun best-first-search (start-node goal-node)
"Performs a best-first search from START-NODE for GOAL-NODE."
(set-goal goal-node)
(let ((open (list start-node)) ;step1
(closed nil)
n l val)
(set-predecessor start-node nil)
(set-f-value start-node (f start-node))
(loop
(if (null open)(return 'failure)) ;step2
(setf n (select-best open)) ;step3
(setf open (remove n open)) ;step4
(push n closed)
(if (eql n (get-goal)) ;step5
(return (extract-path n)) )
(setf l (successors n)) ;step6
(setf l (list-difference l closed))
(dolist (j (intersection l open)) ;step7
(if (< (setf val (f j))
(get-f-value j) )
(progn
(set-f-value j val)
(setf open
(insert j
(remove j open)
open
val) ) ) ) )
(dolist (j (list-difference l (append open closed)))
;; open the node J:
(increment-count)
(set-f-value j (setf val (f j)))
(setf open (insert j open val))
(set-predecessor j n) )
; end of loop -------- this is implicitly step8
)))

;; The supporting functions:

;;; Use local variable to keep track of the goal.


(let (goal)
(defun set-goal (the-goal) (setf goal the-goal))
(defun get-goal () goal) )

;;; EXTRACT-PATH returns the sequence of cities found.


(defun extract-path (n)
"Returns the path to N."
(cond ((null n) nil)
(t (append (extract-path (get-predecessor n))
(list n) )) ) )

;;; SUCCESSORS retrieves the list of cities adjacent


;;; to N from N's property list.
(defun successors (n)
"Returns the list of nodes adjacent to N."
(get-adj n) )

;;; LIST-DIFFERENCE is like the built-in Lisp function


;;; named SET-DIFFERENCE but it preserves the ordering in LST1"
(defun list-difference (lst1 lst2)
"Returns a list of those elements of LST1 that do not
occur on LST2."
(dolist (elt lst2 lst1)
(setf lst1 (remove elt lst1)) ) )

;;; LONGITUDE-DIFF returns the absolute value of the


;;; difference in longitudes between nodes N1 and N2
;;; in tenths of a degree.
(defun longitude-diff (n1 n2)
"Computes difference in longitudes."
(abs (- (get-longitude n1) (get-longitude n2))) )

;;; F evaluates the difference in longitude between


;;; the current node N and the goal node.
(defun f (n)
"Return diff. in longitude from goal node."
(longitude-diff n (get-goal)) )

;;; SELECT-BEST chooses a node in step 3...


(defun select-best (lst)
"Determines the best node to open next."
(cond ((eql (first lst) (get-goal))(first lst))
(t (better (first lst)(rest lst))) ) )

;;; The helping function BETTER for select-best checks


;;; to see if there is a goal node on LST with FVALUE
;;; as low as that of ELT.
(defun better (elt lst)
"Helping function for SELECT-BEST."
(cond ((null lst) elt)
((< (get-f-value elt)(get-f-value (first lst)))
elt)
((eql (first lst) (get-goal))
(first lst) )
(t (better elt (rest lst))) ) )

;;; INSERT puts NODE onto LST, which is ordered


;;; by FVALUE property, where VAL is the FVALUE
;;; of NODE.
(defun insert (node lst val)
"Puts NODE into its proper place on LST."
(cond ((null lst)(list node))
((< val (get-f-value (first lst)))
(cons node lst))
(t (cons (first lst)(insert node (rest lst) val))) ) )

;;; Use a local variable EXPANSION-COUNT for counting the


;;; number of nodes expanded by the algorithm.
(let (expansion-count)
(defun initialize-count () (setf expansion-count 1))
(defun increment-count () (incf expansion-count))
(defun get-count () expansion-count) )

;;; TEST sets EXPANSION-COUNT to 0 and


;;; begins a search from RENNES to AVIGNON.
(defun test ()
"Tests the function BEST-FIRST-SEARCH."
(initialize-count)
(format t "Best-first-search solution: ~s.~%"
(best-first-search 'rennes 'avignon) )
(format t "~s nodes expanded.~%"
(get-count) ))
(test)

Output:
Experiment No.3

AIM: Write A Program to generate output for A* Algorithm.

S/W Requirement: LispWorks IDE, Emacs Editor and SLIME.

;;; ASTAR.CL
;;; A* Search for a shortest path.
;;; Here is the representation of the adjacency distance data,
;;; plus functions for getting at it and at solution path info.
;;; This code is identical to that in UNIFCOST.CL
(let ((distance-info (make-hash-table :size 20))
(path-predecessor-info (make-hash-table :size 20)) )
(defun set-distances (x y)
(setf (gethash x distance-info) y) )
(defun get-distances (x)
(gethash x distance-info) )
(defun set-predecessor (x y)
(setf (gethash x path-predecessor-info) y) )
(defun get-predecessor (x)
(gethash x path-predecessor-info) )
)

;;; Here are actual inter-city distances from the Michelin map:
(set-distances 'brest '((rennes . 244)))
(set-distances 'rennes '((caen . 176)(paris . 348)

(brest . 244)(nantes . 107)))


(set-distances 'caen '((calais . 120)(paris . 241)(rennes . 176)))
(set-distances 'calais '((nancy . 534)(paris . 297)(caen . 120)))
(set-distances 'nancy '((strasbourg . 145)(dijon . 201)

(paris . 372)(calais . 534)))


(set-distances 'strasbourg '((dijon . 335)(nancy . 145)))
(set-distances 'dijon '((strasbourg . 335)(lyon . 192)

(paris . 313)(nancy . 201)))


(set-distances 'lyon '((grenoble . 104)(avignon . 216)

(limoges . 389)(dijon . 192)))


(set-distances 'grenoble '((avignon . 227)(lyon . 104)))
(set-distances 'avignon '((grenoble . 227)(marseille . 99)

(montpellier . 121)(lyon . 216)))


(set-distances 'marseille '((nice . 188)(avignon . 99)))
(set-distances 'nice '((marseille . 188)))
(set-distances 'montpellier '((avignon . 121)(toulouse . 240)))
(set-distances 'toulouse '((montpellier . 240)(bordeaux . 253)

(limoges . 313)))
(set-distances 'bordeaux '((limoges . 220)(toulouse . 253)

(nantes . 329)))
(set-distances 'limoges '((lyon . 389)(toulouse . 313)

(bordeaux . 220)(nantes . 329)(paris . 396)))


(set-distances 'nantes '((limoges . 329)(bordeaux . 329)

(rennes . 107)))
(set-distances 'paris '((calais . 297)(nancy . 372)(dijon . 313)

(limoges . 396)(rennes . 348)(caen . 241)))

;;; And here is the hash table F-VALUES to


;;; remember the heuristic value at each node visited.
;;; We also need a hash table for G-VALUES.
(let ((f-values (make-hash-table :size 20))
(g-values (make-hash-table :size 20)) )
(defun set-f-value (x y)
(setf (gethash x f-values) y) )
(defun get-f-value (x)
(gethash x f-values) )
(defun set-g-value (x y)
(setf (gethash x g-values) y) )
(defun get-g-value (x)
(gethash x g-values) )
)

;;; Next is the information about longitude, which is the same


;;; as that used in BESTFS2.CL
(let ((longitude-info (make-hash-table :size 20)))
(defun set-longitude (x y)
(setf (gethash x longitude-info) y) )
(defun get-longitude (x)
(gethash x longitude-info) )
)

;;; The longitude of each city is stored in tenths of a degree.


;;; We again use a local function with a LAMBDA form, since
;;; SET-LONGITUDE takes two arguments but we want a
;;; function that takes one argument for this use with MAPCAR.
(mapcar #'(lambda (pair) (apply #'set-longitude pair))

'((avignon 48)(bordeaux -6)(brest -45)(caen -4)


(calais 18)(dijon 51)(grenoble 57)(limoges 12)

(lyon 48)(marseille 53)(montpellier 36)

(nantes -16)(nancy 62)(nice 73)(paris 23)

(rennes -17)(strasbourg 77)(toulouse 14) ) )

;;; Now we are ready for the algorithm itself.

;;; A-STAR-SEARCH is the main searching procedure.


(defun a-star-search (start-node goal-node)
"Performs a search with the A* algorithm."
(set-goal goal-node)
(let ((open (list start-node)) ;step1
(closed nil)
x
successors)
(set-predecessor start-node nil)
(set-g-value start-node 0)
(set-f-value start-node (f start-node))
(loop
(if (null open)(return 'failure)) ;step2
(setf x (select-best open)) ;step3
(setf open (remove x open)) ;step4
(push x closed)
(if (eql x (get-goal))
(return (extract-path x)) ) ;step5
(setf successors (get-successors x)) ;step6
(dolist (y successors) ;step7
(if (not (or (member y open)
(member y closed) ))
(progn
(increment-count)
(set-g-value y (g y x))
(set-f-value y (f y))
(setf open (insert y open))
(set-predecessor y x) )
(let* ((z (get-predecessor y))
(temp (if z
(+ (- (get-f-value y)
(get-g-value z)
(arc-dist z y) )
(get-g-value x)
(arc-dist x y) )
(get-f-value y) ) ) )
(if (< temp (get-f-value y))
(progn
(set-g-value y
(+ (- (get-g-value y)
(get-f-value y) )
temp) )
(set-f-value y temp)
(set-predecessor y x)
(if (member y open)
(progn
(setf open (remove y open))
(setf open (insert y open)) ) )
(if (member y closed)
(progn
(setf open (insert y open))
(setf closed
(remove y closed) ) ) ) ) ) ) ) )

; end of loop -------- this is implicitly step8


)))

;; The supporting functions:

;;; Use local variable to keep track of the goal.


(let (goal)
(defun set-goal (the-goal) (setf goal the-goal))
(defun get-goal () goal) )

;;; F is the sum of G and H.


(defun f (n)
"Computes F value for node N."
(+ (get-g-value n) (h n)) )

;;; G computes the distance from the start node to NODE


;;; by adding the distance from X to NODE to X's distance.
(defun g (node x)
"Returns distance from START-NODE to NODE"
(+ (get-g-value x) (arc-dist x node)) )
;;; H evaluates the difference in longitude between
;;; the current node N and the goal node.
(defun h (n)
"Returns an estimate of the distance from N
to the goal."
(* 10 (longitude-diff n (get-goal))) )

;;; LONGITUDE-DIFF returns the absolute value of the


;;; difference in longitudes between nodes N1 and N2
;;; in tenths of a degree.
(defun longitude-diff (n1 n2)

"Computes difference in longitudes."


(abs (- (get-longitude n1) (get-longitude n2))) )

;;; SELECT-BEST chooses a node in step 3...


(defun select-best (lst)
"Returns the best node on LST for expansion."
(if (eql (first lst) (get-goal))
(first lst)
(better (first lst)(rest lst)) ) )

;;; The helping function BETTER for SELECT-BEST checks


;;; to see if there is a goal node on LST with FVALUE
;;; as low as that of ELT. If so, it returns the goal node.
;;; If not, it returns ELT.
(defun better (elt lst)
"Returns a goal-node on LST if it has an equal value,
otherwise ELT."
(cond ((null lst) elt)
((< (get-f-value elt)(get-f-value (first lst)))
elt)
((eql (first lst) (get-goal))
(first lst) )
(t (better elt (rest lst))) ) )

;;; INSERT puts NODE onto LST, which is ordered


;;; by FVALUE.
(defun insert (node lst)
"Inserts NODE onto LST, according to FVALUE ordering."
(cond ((null lst)(list node))
((< (get-f-value node)
(get-f-value (first lst)) )
(cons node lst) )
(t (cons (first lst)
(insert node (rest lst)) )) ) )

;;; EXTRACT-PATH returns the sequence of cities found.


(defun extract-path (n)
"Returns the path from START-NODE to N."
(cond ((null n) nil)
(t (append (extract-path (get-predecessor n))
(list n) )) ) )

;;; GET-SUCCESSORS retrieves the list of cities adjacent


;;; to N from the hash table.
(defun get-successors (n)
"Returns a list of cities adjacent to N."
(mapcar #'first (get-distances n)) )

;;; Let BIG-DISTANCE represent an impossibly large distance


;;; for this problem:
(defconstant big-distance 9999)

;;; ARC-DIST retrieves the distance between N1 and N2.


(defun arc-dist (n1 n2)
"Returns the distance along arc N1 N2. If no such arc
exists, returns BIG-DISTANCE."
(or (rest (assoc n1 (get-distances n2))) big-distance) )

;;; Use a local variable EXPANSION-COUNT for counting the


;;; number of nodes expanded by the algorithm.
(let (expansion-count)
(defun initialize-count () (setf expansion-count 0))
(defun increment-count () (incf expansion-count))
(defun get-count () expansion-count) )

;;; TEST sets EXPANSION-COUNT to 0 and


;;; begins a search from RENNES to AVIGNON.
(defun test ()
"Runs a test of ASTAR."
(initialize-count)
(format t "A-star-search solution: ~s.~%"
(a-star-search 'rennes 'avignon) )
(format t "Path-length: ~s.~%"
(get-f-value 'avignon) )
(format t "~s nodes expanded.~%"
(get-count) ))
(test)

Output:
Experiment No.4

AIM: Write A Lisp Program to solve Water Jug problem using Heuristic function.

S/W Requirement: LispWorks IDE, Emacs Editor and SLIME.

(defvar *start* '(0 0))


(defun first-jug (state) (car state))
(defun second-jug (state) (cadr state))
(defun mk-state (f s) (list f s))
(defun goalp (state)
(eq (first-jug state) 2))
(defun new-states (state)
(remove-null
(list
(fill-first state)
(fill-second state)
(pour-first-second state)
(pour-second-first state)
(empty-first state)
(empty-second state))))
(defun remove-null (x)
(cond
((null x) nil)
((null (car x)) (remove-null (cdr x)))
((cons (car x) (remove-null (cdr x))))))
(defun fill-first (state)
(cond
((< (first-jug state) 4) (mk-state 4 (second-jug state)))))
(defun fill-second (state)
(cond
((< (second-jug state) 3) (mk-state (first-jug state) 3))))
(defun pour-first-second (state)
(let ( (f (first-jug state))
(s (second-jug state)))
(cond
((zerop f) nil)
((= s 3) nil)
((<= (+ f s) 3)
(mk-state 0 (+ f s)))
(t (mk-state (- (+ f s) 3) 3)))))
(defun pour-second-first (state)
(let ( (f (first-jug state))
(s (second-jug state)))
(cond
((zerop s) nil)
((= f 4) nil)
((<= (+ f s) 4)
(mk-state (+ f s) 0))
(t (mk-state 4 (- (+ f s) 4))))))
(defun empty-first (state)
(cond
((> (first-jug state) 0) (mk-state 0 (second-jug state)))))
(defun empty-second (state)
(cond
((> (second-jug state) 0) (mk-state (first-jug state) 0))))
Output:

Experiment No.5

AIM: Write A Program to show Tic-Tac-Toe.

S/W Requirement: LispWorks IDE, Emacs Editor and SLIME.

#|--------------------------------------------------------------------
--------
TIC-TAC-TOE GAME
"tictactoe.lisp"
----------------------------------------------------------------------
------|#
#|--------------------------------------------------------------------
---------

This file contains code for the game of tic-tac-toe.


The important functions are:

(deep-enough pos depth) t if the search has proceeded deep enough.


(static pos player) evaluation of position pos from player's
point of view.
(movegen pos player) generate all successor positions to pos.
(opposite player) return the opposite player.
(print-board pos) print board position pos.
(make-move pos player move) return new position based on old position and
player's move.
(won? pos player) t if player has won.
(drawn? pos) t if pos is a drawn position.

The important variables are:

*start* the initial board configuration.

These functions and variables are all called from minimax.lisp.

----------------------------------------------------------------------------|#

;; Function NULL-BOARD creates an empty tic-tac-toe board. The board is


;; stored as a list of nine elements. Elements are either 'x, 'o, or nil
;; (empty).

(defun null-board ()
(list nil nil nil nil nil nil nil nil nil))

;; Variable *START* is the starting board position.

(defvar *start* nil)


(setq *start* (null-board))

;; Function MAKE-MOVE takes a board position (pos), a player (player, which


;; is 'x or 'o), and a move (which is a number between 0 and 8). It returns
;; a new board position.

(defun make-move (pos player move)


(let ((b (copy-list pos)))
(setf (nth move b) player)
b))

;; Function MOVEGEN takes a position and a player and generates all legal
;; successor positions, i.e., all possible moves a player could make.

(defun movegen (pos player)


(mapcan
#'(lambda (m)
(if (null (nth m pos))
(list (make-move pos player m))
nil))
'(0 1 2 3 4 5 6 7 8)))

;; Function WON? returns t is pos is a winning position for player,


;; nil otherwise.

(defun won? (pos player)

(or (and (eq (first pos) player)


(eq (second pos) player)
(eq (third pos) player))
(and (eq (fourth pos) player)
(eq (fifth pos) player)
(eq (sixth pos) player))
(and (eq (seventh pos) player)
(eq (eighth pos) player)
(eq (ninth pos) player))
(and (eq (first pos) player)
(eq (fourth pos) player)
(eq (seventh pos) player))
(and (eq (second pos) player)
(eq (fifth pos) player)
(eq (eighth pos) player))
(and (eq (third pos) player)
(eq (sixth pos) player)
(eq (ninth pos) player))
(and (eq (first pos) player)
(eq (fifth pos) player)
(eq (ninth pos) player))
(and (eq (third pos) player)
(eq (fifth pos) player)
(eq (seventh pos) player))))

;; Function DRAWN? returns t if pos is a drawn position, i.e., if there are


;; no more moves to be made.

(defun drawn? (pos)


(not (member nil pos)))

;; Function OPPOSITE returns 'x when given 'o, and vice-versa.

(defun opposite (player)


(if (eq player 'x) 'o 'x))

;; Function STATIC evaluates a position from the point of view of a


;; particular player. It returns a number -- the higher the number, the
;; more desirable the position. The simplest static function would be:
;;

;; (defun static (pos player)


;; (cond ((won? pos player) 1)
;; ((won? pos (opposite player)) -1)
;; (t 0)))
;;
;; However, this heuristic suffers from the problem that minimax search
;; will not "go in for the kill" in a won position. The following static
;; function weighs quick wins more highly than slower ones; it also
;; ranks quick losses more negatively than slower ones, allowing the
;; program to "fight on" in a lost position.

(defun static (pos player)


(cond ((won? pos player)
(+ 1 (/ 1 (length (remove nil pos)))))
((won? pos (opposite player))
(- (+ 1 (/ 1 (length (remove nil pos))))))
(t 0)))
;; Function DEEP-ENOUGH takes a board position and a depth and returns
;; t if the search has proceeded deep enough. The implementation below
;; causes the search to proceed all the way to a finished position. Thus,
;; minimax search will examine the whole search space and never make a
;; wrong move. A depth-limited search might look like:
;;
;; (defun deep-enough (pos depth)
;; (declare (ignore pos))
;; (if (> depth 3) t nil))

(defun deep-enough (pos depth)


(declare (ignore depth))
(or (won? pos 'x)
(won? pos 'o)
(drawn? pos)))

;; Function PRINT-BOARD prints a two-dimensional representation of the board.

(defun print-board (b)


(format t "~% ~d ~d ~d~% ~d ~d ~d~% ~d ~d ~d~%~%"
(or (first b) ".") (or (second b) ".") (or (third b) ".")
(or (fourth b) ".") (or (fifth b) ".") (or (sixth b) ".")

(or (seventh b) ".") (or (eighth b) ".") (or (ninth b) ".")))

Output:
Experiment No.6

AIM: Write A Program to implement Tower of Hanoi.

S/W Requirement: LispWorks IDE, Emacs Editor and SLIME.

;; The Tower represented by a list of numbers

;; Create empty tower


(defun make-empty-tower () nil)

;; Create tower by stacking DISK on top of TOWER


(defun tower-push (tower disk) (cons disk tower))

;; Get the top disk of TOWER


(defun tower-top (tower) (first tower))

;; Remove the top disk of TOWER


(defun tower-pop (tower) (rest tower))

;; Create a Hanoi Configuration


(defun make-hanoi (from-tower aux-tower to-tower)
(list from-tower aux-tower to-tower))

;; Select I'th tower of HANOI


(defun hanoi-tower (hanoi i)
(nth (1- i) hanoi))

;; replace the I'th tower in the HANOI configuration by tower TOWER


(defun hanoi-tower-update (hanoi i tower)
(cond
((= i 1) (make-hanoi tower (second hanoi) (third hanoi)))
((= i 2) (make-hanoi (first hanoi) tower (third hanoi)))
((= i 3) (make-hanoi (first hanoi) (second hanoi) tower))))

;; return the top disk from I'th tower of HANOI


(defun hanoi-tower-top (hanoi i)
(tower-top (hanoi-tower hanoi i)))

;; Pop the top disk of the I'th tower in the HANOI configuration
(defun hanoi-tower-pop (hanoi i)
(hanoi-tower-update hanoi i (tower-pop (hanoi-tower hanoi i))))

;; Push DISK into I'th tower of HANOI


(defun hanoi-tower-push (hanoi i disk)
(hanoi-tower-update hanoi i (tower-push (hanoi-tower hanoi i) disk)))

(defun move-disk (from to hanoi)


(let
((disk (hanoi-tower-top hanoi from))
(intermediate-hanoi (hanoi-tower-pop hanoi from)))

(hanoi-tower-push intermediate-hanoi to disk)))

;; N disks from peg FROM to peg TO using AUX peg as in HANOI


(defun move-tower (N from aux to hanoi)
(if (= N 1)
(move-disk from to hanoi)
(move-tower (- N 1) aux from to
(move-disk from to
(move-tower (- N 1) from to aux hanoi)))))
(defun solve-hanoi (N)
(move-tower N 1 2 3 (make-hanoi (make-complete-tower N) nil nil)))

;; Create tower of n disks


(defun make-complete-tower (N)
(make-complete-tower-aux N (make-empty-tower)))
;; Push a complete tower of N disks on top of A tower
(defun make-complete-tower-aux (N A)
(if (zerop N)
A
(make-complete-tower-aux (1- N) (tower-push A N))))

Output:
Experiment No.7

AIM: Write A Program to implement Heuristic Search Function.

S/W Requirement: LispWorks IDE, Emacs Editor and SLIME.

;;; Our problem uses a graph whose nodes present cities and
;;; whose arcs carry distances, much as for the UNIFORM-COST
;;; search and A* programs.

;;; Here is a hash table to store the distance information:


(let ((distance-info (make-hash-table :size 20)) )
(defun set-distances (x y)
(setf (gethash x distance-info) y) )
(defun get-distances (x)
(gethash x distance-info) )
)

;;; Here is the set of cities for this problem:


(defparameter *cities*
'(seattle portland spokane wenatchee bellingham) )
(defparameter *ncities* (length *cities*))

;;; Here are the distances.


;;; (These were estimated and not from a map)

(set-distances 'seattle
'((portland . 150)(spokane . 350)
(wenatchee . 100)(bellingham . 90) ) )
(set-distances 'portland
'((seattle . 150)(spokane . 400)
(wenatchee . 200)(bellingham . 235) ) )
(set-distances 'spokane
'((portland . 400)(seattle . 350)
(wenatchee . 275)(bellingham . 385) ) )
(set-distances 'wenatchee
'((portland . 200)(spokane . 275)
(seattle . 100)(bellingham . 130) ) )
(set-distances 'bellingham
'((portland . 235)(seattle . 90)
(spokane . 385)(wenatchee . 130) ) )

;;; We represent an individual as a dotted pair whose left part


;;; is a list of cities and whose right part is a strength value.
(defun get-path (individual)
"Returns the list of cities associated with INDIVIDUAL."
(first individual) )

(defun get-strength (individual)


"Returns the strength value associated with INDIVIDUAL."
(rest individual) )

(defparameter *initial-population*
'( ((seattle seattle seattle seattle seattle) . 0) ) )

(defvar *population*)
(defvar *current-min-strength*)
(defvar *current-pop-size*)

(defparameter *population-limit* 15)

(defun distance (a b)
"Returns the distance between cities A and B."
(if (eql a b) 0
(rest (assoc b (get-distances a))) ) )

(defun cycle-cost (path)


"Returns length of the PATH, including a closing
arc from the last to the first element of PATH."
(+ (distance (first path) (first (last path)))
(path-cost path) ) )

(defun path-cost (path)


"Returns the length of the PATH."
(if (<= (length path) 1) 0
(+ (distance (first path) (second path))
(path-cost (rest path)) ) ) )

(defun non-tour-penalty (path)


"Computes how far PATH is from being a tour.
If PATH is a tour, then the penalty returned is 0."
(* 100
(+ (length (set-difference path *cities*))
(length (set-difference *cities* path)) ) ) )

(defun chromosome-strength (individual)


"Returns a value that is highest when INDIVIDUAL is a
mimimum cost tour."
(/ 10000.0
(+ (* 2 (cycle-cost (get-path individual)))
(* 50 (non-tour-penalty (get-path individual))) ) ) )

(defun mutate (individual)


"Performs either MUTATE1 or MUTATE2, choosing randomly."
(if (oddp (random 2))
(mutate1 individual)
(mutate2 individual) ) )

(defun mutate1 (individual)


"Returns a slightly altered INDIVIDUAL, with the
alteration generated randomly. One city is randomly changed."
(let* ((path (get-path individual))
(where (random (length path)))
(new-city (nth (random *ncities*) *cities*)) )
(cons (replace-nth path where new-city)
0) ) )

(defun mutate2 (individual)


"Returns a slightly altered INDIVIDUAL, with the
alteration generated randomly. Two cities are transposed."
(let* ((path (get-path individual))
(where1 (random (length path)))
(where2 (random (length path)))
(city1 (nth where1 path))
(city2 (nth where2 path)) )
(cons (replace-nth
(replace-nth path where1 city2)
where2
city1)
0) ) )

(defun replace-nth (lst n elt)


"Returns result of replacing the N-th element of LST by ELT."
(cond ((null lst) nil)
((zerop n) (cons elt (rest lst)))
(t (cons (first lst)
(replace-nth (rest lst) (1- n) elt) )) ) )

;;; In CROSSOVER we assume that PATH1 and PATH2 are of the same length.
(defun crossover (individual1 individual2)
"Returns a new path resulting from
genetic crossover of PATH1 and PATH2."
(let* ((path1 (get-path individual1))
(path2 (get-path individual2))
(where (random (length path1))) )
(cons (append (left-part path1 where)
(right-part path2 where) )
0) ) )

(defun left-part (path k)


"Returns the prefix of PATH having length K."
(subseq path 0 k) )

(defun right-part (path k)


"Returns the suffix of PATH starting at position K."
(subseq path k) )

(defun random-individual ()
"Returns a randomly selected member of the population."
(nth (random (length *population*)) *population*) )

(defun another-individual (previous-rand-indiv)


"Returns a randomly selected member of the population
but makes an effort to find one that is different
from PREVIOUS-RAND-INDIV."
(let ((current-population-size (length *population*))
(previous-path (get-path previous-rand-indiv))
candidate)
(dotimes (i 5 candidate) ; try at most 5 times.
(setf candidate
(nth (random current-population-size)
*population*) )
(if (not (equal (get-path candidate) previous-path))
(return candidate) ) ) ) )
(defun evolve (ngenerations nmutations ncrossovers)
"Runs the genetic algorithm for NGENERATIONS times."
(setf *population* *initial-population*)
(dotimes (i ngenerations)
(dotimes (j nmutations)
(let ((mutated-one (mutate (random-individual))))
(add-individual mutated-one) ) )
(dotimes (j ncrossovers)
(let* ((individual1 (random-individual))
(individual2
(another-individual individual1) )
(crossing-result
(crossover individual1
individual2) ) )
(add-individual crossing-result) ) )
(format t "~%In generation ~D, population is: ~S.~%"
(1+ i) *population*)
))

(defun add-individual (individual)


"Computes and stores the chromosome-strength of INDIVIDUAL.
Then adds the INDIVIDUAL to the population
if the population limit has not yet been reached.
Otherwise, if its strength exceeds that of the weakest
member it replaces the weakest member."
(let ((strength (chromosome-strength individual)))
(setf (rest individual) strength) ; Here SETF works like RPLACD
(if (= *current-pop-size* *population-limit*)
(progn
(if (> strength *current-min-strength*)
;;; Remove weakest current member:
(progn
(let ((k (where-strength-occurs
*current-min-strength*
*population*)))
(setf *population* (remove-kth k *population*)) )
;;; Insert INDIVIDUAL into the population:
(push individual *population*)
(update-min-strength) ) ) )

;;; Still room in population...


(progn
(push individual *population*)
(setf *current-min-strength*
(min strength *current-min-strength*) )
(incf *current-pop-size*) ) ) ) )

(defun update-min-strength ()
"Computes and saves the minimum of all strengths of
current members of the population."
(setf *current-min-strength*
(apply #'min (mapcar #'get-strength *population*)) ) )

(defun where-strength-occurs (val population-list)


"Returns the first position in POPULATION-LIST where VAL occurs
as the strength of that individual."
(cond ((null population-list) nil)
((= val (get-strength (first population-list))) 0)
(t (1+ (where-strength-occurs val (rest population-list)))) ) )

(defun remove-kth (k lst)


"Returns a list consisting of LST with the Kth element deleted."
(cond ((null lst) nil)
((zerop k) (rest lst))
(t (cons (first lst)
(remove-kth (1- k) (rest lst)) )) ) )

(defun test ()
"Does a trial run of EVOLVE."
(setf *population* *initial-population*)
(setf *current-min-strength* 0)
(setf *current-pop-size* 1)
(evolve 10 10 10) ; these values often lead to convergence at strength 4.78.
)

(test)
Output:
Experiment No.8

AIM: Write A Program to implement search problem in 3x3(8-Puzzle).

S/W Requirement: LispWorks IDE, Emacs Editor and SLIME.

;;; Domain-specific 8-puzzle code


;;;
;;; An 8 puzzle state is represented by a list of 3 lists of 3 elements each.
;;; The elements are the numbers 0-9 with 0 representing the blank tile. The
;;; rows of the puzzle are represented by the first, second and third set of 3
;;; elements respectively. For instance the puzzle:
;;; 4 2 3
;;; 8 1 0
;;; 6 7 5
;;; would be represented by the list
;;; '((4 2 3) (8 1 0) (6 7 5))
;;;
;;; The data structure used for the search is a list of two lists. The first
;;; is an 8-puzzle representation (as above), the second is the set of
;;; actions that led to this state. So for instance, from the state above,
;;; if the right operator is applied (e.g. move the 1 to the right), the
;;; resulting state is
;;; (((4 2 3) (8 0 1) (6 7 5)) (right)).

(defun up (8-puzzle)
(let* ((board (first 8-puzzle))
(path (second 8-puzzle))
(x (x-position 0 board))
(y (y-position 0 board))
(new-state (copy-board board)))
(unless (= y 2)
(setf (nth x (nth y new-state)) (nth x (nth (+ y 1) new-state)))
(setf (nth x (nth (+ y 1) new-state)) 0)
(list new-state (cons 'up path)))))

(defun down (8-puzzle)


(let* ((board (first 8-puzzle))
(path (second 8-puzzle))
(x (x-position 0 board))
(y (y-position 0 board))
(new-state (copy-board board)))
(unless (= y 0)
(setf (nth x (nth y new-state)) (nth x (nth (- y 1) new-state)))
(setf (nth x (nth (- y 1) new-state)) 0)
(list new-state (cons 'down path)))))

(defun right (8-puzzle)


(let* ((board (first 8-puzzle))
(path (second 8-puzzle))
(x (x-position 0 board))
(y (y-position 0 board))
(new-state (copy-board board)))
(unless (= x 0)
(setf (nth x (nth y new-state)) (nth (- x 1) (nth y new-state)))
(setf (nth (- x 1) (nth y new-state)) 0)
(list new-state (cons 'right path)))))

(defun left (8-puzzle)


(let* ((board (first 8-puzzle))
(path (second 8-puzzle))
(x (x-position 0 board))
(y (y-position 0 board))
(new-state (copy-board board)))
(unless (= x 2)
(setf (nth x (nth y new-state)) (nth (+ x 1) (nth y new-state)))
(setf (nth (+ x 1) (nth y new-state)) 0)
(list new-state (cons 'left path)))))

(defun x-position (value board)


(let ((row (nth (y-position value board) board)))
(position value row)))

(defun y-position (value board)


(position value board :test #'member))

(defun copy-board (board)


(list (copy-list (first board)) (copy-list (second board))
(copy-list (third board))))

(defun 8-puzzle-generate (state)


(let ((moves '(up down left right)))
(case (first (second state))
(down (setq moves (remove 'up moves))))
(generic-generate state moves)))

(defun 8-puzzle-final (8-puzzle)


(equal (first 8-puzzle) '((1 2 3) (4 5 6) (7 8 0))))

(defun 8-puzzle-equal (puzzle-1 puzzle-2)


(equal (first puzzle-1) (first puzzle-2)))

(defun make-8-puzzle-problem (moves)


"Generates an 8-puzzle state representation. The state it returns is
guaranteed to be solvable because it is derived from the final state by a
legal set of moves."
;; Initialize state, new-state will temporarily hold the results of a move
;; in case the move was illegal (returned nil)
(let ((state '(((1 2 3) (4 5 6) (7 8 0))))
new-state)
;; For each move
(dolist (move moves)
;; Generate a new state
(setq new-state (funcall move state))
;; If the generation succeeded record the new state
(unless (null new-state)
(setq state new-state)))
;; Remove the path component and return state
(list (first state))))

(defun manhattan-distance (state)


(let ((board (first state))
(distance 0))
(dotimes (x 3)
(dotimes (y 3)
(if (not (= (nth x (nth y board)) 0))
(setf distance (+ distance (piece-distance (nth x (nth y board))
board))))))
distance))

(defun piece-distance (piece board)


(let ((final-board '((1 2 3) (4 5 6) (7 8 0))))
(+ (abs (- (x-position piece board) (x-position piece final-board)))
(abs (- (y-position piece board) (y-position piece final-board))))))

Output:
3

Você também pode gostar