[PROGRAMAÇÃO] - Desafio - O tabuleiro de Xadrez e os bagos de arroz

Coloquem aqui as vossas dúvidas informáticas, e algumas notícias que achem de interesse para a comunidade DvdManiaca
Samwise
DVD Maníaco
DVD Maníaco
Posts: 6267
Joined: February 19th, 2009, 9:07 pm
Contact:

[PROGRAMAÇÃO] - Desafio - O tabuleiro de Xadrez e os bagos de arroz

Post by Samwise »

Conforme mencionei no outro tópico sobre os módulos VBA para recolher dados no IMDB, ando envolvido na elaboração de um programita para devolver uma string a partir de um inteiro. Mais em concreto, um procedimento que permita receber como argumento um determinado número literal, e a partir dele deduzir e devolver "como se escreve em texto".

Exs:
recebe argumento: 1 -> devolve: "um"
recebe argumento: 23 -> devolve: "vinte e três"
recebe argumento: 1800 -> devolve: "mil e oitocentos"
recebe argumento: 1000235 -> devolve: "um milhão, duzentos e trinta e cinco"

Isto é um desafio interessante (com nuances engraçadas), e não demasiado complicado, para quem está a começar a aprender a programar e para quem está a dar os primeiros passos a escrever código em métodos/procedimentos/funções, seja qual for a linguagem utilizada.

Eu fiz isto em VBA há uns anos atrás (foi a coisa mais complicada que fiz em VBA, mesmo não sendo muito complexa), e agora ando a fazê-la em java, utilizando outros pressupostos no código.

E o que tem isto a ver com Xadrez? :-)))

Bom, com Xadrez não tem muito a ver, mas tem a ver com uma das lendas que se contam sobre a invenção do jogo, e que diz que o monarca desse país distante onde o jogo surgiu decidiu premiar o inventor concedendo-lhe um desejo. O inventor disse ao rei que queria uns bagos de arroz. O Rei começou-se a rir e perguntou quantos. O inventor disse-lhe para colocar um bago na primeira casa de um tabuleiro de Xadrez, o dobro na segunda casa, o quádruplo na terceira e assim sucessivamente até ao final das 64 casas. O Rei riu-se outra vez e perguntou se era só isso. E desta vez foi o inventor que se começou a rir...

Os cálculos para os bagos de arroz são estes:

Casa / número de bagos
1 - 1
2 - 2
3 - 4
4 - 8
5 - 16
6 - 32
7 - 64
8 - 128
9 - 256
10 - 512
11 - 1.024
12 - 2.048
13 - 4.096
14 - 8.192
15 - 16.384
16 - 32.768
17 - 65.536
18 - 131.072
19 - 262.144
20 - 524.288
21 - 1.048.576
22 - 2.097.152
23 - 4.194.304
24 - 8.388.608
25 - 16.777.216
26 - 33.554.432
27 - 67.108.864
28 - 134.217.728
29 - 268.435.456
30 - 536.870.912
31 - 1.073.741.824
32 - 2.147.483.648
33 - 4.294.967.296
34 - 8.589.934.592
35 - 17.179.869.184
36 - 34.359.738.368
37 - 68.719.476.736
38 - 137.438.953.472
39 - 274.877.906.944
40 - 549.755.813.888
41 - 1.099.511.627.776
42 - 2.199.023.255.552
43 - 4.398.046.511.104
44 - 8.796.093.022.208
45 - 17.592.186.044.416
46 - 35.184.372.088.832
47 - 70.368.744.177.664
48 - 140.737.488.355.328
49 - 281.474.976.710.656
50 - 562.949.953.421.312
51 - 1.125.899.906.842.620
52 - 2.251.799.813.685.250
53 - 4.503.599.627.370.500
54 - 9.007.199.254.740.990
55 - 18.014.398.509.482.000
56 - 36.028.797.018.964.000
57 - 72.057.594.037.927.900
58 - 144.115.188.075.856.000
59 - 288.230.376.151.712.000
60 - 576.460.752.303.423.000
61 - 1.152.921.504.606.850.000
62 - 2.305.843.009.213.690.000
63 - 4.611.686.018.427.390.000
64 - 9.223.372.036.854.780.000

E agora? Como se "diz" este número?

Em vez de ir só à procura das notações para grandes numerais, decidi voltar a escrever o código para me dar automaticamente esse texto, para qualquer número que introduza.

E voilá, é este o desafio.

---

Como nota adicional, deixo aqui a notação portuguesa para os grandes numerais:

numérico extenso potência
1.000 Mil 10^3 três zeros
1.000.000 1 Milhão 10^6 seis zeros
1.000.000.000 Mil milhões 10^9 nove zeros
1.000.000.000.000 1 Bilião 10^12 doze zeros
1.000.000.000.000.000 Mil Biliões 10^15 quinze zeros
1.000.000.000.000.000.000 1 Trilião 10^18 dezoito zeros
1.000.000.000.000.000.000.000 Mil triliões 10^21 vinte e um zeros
1.000.000.000.000.000.000.000.000 1 Quatrilião 10^24 vinte e quatro zeros
1.000.000.000.000.000.000.000.000.000 Mil Quatriliões 10^27 vinte e sete zeros
1.000.000.000.000.000.000.000.000.000.000 1 Quintilião 10^30 trinta zeros
1.000.000.000.000.000.000.000.000.000.000.000 Mil Quintiliões 10^33 trinta e três zeros
1.000.000.000.000.000.000.000.000.000.000.000.000 1 Sextilião 10^36 trinta e seis zeros
...
1 Septilião 10^42
1 Octilião 10^48
1 Nonilião 10^54
1 Decilião 10^60
1 Undecilião 10^66
1 Duodecilião 10^72
...
1 Centilião 10^600 seiscentos zeros
Last edited by Samwise on February 28th, 2019, 6:00 pm, edited 2 times in total.
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.

«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death

Câmara Subjectiva
Samwise
DVD Maníaco
DVD Maníaco
Posts: 6267
Joined: February 19th, 2009, 9:07 pm
Contact:

Re: [PROGRAMAÇÃO] O desafio do tabuleiro de Xadrez e dos bagos de arroz

Post by Samwise »

Terminei praticamente o código em Java, mas não atingi ainda um dos objectivos iniciais, por causa de uma limitação de capacidade na variável de memória que utilizei, e que não chega para armazenar um numero tão grande quanto o 2 elevado a 64.

Dito de outra forma, o programa neste momento devolve o extenso de todos os inteiros até 9.223.372.036.854.775.807 (Long.MAX_VALUE), que é o limite superior do tipo de variável "long", e o número de bagos de arroz na casa 64 do tabuleiro de Xadrez é 9.223.372.036.854.780.000. Por uns míseros milhares que não chega para esse cálculo. :lol:

Não vai ser já, mas um dia destes vou adaptar esta classe que está pronta para contornar esta limitação, sendo que para esse efeito vou ter de deixar de utilizar as variáveis nativas da linguagem e passar a utilizar uma classe específica para tratar grande quantidades (e que dá pelo nome de "BigInteger") - mas para isso, terei de reescrever algumas partes do código, porque a substituição não é directa. Em todo o caso, a estrutura e o modelo de fluxos estão feitos, e isso vale mais de metade do problema.

--- EDIT

Fui investigar os "data types " do VBA e aparentemente existe a mesma limitação na atribuição de memória às variáveis. O máximo que dá para alocar a um número inteiro permite-nos atribuir a uma variável do tipo "longlong" um valor de 9.223.372.036.854.775.807. Para considerar valores acima, existe outro data type que é o "decimal", mas este não obedece aos mesmos padrões de funcionamento dos data types nativos - o código para o utilizar é diferente.
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.

«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death

Câmara Subjectiva
Samwise
DVD Maníaco
DVD Maníaco
Posts: 6267
Joined: February 19th, 2009, 9:07 pm
Contact:

Re: [PROGRAMAÇÃO] O desafio do tabuleiro de Xadrez e dos bagos de arroz

Post by Samwise »

Ponto da situação:

A "Fase 1" está prestes a ficar concluída - falta-me fazer uma sessão de "debugging" mais à séria para garantir que o código funciona na totalidade, e que não há fugas imprevistas entre os procedimentos. Depois disso partilho aqui o resultado.

A seguir, tenho planeado:

Fase 2 - Optimização de código. Enquanto o processo na fase 1 visou construir uma classe que funcionasse, nesta fase 2 quero melhorar o que está feito, de modo a limpar as gorduras do código, nomeadamente a nível de repetições desnecessárias de comandos e procedimentos. Dada a natureza circular que é característica deste projecto específico (funções que chamam outras funções muito semelhantes, que chamam por sua vez outras funções muito semelhantes), é possível reunir estas repetições em funções únicas, em que só variam os argumentos recebidos e o tipo de grandeza utilizada nos cálculos.

Fase 3 - Reescrever a aplicação de modo a receber valores de grandeza acima do "trilião", utilizando para isso a classe BigInteger.

Fase 4 (?) - Transcrever o código para VBA, para poder ser utilizado no Excel, através de uma função (que dê para utilizar numa célula qualquer, tipo =Extenso(A1) ).
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.

«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death

Câmara Subjectiva
Samwise
DVD Maníaco
DVD Maníaco
Posts: 6267
Joined: February 19th, 2009, 9:07 pm
Contact:

Re: [PROGRAMAÇÃO] O desafio do tabuleiro de Xadrez e dos bagos de arroz

Post by Samwise »

Avanço para a publicação do código já terminado. Vou apresentar primeiro uma mini-versão, que só considera números até 999.999 unidades, para explicar algumas particularidades da lógica, e para estabelecer um paralelo com o VBA.

A lógica do programa é separar por métodos/funções/módulos (chamem-lhe o que quiserem) as principais grandezas para as quais é necessário escrever manualmente o respectivo extenso, de modo a que só seja necessário declarar uma vez esse valor, e de modo a que cada módulo possa ser reutilizado por outros módulos "superiores". Por exemplo, os inteiros de zero a vinte ficam agrupados num módulo ("zero", "um", "dois"...), outro módulo a seguir agrupa os valores de dezena até ao cem ("trinta", "quarenta""...), outro ainda o das centenas ("cem", "duzentos", "trezentos"...). A seguir, com a chegada do milhar, esta lógica altera-se, porque nos números acerca dos quais necessitamos de um extenso já estão traduzidos em cada um dos módulos anteriores, e apenas necessitamos de escolher um enquadramento para colocar o "mil" face a esses outros números. Se for 2.000, vamos buscar o "dois" ao primeiro módulo e acrescentamos o "mil". Se for 110.000, vamos buscar o "dez" ao primeiro módulo, o "cento" ao segundo e acrescentamos o "mil". Não é assim tão directo, mas a geral lógica é esta. Há um módulo inicial de "triagem", que avalia o número passado e decide a que módulo vai fazer o pedido de tradução. Depois, os módulos comunicam entre si necessário, para pedir traduções de valores que sejam componentes desse número.

Uma pequena legenda, a ver com a linguagem Java:

// - significa um comentário (código não executado)
|| - significa o operador lógico OR
&& - significa operador lógico AND
/ - operador matemático para a divisão
% - operador matemático que devolve o resto de uma divisão
== - operador de comparação entre variáveis
{ } - as "chavetas" indicam um bloco lógico de código, início e fim (no VBA não existem, e o início e fim de cada bloco são assinalados com comandos concretos, ou com o final de uma linha).

Code: Select all

public class MiniExtenso {

    // método de arranque, onde podemos inserir manualmente o número pretendido, neste
    // caso está a indicar 999999 como argumento.
    	
    public static void main(String[] args) {

        long iVar;
        iVar = 999_999;
        System.out.println(triagemInicial(iVar));

    }

    public static String triagemInicial(long i) {

        String valorFinal;
        
        if(i<0){
           System.out.println("Insira um número maior ou igual a zero.");
           return "";
        }

        if(i < 20) {
            valorFinal = deZeroaDezanove((int) i);
        }
        else if(i <= 100) {
            valorFinal = menorQueCem((int) i);
        }
        else if(i <= 1000) {
            valorFinal = menorQueMil((int) i);
        }
        else if(i < 1_000_000) {
            valorFinal = menorQueUmMilhao((int) i);
        }
        else {
            valorFinal = "Grandeza demasiado grande - não suportada por enquanto.";
        }
        return valorFinal;
    }


    public static String deZeroaDezanove(int i){

        String valorFinal;

        switch(i) {
            case 0:
                valorFinal = "zero";
                break;
            case 1:
                valorFinal = "um";
                break;
            case 2:
                valorFinal = "dois";
                break;
            case 3:
                valorFinal = "três";
                break;
            case 4:
                valorFinal = "quatro";
                break;
            case 5:
                valorFinal = "cinco";
                break;
            case 6:
                valorFinal = "seis";
                break;
            case 7:
                valorFinal = "sete";
                break;
            case 8:
                valorFinal = "oito";
                break;
            case 9:
                valorFinal = "nove";
                break;
            case 10:
                valorFinal = "dez";
                break;
            case 11:
                valorFinal = "onze";
                break;
            case 12:
                valorFinal = "doze";
                break;
            case 13:
                valorFinal = "treze";
                break;
            case 14:
                valorFinal = "catorze";
                break;
            case 15:
                valorFinal = "quinze";
                break;
            case 16:
                valorFinal = "dezasseis";
                break;
            case 17:
                valorFinal = "dezassete";
                break;
            case 18:
                valorFinal = "dezoito";
                break;
            case 19:
                valorFinal = "dezanove";
                break;
            default:
                valorFinal = "**** Algo correu mal no método #deZeroaVinte ****";
        }
        return valorFinal;
    }

    public static String menorQueCem(int i) {

        String valorFinal;

        if(i%10 == 0) {
            valorFinal = deVinteaNoventaeNove(i);
        }
        else {
            valorFinal = deVinteaNoventaeNove(i - (i%10)) + " e "
                    + deZeroaDezanove(i%10);
        }

        return valorFinal;
    }

    public static String deVinteaNoventaeNove(int i) {

        String valorFinal;

        switch(i) {
            case 20:
                valorFinal = "vinte";
                break;
            case 30:
                valorFinal = "trinta";
                break;
            case 40:
                valorFinal = "quarenta";
                break;
            case 50:
                valorFinal = "cinquenta";
                break;
            case 60:
                valorFinal = "sessenta";
                break;
            case 70:
                valorFinal = "setenta";
                break;
            case 80:
                valorFinal = "oitenta";
                break;
            case 90:
                valorFinal = "noventa";
                break;
            case 100:
                valorFinal = "cem";
                break;
            default:
                valorFinal = "**** Algo correu mal no método #deVinteaNoventaeNove ****";
        }
        return valorFinal;
    }

    public static String menorQueMil(int i) {

        String valorFinal;

        if(i%100 == 0)
            valorFinal = deCemaNoveNoveNove(i);
        else if(i<200)
            valorFinal = "cento e " + triagemInicial(i%100);
        else
            valorFinal = deCemaNoveNoveNove(i - i%100) + " e " + triagemInicial(i%100);

        return valorFinal;
    }

    public static String deCemaNoveNoveNove(int i) {

        String valorFinal;

        switch(i) {

            case 200:
                valorFinal = "duzentos";
                break;
            case 300:
                valorFinal = "trezentos";
                break;
            case 400:
                valorFinal = "quatrocentos";
                break;
            case 500:
                valorFinal = "quinhentos";
                break;
            case 600:
                valorFinal = "seiscentos";
                break;
            case 700:
                valorFinal = "setecentos";
                break;
            case 800:
                valorFinal = "oitocentos";
                break;
            case 900:
                valorFinal = "novecentos";
                break;
            case 1000:
                valorFinal = "mil";
                break;
            default:
                valorFinal = "**** Algo correu mal no método #deCemaNoveNoveNove ****";
        }
        return valorFinal;
    }

    public static String menorQueUmMilhao(int i) {

        String valorFinal ;

        if(i%1000 == 0) {
            valorFinal = triagemInicial(i/1000) + " mil" ;
        }
        else if(i%1000 <= 100 || ((i%1000)%100) == 0){
            if(i/1000 == 1 ) {
                valorFinal = "mil e " + triagemInicial(i%1000);
            }
            else {
                valorFinal = triagemInicial(i/1000) + " mil e " + triagemInicial(i%1000);
            }
        }
        else {
            if(i/1000 == 1 ){
                valorFinal = "mil " + triagemInicial(i%1000);
            }
            else {
                valorFinal = triagemInicial(i/1000) + " mil " + triagemInicial(i%1000);
            }
        }
        return valorFinal;
    }
}
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.

«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death

Câmara Subjectiva
Samwise
DVD Maníaco
DVD Maníaco
Posts: 6267
Joined: February 19th, 2009, 9:07 pm
Contact:

Re: [PROGRAMAÇÃO] O desafio do tabuleiro de Xadrez e dos bagos de arroz

Post by Samwise »

Algumas comparações com VBA:

Declaração de início (e fim) de um método Java:

Code: Select all

public static String triagemInicial(long i) {
	...
	...
}
Em VBA será qualquer coisa como:

Code: Select all

Function triagemInicial(i As Long) as String
	...
	...
End Function
---

Declaração de uma variável Java:

Code: Select all

 String valorFinal;
Em VBA:

Code: Select all

Dim valorFinal as String
---

"If then else" em Java:

Code: Select all

if(i%10 == 0) {
       valorFinal = deVinteaNoventaeNove(i);
}
else {
       valorFinal = deVinteaNoventaeNove(i - (i%10)) + " e " + deZeroaDezanove(i%10);
}
VBA:

Code: Select all

If ( i Mod 10 = 0) then
	valorFinal = deVinteaNoventaeNove(i)
Else
	valorFinal = deVinteaNoventaeNove(i - ( i Mod 10) + " e " + deZeroaDezanove( i Mod 10)
End If

---

"Do case" em Java:

Code: Select all

 switch(i) {
            case 0:
                valorFinal = "zero";
                break;
            case 1:
                valorFinal = "um";
                break;
             default:
                valorFinal = "**** Algo correu mal no método #deZeroaVinte ****";
        }
Em VBA:

Code: Select all

Select Case i
	Case 0
		valorFinal = "zero"
	Case 1
		valorFinal = "um"	
	Case else
		valorFinal = "**** Algo correu mal no método #deZeroaVinte ****"	
End Select
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.

«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death

Câmara Subjectiva
Samwise
DVD Maníaco
DVD Maníaco
Posts: 6267
Joined: February 19th, 2009, 9:07 pm
Contact:

Re: [PROGRAMAÇÃO] O desafio do tabuleiro de Xadrez e dos bagos de arroz

Post by Samwise »

Fase 1 concluída.

Debug efectuado, algumas situações corrigidas, e alguma melhorias acrescentadas, em concreto:

1 - O programa aceita agora inteiros negativos;
2 - o programa devolve o extenso de inteiros até ao trilião, exclusive, ou seja, inteiros compostos por até 18 dígitos;
3 - corrigidas as situações na acentuação através da utilização de códigos UNICODE (e que corrige o output dos termos: três, milhão, milhões, etc);
4 - o programa pode ser lançado a partir da linha de comando.

Image

O código para esta versão (***** DISCLAIMER - Esta versão do código tem alguns erros identificados *****:

Code: Select all

public class Extenso2 {

   public static void main(String[] args) {

      if(args[0].length() > 19) {
        System.out.println("Inteiro demasiado grande - ainda n\u00E3o suportado.");
        return;
      }

      long iVar = Long.parseLong(args[0], 10) ;

         System.out.println(triagemInicial( iVar));
   }

   public static String triagemInicial(long i) {

      String valorFinal;
      boolean isNeg = false;

      if(i<0) {
         isNeg = true;
         i = -i;
      }

      if(i < 20) {
         valorFinal = deZeroaDezanove((int) i);
      }
      else if(i <= 100) {
         valorFinal = menorQueCem((int) i);
      }
      else if(i <= 1000) {
         valorFinal = menorQueMil((int) i);
      }
      else if(i < 1_000_000) {
         valorFinal = menorQueUmMilhao((int) i);
      }
      else if(i < 1_000_000_000_000L) {
         valorFinal = menorQueUmBiliao(i);
      }
      else if(i < 1_000_000_000_000_000_000L) {
         valorFinal = menorQueUmTriliao(i);
      }
      else {
         valorFinal = "Inteiro demasiado grande - ainda n\u00E3o suportado.";
      }

      return (isNeg ? "menos " + valorFinal : valorFinal);
   }

   public static String deZeroaDezanove(int i){

      String valorFinal;

      switch(i) {
         case 0:
            valorFinal = "zero";
            break;
         case 1:
            valorFinal = "um";
            break;
         case 2:
            valorFinal = "dois";
            break;
         case 3:
            valorFinal = "tr\u00EAs";
            break;
         case 4:
            valorFinal = "quatro";
            break;
         case 5:
            valorFinal = "cinco";
            break;
         case 6:
            valorFinal = "seis";
            break;
         case 7:
            valorFinal = "sete";
            break;
         case 8:
            valorFinal = "oito";
            break;
         case 9:
            valorFinal = "nove";
            break;
         case 10:
            valorFinal = "dez";
            break;
         case 11:
            valorFinal = "onze";
            break;
         case 12:
            valorFinal = "doze";
            break;
         case 13:
            valorFinal = "treze";
            break;
         case 14:
            valorFinal = "catorze";
            break;
         case 15:
            valorFinal = "quinze";
            break;
         case 16:
            valorFinal = "dezasseis";
            break;
         case 17:
            valorFinal = "dezassete";
            break;
         case 18:
            valorFinal = "dezoito";
            break;
         case 19:
            valorFinal = "dezanove";
            break;
         default:
            valorFinal = "BUG eating method deZeroaVinte";
             }
      return valorFinal;
   }

   public static String menorQueCem(int i) {

      String valorFinal;

      if(i%10 == 0) {
         valorFinal = deVinteaNoventaeNove(i);
      }
      else {
         valorFinal = deVinteaNoventaeNove(i - (i%10)) + " e "
               + deZeroaDezanove(i%10);
      }

      return valorFinal;
   }

   public static String deVinteaNoventaeNove(int i) {

      String valorFinal;

      switch(i) {
         case 20:
            valorFinal = "vinte";
            break;
         case 30:
            valorFinal = "trinta";
            break;
         case 40:
            valorFinal = "quarenta";
            break;
         case 50:
            valorFinal = "cinquenta";
            break;
         case 60:
            valorFinal = "sessenta";
            break;
         case 70:
            valorFinal = "setenta";
            break;
         case 80:
            valorFinal = "oitenta";
            break;
         case 90:
            valorFinal = "noventa";
            break;
         case 100:
            valorFinal = "cem";
            break;
         default:
            valorFinal = "A BUG is chewing method deVinteaNoventaeNove";
             }
      return valorFinal;
    }

   public static String menorQueMil(int i) {

      String valorFinal;

      if(i%100 == 0)
         valorFinal = deCemaNoveNoveNove(i);
      else if(i<200)
         valorFinal = "cento e " + triagemInicial(i%100);
      else
         valorFinal = deCemaNoveNoveNove(i - i%100) + " e " + triagemInicial(i%100);

      return valorFinal;
    }

   public static String deCemaNoveNoveNove(int i) {

      String valorFinal;

      switch(i) {

         case 200:
            valorFinal = "duzentos";
            break;
         case 300:
            valorFinal = "trezentos";
            break;
         case 400:
            valorFinal = "quatrocentos";
            break;
         case 500:
            valorFinal = "quinhentos";
            break;
         case 600:
            valorFinal = "seiscentos";
            break;
         case 700:
            valorFinal = "setecentos";
            break;
         case 800:
            valorFinal = "oitocentos";
            break;
         case 900:
            valorFinal = "novecentos";
            break;
         case 1000:
            valorFinal = "mil";
            break;
         default:
            valorFinal = "A BUG is chewing method deCemaNoveNoveNove";
      }
      return valorFinal;
    }

   public static String menorQueUmMilhao(int i) {

      String valorFinal ;

      if(i%1000 == 0) {
         valorFinal = triagemInicial(i/1000) + " mil" ;
      }
      else if(i%1000 <= 100 || ((i%1000)%100) == 0){
         if(i/1000 == 1 ) {
            valorFinal = "mil e " + triagemInicial(i%1000);
         }
         else {
            valorFinal = triagemInicial(i/1000) + " mil e " + triagemInicial(i%1000);
         }
      }
      else {
         if(i/1000 == 1 ){
            valorFinal = "mil " + triagemInicial(i%1000);
         }
         else {
            valorFinal = triagemInicial(i/1000) + " mil " + triagemInicial(i%1000);
         }
      }
      return valorFinal;
   }

   public static String menorQueUmBiliao (long i) {

        String valorFinal;

        if(i%1_000_000 == 0){
            valorFinal = (i == 1_000_000 ? "um milh\u00E3o" : triagemInicial(i/1_000_000) + " milh\u00F5es");
        }
        else if( i%1_000_000 <= 100 || ( (i%1_000_000 <= 1000) && (i%1_000_000)%100 == 0) || ( (i%1_000_000 <= 100_000) && (i%1_000_000)%1000 == 0) ) {
                if (i/1_000_000 == 1) {
                    valorFinal = "um milh\u00E3o e " + triagemInicial(i % 1_000_000);
                }
                else{
                    valorFinal = triagemInicial(i/1_000_000) + " milh\u00F5es e " + triagemInicial(i%1_000_000);
                }
        }
        else {
            if (i/1_000_000 == 1) {
               valorFinal = "um milh\u00E3o, " + triagemInicial(i%1_000_000);
            }
            else{
                valorFinal = triagemInicial(i/1_000_000) + " milh\u00F5es, " + triagemInicial(i%1_000_000);
            }
        }
        return valorFinal;
    }

    public static String menorQueUmTriliao (long i) {

        String valorFinal;
        long milMil = 1_000_000_000_000L;

        if(i%milMil == 0) {
            valorFinal = (i == milMil ? "um bili\u00E3o" : triagemInicial(i/milMil ) + " bili\u00F5es");
        }
        else if( i%milMil <= 100 || ( (i%milMil) <= 1000  && (i%milMil)%100 == 0) || ( (i%milMil) <= 100_000  && (i%milMil)%1000 == 0)
                  ||  ( (i%milMil) <= 100_000_000  && (i%milMil)%10_000 == 0)
                  ||  ( (i%milMil) <= 100_000_000_000L  && (i%milMil)%100_000 == 0)  ){
            if (i/milMil == 1) {
                valorFinal = "um bili\u00E3o e " + triagemInicial(i%milMil);
            } else {
                valorFinal = triagemInicial(i / milMil) + " bili\u00F5es e " + triagemInicial(i%milMil);
            }
        }
        else{
            if(i/milMil == 1) {
                valorFinal = "um bili\u00E3o, " + triagemInicial(i%milMil);
            }
            else {
                valorFinal =  triagemInicial(i/milMil ) + " bili\u00F5es, " + triagemInicial(i%milMil);
            }
        }
        return valorFinal;
    }
}

Vou fazer um bypass à optimização que estava pensada para ser a segunda fase (e que vai dar bastante trabalho, decididamente), e vou avançar para a fase 3 - algo que me vai permitir acrescentar módulos para calcular grandezas superiores ao trilião.
Last edited by Samwise on February 28th, 2019, 6:01 pm, edited 1 time in total.
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.

«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death

Câmara Subjectiva
Samwise
DVD Maníaco
DVD Maníaco
Posts: 6267
Joined: February 19th, 2009, 9:07 pm
Contact:

Re: [PROGRAMAÇÃO] O desafio do tabuleiro de Xadrez e dos bagos de arroz

Post by Samwise »

Um pouco de marcha atrás no projecto.

Indo já bem lançado a meio da adaptação do programa para numerais mais extensos, e começo a ver código e mais código, e cada vez mais complexo de "ler/interpretar", sendo que, por conta essencialmente dessa multiplicação exponencial de palavras "chinesas" (entenda-se: para chinês ler), decidi incluir nesta fase o tal processo de optimização de código (já comecei), coisa que me vai dar algum trabalho inicial adicional, mas permitir poupar depois tempo e preocupações em desenvolvimento futuros. E o código fica mais eficiente e legível.

E nos entretanto encontrei uma excepção no programa que estava a permitir a alguns números escaparem-se à "tradução", ou melhor, ficarem com as vírgulas e os "e" mal atribuídos. Esta parte dos "e" e das vírgulas é de longe a mais complexa envolvida neste programa - saber onde se colocam e como desenvolver código que contemple todos os casos. Ex: "Mil Milhões e um", "Mil Milhões e duzentos mil", "Mil Milhões, trezentos e trinta e três mil e vinte." eh-)
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.

«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death

Câmara Subjectiva
Samwise
DVD Maníaco
DVD Maníaco
Posts: 6267
Joined: February 19th, 2009, 9:07 pm
Contact:

Re: [PROGRAMAÇÃO] O desafio do tabuleiro de Xadrez e dos bagos de arroz

Post by Samwise »

Já vejo luz ao fundo do túnel. :wink:

Image

- O objectivo inicial está cumprido: o programa devolve o extenso do valor de bagos de arroz na casa 64 do tabuleiro de xadrez:

- As fases 2 e 3 também estão concluídas, e neste momento consigo acrescentar facilmente módulos/métodos para cada nova grandeza que pretenda. Está feito até ao quatrilião, exclusive, mas irei amanhã acrescentar mais umas quantas camadas de zeros, até chegar ao decilião, o que permite algo como inserir inteiros com 60 algarismos. :mrgreen: Com a utilização da classe BigInteger, não há virtualmente um teto superior limitativo - o limite de cálculo é a capacidade de memória (RAM) da máquina onde isto estiver a correr.

- Falta fazer nova sessão de debugging - um procedimento bastante penoso neste programa, e que implica basicamente testar uma série de conjuntos de números para cada mudança de dezena, centena, milher, etc. É moroso e secante. :| Assim que isto estiver feito, coloco aqui o código final.
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.

«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death

Câmara Subjectiva
User avatar
Rui Santos
Site Admin
Posts: 6163
Joined: June 4th, 2001, 11:42 pm
Location: Portugal - Lisboa / MAC
Contact:

Re: [PROGRAMAÇÃO] O desafio do tabuleiro de Xadrez e dos bagos de arroz

Post by Rui Santos »

Eu não tenho comentado, mas tenho acompanhado de muito perto este teu exercício e reflexão.
E é das coisas mais fantásticas tentar programar uma regra "simples" como esta, mas que no nosso cérebro apreende com uma idade de 6/7 anos... e ver a complexidade da mesma, e como nós fazemos isso naturalmente.
Rui Santos - 54 Anos | 22 Anos DVDMania
DVD/BR | Jogos | Life is Short, Play More | FB Collectors HV-PT
Samwise
DVD Maníaco
DVD Maníaco
Posts: 6267
Joined: February 19th, 2009, 9:07 pm
Contact:

Re: [PROGRAMAÇÃO] O desafio do tabuleiro de Xadrez e dos bagos de arroz

Post by Samwise »

Rui Santos wrote: February 28th, 2019, 9:11 am Eu não tenho comentado, mas tenho acompanhado de muito perto este teu exercício e reflexão.
E é das coisas mais fantásticas tentar programar uma regra "simples" como esta, mas que no nosso cérebro apreende com uma idade de 6/7 anos... e ver a complexidade da mesma, e como nós fazemos isso naturalmente.
Bom, este meu exercício surgiu assim do nada - ou do quase nada. É o que dá ter filhos inscritos no Xadrez no secundário, e as 64 casas do tabuleiro virem à baila na conversa... :lol: :lol: :lol:

Mas é muito isso, Rui. Para lá do gozo que é tentar resolver um problema através de um processo de desenvolvimento de um programa dedicado, este projecto serve também de micro-exemplo ilustrativo daquilo que são muitos dos problemas e desafios de projectos maiores, e também das formas de os resolver. Mesmo em casos mais simples, as coisas podem complicar a determinada altura, e podem envolver a separação do problema inicial numa quantidade ainda maior de problemas "mais pequenos". Digamos que até ao milhão isto foi muito fácil. A partir daí já deu para umas horitas extra de reflexão e experimentação não equacionadas. :wink:
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.

«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death

Câmara Subjectiva
Samwise
DVD Maníaco
DVD Maníaco
Posts: 6267
Joined: February 19th, 2009, 9:07 pm
Contact:

Re: [PROGRAMAÇÃO] O desafio do tabuleiro de Xadrez e dos bagos de arroz

Post by Samwise »

Neste momento, está assim:

Image

Image

Faz-me lembrar o reino de "bué bué longe" no Shrek 2 - aqui, temos um número "bué bué grande". :lol:

Falta-me "apenas" fazer a revisão ao código para apanhar "infracções", processo também conhecido por "caça ao bug". No easy task, though... :roll:

Nos entretantos, aqui fica o código para a versão actual, e que ronda as 450 linhas:

Code: Select all

import java.math.BigInteger; 

public class Extenso5 {
            
    public static void main(String[] args) {

        String inputVal = args[0].trim();   
        
        boolean isNeg = false;
        if( inputVal.startsWith("-")) {
            isNeg = true;
            inputVal = inputVal.substring(1);
        }

        char[] diagS = inputVal.toCharArray();

        int contarDigitos = 0;
        for(char algarismo: diagS) {

            if( ! Character.isDigit(algarismo)){
                System.out.println("*** EXITING *** A express\u00E3o contem caracteres n\u00E3o num\u00E9ricos.");
                return;
            }
            contarDigitos++;
        }
       
         // pseudo-info-stats
        System.out.println();
        BigInteger inteiro = new BigInteger(inputVal);
        String sepMilhares = String.format("%,d", inteiro);
        System.out.println(sepMilhares);
        System.out.println("Express\u00E3o composta por " + contarDigitos + " algarismos.");
        System.out.println();

        // Chamada ao método "nuclear": para triagem da grandeza e seguimento do fluxo
        System.out.println("Extenso: " + ( isNeg ? "menos " : "" ) + triagemInicial(inputVal)); 
    }

    public static String triagemInicial(String i) {

        String valorFinal;
      
        BigInteger inputVal = new BigInteger(i);

        if(inputVal.compareTo(BigInteger.valueOf(1_000_000)) < 0) {
     
            int inputValNum = Integer.parseInt(i);
           
            if(inputValNum < 20) {

                valorFinal = deZeroaDezanove(inputValNum);
            }
            else if(inputValNum <= 100) {

                valorFinal = menorQueCem(inputValNum);
            }
            else if(inputValNum <= 1000) {
                
                valorFinal = menorQueMil(inputValNum);
            }
            else {  // <1_000_000
               
                valorFinal = menorQueUmMilhao(inputValNum);
            }
        }    
        else{  // >= 1_000_000

            //... Acrescentar "grandezas" à lista, criar a excepção "else if" a seguir...
            BigInteger bil =     new BigInteger("1000000000000"); //bilião 
            BigInteger tril =    new BigInteger("1000000000000000000");  //trilião 
            BigInteger quatril = new BigInteger("1000000000000000000000000");  //quatrilião  
            BigInteger quintil = new BigInteger("1000000000000000000000000000000");  //quintilião 
            BigInteger seistil = new BigInteger("1000000000000000000000000000000000000");  //seistilião  
            BigInteger setil =   new BigInteger("1000000000000000000000000000000000000000000");  //setilião 
            BigInteger octil =   new BigInteger("1000000000000000000000000000000000000000000000000");  //octilião 
            BigInteger nonil =   new BigInteger("1000000000000000000000000000000000000000000000000000000");  //nonilião 
            BigInteger decil =   new BigInteger("1000000000000000000000000000000000000000000000000000000000000");  //decilião 
            BigInteger undecil = new BigInteger("1000000000000000000000000000000000000000000000000000000000000000000");  //undecilião 

            if(inputVal.compareTo(bil) < 0) { // < 1_000_000_000_000
               
                valorFinal = metodoMilinario( inputVal.toString(), "milh\u00E3o", "milh\u00F5es", "1000000"); 
                
            }
            else if(inputVal.compareTo(tril) < 0) { // < 1_000_000_000_000_000_000
               
                valorFinal = metodoMilinario( inputVal.toString(), "bili\u00E3o", "bili\u00F5es", "1000000000000"); 
            }
            else if(inputVal.compareTo(quatril) < 0) { // < 1_000_000_000_000_000_000_000_000
              
               valorFinal = metodoMilinario( inputVal.toString(), "trili\u00E3o", "trili\u00F5es", "1000000000000000000"); 
            }
            else if(inputVal.compareTo(quintil) < 0) { // < 1_000_000_000_000_000_000_000_000_000_000
                
                valorFinal = metodoMilinario( inputVal.toString(), "quatrili\u00E3o", "quatrili\u00F5es",
                                                                   "1000000000000000000000000"); 
            }
            else if(inputVal.compareTo(seistil) < 0) { // < 1_000_000_000_000_000_000_000_000_000_000_000_000
                
                valorFinal = metodoMilinario( inputVal.toString(), "quintili\u00E3o", "quintili\u00F5es",
                                                                   "1000000000000000000000000000000"); 
            }
            else if(inputVal.compareTo(setil) < 0) { // < 1_000_000_000_000_000_000_000_000_000_000_000_000_000_000
                
                valorFinal = metodoMilinario( inputVal.toString(), "seistili\u00E3o", "seistili\u00F5es", 
                                                                   "1000000000000000000000000000000000000"); 
            }
            else if(inputVal.compareTo(octil) < 0) { // < 1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000
                
                valorFinal = metodoMilinario( inputVal.toString(), "setili\u00E3o", "setili\u00F5es", 
                                                                   "1000000000000000000000000000000000000000000"); 
            }
            else if(inputVal.compareTo(nonil) < 0) { // < 1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000
                
                valorFinal = metodoMilinario( inputVal.toString(), "octili\u00E3o", "octili\u00F5es", 
                                                                   "1000000000000000000000000000000000000000000000000"); 
            }
            else if(inputVal.compareTo(decil) < 0) { // < 1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000
                
                valorFinal = metodoMilinario( inputVal.toString(), "nonili\u00E3o", "nonili\u00F5es", 
                                                                   "1000000000000000000000000000000000000000000000000000000"); 
            }
            else if(inputVal.compareTo(undecil) < 0) { // < 1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000
                
                valorFinal = metodoMilinario( inputVal.toString(), "decili\u00E3o", "decili\u00F5es", 
                                                                   "1000000000000000000000000000000000000000000000000000000000000"); 
            }
            else {

            valorFinal = "Inteiro demasiado grande - ainda n\u00E3o suportado.";
            }
        }
        return valorFinal;

    }

    public static String deZeroaDezanove(int i){

        String valorFinal;

        switch(i) {
            case 0:
                valorFinal = "zero";
                break;
            case 1:
                valorFinal = "um";
                break;
            case 2:
                valorFinal = "dois";
                break;
            case 3:
                valorFinal = "tr\u00EAs";
                break;
            case 4:
                valorFinal = "quatro";
                break;
            case 5:
                valorFinal = "cinco";
                break;
            case 6:
                valorFinal = "seis";
                break;
            case 7:
                valorFinal = "sete";
                break;
            case 8:
                valorFinal = "oito";
                break;
            case 9:
                valorFinal = "nove";
                break;
            case 10:
                valorFinal = "dez";
                break;
            case 11:
                valorFinal = "onze";
                break;
            case 12:
                valorFinal = "doze";
                break;
            case 13:
                valorFinal = "treze";
                break;
            case 14:
                valorFinal = "catorze";
                break;
            case 15:
                valorFinal = "quinze";
                break;
            case 16:
                valorFinal = "dezasseis";
                break;
            case 17:
                valorFinal = "dezassete";
                break;
            case 18:
                valorFinal = "dezoito";
                break;
            case 19:
                valorFinal = "dezanove";
                break;
            default:
                valorFinal = "BUG eating method deZeroaVinte";
        }
        return valorFinal;
    }

   public static String menorQueCem(int i) {

      String valorFinal;

      if(i%10 == 0) {
         valorFinal = deVinteaNoventaeNove(i);
      }
      else {
         valorFinal = deVinteaNoventaeNove(i - (i%10)) + " e "
               + deZeroaDezanove(i%10);
      }

      return valorFinal;
   }

   public static String deVinteaNoventaeNove(int i) {

      String valorFinal;

      switch(i) {
         case 20:
            valorFinal = "vinte";
            break;
         case 30:
            valorFinal = "trinta";
            break;
         case 40:
            valorFinal = "quarenta";
            break;
         case 50:
            valorFinal = "cinquenta";
            break;
         case 60:
            valorFinal = "sessenta";
            break;
         case 70:
            valorFinal = "setenta";
            break;
         case 80:
            valorFinal = "oitenta";
            break;
         case 90:
            valorFinal = "noventa";
            break;
         case 100:
            valorFinal = "cem";
            break;
         default:
            valorFinal = "A BUG is chewing method deVinteaNoventaeNove";
             }
      return valorFinal;
    }

   public static String menorQueMil(int i) {

      String valorFinal;

      if(i%100 == 0)
         valorFinal = deCemaNoveNoveNove(i);
      else if(i<200)
         valorFinal = "cento e " + triagemInicial(String.valueOf(i%100));
      else
         valorFinal = deCemaNoveNoveNove(i - i%100) + " e " + triagemInicial(String.valueOf(i%100));

      return valorFinal;
    }

   public static String deCemaNoveNoveNove(int i) {

      String valorFinal;

      switch(i) {

         case 200:
            valorFinal = "duzentos";
            break;
         case 300:
            valorFinal = "trezentos";
            break;
         case 400:
            valorFinal = "quatrocentos";
            break;
         case 500:
            valorFinal = "quinhentos";
            break;
         case 600:
            valorFinal = "seiscentos";
            break;
         case 700:
            valorFinal = "setecentos";
            break;
         case 800:
            valorFinal = "oitocentos";
            break;
         case 900:
            valorFinal = "novecentos";
            break;
         case 1000:
            valorFinal = "mil";
            break;
         default:
            valorFinal = "A BUG is chewing method deCemaNoveNoveNove";
      }
      return valorFinal;
    }

   public static String menorQueUmMilhao(int i) {

      String valorFinal ;

      if(i%1000 == 0) {
         valorFinal = triagemInicial(String.valueOf(i/1000)) + " mil" ;
      }
      else if(i%1000 <= 100 || ((i%1000)%100) == 0){
         if(i/1000 == 1 ) {
            valorFinal = "mil e " + triagemInicial(String.valueOf(i%1000));
         }
         else {
            valorFinal = triagemInicial(String.valueOf(i/1000)) + " mil e " + triagemInicial(String.valueOf(i%1000));
         }
      }
      else {
         if(i/1000 == 1 ){
            valorFinal = "mil " + triagemInicial(String.valueOf(i%1000));
         }
         else {
            valorFinal = triagemInicial(String.valueOf(i/1000)) + " mil " + triagemInicial(String.valueOf(i%1000));
         }
      }
      return valorFinal;
    }

    public static boolean levaE(String grandeza) {
        // Método para verificar a necessidade de 
        //  utilização de um "e" logo após a grandeza maior do inteiro.
        // Exs:
        // 1.000.001 = "um milhão e um" (verifica as condições)
        // 1.000.200 = "um milhão e duzentos" (verifica as condições)
        // 1.200.000 = "um milhão e duzentos mil" (verifica as condições)
        // 1.000.101 = "um milhão, cento e um" (NÃO verifica as condições)

        boolean comE = false;
    
        BigInteger grandezaA = new BigInteger(grandeza);
        BigInteger grandezaB = new BigInteger(grandeza);

        int powerVal = 0;
        while( grandezaB.compareTo(BigInteger.valueOf(1_000_000)) >= 0) {
            grandezaB = grandezaB.divide(BigInteger.valueOf(1_000_000));
            powerVal++;
        }

        BigInteger resto = new BigInteger("1");
        BigInteger comparador = new BigInteger("1000000"); // Um milhão
        comparador = comparador.pow(powerVal);
        resto = grandezaA.mod(comparador);

      // Teste Condição 1:  Resto da grandeza a dividir pelo comparador é menor ou igual a 100 (ex input: 1.0000.100)

        if(resto.compareTo(BigInteger.valueOf(100)) <= 0) {
          comE = true;
          return comE;
        }
        else {
          comE = false;
        }

      //  Condição 2
    
        BigInteger resto2 = new BigInteger("1");
        BigInteger comparador2 = new BigInteger("1");
        comparador2 = comparador.divide(BigInteger.valueOf(10));
  
        for( BigInteger z = new BigInteger("100000"),  x = new BigInteger("1000") ;
            z.compareTo(comparador2) <= 0 ; 
            z = z.multiply(BigInteger.valueOf(1_000)), x = x.multiply(BigInteger.valueOf(10)) ) {
       
            resto2 = resto.mod(x);

            if( resto.compareTo(z) <= 0 && resto2.compareTo(BigInteger.valueOf(0)) == 0 ){
                comE = true;
                return comE;
            }
            else {
                comE = false;
            }
        }

      //  Condição 3

        BigInteger resto3 = new BigInteger("1");
       
        for( BigInteger w = new BigInteger("1000"),  y = new BigInteger("100") ;
            w.compareTo(comparador) <= 0 ; 
            w = w.multiply(BigInteger.valueOf(1_000)), y = y.multiply(BigInteger.valueOf(1000)) ) {
    
            resto3 = resto.mod(y);

            if( resto.compareTo(w) <= 0 && resto3.compareTo(BigInteger.valueOf(0)) == 0 ){
                comE = true;
                return comE;
            }
            else {
                comE = false;
            }
        }

      return comE;
    }

    public static String metodoMilinario(String i, String sing, String plur, String grand) {
        
        BigInteger grandeza = new BigInteger(grand);  
        String singular = sing, plural = plur;
       
        String valorFinal;
        BigInteger inputVal = new BigInteger(i);
    
        BigInteger i2 = inputVal.divide(grandeza);
        BigInteger i3 = inputVal.mod(grandeza);

        if(i3.compareTo(BigInteger.valueOf(0)) == 0 ) {
            if(inputVal.compareTo(grandeza) == 0) {
                valorFinal = "um "+ singular;
            }         
            else {
                inputVal = inputVal.divide(grandeza);
                valorFinal = triagemInicial(inputVal.toString()) + " " + plural;
            }
        }
        else if(levaE(i)) {
            if(i2.compareTo(BigInteger.valueOf(1)) == 0) {
                valorFinal = "um " + singular + " e " + triagemInicial(i3.toString());
            }
            else{
                valorFinal = triagemInicial(i2.toString()) + " " + plural + " e " + triagemInicial(i3.toString());
            }
        }
        else {
            if (i2.compareTo(BigInteger.valueOf(1)) ==0 ) {
                valorFinal = "um "+ singular + ", " + triagemInicial(i3.toString());
            }
            else{
                valorFinal = triagemInicial(i2.toString()) + " " + plural + ", " + triagemInicial(i3.toString());
           }
        }
        return valorFinal;
    }
}
Se colarem isto num editor de texto "especializado", ou num IDE próprio para programação (tipo IntelliJ, ou Eclipse), a coisa fica mais legível.
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.

«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death

Câmara Subjectiva
Samwise
DVD Maníaco
DVD Maníaco
Posts: 6267
Joined: February 19th, 2009, 9:07 pm
Contact:

Re: [PROGRAMAÇÃO] - Desafio - O tabuleiro de Xadrez e os bagos de arroz

Post by Samwise »

Encontrei uma página muito boa com informação extensa acerca da notação portuguesa para números:

https://european-portuguese.info/pt/numbers
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.

«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death

Câmara Subjectiva
Samwise
DVD Maníaco
DVD Maníaco
Posts: 6267
Joined: February 19th, 2009, 9:07 pm
Contact:

Re: [PROGRAMAÇÃO] - Desafio - O tabuleiro de Xadrez e os bagos de arroz

Post by Samwise »

Próximas etapas em perspectiva:

- O debugging está a decorrer lentamente, à unha. Vou talvez pensar num modelo para automatizar os testes.

- A fase 4 pensada anteriormente (passagem do código para VBA, de modo a poder ser utilizado no Excel) vai ficar para outras núpcias. Vou no entanto partilhar a última versão em Java anterior à utilização de classe BigInteger, que vai até à grandeza "trilião" exclusive, e que poderá ser adaptada quase directamente para VBA, dada a proximidade semântica das duas linguagens, e dada a estrutura similar dos métodos/funções e dos fluxos de informação.

- Fase 5 - nova optimização de código. Se na optimização anterior estava em causa a própria estrutura do processamento de dados - e esta visou, através de mecanismos de loop, eliminar redundâncias estruturais no código (reunindo as operações principais em métodos distintos, que não necessitam de clones adicionais sempre que a grandeza em causa suba de patamar), o novo processo de optimização visa rotinas mais pequenas, mas que ainda me estão a incomodar um pouco. Não faz sentido, por exemplo, ter de estar a escrever à mão os zeros todos sempre que quero escalar o modelo para uma grandeza acima. Posso programar uma rotina que, através do número inserido para análise, calcule qual é essa grandeza e me devolva já formatada em String. Outra coisa que quero implementar são alternativas aos "do case" e aos "ifs" - sei que há classes específicas para gerar arrays temporários onde a informação pode ser guardada e que talvez possibilitem maior rapidez num processo de "escolha múltipla", para além de menos linhas de código (a investigar...).

- Fase 6 - Optimização de memória. Aqui vou ter de estudar novas matérias, porque não conheço como funciona a gestão de memoria do Java. Sei que há um "Garbage Colector" que se encarrega de limpar automaticamente toda a memória que já não é necessária, mas não sei ao certo como é que as estruturas de dados que utilizei no programa preenchem essa memória. Não sei se vou conseguir fazer alguma coisa, mas quero pelo menos perceber se há espaço para isso. Mesmo que isto seja uma aplicaçãozita da treta, que não reserva espaço nenhum.
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.

«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death

Câmara Subjectiva
Samwise
DVD Maníaco
DVD Maníaco
Posts: 6267
Joined: February 19th, 2009, 9:07 pm
Contact:

Re: [PROGRAMAÇÃO] - Desafio - O tabuleiro de Xadrez e os bagos de arroz

Post by Samwise »

Fases 5 e 6 concluídas. Estou muito próximo de fechar este projecto, sem no entanto pretender desligar-me do assunto, uma vez que ainda tenho planos para seguir com esta "ideia".

Neste momento o código está praticamente fechado e coeso dentro do seu modelo, a optimização chegou a um ponto em que me deixa satisfeito, e a gestão de memória está "razoável" tendo em conta o contexto (aqui poderia investigar um pouco mais a fundo, e ser picuinhas, mas não quero, neste momento, enveredar para aí). A escalabilidade ficou assegurada através do princípio "do menor esforço" ( :-))) ): só tenho a acrescentar 4 ou 5 linhas de código seguidas para cada nova grandeza que pretender acrescentar - muito simples e rápido de fazer.

Todo este código que foi feito "à padeiro" na versão anterior...

Code: Select all

  //... Acrescentar "grandezas" à lista, criar a excepção "else if" a seguir...
            BigInteger bil =     new BigInteger("1000000000000"); //bilião 
            BigInteger tril =    new BigInteger("1000000000000000000");  //trilião 
            BigInteger quatril = new BigInteger("1000000000000000000000000");  //quatrilião  
            BigInteger quintil = new BigInteger("1000000000000000000000000000000");  //quintilião 
            BigInteger seistil = new BigInteger("1000000000000000000000000000000000000");  //seistilião  
            BigInteger setil =   new BigInteger("1000000000000000000000000000000000000000000");  //setilião 
            BigInteger octil =   new BigInteger("1000000000000000000000000000000000000000000000000");  //octilião 
            BigInteger nonil =   new BigInteger("1000000000000000000000000000000000000000000000000000000");  //nonilião 
            BigInteger decil =   new BigInteger("1000000000000000000000000000000000000000000000000000000000000");  //decilião 
            BigInteger undecil = new BigInteger("1000000000000000000000000000000000000000000000000000000000000000000");  //undecilião 

            if(inputVal.compareTo(bil) < 0) { // < 1_000_000_000_000
               
                valorFinal = metodoMilinario( inputVal.toString(), "milh\u00E3o", "milh\u00F5es", "1000000"); 
                
            }
            else if(inputVal.compareTo(tril) < 0) { // < 1_000_000_000_000_000_000
               
                valorFinal = metodoMilinario( inputVal.toString(), "bili\u00E3o", "bili\u00F5es", "1000000000000"); 
            }
            else if(inputVal.compareTo(quatril) < 0) { // < 1_000_000_000_000_000_000_000_000
              
               valorFinal = metodoMilinario( inputVal.toString(), "trili\u00E3o", "trili\u00F5es", "1000000000000000000"); 
            }
            else if(inputVal.compareTo(quintil) < 0) { // < 1_000_000_000_000_000_000_000_000_000_000
                
                valorFinal = metodoMilinario( inputVal.toString(), "quatrili\u00E3o", "quatrili\u00F5es",
                                                                   "1000000000000000000000000"); 
            }
            else if(inputVal.compareTo(seistil) < 0) { // < 1_000_000_000_000_000_000_000_000_000_000_000_000
                
                valorFinal = metodoMilinario( inputVal.toString(), "quintili\u00E3o", "quintili\u00F5es",
                                                                   "1000000000000000000000000000000"); 
            }
            else if(inputVal.compareTo(setil) < 0) { // < 1_000_000_000_000_000_000_000_000_000_000_000_000_000_000
                
                valorFinal = metodoMilinario( inputVal.toString(), "seistili\u00E3o", "seistili\u00F5es", 
                                                                   "1000000000000000000000000000000000000"); 
            }
            else if(inputVal.compareTo(octil) < 0) { // < 1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000
                
                valorFinal = metodoMilinario( inputVal.toString(), "setili\u00E3o", "setili\u00F5es", 
                                                                   "1000000000000000000000000000000000000000000"); 
            }
            else if(inputVal.compareTo(nonil) < 0) { // < 1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000
                
                valorFinal = metodoMilinario( inputVal.toString(), "octili\u00E3o", "octili\u00F5es", 
                                                                   "1000000000000000000000000000000000000000000000000"); 
            }
            else if(inputVal.compareTo(decil) < 0) { // < 1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000
                
                valorFinal = metodoMilinario( inputVal.toString(), "nonili\u00E3o", "nonili\u00F5es", 
                                                                   "1000000000000000000000000000000000000000000000000000000"); 
            }
            else if(inputVal.compareTo(undecil) < 0) { // < 1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000
                
                valorFinal = metodoMilinario( inputVal.toString(), "decili\u00E3o", "decili\u00F5es", 
                                                                   "1000000000000000000000000000000000000000000000000000000000000"); 
            }
            else {
Foi substituido por este, muito mais funcional, fluído, e sem uma carrada de objectos a serem gerados desnecessariamente a cada passagem pelo método:

Code: Select all

  BigInteger milhaoComparador = new BigInteger("1"+"0".repeat(6));
         BigInteger iterador = inputVal;
         int tamanhoGrandeza = 0;
         String extensoGrandeza = "1";

         while( iterador.compareTo(milhaoComparador) >= 0 ) {
            tamanhoGrandeza += 1;
            extensoGrandeza += "0".repeat(6);
            iterador = iterador.divide(milhaoComparador);
         }
         String preExt;

         switch(tamanhoGrandeza){

            case 1:    // < 1_000_000_000_000, menor do que 1 Bilião
               preExt = "milh";
               break;
            case 2:   // < 1_000_000_000_000_000_000, menor do que 1 Trilião
               preExt = "bili";
               break;
            case 3:   // < 1_000_000_000_000_000_000, menor do que 1 Quatrilião
               preExt = "trili";
               break;
            case 4:   // < 1 Quintilião ....
               preExt = "quatrili";
               break;
            case 5:   // < 1 Sextilião
               preExt = "quintili";
               break;
            case 6:   // < 1 Setptilião
               preExt = "sextili";
               break;
            case 7:   // < 1 Octilião
               preExt = "septili";
               break;
            case 8:   // < 1 Nonilião
               preExt = "octili";
               break;
            case 9:   // < 1 Decilião
               preExt = "nonili";
               break;
            case 10:   // < 1 Undecilião
               preExt = "decili";
               break;
            default:
               preExt = "nulo";


Próximas ideias em mente: como o processo de debugging continua a ser uma preocupação importante, e como neste caso não se trata de verificar se há erros técnicos no código (essa parte já está fechada), mas antes de testar se o que está a sair corresponde ao que está a entrar (ou seja, garantir que ao introduzirmos 1250 não obtemos em resposta "mil trezentos e vinte"), estou a pensar numa forma relativamente simples de programar os inputs: através de um ficheiro de Excel, que tem um modelo muito user friendly e flexível de inserir e manipular dados. A ideia é então programar um interface que pegue neste código que já está desenvolvido, e que aceite como input um conjunto de células em determinado ficheiro de Excel, devolvendo depois, para cada célula adjacente, o respectivo extenso. O que equivale a dizer que é um projecto novo e autónomo, mas que depende e aproveita o que está pronto neste.

O primeiro passo é fechar estes métodos numa classe "encapsulada", trancar os métodos ao exterior ("private" em vez de "public"), a garantir um único ponto de acesso para passar argumentos. Com esta classe feita, poderei num outro qualquer projecto instanciar um objecto desta classe, e fazer com ele o que me apetecer (inclusivamente criar uma nova classe que amplie as características desta).

Para já deixo o código que está pronto. Quando tiver a classe concluida (não deve dar trabalho praticamente nenhum, são menos de dez linhas de código, acho), volto a actualizar a informação:

Code: Select all

import java.math.BigInteger;

public class Extenso6 {

   public static void main(String[] args) {

      String inputVal = args[0].trim();

      boolean isNeg = false;
      if( inputVal.startsWith("-")) {
         isNeg = true;
         inputVal = inputVal.substring(1);
      }

      // Caçar caracteres não permitidos:
      char[] diagS = inputVal.toCharArray();

      int contarDigitos = 0;
      for(char algarismo: diagS) {

         if( ! Character.isDigit(algarismo)){
            System.out.println("*** EXITING *** A express\u00E3o cont\u00E9m caracteres n\u00E3o num\u00E9ricos.");
            return;
         }
         contarDigitos++;
      }

      // pseudo-info-stats
      System.out.println();
      BigInteger inteiro = new BigInteger(inputVal);
      String sepMilhares = String.format("%,d", inteiro);
      System.out.println(sepMilhares);
      System.out.println("Express\u00E3o composta por " + contarDigitos + " algarismos.");
      System.out.println();

      // Chamada ao método "nuclear": para triagem da grandeza e seguimento do fluxo
      System.out.println("Extenso: " + ( isNeg ? "menos " : "" ) + triagemInicial(inputVal));
   }

   public static String triagemInicial(String i) {

      String valorFinal;

      BigInteger inputVal = new BigInteger(i);

      if(inputVal.compareTo(BigInteger.valueOf(1_000_000)) < 0) {

         int inputValNum = Integer.parseInt(i);

         if(inputValNum < 20) {

            valorFinal = deZeroaDezanove(inputValNum);
         }
         else if(inputValNum <= 100) {

            valorFinal = menorQueCem(inputValNum);
         }
         else if(inputValNum <= 1000) {

            valorFinal = menorQueMil(inputValNum);
         }
         else {  // <1_000_000

            valorFinal = menorQueUmMilhao(inputValNum);
         }
      }
      else{  // >= 1_000_000

         BigInteger milhaoComparador = new BigInteger("1"+"0".repeat(6));
         BigInteger iterador = inputVal;
         int tamanhoGrandeza = 0;
         String extensoGrandeza = "1";

         while( iterador.compareTo(milhaoComparador) >= 0 ) {
            tamanhoGrandeza += 1;
            extensoGrandeza += "0".repeat(6);
            iterador = iterador.divide(milhaoComparador);
         }
         String preExt;

         switch(tamanhoGrandeza){

            case 1:    // < 1_000_000_000_000, menor do que 1 Bilião
               preExt = "milh";
               break;
            case 2:   // < 1_000_000_000_000_000_000, menor do que 1 Trilião
               preExt = "bili";
               break;
            case 3:   // < 1_000_000_000_000_000_000, menor do que 1 Quatrilião
               preExt = "trili";
               break;
            case 4:   // < 1 Quintilião ....
               preExt = "quatrili";
               break;
            case 5:   // < 1 Sextilião
               preExt = "quintili";
               break;
            case 6:   // < 1 Setptilião
               preExt = "sextili";
               break;
            case 7:   // < 1 Octilião
               preExt = "septili";
               break;
            case 8:   // < 1 Nonilião
               preExt = "octili";
               break;
            case 9:   // < 1 Decilião
               preExt = "nonili";
               break;
            case 10:   // < 1 Undecilião
               preExt = "decili";
               break;
            default:
               preExt = "nulo";
         }

         valorFinal = (preExt != "nulo"
                        ? metodoMilionario( inputVal.toString(), preExt, extensoGrandeza)
                        : "Inteiro demasiado grande - ainda n\u00E3o suportado.");
//
      }
      return valorFinal;

   }

   public static String deZeroaDezanove(int i){

      String valorFinal;

      switch(i) {
         case 0:
            valorFinal = "zero";
            break;
         case 1:
            valorFinal = "um";
            break;
         case 2:
            valorFinal = "dois";
            break;
         case 3:
            valorFinal = "tr\u00EAs";
            break;
         case 4:
            valorFinal = "quatro";
            break;
         case 5:
            valorFinal = "cinco";
            break;
         case 6:
            valorFinal = "seis";
            break;
         case 7:
            valorFinal = "sete";
            break;
         case 8:
            valorFinal = "oito";
            break;
         case 9:
            valorFinal = "nove";
            break;
         case 10:
            valorFinal = "dez";
            break;
         case 11:
            valorFinal = "onze";
            break;
         case 12:
            valorFinal = "doze";
            break;
         case 13:
            valorFinal = "treze";
            break;
         case 14:
            valorFinal = "catorze";
            break;
         case 15:
            valorFinal = "quinze";
            break;
         case 16:
            valorFinal = "dezasseis";
            break;
         case 17:
            valorFinal = "dezassete";
            break;
         case 18:
            valorFinal = "dezoito";
            break;
         case 19:
            valorFinal = "dezanove";
            break;
         default:
            valorFinal = "BUG eating method deZeroaVinte";
      }
      return valorFinal;
   }

   public static String menorQueCem(int i) {

      String valorFinal;

      if(i%10 == 0) {
         valorFinal = deVinteaNoventaeNove(i);
      }
      else {
         valorFinal = deVinteaNoventaeNove(i - (i%10)) + " e "
               + deZeroaDezanove(i%10);
      }

      return valorFinal;
   }

   public static String deVinteaNoventaeNove(int i) {

      String valorFinal;

      switch(i) {
         case 20:
            valorFinal = "vinte";
            break;
         case 30:
            valorFinal = "trinta";
            break;
         case 40:
            valorFinal = "quarenta";
            break;
         case 50:
            valorFinal = "cinquenta";
            break;
         case 60:
            valorFinal = "sessenta";
            break;
         case 70:
            valorFinal = "setenta";
            break;
         case 80:
            valorFinal = "oitenta";
            break;
         case 90:
            valorFinal = "noventa";
            break;
         case 100:
            valorFinal = "cem";
            break;
         default:
            valorFinal = "A BUG is chewing method deVinteaNoventaeNove";
      }
      return valorFinal;
   }

   public static String menorQueMil(int i) {

      String valorFinal;

      if(i%100 == 0)
         valorFinal = deCemaNoveNoveNove(i);
      else if(i<200)
         valorFinal = "cento e " + triagemInicial(String.valueOf(i%100));
      else
         valorFinal = deCemaNoveNoveNove(i - i%100) + " e " + triagemInicial(String.valueOf(i%100));

      return valorFinal;
   }

   public static String deCemaNoveNoveNove(int i) {

      String valorFinal;

      switch(i) {

         case 200:
            valorFinal = "duzentos";
            break;
         case 300:
            valorFinal = "trezentos";
            break;
         case 400:
            valorFinal = "quatrocentos";
            break;
         case 500:
            valorFinal = "quinhentos";
            break;
         case 600:
            valorFinal = "seiscentos";
            break;
         case 700:
            valorFinal = "setecentos";
            break;
         case 800:
            valorFinal = "oitocentos";
            break;
         case 900:
            valorFinal = "novecentos";
            break;
         case 1000:
            valorFinal = "mil";
            break;
         default:
            valorFinal = "A BUG is chewing method deCemaNoveNoveNove";
      }
      return valorFinal;
   }

   public static String menorQueUmMilhao(int i) {

      String valorFinal ;

      if(i%1000 == 0) {
         valorFinal = triagemInicial(String.valueOf(i/1000)) + " mil" ;
      }
      else if(i%1000 <= 100 || ((i%1000)%100) == 0){
         if(i/1000 == 1 ) {
            valorFinal = "mil e " + triagemInicial(String.valueOf(i%1000));
         }
         else {
            valorFinal = triagemInicial(String.valueOf(i/1000)) + " mil e " + triagemInicial(String.valueOf(i%1000));
         }
      }
      else {
         if(i/1000 == 1 ){
            valorFinal = "mil " + triagemInicial(String.valueOf(i%1000));
         }
         else {
            valorFinal = triagemInicial(String.valueOf(i/1000)) + " mil " + triagemInicial(String.valueOf(i%1000));
         }
      }
      return valorFinal;
   }

   public static boolean levaE(String grandeza) {
      // Método para verificar a necessidade de
      //  utilização de um "e" logo após a grandeza maior do inteiro.
      // Exs:
      // 1.000.001 = "um milhão e um" (verifica as condições) - devolve TRUE
      // 1.000.200 = "um milhão e duzentos" (verifica as condições) - devolve TRUE
      // 1.200.000 = "um milhão e duzentos mil" (verifica as condições) - devolve TRUE
      // 1.000.101 = "um milhão, cento e um" (NÃO verifica as condições - logo a seguir a milhão, leva uma vírgula) - devolve FALSE

      boolean comE = false;

      BigInteger grandezaA = new BigInteger(grandeza);
      BigInteger grandezaB = new BigInteger(grandeza);

      int powerVal = 0;
      while( grandezaB.compareTo(BigInteger.valueOf(1_000_000)) >= 0) {
         grandezaB = grandezaB.divide(BigInteger.valueOf(1_000_000));
         powerVal++;
      }

      BigInteger resto = new BigInteger("1");
      BigInteger comparador = new BigInteger("1000000"); // Um milhão
      comparador = comparador.pow(powerVal);
      resto = grandezaA.mod(comparador);

      // Teste Condição 1:  Resto da grandeza a dividir pelo comparador é menor ou igual a 100 (ex input: 1.0000.100)

      if(resto.compareTo(BigInteger.valueOf(100)) <= 0) {
         comE = true;
         return comE;
      }
      else {
         comE = false;
      }

      //  Condição 2

      BigInteger resto2 = new BigInteger("1");
      BigInteger comparador2 = new BigInteger("1");
      comparador2 = comparador.divide(BigInteger.valueOf(10));

      for( BigInteger z = new BigInteger("100000"),  x = new BigInteger("1000") ;
           z.compareTo(comparador2) <= 0 ;
           z = z.multiply(BigInteger.valueOf(1_000)), x = x.multiply(BigInteger.valueOf(10)) ) {

         resto2 = resto.mod(x);

         if( resto.compareTo(z) <= 0 && resto2.compareTo(BigInteger.valueOf(0)) == 0 ){
            comE = true;
            return comE;
         }
         else {
            comE = false;
         }
      }
      //  Condição 3

      BigInteger resto3 = new BigInteger("1");

      for( BigInteger w = new BigInteger("1000"),  y = new BigInteger("100") ;
           w.compareTo(comparador) <= 0 ;
           w = w.multiply(BigInteger.valueOf(1_000)), y = y.multiply(BigInteger.valueOf(1000)) ) {

         resto3 = resto.mod(y);

         if( resto.compareTo(w) <= 0 && resto3.compareTo(BigInteger.valueOf(0)) == 0 ){
            comE = true;
            return comE;
         }
         else {
            comE = false;
         }
      }
      return comE;
   }

   public static String metodoMilionario(String i, String preExt, String grand) {

      BigInteger grandeza = new BigInteger(grand);
      String singular = preExt + "\u00E3o", plural = preExt + "\u00F5es" ;

      String valorFinal;
      BigInteger inputVal = new BigInteger(i);

      BigInteger i2 = inputVal.divide(grandeza);
      BigInteger i3 = inputVal.mod(grandeza);

      if(i3.compareTo(BigInteger.valueOf(0)) == 0 ) {
         if(inputVal.compareTo(grandeza) == 0) {
            valorFinal = "um "+ singular;
         }
         else {
            inputVal = inputVal.divide(grandeza);
            valorFinal = triagemInicial(inputVal.toString()) + " " + plural;
         }
      }
      else if(levaE(i)) {
         if(i2.compareTo(BigInteger.valueOf(1)) == 0) {
            valorFinal = "um " + singular + " e " + triagemInicial(i3.toString());
         }
         else{
            valorFinal = triagemInicial(i2.toString()) + " " + plural + " e " + triagemInicial(i3.toString());
         }
      }
      else {
         if (i2.compareTo(BigInteger.valueOf(1)) ==0 ) {
            valorFinal = "um "+ singular + ", " + triagemInicial(i3.toString());
         }
         else{
            valorFinal = triagemInicial(i2.toString()) + " " + plural + ", " + triagemInicial(i3.toString());
         }
      }
      return valorFinal;
   }
}
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.

«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death

Câmara Subjectiva
Samwise
DVD Maníaco
DVD Maníaco
Posts: 6267
Joined: February 19th, 2009, 9:07 pm
Contact:

Re: [PROGRAMAÇÃO] - Desafio - O tabuleiro de Xadrez e os bagos de arroz

Post by Samwise »

Mais um tempito à volta do projecto, e deu nisto:

Código para ir "pescar" valores a um ficheiro de Excel, e, com os valores obtidos, passá-los pela Classe Extenso, obtendo assim a notação pretendida:

Code: Select all

// Bibliotecas de dependência necessárias : 
// - Apache POI 4.0.1
// - commons collections 4.3
// - xmlbeans 3.0.2
// - commons compress 1.18
// - Classe Extenso5

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import static com.company.Extenso5.extenso;

public class Main {

    public static void main(String[] args) {

      try{

            FileInputStream file = new FileInputStream(new File( "C:\\Temp\\Java\\translate.xlsx"));
            XSSFWorkbook workbook = new XSSFWorkbook(file);
            Sheet sheet = workbook.getSheetAt(0);
            Cell cell;
            Row row;
            int rows = sheet.getPhysicalNumberOfRows();

            // String listaColA[] = new String[rows];

            String getterS, extVal;

            for(int r = 1; r < rows; r++) {
                row = sheet.getRow(r);
                if(row != null) {
                   cell = row.getCell((short)0);
                   if(cell != null) {
                       getterS = String.valueOf(cell.getNumericCellValue());
                       getterS = getterS.substring(0,getterS.indexOf("."));
                       extVal = extenso(getterS);
                       System.out.println(getterS + " - " + extVal);
                   }
                }
            }
        }
        catch (FileNotFoundException naoHaFicheiro){
            System.out.println("No file: " + naoHaFicheiro);
        }
        catch (IOException erroIO){
            System.out.println("IO Error: " + erroIO);
        }
    }
}
O ficheiro de Excel:
Image

O resultado:
Image

Próximo passo, mandar o resultado de volta para o ficheiro de Excel, colocando na segunda coluna cada tradução respectiva.
«The most interesting characters are the ones who lie to themselves.» - Paul Schrader, acerca de Travis Bickle.

«One is starved for Technicolor up there.» - Conductor 71 in A Matter of Life and Death

Câmara Subjectiva
Post Reply