Compare commits
5 Commits
7312f8a293
...
2fda876df3
| Author | SHA1 | Date | |
|---|---|---|---|
|
2fda876df3
|
|||
|
68ccc3c183
|
|||
|
3c100a08fe
|
|||
|
9c6bf54f20
|
|||
|
70daa208d0
|
12
README.md
12
README.md
@@ -36,7 +36,7 @@ def function1(
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/ex1_.py)
|
||||
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/Ex1.py)
|
||||
/
|
||||
[Tests](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/tests/test_ex1.py)
|
||||
|
||||
@@ -46,7 +46,7 @@ def function1(
|
||||
<table>
|
||||
<tr>
|
||||
<td><strong>But</strong></td>
|
||||
<td></td>
|
||||
<td>...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Input</strong></td>
|
||||
@@ -70,7 +70,7 @@ def function2(
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/ex2_.py)
|
||||
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/Ex2.py)
|
||||
/
|
||||
[Tests](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/tests/test_ex2.py)
|
||||
|
||||
@@ -104,7 +104,7 @@ def function3(
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/ex3_.py)
|
||||
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/Ex3.py)
|
||||
/
|
||||
[Tests](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/tests/test_ex3.py)
|
||||
|
||||
@@ -138,7 +138,7 @@ def function4(
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/ex4_.py)
|
||||
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/Ex4.py)
|
||||
/
|
||||
[Tests](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/tests/test_ex4.py)
|
||||
|
||||
@@ -172,6 +172,6 @@ def function5(
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/ex5_.py)
|
||||
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/Ex5.py)
|
||||
/
|
||||
[Tests](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/tests/test_ex5.py)
|
||||
|
||||
57
src/Ex1.py
Normal file
57
src/Ex1.py
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
"""
|
||||
Nom/Prénom: Heredero/Louis
|
||||
Explications:
|
||||
|
||||
Une approche serait de trier la liste des valeurs par ordre croissant
|
||||
Une fois triée, nous pouvons comparer les valeurs absolues des 2 extrémités :
|
||||
- Si elles sont égales, nous avons une touche complète supplémentaire (nous les enlevons de la liste)
|
||||
- Sinon, nous enlevons celle avec la plus grande valeur absolue
|
||||
|
||||
NB: Afin de ne compter que les paires distinctes, nous pouvons soit transformer
|
||||
la liste en `set` (retire les valeurs à double), soit garder une liste des valeurs
|
||||
de touches complètes trouvées
|
||||
Cela permettrait aussi peut-être d'améliorer l'efficacité de l'algorithme de la manière suivante:
|
||||
- Créer deux `set` : valeurs positives et valeurs négatives (stocker la valeur
|
||||
absolue des valeurs négatives dans le `set`)
|
||||
- Calculer l'intersection des deux `set` :
|
||||
`intersection = positives.intersection(negatives)`
|
||||
- Le nombre de touches complètes est la taille de cette intersection :
|
||||
`complete = len(intersection)`
|
||||
|
||||
Par exemple :
|
||||
list = [-3, -2, -1, 1, 2, 5] -> |-3| != |5| -> on enlève 5
|
||||
list = [-3, -2, -1, 1, 2] -> |-3| != |2| -> on enlève -3
|
||||
list = [-2, -1, 1, 2] -> |-2| = |2| -> une touche complète
|
||||
list = [-1, 1] -> |-1| = |1| -> une autre touche complète
|
||||
list = []
|
||||
"""
|
||||
|
||||
|
||||
def countKey(pieces: list[int])->int:
|
||||
pieces = sorted(pieces)
|
||||
complete: int = 0
|
||||
|
||||
while len(pieces) >= 2:
|
||||
a, b = pieces[0], pieces[-1]
|
||||
|
||||
# Si toutes les pièces restantes sont de même signe, on peut s'arrêter
|
||||
if a >= 0 or b <= 0:
|
||||
break
|
||||
|
||||
abs_a, abs_b = abs(a), abs(b)
|
||||
if abs_a == abs_b:
|
||||
complete += 1
|
||||
pieces = pieces[1:-1]
|
||||
elif abs_a < abs_b:
|
||||
pieces.pop(-1)
|
||||
else:
|
||||
pieces.pop(0)
|
||||
|
||||
return complete
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
#print(countKey([-3, 4, 2, 8, 9, 1, -3, -8, -4, 2, 8, 2, -8, 1, 3]) == 3)
|
||||
print(countKey([-3, 4, 2, 8, 9, 1, -3, -8, -4, 2, 8, 2, -8, 1, 3]) == 4)
|
||||
print(countKey([-4, 5, 6, -1500, 4, 7, 49, 60, -60, 82, -41, 1500, 1, -7]) == 4)
|
||||
96
src/Ex2.py
Normal file
96
src/Ex2.py
Normal file
@@ -0,0 +1,96 @@
|
||||
|
||||
"""
|
||||
Nom/Prénom: Heredero/Louis
|
||||
Explications:
|
||||
|
||||
Tout d'abord, le réseau de routes et d'intersections peut être représenté par un graphe,
|
||||
dans lequel les interséctions sont les nœuds et les routes les arêtes.
|
||||
|
||||
Ainsi, nous cherchons à trouver le chemin le plus court du point de départ au
|
||||
point d'arrivée, tel que les routes marquées 1 ne soient parcourues que de jour
|
||||
(c'est-à-dire si leurs index dans le chemin parcouru est pair), et celles marquées -1
|
||||
seulement de nuit (index impair). En plus des routes données, nous pouvons aussi
|
||||
rester sur un même nœud pour une nuit.
|
||||
Afin de bien gérer les différences d'états entre jour et nuit, nous pouvons intégrer le demi-jour
|
||||
associé à chaque visite de nœud. Ainsi, une même intersection peut avoir deux nœud:
|
||||
un pour une visite de jour, et un de nuit.
|
||||
|
||||
Pour résoudre ce problème, comme nous ne pouvons pas établir d'heuristique mesurant
|
||||
notre distance au point d'arrivée, nous pouvons utiliser un algorithme BFS assez simple:
|
||||
- Initialiser la liste des nœuds à traiter avec le nœud de départ et le demi-jour de départ (`DAY`)
|
||||
- Tant que nous n'avons pas trouvé le nœud d'arrivée:
|
||||
- Pour chaque nœud à traiter :
|
||||
- Visiter les nœuds voisins non visités (liés par une route praticable)
|
||||
- Indiquer pour chaque voisin son parent
|
||||
- L'ajouter à la nouvelle liste des nœuds à traiter
|
||||
- Alterner le demi-jour courant
|
||||
- Recommencer avec la nouvelle liste de nœuds à traiter
|
||||
"""
|
||||
from typing import Optional
|
||||
|
||||
ALWAYS = 0
|
||||
DAY = 1
|
||||
NIGHT = -1
|
||||
|
||||
|
||||
def get_path(visited: dict[tuple[int, int], Optional[int]], end: int, end_time: int) -> list[int]:
|
||||
path: list[int] = []
|
||||
parent: Optional[int] = end
|
||||
|
||||
time: int = end_time
|
||||
while parent is not None:
|
||||
path.append(parent)
|
||||
parent = visited[(parent, time)]
|
||||
time = -time
|
||||
|
||||
return list(reversed(path))
|
||||
|
||||
def findSafestPath(start: int, end: int, intersections: list[tuple[int, int, int]]) -> list[int]:
|
||||
edges: dict[int, dict[int, set[int]]] = {
|
||||
ALWAYS: {},
|
||||
DAY: {},
|
||||
NIGHT: {}
|
||||
}
|
||||
|
||||
for i1, i2, mode in intersections:
|
||||
edge_dict: dict[int, set[int]] = edges[mode]
|
||||
if i1 not in edge_dict:
|
||||
edge_dict[i1] = set()
|
||||
if i2 not in edge_dict:
|
||||
edge_dict[i2] = set()
|
||||
edge_dict[i1].add(i2)
|
||||
edge_dict[i2].add(i1)
|
||||
|
||||
visited: dict[tuple[int, int], Optional[int]] = {
|
||||
(start, DAY): None
|
||||
}
|
||||
to_process: list[int] = [start]
|
||||
time = DAY
|
||||
while len(to_process) != 0:
|
||||
to_process2 = []
|
||||
time2 = -time
|
||||
for idx in to_process:
|
||||
always: set[int] = edges[ALWAYS].get(idx, set())
|
||||
matching_time: set[int] = edges[time].get(idx, set())
|
||||
neighbors: set[int] = always | matching_time
|
||||
neighbors.add(idx)
|
||||
|
||||
for neighbor in neighbors:
|
||||
key = (neighbor, time2)
|
||||
# Skip if already visited
|
||||
if key in visited:
|
||||
continue
|
||||
visited[key] = idx
|
||||
if neighbor == end:
|
||||
return get_path(visited, end, time2)
|
||||
to_process2.append(neighbor)
|
||||
|
||||
to_process = to_process2
|
||||
time = time2
|
||||
|
||||
return []
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(findSafestPath(0,2,[(0, 1, -1), (1, 2, 0)]) == [0, 0, 1, 2])
|
||||
print(findSafestPath(0, 5, [(0,1,0), (0,2,1), (2,1,-1), (1,3,-1), (2,4,-1), (3,5,1), (3,4,0), (4,5,-1)]) == [0, 1, 3, 5])
|
||||
76
src/Ex3.py
Normal file
76
src/Ex3.py
Normal file
@@ -0,0 +1,76 @@
|
||||
|
||||
"""
|
||||
Nom/Prénom: Heredero/Louis
|
||||
Explications:
|
||||
|
||||
Comme indiqué dans la donnée de l'exercice, il s'agit ici de trouvé un sous-graphe
|
||||
connexe dans un graphe quelconque de consoles interconnectées
|
||||
|
||||
Pour ce faire nous pouvons procéder ainsi:
|
||||
Étape 1 :
|
||||
- Compter le nombre de voisins de chaque nœud (console)
|
||||
- Éliminer ceux ayant moins de voisins que la taille de sous-graphe recherché
|
||||
- Supprimer également les arêtes connectées à ces nœuds
|
||||
- Recommencer jusqu'à ce que :
|
||||
a) il y ait moins de nœuds que la taille du sous-graphe recherché
|
||||
-> il n'est donc pas possible de trouver un sous-graphe connexe de taille n
|
||||
b) aucun nœud du graphe n'ait moins de voisins que voulu (aucune suppression de nœud)
|
||||
-> il peut exister un sous-graphe connexe de taille n (Cf. étape 2)
|
||||
|
||||
Étape 2 :
|
||||
- Pour chaque nœud du graphe :
|
||||
- Calculer l'ensemble des nœuds communs entre ses voisins (et lui-même),
|
||||
et les voisins des ses voisins (et eux-mêmes)'
|
||||
C'est-à-dire, si N1 et un nœuds et nb(N1) = {N2, N3, ...} est l'ensemble de ses voisins,
|
||||
on cherche l'intersection de {N1} U nb(N1), {N2} U nb(N2), {N3} U nb(N3), etc.
|
||||
- Si c'est ensemble contient au moins n éléments, il s'agit alors d'un sous-graphe connexe.
|
||||
On peut ainsi en extraire les n premiers nœuds comme résultat
|
||||
"""
|
||||
|
||||
|
||||
def findTightlyLinkedConsoles(n: int, consoles: list[tuple[int, int]]) -> list[int]:
|
||||
nodes: dict[int, set[int]] = {}
|
||||
|
||||
for i1, i2 in consoles:
|
||||
if i1 not in nodes:
|
||||
nodes[i1] = set()
|
||||
if i2 not in nodes:
|
||||
nodes[i2] = set()
|
||||
nodes[i1].add(i2)
|
||||
nodes[i2].add(i1)
|
||||
|
||||
while True:
|
||||
removed: set[int] = set()
|
||||
for node, neighbors in nodes.items():
|
||||
if len(neighbors) < n - 1:
|
||||
removed.add(node)
|
||||
|
||||
if len(removed) == 0:
|
||||
break
|
||||
|
||||
new_nodes = {}
|
||||
for node, neighbors in nodes.items():
|
||||
if node in removed:
|
||||
continue
|
||||
new_nodes[node] = neighbors - removed
|
||||
|
||||
nodes = new_nodes
|
||||
|
||||
if len(nodes) < n:
|
||||
return []
|
||||
|
||||
for node, neighbors in nodes.items():
|
||||
common: set[int] = neighbors | {node}
|
||||
for nb in neighbors:
|
||||
common = common.intersection(nodes[nb] | {nb})
|
||||
|
||||
if len(common) >= n:
|
||||
return list(sorted(common))[:n]
|
||||
|
||||
return []
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(findTightlyLinkedConsoles(3,[(0,1),(0,4),(2,1),(3,1),(4,2),(2,3)]) == [1,2,3])
|
||||
print(findTightlyLinkedConsoles(4,[(0,1),(0,4),(2,1),(3,1),(4,2),(2,3)]) == [])
|
||||
print(findTightlyLinkedConsoles(4,[(0,1),(0,4),(2,1),(3,1),(4,2),(2,3),(1,4),(4,3)]) == [1,2,3,4])
|
||||
75
src/Ex4.py
Normal file
75
src/Ex4.py
Normal file
@@ -0,0 +1,75 @@
|
||||
|
||||
"""
|
||||
Nom/Prénom: Heredero/Louis
|
||||
Explications:
|
||||
|
||||
Une approche pour résoudre ce problème grâce à la programmation dynamique consiste
|
||||
à se représenter les différentes séquences comme un arbre de décisions, où chaque nœud
|
||||
représente une séquence, et chaque arête un coup supplémentaire
|
||||
On peut alors parcourir l'arbre en profondeur (DFS) jusqu'à trouver une séquence
|
||||
de longueur N et de valeur H (en élaguant les branches dépassant H ou N)
|
||||
On peut également mémoïser un certain nombre de valeurs : en effet, pour une même
|
||||
combinaison N, C, H, le résultat sera toujours le même. Cela optimise donc grandement
|
||||
le calcul récursif puisque cela évite de calculer les états partagés (sous-branches
|
||||
identiques)
|
||||
|
||||
Bonus :
|
||||
Nous cherchons la valeur N la plus petite telle que:
|
||||
`computeNbrOfDifferentSequences(N, 5, 100) > 2^16`
|
||||
"""
|
||||
|
||||
mem: dict[tuple[int, int, int], int] = {}
|
||||
|
||||
def computeNbrOfDifferentSequences(N: int, C: int, H: int) -> int:
|
||||
if N == 0:
|
||||
if H == 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
if H < 0:
|
||||
return 0
|
||||
|
||||
key: tuple[int, int, int] = (N, C, H)
|
||||
if key in mem:
|
||||
return mem[key]
|
||||
|
||||
total: int = 0
|
||||
for c in range(1, C + 1):
|
||||
total += computeNbrOfDifferentSequences(N - 1, C, H - c)
|
||||
|
||||
mem[key] = total
|
||||
return total
|
||||
|
||||
|
||||
def bonus():
|
||||
# Finding N2
|
||||
N1 = 100
|
||||
N2 = 1_000_000_000
|
||||
C = 5
|
||||
H = 100
|
||||
lim = 2 ** 16
|
||||
|
||||
while computeNbrOfDifferentSequences(N2, C, H) <= lim:
|
||||
N2 *= 2
|
||||
print(f"*= 2 -> {N2}")
|
||||
|
||||
print(f"{N2=}")
|
||||
|
||||
# Finding N
|
||||
while N2 - N1 > 1:
|
||||
Nm = (N1 + N2) // 2
|
||||
value = computeNbrOfDifferentSequences(Nm, C, H)
|
||||
if value == lim:
|
||||
return Nm
|
||||
|
||||
if value < lim:
|
||||
N1 = Nm
|
||||
else:
|
||||
N2 = Nm
|
||||
|
||||
return N2
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(computeNbrOfDifferentSequences(1, 6, 3) == 1)
|
||||
print(computeNbrOfDifferentSequences(2, 6, 7) == 6)
|
||||
print(bonus())
|
||||
190
src/Ex5.py
Normal file
190
src/Ex5.py
Normal file
@@ -0,0 +1,190 @@
|
||||
"""
|
||||
Nom/Prénom: Heredero/Louis
|
||||
|
||||
"""
|
||||
from typing import Optional
|
||||
|
||||
|
||||
# UTILITY FUNCTIONS
|
||||
# Those functions are provided as helpers, you do not have to use them
|
||||
# The displayBoardSequence function will be used to visualize the results of your algorithms during the evaluation
|
||||
|
||||
def printPiece(piece:tuple[tuple[int,int], tuple[int,int]]) -> None:
|
||||
print(piece[0][1], piece[1][1])
|
||||
print(piece[0][0], piece[1][0])
|
||||
|
||||
def printBoard(board:list[list[int, int]]) -> None:
|
||||
|
||||
if len(board) <= 0 or len(board[0]) <= 0:
|
||||
print("Empty board -> skipping printing")
|
||||
return None
|
||||
|
||||
for i in range(len(board)-1):
|
||||
if len(board[i]) != len(board[i+1]):
|
||||
print("Board is not a rectangle --> skipping printing")
|
||||
return None
|
||||
|
||||
for y in range(len(board[0])-1, -1, -1):
|
||||
line = ""
|
||||
for x in range(len(board)):
|
||||
line += str(board[x][y],)
|
||||
print(line)
|
||||
|
||||
|
||||
def placeAt(loc, board, piece):
|
||||
for x in range(2):
|
||||
for y in range(2):
|
||||
if piece[x][y] == 0:
|
||||
continue
|
||||
board[loc[0] + x][loc[1] + y] = piece[x][y]
|
||||
|
||||
|
||||
def displayBoardSequence(board_width:int, board_height:int, pieces:list[tuple[tuple[int,int], tuple[int,int]]], placements:list[list[int, int]]):
|
||||
"""Display a sequence of move on the board by placing the blocs at the given locations
|
||||
==> /!\ This is an unsafe function that simply place the 1 ones of the given blocs at the given placements, it will crash while trying to place blocs outside the board
|
||||
==> /!\ it does not check the validity of the placement
|
||||
=> It's main use is for debugging
|
||||
"""
|
||||
board = [None] * board_width
|
||||
for i in range(board_width):
|
||||
board[i] = [0] * board_height
|
||||
|
||||
for i in range(len(pieces)):
|
||||
print( "----", i, "----")
|
||||
print("Piece to place")
|
||||
printPiece(pieces[i])
|
||||
print("Board state after placing piece @ "+ str(placements[i]))
|
||||
placeAt(placements[i], board, pieces[i])
|
||||
printBoard(board)
|
||||
|
||||
"""
|
||||
Explications:
|
||||
|
||||
Une approche possible consiste à représenter la partie sous la forme d'un arbre
|
||||
dans lequel les nœuds sont les états de la grille et les arêtes sont les coups
|
||||
possibles (i.e. placement d'une pièce)
|
||||
|
||||
Ainsi, l'état initial serait celui de la grille vide, et chaque "niveau" de l'arbre
|
||||
représenterait une pièce différente pouvant être posée
|
||||
|
||||
On peut ensuite parcourir l'arbre en largeur (BFS) ce qui nous garantit de trouver une solution optimale en premier.
|
||||
On peut également le parcourir en profondeur (DFS) jusqu'à trouver une solution, puis en parcourant le reste de l'arbre
|
||||
à la recherche d'une meilleure solution. Cela permettrait également d'appliquer
|
||||
de la mémoïsation (principe de programmation dynamique) afin d'optimiser la recherche
|
||||
|
||||
Afin d'accélérer la recherche nous pouvons appliquer les optimisations suivantes:
|
||||
- élagage des branches inintéressantes : dès qu'une pièce laisse un espace vide sous elle, il devient impossible de le remplir
|
||||
- tri des branches selon la hauteur de la pièce une fois posée : prioriser les branches plaçant les pièces le plus bas possible
|
||||
- combinaisons de pièces en macro-blocs : combiner les pièces pouvant s'assembler (p.ex. coin et carré)
|
||||
|
||||
"""
|
||||
|
||||
def find_y(board: list[list[int]], height: int, piece: tuple[tuple[int,int], tuple[int,int]], x: int) -> int:
|
||||
y_max = height - 2
|
||||
if piece[0][1] == 0 and piece[1][1] == 0:
|
||||
y_max = height - 1
|
||||
|
||||
y_min = 0
|
||||
if piece[0][0] == 0 and piece[1][0] == 0:
|
||||
y_min = -1
|
||||
|
||||
lowest = 0
|
||||
for y in range(y_max, y_min - 1, -1):
|
||||
valid = True
|
||||
for dy in range(2):
|
||||
for dx in range(2):
|
||||
if piece[dx][dy] == 1 and board[x + dx][y + dy] == 1:
|
||||
valid = False
|
||||
break
|
||||
if not valid:
|
||||
break
|
||||
|
||||
if valid:
|
||||
lowest = y
|
||||
else:
|
||||
break
|
||||
return lowest
|
||||
|
||||
def copy_board(board: list[list[int]]) -> list[list[int]]:
|
||||
new_board: list[list[int]] = [
|
||||
row.copy()
|
||||
for row in board
|
||||
]
|
||||
return new_board
|
||||
|
||||
def playMinitris(
|
||||
board_width: int,
|
||||
board_height: int,
|
||||
board: list[list[int]],
|
||||
pieces: list[tuple[tuple[int,int], tuple[int,int]]],
|
||||
path: list[tuple[int, int]]
|
||||
) -> Optional[list[tuple[int, int]]]:
|
||||
if len(pieces) == 0:
|
||||
for y in range(board_height):
|
||||
row = []
|
||||
for x in range(board_width):
|
||||
row.append(board[x][y])
|
||||
|
||||
if row != [row[0]] * board_width:
|
||||
return None
|
||||
return path
|
||||
|
||||
first_piece: tuple[tuple[int, int], tuple[int, int]] = pieces[0]
|
||||
rest: list[tuple[tuple[int, int], tuple[int, int]]] = pieces[1:]
|
||||
|
||||
x_min = 0
|
||||
if first_piece[0][0] == 0 and first_piece[0][1] == 0:
|
||||
x_min = -1
|
||||
|
||||
x_max = board_width - 2
|
||||
if first_piece[1][0] == 0 and first_piece[1][1] == 0:
|
||||
x_max = board_width - 1
|
||||
|
||||
for x in range(x_min, x_max + 1):
|
||||
y = find_y(board, board_height, first_piece, x)
|
||||
new_board = copy_board(board)
|
||||
pos = (x, y)
|
||||
path2 = path + [pos]
|
||||
placeAt(pos, new_board, first_piece)
|
||||
|
||||
# If space below piece
|
||||
if first_piece[0][1] == 1 and first_piece[1][1] and first_piece[0][0] != first_piece[1][0]:
|
||||
if new_board[x][y] == 0 or new_board[x + 1][y] == 0:
|
||||
return None
|
||||
|
||||
res: Optional[list[tuple[int, int]]] = playMinitris(board_width, board_height, new_board, rest, path2)
|
||||
if res is not None:
|
||||
return res
|
||||
|
||||
return None
|
||||
|
||||
# This is the function to fill
|
||||
def playMinitrisFastAndWell(
|
||||
board_width: int,
|
||||
board_height: int,
|
||||
pieces: list[tuple[tuple[int,int], tuple[int,int]]]
|
||||
) -> list[list[int, int]]:
|
||||
board: list[list[int]] = [
|
||||
[0] * board_height
|
||||
for _ in range(board_width)
|
||||
]
|
||||
result: Optional[list[tuple[int, int]]] = playMinitris(
|
||||
board_width,
|
||||
board_height,
|
||||
board,
|
||||
pieces,
|
||||
[]
|
||||
)
|
||||
if result is None:
|
||||
return []
|
||||
return list(map(list, result))
|
||||
|
||||
if __name__ == '__main__':
|
||||
displayBoardSequence(3, 4, [((1, 0), (0, 0)), ((1, 0), (0, 0)), ((1, 0), (0, 0))], [(0, 0), (1, 0), (2, 0)])
|
||||
displayBoardSequence(3, 4, [((1, 0), (0, 0)), ((1, 1), (0, 1)), ((1, 1), (0, 0))], [(1, 0), (0, 0), (2, 0)])
|
||||
|
||||
w = 3
|
||||
h = 4
|
||||
pieces = [((1, 0), (0, 0)), ((1, 0), (0, 0)), ((1, 0), (0, 0))]
|
||||
seq = playMinitrisFastAndWell(w, h, pieces)
|
||||
displayBoardSequence(w, h, pieces, seq)
|
||||
@@ -1,8 +1,26 @@
|
||||
import unittest
|
||||
|
||||
from Ex1 import countKey
|
||||
|
||||
|
||||
class MyTestCase(unittest.TestCase):
|
||||
def test_simple1(self):
|
||||
pass
|
||||
self.assertEqual(
|
||||
countKey([-3, 4, 2, 8, 9, 1, -3, -8, -4, 2, 8, 2, -8, 1, 3]),
|
||||
4
|
||||
)
|
||||
|
||||
def test_simple2(self):
|
||||
self.assertEqual(
|
||||
countKey([-4, 5, 6, -1500, 4, 7, 49, 60, -60, 82, -41, 1500, 1, -7]),
|
||||
4
|
||||
)
|
||||
|
||||
def test_simple3(self):
|
||||
self.assertEqual(
|
||||
countKey([-3, -2, -1, 1, 2, 5]),
|
||||
2
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
import unittest
|
||||
|
||||
from Ex2 import findSafestPath
|
||||
|
||||
|
||||
class MyTestCase(unittest.TestCase):
|
||||
def test_simple1(self):
|
||||
pass
|
||||
self.assertEqual(
|
||||
findSafestPath(0, 2, [(0, 1, -1), (1, 2, 0)]),
|
||||
[0, 0, 1, 2]
|
||||
)
|
||||
|
||||
def test_simple2(self):
|
||||
self.assertEqual(
|
||||
findSafestPath(0, 5, [(0,1,0), (0,2,1), (2,1,-1), (1,3,-1), (2,4,-1), (3,5,1), (3,4,0), (4,5,-1)]),
|
||||
[0, 1, 3, 5]
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -1,8 +1,27 @@
|
||||
import unittest
|
||||
|
||||
from Ex3 import findTightlyLinkedConsoles
|
||||
|
||||
|
||||
class MyTestCase(unittest.TestCase):
|
||||
def test_simple1(self):
|
||||
pass
|
||||
self.assertEqual(
|
||||
findTightlyLinkedConsoles(3,[(0,1),(0,4),(2,1),(3,1),(4,2),(2,3)]),
|
||||
[1,2,3]
|
||||
)
|
||||
|
||||
def test_simple2(self):
|
||||
self.assertEqual(
|
||||
findTightlyLinkedConsoles(4,[(0,1),(0,4),(2,1),(3,1),(4,2),(2,3)]),
|
||||
[]
|
||||
)
|
||||
|
||||
def test_simple3(self):
|
||||
self.assertEqual(
|
||||
findTightlyLinkedConsoles(4,[(0,1),(0,4),(2,1),(3,1),(4,2),(2,3),(1,4),(4,3)]),
|
||||
[1,2,3,4]
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
import unittest
|
||||
|
||||
from Ex4 import computeNbrOfDifferentSequences
|
||||
|
||||
|
||||
class MyTestCase(unittest.TestCase):
|
||||
def test_simple1(self):
|
||||
pass
|
||||
self.assertEqual(
|
||||
computeNbrOfDifferentSequences(1, 6, 3),
|
||||
1
|
||||
)
|
||||
|
||||
def test_simple2(self):
|
||||
self.assertEqual(
|
||||
computeNbrOfDifferentSequences(2, 6, 7),
|
||||
6
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
import unittest
|
||||
|
||||
from Ex5 import playMinitrisFastAndWell
|
||||
|
||||
|
||||
class MyTestCase(unittest.TestCase):
|
||||
def test_simple1(self):
|
||||
pass
|
||||
self.assertEqual(
|
||||
playMinitrisFastAndWell(3, 4, [((1, 0), (0, 0)), ((1, 0), (0, 0)), ((1, 0), (0, 0))]),
|
||||
[[0, 0], [1, 0], [2, 0]]
|
||||
)
|
||||
|
||||
def test_simple2(self):
|
||||
self.assertEqual(
|
||||
playMinitrisFastAndWell(3, 4, [((1, 0), (0, 0)), ((1, 1), (0, 1)), ((1, 1), (0, 0))]),
|
||||
[[1, 0], [0, 0], [2, 0]]
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user