Completed HW1
This commit is contained in:
parent
4e84e62dff
commit
f8c487e831
155
hw1/actors/degrees.py
Normal file
155
hw1/actors/degrees.py
Normal file
@ -0,0 +1,155 @@
|
||||
import csv
|
||||
import sys
|
||||
from collections import deque
|
||||
|
||||
# Maps names to a set of corresponding person_ids
|
||||
names = {}
|
||||
|
||||
# Maps person_ids to a dictionary of: name, birth, movies (a set of movie_ids)
|
||||
people = {}
|
||||
|
||||
# Maps movie_ids to a dictionary of: title, year, stars (a set of person_ids)
|
||||
movies = {}
|
||||
|
||||
|
||||
class Node:
|
||||
def __init__(self, state, parent, action):
|
||||
self.state = state
|
||||
self.parent = parent
|
||||
self.action = action
|
||||
|
||||
|
||||
def shortest_path(source, target):
|
||||
"""
|
||||
Returns the shortest list of (movie_id, person_id) pairs
|
||||
that connect the source to the target.
|
||||
|
||||
If no possible path, returns None.
|
||||
"""
|
||||
visited = set()
|
||||
queue = deque([ (source, []) ])
|
||||
|
||||
while queue:
|
||||
(node, path) = queue.popleft()
|
||||
if node == target:
|
||||
return path
|
||||
if node not in visited:
|
||||
visited.add(node)
|
||||
for neighbor in neighbors_for_person(node):
|
||||
queue.append((neighbor[1], path + [neighbor]))
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def person_id_for_name(name):
|
||||
"""
|
||||
Returns the IMDB id for a person's name,
|
||||
resolving ambiguities as needed.
|
||||
"""
|
||||
person_ids = list(names.get(name.lower(), set()))
|
||||
if len(person_ids) == 0:
|
||||
return None
|
||||
elif len(person_ids) > 1:
|
||||
print(f"Which '{name}'?")
|
||||
for person_id in person_ids:
|
||||
person = people[person_id]
|
||||
name = person["name"]
|
||||
birth = person["birth"]
|
||||
print(f"ID: {person_id}, Name: {name}, Birth: {birth}")
|
||||
try:
|
||||
person_id = input("Intended Person ID: ")
|
||||
if person_id in person_ids:
|
||||
return person_id
|
||||
except ValueError:
|
||||
pass
|
||||
return None
|
||||
else:
|
||||
return person_ids[0]
|
||||
|
||||
|
||||
def neighbors_for_person(person_id):
|
||||
"""
|
||||
Returns (movie_id, person_id) pairs for people
|
||||
who starred with a given person.
|
||||
"""
|
||||
movie_ids = people[person_id]["movies"]
|
||||
neighbors = set()
|
||||
for movie_id in movie_ids:
|
||||
for person_id in movies[movie_id]["stars"]:
|
||||
neighbors.add((movie_id, person_id))
|
||||
return neighbors
|
||||
|
||||
|
||||
def load_data(directory):
|
||||
"""
|
||||
Load data from CSV files into memory.
|
||||
"""
|
||||
# Load people
|
||||
with open(f"{directory}/people.csv", encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
people[row["id"]] = {
|
||||
"name": row["name"],
|
||||
"birth": row["birth"],
|
||||
"movies": set()
|
||||
}
|
||||
if row["name"].lower() not in names:
|
||||
names[row["name"].lower()] = {row["id"]}
|
||||
else:
|
||||
names[row["name"].lower()].add(row["id"])
|
||||
|
||||
# Load movies
|
||||
with open(f"{directory}/movies.csv", encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
movies[row["id"]] = {
|
||||
"title": row["title"],
|
||||
"year": row["year"],
|
||||
"stars": set()
|
||||
}
|
||||
|
||||
# Load stars
|
||||
with open(f"{directory}/stars.csv", encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
try:
|
||||
people[row["person_id"]]["movies"].add(row["movie_id"])
|
||||
movies[row["movie_id"]]["stars"].add(row["person_id"])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) > 2:
|
||||
sys.exit("Usage: python degrees.py [directory]")
|
||||
directory = sys.argv[1] if len(sys.argv) == 2 else "large"
|
||||
|
||||
# Load data from files into memory
|
||||
print("Loading data...")
|
||||
load_data(directory)
|
||||
print("Data loaded.")
|
||||
|
||||
source = person_id_for_name(input("Name: "))
|
||||
if source is None:
|
||||
sys.exit("Person not found.")
|
||||
target = person_id_for_name(input("Name: "))
|
||||
if target is None:
|
||||
sys.exit("Person not found.")
|
||||
|
||||
path = shortest_path(source, target)
|
||||
|
||||
if path is None:
|
||||
print("Not connected.")
|
||||
else:
|
||||
degrees = len(path)
|
||||
print(f"{degrees} degrees of separation.")
|
||||
path = [(None, source)] + path
|
||||
for i in range(degrees):
|
||||
person1 = people[path[i][1]]["name"]
|
||||
person2 = people[path[i + 1][1]]["name"]
|
||||
movie = movies[path[i + 1][0]]["title"]
|
||||
print(f"{i + 1}: {person1} and {person2} starred in {movie}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
344277
hw1/actors/large/movies.csv
Normal file
344277
hw1/actors/large/movies.csv
Normal file
File diff suppressed because it is too large
Load Diff
1044500
hw1/actors/large/people.csv
Normal file
1044500
hw1/actors/large/people.csv
Normal file
File diff suppressed because it is too large
Load Diff
1189595
hw1/actors/large/stars.csv
Normal file
1189595
hw1/actors/large/stars.csv
Normal file
File diff suppressed because it is too large
Load Diff
6
hw1/actors/small/movies.csv
Normal file
6
hw1/actors/small/movies.csv
Normal file
@ -0,0 +1,6 @@
|
||||
id,title,year
|
||||
112384,"Apollo 13",1995
|
||||
104257,"A Few Good Men",1992
|
||||
109830,"Forrest Gump",1994
|
||||
93779,"The Princess Bride",1987
|
||||
95953,"Rain Man",1988
|
||||
|
17
hw1/actors/small/people.csv
Normal file
17
hw1/actors/small/people.csv
Normal file
@ -0,0 +1,17 @@
|
||||
id,name,birth
|
||||
102,"Kevin Bacon",1958
|
||||
129,"Tom Cruise",1962
|
||||
144,"Cary Elwes",1962
|
||||
158,"Tom Hanks",1956
|
||||
1597,"Mandy Patinkin",1952
|
||||
163,"Dustin Hoffman",1937
|
||||
1697,"Chris Sarandon",1942
|
||||
193,"Demi Moore",1962
|
||||
197,"Jack Nicholson",1937
|
||||
200,"Bill Paxton",1955
|
||||
398,"Sally Field",1946
|
||||
420,"Valeria Golino",1965
|
||||
596520,"Gerald R. Molen",1935
|
||||
641,"Gary Sinise",1955
|
||||
705,"Robin Wright",1966
|
||||
914612,"Emma Watson",1990
|
||||
|
21
hw1/actors/small/stars.csv
Normal file
21
hw1/actors/small/stars.csv
Normal file
@ -0,0 +1,21 @@
|
||||
person_id,movie_id
|
||||
102,104257
|
||||
102,112384
|
||||
129,104257
|
||||
129,95953
|
||||
144,93779
|
||||
158,109830
|
||||
158,112384
|
||||
1597,93779
|
||||
163,95953
|
||||
1697,93779
|
||||
193,104257
|
||||
197,104257
|
||||
200,112384
|
||||
398,109830
|
||||
420,95953
|
||||
596520,95953
|
||||
641,109830
|
||||
641,112384
|
||||
705,109830
|
||||
705,93779
|
||||
|
BIN
hw1/hw1.pdf
Normal file
BIN
hw1/hw1.pdf
Normal file
Binary file not shown.
BIN
hw1/tictactoe/OpenSans-Regular.ttf
Normal file
BIN
hw1/tictactoe/OpenSans-Regular.ttf
Normal file
Binary file not shown.
BIN
hw1/tictactoe/__pycache__/tictactoe.cpython-312.pyc
Normal file
BIN
hw1/tictactoe/__pycache__/tictactoe.cpython-312.pyc
Normal file
Binary file not shown.
1
hw1/tictactoe/requirements.txt
Normal file
1
hw1/tictactoe/requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
pygame
|
||||
146
hw1/tictactoe/runner.py
Normal file
146
hw1/tictactoe/runner.py
Normal file
@ -0,0 +1,146 @@
|
||||
import pygame
|
||||
import sys
|
||||
import time
|
||||
|
||||
import tictactoe as ttt
|
||||
|
||||
pygame.init()
|
||||
size = width, height = 600, 400
|
||||
|
||||
# Colors
|
||||
black = (0, 0, 0)
|
||||
white = (255, 255, 255)
|
||||
|
||||
screen = pygame.display.set_mode(size)
|
||||
|
||||
mediumFont = pygame.font.Font("OpenSans-Regular.ttf", 28)
|
||||
largeFont = pygame.font.Font("OpenSans-Regular.ttf", 40)
|
||||
moveFont = pygame.font.Font("OpenSans-Regular.ttf", 60)
|
||||
|
||||
user = None
|
||||
board = ttt.start_state()
|
||||
ai_turn = False
|
||||
|
||||
while True:
|
||||
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
sys.exit()
|
||||
|
||||
screen.fill(black)
|
||||
|
||||
# Let user choose a player.
|
||||
if user is None:
|
||||
|
||||
# Draw title
|
||||
title = largeFont.render("Play Tic-Tac-Toe", True, white)
|
||||
titleRect = title.get_rect()
|
||||
titleRect.center = ((width / 2), 50)
|
||||
screen.blit(title, titleRect)
|
||||
|
||||
# Draw buttons
|
||||
playXButton = pygame.Rect((width / 8), (height / 2), width / 4, 50)
|
||||
playX = mediumFont.render("Play as X", True, black)
|
||||
playXRect = playX.get_rect()
|
||||
playXRect.center = playXButton.center
|
||||
pygame.draw.rect(screen, white, playXButton)
|
||||
screen.blit(playX, playXRect)
|
||||
|
||||
playOButton = pygame.Rect(5 * (width / 8), (height / 2), width / 4, 50)
|
||||
playO = mediumFont.render("Play as O", True, black)
|
||||
playORect = playO.get_rect()
|
||||
playORect.center = playOButton.center
|
||||
pygame.draw.rect(screen, white, playOButton)
|
||||
screen.blit(playO, playORect)
|
||||
|
||||
# Check if button is clicked
|
||||
click, _, _ = pygame.mouse.get_pressed()
|
||||
if click == 1:
|
||||
mouse = pygame.mouse.get_pos()
|
||||
if playXButton.collidepoint(mouse):
|
||||
time.sleep(0.2)
|
||||
user = ttt.X
|
||||
elif playOButton.collidepoint(mouse):
|
||||
time.sleep(0.2)
|
||||
user = ttt.O
|
||||
|
||||
else:
|
||||
|
||||
# Draw game board
|
||||
tile_size = 80
|
||||
tile_origin = (width / 2 - (1.5 * tile_size),
|
||||
height / 2 - (1.5 * tile_size))
|
||||
tiles = []
|
||||
for i in range(3):
|
||||
row = []
|
||||
for j in range(3):
|
||||
rect = pygame.Rect(
|
||||
tile_origin[0] + j * tile_size,
|
||||
tile_origin[1] + i * tile_size,
|
||||
tile_size, tile_size
|
||||
)
|
||||
pygame.draw.rect(screen, white, rect, 3)
|
||||
|
||||
if board[i][j] != ttt.EMPTY:
|
||||
move = moveFont.render(board[i][j], True, white)
|
||||
moveRect = move.get_rect()
|
||||
moveRect.center = rect.center
|
||||
screen.blit(move, moveRect)
|
||||
row.append(rect)
|
||||
tiles.append(row)
|
||||
|
||||
game_over = ttt.terminal(board)
|
||||
player = ttt.player(board)
|
||||
|
||||
# Show title
|
||||
if game_over:
|
||||
winner = ttt.winner(board)
|
||||
if winner is None:
|
||||
title = f"Game Over: Tie."
|
||||
else:
|
||||
title = f"Game Over: {winner} wins."
|
||||
elif user == player:
|
||||
title = f"Play as {user}"
|
||||
else:
|
||||
title = f"Computer thinking..."
|
||||
title = largeFont.render(title, True, white)
|
||||
titleRect = title.get_rect()
|
||||
titleRect.center = ((width / 2), 30)
|
||||
screen.blit(title, titleRect)
|
||||
|
||||
# Check for AI move
|
||||
if user != player and not game_over:
|
||||
if ai_turn:
|
||||
time.sleep(0.5)
|
||||
move = ttt.minimax(board)
|
||||
board = ttt.succ(board, move)
|
||||
ai_turn = False
|
||||
else:
|
||||
ai_turn = True
|
||||
|
||||
# Check for a user move
|
||||
click, _, _ = pygame.mouse.get_pressed()
|
||||
if click == 1 and user == player and not game_over:
|
||||
mouse = pygame.mouse.get_pos()
|
||||
for i in range(3):
|
||||
for j in range(3):
|
||||
if (board[i][j] == ttt.EMPTY and tiles[i][j].collidepoint(mouse)):
|
||||
board = ttt.succ(board, (i, j))
|
||||
|
||||
if game_over:
|
||||
againButton = pygame.Rect(width / 3, height - 65, width / 3, 50)
|
||||
again = mediumFont.render("Play Again", True, black)
|
||||
againRect = again.get_rect()
|
||||
againRect.center = againButton.center
|
||||
pygame.draw.rect(screen, white, againButton)
|
||||
screen.blit(again, againRect)
|
||||
click, _, _ = pygame.mouse.get_pressed()
|
||||
if click == 1:
|
||||
mouse = pygame.mouse.get_pos()
|
||||
if againButton.collidepoint(mouse):
|
||||
time.sleep(0.2)
|
||||
user = None
|
||||
board = ttt.start_state()
|
||||
ai_turn = False
|
||||
|
||||
pygame.display.flip()
|
||||
184
hw1/tictactoe/tictactoe.py
Normal file
184
hw1/tictactoe/tictactoe.py
Normal file
@ -0,0 +1,184 @@
|
||||
import math
|
||||
|
||||
# Use these constants to fill in the game board
|
||||
X = "X"
|
||||
O = "O"
|
||||
EMPTY = None
|
||||
|
||||
|
||||
def start_state():
|
||||
"""
|
||||
Returns starting state of the board.
|
||||
"""
|
||||
return [[EMPTY, EMPTY, EMPTY],
|
||||
[EMPTY, EMPTY, EMPTY],
|
||||
[EMPTY, EMPTY, EMPTY]]
|
||||
|
||||
|
||||
def player(board):
|
||||
"""
|
||||
Returns which player (either X or O) who has the next turn on a board.
|
||||
|
||||
In the initial game state, X gets the first move. Subsequently, the player alternates with each additional move.
|
||||
Any return value is acceptable if a terminal board is provided as input (i.e., the game is already over).
|
||||
"""
|
||||
count_X = sum(row.count(X) for row in board)
|
||||
count_O = sum(row.count(O) for row in board)
|
||||
|
||||
if count_X > count_O:
|
||||
return O
|
||||
else:
|
||||
return X
|
||||
|
||||
|
||||
def actions(board):
|
||||
"""
|
||||
Returns the set of all possible actions (i, j) available on the board.
|
||||
|
||||
The actions function should return a set of all the possible actions that can be taken on a given board.
|
||||
Each action should be represented as a tuple (i, j) where i corresponds to the row of the move (0, 1, or 2)
|
||||
and j corresponds to the column of the move (also 0, 1, or 2).
|
||||
|
||||
Possible moves are any cells on the board that do not already have an X or an O in them.
|
||||
|
||||
Any return value is acceptable if a terminal board is provided as input.
|
||||
"""
|
||||
actions = set()
|
||||
for i in range(3):
|
||||
for j in range(3):
|
||||
if board[i][j] == EMPTY:
|
||||
actions.add((i, j))
|
||||
return actions
|
||||
|
||||
|
||||
def succ(board, action):
|
||||
"""
|
||||
Returns the board that results from making move (i, j) on the board, without modifying the original board.
|
||||
|
||||
If `action` is not a valid action for the board, you should raise an exception.
|
||||
|
||||
The returned board state should be the board that would result from taking the original input board, and letting
|
||||
the player whose turn it is make their move at the cell indicated by the input action.
|
||||
|
||||
Importantly, the original board should be left unmodified. This means that simply updating a cell in `board` itself
|
||||
is not a correct implementation of this function. You’ll likely want to make a deep copy of the board first before
|
||||
making any changes.
|
||||
"""
|
||||
if action not in actions(board):
|
||||
raise ValueError("Invalid action")
|
||||
|
||||
new_board = [row[:] for row in board]
|
||||
new_board[action[0]][action[1]] = player(board)
|
||||
|
||||
return new_board
|
||||
|
||||
|
||||
def winner(board):
|
||||
"""
|
||||
Returns the winner of the game, if there is one.
|
||||
|
||||
- If the X player has won the game, the function should return X.
|
||||
- If the O player has won the game, the function should return O.
|
||||
- If there is no winner of the game (either because the game is in progress, or because it ended in a tie), the
|
||||
function should return None.
|
||||
|
||||
You may assume that there will be at most one winner (that is, no board will ever have both players with
|
||||
three-in-a-row, since that would be an invalid board state).
|
||||
"""
|
||||
# Check rows
|
||||
for row in board:
|
||||
if row[0] == row[1] == row[2] and row[0] is not None:
|
||||
return row[0]
|
||||
|
||||
# Check columns
|
||||
for col in range(3):
|
||||
if board[0][col] == board[1][col] == board[2][col] and board[0][col] is not None:
|
||||
return board[0][col]
|
||||
|
||||
# Check diagonals
|
||||
if board[0][0] == board[1][1] == board[2][2] and board[0][0] is not None:
|
||||
return board[0][0]
|
||||
if board[0][2] == board[1][1] == board[2][0] and board[0][2] is not None:
|
||||
return board[0][2]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def terminal(board):
|
||||
"""
|
||||
Returns True if game is over, False otherwise.
|
||||
|
||||
If the game is over, either because someone has won the game or because all cells have been filled without anyone
|
||||
winning, the function should return True.
|
||||
|
||||
Otherwise, the function should return False if the game is still in progress.
|
||||
"""
|
||||
if winner(board) is not None or all(all(cell is not EMPTY for cell in row) for row in board):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def utility(board):
|
||||
"""
|
||||
Returns 1 if X has won the game, -1 if O has won, 0 otherwise.
|
||||
|
||||
You may assume utility will only be called on a board if terminal(board) is True.
|
||||
"""
|
||||
if winner(board) == X:
|
||||
return 1
|
||||
elif winner(board) == O:
|
||||
return -1
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
def minimax(board):
|
||||
"""
|
||||
Returns the optimal action for the current player on the board.
|
||||
|
||||
The move returned should be the optimal action (i, j) that is one of the allowable actions on the board.
|
||||
|
||||
If multiple moves are equally optimal, any of those moves is acceptable.
|
||||
|
||||
If the board is a terminal board, the minimax function should return None.
|
||||
"""
|
||||
if terminal(board):
|
||||
return None
|
||||
|
||||
if player(board) == X:
|
||||
best_score = float('-inf')
|
||||
best_action = None
|
||||
for action in actions(board):
|
||||
score = min_value(succ(board, action))
|
||||
if score > best_score:
|
||||
best_score = score
|
||||
best_action = action
|
||||
return best_action
|
||||
else:
|
||||
best_score = float('inf')
|
||||
best_action = None
|
||||
for action in actions(board):
|
||||
score = max_value(succ(board, action))
|
||||
if score < best_score:
|
||||
best_score = score
|
||||
best_action = action
|
||||
return best_action
|
||||
|
||||
|
||||
def max_value(board):
|
||||
if terminal(board):
|
||||
return utility(board)
|
||||
v = float('-inf')
|
||||
for action in actions(board):
|
||||
v = max(v, min_value(succ(board, action)))
|
||||
return v
|
||||
|
||||
|
||||
def min_value(board):
|
||||
if terminal(board):
|
||||
return utility(board)
|
||||
v = float('inf')
|
||||
for action in actions(board):
|
||||
v = min(v, max_value(succ(board, action)))
|
||||
return v
|
||||
6
main.aux
6
main.aux
@ -6,4 +6,8 @@
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {0.3}Probability}{4}{}\protected@file@percent }
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {0.4}Counting}{6}{}\protected@file@percent }
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {0.5}Programming in Python}{6}{}\protected@file@percent }
|
||||
\gdef \@abspage@last{7}
|
||||
\@writefile{toc}{\contentsline {section}{\numberline {1}Homework 1}{7}{}\protected@file@percent }
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {1.1}Grid City}{7}{}\protected@file@percent }
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {1.2}Six Degrees}{8}{}\protected@file@percent }
|
||||
\@writefile{toc}{\contentsline {subsection}{\numberline {1.3}Tic Tac Toe}{8}{}\protected@file@percent }
|
||||
\gdef \@abspage@last{9}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
# Fdb version 4
|
||||
["pdflatex"] 1707463862.19733 "c:/Users/uzair/OneDrive/Documents/CSC 665/main.tex" "main.pdf" "main" 1707463863.15428 0
|
||||
["pdflatex"] 1709000449.89094 "c:/Users/uzair/OneDrive/Documents/CSC 665/main.tex" "main.pdf" "main" 1709000450.74539 0
|
||||
"C:/Users/uzair/AppData/Local/MiKTeX/fonts/map/pdftex/pdftex.map" 1707457733 80909 eab91d9745dd2edfd62a31d53cd5fe15 ""
|
||||
"C:/Users/uzair/AppData/Local/MiKTeX/fonts/pk/ljfour/jknappen/ec/dpi600/tcrm1000.pk" 1707288887 11548 1854d2b3451e3d517cccd4e0b4daead1 ""
|
||||
"C:/Users/uzair/AppData/Local/MiKTeX/miktex/data/le/pdftex/pdflatex.fmt" 1707288883 24210786 eea8c83a2618bf979528f763e32e98c9 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/tfm/jknappen/ec/tcrm1000.tfm" 993058908 1436 c7f957a372ef2fbe93c0982f96625e12 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/tfm/jknappen/ec/tcrm1000.tfm" 993062508 1436 c7f957a372ef2fbe93c0982f96625e12 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/tfm/public/amsfonts/cmextra/cmex7.tfm" 1233951848 1004 54797486969f23fa377b128694d548df ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/tfm/public/amsfonts/symbols/msam10.tfm" 1233951854 916 f87d7c45f9c908e672703b83b72241a3 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/tfm/public/amsfonts/symbols/msam5.tfm" 1233951854 924 9904cf1d39e9767e7a3622f2a125a565 ""
|
||||
@ -16,47 +16,47 @@
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/tfm/public/cm/cmr12.tfm" 1136765053 1288 655e228510b4c2a1abe905c368440826 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/tfm/public/cm/cmr17.tfm" 1136765053 1292 296a67155bdbfc32aa9c636f21e91433 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/tfm/public/cm/cmti10.tfm" 1136765053 1480 aa8e34af0eb6a2941b776984cf1dfdc4 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmbx10.pfb" 1247593066 34811 78b52f49e893bcba91bd7581cdc144c0 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmbx12.pfb" 1247593066 32080 340ef9bf63678554ee606688e7b5339d ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmex10.pfb" 1247593067 30251 6afa5cb1d0204815a708a080681d4674 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmmi10.pfb" 1247593067 36299 5f9df58c2139e7edcf37c8fca4bd384d ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmmi7.pfb" 1247593067 36281 c355509802a035cadc5f15869451dcee ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmr10.pfb" 1247593067 35752 024fb6c41858982481f6968b5fc26508 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmr12.pfb" 1247593067 32722 d7379af29a190c3f453aba36302ff5a9 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmr7.pfb" 1247593067 32762 7fee39e011c23b3589931effd97b9702 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmsy10.pfb" 1247593067 32569 5e5ddc8df908dea60932f3c484a54c0d ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmsy7.pfb" 1247593066 32716 08e384dc442464e7285e891af9f45947 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmti10.pfb" 1247593067 37944 359e864bd06cde3b1cf57bb20757fb06 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/latxfont/line10.pfb" 1247593053 11493 4f5ed183a47d3197cf8cd322325db6de ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmbx10.pfb" 1247596666 34811 78b52f49e893bcba91bd7581cdc144c0 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmbx12.pfb" 1247596666 32080 340ef9bf63678554ee606688e7b5339d ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmex10.pfb" 1247596667 30251 6afa5cb1d0204815a708a080681d4674 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmmi10.pfb" 1247596667 36299 5f9df58c2139e7edcf37c8fca4bd384d ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmmi7.pfb" 1247596667 36281 c355509802a035cadc5f15869451dcee ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmr10.pfb" 1247596667 35752 024fb6c41858982481f6968b5fc26508 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmr12.pfb" 1247596667 32722 d7379af29a190c3f453aba36302ff5a9 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmr7.pfb" 1247596667 32762 7fee39e011c23b3589931effd97b9702 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmsy10.pfb" 1247596667 32569 5e5ddc8df908dea60932f3c484a54c0d ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmsy7.pfb" 1247596666 32716 08e384dc442464e7285e891af9f45947 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmti10.pfb" 1247596667 37944 359e864bd06cde3b1cf57bb20757fb06 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/latxfont/line10.pfb" 1247596653 11493 4f5ed183a47d3197cf8cd322325db6de ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/context/base/mkii/supp-pdf.mkii" 1580390158 71627 94eb9990bed73c364d7f53f960cc8c5b ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/00miktex/epstopdf-sys.cfg" 1616063685 584 2a1075dd71571459f59146da9f7502ad ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/00miktex/epstopdf-sys.cfg" 1616067285 584 2a1075dd71571459f59146da9f7502ad ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/amsfonts/amsfonts.sty" 1358197772 5949 3f3fd50a8cc94c3d4cbf4fc66cd3df1c ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/amsfonts/amssymb.sty" 1358197772 13829 94730e64147574077f8ecfea9bb69af4 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/amsfonts/umsa.fd" 1358197772 961 6518c6525a34feb5e8250ffa91731cff ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/amsfonts/umsb.fd" 1358197772 961 d02606146ba5601b5645f987c92e6193 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/amsmath/amsbsy.sty" 1686928188 2222 499d61426192c39efd8f410ee1a52b9c ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/amsmath/amsgen.sty" 1686928187 4173 82ac04dfb1256038fad068287fbb4fe6 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/amsmath/amsmath.sty" 1686928188 88371 d84032c0f422c3d1e282266c01bef237 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/amsmath/amsopn.sty" 1686928188 4474 b811654f4bf125f11506d13d13647efb ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/amsmath/amstext.sty" 1686928188 2444 0d0c1ee65478277e8015d65b86983da2 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/amsmath/amsbsy.sty" 1686931788 2222 499d61426192c39efd8f410ee1a52b9c ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/amsmath/amsgen.sty" 1686931787 4173 82ac04dfb1256038fad068287fbb4fe6 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/amsmath/amsmath.sty" 1686931788 88371 d84032c0f422c3d1e282266c01bef237 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/amsmath/amsopn.sty" 1686931788 4474 b811654f4bf125f11506d13d13647efb ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/amsmath/amstext.sty" 1686931788 2444 0d0c1ee65478277e8015d65b86983da2 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/base/article.cls" 1705273579 20144 147463a6a579f4597269ef9565205cfe ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/base/size10.clo" 1705273578 8448 dbc0dbf4156c0bb9ba01a1c685d3bad0 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/cancel/cancel.sty" 1388370247 7592 dd751af313a16a0308545d5bfd7aaaa2 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/epstopdf-pkg/epstopdf-base.sty" 1622999586 13886 d1306dcf79a944f6988e688c1785f9ce ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/graphics-cfg/graphics.cfg" 1465890692 1224 978390e9c2234eab29404bc21b268d1e ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/graphics-def/pdftex.def" 1663915090 19448 1e988b341dda20961a6b931bcde55519 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/graphics/graphics.sty" 1665063979 18387 8f900a490197ebaf93c02ae9476d4b09 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/graphics/graphicx.sty" 1665063979 8010 a8d949cbdbc5c983593827c9eec252e1 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/graphics/keyval.sty" 1665063979 2671 7e67d78d9b88c845599a85b2d41f2e39 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/graphics/trig.sty" 1665063979 4023 293ea1c16429fc0c4cf605f4da1791a9 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/epstopdf-pkg/epstopdf-base.sty" 1623003186 13886 d1306dcf79a944f6988e688c1785f9ce ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/graphics-cfg/graphics.cfg" 1465894292 1224 978390e9c2234eab29404bc21b268d1e ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/graphics-def/pdftex.def" 1663918690 19448 1e988b341dda20961a6b931bcde55519 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/graphics/graphics.sty" 1665067579 18387 8f900a490197ebaf93c02ae9476d4b09 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/graphics/graphicx.sty" 1665067579 8010 a8d949cbdbc5c983593827c9eec252e1 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/graphics/keyval.sty" 1665067579 2671 7e67d78d9b88c845599a85b2d41f2e39 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/graphics/trig.sty" 1665067579 4023 293ea1c16429fc0c4cf605f4da1791a9 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/l3backend/l3backend-pdftex.def" 1704400941 30006 57b07afb710ee2f649c65cfbafda39c1 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/mathtools/mathtools.sty" 1656511286 62269 5c1837a5bc5db4c0d255eedc225ca44b ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/mathtools/mhsetup.sty" 1656511286 5582 a43dedf8e5ec418356f1e9dfe5d29fc3 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/mathtools/mathtools.sty" 1656514886 62269 5c1837a5bc5db4c0d255eedc225ca44b ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/mathtools/mhsetup.sty" 1656514886 5582 a43dedf8e5ec418356f1e9dfe5d29fc3 ""
|
||||
"C:/Users/uzair/AppData/Local/Programs/MiKTeX/tex/latex/tools/calc.sty" 1700599895 10214 547fd4d29642cb7c80bf54b49d447f01 ""
|
||||
"c:/Users/uzair/OneDrive/Documents/CSC 665/main.tex" 1707463861 9116 b6ac4480cf77923a8dc09ee3aba8dbcd ""
|
||||
"main.aux" 1707463862 679 285e5213a7436d1f29c230a5e4d21e1f "pdflatex"
|
||||
"main.tex" 1707463861 9116 b6ac4480cf77923a8dc09ee3aba8dbcd ""
|
||||
"titlePage.aux" 1707463862 456 c979711f53deacf2b09031977e556db8 "pdflatex"
|
||||
"c:/Users/uzair/OneDrive/Documents/CSC 665/main.tex" 1709000447 12730 ae20bfc5e0f04caa86c900106aea97ed ""
|
||||
"main.aux" 1709000450 1087 ba931f15dd3503a818797c381a180181 "pdflatex"
|
||||
"main.tex" 1709000447 12730 ae20bfc5e0f04caa86c900106aea97ed ""
|
||||
"titlePage.aux" 1709000450 456 c979711f53deacf2b09031977e556db8 "pdflatex"
|
||||
"titlePage.tex" 1707288498 394 ccdbd50244b3194dbad72dd1c7995bf0 ""
|
||||
(generated)
|
||||
"main.aux"
|
||||
|
||||
14
main.log
14
main.log
@ -1,4 +1,4 @@
|
||||
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (MiKTeX 24.1) (preloaded format=pdflatex 2024.2.6) 8 FEB 2024 23:31
|
||||
This is pdfTeX, Version 3.141592653-2.6-1.40.25 (MiKTeX 24.1) (preloaded format=pdflatex 2024.2.6) 26 FEB 2024 18:20
|
||||
entering extended mode
|
||||
restricted \write18 enabled.
|
||||
file:line:error style messages enabled.
|
||||
@ -215,24 +215,24 @@ Underfull \hbox (badness 10000) in paragraph at lines 108--111
|
||||
|
||||
[]
|
||||
|
||||
[4] [5] [6] (main.aux (titlePage.aux))
|
||||
[4] [5] [6] [7] [8] (main.aux (titlePage.aux))
|
||||
***********
|
||||
LaTeX2e <2023-11-01> patch level 1
|
||||
L3 programming layer <2024-01-22>
|
||||
***********
|
||||
)
|
||||
Here is how much of TeX's memory you used:
|
||||
3222 strings out of 474542
|
||||
50257 string characters out of 5744447
|
||||
3224 strings out of 474542
|
||||
50311 string characters out of 5744447
|
||||
1935978 words of memory out of 5000000
|
||||
25434 multiletter control sequences out of 15000+600000
|
||||
25436 multiletter control sequences out of 15000+600000
|
||||
562573 words of font info for 53 fonts, out of 8000000 for 9000
|
||||
1141 hyphenation exceptions out of 8191
|
||||
65i,19n,72p,466b,279s stack positions out of 10000i,1000n,20000p,200000b,200000s
|
||||
<C:\Users\uzair\AppData\Local\MiKTeX\fonts/pk/ljfour/jknappen/ec/dpi600\tcrm1000.pk><C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmbx10.pfb><C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmbx12.pfb><C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmex10.pfb><C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmmi10.pfb><C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmmi7.pfb><C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmr10.pfb><C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmr12.pfb><C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmr7.pfb><C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmsy10.pfb><C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmsy7.pfb><C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/cm/cmti10.pfb><C:/Users/uzair/AppData/Local/Programs/MiKTeX/fonts/type1/public/amsfonts/latxfont/line10.pfb>
|
||||
Output written on main.pdf (7 pages, 155481 bytes).
|
||||
Output written on main.pdf (9 pages, 163153 bytes).
|
||||
PDF statistics:
|
||||
91 PDF objects out of 1000 (max. 8388607)
|
||||
97 PDF objects out of 1000 (max. 8388607)
|
||||
0 named destinations out of 1000 (max. 500000)
|
||||
1 words of extra memory for PDF output out of 10000 (max. 10000000)
|
||||
|
||||
|
||||
BIN
main.synctex.gz
BIN
main.synctex.gz
Binary file not shown.
73
main.tex
73
main.tex
@ -128,7 +128,7 @@ When it's time to submit an assignment, I will export this document as a PDF fil
|
||||
|
||||
\underline{Solution}:\\
|
||||
$\rightarrow$ \underline{Let} $P(A) = 0.6$ (probability battery is from Factory A)\\
|
||||
$\rightarrow$ \underline{Let} $P(D|A) = 0.02$ (probaility battery is defective if it's from Factory A)\\
|
||||
$\rightarrow$ \underline{Let} $P(D|A) = 0.02$ (probability battery is defective if it's from Factory A)\\
|
||||
$\rightarrow$ \underline{Let} $P(A)' = 0.4$ (probability battery is not from Factory A)\\
|
||||
$\rightarrow$ \underline{Let} $P(D|A)' = 0.04$ (probability battery is defective if it's not from Factory A)
|
||||
|
||||
@ -190,4 +190,75 @@ that you have COVID?
|
||||
\subsection{Programming in Python}
|
||||
See attached .py file
|
||||
|
||||
\newpage
|
||||
|
||||
\section{Homework 1}
|
||||
|
||||
\textit{By turning in this assignment, I agree to abide by SFSU's academic integrity code and declare that all of my solutions are my own work: }
|
||||
|
||||
\subsection{Grid City}
|
||||
|
||||
Modeled as a search problem:
|
||||
\begin{itemize}
|
||||
\item $s_0 = (0,0)$
|
||||
\item Actions$(s) = \lbrace{(+1,0), (-1,0), (0,+1), (0,-1)}\rbrace$
|
||||
\item Succ$(s,a) = s+a$
|
||||
\item Cost$((x,y), a) = 1+$ max$(x,0)$ (it is more expensive as you go further to the right)
|
||||
\item IsEnd$(s) = \begin{cases}
|
||||
\text{True} &\text{if\ } s = (m,n)\\
|
||||
\text{False} &\text{otherwise}
|
||||
\end{cases}$
|
||||
\end{itemize}
|
||||
|
||||
\begin{itemize}
|
||||
\item[a.] Minimum cost of reaching location $(m,n)$ starting from $(0,0)$? Describe possible path achieving the minimum cost. Is it unique?
|
||||
|
||||
\underline{Solution}: Since $(m,n) \geq 0$, we can safely say that $(m,n)$ can't be at $(0,0)$ in the minimum cost path. The next closest location to $(0,0)$ that $(m,n)$
|
||||
could be is $(1,1)$, as it satisfies the condition listed earlier. With this in mind, the minimum cost would be:
|
||||
\begin{align*}
|
||||
\text{Cost}((x,y),a) &= 1 + \text{max}(x,0) \\
|
||||
&= (1 + \text{max}(m,0)) + (1 + \text{max}(n,0)) \\
|
||||
&= 1 + m + 1 + n \\
|
||||
\Aboxed{&= 2 + m + n}
|
||||
\end{align*}
|
||||
|
||||
\item[b.] True or false (and explain): UCS will never terminate on this problem because the number of states is infinite.
|
||||
|
||||
\underline{Solution}: False, because UCS explores nodes with the lowest cost first. If $(m,n)$ is available at the minimum cost from $(0,0)$, then UCS will terminate, and that too fairly quickly.
|
||||
|
||||
\item[c.] True or false (and explain): UCS will return the minimum cost path and explore only locations between $(0, 0)$ and $(m, n)$; that is, locations $(x, y)$ such that $0 \leq x \leq m$ and $0 \leq y \leq n$.
|
||||
|
||||
\underline{Solution}: True, if $(m,n)$ is available at the minimum cost from $(0,0)$, because UCS will terminate very quickly and therefore won't explore other paths. This is because UCS prioritizes the lowest cost first.
|
||||
|
||||
|
||||
\item[d.] True or false (and explain): UCS will return the minimum cost path and explore only
|
||||
locations whose path costs are strictly less than the minimum cost from $(0, 0)$ to $(m, n)$.
|
||||
|
||||
\underline{Solution}: True, because UCS focuses on cumulative costs that are less than the optimal cost to reach $(m,n)$.
|
||||
|
||||
\end{itemize}
|
||||
|
||||
Now consider UCS running on an arbitrary graph.
|
||||
|
||||
\begin{itemize}
|
||||
\item[e.] True or false (and explain): If you add an edge between two nodes, the cost of the min-cost path cannot go up.
|
||||
|
||||
\underline{Solution}: True, because adding an edge can only maintain or reduce the cost of the min-cost path.
|
||||
|
||||
\item[f.] True or false (and explain): If you make the cost of an action from some state small enough (possibly negative), you can guarantee that that action will show up in the minimum cost path.
|
||||
|
||||
\underline{Solution}: False, because that action isn't guaranteed to lead us to the goal, no matter how cheap we make it.
|
||||
|
||||
\item[g.] True or false (and explain): If you increase the cost of every action by 1, the minimum cost path does not change (even though its cost does).
|
||||
|
||||
\underline{Solution}: True. Since we are raising the cost of \underline{all} costs equally, the minimum cost path will remain the the same even despite the costs going up.
|
||||
|
||||
\subsection{Six Degrees}
|
||||
See degrees.py
|
||||
|
||||
\subsection{Tic Tac Toe}
|
||||
See tictactoe.py
|
||||
|
||||
\end{itemize}
|
||||
|
||||
\end{document}
|
||||
Loading…
Reference in New Issue
Block a user