Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>Microsft Python IDENew to Visual Studio Code? Get it now.
Microsft Python IDE

Microsft Python IDE

Publisher1234

|
3,985 installs
| (1) | Free
Microsft Python IDE Environment
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

MicroSft IDE for Bison and Flex

https://github.com/Ishgar14/Artificial-Intelligence https://github.com/JyotBuch/ESE-Codes/tree/master/AI%20Assignments

1. Tic tac Magic Square

import random
import sys
from random import randint
computer_turn_counter = 0
def printBoard(board):
    print(' ' + board[1] + ' |' + board[2] + ' |' + board[3])
    print(' ' + board[4] + ' |' + board[5] + ' |' + board[6])
    print(' ' + board[7] + ' |' + board[8] + ' |' + board[9])
def isSpaceFree(board, move):
    if board[move] == ' ':
        return True
    else:
        False 
def my_custom_random(takenmoves):
    # Returns a valid move from the passed list on the passed board.
    # Returns None if there is no valid move.
    allmoves = [1,2,3,4,5,6,7,8,9]
    movesList = list(set(allmoves) - set(takenmoves))
    return random.choice(movesList)
def updateMove(board, letter , move):
    board[move] = letter
def getPlayerMove(board):
    # Let the player type in their move.
    move = ' '
    while move not in '1 2 3 4 5 6 7 8 9'.split() or not isSpaceFree(board, int(move)):
        print('What is your next move? (1-9)')
        move = input()
    return int(move)
def getComputersMove(board, computerletter, playerletter, dict ,list, computer_turn_counter):
    global magicboard
    checkforplayer = 0
    print("Comp Turns Completed : ",computer_turn_counter)
    #If First Time 
    if (computer_turn_counter == 0):
        move = my_custom_random(list )
        computer_turn_counter=+1
        return move , computer_turn_counter
    #Second Time
    if (computer_turn_counter == 1):
        computer_turn_counter= 2
        #try to get middle element
        if (isSpaceFree(board,5)):
            move = 5
            return 5 , computer_turn_counter
        else:
            checkforplayer = 1
    #Checks self wining chances
    if (computer_turn_counter and len(dict[computerletter]) > 1 ):
        print("|| In self wining chances ")
        computer_turn_counter=3
        length = len(dict[computerletter]) 
        for i in range(0,length - 1):
            #Formula 
            diff = 15 - (magicboard[ dict[computerletter][i] -1 ] + magicboard[ dict[computerletter][length - 1] - 1 ])
            print("The Diff: 15 - (",magicboard[ dict[computerletter][i] -1 ] ," + ",magicboard[ dict[computerletter][length - 1] - 1 ],"): " ,diff)
            if(diff in magicboard):
                checkforplayer = 1
            else:
                checkforplayer = 1
                continue
            index = magicboard.index(diff) + 1
            print("The Index to be placed at is : ", index )
            if (index <= 9 and index > 0):
                if isSpaceFree(board, index) :
                    print("Returned the Difference in self win")
                    return index  , computer_turn_counter
                else:
                    print("Cant Add , Position is Taken Already")
                    checkforplayer = 1
            else : 
                checkforplayer = 1
    #Checks to Defeat the Player
    if checkforplayer == 1:
        print("|| In Defeat the Player ")
        length = len(dict[playerletter]) 
        for i in range(0,length - 1):
            #Formula 
            diff = 15 - (magicboard[ dict[playerletter][i] -1 ] + magicboard[ dict[playerletter][length - 1] - 1 ] )
            print("The Diff: 15 - (",magicboard[ dict[playerletter][i] -1 ] ," + ",magicboard[ dict[playerletter][length - 1] - 1 ],"): " ,diff)
            if(magicboard.index(diff)):
                if(magicboard.index(diff) > 9 or magicboard.index(diff) <= 0):
                    checkforplayer = 1
                    continue
            index = magicboard.index(diff) + 1
            print("The Index to be placed at is : ", index )
            if (index <= 9 and index > 0):
                if isSpaceFree(board, index) :
                    print("Returned the Difference defeat player")
                    return index , computer_turn_counter
                else:
                    print("Cant Add , Position is Taken Already")
                    checkforplayer = 1
            else : 
                checkforplayer = 1
    computer_turn_counter = computer_turn_counter + 1
    return my_custom_random(list) , computer_turn_counter
def isWinner(bo, le):
     # Given a board and a player’s letter, this function returns True if that player has won.
     # We use bo instead of board and le instead of letter so we don’t have to type as much.
     return ((bo[7] == le and bo[8] == le and bo[9] == le) or # across the top
     (bo[4] == le and bo[5] == le and bo[6] == le) or # across the middle
     (bo[1] == le and bo[2] == le and bo[3] == le) or # across the bottom
     (bo[7] == le and bo[4] == le and bo[1] == le) or # down the left side
     (bo[8] == le and bo[5] == le and bo[2] == le) or # down the middle
     (bo[9] == le and bo[6] == le and bo[3] == le) or # down the right side
     (bo[7] == le and bo[5] == le and bo[3] == le) or # diagonal
     (bo[9] == le and bo[5] == le and bo[1] == le)) # diagonal
def makechoice():
    #TicTacToe()
    x = 1
    while(x):
        choice = input("Choose your Player X or O : ")
        if choice =="x" or choice=="X":
            print("Player has chosen X and will go First\n")
            x = 0
            playerletter = "X"
            computerletter = "O"
            turn = "player"
        elif choice =="O" or choice=="o":
            print("Player has chosen O , Bot will go First\n")
            x = 0
            playerletter = "O"
            turn = "computer"
            computerletter = "X"
        else:
            print("Not an option, IDIOT. Choose again.\n")
    return playerletter,computerletter,turn 
def isBoardFull(board):
    # Return True if every space on the board has been taken. Otherwise return False.
    for i in range(1, 10):
        if isSpaceFree(board, i):
            return False
    return True
magicboard = [8,3,4,
              1,5,9,
              6,7,2]
dict = {
    "X":[],
    "O":[]
}
LIST = []
board = [' '] * 10
playerletter,computerletter,turn = "X", "O", "player"
#playerletter,computerletter,turn = makechoice()
gamePlaying = True  
while gamePlaying:
    if turn =="player":
        #Player’s turn.
        printBoard(board)
        move = getPlayerMove(board)
        dict[playerletter].append(move )
        LIST.append(move)
        print(dict)
        updateMove(board,playerletter,move)
        if isWinner(board, playerletter):
               printBoard(board)
               print('****************** Hooray! You have won the game! ******************')
               sys.exit("Thank You For Playing!") 
               gameIsPlaying = False
        else:
            if isBoardFull(board):
                print('****************** The game is a tie! ****************** ')
                printBoard(board)
                sys.exit("Thank You For Playing!")
                break
            else:
                   turn = 'computer'
    else:
        #Computer's Turn
        move , computer_turn_counter = getComputersMove(board,computerletter ,playerletter, dict ,LIST , computer_turn_counter)
        dict[computerletter].append(move )
        LIST.append(move)
        print(dict)
        updateMove(board,computerletter,move)
        if isWinner(board, computerletter):
            printBoard(board)
            print('You Lost to a bOt! .')
            sys.exit("Thank You For Playing!")
            gameIsPlaying = False
        else:
            if isBoardFull(board):
                board(board)
                print('The game is a tie!')
                break
            else:
                turn = 'player'

Tic Tac Minimax

PLAYER_CHARACTER = 'O'
COMPUTER_CHARACTER = 'X'
board = {
    1: ' ', 2: ' ', 3: ' ',
    4: ' ', 5: ' ', 6: ' ',
    7: ' ', 8: ' ', 9: ' '
}
def display_board(board):
    print(
        board[1].center(5, ' ') + '|' + 
        board[2].center(5, ' ') + '|' + 
        board[3].center(5, ' ')
    )
    print('-' * 17)
    print(
        board[4].center(5, ' ') + '|' + 
        board[5].center(5, ' ') + '|' + 
        board[6].center(5, ' ')
    )
    print('-' * 17)
    print(
        board[7].center(5, ' ') + '|' + 
        board[8].center(5, ' ') + '|' + 
        board[9].center(5, ' ')
    )
    print('\n')
def is_free(pos):
    return board[pos] == ' '
def is_draw():
    for key in board.keys():
        if board[key] == ' ':
            return False
    return True
def somebody_won():
    # Row check
    if board[1] == board[2] and board[1] == board[3] and board[1] != ' ':
        return True
    elif board[4] == board[5] and board[4] == board[6] and board[4] != ' ':
        return True
    elif board[7] == board[8] and board[7] == board[9] and board[7] != ' ':
        return True
    # Column check
    elif board[1] == board[4] and board[1] == board[7] and board[1] != ' ':
        return True
    elif board[2] == board[5] and board[2] == board[8] and board[2] != ' ':
        return True
    elif board[3] == board[6] and board[3] == board[9] and board[3] != ' ':
        return True
    # Diagonal check
    elif board[1] == board[5] and board[1] == board[9] and board[1] != ' ':
        return True
    elif board[7] == board[5] and board[7] == board[3] and board[7] != ' ':
        return True
    else:
        return False
def has_won(mark):
    # Row check
    if board[1] == board[2] and board[1] == board[3] and board[1] == mark:
        return True
    elif board[4] == board[5] and board[4] == board[6] and board[4] == mark:
        return True
    elif board[7] == board[8] and board[7] == board[9] and board[7] == mark:
        return True
    # Column check
    elif board[1] == board[4] and board[1] == board[7] and board[1] == mark:
        return True
    elif board[2] == board[5] and board[2] == board[8] and board[2] == mark:
        return True
    elif board[3] == board[6] and board[3] == board[9] and board[3] == mark:
        return True
    # Diagoanl check
    elif board[1] == board[5] and board[1] == board[9] and board[1] == mark:
        return True
    elif board[7] == board[5] and board[7] == board[3] and board[7] == mark:
        return True
    else:
        return False
def putchar(character, position):
    if is_free(position):
        board[position] = character
        display_board(board)
        if is_draw():
            print("\nIt was a tie 👨🤝💻")
            exit()
        if somebody_won():
            if character == COMPUTER_CHARACTER:
                print("\nThe computer wins 💻")
            else:
                print("\nThe player wins 🤴")
            exit()
    else:
        print("This slot is already used!")
        position = int(input("Enter new position: "))
        putchar(character, position)
def get_player_move():
    print(" Player's Turn ".center(40, '='))
    pos = int(input("Enter the position for 'O': "))
    putchar(PLAYER_CHARACTER, pos)
def get_computer_move():
    print(" Computer's Turn ".center(40, '='))
    best_score = -100
    best_move = 0
    for key in board.keys():
        if board[key] != ' ':
            continue
        board[key] = COMPUTER_CHARACTER
        score = minimax(board, False)
        board[key] = ' '
        if score > best_score:
            best_score = score
            best_move = key
        print(f"Computer found move {best_move} with score {best_score}")
    print(f"Computer picks move {best_move} with score {best_score}")
    putchar(COMPUTER_CHARACTER, best_move)
def minimax(board, maximising):
    if has_won(COMPUTER_CHARACTER):
        return 10
    if has_won(PLAYER_CHARACTER):
        return -10
    elif is_draw():
        return 0
    if maximising:
        bestScore = -1000
        for key in board.keys():
            if board[key] == ' ':
                board[key] = COMPUTER_CHARACTER
                score = minimax(board, False)
                board[key] = ' '
                if score > bestScore:
                    bestScore = score
        return bestScore
    else:
        bestScore = 1000
        for key in board.keys():
            if board[key] == ' ':
                board[key] = PLAYER_CHARACTER
                score = minimax(board, True)
                board[key] = ' '
                if score < bestScore:
                    bestScore = score
        return bestScore
def main():
    display_board(board)
    first = input("Do you wish to play first (Y/N): ").strip().upper()
    turn = first == 'Y'
    while not somebody_won():
        if turn:
            get_player_move()
        else:
            get_computer_move()
        turn = not turn
if __name__ == '__main__':
    main()

N queens

STUCK = 0
DONE  = 1
steps = 0
def generate(size):
    square = []
    # Generate a square of dimensions `size`
    for _ in range(size):
        listofzeros = [0] * size
        square.append(listofzeros)
    #print(square)
    return square
# This function reutrns true if given position is safe for new queen
def is_safe(board: list, row: int, col: int) -> bool:
    # Check the row
    for i in range(len(board)):
        if board[row][i] == 1:
            return False
    # Check the column
    for i in range(len(board)):
        if board[i][col] == 1:
            return False
    # Check the left diagonal
    for difference in range(1, len(board)):
        _row = row - difference
        _col = col - difference
        if _row < 0 or _col < 0:
            break
        if board[_row][_col] == 1:
            return False
    for difference in range(1, len(board)):
        _row = row + difference
        _col = col + difference
        if _row >= len(board) or _col >= len(board):
            break
        if board[_row][_col] == 1:
            return False
    # Check the right diagonal
    for difference in range(1, len(board)):
        _row = row + difference
        _col = col - difference
        if _row >= len(board) or _col < 0:
            break
        if board[_row][_col] == 1:
            return False
    for difference in range(1, len(board)):
        _row = row - difference
        _col = col + difference
        if _row < 0 or _col >= len(board):
            break
        if board[_row][_col] == 1:
            return False
    return True
# This function takes board and row and returns all safe column spots of that row
def get_all_safe_spots(board: list, row: int) -> list:
    spots = []
    for column in range(len(board)):
        if is_safe(board, row, column):
            spots.append(column)
    return spots
def solve(board, row: int = 0):
    if row >= len(board):
        return DONE
    global steps
    print("\n", f" Step {steps} ".center(20, '='))
    display_board(board)
    steps += 1
    spots = get_all_safe_spots(board, row)
    if len(spots) == 0:
        print("No safe spots left for current queen!")
        return STUCK
    for i in range(len(board)):
        if i not in spots:
            print(f"Skipping column {i + 1} because it is not safe")
            continue
        spot = i
        board[row][spot] = 1
        # If we can't place next queen then backtrack and select next position for current queen
        if solve(board, row + 1) == STUCK:
            print(f"Backtracking from row {row + 1} column {spot + 1} ..")
            board[row][spot] = 0
        else:
            # If every position of queen is filled then its done
            if sum([sum(row) for row in board]) == len(board):
                print("\n", f" Step {steps} ".center(20, '='))
                display_board(board)
                exit()
    # If every position of queen is filled then its done
    if sum([sum(row) for row in board]) == len(board):
        return DONE
    else:
        # Otherwise backtrack
        print(f"Backtracking from row {row + 1} column {spot + 1} ...")
        return STUCK
def display_board(board: list, special: bool = True) -> None:
    if not special:
        for i in range(len(board)):
            for j in range(len(board)):
                if board[i][j] == 1:
                   print('{:3}'.format(1), end='')
                else:
                    print('{:>3}'.format('.'), end='')
            print()
        return
    for i in range(len(board)):
        solid = i % 2 == 0
        for j in range(len(board)):
            if board[i][j] == 1:
                print('{:>3}'.format('👑'), end='')
            else:
                if solid:
                    print('{:>3}'.format('⬛'), end='')
                else:
                    print('{:>3}'.format('⬜'), end='')
            solid = not solid
        print()
def main():
    size  = int(input("Enter size of chessboard: "))
    board = generate(size)
    if solve(board) == STUCK:
        print("\nThere are no valid queen positions for given dimensions of board")
        return
    print("\n", " Finally ".center(20, '='))
    display_board(board, True)
if __name__ == '__main__':
    main()

Magic Square

def generate(size: int) -> list:
    EMPTY = 0
    square = []
    # Generate a square of dimensions `size`
    for _ in range(size):
        buffer = []
        for _ in range(size):
            buffer.append(EMPTY)
        square.append(buffer)
    counter = 1
    row = 0
    col = len(square) // 2
    # Pick middle of first row as 1
    square[row][col] = counter
    while counter != size ** 2:
        print("\n", f" Step {counter} ".center(20, '='), sep='')
        display(square)
        counter       += 1
        cyclic_row    = row - 1
        cyclic_column = col + 1
        cyclic_row    = cycle(cyclic_row, size)
        cyclic_column = cycle(cyclic_column, size)
        # Check if North-East slot is available
        if square[cyclic_row][cyclic_column] == 0:
            square[cyclic_row][cyclic_column] = counter
            row, col = cyclic_row, cyclic_column
        else:
            # Otherwise go South
            row += 1
            square[row][col] = counter
    return square
# For verbosity ... The entire thing could've been a single % opeartion lmao
def cycle(number: int, size: int) -> int:
    if number == size:
        return 0
    elif number > size:
        return number % size
    elif number < 0:
        number *= -1
        number %= size
        number = size - number
        return number
    else:
        return number
def display(board: list) -> None:
    for row in board:
        for col in row:
            print('{:5}'.format(col), end='')
        print()
def main():
    while True:
        size = int(input("Enter size of square: "))
        if size % 2 == 0:
            print("Please type an odd number!")
            continue
        board = generate(size)
        print("\n", f" Step {size ** 2} ".center(20, '='))
        display(board)
        break
if __name__ == '__main__':
    main()

Assn2

Water Jug BFS

LEFT_BUCKET_CAPACITY = 4
RIGHT_BUCKET_CAPACITY = 3
GOAL = (0, 2)
RESULT = []
def move_left_to_right(jug):
    allowed_space = min(RIGHT_BUCKET_CAPACITY - jug[1], jug[0])
    return (jug[0] - allowed_space, jug[1] + allowed_space)
def move_right_to_left(jug):
    allowed_space = min(LEFT_BUCKET_CAPACITY - jug[0], jug[1])
    return (jug[0] + allowed_space, jug[1] - allowed_space)
def empty_left(jug):
    return (0, jug[1])
def empty_right(jug):
    return (jug[0], 0)
def fill_left(jug):
    return (LEFT_BUCKET_CAPACITY, jug[1])
def fill_right(jug):
    return (jug[0], RIGHT_BUCKET_CAPACITY)
def get_available_operations(jug):
    operations = {
        move_left_to_right,
        move_right_to_left,
        empty_left,
        empty_right,
        fill_left,
        fill_right
    }
    # if left jug is empty
    if jug[0] == 0:
        operations.remove(empty_left)
        operations.remove(move_left_to_right)
    # if left jug is full
    elif jug[0] == LEFT_BUCKET_CAPACITY:
        operations.remove(fill_left)
        operations.remove(move_right_to_left)
    # if right jug is empty
    if jug[1] == 0:
        operations.remove(empty_right)
        try: operations.remove(move_right_to_left)
        except KeyError: pass
    # if right jug is full
    elif jug[1] == RIGHT_BUCKET_CAPACITY:
        operations.remove(fill_right)
        try: operations.remove(move_left_to_right)
        except KeyError: pass
    return operations
def get_operation_name(operation) -> str:
    return {
        fill_left: 'fill left jug',
        fill_right: 'fill right jug',
        empty_left: 'empty left jug',
        empty_right: 'empty right jug',
        move_left_to_right: 'pour left jug into right jug',
        move_right_to_left: 'pour right jug into left jug',
    }[operation]
class Node:
    def __init__(self, jug: tuple[int, int], parent = None, operation_name: str = None) -> None:
        self.jug = jug
        self.parent = parent
        self.operation_name = operation_name
def grow_tree(parent: Node, previous = {(0, 0)}) -> bool:
    queue = [parent]
    opened = []
    closed = []
    level = 1
    while len(queue) != 0:
        node = queue.pop(0) # Remove first elemnt from queue
        opened.append(node.jug)
        operations = get_available_operations(node.jug)
        # Iterate over all operations for current node
        # Assign the child nodes to parent
        for op in operations:
            child_jug = op(node.jug)
            child = Node(child_jug, node, get_operation_name(op))
            closed.append(child_jug)
            if child_jug == GOAL:
                RESULT.append(child)
                return True
            if child_jug in previous:
                continue
            else:
                previous.add(child_jug)
            queue.append(child)
        print(f" At breadth level {level} ".center(40, '='))
        print("Opened list: ", opened)
        print("Closed list: ", closed, end='\n\n')
        level += 1
    return False
def main():
    seed = Node((0, 0))
    if grow_tree(seed):
        print("=" * 40)
        print("The full path is")
        for endpoint in RESULT:
            path = []
            operations: list[str] = []
            while endpoint.parent:
                path.append(endpoint.jug)
                operations.append(endpoint.operation_name)
                endpoint = endpoint.parent
            path = list(reversed(path))
            operations = list(reversed(operations))
            print("From (0, 0)")
            for i, _ in enumerate(path):
                print(f'Step {i + 1}   {operations[i].ljust(30)} => {path[i]}')
    else:
        print("Could not reach the goal", GOAL)
if __name__ == '__main__':
    main()
    # For (0, 2)
    # (0, 0) -> (0, 3) -> (3, 0) -> (3, 3) -> (4, 2) -> (0, 2)

Water Jug DFS

def LevelOrderTraversal(root):
    if (root == None):
        return;
    # Standard level order traversal code
    # using queue
    q = []  # Create a queue
    q.append(root); # Enqueue root
    while (len(q) != 0):
        n = len(q);
        # If this node has children
        while (n > 0):
            # Dequeue an item from queue and print it
            p = q[0]
            q.pop(0)
            print(p.list, end=' ')
            # Enqueue all children of the dequeued item
            for i in range(len(p.child)):
                q.append(p.child[i]);
            n -= 1
        print() # Print new line between two levels
        print("-------")
def fill4LitreJug(list):
    if list[0] == 4:
        return False
    list[0] = 4
    return list
def fill3LitreJug(list):
    if list[1] == 3:
        return False
    list[1] = 3
    return list
def empty3(list):
    listt = list.copy()
    if listt[1] == 0:
        return False
    listt[1] = 0
    return listt
def empty4(list):
    listt = list.copy()
    if listt[0] == 0:
        return False
    listt[0] = 0
    return listt
def transferFrom_3to4(listt):
    if listt[0]==4:
        return False
    elif listt[1] == 0:
        return False
    elif listt[0] < 4:
        if (4 - listt[0]) >= listt[1]:
            listt[0] = listt[0] + listt[1]
            listt[1] = 0
        else:
            #avail = 2 , hai second mei 3
            emptySpace = 4 - listt[0]
            listt[1] = listt[1] - emptySpace
            listt[0] = listt[0] + emptySpace
    return listt
def transferFrom_4to3(listt):
    if listt[1]==3:
        return False
    elif listt[0] == 0:
        return False
    elif listt[1] < 3:
        if (3 - listt[1]) >= listt[0]:
            listt[1] = listt[1] + listt[0]
            listt[0] = 0
        else:
            #avail = 2 , hai second mei 3
            emptySpace = 3 - listt[1]
            listt[0] = listt[0] - emptySpace
            listt[1] = listt[1] + emptySpace
    return listt
GOAL = [2,0]
class Node:
    def __init__(self, list):
        self.list = list
        self.child = []
        self.myParents = []
 # Utility function to create a new tree node
def newNode(key):   
    temp = Node(key)
    return temp
# Prints the n-ary tree level wise
answerslist = []
#list = [0 , 0]
#-------------------------------------------------------------------
def findOptimalPath(node):
    if node.myParents:
        if node.myParents[-1] ==GOAL:
            #print("--",node.myParents[-1],"--")
            answerslist.append(node.myParents)
    if node.list in node.myParents:
        return
    childrenlist = []
    #print("Passed Node: ",node.list)
    list1 = empty4((node.list).copy())
    list2 = empty3((node.list).copy())
    list3 = transferFrom_3to4((node.list).copy())
    list4 = transferFrom_4to3((node.list).copy())
    list5 = fill4LitreJug((node.list).copy())
    list6 = fill3LitreJug((node.list).copy())
    #print("lists: ", list1, list2 ,list3, list4 , list5 , list6)
    childrenlist.extend((list1, list2, list3,list4,list5,list6))
    childrenlist = [x for x in childrenlist if x is not False]
    #print("Childrenlist: ",childrenlist)
    #print("\n")
    for i in range(0,len(childrenlist)):
        (node.child).append(newNode(childrenlist[i]))
        node.child[i].myParents.extend(node.myParents)
        node.child[i].myParents.append(node.list)
        if node.child[i].myParents[-1] ==GOAL:
            answerslist.append(node.child[i].myParents)
            return
        #print("myParents: ", i +1," : ", node.child[i].myParents )
        findOptimalPath(node.child[i])
    return
#-------------------------------------------------------------------
# WE START HERE !  ----- 
mainlist= [0, 0]
root = newNode(mainlist)
findOptimalPath(root)
#print("AnswersList: ", answerslist)
print("AnswersList")
print('\n'.join(map(str, answerslist)))
smallest = []
for i in answerslist:
    smallest.append(len(i))
print("\nThe Most Optimal Path to this Water Jug Problem is :\n", answerslist[smallest.index(min(smallest))])
#---
# RunTime Values
# Infinity to 0.9s to 0.5s to 0.1s
LevelOrderTraversal(root)

Rush dfs

LEFT_BUCKET_CAPACITY = 4
RIGHT_BUCKET_CAPACITY = 3
GOAL = (0, 2)
RESULT = []
def move_left_to_right(jug) -> tuple[int, int]:
    allowed_space = min(RIGHT_BUCKET_CAPACITY - jug[1], jug[0])
    return (jug[0] - allowed_space, jug[1] + allowed_space)
def move_right_to_left(jug) -> tuple[int, int]:
    allowed_space = min(LEFT_BUCKET_CAPACITY - jug[0], jug[1])
    return (jug[0] + allowed_space, jug[1] - allowed_space)
def empty_left(jug) -> tuple[int, int]:
    return (0, jug[1])
def empty_right(jug) -> tuple[int, int]:
    return (jug[0], 0)
def fill_left(jug) -> tuple[int, int]:
    return (LEFT_BUCKET_CAPACITY, jug[1])
def fill_right(jug) -> tuple[int, int]:
    return (jug[0], RIGHT_BUCKET_CAPACITY)
def get_available_operations(jug):
    operations = {
        move_left_to_right,
        move_right_to_left,
        empty_left,
        empty_right,
        fill_left,
        fill_right
    }
    # if left jug is empty
    if jug[0] == 0:
        operations.remove(empty_left)
        operations.remove(move_left_to_right)
    # if left jug is full
    elif jug[0] == LEFT_BUCKET_CAPACITY:
        operations.remove(fill_left)
        operations.remove(move_right_to_left)
    # if right jug is empty
    if jug[1] == 0:
        operations.remove(empty_right)
        try: operations.remove(move_right_to_left)
        except KeyError: pass
    # if right jug is full
    elif jug[1] == RIGHT_BUCKET_CAPACITY:
        operations.remove(fill_right)
        try: operations.remove(move_left_to_right)
        except KeyError: pass
    return operations
def get_operation_name(operation) -> str:
    return {
        fill_left: 'fill left jug',
        fill_right: 'fill right jug',
        empty_left: 'empty left jug',
        empty_right: 'empty right jug',
        move_left_to_right: 'pour left jug into right jug',
        move_right_to_left: 'pour right jug into left jug',
    }[operation]
class Node:
    def __init__(self, jug: tuple[int, int], operation_name: str = None) -> None:
        self.jug = jug
        self.children: list[Node] = []
        self.operation_name = operation_name
    def __eq__(self, other):
        if isinstance(other, Node):
            return self.jug == other.jug
        elif isinstance(other, tuple):
            return self.jug == other
        else:
            return False
    def __repr__(self) -> str:
        return str(self.jug)
def grow_tree(node: Node, previous = {(0, 0)}, maxdepth = 10, 
            opened: list[tuple[int, int]] = [], closed: list[tuple[int, int]] = []
        ) -> bool:
    if maxdepth == 0:
        return False
    operations = get_available_operations(node.jug)
    for _op in operations:
        closed.append(_op(node.jug))
    opened.append(node.jug)
    closed = [val for i, val in enumerate(closed) if val not in opened and val not in closed[:i]]
    print("\n", f" At depth level {10 - maxdepth} ".center(40, '='), sep='')
    print("Opened list: ", opened)
    print("Closed list: ", closed, end='\n\n')
    for op in operations:
        child = op(node.jug)
        if child == GOAL:
            RESULT.append(Node(GOAL, get_operation_name(op)))
            return True
        if child in previous:
            continue
        else:
            previous.add(child)
        node.children.append(Node(child, get_operation_name(op)))
        if grow_tree(node.children[-1], previous, maxdepth - 1, opened, closed):
            RESULT.append(node.children[-1])
            return True
        else:
            node.children.pop()
    return False
# This function prunes the nodes which can be reached directly by root (0, 0)
def optimise(result: list[Node]) -> list[Node]:
    operations = get_available_operations((0, 0))
    for op in operations:
        child = op((0, 0))
        try:
            index = result.index(child)
            result = result[index:]
        except ValueError:
            pass
    return result
def main():
    seed = Node((0, 0))
    if grow_tree(seed):
        print('=' * 40)
        print("The full path is")
        print("From (0, 0)".rjust(49))
        result = list(reversed(RESULT))
        result = optimise(result)
        for i, node in enumerate(result):
            print(f'Step {i + 1}   {node.operation_name.ljust(30)} => {node.jug}')
    else:
        print("Could not reach the goal", GOAL)
if __name__ == '__main__':
    main()
    # For (0, 2)
    # (0, 0) -> (0, 3) -> (3, 0) -> (3, 3) -> (4, 2) -> (0, 2)

Assn3

8 puzzle Hill Climbing

GOAL = {
    1: 1, 2: 2, 3: 3,
    4: 8, 5: -1, 6: 4,
    7: 7, 8: 6, 9: 5,
}
t_board = dict[int, int]
#  ============================= Helper Functions ==================================
class Node:
    def __init__(self, board: dict[int, int], steps: int, prev=None, op=None):
        self.board = board.copy()
        self.steps = steps
        self.prev = prev
        self.operation = op
    def __eq__(self, other):
        return self.board == other.board
    def __hash__(self) -> int:
        return heuristic(self.board)
    def __repr__(self):
        return str(heuristic(self.board))
    def heu(self) -> int:
        return self.steps + heuristic(self.board)
def get_empty_pos(puzzle: t_board) -> int:
    for key in puzzle:
        if puzzle[key] == -1:
            return key
def move_up(puzzle: t_board):
    pos = get_empty_pos(puzzle)
    puzzle[pos], puzzle[pos - 3] = puzzle[pos - 3], puzzle[pos]
    return puzzle
def move_down(puzzle: t_board):
    pos = get_empty_pos(puzzle)
    puzzle[pos], puzzle[pos + 3] = puzzle[pos + 3], puzzle[pos]
    return puzzle
def move_right(puzzle: t_board):
    pos = get_empty_pos(puzzle)
    puzzle[pos], puzzle[pos + 1] = puzzle[pos + 1], puzzle[pos]
    return puzzle
def move_left(puzzle: t_board):
    pos = get_empty_pos(puzzle)
    puzzle[pos], puzzle[pos - 1] = puzzle[pos - 1], puzzle[pos]
    return puzzle
def get_available_operations(puzzle: t_board):
    operations = {
        move_up,
        move_left, move_right,
        move_down,
    }
    empty_pos = get_empty_pos(puzzle)
    if empty_pos in {1, 2, 3}:
        operations.remove(move_up)
    if empty_pos in {7, 8, 9}:
        operations.remove(move_down)
    if empty_pos in {3, 6, 9}:
        operations.remove(move_right)
    if empty_pos in {1, 4, 7}:
        operations.remove(move_left)
    return operations
def get_operation_name(op):
    return {
        move_up: "Move the empty slot above",
        move_left: "Move the empty slot left",
        move_right: "Move the empty slot right",
        move_down: "Move the empty slot down",
    }[op]
# This function takes a board and returns heuristic value of it
# Heuristic is how many board are misplaced
def heuristic(puzzle: t_board) -> int:
    score = 0
    for key in puzzle:
        if puzzle[key] != GOAL[key]:
            score += 1
    return score
def safe_get(puzzle: t_board, key: int) -> str:
    if puzzle[key] != -1:
        return puzzle[key]
    return '@'
def display_board(puzzle: dict[int, int]):
    print(
        str(safe_get(puzzle, 1)).center(3, ' ') +
        str(safe_get(puzzle, 2)).center(3, ' ') +
        str(safe_get(puzzle, 3)).center(3, ' ')
    )
    print('-' * 10)
    print(
        str(safe_get(puzzle, 4)).center(3, ' ') +
        str(safe_get(puzzle, 5)).center(3, ' ') +
        str(safe_get(puzzle, 6)).center(3, ' ')
    )
    print('-' * 10)
    print(
        str(safe_get(puzzle, 7)).center(3, ' ') +
        str(safe_get(puzzle, 8)).center(3, ' ') +
        str(safe_get(puzzle, 9)).center(3, ' ')
    )
# ========================= Actual Hill Climbing Logic ====================================
def start(puzzle) -> Node:
    root = Node(puzzle, 0)
    queue = [root]
    steps = 0
    previous = set()
    best_score = 1000
    while len(queue) > 0:
        steps += 1
        queue.sort(key=lambda n: n.heu())
        current = queue.pop(0)
        score = heuristic(current.board)
        if score == 0:
            return current
        if current in previous:
            # print("Skipping current state because it was repeated previously ...")
            continue
        else:
            previous.add(current)
        if score < best_score:
            best_score = score
        for operation in get_available_operations(current.board):
            child = Node(operation(current.board.copy()), steps, current, operation)
            queue.append(child)
    return current
def main():
    puzzle = {
        1: 1, 2: -1, 3: 3,
        4: 8, 5: 2, 6: 6,
        7: 7, 8: 5, 9: 4,
    }
    print("The initial board configuration is ")
    display_board(puzzle)
    print(f"The heuristic of this board is {heuristic(puzzle)}")
    node = start(puzzle)
    path: list[Node] = []
    while node:
        path.append(node)
        node = node.prev
    path = path[::-1]
    path = path[1:]
    for i, node in enumerate(path):
        print(f" Step {i + 1} ".center(40, '='))
        if node.operation:
            print(get_operation_name(node.operation))
        display_board(node.board)
        print(f"The heuristic of this board is {heuristic(node.board)}")
        # print(f"The f(x) of this board is {node.heu()}")
    if heuristic(path[-1].board) != 0:
        print("Not found ideal board position")
    else:
        print("This is the required solution✅")
if __name__ == '__main__':
    main()

Assn4

Astar

Astar - Robot Nav

# Board Contents
EMPTY = 0
WALL = 1
SELECTED = 2
class Node:
    def __init__(self, x, y, prev = None):
        self.x = x
        self.y = y
        self.prev = prev
    def __eq__(self, other):
        if isinstance(other, Node):
            return self.x == other.x and self.y == other.y
        elif isinstance(other, tuple):
            return self.x == other[0] and self.y == other[1]
    def __repr__(self):
        return str((self.x, self.y))
    def __hash__(self):
        return (self.x, self.y).__hash__()
    def man_dist(self, to) -> int:
        return abs(self.x - to.x) + abs(self.y - to.y)
    def heu(self, goal) -> int:
        return self.man_dist(goal)
    def neighbours(self, board) -> list:
        neigh = [
            # No diagonal neighbours
            (self.x, self.y - 1), # Top
            (self.x - 1, self.y), # Left
            (self.x + 1, self.y), # Right
            (self.x, self.y + 1), # Bottom
        ]
        ugly_neighbours = []
        for n in neigh:
            x, y = n
            if x < 0 or y < 0:
                ugly_neighbours.append((x, y))
            elif x >= len(board) or y >= len(board[0]):
                ugly_neighbours.append((x, y))
            elif board[x][y] == WALL:
                ugly_neighbours.append((x, y))
        for ugly in ugly_neighbours:
            neigh.remove(ugly)
        return [Node(n[0], n[1], self) for n in neigh]
# Defining custom type
Board = list[list[Node]]
def display_board(board, initial: Node, goal: Node) -> None:
    print('', '-' * len(board[0] * 3))
    for i, row in enumerate(board):
        print(end='|')
        for j, col in enumerate(row):
            if Node(i, j) == initial:
                ch='S'
            elif Node(i, j) == goal:
                ch='E'
            elif col == EMPTY:
                ch=' '
            elif col == WALL:
                ch='#'
            elif col == SELECTED:
                ch='.'
            print("{:>3}".format(ch), end='')
        print(end='|\n')
    print('', '-' * len(board[0]) * 3)
def start(board, initial: Node, goal: Node) -> Node:
    opened = []
    closed = [Node(initial.x, initial.y)]
    # Create a copy of board to display the steps of A*
    d_board = []
    for row in board:
        d_board.append([])
        for col in row:
            d_board[-1].append(col)
    # Actual A* Logic
    previous = set()
    while len(closed) > 0:
        closed.sort(key = lambda n: n.heu(initial) + n.heu(goal))
        current = closed.pop(0)
        opened.append(current)
        if current in previous:
            continue
        else:
            previous.add(current)
        d_board[current.x][current.y] = SELECTED
        print('=' * 40)
        print("Open List:", opened)
        print("Close List:", closed)
        print("\n\nCurrently selected ({}, {})".format(current.x, current.y))
        display_board(d_board, initial, goal)
        if current == goal:
            print("Reached goal!")
            break
        for neighbour in current.neighbours(board):
            if neighbour not in previous:
                closed.append(neighbour)
    return current
# For test case validity check
def safety_check(board, initial: tuple[int, int], goal: tuple[int, int]):
    if board[initial[0]][initial[1]] == WALL:
        raise ValueError("Initial Position cannot be a wall")
    if board[goal[0]][goal[1]] == WALL:
        raise ValueError("Goal Position cannot be a wall")
def main():
    board = [
        [0, 0, 0, 0, 0, 0, 0, 0, 0,],
        [0, 1, 0, 0, 1, 1, 1, 1, 0,],
        [0, 1, 0, 0, 0, 0, 0, 1, 0,],
        [0, 0, 1, 1, 1, 1, 1, 1, 0,],
        [0, 0, 0, 0, 0, 0, 0, 0, 0,],
    ]
    initial = (3, 0)
    goal = (2, 5)
    safety_check(board, initial, goal)
    end = start(board, Node(initial[0], initial[1]), Node(goal[0], goal[1]))
    print("\nThe best path is ")
    path = []
    while end:
        path.append((end.x, end.y))
        end = end.prev
    # Create a copy of board
    d_board = []
    for row in board:
        d_board.append([])
        for col in row:
            d_board[-1].append(col)
    # mutate it with path found
    for (x, y) in path:
        d_board[x][y] = SELECTED
    display_board(d_board, initial, goal)
if __name__ == '__main__':
    main()

Astar - City Dist

SOURCE = "Latur"
DESTINATION = "Navi Mumbai"
DISTANCE_FROM_DESTINATION = {
    "Solapur": 340,
    "Satara": 177,
    "Navi Mumbai": 0,
    "Nashik": 133,
    "Ahmednagar": 180,
    "Aurangabad": 265,
    "Nanded": 451,
    "Latur": 373,
    "Pune": 105,
}
# A weighted undirected map of cities
GRAPH = {}
def put_city(city1: str, city2: str, weight: int) -> None:
    global GRAPH
    if city1 in GRAPH:
        GRAPH[city1].append((city2, weight))
    else:
        GRAPH[city1] = [(city2, weight)]
    if city2 in GRAPH:
        GRAPH[city2].append((city1, weight))
    else:
        GRAPH[city2] = [(city1, weight)]
def generate_map() -> None:
    put_city("Pune", "Navi Mumbai", 106)
    put_city("Pune", "Satara", 112)
    put_city("Pune", "Solapur", 234)
    put_city("Solapur", "Satara", 203)
    put_city("Solapur", "Latur", 104)
    put_city("Nanded", "Latur", 113)
    put_city("Nanded", "Aurangabad", 221)
    put_city("Nashik", "Aurangabad", 159)
    put_city("Nanded", "Ahmednagar", 267)
    put_city("Pune", "Ahmednagar", 120)
    put_city("Nashik", "Pune", 165)
    put_city("Nashik", "Navi Mumbai", 136)
def distance(from_: str, to: str) -> int:
    if from_ == to:
        return 0
    array = GRAPH[from_]
    for name, weight in array:
        if name == to:
            return weight
    return 10 ** 10
class Node:
    def __init__(self, city: str, prev: object, weight: int) -> None:
        self.city = city
        self.prev = prev
        self.weight = weight
    def __repr__(self) -> str:
        return self.city
    def __eq__(self, other) -> bool:
        if isinstance(other, Node):
            return self.city == other.city
        elif isinstance(other, str):
            return self.city == other
        else:
            return False
def objective(city, parent) -> int:
    return distance(city, parent) + DISTANCE_FROM_DESTINATION[city]
def main() -> None: 
    generate_map()
    print('=' * 40)
    print("Starting city is Latur")
    print("Destination city is Navi Mumbai")
    # from pprint import pprint
    # pprint(GRAPH)
    current = Node(SOURCE, None, 0)
    opened = []
    closed = [current]
    while len(closed) > 0:
        print('=' * 40)
        print("Opened list:", opened)
        print("Closed list:", closed)
        closed.sort(
                key=lambda node: objective(node.city, current),
                reverse=True
        )
        current = closed.pop()
        if current not in opened:
            opened.append(current)
        if current == DESTINATION:
            print("🎉We got there!🎉".center(40, ' '))
            break
        print("Selected", current)
        # Add all neighbours of current city into queue
        print(f"The neighbouring cities of {current} are")
        for name, dist in GRAPH[current.city]:
            print(f"{name:>12} with distance {dist}")
            if name not in opened:
                closed.append(Node(name, current, dist))
        print()
    path = []
    while current:
        path.append(current)
        current = current.prev
    print("=" * 40)
    print("The full path is ")
    for city in path[::-1]:
        if city.prev:
            print(f"{city.prev.city} to {city.city} with distance {city.weight}")
if __name__ == '__main__':
    main()

Astar - 8puzzle

GOAL = {
    1: 1, 2: 2, 3: 3,
    4: 8, 5: -1, 6: 4,
    7: 7, 8: 6, 9: 5,
}
t_board = dict[int, int]
#  ============================= Helper Functions ==================================
class Node:
    def __init__(self, board: dict[int, int], steps: int, prev=None, op=None):
        self.board = board.copy()
        self.steps = steps
        self.prev = prev
        self.operation = op
    def __eq__(self, other):
        return self.board == other.board
    def __hash__(self) -> int:
        return heuristic(self.board)
    def __repr__(self):
        return str(self.heu())
    def heu(self) -> int:
        return self.steps + heuristic(self.board)
def get_empty_pos(puzzle: t_board) -> int:
    for key in puzzle:
        if puzzle[key] == -1:
            return key
def move_up(puzzle: t_board):
    pos = get_empty_pos(puzzle)
    puzzle[pos], puzzle[pos - 3] = puzzle[pos - 3], puzzle[pos]
    return puzzle
def move_down(puzzle: t_board):
    pos = get_empty_pos(puzzle)
    puzzle[pos], puzzle[pos + 3] = puzzle[pos + 3], puzzle[pos]
    return puzzle
def move_right(puzzle: t_board):
    pos = get_empty_pos(puzzle)
    puzzle[pos], puzzle[pos + 1] = puzzle[pos + 1], puzzle[pos]
    return puzzle
def move_left(puzzle: t_board):
    pos = get_empty_pos(puzzle)
    puzzle[pos], puzzle[pos - 1] = puzzle[pos - 1], puzzle[pos]
    return puzzle
def get_available_operations(puzzle: t_board):
    operations = {
        move_up,
        move_left, move_right,
        move_down,
    }
    empty_pos = get_empty_pos(puzzle)
    if empty_pos in {1, 2, 3}:
        operations.remove(move_up)
    if empty_pos in {7, 8, 9}:
        operations.remove(move_down)
    if empty_pos in {3, 6, 9}:
        operations.remove(move_right)
    if empty_pos in {1, 4, 7}:
        operations.remove(move_left)
    return operations
def get_operation_name(op):
    return {
        move_up: "Move the empty slot above",
        move_left: "Move the empty slot left",
        move_right: "Move the empty slot right",
        move_down: "Move the empty slot down",
    }[op]
# This function takes a board and returns heuristic value of it
# Heuristic is how many board are misplaced
def heuristic(puzzle: t_board) -> int:
    score = 0
    for key in puzzle:
        if puzzle[key] != GOAL[key]:
            score += 1
    return score
def safe_get(puzzle: t_board, key: int) -> str:
    if puzzle[key] != -1:
        return puzzle[key]
    return '@'
def display_board(puzzle: dict[int, int]):
    print(
        str(safe_get(puzzle, 1)).center(3, ' ') +
        str(safe_get(puzzle, 2)).center(3, ' ') +
        str(safe_get(puzzle, 3)).center(3, ' ')
    )
    print('-' * 10)
    print(
        str(safe_get(puzzle, 4)).center(3, ' ') +
        str(safe_get(puzzle, 5)).center(3, ' ') +
        str(safe_get(puzzle, 6)).center(3, ' ')
    )
    print('-' * 10)
    print(
        str(safe_get(puzzle, 7)).center(3, ' ') +
        str(safe_get(puzzle, 8)).center(3, ' ') +
        str(safe_get(puzzle, 9)).center(3, ' ')
    )
# ========================= Actual Hill Climbing Logic ====================================
def start(puzzle) -> Node:
    root = Node(puzzle, 0)
    opened = []
    closed = [root]
    steps = 0
    previous = set()
    best_score = 1000
    while len(closed) > 0:
        print("=" * 40)
        print("Opened:", opened)
        print("Closed:", closed)
        steps += 1
        closed.sort(key=lambda n: n.heu())
        current = closed.pop(0)
        opened.append(current)
        score = heuristic(current.board)
        if score == 0:
            return current
        if current in previous:
            # print("Skipping current state because it was repeated previously ...")
            continue
        else:
            previous.add(current)
        if score < best_score:
            best_score = score
        for operation in get_available_operations(current.board):
            child = Node(operation(current.board.copy()), steps, current, operation)
            closed.append(child)
    return current
def main():
    puzzle = {
        1: 1, 2: -1, 3: 3,
        4: 8, 5: 2, 6: 6,
        7: 7, 8: 5, 9: 4,
    }
    print("The initial state is ")
    display_board(puzzle)
    print("The goal state is ")
    display_board(GOAL)
    node = start(puzzle)
    path: list[Node] = []
    while node:
        path.append(node)
        node = node.prev
    path = path[::-1]
    path = path[1:]
    for i, node in enumerate(path):
        print(f" Step {i + 1} ".center(40, '='))
        if node.operation:
            print(get_operation_name(node.operation))
        display_board(node.board)
        print(f"The objective function score of this board is {heuristic(node.board) + i + 1}")
    if heuristic(path[-1].board) != 0:
        print("Not found ideal board position")
    else:
        print("This is the required solution✅")
if __name__ == '__main__':
    main()

Best First

Best First - Robot Nav

# Board Contents
EMPTY = 0
WALL = 1
SELECTED = 2
class Node:
    def __init__(self, x, y, prev = None):
        self.x = x
        self.y = y
        self.prev = prev
    def __eq__(self, other):
        if isinstance(other, Node):
            return self.x == other.x and self.y == other.y
        elif isinstance(other, tuple):
            return self.x == other[0] and self.y == other[1]
    def __repr__(self):
        return str((self.x, self.y))
    def __hash__(self):
        return (self.x, self.y).__hash__()
    def man_dist(self, to) -> int:
        return abs(self.x - to.x) + abs(self.y - to.y)
    def heu(self, goal) -> int:
        return self.man_dist(goal)
    def neighbours(self, board) -> list:
        neigh = [
            # No diagonal neighbours
            (self.x, self.y - 1), # Top
            (self.x - 1, self.y), # Left
            (self.x + 1, self.y), # Right
            (self.x, self.y + 1), # Bottom
        ]
        ugly_neighbours = []
        for n in neigh:
            x, y = n
            if x < 0 or y < 0:
                ugly_neighbours.append((x, y))
            elif x >= len(board) or y >= len(board[0]):
                ugly_neighbours.append((x, y))
            elif board[x][y] == WALL:
                ugly_neighbours.append((x, y))
        for ugly in ugly_neighbours:
            neigh.remove(ugly)
        return [Node(n[0], n[1], self) for n in neigh]
# Defining custom type
Board = list[list[Node]]
def display_board(board, initial: Node, goal: Node) -> None:
    print('', '-' * len(board[0] * 3))
    for i, row in enumerate(board):
        print(end='|')
        for j, col in enumerate(row):
            if Node(i, j) == initial:
                ch='S'
            elif Node(i, j) == goal:
                ch='E'
            elif col == EMPTY:
                ch=' '
            elif col == WALL:
                ch='#'
            elif col == SELECTED:
                ch='.'
            print("{:>3}".format(ch), end='')
        print(end='|\n')
    print('', '-' * len(board[0]) * 3)
def start(board, initial: Node, goal: Node) -> Node:
    opened = []
    closed = [Node(initial.x, initial.y)]
    # Create a copy of board to display the steps of Best First Search
    d_board = []
    for row in board:
        d_board.append([])
        for col in row:
            d_board[-1].append(col)
    # Actual Best First Logic
    previous = set()
    while len(closed) > 0:
        closed.sort(key = lambda n: n.heu(goal))
        current = closed.pop(0)
        opened.append(current)
        if current in previous:
            continue
        else:
            previous.add(current)
        d_board[current.x][current.y] = SELECTED
        print('=' * 40)
        print("Open List:", opened)
        print("Close List:", closed)
        print("\n\nCurrently selected ({}, {})".format(current.x, current.y))
        display_board(d_board, initial, goal)
        if current == goal:
            print("Reached goal!")
            break
        for neighbour in current.neighbours(board):
            if neighbour not in previous:
                closed.append(neighbour)
    return current
# For test case validity check
def safety_check(board, initial: tuple[int, int], goal: tuple[int, int]):
    if board[initial[0]][initial[1]] == WALL:
        raise ValueError("Initial Position cannot be a wall")
    if board[goal[0]][goal[1]] == WALL:
        raise ValueError("Goal Position cannot be a wall")
def main():
    board = [
        [0, 0, 0, 0, 0, 0, 0, 0, 0,],
        [0, 1, 0, 0, 1, 1, 1, 1, 0,],
        [0, 1, 0, 0, 0, 0, 0, 1, 0,],
        [0, 0, 1, 1, 1, 1, 1, 1, 0,],
        [0, 0, 0, 0, 0, 0, 0, 0, 0,],
    ]
    initial = (3, 0)
    goal = (2, 5)
    safety_check(board, initial, goal)
    end = start(board, Node(initial[0], initial[1]), Node(goal[0], goal[1]))
    print("\nThe best path is ")
    path = []
    while end:
        path.append((end.x, end.y))
        end = end.prev
    # Create a copy of board
    d_board = []
    for row in board:
        d_board.append([])
        for col in row:
            d_board[-1].append(col)
    # mutate it with path found
    for (x, y) in path:
        d_board[x][y] = SELECTED
    display_board(d_board, initial, goal)
if __name__ == '__main__':
    main()

Best First - City Dist

SOURCE = "Latur"
DESTINATION = "Navi Mumbai"
DISTANCE_FROM_DESTINATION = {
    "Solapur": 340,
    "Satara": 177,
    "Navi Mumbai": 0,
    "Nashik": 133,
    "Ahmednagar": 180,
    "Aurangabad": 265,
    "Nanded": 451,
    "Latur": 373,
    "Pune": 105,
}
# A weighted undirected map of cities
GRAPH = {}
def put_city(city1: str, city2: str, weight: int) -> None:
    global GRAPH
    if city1 in GRAPH:
        GRAPH[city1].append((city2, weight))
    else:
        GRAPH[city1] = [(city2, weight)]
    if city2 in GRAPH:
        GRAPH[city2].append((city1, weight))
    else:
        GRAPH[city2] = [(city1, weight)]
def generate_map() -> None:
    put_city("Pune", "Navi Mumbai", 106)
    put_city("Pune", "Satara", 112)
    put_city("Pune", "Solapur", 234)
    put_city("Solapur", "Satara", 203)
    put_city("Solapur", "Latur", 104)
    put_city("Nanded", "Latur", 113)
    put_city("Nanded", "Aurangabad", 221)
    put_city("Nashik", "Aurangabad", 159)
    put_city("Nanded", "Ahmednagar", 267)
    put_city("Pune", "Ahmednagar", 120)
    put_city("Nashik", "Pune", 165)
    put_city("Nashik", "Navi Mumbai", 136)
def distance(from_: str, to: str) -> int:
    if from_ == to:
        return 0
    array = GRAPH[from_]
    for name, weight in array:
        if name == to:
            return weight
    return 10 ** 10
class Node:
    def __init__(self, city: str, prev: object, weight: int) -> None:
        self.city = city
        self.prev = prev
        self.weight = weight
    def __repr__(self) -> str:
        return self.city
    def __eq__(self, other) -> bool:
        if isinstance(other, Node):
            return self.city == other.city
        elif isinstance(other, str):
            return self.city == other
        else:
            return False
def objective(city) -> int:
    return DISTANCE_FROM_DESTINATION[city]
def main() -> None: 
    generate_map()
    print('=' * 40)
    print("Starting city is Latur")
    print("Destination city is Navi Mumbai")
    # from pprint import pprint
    # pprint(GRAPH)
    current = Node(SOURCE, None, 0)
    opened = []
    closed = [current]
    while len(closed) > 0:
        print('=' * 40)
        print("Opened list:", opened)
        print("Closed list:", closed)
        closed.sort(
                key=lambda node: objective(node.city),
                reverse=True
        )
        current = closed.pop()
        if current not in opened:
            opened.append(current)
        if current == DESTINATION:
            print("🎉We got there!🎉".center(40, ' '))
            break
        print("Selected", current)
        # Add all neighbours of current city into queue
        print(f"The neighbouring cities of {current} are")
        for name, dist in GRAPH[current.city]:
            print(f"{name:>12} with distance {dist}")
            if name not in opened:
                closed.append(Node(name, current, dist))
        print()
    path = []
    while current:
        path.append(current)
        current = current.prev
    print("=" * 40)
    print("The full path is ")
    for city in path[::-1]:
        if city.prev:
            print(f"{city.prev.city} to {city.city} with distance {city.weight}")
if __name__ == '__main__':
    main()

Best First - 8puzzle

GOAL = {
    1: 1, 2: 2, 3: 3,
    4: 8, 5: -1, 6: 4,
    7: 7, 8: 6, 9: 5,
}
t_board = dict[int, int]
#  ============================= Helper Functions ==================================
class Node:
    def __init__(self, board: dict[int, int], steps: int, prev=None, op=None):
        self.board = board.copy()
        self.steps = steps
        self.prev = prev
        self.operation = op
    def __eq__(self, other):
        return self.board == other.board
    def __hash__(self) -> int:
        return heuristic(self.board)
    def __repr__(self):
        return str(self.heu())
    def heu(self) -> int:
        return self.steps + heuristic(self.board)
def get_empty_pos(puzzle: t_board) -> int:
    for key in puzzle:
        if puzzle[key] == -1:
            return key
def move_up(puzzle: t_board):
    pos = get_empty_pos(puzzle)
    puzzle[pos], puzzle[pos - 3] = puzzle[pos - 3], puzzle[pos]
    return puzzle
def move_down(puzzle: t_board):
    pos = get_empty_pos(puzzle)
    puzzle[pos], puzzle[pos + 3] = puzzle[pos + 3], puzzle[pos]
    return puzzle
def move_right(puzzle: t_board):
    pos = get_empty_pos(puzzle)
    puzzle[pos], puzzle[pos + 1] = puzzle[pos + 1], puzzle[pos]
    return puzzle
def move_left(puzzle: t_board):
    pos = get_empty_pos(puzzle)
    puzzle[pos], puzzle[pos - 1] = puzzle[pos - 1], puzzle[pos]
    return puzzle
def get_available_operations(puzzle: t_board):
    operations = {
        move_up,
        move_left, move_right,
        move_down,
    }
    empty_pos = get_empty_pos(puzzle)
    if empty_pos in {1, 2, 3}:
        operations.remove(move_up)
    if empty_pos in {7, 8, 9}:
        operations.remove(move_down)
    if empty_pos in {3, 6, 9}:
        operations.remove(move_right)
    if empty_pos in {1, 4, 7}:
        operations.remove(move_left)
    return operations
def get_operation_name(op):
    return {
        move_up: "Move the empty slot above",
        move_left: "Move the empty slot left",
        move_right: "Move the empty slot right",
        move_down: "Move the empty slot down",
    }[op]
def heuristic(puzzle: t_board) -> int:
    # This function takes a board and returns heuristic value of it
    # Heuristic is how many board are misplaced
    score = 0
    for key in puzzle:
        if puzzle[key] != GOAL[key]:
            score += 1
    return score
def safe_get(puzzle: t_board, key: int) -> str:
    if puzzle[key] != -1:
        return puzzle[key]
    return '@'
def display_board(puzzle: dict[int, int]):
    print(
        str(safe_get(puzzle, 1)).center(3, ' ') +
        str(safe_get(puzzle, 2)).center(3, ' ') +
        str(safe_get(puzzle, 3)).center(3, ' ')
    )
    print('-' * 10)
    print(
        str(safe_get(puzzle, 4)).center(3, ' ') +
        str(safe_get(puzzle, 5)).center(3, ' ') +
        str(safe_get(puzzle, 6)).center(3, ' ')
    )
    print('-' * 10)
    print(
        str(safe_get(puzzle, 7)).center(3, ' ') +
        str(safe_get(puzzle, 8)).center(3, ' ') +
        str(safe_get(puzzle, 9)).center(3, ' ')
    )
# ========================= Actual Hill Climbing Logic ====================================
def start(puzzle) -> Node:
    root = Node(puzzle, 0)
    opened = []
    closed = [root]
    steps = 0
    previous = set()
    best_score = 1000
    while len(closed) > 0:
        print("=" * 40)
        print("Opened:", opened)
        print("Closed:", closed)
        steps += 1
        closed.sort(key=lambda n: heuristic(n.board))
        current = closed.pop(0)
        opened.append(current)
        score = heuristic(current.board)
        if score == 0:
            return current
        if current in previous:
            # print("Skipping current state because it was repeated previously ...")
            continue
        else:
            previous.add(current)
        if score < best_score:
            best_score = score
        for operation in get_available_operations(current.board):
            child = Node(operation(current.board.copy()),
                         steps, current, operation)
            closed.append(child)
    return current
def main():
    puzzle = {
        1: 1, 2: 3, 3: -1,
        4: 8, 5: 2, 6: 6,
        7: 7, 8: 5, 9: 4,
    }
    print("The initial board state is ")
    display_board(puzzle)
    print("The goal state is ")
    display_board(GOAL)
    print(f"The objective function score of this board is {heuristic(puzzle)}")
    node = start(puzzle)
    path: list[Node] = []
    while node:
        path.append(node)
        node = node.prev
    path = path[::-1]
    path = path[1:]
    for i, node in enumerate(path):
        print(f" Step {i + 1} ".center(40, '='))
        if node.operation:
            print(get_operation_name(node.operation))
        display_board(node.board)
        print(f"The objective function score of this board is {heuristic(node.board)}")
    if heuristic(path[-1].board) != 0:
        print("Not found ideal board position")
    else:
        print("This is the required solution✅")
if __name__ == '__main__':
    main()

Assn5

Crossword

def check_right(i, j, grid) -> tuple[int, int, int]:
    counter = 0
    while (counter + j) < len(grid[i]):
        if grid[i][j + counter] == ' ':
            counter += 1
        else:
            break
    if counter < 2:
        return None
    else:
        return (i, j, counter)
def check_down(i, j, grid) -> tuple[int, int, int]:
    counter = 0
    while (counter + i) < len(grid):
        if grid[i + counter][j] == ' ':
            counter += 1
        else:
            break
    if counter < 2:
        return None
    else:
        return (i, j, counter)
def get_across_slots(grid: list[str]):
    accross_slots = []
    i = 0
    while i < len(grid):
        j = 0
        while j < len(grid[i]):
            if grid[i][j] == ' ':
                if slot := check_right(i, j, grid):
                    accross_slots.append(slot)
                    j += slot[2]
            j += 1
        i += 1
    return accross_slots
def get_down_slots(grid: list[str]):
    t_grid = []
    # Get transpose of grid
    for i in range(len(grid)):
        string = ''.join([row[i] for row in grid])
        t_grid.append(string)
    down_slots = get_across_slots(t_grid)
    # The down slots are for the transposed grid,
    # so we need to convert them to our original grid's coordinates
    down_slots = [(slot[1], slot[0], slot[2]) for slot in down_slots]
    return down_slots
def start(across_words: list[str], down_words: list[str], grid: list[str]) -> None:
    across_slots = get_across_slots(grid)
    down_slots = get_down_slots(grid)
    # We need a mutable grid, so we use list[list[str]]
    mut_grid = []
    for i in range(len(grid)):
        arr = []
        for j in range(len(grid[i])):
            arr.append([grid[i][j]])
        mut_grid.append(arr)
    # Start filling the across words
    i = 0
    while len(across_words):
        used = False
        if used:
            across_slots.pop(i)
        else:
            i = (i + 1) % len(down_slots)
        if len(across_words[0]) == across_slots[i][2]:
            x, y, _ = across_slots[i]
            for counter, letter in enumerate(across_words[0]):
                mut_grid[x][y + counter] = [letter]
            else:
                used = True
            across_words.pop(0)
    # Start filling the down words
    i = 0
    while len(down_words):
        used = False
        if used:
            down_slots.pop(i)
        else:
            i = (i + 1) % len(down_slots)
        if len(down_words[0]) == down_slots[i][2]:
            x, y, _ = down_slots[i]
            for counter, letter in enumerate(down_words[0]):
                mut_grid[x + counter][y] = [letter]
            else:
                used = True
            down_words.pop(0)
    # Convert list[list[str]] to list[str]
    grid = []
    for i in range(len(mut_grid)):
        string = ""
        for j in range(len(mut_grid[i])):
            for k in range(len(mut_grid[i][j])):
                string += mut_grid[i][j][k][0]
        grid.append(string)
    return grid
def display_grid(grid: list[str]) -> None:
    for row in grid:
        for col in row:
            print(f"{col:>2}", end='')
        print()
def main() -> None:
    ACROSS = ['HYBRID', 'EARTH']
    DOWN = ['BREAD', 'HELMET']
    grid = [
        "########",
        "#      #",
        "# # ####",
        "# #     ",
        "# # ####",
        "# # ####",
        "# ######",
    ]
    print(" The Initial Crossword is ".center(40, '='))
    display_grid(grid)
    print("The across words are:", ', '.join(ACROSS))
    print("The down words are:", ', '.join(DOWN))
    result = start(ACROSS, DOWN, grid)
    print('\n\n')
    print(" The Final Crossword is ".center(40, '='))
    display_grid(result)
if __name__ == '__main__':
    main()

Crypt on Git

https://github.com/Ishgar14/Artificial-Intelligence

MapColoring

Graph = dict[str, list[str]]       
COLORS = ["red", "green", "blue", "yellow"]       
def generate_graph() -> dict:       
    graph = {}       
    def put_neighbours(n1: str, n2: str):
        if n1 in graph:
            graph[n1].append(n2)
        else:
            graph[n1] = [n2]
        if n2 in graph:
            graph[n2].append(n1)
        else:
            graph[n2] = [n1] 
    put_neighbours('a', 'b')
    put_neighbours('a', 'c')
    put_neighbours('b', 'c')
    put_neighbours('b', 'f')
    put_neighbours('c', 'e')
    put_neighbours('c', 'd')
    put_neighbours('d', 'e') 
    put_neighbours('e', 'f')
    put_neighbours('f', 'a')
    put_neighbours('f', 'b')
    put_neighbours('f', 'c')
    put_neighbours('g', 'e')
    return graph
def neighbour_colors(node: str, graph: Graph, node_colors: dict[str, str]) -> list[str]:
    # This function returns colours of neighbours of `node`
    neighbours = graph[node]
    return { n:node_colors[n] for n in neighbours if n in node_colors }
def start(graph: Graph, node_colors: dict[str, str] = {}):
    for key in graph:
        if key in node_colors:
            continue
        nc = neighbour_colors(key, graph, node_colors)
        available_colours = [color for color in COLORS if color not in nc.values()]
        print(f"Colours available for {key} are", available_colours)
        for c in available_colours:
            node_colors[key] = c
            print(f"Applying colour {c} to node {key}\n")         
            if color_list := start(graph, node_colors):
                if len(color_list) == len(graph):
                    return color_list
    return node_colors
def main() -> None: 
    graph = generate_graph()
    print(" Structure of Graph ".center(40, '='))
    for node, neighbours in graph.items():
        print(f"Node {node} has neighbours:", neighbours)
    print('\n', ' Applying Colours '.center(40, '='), sep='')
    colors = start(graph)
    print('\n', " After colouring ".center(40, '='), sep='')
    for node, color in colors.items():
        print(f"Node {node} gets {color:<6} colour")
if __name__ == '__main__':
    main()

Sam map coloring

import random
map = {"A": ['B','C','D'],
       "B": ['A','C','D'],
       "C": ['A',"B"],
       "D": ['A',"B"] }
colors = ["red","blue","green"]
dictcolor ={
       "A":"None" ,
       "B":"None" ,
       "C":"None" ,
       "D":"None" 
}
# first color allot random
dictcolor["A"] = random.choice(colors)
flag = 0
print(dictcolor)
for key, value in map.items():
    if flag ==0:
        flag = 1
        continue
    print(key)
    print(value)
    tempdict = {}
    for i in value:
         tempdict.update( {i: dictcolor[i]})
    print("incolors taken:",set(tempdict.values()))
    incolors2 = set(colors) - set(tempdict.values())
    dictcolor[key] = random.choice(tuple(incolors2))
    print("available:", incolors2)
    print(dictcolor)

San map coloring

graph = {'A': ['B', 'C', 'D'],
         'B': ['A', 'C', 'D'],
         'C': ['A', 'B'],
         'D': ['A', 'B']}
colors = ["red", "blue", "green"]
coloredNodes = {}
def avail(graph, colors, node, coloredNodes):
    neighbourcolor = []
    for neighbour in graph[node]:
        if coloredNodes.get(neighbour, None):
            neighbourcolor.append(coloredNodes[neighbour])
    available = set(colors) - set(neighbourcolor)
    return list(available)[0]
def main():
    for node in graph:
        coloredNodes[node] = avail(graph, colors, node, coloredNodes)
        print(coloredNodes)
if __name__ == "__main__":
    main()

Assn6 Prolog

Sam

/* Facts */
male(jack).
male(oliver).
male(ali).
male(james).
male(simon).
male(harry).
female(helen).
female(sophie).
female(jess).
female(lily).
parent(jack,jess).
parent(jack,lily).
parent(helen, jess).
parent(helen, lily).
parent(oliver,james).
parent(sophie, james).
parent(jess, simon).
parent(ali, simon).
parent(lily, harry).
parent(james, harry).
husband(jack, helen).
husband(oliver, sophie).
husband(ali, jess).
husband(james, lily).
/* Rules */
father(X,Y):- male(X), parent(X,Y).
mother(X,Y):- female(X),parent(X,Y).
son(X,Y,Z) :- male(X),father(Y,X),mother(Z,X).
daughter(X,Y,Z) :- female(X),father(Y,X),mother(Z,X).
brother(X,Y):- male(X), father(Z, Y), father(Z,X),X \= Y.
sister(X,Y):-  female(X), father(F, Y), father(F,X),X \= Y.
cousin(X,Y) :- father(Z,X),brother(Z,W),father(W,Y).
grandfather(X,Y):- male(X), parent(X,Z), parent(Z,Y).
grandmother(X,Y):- female(X), parent(X,Z), parent(Z,Y).
uncle(X,Y):- parent(Z,Y), brother(Z,X).
aunt(X,Y):- female(X), parent(Z,Y), sister(Z,X), !.
chacha(X,Y) :- father(Z,Y) , brother(X,Z).
chachi(X,Y) :- female(X), father(Z,Y) , brother(Z,W) , husband(W,X).
mama(X,Y) :- mother(Z,Y) , brother(X,Z).
mami(X,Y) :- female(X), mother(Z,Y) , brother(W,Z) , husband(W,X). 
stepbrother_commonmother(X,Y) :- male(X) , mother(M,X) , mother(M,Y) , father(L,X), father(N,Y) , L \= N.
stepbrother_commonfather(X,Y) :- male(X) , father(F,X) , father(F,Y) , mother(L,X), mother(N,Y) , L \= N.
stepsister_commonmother(X,Y) :- male(X) , mother(M,X) , mother(M,Y) , father(L,X), father(N,Y) , L \= N.
stepsister_commonfather(X,Y) :- male(X) , father(F,X) , father(F,Y) , mother(L,X), mother(N,Y) , L \= N.
ancestor(X,Y):- parent(X,Y).
ancestor(X,Y):- parent(X,Z),ancestor_of(Z,Y).
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2025 Microsoft