AI Algorithms and Prolog Examples — BFS, A*, Minimax

AI Algorithms and Prolog Examples

This document contains:

  • Prolog family facts and queries
  • Python implementations of BFS, DFS, A*, Minimax, Alpha-Beta
  • 8-puzzle A* solver, Tic-Tac-Toe minimax, a simple reflex agent, and a Chess AI

Prolog Family Facts and Queries

Prolog
parent(john, mary).
parent(john, david).
parent(susan, mary).
parent(susan, david).
parent(david, emily).
parent(david, james).
parent(mary, ann).
male(john).
male(david).
male(james).
female(susan).
female(mary).
female(ann).
female(emily).
father(X, Y) :- parent(X, Y), male(X).
mother(X, Y) :- parent(X, Y), female(X).
grandparent(X, Z) :- parent(X, Y), parent(Y,Z).
grandmother(X, Y) :- grandparent(X, Y), female(X).
grandfather(X, Y) :- grandparent(X, Y), male(X).
sibling(X, Y) :- parent(Z, X), parent(Z, Y), X \== Y.
ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z,Y).

QUERIES:
?- father(john, mary).  % Check if John is father of Mary
?- mother(susan, david).  % Check if Susan is mother of David
?- grandparent(john, emily).  % Find if John is a grandparent of Emily
?- grandfather(john, james).  % Check if John is grandfather of James
?- grandmother(susan, ann).  % Check if Susan is grandmother of Ann
?- sibling(mary, david).  % Verify sibling relationship between Mary and David
?- ancestor(john, ann).  % Check if John is an ancestor of Ann
?- ancestor(susan, emily).  % Check if Susan is ancestor of Emily
?- ancestor(david, james).  % Check if David is ancestor of James
?- ancestor(X, emily).  % Find all ancestors of Emily
?- parent(X, Y).  % Display all parent-child pairs

Python: BFS (Breadth-First Search)

from collections import deque

def bfs(graph, start):
    visited = set()
    queue = deque([start])
    while queue:
        node = queue.popleft()
        if node not in visited:
            print(node, end=" ")
            visited.add(node)
            queue.extend(neighbor for neighbor in graph[node] if neighbor not in visited)

graph = {
    'A': ['B', 'C'],
    'B': ['D', 'E'],
    'C': ['F'],
    'D': [],
    'E': ['F'],
    'F': []
}
print("\nBFS Traversal:")
bfs(graph, 'A')

Python: DFS (Depth-First Search)

# 2. DFS (Depth First Search)
def dfs(graph, start, visited=None):
    if visited is None:
        visited = set()
    visited.add(start)
    print(start, end=" ")
    for neighbor in graph[start]:
        if neighbor not in visited:
            dfs(graph, neighbor, visited)
    return visited

graph = {
    'A': ['B', 'C'],
    'B': ['D', 'E'],
    'C': ['F'],
    'D': [],
    'E': ['F'],
    'F': []
}

print("\n\nDFS Traversal:")
dfs(graph, 'A')

Python: Basic A* Search

# 3. Basic A* Search
def a_star(graph, start, goal, heuristic):
    open_list = [(start, [start], 0)]  # (current_node, path, cost_so_far)
    while open_list:
        open_list.sort(key=lambda x: x[2] + heuristic[x[0]])  # Sort by f = g + h
        node, path, cost = open_list.pop(0)

        if node == goal:
            return path

        for neighbor, step_cost in graph[node]:
            new_cost = cost + step_cost
            open_list.append((neighbor, path + [neighbor], new_cost))
    return None

graph = {
    'A': [('B', 1), ('C', 3)],
    'B': [('D', 1), ('E', 5)],
    'C': [('F', 2)],
    'D': [],
    'E': [('F', 1)],
    'F': []
}

heuristic = {'A': 7, 'B': 6, 'C': 2, 'D': 1, 'E': 1, 'F': 0}

path = a_star(graph, 'A', 'F', heuristic)
print("\n\nA* Path:", path)

Python: Basic Minimax Algorithm

# 4. Basic Minimax Algorithm
def minimax(depth, nodeIndex, maximizingPlayer, values):
    if depth == 3:
        return values[nodeIndex]
    
    if maximizingPlayer:
        best = float('-inf')
        for i in range(2):
            val = minimax(depth + 1, nodeIndex * 2 + i, False, values)
            best = max(best, val)
        return best
    else:
        best = float('inf')
        for i in range(2):
            val = minimax(depth + 1, nodeIndex * 2 + i, True, values)
            best = min(best, val)
        return best

values = [3, 5, 6, 9, 1, 2, 0, -1]
print("\n\nMinimax Optimal Value:", minimax(0, 0, True, values))

Python: Alpha-Beta Pruning

# 5. Alpha-Beta Pruning
def minimax_ab(depth, nodeIndex, maximizingPlayer, values, alpha, beta):
    if depth == 3:
        return values[nodeIndex]
    
    if maximizingPlayer:
        best = float('-inf')
        for i in range(2):
            val = minimax_ab(depth + 1, nodeIndex * 2 + i, False, values, alpha, beta)
            best = max(best, val)
            alpha = max(alpha, best)
            if beta <= alpha:
                break
        return best
    else:
        best = float('inf')
        for i in range(2):
            val = minimax_ab(depth + 1, nodeIndex * 2 + i, True, values, alpha, beta)
            best = min(best, val)
            beta = min(beta, best)
            if beta <= alpha:
                break
        return best

values = [3, 5, 6, 9, 1, 2, 0, -1]
print("Alpha-Beta Optimal Value:", minimax_ab(0, 0, True, values, float('-inf'), float('inf')))

A* for the 8-Puzzle

# 6. 8 Puzzle using A*
from heapq import heappush, heappop

def heuristic_puzzle(state, goal):
    return sum(s != g and s != 0 for s, g in zip(state, goal))

def get_neighbors(state):
    neighbors = []
    idx = state.index(0)
    moves = []
    if idx not in [0, 1, 2]: moves.append(-3)
    if idx not in [6, 7, 8]: moves.append(3)
    if idx not in [0, 3, 6]: moves.append(-1)
    if idx not in [2, 5, 8]: moves.append(1)

    for move in moves:
        new_state = list(state)
        new_state[idx], new_state[idx + move] = new_state[idx + move], new_state[idx]
        neighbors.append(tuple(new_state))
    return neighbors

def a_star_8_puzzle(start, goal):
    pq = []
    heappush(pq, (heuristic_puzzle(start, goal), 0, start, [start]))
    visited = set()

    while pq:
        f, g, state, path = heappop(pq)
        if state == goal:
            return path
        visited.add(state)

        for neighbor in get_neighbors(state):
            if neighbor not in visited:
                heappush(pq, (g + 1 + heuristic_puzzle(neighbor, goal), g + 1, neighbor, path + [neighbor]))
    return None

start = (1, 2, 3,
         4, 0, 6,
         7, 5, 8)

goal = (1, 2, 3,
        4, 5, 6,
        7, 8, 0)

path = a_star_8_puzzle(start, goal)

print("\n8-Puzzle Steps to Goal:")
for step in path:
    print(step[0:3])
    print(step[3:6])
    print(step[6:9])
    print()

Tic-Tac-Toe Using Minimax

7. Tic Tac Toe using Minimax
def print_board(b):
    print(b[0], b[1], b[2])
    print(b[3], b[4], b[5])
    print(b[6], b[7], b[8])
    print()

def check_winner(b):
    win = [(0,1,2),(3,4,5),(6,7,8),
           (0,3,6),(1,4,7),(2,5,8),
           (0,4,8),(2,4,6)]
    for x,y,z in win:
        if b[x] == b[y] == b[z] and b[x] != ' ':
            return b[x]
    return None

def minimax(b, is_max):
    winner = check_winner(b)
    if winner == 'X': return 1
    if winner == 'O': return -1
    if ' ' not in b: return 0

    if is_max:  # AI's turn
        best = -10
        for i in range(9):
            if b[i] == ' ':
                b[i] = 'X'
                best = max(best, minimax(b, False))
                b[i] = ' '
        return best
    else:  # Human's turn
        best = 10
        for i in range(9):
            if b[i] == ' ':
                b[i] = 'O'
                best = min(best, minimax(b, True))
                b[i] = ' '
        return best

def ai_move(b):
    best = -10
    move = 0
    for i in range(9):
        if b[i] == ' ':
            b[i] = 'X'
            score = minimax(b, False)
            b[i] = ' '
            if score > best:
                best = score
                move = i
    b[move] = 'X'

def play():
    b = [' '] * 9
    print("Positions: 0 1 2 | 3 4 5 | 6 7 8")
    print_board(b)
    while True:
        m = int(input("Your move (0-8): "))
        if b[m] != ' ':
            print("Invalid move.")
            continue
        b[m] = 'O'
        if check_winner(b) or ' ' not in b: break
        ai_move(b)
        print_board(b)
        if check_winner(b) or ' ' not in b: break
    print_board(b)
    w = check_winner(b)
    if w: print(w, "wins!")
    else: print("It's a draw!")

play()

Simple Reflex Agent

SIMPLE REFLEX AGENT

import random
import time

sensor_inputs = ["Detected", "Not Detected"]

def automatic_door_agent(sensor_input):
    if sensor_input == "Detected":
        return "Open Door"
    else:
        return "Keep Door Closed"

def run_simulation():
    print("Automatic Door System Simulation:\n")
    for step in range(1, 6):
        sensor = random.choice(sensor_inputs)
        action = automatic_door_agent(sensor)
        print(f"Step {step}:")
        print(f"  Sensor Input   : {sensor}")
        print(f"  Agent's Action : {action}\n")
        time.sleep(1)

if __name__ == "__main__":
    run_simulation()

Chess AI

CHESS AI
import chess
import math

# Evaluate based on material balance
def evaluate_board(board):
    piece_values = {
        chess.PAWN: 1,
        chess.KNIGHT: 3,
        chess.BISHOP: 3,
        chess.ROOK: 5,
        chess.QUEEN: 9,
        chess.KING: 0
    }
    eval_score = 0
    for piece_type in piece_values:
        eval_score += len(board.pieces(piece_type, chess.WHITE)) * piece_values[piece_type]
        eval_score -= len(board.pieces(piece_type, chess.BLACK)) * piece_values[piece_type]
    return eval_score

def minimax(board, depth, alpha, beta, maximizing):
    if depth == 0 or board.is_game_over():
        return evaluate_board(board), None

    legal_moves = list(board.legal_moves)
    best_move = None

    if maximizing:
        max_eval = -math.inf
        for move in legal_moves:
            board.push(move)
            eval, _ = minimax(board, depth - 1, alpha, beta, False)
            board.pop()
            if eval > max_eval:
                max_eval = eval
                best_move = move
            alpha = max(alpha, eval)
            if beta <= alpha:
                break
        return max_eval, best_move
    else:
        min_eval = math.inf
        for move in legal_moves:
            board.push(move)
            eval, _ = minimax(board, depth - 1, alpha, beta, True)
            board.pop()
            if eval < min_eval:
                min_eval = eval
                best_move = move
            beta = min(beta, eval)
            if beta <= alpha:
                break
        return min_eval, best_move

def play_game():
    board = chess.Board()
    print("Welcome to Mini Chess AI!")
    print("You play as White. Enter moves in UCI format (e.g., e2e4)\n")

    while not board.is_game_over():
        print(board)
        user_move = input("Your move: ")

        try:
            move = chess.Move.from_uci(user_move)
            if move in board.legal_moves:
                board.push(move)
            else:
                print("Illegal move. Try again.")
                continue
        except:
            print("Invalid input. Try again.")
            continue

        if board.is_game_over():
            break

        print("\nAI is thinking...")
        _, ai_move = minimax(board, 3, -math.inf, math.inf, False)
        if ai_move:
            board.push(ai_move)
            print(f"AI plays: {ai_move}")
        else:
            print("AI has no valid moves.")
            break

    print("\nFinal Board:\n", board)
    result = board.result()
    if result == "1-0":
        print("You win!")
    elif result == "0-1":
        print("AI wins!")
    else:
        print("It's a draw!")

if __name__ == "__main__":
    play_game()

How to Run

How to run
pip install python-chess
python chess_ai.py