# ASCII Art Chessboard

In this challenge, you are to draw the chessboard below, and allow for moves to be made.

1. Drawing

Each white square has 5x9 spaces.

Each black square has 5x9 colons.

The board is surrounded by a border of colons.

The pieces are 5 characters wide and sit on the bottom row of the square in the centre.

The pawns are 4 characters wide. They sit slightly off centre to the right, with 3 blank squares on the left and 2 blank squares on the right. They sit one line above the bottom of the square.

There shall be no whitespace outside the area of the board, with the exception of an optional trailing newline.

The board and the chessmen shall be drawn exactly as shown, except that:

1. You may subsitute the : in the black squares and border for a different symbol, and you may substitute the @ in the black pieces for a different symbol (but not the same one used for the black squares.)

2. You may move the pawns one character to the left if you wish.

.

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:         :::::::::         :::www:::   _+_   :::::::::         ::::::::::
:  |_|_|  :: _,,:::   (/)   :::)@(:::   )@(   :::(/):::   _,,   ::|_|_|:::
:   |@|   ::"- \~::   |@|   :::|@|:::   |@|   :::|@|:::  "- \~  :::|@|::::
:   |@|   :::|@|:::   |@|   :::|@|:::   |@|   :::|@|:::   |@|   :::|@|::::
:  /@@@\  ::/@@@\::  /@@@\  ::/@@@\::  /@@@\  ::/@@@\::  /@@@\  ::/@@@\:::
::::::::::         :::::::::         :::::::::         :::::::::         :
:::::():::    ()   ::::():::    ()   ::::():::    ()   ::::():::    ()   :
:::::)(:::    )(   ::::)(:::    )(   ::::)(:::    )(   ::::)(:::    )(   :
::::/@@\::   /@@\  :::/@@\::   /@@\  :::/@@\::   /@@\  :::/@@\::   /@@\  :
::::::::::         :::::::::         :::::::::         :::::::::         :
:         :::::::::         :::::::::         :::::::::         ::::::::::
:         :::::::::         :::::::::         :::::::::         ::::::::::
:         :::::::::         :::::::::         :::::::::         ::::::::::
:         :::::::::         :::::::::         :::::::::         ::::::::::
:         :::::::::         :::::::::         :::::::::         ::::::::::
::::::::::         :::::::::         :::::::::         :::::::::         :
::::::::::         :::::::::         :::::::::         :::::::::         :
::::::::::         :::::::::         :::::::::         :::::::::         :
::::::::::         :::::::::         :::::::::         :::::::::         :
::::::::::         :::::::::         :::::::::         :::::::::         :
:         :::::::::         :::::::::         :::::::::         ::::::::::
:         :::::::::         :::::::::         :::::::::         ::::::::::
:         :::::::::         :::::::::         :::::::::         ::::::::::
:         :::::::::         :::::::::         :::::::::         ::::::::::
:         :::::::::         :::::::::         :::::::::         ::::::::::
::::::::::         :::::::::         :::::::::         :::::::::         :
::::::::::         :::::::::         :::::::::         :::::::::         :
::::::::::         :::::::::         :::::::::         :::::::::         :
::::::::::         :::::::::         :::::::::         :::::::::         :
::::::::::         :::::::::         :::::::::         :::::::::         :
:         :::::::::         :::::::::         :::::::::         ::::::::::
:    ()   ::::():::    ()   ::::():::    ()   ::::():::    ()   ::::()::::
:    )(   ::::)(:::    )(   ::::)(:::    )(   ::::)(:::    )(   ::::)(::::
:   /__\  :::/__\::   /__\  :::/__\::   /__\  :::/__\::   /__\  :::/__\:::
:         :::::::::         :::::::::         :::::::::         ::::::::::
::::::::::         :::::::::   www   :::_+_:::         :::::::::         :
:::|_|_|::   _,,   :::(/):::   ) (   :::) (:::   (/)   :::_,,:::  |_|_|  :
::::| |:::  "- \~  :::| |:::   | |   :::| |:::   | |   ::"- \~::   | |   :
::::| |:::   | |   :::| |:::   | |   :::| |:::   | |   :::| |:::   | |   :
:::/___\::  /___\  ::/___\::  /___\  ::/___\::  /___\  ::/___\::  /___\  :
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


2. Moving

The columns are labelled A-H from left to right and 1 to 8 from bottom to top. The user shall be able to enter a move in the following form:

<start column><start row><space><destination column><destination row>


For example B1 C3 means move the knight to the square in front of the bishop's pawn (assuming the game has just started).

Alternatively the ICCF system can be used, in which the columns are labelled 1 to 8 instead of A to H. So the knight move mentioned above becomes 21 33.

The following image (source) clarifies both systems:

The move shall be executed and the new board displayed. Any resulting capture shall occur with the moving chessman removing the chessman on the destination square from the board.

There is no need to check for a legal chess move, as that has been covered in other challenges: Smallest chess program and The smallest Chess arbiter If the user tries to move from an empty square, your program or function should ignore the move. If the user tries to capture a friendly piece, you can either ignore the move or allow the stationary piece to be captured.

There is no need to support en passant or castling.

You may assume the input will be well formed, i.e. always in the format described above. Letters will always be in the same case, you can decide what case that is.

3. Scoring and Bonuses

This is code golf. Shortest code wins.

-10% bonus if your program or function allows for promotion. The user enters a third input, this time one of the following letters: Q B R N. This should only be allowed if the move ends with a pawn on the last row. The pawn is exchanged for the named piece. QBRN.

-10% bonus if your program or function implements a special "undo" move for reversal of moves (as far back as the beginning of the game if required.) Obviously it is possible for amateur players to make illegal moves, and they may wish to undo them. You may define the input the user must give for this "undo" move (it must always be the same.) Behaviour is undefined if the user tries to undo beyond the beginning of the game.

Bonuses sum, i.e. if you go for both bonuses you get -20%.

• At first you say "enter a move", and for me it means "just 1 move". Then there is the bonus for undo "as far as the beginning": so it's a complete serie of moves, not just one... please clarify – edc65 Aug 22 '15 at 16:48
• @edc65 it's a complete series of moves. See the first line "allow for moves to be made." The one thing I didn't specify is the exit condition for the loop. It might have been an idea to stop when one of the kings is captured, but the existing answer has an infinite loop, which is acceptable under the spec as written, so I'll leave it. – Level River St Aug 22 '15 at 19:04
• The formatting on the two knights on black squares does not match. Which is correct? – JWT Sep 14 '15 at 2:31
• @JWT wow, no-one noticed before! At this stage I'll have to accept both. I see you've golfed your answer a bit more. Before I test your answer and change the acceptance, have you finished? – Level River St Sep 14 '15 at 7:35
• @ steveverril I'm finished, yes. – JWT Sep 18 '15 at 11:08

# Octave, 776 688 bytes

688:

• functions inlined into main loop (both were used only once),
• used cell notation {'foo','bar'}{i} in place of slightly longer ['foo';'bar'](i,:)

Still none of bonuses implemented.

Uses ICCF system.

There may be no leading spaces in the move description and the source and destination field must be separated by a single whitespace, so 42 44 is correct, while  42 44 and 42 44 are not.

R=@repmat;s=[t='BFJbRJFB';R(('@    A')',1,8);t+1]';while 1q=' ';c=R(':',42,74);m=R([m=R(q,5,9) l=m+26;l m],4,4);c(2:41,2:73)=m;for i=1:8 for j=1:8 f=s(i,j);z=@(c)bitand(+f,c);if z(64)b=z(1)+1;W={') (',')@('}{b};U=43-5*j;Z=9*i-2;T=Z-2:Z;Q=Z-3:Z+1;if z(2)c(U+3,Q)={'/___\','/@@@\'}{b};a=c(U+2,T)={'| |','|@|'}{b};if z(4)c(U+1,Q)='"- \~';c(U,Z-3:Z)=' _,,';else c(U+1,T)=a;if z(8)c(U,T)='(/)';elseif z(16)||z(32)c(U,T)=W;c(U-1,T)={'_+_','www'}{1+z(32)/32};else c(U,Q)='|_|_|';end
end
else c(U+2,Z-2:Z+1)={'/__\','/@@\'}{b};c(U:U+1,Z-1:Z)=['()';')('];end;end;end;end;c
m=input(q,'s')-'0';x=m(1);y=m(2);X=m(4);Y=m(5);if s(x,y)~=q&&(s(X,Y)==q||mod(s(x,y)-s(X,Y),2))s(X,Y)=s(x,y);s(x,y)=q;end
end


Somewhat ungolfed version:

# draw an empty chessboard
function n=cb
R=@repmat;
n=R(':',42,74);
m=R([m=R(' ',5,9) m+26;m+26 m],4,4);
n(2:41,2:73)=m;
end

# function n=put(n,f,c,r) :
#
# put a chessman f on column c and row r of chessboard n,
# returning new chessboard
# chessman is described by single character defined following way
# (please excuse naming bits by value rather than position):
# bit valued  127 -     unused
# bit valued  64  -     0 = field empty, 64 = field occupied.
# bits valued 32,16,8 - 0 = rook, 8 = bishop, 16 = king, 32 = queen
# bit valued  4 -       0 = not knight 4 = knight (only checked if "other piece" bit is set)
# bit valued  2 -       0 = pawn       2 = other piece
# bit valued  1 -       0 = white      1 = black

# this gives the following chars:

# pawns   - 64      (+1)  => @ , A
# knights - 64+4+2  (+1)  => F , G
# rooks   - 64+2    (+1)  => B , C
# bishops - 64+8+2  (+1)  => J , K
# kings   - 64+16+2 (+1)  => R , S
# queens  - 64+32+2 (+1) =>  b , a
# empty space - any character with bit valued 64 unset (space char does)

function n=put(n,f,c,r)
z=@(n)bitand(f-0,n);
if z(64)
b=z(1);
W=') ()@('(1+3*b:3+3*b);
R=5*r;C=9*c;
if z(2)
n(46-R,C-5:C-1)='/___\/@@@\'(1+5*b:5+5*b);
a=n(45-R,C-4:C-2)='| ||@|'(1+3*b:3+3*b);
if z(4) # knight
n(44-R,C-5:C-1)='"- \~';
n(43-R,C-5:C-2)=' _,,';
else
n(44-R,C-4:C-2)=a;
if z(8) # bishop
n(43-R,C-4:C-2)='(/)';
elseif z(16) # king
n(43-R,C-4:C-2)=W;
n(42-R,C-4:C-2)='_+_';
elseif z(32) # queen
n(43-R,C-4:C-2)=W;
n(42-R,C-4:C-2)='www';
else  # rook
n(43-R,C-5:C-1)='|_|_|';
end
end
else
n(45-R,C-4:C-1)='/  \/@@\'(1+4*b:4+4*b);
n(43-R:44-R,C-3:C-2)=['()';')('];
end
end
end

# here we can easily define the chessboard.
s=['BFJbRJFB';repmat(('@    A')',1,8);'CGKcSKGC']';
c=cb;for i=1:8 for j=1:8 c=put(c,s(i,j),i,j);end;end
c

# We scan five characters. They must be positions in ICCF without leading spaces separated by single space.
while m=input('','s')-'0'
x=m(1)
y=m(2)
X=m(4)
Y=m(5)
# if the move is not allowed (capture piece of the same color or the start field is blank,
# do nothing
if s(x,y)==' ' || (s(X,Y) ~=' ' && mod(s(x,y)-s(X,Y),2)==0) continue; end;
# make the move
s(X,Y)=s(x,y);
s(x,y)=' ';
# redraw the board
c=cb;for i=1:8 for j=1:8 c=put(c,s(i,j),i,j);
end end
c
end

• I ran this on ideone.com and got the board displayed but couldn't get it to accept any input. It works great at tutorialspoint.com/codingground.htm (except you have the king and queen reversed - any seasoned chess player will tell you it makes a difference.) I'd give you an extra +1 for not allowing capture of a friendly piece, and one more for the decent explanation, if I could. – Level River St Aug 23 '15 at 20:18
• @steveverrill Indeed, king and queen positions were reversed, thanks for pointing this out. It's fixed now. – pawel.boczarski Aug 24 '15 at 6:46

# Ruby, 715696693 683 bytes

This is a fairly messy solution but I don't have the patience to clean it up further at the moment.

Neither of the bonuses done.

Uses ICCF system.

a,b,c=->f,x,y,p{p.map{|ln|ln.gsub(/\d/){|z|f*(z.to_i)}.tr('AB',x+y)}},Array.new(64){|i|((i%56<8?[4,2,3,5,6,3,2,4][i%56]:(i-8)%40<8?1:0)<<2)+(i<16?2:0)},':'*74
loop{puts c
b.each_slice(8).with_index{|r,y|d,*e=r.map.with_index{|v,x|a[*([[' '],[':']][(x+y)%2]+[[' ','_'],['@','@']][v&2==2?1:0]+[('9@9@9@9@9;9@4()3@4)(3@3/BB\2@9;9@3_,,3@2"- \~2@3|A|3@2/BBB\2;9@3(/)3@3|A|3@3|A|3@2/BBB\2;9@2|_|_|2@3|A|3@3|A|3@2/BBB\2;3www3@3)A(3@3|A|3@3|A|3@2/BBB\2;3_+_3@3)A(3@3|A|3@3|A|3@2/BBB\2'.split(';').map{|s|s.split '@'})[v>>2]])]}
d.zip(*e).each{|r|puts ":#{r.join}:"}}
puts c
gets.scan(/(.)(.) (.)(.)/){|f,g,h,i|j,k=63+(f.to_i)-(g.to_i)*8,63+(h.to_i)-(i.to_i)*8
b[k],b[j]=b[j]>0?b[j]: b[k],0}}

• Excellent, seems to work perfectly! – Level River St Aug 22 '15 at 6:03
• @LevelRiverSt Looks like this answer is shorter than the currently accepted one. – Erik the Outgolfer Nov 9 '17 at 22:33

## Python, 1136890 753 bytes

Apologies for the partial answer but I'm a newbie and I really enjoyed this challenge. I know it's probably really verbose but here's my rough draft:

y=':'*9
z=' '*9
b='::/___\::'
c=':::|@|:::'
d=':::)@(:::'

ps = {'r': [y,'::|*|*|::', c, c,b],'n': [y,':::,,::::', '::"- \~::', c,b],'b': [y,':::(/):::',c,c,b],'k': [':::www:::',d,c,c,b],'q': [':::*+*:::',d,c,c,b],'p': [y, '::::():::','::::)(:::',':::/__\::',y]}

def cell(p,c):
if p == '!':
return ([z]*5,[y]*5)[c]
s = []
for l in ps[p.lower()]:
l = (l.replace('@', ' '), l.replace('_', '@'))[p.islower()]
l = (l.replace(':', ' '), l)[c].replace('*', '_')
s.append(l)
return s

b = {8:'rnbkqbnr',7:'p'*8,2:'P'*8}
b[1] = b[8].upper()
for i in range(3,7):
b[i] = '!'*8

o=[y*8]
c=0
for r in b:
l=['']*5
for p in b[r]:
cc=cell(p,c)
for i in range(0,5):
l[i]+=cc[i]
c=not c
o.extend(l)
c=not c
o.append(o[0])
for l in o:
print ':'+l+':'

• Thanks for the answer. It is our custom to include a title line on answers, with the language and byte count. What language is this? It looks like python but I can't get it to run on ideone.com – Level River St Aug 21 '15 at 23:19
• Remove all spaces around =, and if a for or an if only has one line inside it, it can all go on the same line. Take a look at Tips for Golfing in Python. – mbomb007 Aug 26 '15 at 18:53