17
\$\begingroup\$

You should write a program or function which receives a string representing a chessboard with only pawns as input and outputs or returns whether any capture is possible on the board.

Input is in a FEN-like notation describing positions of white and black pawns with no other pieces present. You should decide if there is a pawn which can capture an enemy one.

Each rank is described, starting with rank 8 and ending with rank 1; within each rank, the contents of each square are described from file "a" through file "h". Each pawn is identified by a single letter (white pawn = "P", black pawn = "p", ). Empty squares are noted using digits 1 through 8 (the number of empty squares), and "/" separates ranks. (partially taken from Wikipedia)

For example

8/pppppppp/8/8/4P3/8/PPPP1PPP/8

describes the board

--------

pppppppp


    P   

PPPP PPP

--------

A white pawn can capture a black one if the black one is positioned diagonally up from it (black is up-left or up-right) and a black pawn can capture a white one if the white one is diagonally below from it (white is down-left or down-right). No other capture move (en passant) should be considered.

Input

  • A FEN-like string consisting of the characters 12345678pP/.
  • The input describes the pawns of a valid chess game position. This means (among other more complex constraints) there will be at most 8 pawns for each side and no pawns on ranks 1 and 8.

Output

  • If there is a possible capture for either side you should output a truthy value and a falsy value otherwise.

Examples

Inputs with truthy output (one per line)

8/7p/6P1/8/8/8/8/8
8/8/p7/1P6/3P3p/8/8/8
8/2P5/8/4P1p1/2p2P2/3p4/3p1P2/8
8/P7/8/5P2/2pp4/3P2p1/3pP3/8
8/P7/p7/p1P1P3/1P3p2/8/1p6/8
8/4p1P1/2P2P1P/2p1pPpp/8/6P1/pP1p4/8

Inputs with falsy output (one per line)

8/8/8/8/8/8/8/8
8/7P/6p1/8/8/8/8/8
8/7p/7P/8/8/8/8/8
8/pppppppp/8/8/8/8/PPPPPPPP/8
8/p7/8/1p6/5P2/8/8/8
8/p7/P7/2P1p1p1/2p5/8/PP6/8

This is code golf so the shortest entry wins.

\$\endgroup\$
  • \$\begingroup\$ Shouldn't the example board be described by 8/pppppppp/8/8/8/7P/PPPP1PPP/8 ? \$\endgroup\$ – TheNumberOne Sep 30 '15 at 14:24
  • \$\begingroup\$ @TheNumberOne No, 7P would mean the pawn is on the last, 8th file. (The diagram was incorrect though, I corrected that.) \$\endgroup\$ – randomra Sep 30 '15 at 14:47
  • 1
    \$\begingroup\$ I feel removing en passant makes this a less interesting puzzle. \$\endgroup\$ – corsiKa Sep 30 '15 at 21:03
6
\$\begingroup\$

Pyth, 25 bytes

/smC,>JsXz`M9*LN9dJ,8T"Pp

Test suite

Steps:

Transform the input by replacing the digits with the equivalent number of quote marks (N). This is saved in J. We then slice off the first 8 or 10 characters, and zip the result with the original. Any capturing pair will be transformed into "Pp", so we then find the count of that string in the resultant list. This is the output.

As a bonus, this actually counts the number of captures possible in the input.

\$\endgroup\$
  • \$\begingroup\$ Another 25 solution: :sXz`M9*LN9"p.{7}(..)?P"1 Sadly the last parameter of : is not optional (I think it should be). \$\endgroup\$ – Jakube Sep 30 '15 at 18:16
  • 3
    \$\begingroup\$ @Jakube Will do. \$\endgroup\$ – isaacg Sep 30 '15 at 18:49
12
+750
\$\begingroup\$

Retina, 33 29 bytes

T`d`w
)`\d
$0.
_

p.{7}(..)?P

To run the code from a single file, use the -s flag.

Should be easily beatable by something like Perl where the expansion of digits into strings of spaces (or other characters) doesn't take up 17 bytes.

The output is positive (truthy) if there is a possible capture and zero (falsy) if there isn't.

Explanation

T`d`w
)`\d
$0.

This is a loop of two stages. The first one is a transliteration stage which decrements each digit, and turns zeroes to underscores. Why? Because d and w expand to the following two lines:

0123456789
_0123456789AB...YZab...yz

If the target set of a transliteration stage is longer than the source set, the extraneous characters are ignored, hence the decrementing behaviour (honestly, it was just luck that I decided to put the underscore in front of the digits when expanding the w character class).

Then the second stage is a replacement, which appends a . to each digit. That means that for each digit n, n periods are added before that digit is turned into an underscore.

_
<empty>

This just gets rid of the underscores.

p.{7}(..)?P

Finally, we find the matches. Since we're ignoring en passant, captures are only possible if there is a p and then a P diagonally below it. In the linear string, this simply means that there must be 7 or 9 characters between the two pawns. This matched with .{7}(..)? (i.e. match 7 characters and then, optionally, match another two).

Such a match stage returns the number of matches it found.

\$\endgroup\$
  • \$\begingroup\$ Re "Should be easily beatable by something like Perl where the expansion of digits into strings of spaces (or other characters) doesn't take up 17 bytes.": I can't get Perl to even tie your score, let alone beat it. (My Perl answer.) But maybe someone else can.... \$\endgroup\$ – msh210 Jun 22 '16 at 23:06
3
\$\begingroup\$

Javascript, 272 characters

function h(t){b=[[]];for(i=-1;i++<7;){c=0;b.push(l=[]);for(j=-1;j++<7;){o=t.split('/')[i][j];switch(o){case'P':l[c++]=-1;break;case'p':l[c++]=1;break;default:c+=parseInt(o);}}}b.push([]);for(i=1;i<9;i++)for(j=0;j<8;j++)if((p=b[i][j])&&(b[i+p][j-1]||b[i+p][j+1]))return 1;}

There's probably a lot of room for improvement.

\$\endgroup\$
3
\$\begingroup\$

Ruby, 145 123 46 bytes

->b{b.gsub(/\d/){|x|?.*x.to_i}=~/p.{7}(..)?P/}

I don't know why I didn't think about this in the first place. It's much shorter and also pretty readable.

Here's the test: http://ideone.com/Gzav8N


The old approach:

->b{l={}
r=p
b.split(?/).map{|s|c={}
i=0
s.chars.map{|x|n=x.to_i;c[i]=x;i+=n<1?1:n;x==?P&&r||=l[i-2]==?p||l[i]==?p}
l=c}
r}

Online test: http://ideone.com/9L01lf, version before golfing: http://ideone.com/CSmqlW

A history of modifications is available here.

\$\endgroup\$
2
\$\begingroup\$

ES6, 64 bytes

An appropriate byte count, if it lasts!

f=s=>/p.{7}(..)?P/.test(s.replace(/\d/g,n=>"        ".slice(-n)))

I actually thought of this solution without reading the other answers first, but I won't mind if you don't believe me.

\$\endgroup\$
0
\$\begingroup\$

Perl 5, 30 bytes

29, plus 1 for -pe instead of -e

s/\d/1x$&/ge;$_=/p.{7}(..)?P/

A Perl copy of w0lf's Ruby answer.

\$\endgroup\$
0
\$\begingroup\$

PHP, 94 87 80 bytes

for(;$i++<8;)$t[$i]=$s.=" ";echo preg_match("#p.{7}(..)?P#",strtr($argv[1],$t));

That loop+strtr is a lot shorter than preg_replace_callback with str_pad.

\$\endgroup\$
0
\$\begingroup\$

Jelly, 88 84 79 72 69 65 64 63 60 bytes

Definitely room for improvement. Noncompeting because Jelly was created before the question. Thanks to @lirtosiast for telling me that!

ØDṖḊ
”_x
e1£¬
1£iЀ2Ŀ€
x"3Ŀ€;"ÇFṣ”/
w€⁾pPn0
5ĿUŒDÇ
5ĿŒD6ĿoÇS
\$\endgroup\$

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.