標籤:

Excel+VBA製作數獨(一):演算法篇

常用功能部分遲遲沒有更新,因為工作中寫的很多宏都是特有的,對其他人的用處幾乎為零。一直沒有找到好的應用場景,索性弄一些有意思的小功能,把VBA的編程屬性展開來說一說。

一、關於數獨

數獨的內容可以自行上網搜索,不再贅述,這裡想講的是Excel與數獨。在Offic2016的版本中,新建文檔時有各種各樣的模板供我們選擇,其中就有數獨。

如果默認中沒有,可以嘗試搜索。這裡比較常用是萬年曆,有機會我們可以試試用VBA生成。這裡的所有模版應該都是用函數來實現的,這個「數獨求解」是先將每一格中可能的數字都列舉出來,再輸入初始狀態,然後利用各種條件函數來循環求解。

這個看起來很神奇的樣子!正如知乎VBA話題下有一個提問,Excel 不用 VBA,你使用過哪些絕妙的公式? - Microsoft Excel,我覺得很好。確實,能用函數解決的就盡量不要用VBA,畢竟函數方法更具有普適性。但是如果函數方法畢竟能力有限,有些功能實現起來太過於複雜,不免有些本末倒置,還是用VBA自己封裝一個函數來的痛快。

二、生成數獨

一般人可能更關心的是數獨求解,因為更具有實用性。然而求解也好,出題也好,本質還是生成一個數獨。求解不過是,在給定的條件下生成數獨;出題則是,在生成數獨後隱藏條件。

生成數獨的方法是隨機填數:從第一行第一列開始,隨機從1到9中選擇一個數字,如果滿足條件則填入,不滿足則再隨機一次。如果都不滿足,則將前一個填入的數字清空,從前一格開始隨機,這樣直到所有格子都被填滿。

這種方法叫回溯。然而數獨81個空格,每個空格能填入9個數字,9^{81} 這麼大的天文數字即使是計算機也hold不住。考慮到這其中有大部分都是無用的,所以我們要將隨機的可能範圍降到最小,使每一次產生的分支儘可能的少,這個方法叫做剪枝

所以,我們將方法描述修改為:從滿足條件的數字從選擇一個填入,如果不存在滿足條件的數字,則回到前一格重新隨機填入。

三、類模塊

在數獨的生成過程中,針對每一個單元格我們有許多相關的數據。比如上面第二幅圖,左邊兩個小宮格分別記錄初始狀態和完成狀態,右邊兩個大宮格分別記錄每個單元格初始可以填入的數字,以及滿足條件的數字。

我們可以用多個數組來存儲這些數據,也可以將每個單元格定義為一個對象,這個對象中就包含了這些數據,然後將單元格對象存入一個數組。對象在VBA中也叫類,對象的創建,需要在類模塊中完成。也就是說,在VBA中可以用類模塊,來完成一些其他語言中面向對象式的編程。

基本方法就先介紹到這裡,下一篇我們從類模塊開始實現。

推薦閱讀:

Excel+VBA製作萬年曆(一):計算方法
Excel+VBA製作數獨(二):類模塊篇
Excel+VBA圖靈完備:Rule 110

TAG:VBA | Excel编程 |