Task: Peaceful chess queen armies


C++: #include <iostream>
#include <vector>

enum class Piece {
    empty,
    black,
    white
};

typedef std::pair<int, int> position;

bool isAttacking(const position &queen, const position &pos) {
    return queen.first == pos.first
        || queen.second == pos.second
        || abs(queen.first - pos.first) == abs(queen.second - pos.second);
}

bool place(const int m, const int n, std::vector<position> &pBlackQueens, std::vector<position> &pWhiteQueens) {
    if (m == 0) {
        return true;
    }
    bool placingBlack = true;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            auto pos = std::make_pair(i, j);
            for (auto queen : pBlackQueens) {
                if (queen == pos || !placingBlack && isAttacking(queen, pos)) {
                    goto inner;
                }
            }
            for (auto queen : pWhiteQueens) {
                if (queen == pos || placingBlack && isAttacking(queen, pos)) {
                    goto inner;
                }
            }
            if (placingBlack) {
                pBlackQueens.push_back(pos);
                placingBlack = false;
            } else {
                pWhiteQueens.push_back(pos);
                if (place(m - 1, n, pBlackQueens, pWhiteQueens)) {
                    return true;
                }
                pBlackQueens.pop_back();
                pWhiteQueens.pop_back();
                placingBlack = true;
            }

        inner: {}
        }
    }
    if (!placingBlack) {
        pBlackQueens.pop_back();
    }
    return false;
}

void printBoard(int n, const std::vector<position> &blackQueens, const std::vector<position> &whiteQueens) {
    std::vector<Piece> board(n * n);
    std::fill(board.begin(), board.end(), Piece::empty);

    for (auto &queen : blackQueens) {
        board[queen.first * n + queen.second] = Piece::black;
    }
    for (auto &queen : whiteQueens) {
        board[queen.first * n + queen.second] = Piece::white;
    }

    for (size_t i = 0; i < board.size(); ++i) {
        if (i != 0 && i % n == 0) {
            std::cout << '\n';
        }
        switch (board[i]) {
        case Piece::black:
            std::cout << "B ";
            break;
        case Piece::white:
            std::cout << "W ";
            break;
        case Piece::empty:
        default:
            int j = i / n;
            int k = i - j * n;
            if (j % 2 == k % 2) {
                std::cout << "x ";
            } else {
                std::cout << "* ";
            }
            break;
        }
    }

    std::cout << "\n\n";
}

int main() {
    std::vector<position> nms = {
        {2, 1}, {3, 1}, {3, 2}, {4, 1}, {4, 2}, {4, 3},
        {5, 1}, {5, 2}, {5, 3}, {5, 4}, {5, 5},
        {6, 1}, {6, 2}, {6, 3}, {6, 4}, {6, 5}, {6, 6},
        {7, 1}, {7, 2}, {7, 3}, {7, 4}, {7, 5}, {7, 6}, {7, 7},
    };

    for (auto nm : nms) {
        std::cout << nm.second << " black and " << nm.second << " white queens on a " << nm.first << " x " << nm.first << " board:\n";
        std::vector<position> blackQueens, whiteQueens;
        if (place(nm.second, nm.first, blackQueens, whiteQueens)) {
            printBoard(nm.first, blackQueens, whiteQueens);
        } else {
            std::cout << "No solution exists.\n\n";
        }
    }

    return 0;
}






Python: from itertools import combinations, product, count
from functools import lru_cache, reduce


_bbullet, _wbullet = '\u2022\u25E6'
_or = set.__or__

def place(m, n):
    "Place m black and white queens, peacefully, on an n-by-n board"
    board = set(product(range(n), repeat=2))  
    placements = {frozenset(c) for c in combinations(board, m)}
    for blacks in placements:
        black_attacks = reduce(_or, 
                               (queen_attacks_from(pos, n) for pos in blacks), 
                               set())
        for whites in {frozenset(c)     
                       for c in combinations(board - black_attacks, m)}:
            if not black_attacks & whites:
                return blacks, whites
    return set(), set()

@lru_cache(maxsize=None)
def queen_attacks_from(pos, n):
    x0, y0 = pos
    a = set([pos])    
    a.update((x, y0) for x in range(n))    
    a.update((x0, y) for y in range(n))    
    
    for x1 in range(n):
        
        y1 = y0 -x0 +x1
        if 0 <= y1 < n: 
            a.add((x1, y1))
        
        y1 = y0 +x0 -x1
        if 0 <= y1 < n: 
            a.add((x1, y1))
    return a

def pboard(black_white, n):
    "Print board"
    if black_white is None: 
        blk, wht = set(), set()
    else:
        blk, wht = black_white
    print(f"
          f"on a {n}-by-{n} board:", end='')
    for x, y in product(range(n), repeat=2):
        if y == 0:
            print()
        xy = (x, y)
        ch = ('?' if xy in blk and xy in wht 
              else 'B' if xy in blk
              else 'W' if xy in wht
              else _bbullet if (x + y)%2 else _wbullet)
        print('%s' % ch, end='')
    print()

if __name__ == '__main__':
    n=2
    for n in range(2, 7):
        print()
        for m in count(1):
            ans = place(m, n)
            if ans[0]:
                pboard(ans, n)
            else:
                print (f"
                break
    
    print('\n')
    m, n = 5, 7
    ans = place(m, n)
    pboard(ans, n)