مسئلهٔ ۸ وزیر میپرسد که در یک صفحهٔ شطرنج چهطور میتوانیم ۸ مهرهٔ وزیر را چنان قرار دهیم که هیچکدام در معرض تهدید دیگری نباشد. در ریاضیات و علوم کامپیوتر، مسئلهٔ n وزیر یک نسخهٔ تعمیمیافته از ۸ وزیر میباشد که برای اکثر nهای صحیح مثبت (یا طبیعی) بیشتر از یک چینش وجود دارد.
قبلاً یک روش برای پیدا کردن راه حل برای مسئلهٔ ۸ وزیر با استفاده از الگوریتم ژنتیک ارائه دادم. حال میخواهم یک روش دیگر برای همین هدف اما به صورت یک الگوریتم قطعی و تصادفی به همراه کد پایتون ارائه دهم.
کد پایتون
from typing import List, Tuple
from pprint import pprint
import random
def empty_slots(board: List[List[int]]) -> List[Tuple[int, int]]:
result = [(x//8, x%8) for x in range(64)]
for i, row in enumerate(board):
for j, slot in enumerate(row):
if slot != 0:
for k in range(8):
if (j, k) in result:
result.remove((j, k))
if (k, i) in result:
result.remove((k, i))
for k in range(j, -1, -1):
if (k, i-abs(k-j)) in result:
result.remove((k, i-abs(k-j)))
for k in range(j, 8):
if (k, i+abs(k-j)) in result:
result.remove((k, i+abs(k-j)))
for k in range(i, -1, -1):
if (j+abs(k-i), k) in result:
result.remove((j+abs(k-i), k))
for k in range(i, 8):
if (j-abs(k-i), k) in result:
result.remove((j-abs(k-i), k))
return result
if __name__ == "__main__":
left_queens = 8
board = None
while left_queens:
left_queens = 8
board = [[0] * 8 for _ in range(8)]
while True:
empty = empty_slots(board)
if len(empty) == 0:
break
x, y = random.choice(empty)
board[y][x] = 1
left_queens -= 1
pprint(board)
- تابع
empty_slotsیک لیست از موقعیتهایی را برمیگرداند که توسط هیچ وزیری تهدید نمیشود. - صفحهٔ بازی در متغیر
boardبه صورت یک لیست تودرتو ذخیره میشود. هر عضو لیست داخلی، یک عدد صحیح است که یا یک است (وزیری در آن قرار دارد) یا صفر (خالی است). - همانطور که در کد مشاهده میکنید، متغیر
left_queensدر ابتدا برابر ۸، تعداد کل وزیرهایی که باید بدون در معرض تهدید قرار گرفتن در صفحه قرار بگیرند، میباشد. - در حلقهٔ
whileداخلی ابتدا فهرستی از موقعیتهایی که هم خالی هستند (هیچ مهرهای در آن وجود ندارد) و هم جزو مکانهای حملهٔ یک وزیر نیستند توسط تابعempty_slotsساخته میشود و درemptyذخیره میشود. - در صورتی که نتوان هیچ وزیر جدیدی را در صفحهٔ بازی قرار داد، حلقهٔ
whileداخلی شکسته میشود. - یک موقعیت تصادفی از میان موقعیتهای آزاد با استفاده از
random.choiceانتخاب میشود و در آن یک وزیر قرار داده میشود. - با توجه به این که حلقهٔ
whileداخلی آخرین جمله (یا دستور) در حلقهٔwhileخارجی است؛ کنترل برنامه بلافاصله به اول حلقهٔwhileخارجی و بررسی شرطش واگذار میشود. - در شرط حلقهٔ
whileخارجی تعداد وزیرهای باقیمانده بررسی میشود و در صورتی که برابر با صفر نبود، دوباره از اول به جستوجوی یک راه حل میرود. - در صورتی که تعداد وزیرهای باقی مانده برابر صفر باشد، یعنی متغیر ارزش بولی متغیر
left_queensبرابر نادرست باشد، حلقهwhileبیرونی نیز شکسته میشود و نهایتاً راه حل پیدا شده به خروجی فرستاده میشود.
طرز کار تابع empty_slots
- این تابع ابتدا در اولین خطّ خود یک فهرست از تمام موقعیتهای صفحهٔ شطرنج میسازد.
- سپس با بررسی تکتک خانههای صفحه، آنهایی که یک وزیر در خود دارند؛ تمام موقعیتهایی که زیر تهدید وزیر است و همچین خود خانهٔ وزیر از فهرست موقعیتهای خالی حذف میشود.
بهینهسازی
به طرق مختلف میتوان کد نوشته شده توسط بنده را بهبود داد و بهینه کرد. بزرگترین بهینهسازیای که به ذهن خودم میرسد، این است که تابع empty_slots یک ورودی جدید بپذیرد: موقعیتهایی که تا الآن خالی بودند. به این ترتیب میتوانیم تنها برای دفعهٔ اول، فهرست تمام موقعیتها را به این تابع بدهیم و دفعات بعد، فهرست ساخته شده توسط دور قبلِ حلقه را به تابع بدهیم.



