Find Chess960 starting position identifier: Difference between revisions

m
(→‎{{header|Go}}: Add problematic examples.)
m (→‎{{header|Wren}}: Minor tidy)
 
(37 intermediate revisions by 7 users not shown)
Line 23:
RQNBBKRN = 601
RNQBBKRN = 617
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">
F validate_position(String candidate)
assert(candidate.len == 8, ‘candidate position has invalid len = ’candidate.len)
 
V valid_pieces = [‘R’ = 2, ‘N’ = 2, ‘B’ = 2, ‘Q’ = 1, ‘K’ = 1]
assert(Set(Array(candidate)) == Set(valid_pieces.keys()), ‘candidate position contains invalid pieces’)
L(piece_type) valid_pieces.keys()
assert(candidate.count(piece_type) == valid_pieces[piece_type], ‘piece type '’piece_type‘' has invalid count’)
 
V bishops_pos = enumerate(Array(candidate)).filter((index, value) -> value == ‘B’).map((index, value) -> index)
assert(bishops_pos[0] % 2 != bishops_pos[1] % 2, ‘candidate position has both bishops in the same color’)
 
assert(candidate.filter(piece -> piece C ‘RK’) == [‘R’, ‘K’, ‘R’], ‘candidate position has K outside of RR’)
 
F calc_position(String start_pos)
validate_position(start_pos)
V subset_step1 = start_pos.filter(piece -> piece !C ‘QB’)
V nights_positions = enumerate(subset_step1).filter((index, value) -> value == ‘N’).map((index, value) -> index)
V nights_table = [(0, 1) = 0,
(0, 2) = 1,
(0, 3) = 2,
(0, 4) = 3,
(1, 2) = 4,
(1, 3) = 5,
(1, 4) = 6,
(2, 3) = 7,
(2, 4) = 8,
(3, 4) = 9]
V n = nights_table[(nights_positions[0], nights_positions[1])]
 
V subset_step2 = start_pos.filter(piece -> piece != ‘B’)
V q = subset_step2.index(‘Q’)
 
V dark_squares = enumerate(Array(start_pos)).filter((index, piece) -> index C Array((0.<9).step(2))).map((index, piece) -> piece)
V light_squares = enumerate(Array(start_pos)).filter((index, piece) -> index C Array((1.<9).step(2))).map((index, piece) -> piece)
V d = dark_squares.index(‘B’)
V l = light_squares.index(‘B’)
 
R 4 * (4 * (6*n + q) + d) + l
 
L(example) [‘QNRBBNKR’, ‘RNBQKBNR’, ‘RQNBBKRN’, ‘RNQBBKRN’]
print(‘Position: ’example‘; Chess960 PID= ’calc_position(example))
</syntaxhighlight>
 
{{out}}
<pre>
Position: QNRBBNKR; Chess960 PID= 105
Position: RNBQKBNR; Chess960 PID= 518
Position: RQNBBKRN; Chess960 PID= 601
Position: RNQBBKRN; Chess960 PID= 617
</pre>
 
=={{header|BASIC}}==
Line 29 ⟶ 84:
Unlike the solution for the reverse task, which uses DO/LOOP and so requires at least Commodore BASIC 3.5, this should work on any version.
 
<langsyntaxhighlight lang="basic">100 REM DERIVE SP-ID FROM CHESS960 POS
110 READ A$: IF A$="" THEN END
120 PRINT A$":";
Line 84 ⟶ 139:
630 NEXT I
640 SP = 96*N+16*Q+4*D+L
650 RETURN</langsyntaxhighlight>
 
{{Out}}
Line 97 ⟶ 152:
 
==={{header|FreeBASIC}}===
<langsyntaxhighlight lang="freebasic">Sub SP_ID(PosicPiezas As String)
Dim As String pieza
Dim As Integer pQ(), pK(), pB(), pN(), pR(), i, j
Line 164 ⟶ 219:
Print
SP_ID("RNQBBKRN")
Sleep</langsyntaxhighlight>
{{out}}
<pre>QNRBBNKR has SP_ID of 105
Line 178 ⟶ 233:
{{works with|QBasic|1.1}}
{{trans|Commodore BASIC}}
<langsyntaxhighlight lang="qbasic">CLSCls
PRINTPrint "ENTEREnter STARTstart ARRAYarray ASas SEENseen BYby WHITEwhite."
120 PRINTPrint
PRINTPrint "STARTINGStarting ARRAY:array";
INPUTInput ARAr$
Print
PRINT
IFIf LENLen(ARAr$) = 0 THENThen ENDEnd
IFIf LENLen(ARAr$) = 8 THENThen 170
PRINTPrint "ARRAYArray MUSTmust BEbe 8 PIECESpieces.": GOTOGoTo 120
 
170 FORFor I = 1 TOTo 8
P$ = MIDMid$(ARAr$, I, 1)
IF If P$ = "Q" THENOr P$ = "q" Then Q(Q) = I: Q = Q + 1: GOTOGoTo 250
IF If P$ = "K" THENOr P$ = "k" Then K(K) = I: K = K + 1: GOTOGoTo 250
IF If P$ = "B" THENOr P$ = "b" Then B(B) = I: B = B + 1: GOTOGoTo 250
IF If P$ = "N" THENOr P$ = "n" Then N(N) = I: N = N + 1: GOTOGoTo 250
IF If P$ = "R" THENOr P$ = "r" Then R(R) = I: R = R + 1: GOTOGoTo 250
PRINT Print "ILLEGALIllegal PIECEpiece '"; P$; "'.": GOTOGoTo 120
250 NEXTNext I
 
IFIf K <> 1 THENThen PRINTPrint "THEREThere MUSTmust BEbe EXACTLYexactly ONEone KINGKing.": GOTOGoTo 120
IFIf Q <> 1 THENThen PRINTPrint "THEREThere MUSTmust BEbe EXACTLYexactly ONEone QUEENQueen.": GOTOGoTo 120
IFIf B <> 2 THENThen PRINTPrint "THEREThere MUSTmust BEbe EXACTLYexactly TWOtwo BISHOPSBishops.": GOTOGoTo 120
IFIf N <> 2 THENThen PRINTPrint "THEREThere MUSTmust BEbe EXACTLYexactly TWOtwo KNIGHTSKnights.": GOTOGoTo 120
IFIf R <> 2 THENThen PRINTPrint "THEREThere MUSTmust BEbe EXACTLYexactly TWOtwo ROOKSRooks.": GOTOGoTo 120
IFIf (K(0) > R(0)) ANDAnd (K(0) < R(1)) THENThen 330
PRINTPrint "KINGKing MUSTmust BEbe BETWEENbetween THEthe ROOKSRooks.": GOTOGoTo 120
 
330 IFIf (B(0) ANDAnd 1) <> (B(1) ANDAnd 1) THENThen 350
PRINTPrint "BISHOPSBishops MUSTmust BEbe ONon OPPOSITEopposite COLORScolors.": GOTOGoTo 120
 
350 FORFor I = 0 TOTo 1
N = N(I)
IF If N(I) > Q(I) THENThen N = N - 1
FOR For J = 0 TOTo 1
IF If N(I) > B(J) THENThen N = N - 1
Next J
NEXT J
N(I) = N
NEXTNext I
N0 = 1: N1 = 2
 
FORFor N = 0 TOTo 9
IFIf N0 = N(0) ANDAnd N1 = N(1) THENThen 490
N1 = N1 + 1
IFIf N1 > 5 THENThen N0 = N0 + 1: N1 = N0 + 1
NEXTNext N
490 Q = Q(0) - 1
 
FORFor I = 0 TOTo 1
IFIf Q(0) > B(I) THENThen Q = Q - 1
NEXTNext I
 
FORFor I = 0 TOTo 1
B = B(I) - 1
IFIf B ANDAnd 1 THENThen L = INTInt(B / 2)
IFIf (B ANDAnd 1) = 0 THENThen D = B / 2
NEXTNext I
PRINTPrint "SPIDSP-ID ="; 96 * N + 16 * Q + 4 * D + L
End
END</lang>
 
</syntaxhighlight>
{{out}}
<pre>Enter start array as seen by White.
 
Starting array? qnrbbnkr
 
SP-ID = 105
 
Starting array? RNBQKBNR
 
SP-ID = 518
 
Starting array? RQNBBKRN
 
SP-ID = 601
 
Starting array? RNQBBKRN
 
SP-ID = 617
</pre>
 
=={{header|C++}}==
<syntaxhighlight lang="c++">
#include <algorithm>
#include <cstdint>
#include <stdexcept>
#include <iostream>
#include <string>
#include <map>
#include <set>
#include <vector>
 
const std::set<std::pair<char, int32_t>> correct_pieces = { std::make_pair('R', 2), std::make_pair('N', 2),
std::make_pair('B', 2), std::make_pair('Q', 1), std::make_pair('K', 1) };
 
std::map<std::vector<int32_t>, int32_t> knights_table = {
{ std::vector<int32_t>{ 0, 1 }, 0 },
{ std::vector<int32_t>{ 0, 2 }, 1 },
{ std::vector<int32_t>{ 0, 3 }, 2 },
{ std::vector<int32_t>{ 0, 4 }, 3 },
{ std::vector<int32_t>{ 1, 2 }, 4 },
{ std::vector<int32_t>{ 1, 3 }, 5 },
{ std::vector<int32_t>{ 1, 4 }, 6 },
{ std::vector<int32_t>{ 2, 3 }, 7 },
{ std::vector<int32_t>{ 2, 4 }, 8 },
{ std::vector<int32_t>{ 3, 4 }, 9 } };
 
void validate(const std::string& position) {
if ( position.length() != 8 ) {
throw std::invalid_argument("Chess position has invalid length" + std::to_string(position.length()));
}
 
std::map<char, int32_t> position_map;
for ( const char& ch : position ) {
if ( position_map.find(ch) == position_map.end() ) {
position_map.emplace(ch, 1);
} else {
position_map[ch]++;
}
}
 
std::set<std::pair<char, int32_t>> pieces;
std::transform(position_map.begin(), position_map.end(), std::inserter(pieces, pieces.begin()),
[](const std::pair<char, int32_t>& entry) { return entry; });
 
if ( pieces != correct_pieces ) {
throw std::invalid_argument("Chess position contains incorrect pieces.");
}
 
const std::vector<uint64_t> bishops = { position.find_first_of('B'), position.find_last_of('B') };
if ( ( bishops[1] - bishops[0] ) % 2 == 0 ) {
throw std::invalid_argument("Bishops must be on different coloured squares.");
}
 
std::vector<uint64_t> rook_king =
{ position.find_first_of('R'), position.find_first_of('K'), position.find_last_of('R') };
if ( ! ( rook_king[0] < rook_king[1] && rook_king[1] < rook_king[2] ) ) {
throw std::invalid_argument("The king must be between the two rooks.");
}
}
 
int32_t calculate_SPID(std::string& position) {
 
const int32_t index_one = position.find_first_of('B');
const int32_t index_two = position.find_last_of('B');
const int32_t D = ( index_one % 2 == 0 ) ? index_one / 2 : index_two / 2;
const int32_t L = ( index_one % 2 == 0 ) ? index_two / 2 : index_one / 2;
 
position.erase(remove_if(position.begin(), position.end(),
[](const char& ch){ return ch == 'B'; }), position.end());
const uint64_t Q = position.find_first_of('Q');
 
position.erase(remove_if(position.begin(), position.end(),
[](const char& ch){ return ch == 'Q'; }), position.end());
const int32_t N =
knights_table[ { (int32_t) position.find_first_of('N'), (int32_t) position.find_last_of('N') } ];
 
return 96 * N + 16 * Q + 4 * D + L;
}
 
int main() {
std::vector<std::string> positions = { "QNRBBNKR", "RNBQKBNR", "RQNBBKRN", "RNQBBKRN" };
 
for ( std::string& position : positions ) {
validate(position);
std::cout << "Position " << position << " has Chess960 SP-ID = " << calculate_SPID(position) << std::endl;
}
}
</syntaxhighlight>
{{ out }}
<pre>
Position QNRBBNKR has Chess960 SP-ID = 105
Igual que la entrada de Commodore BASIC.
Position RNBQKBNR has Chess960 SP-ID = 518
Position RQNBBKRN has Chess960 SP-ID = 601
Position RNQBBKRN has Chess960 SP-ID = 617
</pre>
 
=={{header|Common Lisp}}==
<syntaxhighlight lang="lisp">; make sure string is a valid Chess960 starting array
(defun valid-array-p (start-array)
(and (string-equal (sort (copy-seq start-array) #'string-lessp) "BBKNNQRR") ; right pieces
(not (equal (mod (position #\B start-array) 2) ; bishops on opposite colors
(mod (position #\B start-array :from-end t) 2)))
(< (position #\R start-array) (position #\K start-array)) ; king between two rooks
(< (position #\K start-array) (position #\R start-array :from-end t))))
 
; find Start Position IDentifier for a Chess960 setup
(defun sp-id (start-array)
(if (not (valid-array-p start-array))
-1
(let* ((bishopless (remove #\B start-array))
(queenless (remove #\Q bishopless))
(n5n-pattern (substitute-if-not #\- (lambda (ch) (eql ch #\N)) queenless))
(n5n-table '("NN---" "N-N--" "N--N-" "N---N" "-NN--" "-N-N-" "-N--N" "--NN-" "--N-N" "---NN"))
(knights (position n5n-pattern n5n-table :test #'string-equal))
(queen (position #\Q bishopless))
(left-bishop (position #\B start-array))
(right-bishop (position #\B start-array :from-end t)))
 
; map each bishop to its color complex and position within those four squares
(destructuring-bind (dark-bishop light-bishop)
(mapcar (lambda (p) (floor p 2))
(cond ((zerop (mod left-bishop 2)) (list left-bishop right-bishop))
(t (list right-bishop left-bishop))))
 
(+ (* 96 knights) (* 16 queen) (* 4 dark-bishop) light-bishop)))))
 
(loop for ary in '("RNBQKBNR" "QNRBBNKR" "RQNBBKRN" "RNQBBKRN") doing
(format t "~a: ~a~%" ary (sp-id ary)))
</syntaxhighlight>
 
{{Out}}
<pre>RNBQKBNR: 518
QNRBBNKR: 105
RQNBBKRN: 601
RNQBBKRN: 617</pre>
 
=={{header|Factor}}==
{{works with|Factor|0.99 2021-06-02}}
<langsyntaxhighlight lang="factor">USING: assocs assocs.extras combinators formatting kernel
literals math math.combinatorics sequences sequences.extras sets
strings ;
Line 309 ⟶ 517:
"RNBQKBNR" sp-id.
"RQNBBKRN" sp-id.
"RNQBBKRN" sp-id.</langsyntaxhighlight>
{{out}}
<pre>
Line 320 ⟶ 528:
=={{header|Go}}==
{{trans|Wren}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 411 ⟶ 619:
fmt.Printf("%s or %s has SP-ID of %d\n", pieces, g2l(pieces), spid(pieces))
}
}</langsyntaxhighlight>
 
{{out}}
Line 422 ⟶ 630:
 
=={{header|J}}==
Implementation:<langsyntaxhighlight Jlang="j">REF=: {{
'N Q B0 B1'=. 0 6 4 4 #: y
s=. 'B' (0 1+2*B0,B1)} 8#' '
Line 430 ⟶ 638:
}}"0 i.960
 
c960=: {{ r=. REF i. rplc&((u:9812+i.12);&>12$'KQRBNP') 7 u:deb y assert. r<#REF }}</langsyntaxhighlight>
 
Examples:
<langsyntaxhighlight Jlang="j"> c960'♕♘♖♗♗♘♔♖'
105
c960'♛♞♜♝♝♞♚♜'
Line 442 ⟶ 650:
601
c960'RNQBBKRN'
617</langsyntaxhighlight>
 
=={{header|Java}}==
 
<syntaxhighlight lang="java">
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
 
public final class Chess960SPID {
 
public static void main(String[] aArgs) {
String[] positions = { "QNRBBNKR", "RNBQKBNR", "RQNBBKRN", "RNQBBKRN" };
createKnightsTable();
createCorrectPieces();
for ( String position : positions ) {
validate(position);
System.out.println("Position " + position + " has Chess960 SP-ID = " + calculateSPID(position));
}
}
private static void validate(String aPosition) {
if ( aPosition.length() != 8 ) {
throw new AssertionError("Chess position has invalid length: " + aPosition.length() + ".");
}
Map<Character, Integer> pieces = new HashMap<Character, Integer>();
for ( char ch : aPosition.toCharArray() ) {
pieces.merge(ch, 1, (oldV, newV) -> oldV + 1);
}
if ( ! pieces.entrySet().equals(correctPieces) ) {
throw new AssertionError("Chess position contains incorrect pieces.");
}
List<Integer> bishops = List.of(aPosition.indexOf('B'), aPosition.lastIndexOf('B'));
if ( ( bishops.get(1) - bishops.get(0) ) % 2 == 0 ) {
throw new AssertionError("Bishops must be on different coloured squares.");
}
List<Integer> rookKing = List.of(aPosition.indexOf('R'), aPosition.indexOf('K'), aPosition.lastIndexOf('R'));
if ( ! ( rookKing.get(0) < rookKing.get(1) && rookKing.get(1) < rookKing.get(2) ) ) {
throw new AssertionError("The king must be between the two rooks.");
}
}
private static int calculateSPID(String aPosition) {
String noBishopsOrQueen = retainIf(aPosition, s -> s != 'B' && s != 'Q');
final int N = knightsTable.get(List.of(noBishopsOrQueen.indexOf('N'), noBishopsOrQueen.lastIndexOf('N')));
String noBishops = retainIf(aPosition, s -> s != 'B');
final int Q = noBishops.indexOf('Q');
 
final int indexOne = aPosition.indexOf('B');
final int indexTwo = aPosition.lastIndexOf('B');
final int D = ( indexOne % 2 == 0 ) ? indexOne / 2 : indexTwo / 2;
final int L = ( indexOne % 2 == 0 ) ? indexTwo / 2 : indexOne / 2;
return 96 * N + 16 * Q + 4 * D + L;
}
private static String retainIf(String aText, Predicate<Character> aPredicate) {
return aText.chars()
.mapToObj( i -> (char) i )
.filter(aPredicate)
.map(String::valueOf)
.reduce("", String::concat);
}
private static void createKnightsTable() {
knightsTable = new HashMap<List<Integer>, Integer>();
knightsTable.put(List.of(0, 1), 0);
knightsTable.put(List.of(0, 2), 1);
knightsTable.put(List.of(0, 3), 2);
knightsTable.put(List.of(0, 4), 3);
knightsTable.put(List.of(1, 2), 4);
knightsTable.put(List.of(1, 3), 5);
knightsTable.put(List.of(1, 4), 6);
knightsTable.put(List.of(2, 3), 7);
knightsTable.put(List.of(2, 4), 8);
knightsTable.put(List.of(3, 4), 9);
}
private static void createCorrectPieces() {
correctPieces = Set.of(
Map.entry('R', 2), Map.entry('N', 2), Map.entry('B', 2), Map.entry('Q', 1), Map.entry('K', 1) );
}
private static Map<List<Integer>, Integer> knightsTable;
private static Set<Map.Entry<Character, Integer>> correctPieces;
 
}
</syntaxhighlight>
{{ out }}
<pre>
Position QNRBBNKR has Chess960 SP-ID = 105
Position RNBQKBNR has Chess960 SP-ID = 518
Position RQNBBKRN has Chess960 SP-ID = 601
Position RNQBBKRN has Chess960 SP-ID = 617
</pre>
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">const whitepieces = "♖♘♗♕♔♗♘♖♙"
const whitechars = "rnbqkp"
const blackpieces = "♜♞♝♛♚♝♞♜♟"
Line 482 ⟶ 794:
end
 
for position in ["♕♘♖♗♗♘♔♖", "♖♘♗♕♔♗♘♖", "♖♕♘♗♗♔♖♘", "♖♘♕♗♗♔♖♘"]
println(collect(position), " => ", chess960spid(position))
end
</langsyntaxhighlight>{{out}}
<pre>
['♕', '♘', '♖', '♗', '♗', '♘', '♔', '♖'] => 105
['♖', '♘', '♗', '♕', '♔', '♗', '♘', '♖'] => 518
['♖', '♕', '♘', '♗', '♗', '♔', '♖', '♘'] => 601
['♖', '♘', '♕', '♗', '♗', '♔', '♖', '♘'] => 617
</pre>
 
=={{header|Nim}}==
{{trans|Wren}}
<langsyntaxhighlight Nimlang="nim">import sequtils, strformat, strutils, sugar, tables, unicode
 
type Piece {.pure.} = enum Rook = "R", Knight = "N", Bishop = "B", Queen = "Q", King = "K"
Line 541 ⟶ 855:
let n = NTable[piecesN.positions(Knight)]
 
let piecesQ = pieces.filterIt(it != KnightBishop)
let q = piecesQ.find(Queen)
 
Line 551 ⟶ 865:
 
 
for glyphs in ["♕♘♖♗♗♘♔♖", "♖♘♗♕♔♗♘♖", "♖♕♘♗♗♔♖♘", "♖♘♕♗♗♔♖♘"]:
echo &"{glyphs} or {glyphs.toPieces().join()} has SP-ID of {glyphs.spid()}"</langsyntaxhighlight>
 
{{out}}
<pre>♕♘♖♗♗♘♔♖ or QNRBBNKR has SP-ID of 105
♖♘♗♕♔♗♘♖ or RNBQKBNR has SP-ID of 518</pre>
♖♕♘♗♗♔♖♘ or RQNBBKRN has SP-ID of 601
♖♘♕♗♗♔♖♘ or RNQBBKRN has SP-ID of 617</pre>
 
=={{header|Perl}}==
{{trans|Raku}}
<langsyntaxhighlight lang="perl">use strictv5.36;
use warnings;
use feature 'say';
use List::AllUtils 'indexes';
 
sub sp_id ($setup) {
8 == length $setup or return 'Illegal position: should have exactly eight pieces';
my $setup = shift // 'RNBQKBNR';
1 == @{[ $setup =~ /$_/g ]} or return "Illegal position: should have exactly one $_" for <K Q>;
 
82 == length@{[ $setup =~ /$_/g ]} or diereturn '"Illegal position: should have exactly eighttwo pieces$_\'s" for <B N R>;
1 == @{[ $setup =~ m/$_R .* K .* R/gx ]} or diereturn "'Illegal position: shouldKing havenot exactly one $_" for <Kbetween Q>rooks.';
index($setup,'B')%2 =!= @{[ rindex($setup =~ /$_/g ]} ,'B')%2 or diereturn "'Illegal position: shouldBishops havenot exactlyon twoopposite $_\colors.'s" for <B N R>;
$setup =~ m/R .* K .* R/x or die 'Illegal position: King not between rooks.';
index($setup,'B')%2 != rindex($setup,'B')%2 or die 'Illegal position: Bishops not on opposite colors.';
 
my @knights = indexes { 'N' eq $_ } split '', $setup =~ s/[QB]//gr;
my $knight = indexes { join('', @knights) eq $_ } <01 02 03 04 12 13 14 23 24 34>; # combinations(5,2)
my @bishops = indexes { 'B' eq $_ } split '', $setup;
my $dark = int ((grep { $_ % 2 == 0 } @bishops)[0]) / 2;
my $light = int ((grep { $_ % 2 == 1 } @bishops)[0]) / 2;
my $queen = index(($setup =~ s/B//gr), 'Q');
 
int 4*(4*(6*$knight + $queen)+$dark)+$light;
}
 
say "$_ " . sp_id($_) for <QNRBBNKR RNBQKBNR RQNBBKRN RNQBBKRN QNBRBNKR>;</langsyntaxhighlight>
{{out}}
<pre>QNRBBNKR 105
RNBQKBNR 518</pre>
RQNBBKRN 601
RNQBBKRN 617
QNBRBNKR Illegal position: Bishops not on opposite colors.</pre>
 
=={{header|Phix}}==
<!--<langsyntaxhighlight Phixlang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">spid</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
Line 599 ⟶ 914:
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">n1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n2</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find_all</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'N'</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">filter</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"out"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"QB"</span><span style="color: #0000FF;">)),</span>
<span style="color: #000000;">N</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{-</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">}[</span><span style="color: #000000;">n1</span><span style="color: #0000FF;">]+</span><span style="color: #000000;">n2</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">Q</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'Q'</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">filter</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"!="</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'NB'</span><span style="color: #0000FF;">))-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">D</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">filter</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">odd</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">-- (nb not /2)</span>
<span style="color: #000000;">L</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">filter</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">even</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span>
Line 611 ⟶ 926:
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"QNRBBNKR"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RNBQKBNR"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RQNBBKRN"</span><span style="color: #0000FF;">)</span>
<!--</lang>-->
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RNQBBKRN"</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
QNRBBNKR : 105
RNBQKBNR : 518
RQNBBKRN : 601
</pre>
RNQBBKRN : 617</pre>
To support all those crazy unicode characters just change the start of spid() to:
<!--<langsyntaxhighlight Phixlang="phix">(phixonline)-->
<span style="color: #008080;">function</span> <span style="color: #000000;">spid</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">u</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">u32</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">utf8_to_utf32</span><span style="color: #0000FF;">(</span><span style="color: #000000;">u</span><span style="color: #0000FF;">),</span>
Line 628 ⟶ 946:
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"♕♘♖♗♗♘♔♖"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"♖♘♗♕♔♗♘♖"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"♜♛♞♝♝♚♜♞"</span><span style="color: #0000FF;">)</span>
<!--</lang>-->
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"♜♞♛♝♝♚♜♞"</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
{{out}}
Note that output on a windows terminal is as expected far from pretty, this is from pwa/p2js
Line 634 ⟶ 954:
QNRBBNKR : 105
RNBQKBNR : 518
RQNBBKRN : 601
RNQBBKRN : 617
♕♘♖♗♗♘♔♖ : 105
♖♘♗♕♔♗♘♖ : 518
♜♛♞♝♝♚♜♞ : 601
♜♞♛♝♝♚♜♞ : 617
</pre>
 
Line 641 ⟶ 965:
{{works with|Python|3.10.5 2022-06-28}}
 
<syntaxhighlight lang="python"># optional, but task function depends on it as written
<lang python>
# optional, but task function depends on it as written
def validate_position(candidate: str):
assert (
Line 657 ⟶ 980:
), f"piece type '{piece_type}' has invalid count"
 
bishops_pos = [index for index, value in enumerate(candidate) if value == "B"]
value in enumerate(candidate) if value == "B"]
assert (
bishops_pos[0] % 2 != bishops_pos[1] % 2
Line 694 ⟶ 1,018:
 
# step 2
subset_step2 = [piece for piece in start_pos if piece != "NB"]
Q = subset_step2.index("Q")
 
Line 708 ⟶ 1,032:
 
return 4 * (4 * (6*N + Q) + D) + L
</lang>
 
if __name__ == '__main__':
for example in ["QNRBBNKR", "RNBQKBNR", "RQNBBKRN", "RNQBBKRN"]:
print(f'Position: {example}; Chess960 PID= {calc_position(example)}')</syntaxhighlight>
{{out}}
<pre>
'Position: RNBQKBNRQNRBBNKR; Chess960 PID= 518'105
'Position: QNRBBNKRRNBQKBNR; Chess960 PID= 105'518
Position: RQNBBKRN; Chess960 PID= 601
Position: RNQBBKRN; Chess960 PID= 617
</pre>
 
=={{header|Raku}}==
<syntaxhighlight lang="raku" line>sub c960-spid($array) {
<lang perl6>#!/usr/bin/env raku
# standardize on letters for easier processing
# derive a chess960 position's SP-ID
my $ascii = $array.trans('♜♞♝♛♚♖♘♗♕♔' => 'RNBQK');
unit sub MAIN($array = "♖♘♗♕♔♗♘♖");
 
# error-checking
# standardize on letters for easier processing
my %Names = <Q Queen K King R Rook N Knight B Bishop>;
my $ascii = $array.trans("♜♞♝♛♚♖♘♗♕♔" => "RNBQKRNBQK");
return 'Illegal position: should have exactly eight pieces' unless 8 == $ascii.chars;
return 'Illegal position: Bishops not on opposite colors.' unless 1 == sum $ascii.indices('B').map(* % 2);
return 'Illegal position: King not between rooks.' unless $ascii ~~ /'R' .* 'K' .* 'R'/;
for <K 1 Q 1 B 2 N 2 R 2> -> $piece, $count {
return "Illegal position: should have exactly $count %Names{$piece}\(s\)\n" unless $count == $ascii.indices($piece)
}
 
# Work backwards through the placement rules.
# (optional error-checking)
# King and rooks are forced during placement, so ignore them.
if $ascii.chars != 8 {
die "Illegal position: should have exactly eight pieces\n";
}
 
# 1. Figure out which knight combination was used:
for «K Q» -> $one {
my @knights = $ascii.subst(/<[QB]>/, '', :g).indices('N');
if +$ascii.indices($one) != 1 {
my $knight = combinations(5,2).kv.grep( -> $i, @c { @c eq @knights } ).flat.first;
die "Illegal position: should have exactly one $one\n";
}
}
 
# 2. Then which queen position:
for «B N R» -> $two {
if + my $queen = $ascii.indicessubst($two)'B', !='', 2:g).index('Q'); {
die "Illegal position: should have exactly two $two\'s\n";
}
}
 
# 3. Finally the two bishops:
if $ascii !~~ /'R' .* 'K' .* 'R'/ {
my @bishops = $ascii.indices('B');
die "Illegal position: King not between rooks.";
my ($dark,$light) = (@bishops.first %% 2 ?? @bishops !! @bishops.reverse) Xdiv 2;
}
 
$ascii.trans('RNBQK' => '♖♘♗♕♔') ~ ' ' ~ 4 × (4 × (6 × $knight + $queen) + $dark) + $light;
if [+]($ascii.indices('B').map(* % 2)) != 1 {
die "Illegal position: Bishops not on opposite colors.";
}
# (end optional error-checking)
 
say .&c960-spid for <♖♘♗♕♔♗♘♖ ♛♞♜♝♝♞♚♜ RQNBBKRN RNQBBKRN QNBRBNKR>;</syntaxhighlight>
# Work backwards through the placement rules.
{{out}}
# King and rooks are forced during placement, so ignore them.
<pre>♖♘♗♕♔♗♘♖ 518
 
♕♘♖♗♗♘♔♖ 105
# 1. Figure out which knight combination was used:
♖♕♘♗♗♔♖♘ 601
my @knights = $ascii
♖♘♕♗♗♔♖♘ 617
.subst(/<[QB]>/,'',:g)
Illegal position: Bishops not on opposite colors.</pre>
.indices('N');
 
my $knight = combinations(5,2).kv.grep(
-> $i,@c { @c eq @knights }
)[0][0];
 
# 2. Then which queen position:
my $queen = $ascii
.subst(/<[B]>/,'',:g)
.index('Q');
 
# 3. Finally the two bishops:
my @bishops = $ascii.indices('B');
my $dark = @bishops.grep({ $_ %% 2 })[0] div 2;
my $light = @bishops.grep({ not $_ %% 2 })[0] div 2;
 
my $sp-id = 4*(4*(6*$knight + $queen)+$dark)+$light;
 
# standardize output
my $display = $ascii.trans("RNBQK" => "♖♘♗♕♔");
 
say "$display: $sp-id";</lang>
 
{{Out}}
<pre>$ c960spid QNRBBNKR
♕♘♖♗♗♘♔♖: 105
$ c960spid
♖♘♗♕♔♗♘♖: 518</pre>
 
=={{header|Ruby}}==
<syntaxhighlight lang="ruby">CHESS_PIECES = %w<♖♘♗♕♔ ♜♞♝♛♚>
<lang ruby>def chess960_to_spid(pos)
def chess960_to_spid(pos)
start_str = pos.tr("♖♘♗♕♔", "RNBQK")
start_str = pos.tr(CHESS_PIECES.join, "RNBQKRNBQK")
#1 knights score
s = start_str.delete("QB")
n = [0,1,2,3,4].combination(2).to_a.index( [s.index("N"), s.rindex("N")] )
#2 queen score
q = start_str.delete("NB").index("Q")
#3 bishops
bs = start_str.index("B"), start_str.rindex("B")
Line 801 ⟶ 1,100:
end
 
%w<QNRBBNKR RNBQKBNR RQNBBKRN RNQBBKRN>.each_with_index do |array, i|
positions = ["QNRBBNKR", "♖♘♗♕♔♗♘♖"]
pieces = array.tr("RNBQK", CHESS_PIECES[i%2])
positions.each{|pos| puts "#{pos}: #{chess960_to_spid(pos)}" }
puts "#{pieces} (#{array}): #{chess960_to_spid array}"
</lang>
end
</syntaxhighlight>
{{out}}
<pre>♕♘♖♗♗♘♔♖ (QNRBBNKR): 105
♜♞♝♛♚♝♞♜ (RNBQKBNR): 518
♖♘♗♕♔♗♘♖: 518
♖♕♘♗♗♔♖♘ (RQNBBKRN): 601
♜♞♛♝♝♚♜♞ (RNQBBKRN): 617
</pre>
 
=={{header|Wren}}==
{{libheader|Wren-traititerate}}
<langsyntaxhighlight ecmascriptlang="wren">import "./traititerate" for Indexed
 
var glyphs = "♜♞♝♛♚♖♘♗♕♔".toList
Line 848 ⟶ 1,152:
var N = ntable[np]
 
var piecesQ = pieces.replace("NB", "")
var Q = piecesQ.indexOf("Q")
 
Line 861 ⟶ 1,165:
}
 
for (pieces in ["♕♘♖♗♗♘♔♖", "♖♘♗♕♔♗♘♖", "♜♛♞♝♝♚♜♞", "♜♞♛♝♝♚♜♞"]) {
System.print("%(pieces) or %(g2l.call(pieces)) has SP-ID of %(spid.call(pieces))")
}</langsyntaxhighlight>
 
{{out}}
Line 869 ⟶ 1,173:
♕♘♖♗♗♘♔♖ or QNRBBNKR has SP-ID of 105
♖♘♗♕♔♗♘♖ or RNBQKBNR has SP-ID of 518
♜♛♞♝♝♚♜♞ or RQNBBKRN has SP-ID of 601
♜♞♛♝♝♚♜♞ or RNQBBKRN has SP-ID of 617
</pre>
9,476

edits