Convertir una cadena de notación de Forsyth-Edwards a arte ASCII

9

En ajedrez, la notación de Forsyth-Edwards , más comúnmente llamada "FEN", es una forma textual de transcribir tableros. Describe cada una de las ocho filas del tablero (llamadas "rangos" en ajedrez) de arriba a abajo desde la perspectiva de White. Las piezas se escriben como K (rey), Q (reina), R (torre), B (alfil), N (caballero) y P (peón). Las piezas negras usan estas letras en minúsculas, y las piezas blancas usan estas letras en mayúsculas. Los espacios vacíos se indican mediante un número del 1 al 8 que indica cuántos espacios vacíos consecutivos hay. Un rango completamente vacío sería 8, una sola torre negra en la columna más a la derecha (llamada "archivos" en ajedrez) 7r, y dos peones blancos en cada extremo de una fila PP4PP. Los rangos están separados por un/. Normalmente existe otra información adicional, lo que indica de qué lado es mover, enroque y en passant derechos, número de jugadas, y el reloj halfmove, pero vamos a ignorar a los efectos de este desafío.

Entrada

Una cadena FEN, desde la línea de comando o STDIN, como desee. Puede suponer que esta cadena siempre es válida.

Salida

Escriba a STDOUT una simple representación artística ASCII de la pizarra tal como aparecería en realidad:

  • Las piezas están representadas por su personaje en FEN
  • Los cuadrados vacíos están representados por espacios.
  • Las piezas y los cuadrados están separados por una tubería |y hay tuberías a cada lado del tablero.

Entonces un tablero vacío, escrito como 8/8/8/8/8/8/8/8en FEN, aparecería como

| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |

La posición inicial de un juego de ajedrez se escribe como rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR, y aparecería como

|r|n|b|q|k|b|n|r|
|p|p|p|p|p|p|p|p|
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
|P|P|P|P|P|P|P|P|
|R|N|B|Q|K|B|N|R|

La posición final de Anderssen-Kieseritzky 1851 , llamada "El juego inmortal" en la comunidad de ajedrez, se escribe como r1bk3r/p2pBpNp/n4n2/1p1NP2P/6P1/3P4/P1P1K3/q5b1, y su programa cuando se alimenta esa entrada generaría:

|r| |b|k| | | |r|
|p| | |p|B|p|N|p|
|n| | | | |n| | |
| |p| |N|P| | |P|
| | | | | | |P| |
| | | |P| | | | |
|P| |P| |K| | | |
|q| | | | | |b| |
EMBLEMA
fuente
¿Es aceptable escribir una función que toma entrada y devuelve salida, en lugar de escribirla en STDOUT?
Financia la demanda de Mónica el
@QPaysTaxes De forma predeterminada, lo permitimos y, de hecho, varias soluciones ya lo hacen. En última instancia, depende del OP, aunque parece innecesario anular nuestros valores predeterminados en este caso.
Alex A.
2
La respuesta que aceptó no es la más corta. Independientemente de sus sentimientos hacia los idiomas de golf, el código de golf significa que gana el código más corto .
Dennis
3
Tampoco puede penalizarlos ni aceptar una respuesta arbitraria . Todo el sitio está construido alrededor de criterios objetivos ganadores.
Dennis
1
+1por un reto interesante -2por aceptar la respuesta incorrecta sin una buena razón
James

Respuestas:

9

Perl, 28 bytes

Incluye +2 para -lp

Dar entrada sobre STDIN

fen.pl <<< "r1bk3r/p2pBpNp/n4n2/1p1NP2P/6P1/3P4/P1P1K3/q5b1"

fen.pl:

#!/usr/bin/perl -lp
s/\d/$"x$&/eg;s/|/|/g;y;/;

En realidad en la liga de algunos idiomas de golf ...

Tenga en cuenta que la versión basada en archivo necesita la nueva línea final en el archivo, de modo que uno sea realmente 29 bytes. Pero la versión de línea de comandos no necesita esa nueva línea adicional y, por lo tanto, el código cuenta como 28 bytes:

perl -lpe 's/\d/$"x$&/eg;s/|/|/g;y;/;' <<< "r1bk3r/p2pBpNp/n4n2/1p1NP2P/6P1/3P4/P1P1K3/q5b1"
Ton Hospel
fuente
1
¿Shebang perdido?
user253751
15

Retina, 13 bytes

\d
$* 
/
¶

|

Pruébalo en línea!

Explicación

La primera parte (tenga en cuenta el espacio final):

\d
$* 

es convertir a al número específico de espacios. La retina tiene una $*función para repetir. La forma en que funciona es: <num>$*<char>si no hay <num>, Retina asumirá $&o la cadena coincidente, en este caso, el número coincidente.

La siguiente parte:

/
¶

es bastante simple, que sustituye todos /con los cuales es una nueva línea.

La última parte funciona igual:

    
El |

Esto reemplazará todo (por eso no hay nada en la primera línea) con |. Poniendo un en |todas partes.

Downgoat
fuente
1
Incluso puede hacerlo todo en ASCII para el mismo recuento de bytes con S`/la segunda etapa.
Martin Ender
12

Ruby - 75 82 78 76 75 62 59 58 57 56 bytes

->n{"|#{n.gsub(/\d|
/){' '*$&.hex}.chars*?|}|".tr'/',$/}

Guardado algunos bytes gracias a Ventero

Déjame explicarte ( \nreemplazando la nueva línea literal):

->n{"...".tr'/',$/}

Esto devuelve implícitamente el valor de la cadena, con cada uno /reemplazado por una nueva línea (por defecto, $/contiene una nueva línea)

"|#{...}|"

Esto es super simple; es solo una cadena que contiene una tubería, interpolación de cadenas y otra tubería. Se evalúa la interpolación de cadenas

n.gsub(/\d|\n/){' '*$&.hex}...

Esto reemplaza cada número con tantos espacios. Puedo guardar algunos bytes al encontrar nuevas líneas aquí; porque hexdevuelve 0 si la cadena no es un número válido, cuando encuentra una nueva línea, es decir, la que está al final del resultado de gets, la reemplaza con una cadena de longitud 0, eliminándola efectivamente. Sin esto, habría una tubería de arrastre.

$&es una variable mágica que representa el texto completo de la última coincidencia de variables, lo que me permite guardar un byte al eliminarlo |d|. Puedo guardar otro byte usando en .hexlugar de .to_i, que funciona porque cada número es menor que 9, lo que significa que hexadecimal y decimal tienen los mismos valores.

.chars*?|

Esto pone una tubería entre cada personaje. Tenga en cuenta que esto es lo que coloca las tuberías a ambos lados de las líneas (excepto la primera y la última) porque las barras, que eventualmente se convierten en líneas nuevas tr, cuentan como caracteres y, por lo tanto, están rodeadas de tuberías. El ?|justo significa "la cadena de un carácter "|"".

Y eso es. Es un programa francamente escandalosamente simple. Solo usa muchos trucos de sintaxis furtivos.

Fondo de la demanda de Mónica
fuente
2
Puede guardar 4 caracteres más aplicando algunos trucos simples: puts"|#{gets.gsub(/\d|\n/){' '*$&.hex}.chars*?|}|".split'/'(por supuesto, reemplace el \ncon una nueva línea literal nuevamente).
Ventero
5

Pyth - 24 22 21 bytes

.i*\|72jcu:G`H*Hd9z\/

Test Suite .

+                     Concatenate
 K\|                  Store "|" in K and use value
+         K           Concatenate to end
 jK                   Join string by K, this puts "|" between each char
  :                   String substitution
        \/            Replace "/"
         b            With newline
   u                  Reduce
        9             Over [0, 9)
         z            With input as base case
    :G                String substitution current val
     `H               Replace stringifyed int from list we're looping through
     *Hd              With " "*that int
Maltysen
fuente
4

Pyth, 23 bytes

VT=:Q`N*dN;jc.i*\|72Q\/

Pruébalo en línea!

Cómo funciona:

VT=:Q`N*dN;jc.i*\|72Q\/
VT        ;                for N in range(10):
  =:Q`N*dN                     Q = Q.replace(`N`,repeat(' ',N))
             .i*\|72Q      temp = interweave(repeat('|',72), Q)
            c        \/    temp = chop(temp,'/')
           j               temp = join(temp,'\n')
                           print temp
Monja permeable
fuente
4

JavaScript ES7, 80 70 bytes

Es una función anónima que acepta una cadena como entrada.

a=>[,...[+t?" ".repeat(t):t<"0"?`
`:t for(t of a)].join``,`
`].join`|`

Aproximación de 80 bytes solo para ES6.

a=>a.split`/`.map(x=>[,...x.replace(/\d/g,t=>" ".repeat(t)),`
`].join`|`).join``

Explicación

Usamos una comprensión de matriz para recorrer la lista:

[+t?" ".repeat(t):t<"0"?`
`:t for(t of a)]

Esto es equivalente a:

[!isNaN(parseInt(t, 10)) ? " ".repeat(parseInt(t, 10)) : t === "/" ? "\n" : t for(t of a)]

Si es un número, tenemos ese número de espacios. Si es un /, tenemos una nueva línea. De lo contrario, tenemos el personaje. Luego, unimos la comprensión sin nada para hacer una cuerda.

Luego, creamos una matriz de longitud 3 [,...that,"\n"]. ...Splats la comprensión unida en caracteres. Unirse a esto produce el resultado.

Conor O'Brien
fuente
¿No te refieres a ES6? ES7 aún no está disponible, creo.
ericw31415
@ ericw31415 No está disponible, tienes razón, pero algunos navegadores han comenzado a implementar parte de la especificación ES7.
Conor O'Brien
Oh ok Pero aún así su código no usa ninguna de las características de ES7, ¿verdad?
ericw31415
1
@ ericw31415 En realidad, lo hace. Las comprensiones de matriz ( [x for(x of a)]) son ES7.
Conor O'Brien
No se eliminaron las Comprensiones de matriz de la especificación, MDN dice que sí lo fueron
MayorMonty
3

Julia, 62 bytes

s->split("|"join(replace(s,r"\d",d->" "^parse(d)),"|")"|","/")

Esta es una función anónima que acepta una cadena y devuelve una matriz de cadenas. Para llamarlo, asígnelo a una variable.

El enfoque es el mismo que en la inteligente respuesta de Ruby de QPaysTaxes . Reemplazamos cada dígito en la entrada con esa cantidad de espacios, lo colocamos |entre cada carácter, lo pegamos |al frente y atrás, y lo dividimos en una matriz /.

Pruébalo en línea!

Alex A.
fuente
Sí, inspiré cosas: D
Fund Monica's Lawsuit
@QPaysTaxes Lo hiciste de hecho. Buena solución!
Alex A.
2

05AB1E , 21 bytes

Código:

9GNNð×:}S'|ý"|ÿ|"'/¶:

También 21 bytes: '|¹9GNNð×:}S'|«JJ'/¶:.

Utiliza la codificación CP-1252 . Pruébalo en línea! .

Adnan
fuente
2

JavaScript (ES6), 69 67 62 bytes

s=>[,...s.replace(/[/-8]/g,c=>+c?' '.repeat(c):`
`),,].join`|`

Las comas adicionales crean valores vacíos en la división externa que crea los caracteres iniciales y finales |. Necesita dos comas finales porque las comas finales son opcionales al final de las listas, por lo que la primera sigue siendo parte del elemento anterior.

Editar: Guardado 5 bytes gracias a @ user81655.

Neil
fuente
Funcionaria /[\d/]/g,c=>+c?` `.repeat(c):`\n`?
user81655
1
@ user81655 Gracias, pero no me gustó tu emoticón, así que lo reemplacé con una cara molesta con gafas.
Neil
1

Retina , 50 45 bytes

Esto fue divertido jaja. No solo soy un novato en Retina, sino también en expresiones regulares en general ... Esto probablemente se puede jugar mucho al golf , así que investigaré un poco más.

Código:

8
44
7
34
6
42
5
 4
4
22
3
 2
2

1

/
¶

|

Pruébalo en línea!

Adnan
fuente
Intente usar la $*funcionalidad :)
Leaky Nun
1

Jolf, 28 bytes

RΜGi'/dΆγ'|RGρH«\d»d*♣PHEγγS

¡Reemplácelo con el personaje \x05, o pruébelo aquí!

Conor O'Brien
fuente
1

Python 3.5, 112 bytes:

def r(o):print(''.join(['| '*8if h=='8'else'| '*int(h)if h.isdigit()else'|\n'if h=='/'else'|'+h for h in o])+'|')

Pruébalo en línea! (Ideona)

R. Kap
fuente
1

C, 252 bytes

i=-1,j,s=1,x;C(char*n){while(n[++i])s+=isdigit(n[i])?n[i]*2+1:2;char*m=(char*)malloc(s);for(i=j=-1;n[++i]&(m[++j]='|');)if(n[i]=='/')m[++j]='\n';else if(isdigit(n[i]))for(x=n[i]-'0';x;--x&&(m[++j]='|'))m[++j]=' ';else m[++j]=n[i];m[++j]='\0';return m;}

Prueba detallada en línea

// input-string, input-string-size
char* C(char*n)
{
    int i=-1,j,s=1,x;

    // figure out required grid size
    while(n[++i])s+=isdigit(n[i])?n[i]*2+1:2;
    char*m=(char*)malloc(s);

    i=j=-1;
    while(n[++i]) // while not end of string
    {
        m[++j]='|'; // seperator

        if (n[i]=='/') // end of row
            m[++j]='\n';
        else if (isdigit(n[i])) // fill spaces
            for(x=n[i]-'0';x;--x&&(m[++j]='|')) m[++j]=' ';
        else
            m[++j]=n[i]; // single literals
    }

    m[++j]='|';
    m[++j]='\0';
    return m;
}
Khaled.K
fuente
1

JavaScript (FireFox 30+), 61

Usar una comprensión de matriz que ya no es EcmaScript estándar

f=>'|'+[for(c of f)+c?' |'.repeat(c):c<'A'?`
|`:c+'|'].join``

Prueba

F=f=>'|'+[for(c of f)+c?' |'.repeat(c):c<'A'?`\n|`:c+'|'].join``

console.log=x=>O.textContent+=x+'\n'

;['8/8/8/8/8/8/8/8','rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR',
'r1bk3r/p2pBpNp/n4n2/1p1NP2P/6P1/3P4/P1P1K3/q5b1']
.forEach(t=>console.log(F(t)+'\n'))
<pre id=O></pre>

edc65
fuente
1

Lua, 106 bytes

print("|"..(...):gsub(".",function(c)return c:find("%d")and(" |"):rep(c)or c=="/"and"\n|"or c.."|"end),'')

Sin golf

print("|"..                   -- prepend | to the following string
  (...):gsub(".",function(c)  -- iterate over each character in the argument
    return                    -- replaces in the argument
           c:find("%d")       -- if c is a number
             and(" |"):rep(c) --   replace by " |"*c
           or c=="/"          -- elseif c is a slash
             and"\n|"         -- replace by "\n|"
           or c.."|"          -- else (case letter)replace by c
  end)                        -- return the modified string
,'')                          -- add an empty parameter to print
                              -- it suppresses the second output of gsub
Katenkyo
fuente
print((...):gsub(".",function(c)return(c:find("%d")and("| "):rep(c)or c=="/"and"|\n"or"|"..c)end).."|")
Leaky Nun
print((...):gsub("%d",function(c)return("| "):rep(c)end):gsub("/","|\n"):gsub("([^%d%s|])","|%1").."|")para el mismo número de bytes.
Leaky Nun
print((...):gsub("%d",function(c)return("| "):rep(c)end):gsub("([^%d |])","|%1"):gsub("/","\n").."|")es 101 bytes
Leaky Nun
1

R (fuera de competencia)

Lo siento si no es apropiado publicar esto, pero pensé que era genial que tuviera una función que realmente funciona para esta pregunta sin editar. Sin embargo, imprime salida unicode en lugar de ascii. No recuerdo exactamente por qué lo escribí, pero no fue para responder a un desafío.

function(x){
# x = FEN position, a string
# can be split with / or ,
# example: forsythe("rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R")

allowed <- c(paste(1:64), 
c("k", "q", "r", "b", "n", "p", "K", "Q", "R", "B", "N", "P"))
chars <- strsplit(x, "")[[1]]
chars <- chars[-which(!(chars %in% allowed))]
out <- c()
for (i in 1:length(chars)){
  if (chars[i] %in% paste(1:64)){
    out <- c(out, rep(" ", as.numeric(chars[i])))
  }
  else{
    out <- c(out, chars[i])
  }
}
if (length(out) < 64) out <- c(out, rep(" ", 64-length(out)))

pieces <- strsplit("KQRBNPkqrbnp", "")[[1]]
unicode <- c("\u2654", "\u2655", "\u2656", 
"\u2657", "\u2658", "\u2659", "\u265A", "\u265B", 
"\u265C", "\u265D", "\u265E", "\u265F")

for (i in 1:64){
  if (out[i] %in% pieces){
    out[i] <- unicode[which(pieces==out[i])]
  }
  else{
  }
}
out <- matrix(out, nc=8, byrow=T)
#print(out)

plot(0, xlim=c(0, 8), ylim=c(0, 8), type="n", xaxt="n", yaxt="n",
xlab="", ylab="")
for (i in 0:7){ for (j in 0:7){ rect(i, j, i+1, j+1,
col=ifelse(((i+j) %% 2) == 0, grey(0.95), "white"), border=F) }}

for (i in 0:7){ for (j in 0:7){
  text(i+0.5, j+0.5, out[8-j, i+1], cex=2)  
}}

axis(1, labels=letters[1:8], at=1:8 - 0.5, tick=F)
axis(2, labels=paste(1:8), at=1:8-0.5, las=2, tick=F)

}
Flounderer
fuente
Las reglas descritas en nuestro centro de ayuda establecen que todas las soluciones a los desafíos deben ser un contendiente serio para los criterios ganadores en uso. Para el golf de código, esto significa que todas las respuestas deben ser golfizadas.
Dennis
Técnicamente, se juega al golf. Simplemente no muy bien.
Flounderer
0

Haskell, 110 bytes

p '/'="\n"
p c|'1'<=c&&c<='8'=replicate(read[c])' '
p c=[c]
main=getLine>>=putStrLn.('|':).(>>=(:"|")).(>>=p)

Sin golf:

p c | c=='/'           = "\n"
    | '1'<=c && c<='8' = replicate (read [c]) ' '
    | otherwise        = [c]
addPipes string = "|" ++ concatMap (\c -> [c] ++ "|") string
main = getLine >>= putStrLn . addPipes . concatMap p
viercc
fuente
0

Java 7, 190 184 bytes

String Z(int c){String m="";if(c==47)m+="|\n";else if(c>57)m+="|"+c;else while(c-->48)m+="| ";return m;}String C(String n){String m="";for(char x:n.toCharArray())m+=Z(x);return m+"|";}

Prueba detallada en línea

public static String Z(char c)
{
    String m="";
    if(c=='/')m+="|\n";
    else if(c>'9')m+="|"+c;
    else while(c-->'0')m+="| ";
    return m;
}

public static String C(String n)
{
    String m="";
    for(char x:n.toCharArray())m+=Z(x);
    return m+"|";
}
Khaled.K
fuente
Puede guardar un par de bytes utilizando números enteros en lugar de literales char en las comparaciones
azul
@Blue notas tomadas
Khaled.K
0

Pyke, 25 20 bytes

FD~u{RIbd*(s\/n:k\|:

Explicación:

F         (          -    for char in input:
 D~u{RI              -     if char in '0123456789': 
       bd*           -      char = " "*int(char)
           s         -   sum(^)
            \/n:     -  ^.replace("/","\n")
                k\|: - ^.replace("", "|")

Pruébalo aquí!

Azul
fuente
0

Python, 84 bytes

lambda a:"".join(c*c.isalpha()or"\n"*(c=="/")or" "*int(c)for c in a).replace("","|")

Explicación:

        c*c.isalpha()                                                       - if c is alphabetical, use c
                       "\n"*(c=="/")                                        - if it's "|", replace it with a newline
                                      " "*int(c)                            - else its an int.
"".join(                                                  ).replace("","|") - interweave "|" between the chars
Azul
fuente
0

> <>, 64 bytes

<v?(0:i
r\
"<o-*=@"%/":   v?*(@)@":/"::;?(0:o"|
 ^~?="0":-1o" "<

4 bytes desperdiciados debido a problemas de alineación, aunque no estoy seguro de cómo jugarlos. ¯ \ _ (ツ) _ / ¯

Sok
fuente