Compare commits

..

22 Commits

Author SHA1 Message Date
9c2535274d renamed pdf 2026-04-16 15:22:51 -04:00
f03e390fa4 reformatted docstrtings 2026-04-16 15:22:23 -04:00
98a24a92cb finished project 3 2026-04-16 14:27:02 -04:00
470d4b0b2b Final changes to project 3 2026-04-16 14:22:01 -04:00
34e88112c6 added typehints 2026-04-16 14:16:23 -04:00
864d07348d Final changes to Project 1 and Project 2 2026-04-09 14:27:21 -04:00
a30e9b2556 Changes from CAT session 2026-04-09 14:15:45 -04:00
6949336bbe finished revisions for project 2 2026-04-01 21:05:49 -04:00
33e75d0529 Revisions for Project 1 2026-04-01 20:30:46 -04:00
f0dda78b43 added repr 2026-04-01 11:54:16 -04:00
e613278fa2 added tests to Card.py 2026-04-01 11:52:25 -04:00
1b7352680b finished project 5 version 1 2026-03-30 11:27:29 -04:00
deba677725 test commit for git token 2026-03-30 09:38:33 -04:00
8dc989a0a8 Part f 2026-03-30 09:35:47 -04:00
5e3b122ab1 spacing 2026-03-30 09:25:54 -04:00
6c2d865d96 modified dfs() for part e 2026-03-30 09:25:29 -04:00
98a59532da part d 2026-03-30 09:21:53 -04:00
2f6dd3858c added to main 2026-03-30 09:19:29 -04:00
d4b6db8edf added main 2026-03-30 09:19:13 -04:00
9ca023025b added part b of step 4 2026-03-30 09:17:33 -04:00
97bdfd1907 added imports 2026-03-30 09:16:47 -04:00
ee4da2417d Finished step 2 2026-03-30 09:12:30 -04:00
31 changed files with 351 additions and 70 deletions

2
.idea/misc.xml generated
View File

@@ -3,5 +3,5 @@
<component name="Black">
<option name="sdkName" value="Python 3.14 (test)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.14 (test)" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.14" project-jdk-type="Python SDK" />
</project>

2
.idea/test.iml generated
View File

@@ -4,7 +4,7 @@
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.14 (test)" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="Python 3.14" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -1,3 +1,10 @@
######################################
# DCS 229 -- Unfair Solitaire
# This is the Card.py file, which defines the Card class used in the Solitaire game. The Card class represents a playing card with a suit and value, and includes methods to retrieve the suit and value, as well as a string representation of the card.
# Date: 04/01/2026
# Name: Benjamin Adovasio
# Resources Used: Fran
##########################################
class Card:
"""
Represents a playing card with a suit and value.
@@ -20,3 +27,17 @@ class Card:
return f"{self._value} of {self._suit}"
#Returns a string representation of the card in the format "Value of Suit".
if __name__ == "__main__":
card1 = Card("Hearts", "Ace")
card2 = Card("Spades", "10")
assert card1.get_suit() == "Hearts"
assert card1.get_value() == "Ace"
assert card2.get_suit() == "Spades"
assert card2.get_value() == "10"
assert repr(card1) == "Ace of Hearts"
assert repr(card2) == "10 of Spades"
print("All Card tests passed.")

View File

@@ -1,3 +1,11 @@
######################################
# DCS 229 -- Unfair Solitaire
# This is the Deck.py file, which defines the Deck class used in the Solitaire game. The Deck class represents a standard 52-card deck, and includes methods to shuffle the deck, deal cards, and check the number of remaining cards.
# Date: 04/01/2026
# Name: Benjamin Adovasio
# Resources Used: Fran
##########################################
import random
from Card import Card
@@ -19,12 +27,18 @@ class Deck:
self._cards.append(Card(suit, value)) #creates a standard 52-card deck
def shuffle(self):
"""
Shuffles the deck of cards using the Fisher-Yates algorithm. This algorithm iterates through the deck and swaps each card with a randomly selected card from the remaining unshuffled portion of the deck. After shuffling, it resets the next card index to 0.
"""
for i in range(len(self._cards)): #iterates through each card in the deck
j = random.randrange(i, len(self._cards)) #selects a random index from i to the end of the deck
self._cards[i], self._cards[j] = self._cards[j], self._cards[i] #Shuffles the deck
self._next_card = 0 #Resets the next card index after shuffling.
def deal(self):
"""
Deals the next card from the deck. Returns None if there are no cards left to deal.
"""
if self._next_card >= len(self._cards):
return None #Returns None if there are no cards left to deal.
card = self._cards[self._next_card]
@@ -34,6 +48,14 @@ class Deck:
def number_of_cards(self) -> int:
return len(self._cards) - self._next_card #Returns the number of remaining cards in the deck.
def __repr__(self) -> str:
"""
Returns a string representation of the entire deck,
with one card per line.
"""
return "\n".join(str(card) for card in self._cards)
if __name__ == "__main__":
deck = Deck()
deck.shuffle() #Calls the shuffle method to randomize the deck.

BIN
Project 1/Project 1.pdf Normal file

Binary file not shown.

View File

@@ -1,19 +1,28 @@
from Deck import Deck
"""
Defines the Solitaire game logic. Contains methods to play the game by dealing cards, removing cards based on game rules, and checking for a win condition.
######################################
# DCS 229 -- Unfair Solitaire
# Defines the Solitaire game logic. Contains methods to play the game by dealing cards, removing cards based on game rules, and checking for a win condition.
# Name: Benjamin Adovasio
# Resources Used: Fran
##########################################
from Deck import Deck
Important Note: The prints in this file only run when this file is ececuted directly. This file should not be executed directly normally.
"""
class Solitaire:
def __init__(self):
self.deck = Deck()
self.face_up = [] #List to hold face-up cards.
'''
deals cards until there are four face-up cards or the deck is empty.
'''
def deal_until_four(self):
while len(self.face_up) < 4 and self.deck.number_of_cards() > 0:
self.face_up.append(self.deck.deal()) #Deals cards until there are four face-up cards.
'''
removes the last four cards if they are all the same suit. Returns True if cards were removed, False otherwise.
'''
def remove_four_same_suit(self) -> bool:
if len(self.face_up) < 4:
return False #Not enough cards to remove four of the same suit.
@@ -27,6 +36,9 @@ class Solitaire:
return False
'''
removes the inner two cards if the first and last card of the last four cards are the same suit. Returns True if cards were removed, False otherwise.
'''
def remove_inner_two(self) -> bool:
if len(self.face_up) < 4:
return False #Not enough cards to remove inner two cards.
@@ -38,6 +50,10 @@ class Solitaire:
return False
'''
Attempts to remove cards based on game rules.
'''
def remove_all_possible(self):
removed = True
while removed and len(self.face_up) >= 4:
@@ -45,6 +61,9 @@ class Solitaire:
if not removed:
removed = self.remove_inner_two() # Attempts to remove cards based on game rules.
'''
plays the game by shuffling the deck, dealing cards, removing cards based on game rules, and checking for a win condition.
'''
def playGame(self) -> bool:
self.deck.shuffle()
self.face_up = []

View File

@@ -1,6 +1,10 @@
"""
This is the main file that should be called to run the simulation.
"""
######################################
# DCS 229 -- Unfair Solitaire
# This is the main.py file, which contains the main function to run the simulation.
# Date: 04/01/2026
# Name: Benjamin Adovasio
# Resources Used: Fran
##########################################
from Solitaire import Solitaire

2
Project 1/test.py Normal file
View File

@@ -0,0 +1,2 @@
for i in range (0, 10):
print(i)

View File

@@ -1,3 +1,11 @@
######################################
# DCS 229 -- Project 2
# This is the Card.py file, which defines the Card class used in the Solitaire game. The Card class represents a playing card with a suit and value, and includes methods to retrieve the suit and value, as well as a string representation of the card.
# Date: 04/01/2026
# Name: Benjamin Adovasio
# Resources Used: Fran
##########################################
class Card:
"""
Represents a playing card with a suit and value.
@@ -23,9 +31,15 @@ class Card:
def __add__(self, other) -> int:
#Adding 2 cards together
return "Cat"
if isinstance(other, Card):
return self.value + other.value
return self._value + other._value
elif isinstance(other, int):
#allows adding a card to an int
return self.value + other
return self._value + other
return NotImplemented
def __radd__(self, other) -> int:
return self.__add__(other)
#Added for project 2: Created an "__add__" meathod to allow adding Cards together.

View File

@@ -1,3 +1,11 @@
######################################
# DCS 229 -- Project 2
# This is the Deck.py file, which defines the Deck class used in the Solitaire game. The Deck class represents a standard 52-card deck, and includes methods to shuffle the deck, deal cards, and check the number of remaining cards.
# Date: 04/01/2026
# Name: Benjamin Adovasio
# Resources Used: Fran
##########################################
import random
from Card import Card
"""
@@ -18,12 +26,18 @@ class Deck:
self._cards.append(Card(suit, value)) #creates a standard 52-card deck
def shuffle(self):
"""
Shuffles the deck of cards using the Fisher-Yates algorithm. This algorithm iterates through the deck and swaps each card with a randomly selected card from the remaining unshuffled portion of the deck. After shuffling, it resets the next card index to 0.
"""
for i in range(len(self._cards)): #iterates through each card in the deck
j = random.randrange(i, len(self._cards)) #selects a random index from i to the end of the deck
self._cards[i], self._cards[j] = self._cards[j], self._cards[i] #Shuffles the deck
self._next_card = 0 #Resets the next card index after shuffling.
def deal(self):
"""
Deals the next card from the deck. Returns None if there are no cards left to deal.
"""
if self._next_card >= len(self._cards):
return None #Returns None if there are no cards left to deal.
card = self._cards[self._next_card]
@@ -33,6 +47,13 @@ class Deck:
def number_of_cards(self) -> int:
return len(self._cards) - self._next_card #Returns the number of remaining cards in the deck.
def __repr__(self) -> str:
"""
Returns a string representation of the entire deck,
with one card per line.
"""
return "\n".join(str(card) for card in self._cards)
if __name__ == "__main__":
deck = Deck()
deck.shuffle() #Calls the shuffle method to randomize the deck.

BIN
Project 2/Project 2.pdf Normal file

Binary file not shown.

View File

@@ -1,19 +1,28 @@
from Deck import Deck
"""
Defines the Solitaire game logic. Contains methods to play the game by dealing cards, removing cards based on game rules, and checking for a win condition.
######################################
# DCS 229 -- Project 2
# Defines the Solitaire game logic. Contains methods to play the game by dealing cards, removing cards based on game rules, and checking for a win condition.
# Name: Benjamin Adovasio
# Resources Used: Fran
##########################################
from Deck import Deck
Important Note: The prints in this file only run when this file is ececuted directly. This file should not be executed directly normally.
"""
class Solitaire:
def __init__(self):
self.deck = Deck()
self.face_up = [] #List to hold face-up cards.
'''
deals cards until there are four face-up cards or the deck is empty.
'''
def deal_until_four(self):
while len(self.face_up) < 4 and self.deck.number_of_cards() > 0:
self.face_up.append(self.deck.deal()) #Deals cards until there are four face-up cards.
'''
removes the last four cards if they are all the same suit. Returns True if cards were removed, False otherwise.
'''
def remove_four_same_suit(self) -> bool:
if len(self.face_up) < 4:
return False #Not enough cards to remove four of the same suit.
@@ -27,6 +36,9 @@ class Solitaire:
return False
'''
removes the inner two cards if the first and last card of the last four cards are the same suit. Returns True if cards were removed, False otherwise.
'''
def remove_inner_two(self) -> bool:
if len(self.face_up) < 4:
return False #Not enough cards to remove inner two cards.
@@ -38,6 +50,9 @@ class Solitaire:
return False
'''
Attempts to remove cards based on game rules.
'''
def remove_all_possible(self):
removed = True
while removed and len(self.face_up) >= 4:
@@ -45,6 +60,9 @@ class Solitaire:
if not removed:
removed = self.remove_inner_two() # Attempts to remove cards based on game rules.
'''
plays the game by shuffling the deck, dealing cards, removing cards based on game rules, and checking for a win condition.
'''
def playGame(self) -> bool:
self.deck.shuffle()
self.face_up = []

Binary file not shown.

Binary file not shown.

View File

@@ -1,6 +1,11 @@
"""
This is the main file that should be called to run the simulation.
"""
######################################
# DCS 229 -- Unfair Solitaire
# This is the main.py file, which contains the main function to run the simulation.
# Date: 04/01/2026
# Name: Benjamin Adovasio
# Resources Used: Fran
##########################################
from Solitaire import Solitaire

View File

@@ -1,24 +1,37 @@
"""
Reo
"""
######################################
# DCS 229 -- Project 2
# This is the utilities.py file, which contains utility functions for the Solitaire game.
# Date: 04/01/2026
# Name: Benjamin Adovasio
# Resources Used: Fran
##########################################
from __future__ import annotations
from Card import Card
def sum_cards_iter(cards: list[Card]) -> int:
'''
Added for project 2: Created a function to sum a list of Card objects using iteration.
'''
def sum_cards_iter(cards: list[Card]) -> int: #start total at 0
total = 0 #start total at 0
for card in cards:
total = total + card
total = total + card #Adds the value of each card to the total using iteration.
return total
#Added for project 2: Created a function to sum a list of Card objects using iteration.
def sum_cards_recursive(cards: list[Card]) -> int:
'''
Added for project 2: Created a function to sum a list of Card objects using recursion.
'''
def sum_cards_recursive(cards: list[Card]) -> int: #start total at 0
if cards == []:
#Base case
return 0
return cards[0] + sum_cards_recursive(cards[1:])
return 0 #If the list of cards is empty, return 0.
return cards[0] + sum_cards_recursive(cards[1:]) #Adds the value of the first card to the sum of the remaining cards using recursion.
#Recursive case
#Added for project 2: Created a function to sum a list of Card objects using recursion.
'''
Added for project 2: Example tests given
'''
def test_sum_cards():
cards = [
Card("diamond", 5),
@@ -26,6 +39,8 @@ def test_sum_cards():
Card("spade", 12),
Card("clubs", 1)
]
assert sum_cards_iter(cards) == 21
assert sum_cards_recursive(cards) == 21
#Added for project 2: Example tests given
print(sum_cards_iter(cards))
# assert sum_cards_iter(cards) == 21
# assert sum_cards_recursive(cards) == 21
test_sum_cards()

Binary file not shown.

Binary file not shown.

View File

@@ -9,15 +9,18 @@
import random #to generate the 100 random values
import time #for part 4, to calculae total time
from collections.abc import Sequence
#I decided to put all 4 functions into one class to keep it organized
class Search:
"""
This function generates the list of random integers.
"""
def generate_random_list(self, n):
array = [] #array starts as blank
def generate_random_list(self, n: int) -> list[int]:
"""
This function generates a list of n random integers between 0 and 1000, and returns the list.
Args: n: the number of random integers to generate
Returns: a list of n random integers between 0 and 1000
"""
array: list[int] = [] #array starts as blank
for element in range(n): #will run n times
array.append(random.randint(0, 1000)) #random integer between 0-1000
@@ -27,10 +30,12 @@ class Search:
return array
"""
This funciton preforms a search on the list for the target value, and prints the number of checks it took to find the target.
"""
def linear_search_print(self, arr, target):
def linear_search_print(self, arr: Sequence[int], target: int) -> int:
"""
This function performs a linear search for the target value in the given array. It prints the number of unsuccessful checks it took to find the target value, and returns the number of checks. If the target value is not found, it prints "Not found." and returns the total number of checks.
Args: arr: the array to search through, target: the value to search for
Returns: the number of checks it took to find the target value, or the total number of checks if the target value is not found
"""
checks = 0 #check count starts at 0
for value in arr:
if value == target:
@@ -41,10 +46,13 @@ class Search:
print("Not found.") #Only gets printed if the code doesnt return earlier
return checks
"""
This function is the same as the previous one, but instead of printing the number of checks, it returns the number of checks.
"""
def linear_search_count(self, arr, target):
def linear_search_count(self, arr: Sequence[int], target: int) -> int:
"""
This function performs a linear search for the target value in the given array. It returns the number of checks it took to find the target value, or the total number of checks if the target value is not found.
Args: arr: the array to search through, target: the value to search for
Returns: the number of checks it took to find the target value, or the total number of checks if the target value is not found
"""
checks = 0
for value in arr:
checks += 1
@@ -52,10 +60,22 @@ class Search:
return checks
return checks
"""
This function uses recursive searching.
"""
def binary_search_recursive(self, arr, target, low, high):
def binary_search_recursive(
self,
arr: Sequence[int],
target: int,
low: int = 0,
high: int | None = None,
) -> int:
"""
This function performs a binary search for the target value in the given sorted array. It returns the index of the target value if found, or -1 if not found.
Args: arr: the sorted array to search through, target: the value to search for
Returns: the index of the target value if found, or -1 if not found
"""
if high is None:
high = len(arr) - 1
if low > high:
return -1 #base case: if low is greater than high, the target is not found
@@ -68,7 +88,12 @@ class Search:
else:
return self.binary_search_recursive(arr, target, low, mid - 1)
def main():
def main(n: int = 1000) -> None:
"""
This function is the main function that runs the search tests. It generates random lists of integers, performs linear and binary searches, and prints the results.
Args: n: the number of random integers to generate for the tests (default is 1000)
Returns: None
"""
search = Search() #search object to call Search() class
"""
@@ -92,16 +117,13 @@ def main():
Part 3: Uses the recursive search
"""
arr = sorted(search.generate_random_list(100)) #generate the list of 100 random integers and sort it for binary search
index = search.binary_search_recursive(arr, 42, 0, len(arr) - 1) #search for the value 42 using binary search and get the index of 42
index = search.binary_search_recursive(arr, 42) #search for the value 42 using binary search and get the index of 42
print("Index of 42 in sorted array:", index) #print the index of 42 in the sorted array
"""
Part 4: Tests
At what number of queries does Sorting + Binary Search start to show an advantage over Linear Search?:
Sorting + binary search shows an advantage at around 500 queries
"""
n = 1000
arr = search.generate_random_list(n) #generate the list of n random integers
for multiplier in [0.5, 1, 2, 4]: #I used a "multiplier" to avoid rewriting the code for each query
@@ -112,17 +134,17 @@ def main():
queries.append(random.choice(arr))
# Linear timing
start = time.perf_counter()
start = time.perf_counter() #start time is recorded before any of the queries are searched for using linear search
for q in queries:
search.linear_search_count(arr, q)
end = time.perf_counter()
search.linear_search_count(arr, q) #search for each query using linear search on the unsorted array
end = time.perf_counter() #end time is recorded after all queries have been searched for using linear search
linear_time = end - start
# Sorting + Binary timing
start = time.perf_counter()
sorted_arr = sorted(arr)
start = time.perf_counter() #start time is recorded before the array is sorted and any of the queries are searched for using binary search
sorted_arr = sorted(arr) #the array is sorted before the queries are searched for using binary search, but the time it takes to sort the array is included in the total time for this part
for q in queries:
search.binary_search_recursive(sorted_arr, q, 0, len(sorted_arr) - 1)
search.binary_search_recursive(sorted_arr, q) #search for each query using binary search on the sorted array
end = time.perf_counter()
binary_time = end - start

107
Project 5/TurtleDFS.py Normal file
View File

@@ -0,0 +1,107 @@
######################################
# DCS 229 -- TurtleDFS
# Depth-First Search implementation for Turtle Maze
# Date: 03/29/2026
# Name: Benjamin Adovasio
# Resources Used: I worked with Pat Cohen on the project.
##########################################
import os
from Stack import Stack
from TurtleMaze import TurtleMaze, Cell, Contents
def get_neighbors(maze: TurtleMaze, cell: Cell) -> list[Cell]:
'''returns a list of non-obstacle neighbors in north, south, east, west order'''
neighbors = []
row = cell.y
col = cell.x
# north
if row - 1 >= 0:
north = maze[row - 1][col]
if not north.isBlocked():
neighbors.append(north)
# south
if row + 1 < len(maze.maze_grid):
south = maze[row + 1][col]
if not south.isBlocked():
neighbors.append(south)
# east
if col + 1 < len(maze[0]):
east = maze[row][col + 1]
if not east.isBlocked():
neighbors.append(east)
# west
if col - 1 >= 0:
west = maze[row][col - 1]
if not west.isBlocked():
neighbors.append(west)
return neighbors
def dfs(maze: TurtleMaze) -> bool:
'''runs a non-recursive depth first search on the maze with backtracking
Returns:
True if the goal is found, False otherwise
'''
stack = Stack()
start = maze.getStart()
visited = set()
stack.push(start)
visited.add((start.y, start.x))
maze.updatePosition(start)
while not stack.is_empty():
current = stack.peek()
# if we reached the goal, we are done
if current.isGoal():
return True
found_next = False
# look for an unvisited neighbor
for neighbor in get_neighbors(maze, current):
if (neighbor.y, neighbor.x) not in visited:
neighbor.setParent(current)
visited.add((neighbor.y, neighbor.x))
stack.push(neighbor)
if not neighbor.isGoal():
maze.updatePosition(neighbor, Contents.TRIED)
else:
maze.updatePosition(neighbor)
found_next = True
break
# if no unvisited neighbor exists, backtrack
if not found_next:
dead_end = stack.pop()
if dead_end != start and not dead_end.isGoal():
maze.updatePosition(dead_end, Contents.DEAD_END)
if not stack.is_empty():
maze.updatePosition(stack.peek())
return False
def main():
maze = TurtleMaze('maze_1.txt')
maze.drawMaze()
solved = dfs(maze)
print("Maze solved:", solved)
maze.t.screen.mainloop()
if __name__ == "__main__":
main()

View File

@@ -235,16 +235,27 @@ class TurtleMaze:
def main():
maze = TurtleMaze('maze_3.txt')
maze = TurtleMaze('maze_2.txt')
maze.drawMaze()
# print("row at index 4", maze[4])
# print("cell at index 4, 4", maze[4][4])
# print the contents of the top-right corner
top_right = maze[0][len(maze[0]) - 1]
print("Top-right corner:", top_right)
# print the start and goal cells
print("Start cell:", maze.getStart())
print("Goal cell:", maze.getGoal())
# start at S
maze.updatePosition(maze.getStart())
print(maze.getStart())
# move only to neighboring cells so the turtle stays on the path
maze.updatePosition(maze[9][15], Contents.TRIED) # down 1
maze.updatePosition(maze[9][16], Contents.PART_OF_PATH) # right 1
maze.updatePosition(maze[9][17], Contents.PART_OF_PATH) # right 1
maze.updatePosition(maze[8][17], Contents.DEAD_END) # up 1
maze.t.screen.mainloop()
if __name__ == "__main__":
main()