-
Notifications
You must be signed in to change notification settings - Fork 266
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Conclusão do Desafio 13 - @JamesStewart-314 (#1167)
Co-authored-by: Allber Fellype <[email protected]>
- Loading branch information
1 parent
3b7e24d
commit 9e4df72
Showing
3 changed files
with
161 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
1775e84fdf6ead5baea4cc292dc86abab |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# Desafio 13 - Passeio do Cavalo | ||
![Python](https://img.shields.io/badge/Python-512BD4?style=flat&logo=python&logoColor=yellow) | ||
![VS Code](https://img.shields.io/badge/VScode-007ACC?style=flat&logo=visualstudiocode&logoColor=white) | ||
## Descrição do Projeto: | ||
No famigerado jogo de [Xadrez](https://pt.wikipedia.org/wiki/Xadrez), existe uma peça | ||
chamada Cavalo que realiza movimentos em formato de "L" em todas as direções cardinais | ||
numa malha quadriculada 8x8 que compõe o tabuleiro do jogo. O objetivo deste projeto | ||
consiste em exibir a sequência de movimentos do cavalo, partindo de uma casa arbitrária | ||
qualquer do tabuleiro, que passe uma única vez por todas as 64 casas. | ||
|
||
Para alcançar este objetivo, este programa utiliza a | ||
[Heurística de Warnsdorff](https://en.wikipedia.org/wiki/Knight%27s_tour#:~:text=Warnsdorf's%20rule%20is%20a%20heuristic,revisit%20any%20square%20already%20visited.) | ||
para otimizar as buscas recursivas pelo primeiro caminho válido que soluciona o problema. | ||
|
||
## Exemplo de Uso: | ||
```bash | ||
python ./solution.py a1 | ||
``` | ||
|
||
## Saída Esperada: | ||
```bash | ||
a1 | ||
c2 | ||
e1 | ||
g2 | ||
. | ||
. | ||
. | ||
``` | ||
|
||
## Requisitos para Execução | ||
- Possuir um ambiente virtual Python instalado localmente em sua máquina com a | ||
versão `3.10` ou superior. | ||
Para baixar esta e outras versões, visite o site | ||
<a target="_blank" href="https://www.python.org/downloads/" style="color: lightgreen">Python.org</a> | ||
e siga os procedimentos de instalação para o | ||
seu sistema operacional. | ||
Após a instalação, abra o terminal de comando em sua máquina e digite o comando | ||
`python --version`. O comando deverá informar a versão atual do interpretador de | ||
Python caso o download tenha sido feito corretamente. Certifique-se de possuir uma | ||
versão igual ou superior à `3.10`, caso contrário, o código não funcionará. | ||
## Instruções para Executar o Código | ||
- Certificando-se de ter instalado corretamente o `Python` em sua | ||
máquina, execute os seguintes comandos: | ||
1. Abra o terminal e navegue até a pasta em que deseja copiar este repositório com o | ||
comando `cd <caminho_absoluto_do_diretótio>`; | ||
2. Em seguida, copie e cole o seguinte código: | ||
`git clone https://github.com/OsProgramadores/op-desafios.git`; | ||
3. Navegue até a pasta contendo o arquivo `solution.py` na árvore do repositório - se | ||
necessário, utilize o comando `cd ".\op-desafios\desafio-13\JamesStewart-314"` | ||
4. Execute o script `"solution.py"` com o comando `python solution.py` | ||
e os resultados deverão ser impressos de maneira formatada na CLI. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import re | ||
import sys | ||
from typing import TypeAlias | ||
|
||
coord_pos: TypeAlias = tuple[int, int] | ||
|
||
def map_position_to_board(coordinate_pos: coord_pos) -> str: | ||
return f"{chr(97 + coordinate_pos[1])}{8 - coordinate_pos[0]}" | ||
|
||
|
||
def map_board_to_position(board_pos: str) -> coord_pos: | ||
return (8 - int(board_pos[1]), ord(board_pos[0]) - 97) | ||
|
||
|
||
def get_possible_knight_moves(current_position: coord_pos) -> set[coord_pos]: | ||
set_pos_moves: set[coord_pos] = set() | ||
|
||
if (tmp_pos_1 := current_position[0] + 2) <= 7: | ||
if (tmp_pos_2 := current_position[1] + 1) <= 7: | ||
set_pos_moves.add((tmp_pos_1, tmp_pos_2)) | ||
if (tmp_pos_2 := current_position[1] - 1) >= 0: | ||
set_pos_moves.add((tmp_pos_1, tmp_pos_2)) | ||
|
||
if (tmp_pos_1 := current_position[1] + 2) <= 7: | ||
if (tmp_pos_2 := current_position[0] + 1) <= 7: | ||
set_pos_moves.add((tmp_pos_2, tmp_pos_1)) | ||
if (tmp_pos_2 := current_position[0] - 1) >= 0: | ||
set_pos_moves.add((tmp_pos_2, tmp_pos_1)) | ||
|
||
if (tmp_pos_1 := current_position[0] - 2) >= 0: | ||
if (tmp_pos_2 := current_position[1] + 1) <= 7: | ||
set_pos_moves.add((tmp_pos_1, tmp_pos_2)) | ||
if (tmp_pos_2 := current_position[1] - 1) >= 0: | ||
set_pos_moves.add((tmp_pos_1, tmp_pos_2)) | ||
|
||
if (tmp_pos_1 := current_position[1] - 2) >= 0: | ||
if (tmp_pos_2 := current_position[0] - 1) >= 0: | ||
set_pos_moves.add((tmp_pos_2, tmp_pos_1)) | ||
if (tmp_pos_2 := current_position[0] + 1) <= 7: | ||
set_pos_moves.add((tmp_pos_2, tmp_pos_1)) | ||
|
||
return set_pos_moves | ||
|
||
|
||
class ChessKnight: | ||
_board_positions: set[coord_pos] = {(p1, p2) for p1 in range(8) for p2 in range(8)} | ||
|
||
_positions_mapping: dict[coord_pos, set[coord_pos]] = dict(zip(_board_positions, | ||
(get_possible_knight_moves(pos)\ | ||
for pos in _board_positions))) | ||
|
||
def __init__(self, knight_position, | ||
m_list: list[coord_pos] | None = None, | ||
m_set: set[coord_pos] | None = None): | ||
self.current_position: coord_pos = knight_position | ||
self.knight_mov_history_list: list[coord_pos] = m_list or [knight_position] | ||
self.knight_mov_history_set: set[coord_pos] = m_set or {coord_pos} | ||
|
||
def __repr__(self) -> str: | ||
return f"ChessKnight<{self.current_position},"\ | ||
f"{self.knight_mov_history_list},"\ | ||
f"{self.knight_mov_history_set}>" | ||
|
||
@classmethod | ||
def move_knight(cls, knight, new_pos: coord_pos): | ||
new_knight = cls(new_pos, | ||
[*knight.knight_mov_history_list, new_pos], | ||
{*knight.knight_mov_history_set, new_pos}) | ||
return new_knight | ||
|
||
@staticmethod | ||
def get_next_knight_moves(knight)-> set[coord_pos]: | ||
return ChessKnight._positions_mapping[knight.current_position] -\ | ||
knight.knight_mov_history_set | ||
|
||
@staticmethod | ||
def next_knight_movement_size(knight, new_pos: coord_pos) -> int: | ||
return len(ChessKnight.get_next_knight_moves(ChessKnight.move_knight(knight, new_pos))) | ||
|
||
@staticmethod | ||
def get_warnsdorff_move(knight, pos_moves: set[coord_pos]) -> coord_pos: | ||
return min(pos_moves, key=lambda x: ChessKnight.next_knight_movement_size(knight, x)) | ||
|
||
|
||
def knight_tour(knight: ChessKnight) -> list[coord_pos]: | ||
if len(knight.knight_mov_history_list) == 64: | ||
return knight.knight_mov_history_list | ||
|
||
for _ in range(len(n_moves := ChessKnight.get_next_knight_moves(knight))): | ||
current_movement: tuple[int, int] = ChessKnight.get_warnsdorff_move(knight, n_moves) | ||
if (res := knight_tour(ChessKnight.move_knight(knight, current_movement))): | ||
return res | ||
n_moves.remove(current_movement) | ||
|
||
return None | ||
|
||
|
||
if __name__ == '__main__': | ||
if len(sys.argv) != 2 or not re.match(r"^[a-h][1-8]$", (init_pos := sys.argv[1].lower())): | ||
print("Error: Provide just one argument representing a valid chess board position. "\ | ||
"E.g.: \"python solution.py a3\".") | ||
sys.exit() | ||
|
||
initial_position: coord_pos = map_board_to_position(init_pos) | ||
final_path: list[coord_pos] = knight_tour(ChessKnight(initial_position)) | ||
|
||
for position in map(map_position_to_board, final_path): | ||
print(position) |