This commit is contained in:
		
							
								
								
									
										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) | ||||
		Reference in New Issue
	
	Block a user