Convertir une chaîne de notation Forsyth-Edwards en art ASCII

9

Aux échecs, la notation Forsyth-Edwards , plus communément appelée "FEN", est une manière textuelle de transcrire les tableaux. Il décrit chacune des huit rangées du plateau (appelées "rangs" aux échecs) de haut en bas du point de vue de White. Les pièces sont écrites comme K (roi), Q (reine), R (tour), B (évêque), N (chevalier) et P (pion). Les pièces noires utilisent ces lettres en minuscules et les pièces blanches utilisent ces lettres en majuscules. Les espaces vides sont indiqués par un nombre de 1 à 8 indiquant le nombre d'espaces vides consécutifs. Un rang complètement vide serait 8, une seule tour noire dans la colonne la plus à droite (appelée "fichiers" dans les échecs) serait 7r, et deux pions blancs à chaque extrémité d'une rangée seraient PP4PP. Les rangs sont séparés par un/. Il y a normalement d' autres informations ajoutées, ce qui indique de quel côté est de se déplacer, roque et en passant les droits, numéro de mouvement, et l' horloge halfmove, mais nous les ignorer dans le cadre de ce défi.

Contribution

Une chaîne FEN, depuis la ligne de commande ou STDIN, à votre guise. Vous pouvez supposer que cette chaîne est toujours valide.

Production

Écrivez à STDOUT une simple représentation artistique ASCII du tableau tel qu'il apparaîtrait en fait:

  • Les pièces sont représentées par leur caractère dans FEN
  • Les carrés vides sont représentés par des espaces
  • Les morceaux et les carrés sont séparés par un tuyau |et il y a des tuyaux de chaque côté de la planche

Ainsi, un tableau vide, écrit comme 8/8/8/8/8/8/8/8dans FEN, apparaîtrait comme

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

La position de départ d'une partie d'échecs est écrite comme rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR, et apparaîtrait comme

|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 position finale d' Anderssen-Kieseritzky 1851 , appelée "The Immortal Game" dans la communauté d'échecs, est écrite ainsi r1bk3r/p2pBpNp/n4n2/1p1NP2P/6P1/3P4/P1P1K3/q5b1, et votre programme, une fois alimenté, produira:

|r| |b|k| | | |r|
|p| | |p|B|p|N|p|
|n| | | | |n| | |
| |p| |N|P| | |P|
| | | | | | |P| |
| | | |P| | | | |
|P| |P| |K| | | |
|q| | | | | |b| |
EMBLÈME
la source
Est-il acceptable d'écrire une fonction qui prend une entrée et retourne une sortie, plutôt que de l'écrire dans STDOUT?
Fund Monica's Lawsuit
@QPaysTaxes Par défaut, nous l'autorisons et plusieurs solutions le font déjà. En fin de compte, c'est à l'OP bien qu'il semble inutile de remplacer nos valeurs par défaut dans ce cas.
Alex A.
2
La réponse que vous avez acceptée n'est pas la plus courte. Indépendamment de vos sentiments envers les langues de golf, le golf par code signifie que le code le plus court l' emporte.
Dennis
3
Vous ne pouvez pas non plus les pénaliser ou accepter une réponse arbitraire . L'ensemble du site est construit autour de critères de gain objectifs .
Dennis
1
+1pour un défi intéressant. -2pour avoir accepté la mauvaise réponse sans raison valable
James

Réponses:

9

Perl, 28 octets

Comprend +2 pour -lp

Donnez votre avis sur 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 fait dans la ligue de certaines langues de golf ...

Notez que la version basée sur fichier a besoin de la nouvelle ligne finale dans le fichier afin que l'on soit vraiment 29 octets. Mais la version en ligne de commande n'a pas besoin de cette nouvelle ligne supplémentaire et donc le code compte pour 28 octets:

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

Rétine, 13 octets

\d
$* 
/
¶

|

Essayez-le en ligne!

Explication

La première partie (notez l'espace de fin):

\d
$* 

est de convertir un au nombre spécifique d'espaces. La rétine a une $*fonction à répéter. La façon dont cela fonctionne est: <num>$*<char>s'il n'y en a pas <num>, Retina assumera $&ou la chaîne correspondante, dans ce cas le numéro correspondant.

La partie suivante:

/
¶

est assez simple, il remplace tout /avec ce qui est une nouvelle ligne.

La dernière partie fonctionne de la même façon:

    
|

Cela remplacera tout (d'où pourquoi il n'y a rien sur la première ligne) par |. Mettre un |partout.

Downgoat
la source
1
Vous pouvez même tout faire en ASCII pour le même nombre d'octets avec S`/comme deuxième étape.
Martin Ender
12

Rubis - 75 82 78 76 75 62 59 58 57 56 octets

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

Enregistré quelques octets grâce à Ventero

Laissez-moi vous expliquer (en \nremplaçant la nouvelle ligne littérale):

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

Cela renvoie implicitement la valeur de la chaîne, chacune étant /remplacée par une nouvelle ligne (par défaut, $/contient une nouvelle ligne)

"|#{...}|"

C'est super simple; c'est juste une chaîne contenant un tuyau, une interpolation de chaîne et un autre tuyau. L'interpolation de chaîne est évaluée

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

Cela remplace chaque numéro par autant d'espaces. Je peux économiser quelques octets en trouvant également des retours à la ligne ici; car hexrenvoie 0 si la chaîne n'est pas un nombre valide, lorsqu'il trouve une nouvelle ligne - c'est-à-dire celle à la fin du résultat de gets- il la remplace par une chaîne de longueur 0, la supprimant effectivement. Sans cela, il y aurait un tuyau de fuite.

$&est une variable magique qui représente le texte complet de la dernière correspondance de variable, ce qui me permet de sauvegarder un octet en éliminant |d|. Je peux enregistrer un autre octet en utilisant .hexau lieu de .to_i, ce qui fonctionne parce que chaque nombre est inférieur à 9, ce qui signifie que hexadécimal et décimal ont les mêmes valeurs.

.chars*?|

Cela met un tuyau entre chaque personnage. Notez que c'est ce qui place les tuyaux de chaque côté des lignes (sauf le premier et le dernier) car les barres obliques, qui finissent par se transformer en sauts de ligne tr, comptent comme des caractères et sont donc entourées de tuyaux. Le ?|juste signifie "la chaîne d'un caractère "|"".

Et c'est tout. C'est un programme franchement scandaleusement simple. Il utilise juste beaucoup d'astuces de syntaxe sournoises.

Action en justice de Fund Monica
la source
2
Vous pouvez enregistrer 4 caractères supplémentaires en appliquant quelques astuces simples: puts"|#{gets.gsub(/\d|\n/){' '*$&.hex}.chars*?|}|".split'/'(bien sûr, remplacez le \npar une nouvelle ligne littérale).
Ventero
5

Pyth - 24 22 21 octets

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

Suite de tests .

+                     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
la source
4

Pyth, 23 octets

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

Essayez-le en ligne!

Comment ça fonctionne:

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
Leaky Nun
la source
4

JavaScript ES7, 80 70 octets

Est une fonction anonyme qui accepte une chaîne en entrée.

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

Approche ES6 de 80 octets uniquement.

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

Explication

Nous utilisons une compréhension de tableau pour parcourir la liste:

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

Cela équivaut à:

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

Si c'est un nombre, nous avons ce nombre d'espaces. Si c'est le cas /, nous avons une nouvelle ligne. Sinon, nous avons le personnage. Ensuite, nous rejoignons la compréhension avec rien pour faire une chaîne.

Ensuite, nous créons un tableau de longueur 3 [,...that,"\n"]. ...éclate la compréhension jointe en caractères. Rejoindre cela donne le résultat.

Conor O'Brien
la source
Tu ne veux pas dire ES6? ES7 n'est pas encore sorti je crois.
ericw31415
@ ericw31415 Il n'est pas sorti, vous avez raison, mais certains navigateurs ont commencé à implémenter une partie de la spécification ES7.
Conor O'Brien
Ah d'accord. Mais votre code n'utilise toujours aucune des fonctionnalités ES7, non?
ericw31415
1
@ ericw31415 En fait, c'est le cas. Les compréhensions de tableau ( [x for(x of a)]) sont ES7.
Conor O'Brien
Les compréhensions de tableau n'étaient pas supprimées de la spécification, MDN dit qu'elles l'étaient
MayorMonty
3

Julia, 62 octets

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

Il s'agit d'une fonction anonyme qui accepte une chaîne et renvoie un tableau de chaînes. Pour l'appeler, affectez-le à une variable.

L'approche est la même que dans intelligent Ruby QPaysTaxes réponse . Nous remplaçons chaque chiffre dans l'entrée par autant d'espaces, nous plaçons |entre chaque caractère, nous plaçons |sur le devant et le dos, et nous divisons en un tableau /.

Essayez-le en ligne!

Alex A.
la source
Oui, j'ai inspiré des choses: D
Fund Monica's Lawsuit
@QPaysTaxes Vous l'avez fait. Bonne solution!
Alex A.
2

05AB1E , 21 octets

Code:

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

De plus 21 octets: '|¹9GNNð×:}S'|«JJ'/¶:.

Utilise l' encodage CP-1252 . Essayez-le en ligne! .

Adnan
la source
2

JavaScript (ES6), 69 67 62 octets

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

Les virgules supplémentaires créent des valeurs vides dans la division externe, ce qui crée les caractères de début et de fin |. Vous avez besoin de deux virgules de fin car les virgules de fin sont facultatives à la fin des listes, donc la première fait toujours partie de l'élément précédent.

Edit: 5 octets enregistrés grâce à @ user81655.

Neil
la source
Ça /[\d/]/g,c=>+c?` `.repeat(c):`\n`marcherait?
user81655
1
@ user81655 Merci, mais je n'aimais pas votre émoticône, je l'ai donc remplacée par un visage ennuyé avec des lunettes.
Neil
1

Rétine , 50 45 octets

C'était amusant haha. Non seulement je suis un noob à Retina, mais aussi dans les regex en général ... Cela peut probablement être beaucoup joué au golf , donc je ferai plus de recherches.

Code:

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

1

/
¶

|

Essayez-le en ligne!

Adnan
la source
Essayez d'utiliser la $*fonctionnalité :)
Leaky Nun
1

Jolf, 28 octets

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

Remplacez-le par le personnage \x05ou essayez-le ici!

Conor O'Brien
la source
1

Python 3.5, 112 octets:

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

Essayez-le en ligne! (Ideone)

R. Kap
la source
1

C, 252 octets

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;}

Essai détaillé en ligne

// 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
la source
1

JavaScript (FireFox 30+), 61

Utiliser une compréhension de tableau qui n'est plus EcmaScript standard

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

Tester

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
la source
1

Lua, 106 octets

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

Non 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
la source
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").."|")pour le même nombre d'octets.
Leaky Nun
print((...):gsub("%d",function(c)return("| "):rep(c)end):gsub("([^%d |])","|%1"):gsub("/","\n").."|")est de 101 octets
Leaky Nun
1

R (hors compétition)

Désolé si ce n'est pas approprié de poster ceci, mais je pensais que c'était cool d'avoir juste une fonction qui traîne qui fonctionne réellement pour cette question sans modification! Il imprime cependant la sortie unicode plutôt que l'ascii. Je ne me souviens pas vraiment pourquoi je l'ai écrit, mais ce n'était pas pour répondre à un défi.

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)

}
Flet
la source
Les règles décrites dans notre centre d'aide stipulent que toutes les solutions aux défis doivent être un candidat sérieux aux critères gagnants utilisés. Pour le golf de code, cela signifie que toutes les réponses doivent être jouées.
Dennis
Techniquement, c'est du golf. Mais pas très bien.
Flounderer
0

Haskell, 110 octets

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

Non 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
la source
0

Java 7, 190 184 octets

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+"|";}

Essai détaillé en ligne

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
la source
Vous pouvez enregistrer quelques octets en utilisant des entiers au lieu des littéraux char dans les comparaisons
Blue
@Blue notes prises
Khaled.K
0

Pyke, 25 20 octets

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

Explication:

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

Essayez-le ici!

Bleu
la source
0

Python, 84 octets

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

Explication:

        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
Bleu
la source
0

> <>, 64 octets

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

4 octets gaspillés en raison de problèmes d'alignement, je ne sais pas comment les jouer au golf. ¯ \ _ (ツ) _ / ¯

Sok
la source