Torres de Hanói - Versão 2.0
Publicado por Washington Luis de O Santos (última atualização em 23/12/2021)
[ Hits: 1.872 ]
O objetivo deste quebra-cabeça é transferir todos os discos da torre inicial (um de cada vez) para uma das outras torres vazias, sempre respeitando o fato de que, nunca é possível colocar um disco maior em cima de um disco menor. O jogador poderá ir e voltar com os discos em qualquer uma das três torres.
De acordo com um cálculo matemático, o número de movimentos minímos necessários para resolver o quebra-cabeça com 10 discos é igual a 1023.
Esta nova versão do programa, foi feita com o uso de classes/objetos para a criação das torres e também foi ativado o uso do mouse.
Arquivos zipados incluídos no pacote:
LEIAME.txt --> este texto
hanoi-2.0.py --> prg
torresdehanoi.png --> icone do prg
Torres de Hanói.desktop --> edite este arquivo, coloque o caminho onde foi salvo o
prg e o icone e copie ele dentro da pasta "Área de Trabalho" do kde, para criar
um atalho.
torre_de_hanoi.pdf --> doc contando a história do jogo(*)
(*) pego no link: https://www.ibilce.unesp.br/Home/Departamentos/Matematica/labmat/torre_de_hanoi.pdf
Observações:
Para rodar o programa use o Python3
No Debian e/ou Kubuntu (Ubuntu com KDE) instale o pacote " sox " através do apt-get para poder reproduzir os beep's através do " play "
O play é um utilitário de linha de comando (shell), para testar o play direto no terminal copie e cole a linha abaixo:
play --no-show-progress --null -t alsa --channels 1 synth .5 sine 1000
No mais então... FELIZ NATAL, divirtam-se, deem um joinha se gostaram e vejam os outros
programas no link: https://www.vivaolinux.com.br/~WashingtonLuis/scripts/
Por: Washington Luis de O Santos
#!/usr/bin/env python3 # -*- coding:UTF-8 -*- #coding: cp1252 #coding: latin1 ''' Torres de Hanoi version 2.0 - Program Copyright (c) 2002-2004 Washington Luis de O. Santos < owashington[arroba]terra.com.br > Este programa, primeiro, foi desenvolvido em clipper 5.2 por mim em novembro de 1994 e agora foi convertido e adaptado para o python3 com o uso do módulo 'curses' This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Taubaté - SP, 17 de dezembro de 2020 ''' import sys import time import curses import os from random import shuffle, randint # janela principal screen = curses.initscr() # tamanho da janela principal screen_x, screen_y = screen.getmaxyx() if screen_x < 24 or screen_y < 81: screen.clear() curses.endwin() print('Tamanho atual do terminal: {} x {}'.format(screen_x, screen_y)) print('\nO seu terminal tem que ter no minimo 24 linhas por 81 colunas.\n') print('Reajuste o tamanho do seu terminal para poder jogar... \n') sys.exit(0) screen.keypad(True) screen.notimeout(False) curses.cbreak() # Não retorna caracteres na tela curses.noecho() # esconde o cursor do mouse e do terminal curses.curs_set(0) # move o cursor para a posicao 0,0 #screen.move(0,0) # limpa a tela screen.clear() #screen.set_title('T O R R E S D E H A N O I') curses.mousemask(curses.ALL_MOUSE_EVENTS) # atualiza a tela automaticamente mais causa perda de performance # pode ser usado no lugar das chamadas da funcao screen.refresh() #screen.immedok(True) # iniciando cores curses.start_color() curses.use_default_colors() # Define cor da tela de abertura (autor) curses.init_pair( 1, curses.COLOR_GREEN, curses.COLOR_WHITE) # Define cor dos textos (autor) e box e da Base das Torres curses.init_pair( 2, curses.COLOR_BLUE, curses.COLOR_WHITE) # Define cor da Versão (autor) e sombra curses.init_pair( 3, curses.COLOR_BLACK, curses.COLOR_WHITE) # Define cor da Barra de Status curses.init_pair( 4, curses.COLOR_WHITE, curses.COLOR_CYAN) # Define cor da mensagem de error (box) curses.init_pair( 5, curses.COLOR_RED, curses.COLOR_WHITE) # Define cor da parte de baixo da tela curses.init_pair( 6, curses.COLOR_WHITE, curses.COLOR_BLUE) # Define cor do botão acionado curses.init_pair( 7, curses.COLOR_BLUE, curses.COLOR_WHITE) # Define cor da sombra do botão acionado (apaga) curses.init_pair( 8, curses.COLOR_WHITE, curses.COLOR_BLUE) # Define cor do botão NÃO acionado curses.init_pair( 9, curses.COLOR_BLACK, curses.COLOR_WHITE) # Define cor da sombra do botão NÃO acionado (cria) curses.init_pair(10, curses.COLOR_BLACK, curses.COLOR_BLUE) # Define as cores dos discos e embaralha (shuffle) cor = [0,1,2,3,4,5,6,0,1,2,3] shuffle(cor) for i in range(11): curses.init_pair(i+11, cor[i], curses.COLOR_WHITE) # Define Constantes usadas como caracteres especiais # Single-line # Chr( 218 ) + Chr( 196 ) + Chr( 191 ) ┌ ─ ┐ # Chr( 179 ) + Chr( 32 ) + Chr( 179 ) │ │ # Chr( 192 ) + Chr( 196 ) + Chr( 217 ) └ ─ ┘ c_032 = chr( 32) # espaço c_168 = chr(9608) c_177 = chr(9619) # bloco c_178 = chr(9618) c_179 = chr(9474) c_191 = chr(9488) c_192 = chr(9492) c_196 = chr(9472) c_217 = chr(9496) c_218 = chr(9484) c_219 = chr(9604) c_223 = chr(9600) # Define Constantes K_CTRL_Q = 17 K_ESC = 27 K_1 = 49 K_2 = 50 K_3 = 51 class Box: def Fill(lt,ce,lb,cd, cor): #Desenha uma caixa sem bordas e sem sombras for x in range(lt,lb+1): screen.addstr(x, ce, c_032 * (cd-ce+1), curses.color_pair(cor)) def Display(lt,ce,lb,cd,cor): #Desenha uma caixa com bordas e sem sombras __class__.Fill(lt,ce,lb,cd,cor) screen.addstr(lt, ce, c_196 * (cd-ce), curses.color_pair(cor)) screen.addstr(lt, ce, c_218, curses.color_pair(cor)) screen.addstr(lt, cd, c_191, curses.color_pair(cor)) screen.addstr(lb, ce, c_196 * (cd-ce), curses.color_pair(cor)) screen.addstr(lb, ce, c_192, curses.color_pair(cor)) screen.addstr(lb, cd, c_217, curses.color_pair(cor)) for x in range(lt+1,lb): screen.addstr(x, ce, c_179, curses.color_pair(cor)) screen.addstr(x, cd, c_179, curses.color_pair(cor)) def Shadow(lt,ce,lb,cd,cor): #Desenha uma caixa com bordas e com sombras __class__.Display(lt,ce,lb,cd,cor) #Desenha a Sombra da Caixa for x in range(lt+1,lb+1): screen.addstr(x, cd+1, c_032, curses.color_pair(0)) screen.addstr(lb+1, ce+1, c_032 * (cd-ce+1), curses.color_pair(0)) def Beep(duration = .1, frequency = 850): #curses.beep() #os.system('beep -f %s -l %s' % (frequency,duration)) #os.system('beep -f 555 -l 460') # Observação: # O play é um utilitário de linha de comando (shell), para poder usa-lo # instale o Pacote sox atraves do apt-get no Debian # Para testar o play direto no bash copie e cole a linha abaixo: #play --no-show-progress --null -t alsa --channels 1 synth .5 sine 1000 try: os.system('play --no-show-progress --null -t alsa --channels 1 synth %s sine %f' % (duration, frequency)) except: pass def pause(tempo): # Atualiza a tela screen.refresh() # Pausa por um tempo time.sleep(tempo) # Limpa qualquer outra coisa que o usuário tenha digitado curses.flushinp() def autor(): # Mostra a tela de abertura # Obs: As 'fontes' usadas foram criadas através do programa # figlet - http://www.figlet.org/ # digite o cmd abaixo para ver as fontes disponiveis # showfigfonts # digite o cmd abaixo para criar o arquivo com o texto # figlet -f big "Torres" >> hanoi.txt # figlet -f big "de" >> hanoi.txt # figlet -f big "Hanói" >> hanoi.txt Box.Shadow(1,10,20,68, 2) screen.addstr( 2, 22, ' _____', curses.color_pair(1) | curses.A_BOLD) screen.addstr( 3, 22, '|_ _|__ _ __ _ __ ___ ___', curses.color_pair(1) | curses.A_BOLD) screen.addstr( 4, 22, ' | |/ _ \\| \'__| \'__/ _ \\/ __|', curses.color_pair(1) | curses.A_BOLD) screen.addstr( 5, 22, ' | | (_) | | | | | __/\\__ \\', curses.color_pair(1) | curses.A_BOLD) screen.addstr( 6, 22, ' |_|\\___/|_| |_| \\___||___/', curses.color_pair(1) | curses.A_BOLD) screen.addstr( 7, 22, ' _', curses.color_pair(1) | curses.A_BOLD) screen.addstr( 8, 22, ' __| | ___', curses.color_pair(1) | curses.A_BOLD) screen.addstr( 9, 22, ' / _` |/ _ \\', curses.color_pair(1) | curses.A_BOLD) screen.addstr(10, 22, ' | (_| | __/', curses.color_pair(1) | curses.A_BOLD) screen.addstr(11, 22, ' _ _ \\__,_|\\___| _', curses.color_pair(1) | curses.A_BOLD) screen.addstr(12, 22, ' | | | | __ _ _ __ ___ (_)', curses.color_pair(1) | curses.A_BOLD) screen.addstr(13, 22, ' | |_| |/ _` | \'_ \\ / _ \\| |', curses.color_pair(1) | curses.A_BOLD) screen.addstr(14, 22, ' | _ | (_| | | | | (_) | |', curses.color_pair(1) | curses.A_BOLD) screen.addstr(15, 22, ' |_| |_|\\__,_|_| |_|\\___/|_|', curses.color_pair(1) | curses.A_BOLD) screen.addstr(10, 52, 'Versão 2.0', curses.color_pair(3)) screen.addstr(17, 15, 'Autor: Washington Luis de Oliveira Santos', curses.color_pair(2)) screen.addstr(18, 15, 'End. : Av. Campinas, 749 - Chácara do Visconde', curses.color_pair(2)) screen.addstr(19, 28, 'Taubaté - São Paulo', curses.color_pair(2)) def ENCERRA(): #Restaura a cor do terminal screen.refresh() screen.clear() screen.keypad(False) curses.nocbreak() curses.echo() curses.endwin() sys.exit(0) def inkey(): while True: try: key = screen.getch() if key == curses.KEY_MOUSE: # botão esquerdo do mouse foi pressionado _, mx, my, _, _ = curses.getmouse() #screen.addstr (22, 1,"my = %i | mx = %i" % (my, mx)) # Verifica em que posicao foi pressionado if (6 < my < 22) and ( 2 < mx < 24): return 1 elif (6 < my < 22) and (28 < mx < 50): return 2 elif (6 < my < 22) and (54 < mx < 76): return 3 except curses.error: pass if key in (K_ESC, K_CTRL_Q): # encerra o programa Box.Shadow( 8,23,14,55, 5) screen.addstr(11, 30, 'Jogo abortado...', curses.color_pair(5)) pause(5) ENCERRA() elif key in (curses.KEY_F1, ord('h'), ord('H')): # help acionado autor() screen.addstr(23, 0, c_032 * 80, curses.color_pair(4)) screen.addstr(23, 1, 'Tecle algo para sair...', curses.color_pair(4) | curses.A_BOLD) # O comando abaixo faz com que a chamada a getch() retorne depois # de um tempo simulando a função inkey(<tempo>) do CLIPPER curses.halfdelay(7) while True: key = screen.getch() if key != -1:break # Fica piscando a tela (mudando de cor) curses.init_pair( 1, randint(0, 7), curses.COLOR_WHITE) screen.refresh() return 0 elif key == K_1: return 1 elif key == K_2: return 2 elif key == K_3: return 3 class Torre: def __init__(self): # cria uma torre sem os Discos self.nd = 0 # Se quiser ver os discos com 'caracteres graficos' # mude a linha IF abaixo de 0 para 1 if 0: self.torre = [[1, (c_032 * 10) + c_178]] * 11 else: self.torre = [[1, (c_032 * 10) + '|']] * 11 def disc_fill(self): # cria uma torre com os Discos self.nd = 10 self.torre[ 0] = ([ 1, ' | ']) self.torre[ 1] = ([ 2, ' #|# ']) self.torre[ 2] = ([ 3, ' ##|## ']) self.torre[ 3] = ([ 4, ' ###|### ']) self.torre[ 4] = ([ 5, ' # FELIZ # ']) self.torre[ 5] = ([ 6, ' ## NATAL ## ']) self.torre[ 6] = ([ 7, ' ######|###### ']) self.torre[ 7] = ([ 8, ' ## GENTILEZA ## ']) self.torre[ 8] = ([ 9, ' ### GERA ### ']) self.torre[ 9] = ([10, ' #### GENTILEZA #### ']) self.torre[10] = ([11, '##########|##########']) # Se quiser ver os discos com 'caracteres graficos' # mude a linha IF abaixo de 0 para 1 if 0: for x in range(11): self.torre[x][1] = self.torre[x][1].replace('#', c_177) self.torre[x][1] = self.torre[x][1].replace('|', c_178) def disc_entra(self, de): self.torre[10 - self.nd] = de self.nd += 1 def disc_sai(self): self.nd -= 1 aux = self.torre[10 - self.nd] self.torre[10 - self.nd] = self.torre[0] return aux def disc_size(self): if self.nd == 0: return(self.torre[self.nd][0]) else: return(self.torre[11 - self.nd][0]) def disc_total(self): return self.nd def disc_show(self, col): for x in range(11): screen.addstr(x+7, col, self.torre[x][1], curses.color_pair(self.torre[x][0]+10))# | curses.A_BOLD) def bt_solto(n_bt): ''' desenha o botão não acionado n_bt = numero do botão ''' posicao = {1:(10,11,17), 2:(36,37,43), 3:(62,63,69)} screen.addstr(20, posicao[n_bt][0], '{:^7}'.format(n_bt), curses.color_pair(9)) # Cria a sombra do botão screen.addstr(21, posicao[n_bt][1], c_223 * 7, curses.color_pair(10)) screen.addstr(20, posicao[n_bt][2], c_219 , curses.color_pair(10)) def bt_press(n_bt): ''' desenha o botão acionado n_bt = numero do botão ''' posicao = {1:(10,11), 2:(36,37), 3:(62,63)} screen.addstr(20, posicao[n_bt][1], '{:^7}'.format(n_bt), curses.color_pair(7) | curses.A_BOLD) # Apaga a sombra do botão screen.addstr(20, posicao[n_bt][0], c_032 , curses.color_pair(8)) screen.addstr(21, posicao[n_bt][1], c_032 * 7, curses.color_pair(8)) def display_tela(): #Cria um quadro na tela com char azul e fundo branco Box.Display(0,0,18,79, 2) #Escreve o titulo screen.addstr( 2,24, 'T O R R E S D E H A N O I', curses.color_pair(2) | curses.A_BOLD) screen.addstr( 3,45, 'ver. 2.0', curses.color_pair(2)) #Desenha a Torre e os discos torre[1].disc_show( 3) torre[2].disc_show(29) torre[3].disc_show(55) #Desenha a base screen.addstr(18, 0, c_178 * 80, curses.color_pair(2)) #Apaga/Muda a cor na parte de baixo da tela Box.Fill(19,0,23,79,10) # Desenha os botoes bt_solto(1) bt_solto(2) bt_solto(3) screen.addstr(23, 0, c_032 * 80, curses.color_pair(4)) def main(): while True: global torre torre = {} # Determina a torre que contera os discos e embaralha ti = [1, 2, 3] shuffle(ti) # Conta o nº de movimentos n_mov = 0 # Cria as torres sem os discos torre[ti[0]] = Torre() torre[ti[1]] = Torre() torre[ti[2]] = Torre() # Preenche a torre com os discos torre[ti[0]].disc_fill() #Imprimi a tela de abertura display_tela() autor() for _ in range(10): # Fica piscando a tela (mudando de cor) curses.init_pair(1, randint(0, 7), curses.COLOR_WHITE) pause(.7) while True: display_tela() # mostra o nº de discos em cada torre (só pra depuração) #screen.addstr(21, 8, 'tot disc {}'.format(torre[1].disc_total()), curses.color_pair(6)) #screen.addstr(21, 34, 'tot disc {}'.format(torre[2].disc_total()), curses.color_pair(6)) #screen.addstr(21, 60, 'tot disc {}'.format(torre[3].disc_total()), curses.color_pair(6)) # mostra o tamanho do disco do topo da torre (só pra depuração) #screen.addstr(22, 9, 'tamanho {}'.format(torre[1].disc_size()), curses.color_pair(6)) #screen.addstr(22, 35, 'tamanho {}'.format(torre[2].disc_size()), curses.color_pair(6)) #screen.addstr(22, 61, 'tamanho {}'.format(torre[3].disc_size()), curses.color_pair(6)) screen.addstr(23, 62, 'Movimentos: {:5}'.format(n_mov), curses.color_pair(4) | curses.A_BOLD) #Pede para o usuario fazer o movimento screen.addstr(23, 1, 'Entre com o nº da torre de origem ', curses.color_pair(4) | curses.A_BOLD) origem = inkey() if origem == 0: continue bt_press(origem) if torre[origem].disc_total() == 0: # Torre vazia Beep() screen.addstr(23, 1, 'Esta torre esta vazia... ', curses.color_pair(4) | curses.A_BOLD) pause(2) continue screen.addstr(23, 1, 'Entre com o nº da torre de destino', curses.color_pair(4) | curses.A_BOLD) destino = inkey() if destino == 0: continue bt_press(destino) pause(.1) if destino == origem: Beep() continue # Verifica se o movimento e valido if (torre[destino].disc_total() > 0) and (torre[origem].disc_size() > torre[destino].disc_size()): Beep() screen.addstr(23, 1, 'Movimento ilegal... ', curses.color_pair(4) | curses.A_BOLD | curses.A_BLINK) pause(5) continue # Move o disco de uma torre para a outra torre[destino].disc_entra(torre[origem].disc_sai()) n_mov += 1 #Verifica se chegou no fim do jogo if torre[ti[1]].disc_total() == 10 or torre[ti[2]].disc_total() == 10: display_tela() screen.addstr(23, 62, 'Movimentos: {:5}'.format(n_mov), curses.color_pair(4) | curses.A_BOLD) Box.Shadow(8,23,14,55, 2) screen.addstr( 9, 26, 'Meus Parabéns...', curses.color_pair(2) | curses.A_BOLD) screen.addstr(11, 26, 'Você conseguiu!!!', curses.color_pair(2) | curses.A_BOLD) # Verifica se quer brincar novamente screen.addstr(13, 26, 'Quer tentar outra vez? (S/N)', curses.color_pair(2)) pause(5) key = screen.getch() if key in (ord('S'), ord('s')): break else: ENCERRA() if __name__ == '__main__': try: curses.wrapper(main()) except KeyboardInterrupt: ENCERRA()
Script para fazer o Scroll Lock funcionar no Linux
Simples script para atrasar/adiantar legendas
Enviar mensagem ao usuário trabalhando com as opções do php.ini
Meu Fork do Plugin de Integração do CVS para o KDevelop
Compartilhando a tela do Computador no Celular via Deskreen
Como Configurar um Túnel SSH Reverso para Acessar Sua Máquina Local a Partir de uma Máquina Remota
Configuração para desligamento automatizado de Computadores em um Ambiente Comercial
Compartilhamento de Rede com samba em modo Público/Anônimo de forma simples, rápido e fácil
Cups: Mapear/listar todas as impressoras de outro Servidor CUPS de forma rápida e fácil
Criando uma VPC na AWS via CLI
Falta pacotes de suporte ao sistema de arquivos (Gerenciador de discos... (2)
Enzo quer programar mas não faz código pra não bugar (12)
Erro de Montagem SSD Nvme (12)
WebScrapping através de screenshot devido a bloqueios de Shadow DOM (1)