棋盘上的皇后区在Python

时间:2017-01-16 18:27:41

标签: python random n-queens

这个想法是尝试通过在棋盘的每一行中完全随机地放置女王来尝试解决“女王问题”,并看看解决它需要多少次重复。国际象棋棋盘可以是任何尺寸。

我的想法是创建s列表,每个列表包含s“空”字符(下划线)。然后为每一行随机选择一个位置插入皇后(“I”值)然后标记下面的所有位置和对角线向下(我要逐行,所以我不必打扰上面的行)如果在任何迭代中,女王的随机选择位置与该行中任何X的位置匹配,我从头开始新的棋盘。

我有类似的东西,但似乎卡在第19行(标有注释),但它没有给我任何错误。有什么不对?另外,我的解决方案(除了那条线)是否正确?

from random import *


#Success flag
success = 0

#Trials counter
trials = 0


s = input ("enter board size\n")
s = int(s)
block = 1 #blockade
queen = 2 #queen
board = [[0 for x in range(s)] for y in range(s)] 

while success == 0:
    for y in range (0, s-1):
        pos = randint(0,s-1)    #line 19
        if board[y][pos] != block:
            board[y][pos] = queen
            a = 1
            for z in range (y, s-2):
                board[z + 1][pos] = block
                if pos - a >= 0:
                    board[z + 1][pos - a] = block
                if pos + a <= s-1:
                    board[z + 1][pos + a] = block
                a = a + 1
            success = 1
        else:
            success = 0


#Printing board
for y in range (0, s-1):
    print (board[y])

print ("Number of trials:\n")
print (trials)

3 个答案:

答案 0 :(得分:2)

一些问题:

  • range函数的第二个参数代表访问的第一个数字,所以大多数时候你只有一个简短。
  • 您在尝试失败时需要退出 y 上的循环:您不想继续下一行,但重启
  • 您需要在每次尝试失败后重置电路板,或者在每次尝试之前放置:
  • 如果在多次迭代后没有找到解决方案,您应该建立一些安全性来退出,否则您将面临被卡住的风险。对于输入1,2或3,没有解决方案。
  • 试验编号永远不会增加
  • 不是盲目地选择一个位置,你最好只从可用的位置中选择(没有被阻挡),或者你将进行大量的试验:对于8号大小,它并不罕见没有这种过滤就需要10万次试验!

查看更正的代码,并在我做出更改的评论中

import random

s = input ("enter board size\n")
s = int(s)
trials = 0
block = 1
queen = 2
# add some maximum to the number of attempts
max_trials = 100000 
success = 0

# add safety measure to avoid infinite looping
while success == 0 and trials <= max_trials:
    # initialise board before every trial
    board = [[0 for x in range(s)] for y in range(s)]
    # assume success until failure
    success = 1
    # count trials
    trials += 1 
    for y in range (0, s): # use correct range
        # get the fields that are still available in this row
        available = [x for x, i in enumerate(board[y]) if i == 0]
        if len(available) == 0:
            success = 0
            # exit for loop, you want to start a next trial
            break
        # choose a random position among available spots only
        pos = available[random.randint(0, len(available)-1)]    
        board[y][pos] = queen
        a = 1
        for z in range (y+1, s): # use correct range
            board[z][pos] = block
            if pos - a >= 0:
                board[z][pos - a] = block
            if pos + a < s:
                board[z][pos + a] = block
            a = a + 1

for y in range (0, s): # use correct range
    print (board[y])

print ("Number of trials:", trials)

repl.it

上查看它

答案 1 :(得分:2)

这是一个简短的解决方案,基于对放置的皇后坐标进行算术运算:

import random, itertools

def clashes(p,q):
    a,b = p
    c,d = q
    return a == c or b == d or abs(a-c) == abs(b-d)

def solution(queens):
    #assumes len(queens) == 8
    return not any(clashes(p,q) for p,q in itertools.combinations(queens,2)) 

def randSolve():
    counter = 0
    while True:
        counter += 1
        queens = [(i,random.randint(1,8)) for i in range(1,9)]
        if solution(queens): return counter, queens

print(randSolve())

上次我跑了,我得到了:

(263528, [(1, 4), (2, 7), (3, 3), (4, 8), (5, 2), (6, 5), (7, 1), (8, 6)])

意味着在263527次失败后遇到第一个解决方案。平均而言,在获得成功之前,您可能会遇到182360次失败。

答案 2 :(得分:0)

尝试不同的行并且这次失败后,你必须创建一个新的空板,如果成功为0,你应该打破for循环。

while success == 0:
    board = [[0 for x in range(s)] for y in range(s)]
    for y in range (0, s):
        pos = randint(0,s-1)    #line 19
        if board[y][pos] != block:
            board[y][pos] = queen
            for i in range(y+1, s):
                board[i][pos] = block
            success = 1
        else:
            success = 0
            break
    trials += 1

您可以遵循相同的逻辑来实现对角线情况。