Archives
Trending
Support
Login
clear text
XML
Django
JavaScript
MATLAB
C
C++
C#
Python
SQL
Shell
Bash
Markdown
YAML
JSON
HTML
CSS
PHP
Java
Ruby
Go
Rust
Swift
Kotlin
Arduino
TypeScript
Perl
Autohotkey
Lua
SQF
R
Scala
Haskell
Groovy
Dart
Clojure
VB.NET
Objective-C
PowerShell
Bash
CoffeeScript
Verilog
""" Count (an upper bound on) the number of tinyhouse chess positions. Board: 4x4 = 16 squares. Ranks 2 and 3 are the 8 "middle" squares. Piece inventory (conserved totals, both colours + banks combined): 1 white king, 1 black king 2 "pawn-ish" pieces : each is a pawn, or a promoted pawn (pawn-wazir / pawn-ferz / pawn-horse) 2 true wazirs, 2 true ferzes, 2 true horses Placement domains: king, true wazir/ferz/horse ....... any of the 16 squares (or bank, except kings) plain pawn ........................ one of the 8 middle squares, or the bank promoted pawn (pawn-X) ............ any of the 16 squares, never the bank at most one piece per square Method ------ Every piece is described by a "slot option": (label, place) where label = (colour, kind) -- what the piece is and whose it is place = 'M' (middle 8 squares) | 'F' (free: any of 16) | 'bank' Pieces sharing the same label+place are indistinguishable, so for each group we enumerate *multisets* of options (combinations_with_replacement). Given a whole configuration with `a` on-board pieces restricted to the middle squares and `b` on-board pieces free to use all 16, the number of ways to place them as *distinguishable* pieces is P(8, a) * P(16 - a, b) (place the middle-restricted ones first; each one eats a square from the 16). Dividing by k! for every group of k identical on-board pieces turns that into a count of distinct positions. Identical pieces sitting in the same bank are already handled by the multiset enumeration, so they need no divisor. Finally multiply by 2 for whose turn it is. """ from itertools import combinations_with_replacement, product from collections import Counter from math import perm, factorial COLOURS = ("W", "B") # ---- option lists for each conserved group ------------------------------- # the two pawn-ish pieces PAWN_OPTIONS = ( [((c, "pawn"), "M") for c in COLOURS] # pawn on board + [((c, "pawn"), "bank") for c in COLOURS] # pawn in hand + [((c, "pawn-" + p), "F") # promoted pawn for c in COLOURS for p in ("wazir", "ferz", "horse")] ) def true_piece_options(kind): return ([((c, kind), "F") for c in COLOURS] + [((c, kind), "bank") for c in COLOURS]) WAZIR_OPTIONS = true_piece_options("wazir") FERZ_OPTIONS = true_piece_options("ferz") HORSE_OPTIONS = true_piece_options("horse") KINGS = [(("W", "king"), "F"), (("B", "king"), "F")] # ---- enumeration --------------------------------------------------------- def count_positions(verbose=False): groups = [ list(combinations_with_replacement(PAWN_OPTIONS, 2)), list(combinations_with_replacement(WAZIR_OPTIONS, 2)), list(combinations_with_replacement(FERZ_OPTIONS, 2)), list(combinations_with_replacement(HORSE_OPTIONS, 2)), ] total = 0 by_pieces_on_board = Counter() # how many pieces stand on the board configs = 0 for combo in product(*groups): pieces = KINGS + [item for grp in combo for item in grp] a = sum(1 for _, place in pieces if place == "M") b = sum(1 for _, place in pieces if place == "F") placements = perm(8, a) * perm(16 - a, b) if placements == 0: continue # divide out permutations of identical on-board pieces board_counts = Counter(p for p in pieces if p[1] != "bank") divisor = 1 for k in board_counts.values(): divisor *= factorial(k) n = placements // divisor total += n configs += 1 by_pieces_on_board[a + b] += n total *= 2 # side to move if verbose: print(f"piece configurations considered : {configs}") print("positions by number of pieces standing on the board " "(before the x2 for side to move):") for k in sorted(by_pieces_on_board): print(f" {k:2d} pieces on board : {by_pieces_on_board[k]:>14,}") print() return total if __name__ == "__main__": t = count_positions(verbose=True) print(f"TOTAL tinyhouse positions (upper bound): {t:,}") print(f" ~ {t:.4g}")
Mark as private (unlisted)
for 30 minutes
for 6 hours
for 1 day
for 1 week
for 1 month
for 1 year
everlasting (like CCCP)