漢諾塔游戲,是個佷益智的游戲,其中也蘊含了一些數(shù)學(xué)的知識,故事的背景甚至蘊含了一些古人對宇宙的思考。今天我們來聊下這個游戲,僅僅從游戲的方法和策略的總結(jié)上對這個游戲進(jìn)行一下解剖:
游戲簡介

`由來與傳說:`
法國數(shù)學(xué)家`愛德華·盧卡斯`曾編寫過一個印度的古老傳說:在世界中心貝拿勒斯
(在印度北部)的圣廟里,一塊黃銅板上插著三根寶石針。印度教的主神`梵天`
在創(chuàng)造世界的時候,在其中一根針上從下到上地穿好了由大到小的64片金片,這
就是所謂的漢諾塔。不論白天黑夜,總有一個僧侶在按照下面的法則移動這些金
片:一次只移動一片,不管在哪根針上,小片必須在大片上面。僧侶們預(yù)言,當(dāng)所
有的金片都從梵天穿好的那根針上移到另外一根針上時,世界就將在一聲霹靂中消
滅,而`梵塔`、`廟宇`和`眾生`也都將同歸于盡。
不管這個傳說的可信度有多大,如果考慮一下把64片金片,由一根針上移到另一
根針上,并且始終保持上小下大的順序。這需要多少次移動呢?這里需要遞歸的方
法。假設(shè)有n片,移動次數(shù)是f(n).顯然f(1)=1,f(2)=3,f(3)=7,且f(k+1)=2*f(k)+1。
此后不難證明f(n)=2^n-1。n=64時,
假如每秒鐘一次,共需多長時間呢?一個平年365天有31536000 秒,閏年366天有
31622400秒,平均每年31556952秒,計算一下:
18446744073709551615秒
這表明移完這些金片需要5845.54億年以上,而地球存在至今不過45億年,太陽系
的預(yù)期壽命據(jù)說也就是數(shù)百億年。真的過了5845.54億年,不說太陽系和銀河系,
至少地球上的一切生命,連同梵塔、廟宇等,都早已經(jīng)灰飛煙滅。
游戲的目的
很多人最初接觸到這個益智游戲,都是直接用5個以上圓盤開始游戲的,但是又不太清楚具體的移動規(guī)律,導(dǎo)致玩兒了半天也沒有將所有圓盤成功移動到C柱子上,甚至玩過以后就得出了一個結(jié)論,這游戲太沒意思了。。。
實際上這種益智類的游戲,往往都是具有一定的方法和規(guī)律可循的,因為這類游戲的目的就是讓人開發(fā)思維,啟迪智慧。通常這類游戲或者玩具是最適合給孩子玩的。
既然這個游戲有益智的作用,我們就應(yīng)該掌握玩這種游戲的方法或者至少我們應(yīng)該學(xué)會教孩子如何玩這個游戲,才能讓這個益智游戲開發(fā)孩子的思維啟迪孩子的智慧?。?/p>
游戲的策略
在這一部分,我們要分為兩點去講:1. 推導(dǎo)和歸納;2. Python代碼的實現(xiàn)。
1. 推導(dǎo)和歸納
說到歸納和總結(jié),我們可以參照數(shù)學(xué)上的歸納方法。
舉個例子:
` 1 = 1 `
` 1×2 = 2 `
` 1×2×3 = 6 `
` 1×2×3×4 = 24 `
` 1×2×3×4×5 = 120 `
` ... `
` 1×2×3×...×(n-1)×n = f(n) `
上面的歸納的是一個函數(shù),也就是階乘,表達(dá)式為:
f(n) = n! = n * (n-1) * ... * 1 = n * (n-1)!
歸納之后便形成了一個比較抽象、但是很容易記住的方法——公式。
通過歸納和演繹,用一些簡單的、易操作的數(shù)字和步驟進(jìn)行推演,形成適用于更廣范圍的通行公式。
-
我們來看一下漢諾塔如何推演
要求:將圓盤從 <起點A柱子>借助<緩沖B柱子>移動到<終點C柱子>
分析:為了更好的解釋說明操作步驟,我們講圓盤從小到大依次取名為1、2、3、4、5...
步驟:當(dāng)A柱子上有1個圓盤時
A-->C表示將1移到C:1-->C:圓盤為奇數(shù)時,第一步指向終點C柱當(dāng)A柱子上有2個圓盤時
①A-->B表示將1移到B:1-->B:圓盤為偶數(shù)時,第一步指向緩沖B柱
②A-->C表示將2移到C:2-->C:最下面的圓盤,移動到終點C柱
③B-->C表示將1移到C:1-->C:緩沖柱上的圓盤,移動到終點C柱當(dāng)A柱子上有3個圓盤時
①A-->C表示將1移到C:1-->C:圓盤為奇數(shù)時,第一步指向終點C柱
①A-->B表示將2移到B:2-->B:將2號圓盤移到緩沖B柱
①C-->B表示將1移到B:1-->B:將1號圓盤移到緩沖B柱
②A-->C表示將3移到C:3-->C:最下面的圓盤,移到到終點C柱
③B-->A表示將1移到A:1-->A:將1號圓盤移到起點A柱
③B-->C表示將2移到C:2-->C:將2號圓盤移到終點C柱
③A-->C表示將1移到C:1-->C:將1號圓盤移到終點C柱
-
根據(jù)上面寫的3個推演步驟,我們進(jìn)行歸納如下:
- 整個移動過程(排除只有一個圓盤的特殊情況),可以分為三個階段,用①②③表示。
- ①階段,把
n-1個圓盤移到緩沖B柱;
②階段,把第n個圓盤移到終點C柱;
③階段,把n-1個圓盤移到終點C柱。 - 其中,第②階段,是在最中間的
一步,第①階段和第③階段的移動步數(shù)是一樣多的。 - 第一步的移動方向,根據(jù)圓盤的個數(shù)不同而定
奇數(shù)個圓盤,第一步一定是移到終點C柱
偶數(shù)個圓盤,第一步一定是移到緩沖B柱
別小瞧這個方向的定位,以后每次移動1、2圓盤時,都是按照這個方向定位的。 - 我們把移動圓盤的過程分為
n輪,每一輪都要移動1、2、1和另一個圓盤;
并且每一輪移動1、2、1圓盤的時候,都是按照固定的規(guī)律去移動的。
我們會以1、2圓盤同時所在的柱子為視角做定位,判斷移動的方向。下面有一個圖,上面詳細(xì)寫了具體的移動順序和方法:
- 要想明白具體是如何做的,只用眼睛看是很難理解的,當(dāng)你跟著我寫的步驟操作幾次之后,你一定會豁然開朗,原來移動起來是這么簡單~
2. Python代碼的實現(xiàn)
當(dāng)然了用文字,或者截圖去描述這個過程,無論如何都算不上簡單明了。Python語言中,用函數(shù)將這個游戲的移動方法,定義成了一個遞歸函數(shù),寫法竟然非常的簡單:
# 請編寫 `move(n, a, b, c)`函數(shù),它接收參數(shù) n,表示3個柱子A、B、C中
# 第1個柱子A的盤子數(shù)量,然后打印出把所有盤子從A借助B移動到C的方法
# -*- coding: utf-8 -*-
def move(n, a, b, c):
if n == 1:
print(a, '-->', c)
# 下面else的部分是需補全的代碼,也就是移動方法
else:
move(n-1,a,c,b) # 思考一下為什么要這樣寫?
move(1,a,b,c) # 想一下,這是哪個階段?
move(n-1,b,a,c) # 你知道,這最后的一步,是什么意思嗎?
# 有3個圓盤時
move(3, 'A', 'B', 'C')
# 換行
print('\n')
# 有4個圓盤時
move(4, 'A', 'B', 'C')
# 這是有3個圓盤時的【期待輸出結(jié)果】:
# A --> C
# A --> B
# C --> B
# A --> C
# B --> A
# B --> C
# A --> C
你可以復(fù)制一下這段代碼,去驗證一下結(jié)果是不是和你自己移動的結(jié)果一樣!
