17db96d56Sopenharmony_ci#!/usr/bin/env python3
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ci"""
47db96d56Sopenharmony_ciN queens problem.
57db96d56Sopenharmony_ci
67db96d56Sopenharmony_ciThe (well-known) problem is due to Niklaus Wirth.
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_ciThis solution is inspired by Dijkstra (Structured Programming).  It is
97db96d56Sopenharmony_cia classic recursive backtracking approach.
107db96d56Sopenharmony_ci"""
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_ciN = 8                                   # Default; command line overrides
137db96d56Sopenharmony_ci
147db96d56Sopenharmony_ciclass Queens:
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ci    def __init__(self, n=N):
177db96d56Sopenharmony_ci        self.n = n
187db96d56Sopenharmony_ci        self.reset()
197db96d56Sopenharmony_ci
207db96d56Sopenharmony_ci    def reset(self):
217db96d56Sopenharmony_ci        n = self.n
227db96d56Sopenharmony_ci        self.y = [None] * n             # Where is the queen in column x
237db96d56Sopenharmony_ci        self.row = [0] * n              # Is row[y] safe?
247db96d56Sopenharmony_ci        self.up = [0] * (2*n-1)         # Is upward diagonal[x-y] safe?
257db96d56Sopenharmony_ci        self.down = [0] * (2*n-1)       # Is downward diagonal[x+y] safe?
267db96d56Sopenharmony_ci        self.nfound = 0                 # Instrumentation
277db96d56Sopenharmony_ci
287db96d56Sopenharmony_ci    def solve(self, x=0):               # Recursive solver
297db96d56Sopenharmony_ci        for y in range(self.n):
307db96d56Sopenharmony_ci            if self.safe(x, y):
317db96d56Sopenharmony_ci                self.place(x, y)
327db96d56Sopenharmony_ci                if x+1 == self.n:
337db96d56Sopenharmony_ci                    self.display()
347db96d56Sopenharmony_ci                else:
357db96d56Sopenharmony_ci                    self.solve(x+1)
367db96d56Sopenharmony_ci                self.remove(x, y)
377db96d56Sopenharmony_ci
387db96d56Sopenharmony_ci    def safe(self, x, y):
397db96d56Sopenharmony_ci        return not self.row[y] and not self.up[x-y] and not self.down[x+y]
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_ci    def place(self, x, y):
427db96d56Sopenharmony_ci        self.y[x] = y
437db96d56Sopenharmony_ci        self.row[y] = 1
447db96d56Sopenharmony_ci        self.up[x-y] = 1
457db96d56Sopenharmony_ci        self.down[x+y] = 1
467db96d56Sopenharmony_ci
477db96d56Sopenharmony_ci    def remove(self, x, y):
487db96d56Sopenharmony_ci        self.y[x] = None
497db96d56Sopenharmony_ci        self.row[y] = 0
507db96d56Sopenharmony_ci        self.up[x-y] = 0
517db96d56Sopenharmony_ci        self.down[x+y] = 0
527db96d56Sopenharmony_ci
537db96d56Sopenharmony_ci    silent = 0                          # If true, count solutions only
547db96d56Sopenharmony_ci
557db96d56Sopenharmony_ci    def display(self):
567db96d56Sopenharmony_ci        self.nfound = self.nfound + 1
577db96d56Sopenharmony_ci        if self.silent:
587db96d56Sopenharmony_ci            return
597db96d56Sopenharmony_ci        print('+-' + '--'*self.n + '+')
607db96d56Sopenharmony_ci        for y in range(self.n-1, -1, -1):
617db96d56Sopenharmony_ci            print('|', end=' ')
627db96d56Sopenharmony_ci            for x in range(self.n):
637db96d56Sopenharmony_ci                if self.y[x] == y:
647db96d56Sopenharmony_ci                    print("Q", end=' ')
657db96d56Sopenharmony_ci                else:
667db96d56Sopenharmony_ci                    print(".", end=' ')
677db96d56Sopenharmony_ci            print('|')
687db96d56Sopenharmony_ci        print('+-' + '--'*self.n + '+')
697db96d56Sopenharmony_ci
707db96d56Sopenharmony_cidef main():
717db96d56Sopenharmony_ci    import sys
727db96d56Sopenharmony_ci    silent = 0
737db96d56Sopenharmony_ci    n = N
747db96d56Sopenharmony_ci    if sys.argv[1:2] == ['-n']:
757db96d56Sopenharmony_ci        silent = 1
767db96d56Sopenharmony_ci        del sys.argv[1]
777db96d56Sopenharmony_ci    if sys.argv[1:]:
787db96d56Sopenharmony_ci        n = int(sys.argv[1])
797db96d56Sopenharmony_ci    q = Queens(n)
807db96d56Sopenharmony_ci    q.silent = silent
817db96d56Sopenharmony_ci    q.solve()
827db96d56Sopenharmony_ci    print("Found", q.nfound, "solutions.")
837db96d56Sopenharmony_ci
847db96d56Sopenharmony_ciif __name__ == "__main__":
857db96d56Sopenharmony_ci    main()
86