Code Golf: La vague

Le défi

Le code le plus court par caractère compte pour générer une onde à partir de la chaîne d’entrée.

Une onde est générée en élevant (ligne 1) un caractère plus élevé et en dégradant (ligne + 1) un caractère inférieur. Les caractères égaux sont conservés sur la même ligne (pas d’élévation ni de dégradation).

La saisie est faite de caractères minuscules et de chiffres uniquement, les lettres sont considérées comme supérieures aux nombres.

Cas de test:

Input: 1234567890qwertyuiopasdfghjklzxcvbnm Output: z lxvn kcbm j h g ypsf tuoad wri 9 qe 8 0 7 6 5 4 3 2 1 Input: 31415926535897932384626433832795028841971693993751058209749445923078164062862 Output: 9 9 8 6 6 9 6 8 7 3 3 4 2 4 8 9 88 3 4 5 2 5 5 2 33 3 7 5 2 4 9 9 99 7 1 1 3 2 0 1 7 6 3 3 5 8 8 6 1 1 5 2 9 9 3 7 1 4 6 8 0 0 7 9 5 2 0 0 2 6 4 44 2 

Le nombre de codes comprend les entrées / sorties (c.-à-d. Le programme complet).

code machine x86 (37 octets)

Hdddump:

 6800B807BF8007BE8200B40EAC3C0D741338D8740A720481EF400181C7A000AB86C3EBE8C3 

Exécuter dans MS-DOS avec console de 50 lignes, l’entrée est prise à partir de la ligne de commande.

Par exemple

 wave.com 1234567890qwertyuiopasdfghjklzxcvbnm 

Téléchargez le binary ici

Mise à jour: effacé trois octets grâce à jrandomhacker

J

54 caractères, si vous laissez l’interpréteur gérer les entrées / sorties.

 e=:|:@((#&' '@],[)"0[:(-<./)0,[:+/\[:(}:(>-<)}.)ai]) 

65 pour lire explicitement de stdin et écrire sur stdout.

 (|:((#&' '@],[)"0[:(-<./)0,[:+/\[:(}:(>-<)}.)a.&i.)~1!:1[3)1!:2[4 
 e '1234567890qwertyuiopasdfghjklzxcvbnm'
                              z
                             lxvn
                            kcbm
                           j
                          h
                         g
                ypsf
               tuoad
            wri
         9 qe
        8 0
       7
      6
     5
    4
   3
  2
 1
 e '31415926535897932384626433832795028841971693993751058209749445923078164062862'
             9 9 8 6 6
      9 6 8 7 3 3 4 2 4 8 9 88
 3 4 5 2 5 5 2 33 3 7 5 2 4 9 9 99 7
  1 1 3 2 0 1 7 6 3 3 5 8 8 6
                                         1 1 5 2 9 9 3 7 1 4 6 8
                                                   0 0 7 9 5 2 0 0 2 6
                                                          4 44 2


    NB  Recherchez les codes ASCII
 ord =: ai] 
     ord 'p4ssw0rd'
 112 52 115 115 119 48 114 100

    NB  Monter?
 up =:}: <}. 
     up ord 'p4ssw0rd'
 0 1 0 1 0 1 0

    NB  Descente?
 down =:}:>}. 
     vers le bas 'p4ssw0rd'
 1 0 0 0 1 0 1

    NB  Combiner pour obtenir ± 1
 updown =:}: (> - <)}. 
     updown ord 'p4ssw0rd'
 1 _1 0 _1 1 _1 1

    NB  Commence avec 0, suivi avec des sums partielles
 sum =: 0, + / \ 
     sum updown ord 'p4ssw0rd'
 0 1 0 0 _1 0 _1 0

    NB  Soustrayez le minimum pour obtenir la séquence avec la base à 0
 fix =: - <./ 
     sum de sum updown ord 'p4ssw0rd'
 1 2 1 1 0 1 0 1

    NB  Pour plus de commodité, nommez cette chaîne de fonctions
 d =: [: fix [: sum [: updown ord
    NB  Faire des espaces avant les caractères
 push =: (# & '' @], [) "0 d 
     poussez 'p4ssw0rd'
  p
   4
  s
  s
 w
  0
 r
  ré

    NB  Tournez-le sur le côté
 |: poussez 'p4ssw0rd'
     wr
 p ss 0 d
  4

    NB  Combinez en une fonction nommée…
 e =: |: @ push
    NB  … Et tout incorporer
 e =: |: @ ((# & '' @], [) "0 [: (- <./) 0, [: + / \ [: (}: (> - <)}.) ai])

Le code le plus court par caractère compte pour imprimer une «vague» à partir de la chaîne d’entrée.

Console.WriteLine (“une” vague “de la chaîne d’entrée.”);

Perl (94 caractères)

144 caractères à l’origine par Barnaba:

chop($_=<>);$l=length;push(@a," "x$l)for(1..$l*2);$l+=(ord $p<=>ord $_),substr($a[$l],$r++,1)=$p=$_ for(split //);/^\s+$/||print "$_\n" for(@a)

121 personnages de l’optimisation par Chris Lutz:

$_=<>;chop;$a[@a]=" "x$l for 1..($l=length)*2;$l+=$p cmp$_,substr($a[$l],$r++,1)=$p=$_ for split//;/\S/&&print"$_\n"for@a

94 caractères d’optimisation supplémentaire:

$_=<>;@a=($"x($l=y///c).$/)x(2*$l);s/./substr$a[$l+=$"cmp$&],"@-",1,$"=$&/ge;/\S/&&print for@a

Notez que dans le golf Perl traditionnel, on ajoute généralement le nombre de commutateurs et la longueur du code (ce qui aiderait ici par quelques coups), mais ici nous utilisons des programmes autonomes sans commutateur.

C sur un terminal VT100 (76 caractères)

Cela fonctionne dans mon test sur FreeSBIE:

 o;main(c){for(;(c=getchar())-10;o=c)printf("\33[1%c%c",co?65:71,c);} 

Mais pour voir clairement le résultat, vous devez le lancer avec quelque chose comme ceci:

clear ; printf "\n\n\n\n\n" ; echo the quick brown fox jumps over the lazy dog | ./a.out ; printf "\n\n\n\n\n"

Est-ce que ça compte?

Python (161 caractères)

 v,s="",raw_input() m=n=len(s) r=[' ']*n q=[r[:]for i in range(2*n)] for j,i in enumerate(s): m+=(iv) q[m][j],v=i,i for i in q: if i!=r:print''.join(i) 

Je n’ai cependant pas fait grand chose pour le compresser. Portant à quelque chose avec un opérateur de vaisseau spatial maintenant.

Rubis: 99 octets

 r,a,q,i=[],"",99,0 gets.chars{|x|t=r[q+=a<=>x]||="" a=x r[q]+=" "*(it.size)+x i+=1} puts r.compact 

Non compressé:

 r,a,q,i = [],"",99,0 gets.chars { |x| t = r[q+=a<=>x] ||= "" a = x r[q] += " "*(it.size)+x i += 1 } puts r.compact 

PHP (138 caractères)

 $lc;krsort($o);echo join($c,$o); 

Version ‘lisible’ :

  $last_ch; krsort($out); echo join($ch,$out); 

Python 2.x, maintenant réduit à 156 caractères:

 s=raw_input() R=range(len(s)) m=[0] for i in R[1:]:m+=[m[-1]-cmp(s[i],s[i-1])] for x in range(min(m),max(m)+1):print''.join(m[i]==x and s[i]or' 'for i in R) 

Haskell, 215 caractères. Je poste ceci parce que je n’aime pas du tout la version de Khoth. En écrivant dans un style raisonnablement fonctionnel, je me suis retrouvé avec un programme beaucoup plus court et plus lisible par l’OMI. Je n’ai pas vraiment essayé de le faire en dehors des noms de variables et de l’espacement. La mise à jour destructive d’un tableau peut le rendre plus court que la réplication d’espaces.

 import Char import List main=getLine>>=(putStr.p) ps=unlines$transpose[z++(y:x)|(m,y)<-zip ns,let(x,z)=splitAt m$replicate(maximum n)' '] where o=map ord s n=scanl(+)0$map signum$zipWith(-)(tail o)o 

C89 (151 caractères)

 l[999][999];p;v=500;r;main(c){for(;(c=getchar())>0; )l[v+=c>p,v-=c 

C #:

 using System; static class A { static void Main(ssortingng[] a) { var s=a[0];var r=""; int i=1,h=0,d=0,c=0,n=s.Length; var m=new int[n]; m[0]=0; for(;ih)?c:h; d=(c=d;h--) { for (c=0;c 

Pesé à 287 comprimés.

Perl, 85 caractères avec des commutateurs, 96 sans

Invoquer avec -F// -an commutateurs

 $q=$"x($n=@F);$,=$/;for(@F){/ /&&print@O;substr($O[$n+=$*cmp$_]|=$q,$i++,1)=$_;$*=$_} 

Il y a une nouvelle ligne entre le 2ème et le 3ème slash. Sans interrupteurs, vous pouvez faire

 $q=$"x($n=@C=split//,<>);$,=$/;for(@C){/ /&&print@O;substr($O[$n+=$*cmp$_]|=$q,$i++,1)=$_;$*=$_} 

Haskell (285 caractères):

 heightDiff xy | x == y = 0 | x < y = -1 | True = 1 heights h (x:y:z)= (x,h):(heights (h+(heightDiff xy) ) (y:z)) heights h [y] = [(y,h)] makech ((x,h):xs) i = (if i==h then x else ' '):makech xs i makech [] _ = [] printAll xs = mapM_ (putStrLn . (makech xs)) [(minimum $ map snd xs)..(maximum $ map snd xs)] main = getLine >>= (printAll . heights 0) 

Quelques compression (260 caractères):

 axy|x==y=0 |x>= (p . c 0) 

Perl, 88 caractères

Maintenant, édité à 88 caractères:

 $_=<>; s/.(?=(.))/($"x40).$&.$"x(39+($1cmp$&))/ge; @_=/.{80}/g; {say map{chop||die}@_;redo} 

Était:

 $_=<>; s/.(?=(.))/$&.$"x(79+($1cmp$&))/ge; s/^.{40}|.{80}/$&\n/g; print $& while /.$/gm || s/.$//gm * /\n/; 

97 caractères (espaces omis). Ce n’est pas si court, mais je me demande si une personne ayant plus d’expérience avec PERL pourrait être en mesure de la raccourcir davantage. Et aussi repérer les bugs. La deuxième ligne utilise des espaces pour créer une onde qui tombe verticalement plutôt qu’horizontalement, sur un écran enveloppant de 80 largeurs. La troisième ligne insère des sauts de ligne. La dernière ligne fait basculer les axes X / Y.

Je me suis d’abord demandé si les deux dernières lignes pouvaient être quelque chose comme un entrelacement (s /. {80} / g) où l’interligne entrelace un tableau de chaînes. Mais il ne semble pas y avoir cette fonction que j’espérais. (Ou y a-t-il dans une bibliothèque?)

Un premier cri en C #. L’entrée doit être fournie comme premier argument de ligne de commande.

 using System; using C = System.Console; static class P { static void Main(ssortingng[] a) { var b = a[0]; var l = b.Length; int y = 0, z = 0; for (int i = 0; i < l - 1; i++) { y += Math.Sign(b[i] - b[i + 1]); z = Math.Min(y, z); } y = 0; for (int i = 0; i < l - 1; i++) { C.SetCursorPosition(i, y - z); C.Write(b[i]); y += Math.Sign(b[i] - b[i + 1]); } } } 

Cela donne 280 octets compressés à partir de.

using System;using C=System.Console;static class P{static void Main(ssortingng[]a){var b=a[0];var l=b.Length;int y=0,z=0;for(int i=0;i

Tentative numéro deux avec une approche différente.

 using System; using System.Collections.Generic; static class P { static void Main(ssortingng[] a) { var b = a[0] + "$"; var l = new List(); var y = -1; for (int i = 0; i < b.Length - 1; i++) { if ((y == -1) || (y == l.Count)) { y = y < 0 ? 0 : y; l.Insert(y, b.Substring(i, 1).PadLeft(i + 1)); } else { l[y] = l[y].PadRight(i) + b[i]; } y += Math.Sign(b[i] - b[i + 1]); } foreach (var q in l) Console.WriteLine(q); } } 

La boucle peut être réécrite pour utiliser un bloc try / catch.

 for (int i = 0; i < b.Length - 1; i++) { try { l[y] = l[y].PadRight(i) + b[i]; } catch { y = y < 0 ? 0 : y; l.Insert(y, b.Substring(i, 1).PadLeft(i + 1)); } y += Math.Sign(b[i] - b[i + 1]); } 

Cela donne 321 octets légèrement modifiés et compressés - un peu plus que la première tentative, mais beaucoup plus volumineux.

using System;static class P{static void Main(ssortingng[]a){var b=a[0]+"$";var r=new System.Collections.Generic.List();var y=-1;for(int i=0;i

PowerShell

Je suis sûr que cela peut être fait avec beaucoup moins de code, si quelqu’un veut le modifier, ce serait excellent. Je le laisse lisible.

 $v = (Read-Host).ToCharArray() $r = @(0) for($i = 1; $i -lt $v.length; $i++) { $p = $i - 1 $r += $r[$p] + [System.Math]::Sign($v[$i] - $v[$p]) $t = [System.Math]::Max($t, $r[$i]) $b = [System.Math]::Min($b, $r[$i]) } for($i = $t; $i -ge $b; $i--) { for($x = 0; $x -lt $r.length; $x ++) { if($r[$x] -eq $i) { $o += $v[$x] } else { $o += " " } } $o += "`n" } $o 

F #, 242 caractères:

 let F(s:ssortingng)=(fun L->let a=Array.init(L*3)(fun _->Array.create L ' ')in Seq.fold(fun(r,p,c)n->let r=r+sign(int p-int n)in a.[r].[c]<-n;r,n,c+1)(L,s.[0],0)s;for r in a do if Array.exists((<>)' ')r then printfn"%s"(new ssortingng(r)))s.Length 

Avec les espaces ajoutés pour faciliter la lecture,

 let F(s:ssortingng) = (fun L-> let a = Array.init (L*3) (fun _ -> Array.create L ' ') in Seq.fold (fun (r,p,c) n -> let r = r + sign(int p-int n) in a.[r].[c]<-n; r, n, c+1) (L, s.[0], 0) s; for r in a do if Array.exists ((<>) ' ') r then printfn "%s" (new ssortingng(r)) ) s.Length 

C (157 caractères)

Je suis coincé là pour le moment. Je ne pense pas que C battra J sur celui-ci. Merci à strager pour aider à couper 8 caractères, cependant.

 char*p,a[999][80];w,x,y=500;main(c){for(gets(memset(p=*a,32,79920));*p; a[y][x++]=c=*p++)y+=*pc;for(;++w<998;strspn(p," ")-79&&puts(p)) 79[p=a[w]]=0;} 

Formaté:

 char *p, /* pointer to current character (1st) or line (2nd) */ a[999][80]; /* up to 998 lines of up to 79 characters */ w, x, y = 500; /* three int variables. y initialized to middle of array */ main(c){ for(gets(memset(p=*a, 32, 79920)); /* 999 * 80 = 79920, so the entire array is filled with space characters. * memset() returns the value of its first parameter, so the above is * a shortcut for: * * p = *a; * memset(p, 32, 79920); * gets(p); * * Incidentally, this is why I say "up to 998 lines", since the first * row in the array is used for the input ssortingng. * * **** WARNING: Input ssortingng must not be more than 79 characters! **** */ *p;a[y][x++] = c = *p++) /* read from input ssortingng until end; * put this char in line buffer and in prev */ y += *p < c, /* if this char < prev char, y++ */ y -= *p > c; /* the use of commas saves from using { } */ for(;++w < 998; /* will iterate from 1 to 998 */ strspn(p, " ") - 79 && /* strspn returns the index of the first char in its first parameter * that's NOT in its second parameter, so this gets the first non- * space character in the string. If this is the NULL at the end of * the string (index 79), then we won't print this line (since it's blank). */ puts(p)) /* write the line out to the screen (followed by '\n') */ 79[p = a[w]] = 0; /* same as "(p = a[y])[79] = 0", * or "p = a[y], p[79] = 0", but shorter. * Puts terminating null at the end of each line */ } 

Je n'ai pas pris la peine de supporter une entrée de plus de 79 caractères, car cela causerait une confusion sur la plupart des terminaux.

Une solution Java, pas particulièrement compressée (maintenant modifiée pour lire à partir de stdin).

 public class W { public static void main(Ssortingng[] x) { Ssortingng s = new java.util.Scanner(System.in).nextLine(); int i,j; int t = s.length(); char[] b = s.toCharArray(); char[][] p = new char[2*t][t]; int q = t; char v = b[0]; for (i=0; i<2*t; i++) { for (j=0; j v ? -1 : 1); q += d; p[q][i] = c; v = c; } for (i=0; i<2*t; i++) { String n = new String(p[i]); if (!n.equals(z)) { System.out.println(n); } } } } 

C # (564 caractères de code)

 using System; class Program { static void Main(ssortingng[] args) { var input = args[0]; int min = 0, max = 0; var heights = new int[input.Length]; for (var i = 1; i < input.Length; i++) { heights[i] = heights[i-1] + (input[i] > input[i-1] ? 1 : (input[i] < input[i-1] ? -1 : 0)); min = Math.Min(min, heights[i]); max = Math.Max(max, heights[i]); } for (var row = max; row >= min; row--, Console.WriteLine()) for (var col = 0; col < input.Length; col++) Console.Write(heights[col] == row ? input[col] : ' '); } } 

Compacté: (324 caractères de code)

 using System;class A{static void Main(ssortingng[] args){var I=args[0];int M=0,X=0;var H=new int[I.Length];for(var i=1;iI[i-1]?1:(I[i]=M;r--,Console.WriteLine())for(var c=0;c 

Utiliser les astuces des commentaires (283 caractères):

 using System;class A{static void Main(ssortingng[] a){var I=a[0];int M=0,X=0,i=1,r,h,c=0,l=I.Length;var H=new int[l];for(;iI[i-1]?1:(I[i]h?X:h;}for(r=X;r>=M;r--,Console.Write('\n'))for(;c 

Perl 5.10

159 caractères, la version la plus “conviviale”:

 perl -nE'chop;@l=split//;$l{$_}=$l{$_-1}+($l[$_]cmp$l[$_-1])for 0..$#l;%e=();for$x(sort{$b<=>$a}grep{!$e{$_}++}values%l){say map{$l{$_}==$x?$l[$_]:" "}0..$#l}' 

La version suivante est 153 caractères, mais vous ne pouvez entrer qu’une seule ligne. Pour en entrer plus d’un, vous devez redémarrer le programme. Les règles ne sont pas claires quant à savoir si cela est autorisé ou non, mais j’ai pensé qu’il serait préférable de publier les deux versions quand même:

 perl -nE'chop;@l=split//;$l{$_}=$l{$_-1}+($l[$_]cmp$l[$_-1])for 0..$#l;for$x(sort{$b<=>$a}grep{!$e{$_}++}values%l){say map{$l{$_}==$x?$l[$_]:" "}0..$#l}' 

Et voici une version de 149 caractères – celle-ci est un script plutôt qu’un shell simple, et fonctionne également pour une seule ligne d’entrée, mais ne continue pas à accepter les entrées après cette première ligne, ce qui est probablement une bonne chose :

 $_=<>;chop;@l=split//;$l{$_}=$l{$_-1}+($l[$_]cmp$l[$_-1])for 0..$#l;for$x(sort{$b<=>$a}grep{!$e{$_}++}values%l){say map{$l{$_}==$x?$l[$_]:" "}0..$#l} 

Aucun d’entre eux n’est aussi court que la solution Perl déjà publiée, mais ils semblent certainement battre Python et Ruby. Et d’ailleurs, il y a plus d’une façon de le faire.

F #, 235 caractères

Une stratégie complètement différente a permis d’économiser quelques caractères par rapport à l’autre solution.

 let F(s:ssortingng)=(fun L->let _,_,h=Seq.fold(fun(p,h,l)n->let r=h-sign(int n-int p)in n,r,r::l)(s.[0],0,[0])s in for r in Seq.min h..Seq.max h do printfn"%s"(new ssortingng(Array.init L (fun c->if r=h.[L-1-c]then s.[c]else ' '))))s.Length 

Avec des espaces:

 let F(s:ssortingng) = (fun L-> let _,_,h = Seq.fold (fun (p,h,l) n -> let r = h - sign(int n-int p) in n,r,r::l) (s.[0],0,[0]) s in for r in Seq.min h..Seq.max h do printfn "%s" (new ssortingng(Array.init L (fun c -> if r=h.[L-1-c] then s.[c] else ' '))) ) s.Length 

C # 545 octet non compressé

 using System; using System.Linq; class Program{ static void Main(ssortingng[] b){ var s = b[0]; var t = new System.Collections.Generic.Dictionary(); int y=0, p=0; for (int i = 0; i < s.Length; i++){ y += Math.Sign(s[i] - p); p = s[i]; if (!t.ContainsKey(y)) t.Add(y, ""); t[y] = t[y].PadRight(i) + s[i]; } foreach (var v in t.OrderBy(a => -a.Key)) Console.WriteLine(v.Value); } } 

Ruby: 109 octets, en comptant les caractères de nouvelle ligne!

 s=gets r,a,q,i=[],s[0,1],99,0 s.chars{|x|q+=a<=>x a=x t=r[q]||="" r[q]+=" "*(it.size)+x i+=1} puts r.compact 

Non compressé:

 s = gets r,a,q,i = [],s[0,1],99,0 s.chars { |x| q += a<=>x a = x t = r[q] ||= "" r[q] += " "*(it.size)+x i += 1 } puts r.compact 

Groovy (195 caractères)

tester

 s="1234567890qwertyuiopasdfghjklzxcvbnm" 

court

 =(s=~/./).collect{(char)it} e=' ';x=0;l=[];u=[] w.eachWithIndex({it,n-> if(l.size()>x){l[x]+=e*(nu[x]-1)+it;u[x]=n}else{l+=e*n+it;u+=n} if(w[n+1]>it)x++else x--;}) l.reverse().each({println it}) 

PHP: 108 caractères

 $b);$r[$d].=' ';$r[$d][$k++]=$b=$a;}ksort($r);echo join("\n",$r); 

Version lisible:

 $b); $r[$d].=' '; $r[$d][$k++]=$b=$a; } ksort($r); echo join("\n",$r); 

Golfscript – 65 caractères

 ' ': :c;1/:a,.+,{:N;a,a{:@c<+c@:c<-.N=[ c]\=}%.[n+'']\$-1= ==\;}% 

Générer l'onde ligne par ligne

 {:N;a,a{:@c<+c@:c<-.N=[ c]\=}% 

Filtrer les lignes vides

 .[n+'']\$-1= ==\ 

ASL: 73

 args1[,;{ch},1_]@1]o o>:><-0 0a:/+,/&-;{()@:'{" "`}}@;{};;{(){`}#`}" ":|P 

Je viens de traduire la solution J en ASL.

XQuery

(257 octets)

 declare variable$i external;let$c:=ssortingng-to-codepoints($i),$h:= for$x at$p in$c return sum(for$x in 1 to$p let$d:=$c[$x]-$c[$x -1]return(-1[$d>0],1[$d<0]))return codepoints-to-string(for$p in min($h)to max($h),$x at$q in($c,10)return(32[$h[$q]!=$p],$x)[1]) 

Puisque XQuery est purement déclaratif, j'ai dû simuler l'entrée comme étant passée dans une variable externe. Voici la ligne de commande pour l'exécuter avec XQSharp:

 xquery wave.xq !method=text i='1234567890qwertyuiopasdfghjklzxcvbnm' 

Si la chaîne a été transmise en tant qu'élément de contexte, cela peut être réduit davantage, mais la définition de l'élément de contexte sur une valeur autre qu'un nœud n'est pas prise en charge avec toutes les implémentations XQuery (et non par l'outil de ligne de commande XQSharp):

 let$c:=ssortingng-to-codepoints(.),$h:= for$x at$p in$c return sum(for$x in 1 to$p let$d:=$c[$x]-$c[$x -1]return(-1[$d>0],1[$d<0]))return codepoints-to-string(for$p in min($h)to max($h),$x at$q in($c,10)return(32[$h[$q]!=$p],$x)[1]) 

Juste 228 octets.