• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

deathseeker25

Desafio Math's Challenge - In The Beginning

18 mensagens neste tópico

Boas pessoal,

Estou a tentar fazer em PHP um exercício do Math's Challenge que podem ver aqui: http://mathschallenge.net/index.php?section=problems&show=true&titleid=in_the_beginning.

Acontece que quando executo o meu código, a página aparece toda em branco, mesmo tendo eu o error_reporting(E_ALL) na primeira linha. Cá fica o meu script:


error_reporting(E_ALL);

class InTheBeginning
{
var $seed = 2;
var $string = 'X B M W W N B G C U A O O M W N W H C V R Y L S W A Q';

function define_seed($seed)
{
	$this->seed=$seed;
}
function define_alfabeto()
{
	global $alfabeto = array( "A" => "1",
					   		  "B" => "2",
					   		  "C" => "3",
							  "D" => "4",
							  "E" => "5",
							  "F" => "6",
							  "G" => "7",
							  "H" => "8",
							  "I" => "9",
							  "J" => "10",
							  "K" => "11",
							  "L" => "12",
							  "M" => "13",
							  "N" => "14",
							  "O" => "15",
							  "P" => "16",
							  "Q" => "17",
							  "R" => "18",
							  "S" => "19",
							  "T" => "20",
							  "U" => "21",
							  "V" => "22",
							  "W" => "23",
							  "X" => "24",
							  "Y" => "25",
							  "Z" => "26");
	}
	function convert()
	{		
		//inicia-se o processo de conversao...
		$letras = explode(" ",$string);

		for($i=0;$i<=strlen($string);$i++)
		{
			$letras[$i];
			if(array_key_exists($letras[$i], $alfabeto)
			{
				if($letras[$i] != $alfabeto[0])
				{
					$letra_anterior = array_values($letras[$i-1]);
					$letra_actual = array_values($letras[$i]);
					$valor_letra_convertida = $letra_anterior + $letra_actual;
					/*nao esquecer que o array começa em 0, pelo que aqui deve
					ser subtraido em 1 valor. Por exemplo, imaginemos que a letra 
					é a letra D, que corresponde ao valor 4 no index do array, mas
					ao valor real 3 na estrutura. Assim subtraimos 1 para sabermos o
					o verdadeiro valor no index.*/
					$valor = array_values($alfabeto[$valor_letra_convertida - 1]; 
					$letra_final = array_keys($valor);
					echo "$letra_final ";
				}
				else    	//se a letra a ser percorrida for a primeira letra...
				{
					$primeiraletra = array_values($alfabeto[0]);
					$primeiraletra = $primeiraletra + $seed;
					echo "$primeiraletra ";
				}
			}
		}
	} //fim da função...

} //fim da classe...

$InTheBeginning = new InTheBeginning();
$InTheBeginning->convert();

Se tiverem problemas na compreensão do script por favor peçam esclarecimento que eu dou. Se, por outro lado, acharem que existem algumas coisas que possa modificar, indiquem-nas. Estou a aprender e, como tal, sempre aberto a sugestões. ;)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

O erro esta na função "define_alfabeto();"  não podes definir uma variável a utilizar global... (global $var = ... );

Se quiseres definir a variável $alfabeto como global podes definir da seguinte forma:

global $alfabeto;

$alfabeto = array(...);

ou

$GLOBALS['alfabeto'] = array(...);

PS: Se não aparece nenhum erro mesmo usando error_reporting isso quer dizer que tens que modificar o ficheiro de configuração do PHP.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

feito no excel :thumbsup:

"THERE IS NO FUTURE IN TIME TRAVEL" -> offset de 4

vou tentar com o php ;)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Rui , esse ciclo for não está nada bem feito.

o strlen vai retornar por exemplo se o array na primeira posição tiver um simples A o ciclo só vai até 1.

Outra coisa, porque estás a usar global ?

Ah, e o seed é suposto ser um RANDOM! A SECRET MAGIC NUMBER! ;) Força Nisso

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Fiz isto agora assim, não corri porque estou a usar PHP 5 e penso que tu estás no 4.. é capaz de estar aí algumas coisas mal em OOP o kingless que dê uma ajuda, que não me consigo habituar ao php 4 :thumbsup:

<?php

class MathTest {
var $previous;
var $stringFinal;
var $alfabeto = array( "A" => "1",
					   		  "B" => "2",
					   		  "C" => "3",
							  "D" => "4",
							  "E" => "5",
							  "F" => "6",
							  "G" => "7",
							  "H" => "8",
							  "I" => "9",
							  "J" => "10",
							  "Q" => "11",
							  "L" => "12",
							  "M" => "13",
							  "N" => "14",
							  "O" => "15",
							  "P" => "16",
							  "Q" => "17",
							  "R" => "18",
							  "S" => "19",
							  "T" => "20",
							  "U" => "21",
							  "V" => "22",
							  "W" => "23",
							  "X" => "24",
							  "Y" => "25",
							  "Z" => "26");
							  
        function define_seed()
        {
            #Criei um random para o seed de 0 a 9
            srand(time());
            $random = (rand() % 9);
            return $random;
        }
        
        function convert($toConvert)
        {
            #Fiz isto porque o ARRAY está todo em UpperCase
            $toConvert = strtoupper($toConvert);
            
            $letras = explode(" ", $toConvert);
            
            /* O que fiz foi utilizar o explode para dividr mas depois fiz um count de quantas palavras ele encontroiu, de seguida ele vai correr dentro de cada palavra o numero de letras que a array conter nessa palavra fazendo depois a conversão */
            for($a = 0 ; $a <= count($letras); $a++)
            {
                for($i = 0; $i <= strlen($letras[$a]; $i++)
                {
                    if($a == 0 && $i == 0) // Verifica se estamos a falar da primeira letra
                    {
                       $this->previous = define_seed();
                       $this->stringFinal .= (char) ( $letras[0] + $this->previous ); 
                       
                    }
                    else
                    {
                        $this->stringFinal .= (char) ( $letras[$i] + $this->previous);
                        $this->previous = $letras[$i];
                    }
                }
            }
            
        }
    }
?>

Espero ter ajudado ;)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

@Gurzi

As classes (OOP) do PHP 4 são compatíveis com o PHP 5 por isso podes correr a vontade ;)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

O erro esta na função "define_alfabeto();"  não podes definir uma variável a utilizar global... (global $var = ... );

Se quiseres definir a variável $alfabeto como global podes definir da seguinte forma:

global $alfabeto;

$alfabeto = array(...);

ou

$GLOBALS['alfabeto'] = array(...);

PS: Se não aparece nenhum erro mesmo usando error_reporting isso quer dizer que tens que modificar o ficheiro de configuração do PHP.

Já tentei de todas as maneiras que indicaste kingless mas ainda não deu. A página continua a ficar em branco.

Já alterei o php.ini de modo a conseguir ver os erros. E olha que são mesmo muitos Notice's e Warning's. Vou ver o que posso fazer.

Outra coisa, porque estás a usar global ?

Estava a usar global porque queria que aquela fosse uma variável global. Já corrigi a situação, colocando-a no topo da classe como uma var.

Ah, e o seed é suposto ser um RANDOM! A SECRET MAGIC NUMBER!

Eu estava a tentar fazer primeiro com um número qualquer e só depois com um random. Como ainda não consegui fazer com um número manualmente atribuído também nem sequer tinha estudado como fazer com um random. Mas obrigado pelas dicas no código.

De qualquer das formas, estou no PHP 5. :thumbsup: Mas nem o teu código nem o meu correram para já... ;)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

@deathseeker25, eu corrigi o teu código todo e pu-lo sem erros mas ele n faz output de nada :thumbsup:

Edit: Na array alfabeto tens q mudar o "Q" => "11", para "(capa)" => 11, ;)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Reparei agora que não chamaste as funções acho que é por isso que esta a mostrar a pagina em branco ;)

Fazes o seguinte:

1- Adicionas uma "var" na classe com o nome $alfabeto  ( var $alfabeto = ''; )

2 - Modifica a função define_alfabeto para isto

function define_alfabeto () {

$this->alfabeto = array(...);

}

3 - Na função "convert" chama a função define_alfabeto no principicio do código

function convet {
     $this->define_alfabeto();
       //... resto do código aqui 
}

4 - Troca todas as variáveis $alfabeto da função "convert" por $this->alfabeto se for um array  $this->alfabeto[..]

5 - Troca todas as variáveis $string  da função "convert" por $this->string

6 - E troca a variável $seed que esta quase no fim da função "convert" por $this->seed

7 - No fim da função convert adiciona  echo  $letra_final;

PS: Vou corrigir o teu código

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

kingless, fiz todas as modificações que sugeriste mas continuam a surgir muitos Warning's e Notice's. Cá fica o código actual:

error_reporting(E_ALL);

class InTheBeginning
{
var $seed = 2;
var $string = 'X B M W W N B G C U A O O M W N W H C V R Y L S W A Q';
var $alfabeto = array( 		  "A" => "1",
					   		  "B" => "2",
					   		  "C" => "3",
							  "D" => "4",
							  "E" => "5",
							  "F" => "6",
							  "G" => "7",
							  "H" => "8",
							  "I" => "9",
							  "J" => "10",
							  "K" => "11",
							  "L" => "12",
							  "M" => "13",
							  "N" => "14",
							  "O" => "15",
							  "P" => "16",
							  "Q" => "17",
							  "R" => "18",
							  "S" => "19",
							  "T" => "20",
							  "U" => "21",
							  "V" => "22",
							  "W" => "23",
							  "X" => "24",
							  "Y" => "25",
							  "Z" => "26");

function define_seed($seed)
{
	$this->seed=$seed;
}
function define_alfabeto()
{
	$this->alfabeto = array( "A" => "1",
					   		  "B" => "2",
					   		  "C" => "3",
							  "D" => "4",
							  "E" => "5",
							  "F" => "6",
							  "G" => "7",
							  "H" => "8",
							  "I" => "9",
							  "J" => "10",
							  "K" => "11",
							  "L" => "12",
							  "M" => "13",
							  "N" => "14",
							  "O" => "15",
							  "P" => "16",
							  "Q" => "17",
							  "R" => "18",
							  "S" => "19",
							  "T" => "20",
							  "U" => "21",
							  "V" => "22",
							  "W" => "23",
							  "X" => "24",
							  "Y" => "25",
							  "Z" => "26");
	}
	function convert()
	{		
		$this->define_alfabeto();
		$letras = explode(" ",$this->string);

		for($i=0;$i<=strlen($this->string);$i++)
		{
			$letras[$i];
			if(array_key_exists($letras[$i], $this->alfabeto))
			{
				if($letras[$i] != $this->alfabeto[0])
				{
					$letra_anterior = array_values($letras[$i-1]);
					$letra_actual = array_values($letras[$i]);
					$valor_letra_convertida = $letra_anterior + $letra_actual;
					/*nao esquecer que o array começa em 0, pelo que aqui deve
					ser subtraido em 1 valor. Por exemplo, imaginemos que a letra 
					é a letra D, que corresponde ao valor 4 no index do array, mas
					ao valor real 3 na estrutura. Assim subtraimos 1 para sabermos o
					o verdadeiro valor no index.*/
					$valor = array_values($this->alfabeto[$valor_letra_convertida - 1]); 
					$letra_final = array_keys($valor);
					echo "$letra_final ";
				}
				else    	//se a letra a ser percorrida for a primeira letra...
				{
					$primeiraletra = array_values($this->alfabeto[0]);
					$primeiraletra = $primeiraletra + $this->seed;
					echo "$primeiraletra ";
				}
			}
		}
	} //fim da função...

} //fim da classe...

$InTheBeginning = new InTheBeginning();
$InTheBeginning->convert();

Analisa por aí para tentares ajudar. Eu também vou tentando corrigir os Warning's e os Notice's que ainda aparecem.  ;)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Analisa por aí para tentares ajudar. Eu também vou tentando corrigir os Warning's e os Notice's que ainda aparecem.  ;)

			$letras[$i]; # Remove esta linha 
			if(array_key_exists($letras[$i], $this->alfabeto))

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não analisei bem o código, mas suponho que o facto do array "alfabeto" não ter chaves númericas explícitas poderá gerar Notices ou Warnings em operações como esta:

$this->alfabeto[$valor_letra_convertida - 1]

Uma hipotese seria declarar as chaves númericas, ou então usar simplesmente uma string para o alfabeto e o texto a converter, usando chavetas para aceder aos valores, tipo isto:

...
$alfabeto = 'ABCD...XYZ';
$string = str_replace(' ','', 'X B M W W N B G C U A O O M W N W H C V R Y L S W A Q');
...
$this->alfabeto{$valor_letra_convertida - 1}

Neste caso o código teria de ser adaptado, deixando de se usar as funções específicas para arrays e usando funções similares para strings.

Não?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Tentei arranjar o teu código mas não consegui.. mas consegui fazer outro ;)

Mas o código não vai dar muito certo para esta string porque  "X = 24"  a seed correcta é a "4" (vi na solução do problema) e "B = 2"

24 - 4 = 20  ->  2 - 20 = -18  e -18  não existe na variavel $alfabeto.

class InTheBeginning
{
var $seed = 4;
var $res = '';
var $string = 'X B M W W N B G C U A O O M W N W H C V R Y L S W A Q';
var $alfabeto = array( "A" => "1",  
                                                         "B" => "2",
	                                                  "C" => "3",
							  "D" => "4",
							  "E" => "5",
							  "F" => "6",
							  "G" => "7",
							  "H" => "8",
							  "I" => "9",
							  "J" => "10",
							  "K" => "11",
							  "L" => "12",
							  "M" => "13",
							  "N" => "14",
							  "O" => "15",
							  "P" => "16",
							  "Q" => "17",
							  "R" => "18",
							  "S" => "19",
							  "T" => "20",
							  "U" => "21",
							  "V" => "22",
							  "W" => "23",
							  "X" => "24",
							  "Y" => "25",
							  "Z" => "26");
	function convert() {
		$strings = explode( " ", $this->string );

		$primeiro = true;
		$resultado = '';
		for($x = 0; $x <= 5; $x++) {
			if(array_key_exists( $strings[$x], $this->alfabeto )) {
				if($primeiro) {
					$res = $this->alfabeto[$strings[$x]] - $this->seed;
					$this->res = $res;

					if($lt = array_search( $res, $this->alfabeto )) {
						$resultado .= $lt;
						}

					$primeiro = false;
				} else {
					$res = $this->res - $this->alfabeto[$strings[$x]];

					$this->res = $res;

					if($lt = array_search( $res, $this->alfabeto )) {
						$resultado .= $lt;
						}
				}
			}
		    }
		    echo "$resultado\n";
	}
} 
$classe = new InTheBeginning();
$classe->convert();
?>

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Mas o código não vai dar muito certo para esta string porque  "X = 24"  a seed correcta é a "4" (vi na solução do problema) e "B = 2"

24 - 4 = 20  ->  2 - 20 = -18  e -18  não existe na variavel $alfabeto.

Como estamos a operar num universo restrito temos de usar aritmética modular (também conhecida por aritmética do relógio) de forma a que todos os resultados pertençam ao universo onde estamos: 1 a 26. Estes conceitos derivam da teoria dos números, teoria dos grupos e da noção de congruência. Tudo isto é muito utilizado em vários níveis de criptografia.

Ou seja, não basta considerar que A ->1, ..., Z->26. Há que alargar estas equivalências para lá do 26: A ->1, ..., Z->26, A ->27, B->28, C->29, ...

e também "para cá" do 1: A -> -25, ..., H -> -18, ..., Y-> -1, Z->0, A ->1, ..., Z->26

Basicamente esta aritmética funciona em ciclos. É só construir uma função modular deste tipo. (Algumas linguagens têm algo deste tipo, penso que Perl tem)

Links úteis:

http://www.atractor.pt/mat/alg_controlo/arit_modular/mod_texto.htm

http://www.numaboa.com.br/criptologia/matematica/congruencia.php

http://www.cut-the-knot.org/blue/Modulo.shtml

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Penso que o erro é o que o djthyrax falou... fiz tambem de outra maneira:

<?
class InTheBeginning {

	var $alfabeto = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

	function encode($seed, $string) {
		$return = "";
			$string = strtoupper(str_replace(" ", "", $string));
		$chars_total = strlen($string);

		for ($i = 0; $i < $chars_total; $i++) {
			$letter = substr($string, $i, 1);
			$letter_pos = strpos($this->alfabeto, $letter) + 1;
			$return .= substr($this->alfabeto, ($letter_pos + $seed - 1) , 1);	
			$seed = $letter_pos;
		}

		return $return;
	}

	function decode($seed, $string) {
		$return = "";
		$string = strtoupper(str_replace(" ", "", $string));
		$chars_total = strlen($string);

		for ($i = 0; $i < $chars_total; $i++) {
			$letter = substr($string, $i, 1);
			$letter_pos = strpos($this->alfabeto, $letter) + 1;
			$letter_decode = $letter_pos - $seed;

                                if ($letter_decode > strlen($this->alfabeto)) 
                                     $letter_decode -= strlen($this->alfabeto); // LINHA ADICIONADA PARA AS LETRAS Q ERAM COMIDAS

			$return .= substr($this->alfabeto, ($letter_decode - 1), 1);	
			$seed = $letter_decode;
		}

		return $return;
	}

}

$enc = new InTheBeginning;
echo $enc->decode(4, "X B M W W N B G C U A O O M W N W H C V R Y L S W A Q");
?>

EDIT: tive a olhar bem para o resultado e vi que foram comidas algumas letras, quando vou a ver o output aparece-me isto:

X (24 - 4 = 20) : T

B (2 - 20 = -18) : H

M (13 - -18 = 31) :

W (23 - 31 = -8) : R

W (23 - -8 = 31) :

Fui ver as solucoes eles tem isto:

Seed 4:

X (24) (24 – 4 = 20) T

B (2) (2 – 20 = 8 ) H

M (13) (13 – 8 = 5) E

W (23) (23 – 5 = 18) R

W (23) (23 – 18 = 5) E

2-20 = 8 !? que eu saiba na minha terra 2-20 é -18 ... nao sei onde eles foram buscar o 8 :S

EDIT 2: bug das letras comidas solved!

output:

X (24 - 4 = 20) : T

B (2 - 20 = -18) : H

M (13 - -18 = 5) : E

W (23 - 5 = 18) : R

W (23 - 18 = 5) : E

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Bom, parece que o meu código realmente não está implementado da melhor forma. Vou analisar as vossas propostas e tentar fazer com um novo algoritmo. Obrigado a todos pelas ajudas.  :thumbsup:

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

2-20 = 8 !? que eu saiba na minha terra 2-20 é -18 ... nao sei onde eles foram buscar o 8 :S

Expliquei isto no post anterior...

Editado a partir daqui:

Lembrei-me que uma forma rápida de fazer estes cálculos é ir ao Google :thumbsup: No Google a notação para a aálgebra modular é %, ou seja basta fazer -18%26 e o google dá a resposta!

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

evitas a confusão com as letras com numero negativo se verificares se a letra actual é maior ou menor que a anterior...

se for maior, fazes simplesmente actual-anterior...

se for menor, basta fazeres 26+actual-anterior e dá-te a letra correcta... então, a situação do B e do X já não se apresenta, porque as contas serão 26+2-20=8...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora