| [ index | links | mail ] |
::perl |
TPR03/1 - CantorOvvero: Di come valga piu' la pratica della grammatica
Mettiamola cosi': se non altro posso essere soddisfatto perche' la soluzione che avevo "pensato" sfrutta lo stesso approccio del vincitore (che e' lo stesso per la maggior parte delle soluzioni). Magra consolazione, in effetti, visto che per l'approccio in questione mi ero ispirato a ("l'avevo scopiazzato da") Mathworld... Come mi aspetto abbiano fatto anche gli altri. Quindi la reazione, guardando le soluzioni, non e' stata un "Questa e' magia nera!", come di solito mi accade, ma un per certi versi piu' amaro "Toh! Bastava pensarci!". Riporto la mia soluzione, per far vedere come, dopo sapiente maquillage, essa possa diventare qualcosa di dignitoso, addirittura competitivo.
# 1 2 3 4 5 6 7
#2345678901234567890123456789012345678901234567890123456789012345678901234
%r=('-','- -',$",$"x3);$_="-$/";$n=shift;while($n--){s/(.)/$r{$1}/eg}print
Magari la riscrivo in forma meno stringata:
%r = (
'-' => '- -',
$" => $"x3
);
$_="-$/";
$n=shift;
while( $n-- ) {
s/(.)/$r{$1}/eg
}
print
Chiaro, no? Viene applicata $n volte, attraverso l'espressione regolare, la regola di riscrittura definita nella hash %r. Di trucchi in pratica non ce ne sono, a parte l'uso di variabili predefinite al posto di spazi e newline. In effetti si potrebbero mangiar via un altro paio di caratteri, considerando che l'input e' garantito essere costituito da un solo parametro e che quindi uno shift vale quanto un pop. Diciamo quindi che scendiamo da 74 a 72 caratteri. Ma l'idea che permette di ridurre drasticamente il numero di caratteri e' un'altra. Attenzione alla regola di riscrittura (che riporto scritta "in chiaro"): %r = ( '-' => '- -', ' ' => ' ' ); Devo ammettere che ho passato diversi minuti fissando questa hash, cercando metodi per riscriverla in maniera piu' stringata. Pero', nada. Qui si vede la prima zampata dei primi classificati.
La buona idea a proposito di questa hash e' che... non c'e per niente
bisogno di una hash. Uno spazio va riscritto come due spazio con uno spazio in mezzo. Un * va riscritto come due * con uno spazio in mezzo. Ma questa e' un'istruzione s/// scritta in italiano: in Perl si dice s/./$& $&/ Senza nessun bisogno di tabelle di riscrittura. Non vale dire che lo avevate notato subito; se non altro, e' indelicato nei miei confronti. Riscrivo ancora la soluzione:
# 1 2 3 4
#23456789012345678901234567890123456789012345
$_="-$/";$n=pop;while($n--){s/./$& $&/g}print
Da 72 a 45 caratteri. -27, direi che non c'e' male. Magia nera
"Un colpo di genio, J.F, o una cattiva digestione?"
Da qui alla soluzione del vincitore, pero', ce ne corre. Ecco il programma di Rick Klement, Mtv Europe, Marko Nippula, Eirik Ben Hanssen e MeowChow (che condividono a parimerito la prima posizione in classifica): s/./$& $&/gfor($\="- ")x pop;printE qui c'e' proprio della magia nera, non c'e' niente da fare. Credo che si capisca tutto a parte lo strano costrutto Partiamo dall'operatore x: in un contesto di lista, se l'operando di sinistra e' una lista allora restituisce la lista ripetuta tante volte quante sono indicate dall'operando di destra. Per chiarezza, riscrivo il costrutto esplicitando le parentesi: Ma cosa e' l'operando di sinistra? E' $\ dopo che l'assegnazione e' avvenuta. Se ad esempio il parametro passato fosse 3, il codice eseguito sarebbe equivalente a questo:
$\ = "-\n";
for( $\, $\, $\ ) {
s/./$& $&/g;
}
print
Il resto e' chiaro. Ad ogni iterazione (tante quante gli elementi della lista) $_ diventa un alias di $\, e l'espressione regolare fa il resto, come ho spiegato sopra. Riferimenti
|
Last modified: 09:05:37 09-May-2002 / Maintained by larsen