Torres de Hanói - Versão 2.0
Publicado por Washington Luis de O Santos (última atualização em 23/12/2021)
[ Hits: 1.844 ]
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()
run_update - Atualizador de Sabayon
Exercício com números randômicos - randint
ISOsync_pt-BR.py - Um Baixador Automático de ISOs de Sabayon, escrito em Python
Script para Away com varias funções para xchat.
Vou voltar moderar conteúdos de Dicas e Artigos (0)
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
Como renomear arquivos de letras maiúsculas para minúsculas
Imprimindo no formato livreto no Linux
Vim - incrementando números em substituição
Efeito "livro" em arquivos PDF
Como resolver o erro no CUPS: Unable to get list of printer drivers
Vou voltar moderar conteúdos de Dicas e Artigos (0)
Instalação Uefi com o instalador clássico do Mageia (0)
É cada coisa que me aparece! - não é só 3% (2)
[Python] Automação de scan de vulnerabilidades
[Python] Script para analise de superficie de ataque
[Shell Script] Novo script para redimensionar, rotacionar, converter e espelhar arquivos de imagem
[Shell Script] Iniciador de DOOM (DSDA-DOOM, Doom Retro ou Woof!)
[Shell Script] Script para adicionar bordas às imagens de uma pasta