2016 Update
This commit is contained in:
parent
948b86eafa
commit
dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions
|
|
@ -1,4 +1,4 @@
|
|||
'''[[wp:Chess960|Chess960]]''' is a variant of chess created by world champion [[wp:Bobby Fisher|Bobby Fisher]]. Unlike other variants of the game, Chess960 does not require a different material, but instead relies on a random initial position, with a few constraints:
|
||||
'''[[wp:Chess960|Chess960]]''' is a variant of chess created by world champion [[wp:Bobby Fisher|Bobby Fisher]]. Unlike other variants of the game, Chess960 does not require a different material, but instead relies on a random initial position, with a few constraints:
|
||||
|
||||
* as in the standard chess game, all eight white pawns must be placed on the second rank.
|
||||
* White pieces must stand on the first rank as in the standard game, in random column order but with the two following constraints:
|
||||
|
|
@ -6,7 +6,10 @@
|
|||
** the King must be between two rooks (with any number of other pieces between them all)
|
||||
* Black pawns and pieces must be placed respectively on the seventh and eighth ranks, mirroring the white pawns and pieces, just as in the standard game. (That is, their positions are not independently randomized.)
|
||||
|
||||
With those constraints there are 960 possible starting positions, thus the name of the variant.
|
||||
<br>
|
||||
With those constraints there are '''960''' possible starting positions, thus the name of the variant.
|
||||
|
||||
|
||||
;Task:
|
||||
The purpose of this task is to write a program that can randomly generate any one of the 960 Chess960 initial positions. You will show the result as the first rank displayed with [[wp:Chess symbols in Unicode|Chess symbols in Unicode: ♔♕♖♗♘]] or with the letters '''K'''ing '''Q'''ueen '''R'''ook '''B'''ishop k'''N'''ight.
|
||||
The purpose of this task is to write a program that can randomly generate any one of the 960 Chess960 initial positions. You will show the result as the first rank displayed with [[wp:Chess symbols in Unicode|Chess symbols in Unicode: ♔♕♖♗♘]] or with the letters '''K'''ing '''Q'''ueen '''R'''ook '''B'''ishop k'''N'''ight.
|
||||
<br><br>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
(ns c960.core
|
||||
(:gen-class)
|
||||
(:require [clojure.string :as s]))
|
||||
|
||||
;; legal starting rank - unicode chars for rook, knight, bishop, queen, king, bishop, knight, rook
|
||||
(def starting-rank [\♖ \♘ \♗ \♕ \♔ \♗ \♘ \♖])
|
||||
|
||||
(defn bishops-legal?
|
||||
"True if Bishops are odd number of indicies apart"
|
||||
[rank]
|
||||
(odd? (apply - (cons 0 (sort > (keep-indexed #(when (= \♗ %2) %1) rank))))))
|
||||
|
||||
(defn king-legal?
|
||||
"True if the king is between two rooks"
|
||||
[rank]
|
||||
(let [king-&-rooks (filter #{\♔ \♖} rank)]
|
||||
(and
|
||||
(= 3 (count king-&-rooks))
|
||||
(= \u2654 (second king-&-rooks)))))
|
||||
|
||||
|
||||
(defn c960
|
||||
"Return a legal rank for c960 chess"
|
||||
([] (c960 1))
|
||||
([n]
|
||||
(->> #(shuffle starting-rank)
|
||||
repeatedly
|
||||
(filter #(and (king-legal? %) (bishops-legal? %)))
|
||||
(take n)
|
||||
(map #(s/join ", " %)))))
|
||||
|
||||
|
||||
(c960)
|
||||
;; => "♗, ♖, ♔, ♕, ♘, ♘, ♖, ♗"
|
||||
(c960)
|
||||
;; => "♖, ♕, ♘, ♔, ♗, ♗, ♘, ♖"
|
||||
(c960 4)
|
||||
;; => ("♘, ♖, ♔, ♘, ♗, ♗, ♖, ♕" "♗, ♖, ♔, ♘, ♘, ♕, ♖, ♗" "♘, ♕, ♗, ♖, ♔, ♗, ♘, ♖" "♖, ♔, ♘, ♘, ♕, ♖, ♗, ♗")
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
defmodule Chess960 do
|
||||
@pieces ~w(♔ ♕ ♘ ♘ ♗ ♗ ♖ ♖) # ~w(K Q N N B B R R)
|
||||
@regexes [~r/♗(..)*♗/, ~r/♖.*♔.*♖/] # [~r/B(..)*B/, ~r/R.*K.*R/]
|
||||
|
||||
def shuffle do
|
||||
row = Enum.shuffle(@pieces) |> Enum.join
|
||||
if Enum.all?(@regexes, &Regex.match?(&1, row)), do: row, else: shuffle
|
||||
end
|
||||
end
|
||||
|
||||
Enum.each(1..5, fn _ -> IO.puts Chess960.shuffle end)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
defmodule Chess960 do
|
||||
def construct do
|
||||
row = Enum.reduce(~w[♕ ♘ ♘], ~w[♖ ♔ ♖], fn piece,acc ->
|
||||
List.insert_at(acc, :rand.uniform(length(acc)+1)-1, piece)
|
||||
end)
|
||||
[Enum.random([0, 2, 4, 6]), Enum.random([1, 3, 5, 7])]
|
||||
|> Enum.sort
|
||||
|> Enum.reduce(row, fn pos,acc -> List.insert_at(acc, pos, "♗") end)
|
||||
|> Enum.join
|
||||
end
|
||||
end
|
||||
|
||||
Enum.each(1..5, fn _ -> IO.puts Chess960.construct end)
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
defmodule Chess960 do
|
||||
@krn ~w(NNRKR NRNKR NRKNR NRKRN RNNKR RNKNR RNKRN RKNNR RKNRN RKRNN)
|
||||
|
||||
def start_position, do: start_position(:rand.uniform(960)-1)
|
||||
|
||||
def start_position(id) do
|
||||
pos = List.duplicate(nil, 8)
|
||||
q = div(id, 4)
|
||||
r = rem(id, 4)
|
||||
pos = List.replace_at(pos, r * 2 + 1, "B")
|
||||
q = div(q, 4)
|
||||
r = rem(q, 4)
|
||||
pos = List.replace_at(pos, r * 2, "B")
|
||||
q = div(q, 6)
|
||||
r = rem(q, 6)
|
||||
i = Enum.reject(0..7, &Enum.at(pos,&1)) |> Enum.at(r)
|
||||
pos = List.replace_at(pos, i, "Q")
|
||||
krn = Enum.at(@krn, q) |> String.codepoints
|
||||
Enum.reject(0..7, &Enum.at(pos,&1))
|
||||
|> Enum.zip(krn)
|
||||
|> Enum.reduce(pos, fn {i,x},acc -> List.replace_at(acc,i,x) end)
|
||||
|> Enum.join
|
||||
end
|
||||
end
|
||||
|
||||
IO.puts "Generate Start Position from ID number"
|
||||
Enum.each([0,518,959], fn id ->
|
||||
:io.format "~3w : ~s~n", [id, Chess960.start_position(id)]
|
||||
end)
|
||||
IO.puts "\nGenerate random Start Position"
|
||||
Enum.each(1..5, fn _ -> IO.puts Chess960.start_position end)
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
\ make starting position for Chess960, constructive
|
||||
|
||||
\ 0 1 2 3 4 5 6 7 8 9
|
||||
create krn S" NNRKRNRNKRNRKNRNRKRNRNNKRRNKNRRNKRNRKNNRRKNRNRKRNN" mem,
|
||||
|
||||
create pieces 8 allot
|
||||
|
||||
: chess960 ( n -- )
|
||||
pieces 8 erase
|
||||
4 /mod swap 2* 1+ pieces + 'B swap c!
|
||||
4 /mod swap 2* pieces + 'B swap c!
|
||||
6 /mod swap pieces swap bounds begin dup c@ if swap 1+ swap then 2dup > while 1+ repeat drop 'Q swap c!
|
||||
5 * krn + pieces 8 bounds do i c@ 0= if dup c@ i c! 1+ then loop drop
|
||||
cr pieces 8 type ;
|
||||
|
||||
0 chess960 \ BBQNNRKR ok
|
||||
518 chess960 \ RNBQKBNR ok
|
||||
959 chess960 \ RKRNNQBB ok
|
||||
|
||||
960 choose chess960 \ random position
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
program chess960
|
||||
implicit none
|
||||
|
||||
integer, pointer :: a,b,c,d,e,f,g,h
|
||||
integer, target :: p(8)
|
||||
a => p(1)
|
||||
b => p(2)
|
||||
c => p(3)
|
||||
d => p(4)
|
||||
e => p(5)
|
||||
f => p(6)
|
||||
g => p(7)
|
||||
h => p(8)
|
||||
|
||||
king: do a=2,7 ! King on an internal square
|
||||
r1: do b=1,a-1 ! R1 left of the King
|
||||
r2: do c=a+1,8 ! R2 right of the King
|
||||
b1: do d=1,7,2 ! B1 on an odd square
|
||||
if (skip_pos(d,4)) cycle
|
||||
b2: do e=2,8,2 ! B2 on an even square
|
||||
if (skip_pos(e,5)) cycle
|
||||
queen: do f=1,8 ! Queen anywhere else
|
||||
if (skip_pos(f,6)) cycle
|
||||
n1: do g=1,7 ! First knight
|
||||
if (skip_pos(g,7)) cycle
|
||||
n2: do h=g+1,8 ! Second knight (indistinguishable from first)
|
||||
if (skip_pos(h,8)) cycle
|
||||
if (sum(p) /= 36) stop 'Loop error' ! Sanity check
|
||||
call write_position
|
||||
end do n2
|
||||
end do n1
|
||||
end do queen
|
||||
end do b2
|
||||
end do b1
|
||||
end do r2
|
||||
end do r1
|
||||
end do king
|
||||
|
||||
contains
|
||||
|
||||
logical function skip_pos(i, n)
|
||||
integer, intent(in) :: i, n
|
||||
skip_pos = any(p(1:n-1) == i)
|
||||
end function skip_pos
|
||||
|
||||
subroutine write_position
|
||||
integer :: i, j
|
||||
character(len=15) :: position = ' '
|
||||
character(len=1), parameter :: names(8) = ['K','R','R','B','B','Q','N','N']
|
||||
do i=1,8
|
||||
j = 2*p(i)-1
|
||||
position(j:j) = names(i)
|
||||
end do
|
||||
write(*,'(a)') position
|
||||
end subroutine write_position
|
||||
|
||||
end program chess960
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
function ch960startPos() {
|
||||
var rank = new Array(8),
|
||||
// randomizer (our die)
|
||||
d = function(num) { return Math.floor(Math.random() * ++num) },
|
||||
emptySquares = function() {
|
||||
var arr = [];
|
||||
for (var i = 0; i < 8; i++) if (rank[i] == undefined) arr.push(i);
|
||||
return arr;
|
||||
};
|
||||
// place one bishop on any black square
|
||||
rank[d(2) * 2] = "♗";
|
||||
// place the other bishop on any white square
|
||||
rank[d(2) * 2 + 1] = "♗";
|
||||
// place the queen on any empty square
|
||||
rank[emptySquares()[d(5)]] = "♕";
|
||||
// place one knight on any empty square
|
||||
rank[emptySquares()[d(4)]] = "♘";
|
||||
// place the other knight on any empty square
|
||||
rank[emptySquares()[d(3)]] = "♘";
|
||||
// place the rooks and the king on the squares left, king in the middle
|
||||
for (var x = 1; x <= 3; x++) rank[emptySquares()[0]] = x==2 ? "♔" : "♖";
|
||||
return rank;
|
||||
}
|
||||
|
||||
// test
|
||||
for (var x = 1; x <= 10; x++) console.log(ch960startPos().join(" | "));
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
object Chess960 : Iterable<String> {
|
||||
override fun iterator() = patterns.iterator()
|
||||
|
||||
private operator fun invoke(b: String, e: String) {
|
||||
if (e.length <= 1) {
|
||||
val s = b + e
|
||||
if (s.is_valid()) patterns += s
|
||||
} else
|
||||
for (i in 0..e.length - 1)
|
||||
invoke(b + e[i], e.substring(0, i) + e.substring(i + 1))
|
||||
}
|
||||
|
||||
private fun String.is_valid(): Boolean {
|
||||
val k = indexOf('K')
|
||||
return indexOf('R') < k && k < lastIndexOf('R') &&
|
||||
indexOf('B') % 2 != lastIndexOf('B') % 2
|
||||
}
|
||||
|
||||
private val patterns = sortedSetOf<String>()
|
||||
|
||||
init { invoke("", "KQRRNNBB") }
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
Chess960.forEachIndexed { i, s -> println("$i: $s") }
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
-- Insert 'str' into 't' at a random position from 'left' to 'right'
|
||||
function randomInsert (t, str, left, right)
|
||||
local pos
|
||||
repeat pos = math.random(left, right) until not t[pos]
|
||||
t[pos] = str
|
||||
return pos
|
||||
end
|
||||
|
||||
-- Generate a random Chess960 start position for white major pieces
|
||||
function chess960 ()
|
||||
local t, b1, b2 = {}
|
||||
local kingPos = randomInsert(t, "K", 2, 7)
|
||||
randomInsert(t, "R", 1, kingPos - 1)
|
||||
randomInsert(t, "R", kingPos + 1, 8)
|
||||
b1 = randomInsert(t, "B", 1, 8)
|
||||
b2 = randomInsert(t, "B", 1, 8)
|
||||
while (b2 - b1) % 2 == 0 do
|
||||
t[b2] = false
|
||||
b2 = randomInsert(t, "B", 1, 8)
|
||||
end
|
||||
randomInsert(t, "Q", 1, 8)
|
||||
randomInsert(t, "N", 1, 8)
|
||||
randomInsert(t, "N", 1, 8)
|
||||
return t
|
||||
end
|
||||
|
||||
-- Main procedure
|
||||
math.randomseed(os.time())
|
||||
print(table.concat(chess960()))
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
function Get-RandomChess960Start
|
||||
{
|
||||
$Starts = @()
|
||||
|
||||
ForEach ( $Q in 0..3 ) {
|
||||
ForEach ( $N1 in 0..4 ) {
|
||||
ForEach ( $N2 in ($N1+1)..5 ) {
|
||||
ForEach ( $B1 in 0..3 ) {
|
||||
ForEach ( $B2 in 0..3 ) {
|
||||
$BB = $B1 * 2 + ( $B1 -lt $B2 )
|
||||
$BW = $B2 * 2
|
||||
$Start = [System.Collections.ArrayList]( '♖', '♔', '♖' )
|
||||
$Start.Insert( $Q , '♕' )
|
||||
$Start.Insert( $N1, '♘' )
|
||||
$Start.Insert( $N2, '♘' )
|
||||
$Start.Insert( $BB, '♗' )
|
||||
$Start.Insert( $BW, '♗' )
|
||||
$Starts += ,$Start
|
||||
}}}}}
|
||||
|
||||
$Index = Get-Random 960
|
||||
$StartString = $Starts[$Index] -join ''
|
||||
return $StartString
|
||||
}
|
||||
|
||||
Get-RandomChess960Start
|
||||
Get-RandomChess960Start
|
||||
Get-RandomChess960Start
|
||||
Get-RandomChess960Start
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
use std::collections::BTreeSet;
|
||||
|
||||
struct Chess960 ( BTreeSet<String> );
|
||||
|
||||
impl Chess960 {
|
||||
fn invoke(&mut self, b: &str, e: &str) {
|
||||
if e.len() <= 1 {
|
||||
let s = b.to_string() + e;
|
||||
if Chess960::is_valid(&s) { self.0.insert(s); }
|
||||
} else {
|
||||
for (i, c) in e.char_indices() {
|
||||
let mut b = b.to_string();
|
||||
b.push(c);
|
||||
let mut e = e.to_string();
|
||||
e.remove(i);
|
||||
self.invoke(&b, &e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_valid(s: &str) -> bool {
|
||||
let k = s.find('K').unwrap();
|
||||
k > s.find('R').unwrap() && k < s.rfind('R').unwrap() && s.find('B').unwrap() % 2 != s.rfind('B').unwrap() % 2
|
||||
}
|
||||
}
|
||||
|
||||
// Program entry point.
|
||||
fn main() {
|
||||
let mut chess960 = Chess960(BTreeSet::new());
|
||||
chess960.invoke("", "KQRRNNBB");
|
||||
|
||||
let mut i = 0;
|
||||
for p in chess960.0 {
|
||||
println!("{}: {}", i, p);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
object Chess960 extends App {
|
||||
private def apply(b: String, e: String) {
|
||||
if (e.length <= 1) {
|
||||
val s = b + e
|
||||
if (is_valid(s)) patterns += s
|
||||
} else
|
||||
for (i <- 0 until e.length)
|
||||
apply(b + e(i), e.substring(0, i) + e.substring(i + 1))
|
||||
}
|
||||
|
||||
private def is_valid(s: String) = {
|
||||
val k = s.indexOf('K')
|
||||
if (k < s.indexOf('R')) false
|
||||
else k < s.lastIndexOf('R') && s.indexOf('B') % 2 != s.lastIndexOf('B') % 2
|
||||
}
|
||||
|
||||
private val patterns = scala.collection.mutable.SortedSet[String]()
|
||||
|
||||
apply("", "KQRRNNBB")
|
||||
for ((s, i) <- patterns.zipWithIndex) println(s"$i: $s")
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue