language agnostic - Código Golf: Conectando los puntos.
language-agnostic code-golf (16)
C #, 422 caracteres
758 754 641 627 584 546 532 486 457 454 443 440 422 caracteres (la próxima vez quizás no lo envíe tan pronto).
using A=System.Console;class B{static int C,o,d,e,G,O=1,f,F,u,n;static
void Main(){var s=A.In.ReadToEnd();A.Clear();while(++u<s.Length){f++;if
(s[u]<32){u++;F++;f= 0;}if(s[u]>32){if(int.Parse(s[u]+""+s[++u])==O){o=
e>f?1:f>e?-1:0;C=d>F?1:F>d?-1:0 ;G=e+o;n=d+C;if(O++>1)while(n!=F||G!=f)
{A.SetCursorPosition(G-=o,n-=C);A.Write( "+/-|//"[n==d&&G==e?0:n==F&&G
==f?0:C+o==0?1:C==0?2:o==0?3:4]);}e=f;d=F;F=0;f=u=-1 ;}f++;}}A.Read();}}
Uso: ejecute, pegue (o escriba) la entrada, asegúrese de que la última línea termina, presione CTRL-Z o F6, presione Entrar.
Versión formateada pero básicamente ininteligible:
using A = System.Console;
class B
{
// code golf fun!
static int C, o, d, e, G, O = 1, f, F, u, n;
static void Main()
{
// read the input into a string char by char until EOF
var s = A.In.ReadToEnd();
A.Clear(); // clear console, ready to draw picture
// O is the "dot" number we''re looking for
// f is current column
// F is current row
// loop over the field looking for numbers sequentially
// until no more are found
while (++u < s.Length)
{
f++;
// any char <32 is expected to be a CR/LF
// increment the current row and reset the current column
if (s[u] < 32)
{
u++; // skip the other half of the CR/LF pair
F++; // next row
f = 0; // column reset
}
// any char >32 is expected to be a number
if (s[u] > 32)
{
// parse the current + next char and see if it''s
// the number we want
if (int.Parse(s[u] + "" + s[++u]) == O)
{
// set up coordinates, compare X1 with X2
// and Y1 with Y2 to figure out line direction
// horizontal direction (same as o=e.CompareTo(f))
o = e > f ? 1 : f > e ? - 1 : 0;
// vertical direction (same as C=d.CompareTo(F))
C = d > F ? 1 : F > d ? - 1 : 0;
// initial offsets compensate for off-by-one
G = e + o;
n = d + C;
// draw the line (except for the very first dot)
if (O++ > 1)
while (n != F || G != f)
{
// update coords and write desired char
A.SetCursorPosition(G -= o, n -= C);
// this lovely line decides which char to
// print, and prints it
A.Write(
"+/-|//"[n == d && G == e ? 0 : n == F && G
== f ? 0 : C + o == 0 ? 1 : C == 0 ? 2 : o
== 0 ? 3 : 4]);
}
// remember end point of this line, to use as start point
// of next line
e = f;
d = F;
// reset current row (F), column (f), field position (u)
F = 0;
f = u = -1;
}
// bump current column because we parse 2 chars when we
// find a dot
f++;
}
}
A.Read(); // prevent command prompt from overwriting picture
}
}
Puede recordar estos dibujos de cuando era un niño, pero ahora es el momento de dejar que la computadora los dibuje (en pleno esplendor ascii). ¡Que te diviertas!
Descripción:
Las entradas son múltiples líneas (terminadas por una nueva línea) que describen un "campo". Hay "números" dispersos en este campo (separados por espacios en blanco). Se puede considerar que todas las líneas tienen la misma longitud (puede rellenar espacios hasta el final).
- los números siempre comienzan en 1
- siguen el orden de los números naturales: cada ''número siguiente'' se incrementa con 1
- cada número está rodeado por (al menos) un espacio en blanco a su izquierda y derecha
Tarea:
Dibuje líneas entre estos números en su orden natural (1 -> 2 -> 3 -> ...N)
(suponga N <= 99) con las siguientes características:
- reemplazar un número con un carácter ''
+
'' - para líneas horizontales: use ''
-
'' - para líneas verticales: use ''
|
'' - Ir a la izquierda y abajo o derecha y arriba:
/
- yendo a la izquierda y arriba o derecha y abajo:
/
Notas importantes:
Al dibujar líneas de tipo 4 y 5, puede asumir (dados los puntos para conectar con las coordenadas x1, y1 y x2, y2) esa
distance(x1,x2) == distance(y1,y2)
. O en otras palabras (como comentó el usuario jball): "los elementos consecutivos que no están alineados horizontal o verticalmente siempre se alinean con la pendiente de la barra o barra invertida".Es importante seguir el orden en que se conectan los puntos (las líneas más recientes pueden tachar las líneas más antiguas).
- Entrada de muestra 1 -
8 7 6 10 9 5 3 4 11 12 13 1 2
- Salida de muestra 1 -
+ /| / +--+ +--------+ / / / / + / | / +--+ + | / | +------------------------+ +--------------------------+
- Entrada de muestra 2 -
64 63 62 61 1 65 66 57 58 2 56 59 45 67 55 46 3 44 54 60 47 53 52 49 48 4 51 50 43 5 42 41 6 23 22 25 26 40 20 21 24 34 7 13 12 33 19 27 32 14 35 8 15 16 39 17 18 28 31 36 9 38 10 11 29 30 37
- Salida de muestra 2 - ( referencia unicornio )
+ /+ // // // /+--+ + + / | + +-/+ + / + / + / + + / +/ + / / | + | + + +/ | +--+ +-------+/ + +--+ + / / + + | + + + / / +/ +---+ + / +--+ + / /+ + +--+ / / /+| / | |+ + /+ | / + || / // + + + || / // / / + || / // / / | || / +/ / / +---+ + +/ + + | | | +| +--+ +---+ +
Ganador:
Solución más corta (por número de caracteres de código). La entrada se puede leer a través de la entrada estándar.
F #, 725 caracteres
open System
let mutable h,s,l=0,Set.empty,Console.ReadLine()
while l<>null do
l.Split([|'' ''|],StringSplitOptions.RemoveEmptyEntries)
|>Seq.iter(fun t->s<-s.Add(int t,h,(" "+l+" ").IndexOf(" "+t+" ")))
h<-h+1;l<-Console.ReadLine()
let w=Seq.map(fun(k,h,x)->x)s|>Seq.max
let o=Array2D.create h (w+1)'' ''
Seq.sort s|>Seq.pairwise|>Seq.iter(fun((_,b,a),(_,y,x))->
let a,b,x,y=if b>y then x,y,a,b else a,b,x,y
o.[b,a]<-''+''
o.[y,x]<-''+''
if b=y then for x in(min a x)+1..(max a x)-1 do o.[y,x]<-''-''
elif a=x then for h in b+1..y-1 do o.[h,x]<-''|''
elif a<x then for i in 1..y-b-1 do o.[b+i,a+i]<-''//'
else for i in 1..y-b-1 do o.[b+i,a-i]<-''/'')
for h in 0..h-1 do
for x in 0..w do printf"%c"o.[h,x]
printfn""
Leyenda:
h = height
s = set
l = curLine
w = (one less than) width
o = output array of chars
Líneas 1-6: mantengo un conjunto de tuplas (number, lineNum, xCoord); A medida que leo en cada línea de entrada, encuentro todos los números y los agrego al conjunto.
Línea 7-8: luego creo una matriz de caracteres de salida, inicializada en todos los espacios.
Línea 9: Ordene el conjunto (por ''número''), luego tome cada par adyacente y ...
Líneas 10-16: ... ordenar así que (a, b) es el ''más alto'' de los dos puntos y (x, y) es el otro. Coloque los signos ''+'' y luego, si es horizontal, dibuje eso; de lo contrario, si es vertical, dibuje eso, o dibuje la diagonal correcta. Si la entrada no es "válida", entonces quién sabe qué pasa (este código estaba lleno de "afirmaciones" antes de que yo hiciera el golf).
Líneas 17-19: Imprime el resultado.
AWK - 296 317 321 324 334 340
Aún no ha ganado un premio, pero estoy satisfecho con el esfuerzo (saltos de línea para mostrar). Esta nueva versión utiliza secuencias de escape VT-100. El ''^ ['' es solo un personaje, Escape !!! Cortar y pegar no funcionará con esta versión, ya que la secuencia "^ [" debe reemplazarse con el carácter ESC real. Para que sea amigable con el foro, ESC podría especificarse como "/ 0x1b", pero ocupa demasiado espacio ...
BEGIN{FS="[ ]"}{for(j=i=0;i<NF;j+=length(g)){if(g=$++i){x[g]=k=i+j;y[g]=NR;
m=m>k?m:k}}}END{printf"^[[2J[%d;%dH+",Y=y[i=1],X=x[1];while(a=x[++i])
{a-=X;b=y[i]-Y;t=a?b?a*b>0?92:47:45:124;A=a?a>0?1:-1:0;B=b?b>0?1:-1:0;
for(r=a?a*A:b*B;--r;){printf"^[[%d;%dH%c",Y+=B,X+=A,t}
printf"^[[%d;%dH+",Y+=B,X+=A}}
La versión estándar más antigua.
BEGIN{FS="[ ]"}{for(j=i=0;i<NF;j+=length(g)){if(g=$++i){x[g]=k=i+j;y[g]=NR;
m=m>k?m:k}}}END{q[X=x[1],Y=y[i=1]]=43;while(a=x[++i]){a-=X;b=y[i]-Y;
t=a?b?a*b>0?92:47:45:124;A=a?a>0?1:-1:0;B=b?b>0?1:-1:0;for(r=a?a*A:b*B;--r;
q[X+=A,Y+=B]=t);q[X+=A,Y+=B]=43}for(j=0;++j<NR;){for(i=0;i<m;){t=q[i++,j];
printf"%c",t?t:32}print}}
Ahora una pequeña explicación.
# This will break the input in fields separated by exactly 1 space,
# i.e. the fields will be null or a number.
BEGIN{FS="[ ]"}
# For each line we loop over all fields, if the field is not null
# it is a number, hence store it.
# Also account for the fact the numbers use space.
# Also, find the maximum width of the line.
{
for(j=i=0;i<NF;j+=length(g)){
if(g=$++i){
k=j+i;x[g]=k;y[g]=NR;m=m>k?m:k
}
}
}
# Once we have all the data, let start cooking.
END{
# First, create a matrix with the drawing.
# first point is a +
q[X=x[1],Y=y[i=1]]=43;
# loop over all points
while(a=x[++i]){
# Check next point and select character
# If a == 0 -> -
# If b == 0 -> |
# If a and b have same sign -> / else /
a-=X;b=y[i]-Y;t=a?b?a*b>0?92:47:45:124;
# there is no sgn() function
A=a?a>0?1:-1:0;B=b?b>0?1:-1:0;
# Draw the line between the points
for(k=0;++k<(a?a*A:b*B);){
q[X+=A,Y+=B]=t
}
# store + and move to next point
q[X+=A,Y+=B]=43
}
# Now output all lines. If value in point x,y is 0, emit space
for(j=0;++j<NR;){
for(i=0;i<m;){
t=q[i++,j];printf("%c",t?t:32)
}
print
}
}
Commodore 64 BASIC - 313 caracteres
EDITAR: ver más abajo para la versión de golf
Un pequeño viaje por el camino de la memoria con gráficos PET , POKE s y PEEK s y todo :)
El programa opera directamente en la memoria de la pantalla, por lo que solo sigue adelante, borra la pantalla, coloca tus puntos y escribe RUN :
Tienes que esperar aproximadamente un minuto mientras encuentra los puntos y luego comienza a dibujar. No es rápido, puedes ver las líneas dibujadas, pero esa es la parte más genial :)
Versión de golf:
Commodore BASIC parece ser un excelente lenguaje para jugar al golf, ya que no requiere espacios en blanco :) También puede acortar la mayoría de los comandos ingresando una primera letra sin cambios seguida de una segunda letra desplazada. Por ejemplo, POKE
se puede escribir como P [MAYÚS + O], que aparece como P┌
en la pantalla:
Haskell, 424 caracteres
Recuento de caracteres actual: 424 430 451 466 511 515 516 518 525 532 541 545 550 556 569 571 577 582 586 592 .
import List
x%c=[(i,c)|i<-x]
l k p q|p>q=l k q p|True=head[[p,p+j..q]%c|m<-zip[k-1,k,k+1,1]"/|//-",let (j,c)=m,mod(q-p)j==0]
w=map snd
q(k,m,x)z=w$sort$nubBy((==)&fst)$x%''+''++(concat$zipWith(l k)x$tail x)++z%''/n''++[1..m]%'' ''
r(z,m,x)=q(last z,m-1,w$sort x)z
u[(m,_)]n x=(-m::Int,n):x;u _ _ x=x
t(z,n,x)s|s=="/n"=(n:z,n+1,x)|True=(z,n+length s,u(reads s)n x)
y&x=(.x).y.x
main=interact$r.foldl t([],1,[]).groupBy((&&)&(>'' ''))
Esta versión se inspira mucho en la entrada original de Haskell a continuación, pero hace algunos cambios significativos. Lo más importante es que representa ubicaciones de imágenes con un solo índice, no un par de coordenadas.
Hay algunos cambios:
- La entrada ahora debe tener todas las líneas rellenadas a la misma longitud (permitido por las reglas).
- Ya no necesita ninguna extensión de idioma
Versión original:
(Necesita -XTupleSections
, y tal vez -XNoMonomorphismRestriction
)
import List
b=length
f=map
g=reverse
a(x,y)" "=(x,y+1)
a(x,y)z=([y,read z]:x,y+b z)
x%y=[min x y+1..max x y-1]
j([x,y],[w,z])|y==z=f(,''-'')$f(y,)$x%w|x==w=f(,''|'')$f(,x)$y%z|(y<z)==(x<w)=f(,''//')$zip(y%z)$x%w|True=f(,''/'')$zip(y%z)$g$x%w
k 0=''/n''
k _='' ''
y&x=(.x).y.x
y?x=f y.sort.x.concat
r z=snd?(nubBy((==)&fst).g)$[((y,x),k x)|x<-[0..maximum$f b d],y<-[1..b d]]:[((y,x),''+'')|[x,y]<-e]:(f j$zip e$tail e)where d=f(groupBy$(&&)&(>'' ''))$lines z;e=tail?f g$zipWith(f.(:))[1..]$f(fst.foldl a([],1))d
main=interact r
Explicación:
(1) d=...
: divide la entrada en espacios y números, por ejemplo,
z = " 6 5/n/n1 2/n/n 4 3/n/n 7"
=> d = [[" ","6"," "," ","5"],[],["1"," "," "," "," "," "," "," ","2"],[],[" "," "," "," ","4"," "," "," ","3"],[],[" ","7"]]
(2) e=...
: convierte d
en una lista de coordenadas (y, x) para cada número.
e = [[1,3],[9,3],[9,5],[5,5],[5,1],[2,1],[2,7]]
--- // 1 2 3 4 5 6 7
(3)
-
[((y,x),kx)|...]
es un tablero vacío. (k
devuelve un espacio o un/n
dependiendo de la coordenada x). -
[((y,x),''+''))|...]
son los signos más en los números. -
(fj$zip e$tail e)
son las líneas que conectan los números. (j
asigna un par de coordenadas en una lista de (coordenada, carácter) que representa una línea).
Estos 3 componentes se concatenan y filtran para formar la salida real. Tenga en cuenta que el orden es importante, por lo que nubBy(...).g
solo puede mantener el último carácter en la misma ubicación.
Perl, 222 char (211)
Perl, 384 365 276 273 253 225 222 218 211 caracteres (222 cuando finalizó el concurso). Las nuevas líneas son solo para "legibilidad" y no están incluidas en el recuento de caracteres.
Última edición: ya no se sobrescribe $"
, y se imprime @S
directamente
$_=join'''',@S=map{$n=s/$/$"x97/e;(/./g)[0..95],$/}<>;
while(//b$n /){$S[$q=$-[0]]=''+'';($P,$Q)=sort{$a-$b}$q,$p||$q;
for(qw''/98 |97 /96 -1''){//D/;$S[$P]=$&until($Q-$P)%$''||$Q<=($P+=$'')}
$n++;$p=$q}s//d/ /,print for@S
Explicación:
$_=join'''',@S=map{$n=s/$/$"x97/e;(/./g)[0..95],$/}<>;
Esta tarea será más fácil si todas las líneas tienen la misma longitud (por ejemplo, 97 caracteres). Esta declaración toma cada línea de entrada, reemplaza el carácter de fin de línea con 96 espacios, luego inserta los primeros 96 caracteres más una nueva línea en la matriz @S
. Tenga en cuenta que también estamos configurando $n=1
, ya que 1 es el primer número que buscaremos en la entrada. La instrucción de join
crea una única cadena de la matriz @S
. Es más conveniente usar la variable escalar $_
para la coincidencia de patrones, y más conveniente usar la matriz @S
para hacer actualizaciones a la imagen.
while(//b$n /){
Busque el número $n
en la variable $_
. La evaluación de expresiones regulares en Perl tiene varios efectos secundarios. Una es establecer la variable especial $-[0]
con la posición del inicio del patrón coincidente dentro de la cadena coincidente. Esto nos da la posición del número $n
en la cadena $_
y también la matriz @S
.
Por supuesto, el bucle terminará cuando $n
sea lo suficientemente alto como para que no podamos encontrarlo en la entrada.
$S[$q=$-[0]]=''+'';
Sea $q
la posición del número $n
en la cadena $_
y la matriz @S
, y asigne el carácter ''+'' en esa posición.
$P=($p||=$q)+$q-($Q=$q>$p?$q:$p)
($P,$Q)=sort{$a-$b}$p||$q,$q;
La primera vez que pase por el bucle, establezca $p
en $q
. Después de la primera vez, $p
mantendrá el valor anterior de $q
(que se referirá a la posición en la entrada del número anterior). Asigne $P
y $Q
tal manera que $P
= min ( $p
, $q
), $Q
= max ( $p
, $q
)
for(qw''/98 |97 /96 -1''){
Por construcción, los números consecutivos son:
Conectado por una línea vertical. Dado que la entrada se construye para tener 97 caracteres en cada línea, este caso significa que
$p-$q
es divisible por 97."alineado a la pendiente de una barra invertida", que haría
$p-$q
divisible por 98"alineado con la pendiente de una barra inclinada", que haría
$p-$q
divisible por 96en la misma linea horizontal
Los elementos de esta lista codifican el posible número de posiciones entre los segmentos de línea y el carácter para codificar ese segmento.
//D/;
Otra evaluación de expresiones regulares trivial. Como efecto secundario, establece la variable especial $&
(la variable MATCH ) al carácter de segmento de línea ( / | /
o -
) y $''
(la variable POSTMATCH ) al número (98 97 96 o 1) codificado en el elemento de la lista.
$S[$P]=$&until($Q-$P)%$''||$Q<=($P+=$'')
Esta declaración dibuja el segmento de línea entre dos números. Si $Q-$P
es divisible por $''
, entonces continúe incrementando $P
en $''
y asignando el carácter $&
a $S[$P]
hasta que $P
alcance $Q
Más concretamente, por ejemplo, si $Q-$P
es divisible por 97, entonces incremente $P
en 97 y establezca $S[$P]=''|''
. Repita hasta que $P>=$Q
$n++;$p=$q
Prepararse para la siguiente iteración del bucle. Incremente $n
al siguiente número para buscar en la entrada y deje que $p
mantenga la posición del número anterior.
s//d/ /,print for@S
Genere la matriz, convirtiendo cualquier dígito sobrante (de los identificadores de dos dígitos en la entrada donde solo sobrescribimos el primer dígito con un ''+'') en espacios a medida que avanzamos.
Potencia Shell, 328 304 caracteres
$i=$l=0;$k=@{}
$s=@($input|%{[regex]::matches($_,"/d+")|%{$k[1*$_.Value]=@{y=$l
x=$_.Index}};$l++;""})
while($a=$k[++$i]){
if($i-eq1){$x=$a.x;$y=$a.y}
do{$d=$a.x.CompareTo($x);$e=$a.y.CompareTo($y)
$s[$y]=$s[($y+=$e)].PadRight($x+1).Remove($x,1).Insert(($x+=$d),
"/-/|+|/-/"[4+$d*3+$e])}while($d-or$e)}$s
Y aquí hay una versión bastante impresa con comentarios:
# Usage: gc testfile.txt | dots.ps1
$l=$i=0 # line, dot index (used below)
$k=@{} # hashtable that maps dot index to coordinates
# Apply regular expression to each line of the input
$s=@( $input | foreach{
[regex]::matches($_,"/d+") | foreach{
# Store each match in the hashtable
$k[ 1*$_.Value ] = @{ y = $l; x = $_.Index }
}
$l++; # Next line
"" # For each line return an empty string.
# The strings are added to the array $s which
# is used to produce the final output
}
)
# Connect the dots!
while( $a = $k[ ++$i ] )
{
if( $i -eq 1 ) # First dot?
{
# Current position is ($x, $y)
$x = $a.x;
$y = $a.y
}
do
{
$d = $a.x.CompareTo( $x ) # sign( $a.x - $x )
$e = $a.y.CompareTo( $y ) # sign( $a.y - $y )
$c = ''/-/|+|/-/'[ 4 + $d * 3 + $e ] # character ''
# Move
$x += $d
$y += $e
# "Replace" the charcter at the current position
# PadRight() ensures the string is long enough
$s[ $y ]=$s[ $y ].PadRight( $x+1 ).Remove( $x, 1 ).Insert( $x, $c )
} while( $d -or $e ) # Until the next dot is reached
}
# Print the resulting string array
$s
C #, 638 caracteres
using System;
using System.Linq;
using System.Text.RegularExpressions;
class C
{
static void Main()
{
int i=0,j;
var p = Console.In.ReadToEnd()
.Split(''/n'')
.SelectMany(
r =>
{
i++; j =0;
return Regex.Matches(r, "//s+(//d+)").Cast<Match>()
.Select(m => { j += m.Length; return new { X = j, Y = i-1, N = int.Parse(m.Groups[1].Value) }; });
}
).OrderBy(a=>a.N).ToList();
var W = p.Max(a => a.X)+1;
var k = new char[W*i+W];
i = 0;
while (i < p.Count)
{
var b = p[i > 0 ? i - 1 : 0]; var a = p[i];
int h = a.Y - b.Y, w = a.X - b.X;
var s = "|-///"[h == 0 ? 1 : w == 0 ? 0 : h / w > 0 ? 3 : 2];
while ((h | w) != 0) { k[b.X + w + W * (b.Y + h)] = s; h -= h.CompareTo(0); w -= w.CompareTo(0); }
k[a.X + a.Y * W] = ''+'';
k[W * ++i] = ''/n'';
}
Console.Write(k);
}
}
Rebmu : 218 caracteres
Ma L{-|//}Qb|[sg?SBaB]Da|[feSm[TfiSrj[spAsp]iT[++Tbr]]t]Xa|[i?A]Ya|[i?FImHDa]Ca|[skPCmSCaBKfsA]wh[Jd++N][roG[xJyJ]]Bf+GwhB[JcB Ff+GiF[KcF HqXkXj VqYkYju[chCbPClEZv1[ezH2[eeHv3 4]]e?A+bRE[hV]f]]chJeFIlSCj{+}{+ }Jk Bf]wM
Me estoy volviendo bastante bueno para leerlo y editarlo de forma nativa en su forma de cerdo latino. (¡¡Aunque sí uso saltos de línea !!) :)
Pero aquí es cómo el dialecto es transformado por el intérprete cuando el truco de "mushing" que no distingue entre mayúsculas y minúsculas se desvanece y uno se acostumbra a él. Voy a añadir algunos comentarios. (Sugerencias: fi
es encontrar, fe
es foreach, sp
es un carácter de espacio, i?
Es índice, hd
es head, ch
es change, sk
es skip, pc
es pick, bk
es break, i
is if, e
es cualquiera de los dos, ee
es igual, ad nauseum)
; copy program argument into variable (m)atrix
m: a
; string containing the (l)etters used for walls
l: {-|//}
; q is a "b|function" (function that takes two parameters, a and b)
; it gives you the sign of subtracting b from a (+1, -1, or 0)
q: b| [sg? sb a b]
; d finds you the iterator position of the first digit of a two digit
; number in the matrix
d: a| [fe s m [t: fi s rj [sp a sp] i t [++ t br]] t]
; given an iterator position, this tells you the x coordinate of the cell
x: a| [i? a]
; given an iterator position, this tells you the y coordinate of the cell
y: a| [i? fi m hd a]
; pass in a coordinate pair to c and it will give you the iterator position
; of that cell
c: a| [sk pc m sc a bk fr a]
; n defaults to 1 in Rebmu. we loop through all the numbers up front and
; gather their coordinate pairs into a list called g
wh [j: d ++ n] [ro g [x j y j]]
; b is the (b)eginning coordinate pair for our stroke. f+ returns the
; element at G''s current position and advances G (f+ = "first+")
; advance g''s iteration position
b: f+ g
wh b [
; j is the iterator position of the beginning stroke
j: c b
; f is the (f)inishing coordinate pair for our stroke
f: f+ g
; if there is a finishing pair, we need to draw a line
i f [
; k is the iterator position of the end of the stroke
k: c f
; the (h)orizontal and (v)ertical offsets we''ll step by (-1,0,1)
h: q x k x j
v: q y k y j
u [
; change the character at iterator location for b (now our
; current location) based on an index into the letters list
; that we figure out based on whether v is zero, h is zero,
; v equals h, or v doesn''t equal h.
ch c b pc l ez v 1 [ez h 2 [ee h v 3 4]]
; if we update the coordinate pair by the offset and it
; equals finish, then we''re done with the stroke
e? a+ b re [h v] f
]
]
; whether we overwrite the number with a + or a plus and space
; depends on whether we detect one of our wall "letters" already
; one step to the right of the iterator position
ch j e fi l sc j {+} {+ }
; update from finish pair to be new begin pair for next loop iteration
j: k
b: f
]
; write out m
w m
Tanto el lenguaje como la muestra son nuevos y se encuentran en una etapa experimental. Por ejemplo, un ad
no se podía usar para agregar vectores y matrices antes de que lo cambiara para ayudar con esta muestra. Pero creo que ese es el tipo de cosas que debe tener un lenguaje diseñado específicamente para el código de golf. Es una línea sutil entre "lenguaje" y "biblioteca".
Última fuente con comentarios disponibles en GitHub
¡Aquí va!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int sign(int x) {
if (x < 0)
return -1;
if (x > 0)
return +1;
return 0;
}
#define MAX_ROWS 100
#define MAX_COLS 100
#define MAX_DIGITS 100
int main(void)
{
// Read in the digits
int number[MAX_DIGITS][2];
int rows = 0;
int cols = 0;
char row[MAX_COLS];
int maxvalue = 0;
int i, j, value, x;
for (i = 0; i < MAX_ROWS; i++) {
if (row != fgets(row, MAX_COLS, stdin))
break;
value = 0;
for (j=0; row[j] != 0; j++) {
if (row[j] >= ''0'' && row[j] <= ''9'') {
x = j;
value = 0;
do {
value = 10*value + (row[j]-''0'');
j++;
} while (row[j] >= ''0'' && row[j] <= ''9'');
number[value][0] = i;
number[value][1] = x;
if (maxvalue < value) maxvalue = value;
if (rows < i+1) rows = i+1;
if (cols < x+1) cols = x+1;
}
}
}
// Create an empty field
char field[rows][cols];
memset(field, '' '', rows*cols);
char lines[] = "//|/-+-/|//";
int dr,dc;
// Draw the numbers and lines
field[number[1][0]][number[1][1]] = ''+'';
for (i = 2; i <= maxvalue; ++i) {
int r = number[i-1][0];
int c = number[i-1][1];
int rt = number[i][0];
int ct = number[i][1];
dr = sign(rt-r);
dc = sign(ct-c);
char line = lines[(dr+1)*3+dc+1];
while (r != rt || c != ct) {
r += dr;
c += dc;
field[r][c] = line;
}
field[r][c] = ''+'';
}
for (i = 0; i < rows; ++i) {
for (j = 0; j < cols; ++j)
putchar(field[i][j]);
putchar(''/n'');
}
return 0;
}
Python - 381
import re
b=list(iter(raw_input,''''))
c=sum((zip([i]*999,re.finditer(''//d+'',x))for i,x in enumerate(b)),[])
d=sorted((int(m.group()),i,m.start())for i,m in c)
e=[['' '']*max(map(len,b))for x in b]
for(t,u,v),(x,y,z)in zip(d,d[1:]+d[-1:]):
e[u][v]=''+''
while u!=y or v!=z:i,j=(u<y)-(u>y),(v<z)-(v>z);u+=i;v+=j;e[u][v]=[''|'',''///-''[(i==j)+2*(i==0)]][j!=0]
print''/n''.join(map(''''.join,e))
C ++ 637
#include <iostream>
#include <string>
#include <vector>
#define S(x)((x)<0?-1:x>0?1:0)
using namespace std;enum{R=100,C=100,D=100};int main(){string s;
int N[D][2],M=0,q=0,p=0,i,j,V,L,a,b;for(i=0;j=0,(i<R)&&getline(cin,s);i++)
while((j=s.find_first_not_of(" ",j))<=s.size()){L=sscanf(&s[j],"%d",&V);
N[V][0]=i;N[V][1]=j;if(M<V)M=V;if(q<=i)q=i+1;if(p<=j)p=j+1;j+=L+1;}
string F(q*p,'' ''),l="//|/-+-/|//";F[p*N[1][0]+N[1][1]]=''+'';for(i=2;i<=M;++i){
int r=N[i-1][0],c=N[i-1][1],d=N[i][0],e=N[i][1];for(a=S(d-r),b=S(e-c);r!=d||c!=e;)
r+=a,c+=b,F[p*r+c]=l[(a+1)*3+b+1];F[p*r+c]=''+'';}for(i=0;i<q;i++)
cout<<string(&F[i*p],p)+"/n";}
Con sangría, y con algunos nombres un poco más significativos, que se parece a:
#include <iostream>
#include <string>
#include <vector>
#define S(x)((x)<0?-1:x>0?1:0)
using namespace std;
enum{R=100,C=100,D=100};
int main(){
string s;
int N[D][2],M=0,rs=0,cs=0,i,j,V,L,dr,dc;
for(i=0;j=0,(i<R)&&getline(cin,s);i++)
while((j=s.find_first_not_of(" ",j))<=s.size()){
L=sscanf(&s[j],"%d",&V);
N[V][0]=i;
N[V][1]=j;
if(M<V)M=V;
if(rs<=i)rs=i+1;
if(cs<=j)cs=j+1;
j+=L+1;
}
string F(rs*cs,'' ''),lines="//|/-+-/|//";
F[cs*N[1][0]+N[1][1]]=''+'';
for(i=2;i<=M;++i){
int r=N[i-1][0],c=N[i-1][1],rt=N[i][0],ct=N[i][1];
for(dr=S(rt-r),dc=S(ct-c);r!=rt||c!=ct;)
r+=dr,c+=dc,F[cs*r+c]=lines[(dr+1)*3+dc+1];
F[cs*r+c]=''+'';
}
for(i=0;i<rs;i++)
cout<<string(&F[i*cs],cs)+"/n";
}
A pesar de las diferencias superficiales, es un robo flagrante del código de morotspaj.
C, 386
402 386 caracteres en C. Las líneas nuevas después de la primera son solo para facilitar la lectura.
#include <stdio.h>
int x[101],y[101],c=1,r,w,h,b,i,j,k,m,n;
int main(){
while((b=getchar())-EOF)
b-'' ''?b-''/n''?ungetc(b,stdin),scanf("%d",&b),x[b]=c++,y[b]=h,c+=b>9:(w=c>w?c:w,++h,c=1):++c;
for(r=0;r<h&&putchar(''/n'');++r)
for(c=0;c<w;++c){
for(b='' '',i=2,m=x[1]-c,n=y[1]-r;j=m,k=n,m=x[i]-c,n=y[i]-r,x[i++];)
b=j|k&&m|n?j*m>0|k|n?k*n<0?(j-k|m-n?j+k|m+n?j|m?b:''|'':''/'':''//'):b:''-'':''+'';
putchar(b);
}
}
Ensamblador de Intel
Tamaño ensamblado: 506 bytes.
Fuente: 2252 bytes (hey, este no es un problema trivial)
Para ensamblar: Use A86 Para ejecutar: Probado con un cuadro de WinXP DOS. Invocación jtd.com < input > output
mov ax,3
int 10h
mov ax,0b800h
mov es,ax
mov ah,0bh
int 21h
mov bx,255
cmp al,bl
mov dh,bh
mov si,offset a12
push offset a24
je a1
mov si,offset a14
a1: inc bl
a2: mov dl,255
call si
cmp al,10
jb a4
a3: cmp al,10-48
jne a1
inc bh
mov bl,dh
jmp a2
a4: mov dl,al
call si
cmp al,10
jae a5
mov ah,dl
aad
mov dl,al
a5: mov di,dx
mov ch,al
shl di,2
mov [di+a32],bx
cmp bl,[offset a30]
jb a6
mov [offset a30],bl
a6: cmp bh,[offset a31]
jb a7
mov [offset a31],bh
a7: push offset a19
mov al,80
mul bh
add al,bl
adc ah,0
add ax,ax
lea di,[di+2+a32]
mov [di],ax
add di,2
cmp di,[a22-3]
jbe a8
mov [a22-3],di
mov [a25-3],di
a8: mov di,ax
mov al,dl
aam
cmp ah,0
je a10
a9: add ah,48
mov es:[di],ah
add di,2
a10:add al,48
mov es:[di],al
mov al,ch
inc bl
jmp a3
a11:jmp si
a12:mov ah,0bh
int 21h
cmp al,255
jne a15
mov ah,8
int 21h
a13:cmp al,13
je a11
sub al,48
ret
a14:mov ah,1
int 21h
cmp al,26
jne a13
mov si,offset a15
ret
a15:cmp dl,255
je a16
mov al,32
ret
a16:mov si,offset a32 + 4
lodsw
mov cx,ax
mov dx,ax
lodsw
mov di,ax
mov b es:[di],1
mov bp,0f000h
call a26
add sp,6
mov bx,[a22-3]
mov ax,[offset a31]
inc ax
a17:mov bp,[offset a30]
a18:mov b[bx],32
inc bx
dec bp
jnz a18
mov w[bx],0a0dh
add bx,2
dec ax
jnz a17
mov b[bx],''$''
add w[a30],2
a19:lodsw
xchg ax,dx
cmp ah,dh
lahf
mov bl,ah
cmp al,dl
lahf
shr bl,6
shr ah,4
and ah,12
or bl,ah
mov bh,0
shl bx,3
a20:mov b es:[di],43
a21:mov al,b[a30]
mul ch
add al,cl
adc ah,0
mov bp,ax
mov b[bp+100h],43
a22:add di,[bx + a29]
add cl,[bx + a29 + 4]
add ch,[bx + a29 + 6]
mov b es:[di],1
mov al,[bx + a29 + 2]
mov [a21-1],al
mov [a22-1],al
mov bp,01000h
call a26
cmp di,[si]
jne a20
mov al,es:[di+2]
sub al,48
cmp al,10
jae a23
mov b es:[di+2],0
a23:mov b[a21-1],43
mov b[a22-1],43
mov b es:[di],43
lodsw
ret
a24:mov al,b[a30]
mul ch
add al,cl
adc ah,0
mov bp,ax
mov b[bp+100h],43
a25:mov dx,[a22-3]
mov ah,9
int 21h
ret
a26:pusha
a27:mov cx,0ffffh
a28:loop a28
dec bp
jnz a27
popa
ret
a29:dw -162,92,-1,-1,-2,45,-1,0,158,47,-1,1,0,0,0,0,-160,124,0,-1
a30:dw 0
a31:dw 0,0,0,160,124,0,1,0,0,0,0,-158,47,1,-1,2,45,1,0,162,92,1,1
a32:
Características interesantes: código de auto-modificación, salida animada (el segundo ejemplo funciona, pero es demasiado grande para mostrarlo), abuso de ''ret'' para implementar un contador de bucles, una forma interesante de determinar la dirección de la línea / movimiento.
Lote de MS-DOS (si, has leído bien!)
A menudo escucho (o leo) a la gente decir que el lote no es muy poderoso y no se puede hacer mucho con ellos, bueno, a ellos les digo, ¡he aquí el poder de BATCH!
El script real (script.bat):
set file=%~1
call :FindNextNum 1
for /F "tokens=2 delims=:" %%i IN (''find /c /V "" "%file%"'') DO set /a totalLines=%%i
set maxLen=0
for /F "delims=" %%i IN (%file%) DO (
call :CountChars "%%i"
if /i !charCount! gtr !maxLen! set maxLen=!charCount!
)
for /L %%i IN (0,1,%totalLines%) DO set "final_%%i=" & for /L %%j IN (0,1,%maxLen%) DO set "final_%%i=!final_%%i! "
:MainLoop
set currLineNum=%lineNum%
set currCol=%linePos%
set currNum=%nextNum%
set /a targetNum=%currNum%+1
call :FindNextNum %targetNum%
if "%nextNum%"=="" goto MainEnd
REM echo %currNum% -^> %nextNum%
if /I %currLineNum% lss %lineNum% (
call :DrawLine %currCol% %currLineNum% %linePos% %lineNum%
) else (
call :DrawLine %linePos% %lineNum% %currCol% %currLineNum%
)
goto MainLoop
:MainEnd
for /L %%i IN (0,1,%totalLines%) DO echo.!final_%%i!
goto:eof
:DrawLine
if /I %2 equ %4 goto:DrawHoriz
set "char=" & set "pos=%1" & set "inc=0"
if /I %1 LSS %3 set "char=/" & set "pos=%1" & set "inc=1"
if /I %1 GTR %3 set "char=/" & set "pos=%1" & set "inc=-1"
for /L %%i IN (%2,1,%4) DO call :DrawChar %%i !pos! %char% & set /a "pos+=%inc%"
goto:DrawEnds
:DrawHoriz
set "start=%1+1" & set "end=%3"
if /I %start% gtr %end% set "start=%3+1" & set "end=%1"
set /a lineEnd=%end%+1
set lineEnd=!final_%2:~%lineEnd%!
for /L %%i IN (%start%,1,%end%) DO set final_%2=!final_%2:~0,%%i!-
set final_%2=!final_%2!!lineEnd!
:DrawEnds
call :DrawChar %2 %1 +
call :DrawChar %4 %3 +
goto:eof
:DrawChar
set /a skip2=%2+1
if "%3"=="" (
set final_%1=!final_%1:~0,%2!^|!final_%1:~%skip2%!
) else (
set final_%1=!final_%1:~0,%2!%3!final_%1:~%skip2%!
)
goto:eof
:CountChars
set charCount=0
set val=%~1
:CountChars_loop
if not "%val:~1%"=="" (
set /a charCount+=1
set val=!val:~1!
goto CountChars_loop
)
goto:eof
:FindNextNum
for /F "delims=" %%i IN (''type "%file%" ^| find /V /N ""'') DO (
for /F "tokens=1,2 delims=[]" %%j IN ("%%i") DO (
set /a lineNum=%%j-1
call :FindNext_internal "%%k" %1
if /I !nextNum! equ %1 goto :eof
)
)
goto:eof
:FindNext_internal
set currLine=%~1
set linePos=0
:FindNext_internal_loop
call :NextNumInLine "%currLine%"
set /a linePos+=%spaceInterval%
if "%nextNum%"=="" goto :EOF
if /I %nextNum% equ %2 goto :EOF
set /a spaceInterval+=1
set /a linePos+=1
if /I %nextNum% GTR 9 set /a "spaceInterval+=1" & set /a linePos+=1
set currLine=!currLine:~%spaceInterval%!
goto FindNext_internal_loop
:NextNumInLine
set nextNum=
for /F %%i IN (%1) DO set /a nextNum=%%i
if "%nextNum%"=="" goto :eof
set /a spaceInterval=0
set val=%~1
:NextNumInLine_loop
if "%val:~0,1%"==" " (
set /a spaceInterval+=1
set val=!val:~1!
goto NextNumInLine_loop
)
goto :eof
Y así es como lo llamas.
echo off
setlocal ENABLEDELAYEDEXPANSION
call script.bat input.txt
donde "input.txt" es un archivo que contiene la entrada para el "programa".
PS Esto aún no está optimizado para la longitud de la línea, ya he pasado un par de horas llegando a este punto y ahora necesito dormir ... Veré si puedo mejorarlo mañana (actualmente ''script.bat ''se sienta a 2755 bytes)
No puedo hacer multilínea en un comentario, así que lo demostraré aquí. En los siguientes ejemplos, distancia (x1, x2) == distancia (y1, y2):
+
|/
+-+
+
|/
| /
+--+
+
|/
| /
| /
+---+
Con las reglas explicadas, distancia (x1, x2) == distancia (y1, y2) +2:
+/
| /
+--/+
+/
| /
| /
+---/+
+/
| /
| /
| /
+----/+