摘要:謝耳朵愛(ài)玩的游戲,石頭剪子布的升級(jí)版。擁有最高點(diǎn)數(shù)的玩家獲勝,其點(diǎn)數(shù)必須等于或低于點(diǎn)。在編寫這個(gè)游戲的過(guò)程中第一次引入了類概念。宇宙空間中微小的摩擦力和隕石撞擊后受到的力,都要考慮并且編入游戲中。
人人都應(yīng)該學(xué)編程嗎?隨著每個(gè)人的工作與電腦連結(jié)愈發(fā)緊密,也許這是真的。
我是游戲設(shè)計(jì)師,在分工細(xì)致的國(guó)內(nèi)網(wǎng)游業(yè)界,不需要研發(fā)或美術(shù)背景也能擔(dān)當(dāng)游戲設(shè)計(jì)重任的角色多了起來(lái)。有時(shí)候他們甚至只需負(fù)責(zé)撰寫劇情文檔或游戲文案,一切涉及程序的工作內(nèi)容都有開(kāi)發(fā)同學(xué)代為解決。不離開(kāi)自己的 comfort zone 也能很好地完成任務(wù)。
但在本職之外,了解程序如何工作,能帶來(lái)許多好處:日常工作中重復(fù)的工序可以自行使用程序解決;易犯的錯(cuò)誤可以通過(guò)程序避免;更不用提編寫腳本的能力,能夠讓你直接控制你所設(shè)計(jì)的內(nèi)容的每個(gè)細(xì)節(jié),了解設(shè)計(jì)的邊界及內(nèi)部空間。
畢竟,太初之時(shí),只有程序。程序員想:「專職美術(shù)、策劃、設(shè)計(jì)、產(chǎn)品經(jīng)理是好的。」便有了他們一干人等。
「每周一游」:每個(gè)星期快速開(kāi)發(fā)一個(gè)游戲,連續(xù)進(jìn)行數(shù)個(gè)星期。這是許多開(kāi)發(fā)者們磨練自己想法和技巧的方式。
我沒(méi)有計(jì)算機(jī)背景或美術(shù)基礎(chǔ),但乘中國(guó)游戲行業(yè)大發(fā)展,卻也幸運(yùn)入行成為一名游戲策劃。我希望在日常工作之余,用一個(gè)辦法來(lái)鍛煉自己對(duì)游戲系統(tǒng)設(shè)計(jì)和開(kāi)發(fā)過(guò)程的理解。因此,我參加了 Coursera 上的幾個(gè)課程,并且用課程提供的方便工具來(lái)實(shí)現(xiàn)設(shè)想中的功能。
一開(kāi)始的成果非常基本、非常簡(jiǎn)單,但到后面挑戰(zhàn)等級(jí)逐漸上升,到最后已經(jīng)能獨(dú)立完成 600 行左右的程序。
接下來(lái)我就給各位看看我在這近四個(gè)月中的成果,以及我從中學(xué)習(xí)和體會(huì)到的內(nèi)容。我盡量省略比較枯燥的實(shí)現(xiàn)細(xì)節(jié),一來(lái)可以避免無(wú)聊,二來(lái)需要下功夫的東西還是親手實(shí)踐比較有幫助。如有興趣可來(lái)我的微博交流。
第一周:包剪錘蜥史波克(Rock-paper-scissors-lizard-Spock)
Sheldon 喜歡的游戲。
謝耳朵愛(ài)玩的游戲,石頭剪子布的升級(jí)版。內(nèi)容最最基本,只要在控制臺(tái)里輸入命令,命令通過(guò) if-elif-else 轉(zhuǎn)化成數(shù)字(0-4,分別代表出的5個(gè)東西)。
電腦則會(huì)隨機(jī)生成一個(gè)數(shù)字,轉(zhuǎn)換成字符串。再根據(jù)雙方數(shù)字,用 if-else 判斷勝負(fù)即可。
對(duì)我來(lái)說(shuō)這是自己親手編寫的第一個(gè)游戲。它雖然簡(jiǎn)單,但包含了一個(gè)游戲必須的全部要素:它有著固定的開(kāi)始和結(jié)束,以及勝負(fù)的規(guī)則。
第二周:猜數(shù)字猜數(shù)字游戲就是由電腦隨機(jī)生成指定范圍內(nèi)的一個(gè)數(shù)字,由你來(lái)猜,電腦告訴你是高還是低,一定次數(shù)后未猜中則輸?shù)舻挠螒颉?/p>
在這個(gè)游戲中第一次引入全局變量的概念。初始化時(shí),上下限以及允許你猜測(cè)的次數(shù)都是讀取全局變量。這樣一來(lái),我們可以在游戲核心的方法之外,使用別的方法來(lái)修改全局變量,讓玩家可以自己選擇數(shù)字范圍和猜測(cè)次數(shù)。游戲本身則依然是 if-elif-else 這樣寫成的。
這是我親手編寫的第一個(gè)可以由玩家調(diào)整游戲設(shè)置的游戲。
第三周:秒表游戲秒表游戲是個(gè)考反應(yīng)的游戲。點(diǎn)擊開(kāi)始后秒表開(kāi)始向前走,若你按停秒表時(shí),秒表的時(shí)間恰巧停在整數(shù)(小數(shù)點(diǎn)后為0),則你得1分。游戲會(huì)記錄你按停的總次數(shù)和得分?jǐn)?shù)。
這個(gè)游戲中涉及到為每個(gè)功能編寫多帶帶的方法。如玩家控制的按鈕start()、stop()、reset();游戲本身時(shí)間前進(jìn)的tick()等。同時(shí),為了讓時(shí)間正確地顯示在屏幕上,還有一個(gè)將時(shí)間轉(zhuǎn)化為「A:BC:D」這種形式的方法。
我們計(jì)時(shí)的方法是定義一個(gè)叫 time 的變量。由于這個(gè)游戲中最小的計(jì)時(shí)單位是 0.1 秒,所以每經(jīng)過(guò) 100 毫秒我們就讓這個(gè)數(shù)字 +1。與此同時(shí),編寫一個(gè) format() 方法經(jīng)過(guò)一系列計(jì)算將這個(gè)數(shù)字轉(zhuǎn)化為分、秒和0.1秒,顯示在屏幕上即可。判斷玩家是否得分仍然使用 if-else 結(jié)構(gòu)。
這是第一次涉及到玩家進(jìn)行的復(fù)雜操作,也是第一次認(rèn)識(shí)到,在游戲畫面的表象之下究竟應(yīng)該有些什么機(jī)制在運(yùn)行。
第四周:乒乓(Pong)終于我們從小朋友玩的游戲進(jìn)入了街機(jī)時(shí)代!
傳說(shuō) Pong 是世界上第一個(gè)電子游戲。在那個(gè)游戲機(jī)只有滾軸操作的年代,這個(gè)有著極簡(jiǎn)單畫面的游戲啟發(fā)了無(wú)限后來(lái)者。看著它在手下形成還有些小感動(dòng)呢。
這個(gè)游戲也是我制作的第一個(gè)不模擬現(xiàn)實(shí)中的「邏輯」,而是模擬「物理」的游戲。它的核心部分是球的速度變化、板子的速度變化,以及球與邊界和板子的碰撞。
為了讓這個(gè)游戲不至于無(wú)限地進(jìn)行下去,我讓球的速度隨著每一次板子碰撞上升。但上升的公式寫成了指數(shù)函數(shù),于是這球就啪啪啪越打越快每一回合很快就結(jié)束了。若改為對(duì)數(shù)函數(shù),則會(huì)緩慢地趨近一個(gè)上限,令每一回合后期的雙人對(duì)局非常緊張、充滿變數(shù)。
這是我第一次體會(huì)到游戲的「手感」到底是怎么回事。每一次對(duì)參數(shù)的細(xì)微調(diào)整對(duì)手感帶來(lái)的變化,可以讓設(shè)計(jì)者與游戲本身有著更深刻的接觸。這是在目前分工充分的網(wǎng)游公司的日常工作中體會(huì)不到的感覺(jué)。
除此之外,很快地你就能從一個(gè)簡(jiǎn)單原型中看出未來(lái)變化的可能。是否可以加入:
「球擊打在板子的不同部位,會(huì)彈向不同方向」?
「當(dāng)板子擊球時(shí),板子本身的速度會(huì)令球曲線飛出」?
或者「連續(xù)擊中球數(shù)次后玩家可以發(fā)出大招」?
等等諸如此類。想到這里,這個(gè)游戲能成為數(shù)十年游戲業(yè)的起點(diǎn),也是有其道理的。
第五周:記憶游戲記憶游戲就是將多對(duì)牌打亂順序朝下放置,玩家一次翻開(kāi)兩張,若相同則原樣留著,若不同則翻回去。所有牌都翻開(kāi)后玩家勝利。
在這個(gè)游戲中,暫且用數(shù)字來(lái)代替撲克牌。我們用了一個(gè) list (我有點(diǎn)搞不太清 list, array, tuple, set 幾個(gè)詞的中文翻譯,不亂講了……)來(lái)以 Boolean 值(True 和 False)記錄每張牌是否翻開(kāi)的狀態(tài)。當(dāng)設(shè)為翻開(kāi)時(shí),露出數(shù)字,否則在相應(yīng)位置繪制一張牌背。
這個(gè)游戲的邏輯方面比較 tricky 的地方就是整個(gè)游戲?qū)嶋H上有三種狀態(tài),需要分別處理:
新游戲,一張牌都沒(méi)翻開(kāi)
翻開(kāi)了(本回合內(nèi))第一張牌,等待翻開(kāi)第二張
翻開(kāi)了(本回合內(nèi))第二張牌,等待判斷是否相同
于是我使用一個(gè)叫做 state 的變量,分別以 0, 1, 2 代表三種狀態(tài)。在核心方法中利用 state 的值來(lái)決定接下來(lái)要做什么。
第六周:21點(diǎn)(Blackjack)啊,21 點(diǎn)。我人生中接觸的第一個(gè)撲克游戲。是的,在我會(huì)打「拖拉機(jī)」之前,7歲的我就在DOS下的初代大航海時(shí)代的酒館里學(xué)會(huì)了 21 點(diǎn)。這是年幼的我在那個(gè)游戲里玩懂的唯一一個(gè)系統(tǒng)……
這是個(gè)賭博游戲。簡(jiǎn)單來(lái)說(shuō)規(guī)則是:莊家給自己和玩家各發(fā)(deal)一張暗牌、一張明牌,玩家決定是否繼續(xù)加牌(hit);玩家加牌結(jié)束(stand)后莊家自行加牌,接著雙方攤牌。擁有最高點(diǎn)數(shù)的玩家獲勝,其點(diǎn)數(shù)必須等于或低于21點(diǎn)。
在編寫這個(gè)游戲的過(guò)程中第一次引入了類(class)概念。因?yàn)樵谟螒蛑性S多物件都會(huì)重復(fù)出現(xiàn),使用類可以很方便地重復(fù)制造它們:
每一張牌是 Class Card;
方法 get_suit() 可以獲取它的花色;
方法 get_rank() 可以獲取它的數(shù)字;
還有一個(gè)方法來(lái)把它繪制出來(lái)。
手牌是 Class Hand;
方法 add_card() 可以在手牌中增加一張牌;
方法 get_value() 可以算出手牌的分?jǐn)?shù)。
牌庫(kù)則是 Class Deck。
方法 shuffle() 可以洗牌庫(kù);
方法 deal_card() 用來(lái)發(fā)牌。
規(guī)定好這些基礎(chǔ)方法以后,重發(fā)牌、加牌、攤牌都可以通過(guò)這些功能的組合來(lái)實(shí)現(xiàn)。例如開(kāi)局就是洗牌庫(kù),向雙方發(fā)牌;雙方手牌加上兩張發(fā)出來(lái)的牌。等等。
此外這個(gè)游戲還第一次涉及到怎樣在畫面上繪制固定的圖形。整張牌表是一張大圖,怎么樣根據(jù)牌的值定位到對(duì)應(yīng)的牌面也是要好好算一下。
第七周:小行星(Asteroid)經(jīng)典街機(jī)游戲的復(fù)刻版!大制作來(lái)臨了!
這回的游戲涉及的內(nèi)容比以前多,除了控制小飛船打來(lái)打去之外,動(dòng)畫、音效、UI 等也都引入了游戲中。但每一部分的實(shí)現(xiàn)都可以通過(guò)之前嘗試的小功能疊加實(shí)現(xiàn)。簡(jiǎn)單地了解游戲圖像和聲音到底怎么運(yùn)作后,并無(wú)特別的困難。只是這一次我學(xué)著一個(gè)模塊一個(gè)模塊漸次開(kāi)發(fā)和測(cè)試,一個(gè)功能調(diào)通無(wú)誤,再進(jìn)行下一個(gè)。
反而是在游戲設(shè)計(jì)方面,制作這個(gè)游戲的過(guò)程給我?guī)?lái)很多思考。在這個(gè)游戲中可供調(diào)整的變量太多了:飛船需要推進(jìn)和旋轉(zhuǎn);但推進(jìn)是給飛船一個(gè)向前的加速度,而飛船本身還會(huì)有向著其他方向的速度。宇宙空間中微小的摩擦力、和隕石撞擊后受到的力,都要考慮并且編入游戲中。
這時(shí)你會(huì)發(fā)現(xiàn),同樣的一些參數(shù),經(jīng)過(guò)調(diào)整會(huì)讓整個(gè)游戲變得徹底不同。這艘飛船到底是笨重、轉(zhuǎn)向慢、射速慢、射程遠(yuǎn)的戰(zhàn)列艦,還是輕盈、轉(zhuǎn)向快、射速快、射程近的戰(zhàn)斗機(jī)?你要躲閃的是從一個(gè)方向襲來(lái)的流星群(隕石都從一邊來(lái),而且向一個(gè)方向阻力特別大),還是四面八方出現(xiàn)的亂石?每一種選擇,好像都挺好玩的……
到這時(shí)我才了解到一個(gè)游戲設(shè)計(jì)者腦中「指揮意圖」清晰的重要性。你到底要做一個(gè)什么樣的游戲,給玩家?guī)?lái)什么樣的情感?只有一個(gè)大概的「我要爽」是不夠的:究竟是控制巨大戰(zhàn)艦緩慢機(jī)動(dòng)將將擦過(guò)一塊流星的那種屏氣凝神的爽,還是控制戰(zhàn)斗機(jī)高速穿梭在流星群中那種險(xiǎn)象環(huán)生的爽?有時(shí)候自己也會(huì)猶豫。只有記住一開(kāi)始你要提供的是怎么樣的情感,并且在全程中反復(fù)回看,才不會(huì)偏離目標(biāo)。
一個(gè)人制作尚且如此,當(dāng)需要團(tuán)隊(duì)合作的時(shí)候,若不把一個(gè)確定的思路貫徹到底,怎么行呢?
第八周:2048啊,HTML 小游戲。在這個(gè)星期,2048 游戲突然流行了起來(lái)。于是我也跟風(fēng)復(fù)刻了一個(gè)。看似簡(jiǎn)單的游戲,真的要做出來(lái),對(duì)于新手來(lái)說(shuō)還是挺費(fèi)腦筋的。
第一個(gè)問(wèn)題就是,這個(gè)網(wǎng)格怎么做呢?我采用的轉(zhuǎn)化方法是使用一個(gè)二維的list。看起來(lái)就是:
[[0, 1, 2, 3] [0, 1, 2, 3] [0, 1, 2, 3] [0, 1, 2, 3]]
這樣一來(lái),如果我要定位到第三(2)行第一(0)個(gè)格子,我就讀取這個(gè) list 中的 List[2][0] 即可。這樣一來(lái)看起來(lái)頗為直觀,又能解決問(wèn)題。
接下來(lái)又有好幾個(gè)問(wèn)題需要一一解決。首先,當(dāng)你按下一個(gè)方向鍵以后,所有行(列)的數(shù)字都會(huì)向著那個(gè)方向合并。這件事怎么辦呢?
首先我多帶帶寫了一個(gè) merge() 方法。只要傳來(lái)一個(gè) list,就逐個(gè) iterate 并將合并后的值返回去。然后在主要 Class 中間的移動(dòng)方法 move() 中規(guī)定,向哪個(gè)方向移動(dòng),就以那個(gè)方向的四個(gè)格子為排頭建立四個(gè) list,傳去 merge() 那邊再替換回來(lái)。這樣一來(lái)這個(gè)游戲的核心規(guī)則就實(shí)現(xiàn)完成,剩下的邊邊角角多測(cè)試修繕即可。當(dāng)測(cè)試成功的那一刻真是有一種爆棚的成就感——很少有解謎游戲的謎題能這樣讓你研究琢磨幾個(gè)小時(shí)。
當(dāng)你把游戲的每個(gè)部分分入不同的 Class 和方法中后,可以感覺(jué)到效率提升不少。例如你在制作模塊 B ,此時(shí)要用到模塊 A 中的功能,你可以完全不管模塊 A 怎么實(shí)現(xiàn)的,只要把指定的數(shù)據(jù)傳進(jìn)去,等著它傳出結(jié)果來(lái)就好了。
第九周:Cookie Clicker(點(diǎn)擊-放置游戲)這是個(gè)挺有病(誤)的游戲。你只要點(diǎn)這塊餅干就可以加餅干數(shù),餅干可以買幫你加餅干的道具,越高級(jí)的道具加餅干越快,子子孫孫無(wú)窮匱也。聽(tīng)說(shuō)最近這種放置類游戲在一些小圈子里挺流行的……
游戲本身的設(shè)計(jì)相對(duì)簡(jiǎn)單。加餅干數(shù),加加餅干速度,獲取各種升級(jí)和冷卻的時(shí)間,購(gòu)買道具等等,并不復(fù)雜。
但我們不想自己玩,我們想要電腦自動(dòng)玩,算出最快速的策略,看看到底能獲得多少餅干。
為了這樣,我們專門做了一個(gè)叫 simulator_clicker() 的方法,它會(huì)根據(jù)輸入的策略,在合適的時(shí)間購(gòu)買固定道具;而每個(gè)策略都可以另外定義。這樣一來(lái),這個(gè)方法里引用的方法又引用了別的方法,復(fù)雜性上了一個(gè)臺(tái)階。
至于「策略」,就進(jìn)入了 AI 的范疇。此時(shí)我們雖然只能使用最基本的條件判斷,但反復(fù)計(jì)算應(yīng)該讓 AI 怎樣動(dòng)作,還是挺有挑戰(zhàn)性的。只不過(guò),發(fā)現(xiàn)讓 AI 采用「純隨機(jī)策略」亂買道具出來(lái)的結(jié)果比你辛苦計(jì)算的結(jié)果還好,就有點(diǎn)蛋疼……
第十周:Yahtzee這是個(gè)投骰的游戲,同樣涉及自己的「手」概念。大家自己玩一玩這個(gè)就明白了。 這一次制作的只涉及分?jǐn)?shù)表上半?yún)^(qū)的部分。
Yahtzee游戲打印出的策略
為這個(gè)游戲編寫 AI 最有趣的地方是涉及到了概率和期望。我手上還有這么些骰子,那么接下來(lái)可能出現(xiàn)的所有手我都要算一遍,列成一個(gè)樹(shù),然后找到概率最大的一種。我把列出所有可能手、為一手計(jì)算期望值、為一手計(jì)算分?jǐn)?shù)和 AI 策略分別寫在 4 個(gè)方法里。
第十一周:僵尸末日
一群人類(綠點(diǎn))被僵尸(紅點(diǎn))包圍在破敗廢墟中的場(chǎng)景。請(qǐng)自行腦補(bǔ)。
啊,僵尸。也不知道誰(shuí)規(guī)定的,僵尸及其變種的怪物成了無(wú)數(shù)影視游戲中人類可以毫無(wú)道德顧慮地?fù)魵⒌挠螒蚬治铩?/p>
這個(gè)游戲的畫面如上圖所示:
黑色是障礙物。可以理解為房子、籬笆、爛掉的車什么的;任何單位不能通過(guò)。
紅色是僵尸。它們可以向上下左右四個(gè)方向移動(dòng),會(huì)自動(dòng)前往最近的人類。
綠色是人類。他們可以向8個(gè)方向移動(dòng),會(huì)自動(dòng)遠(yuǎn)離僵尸。請(qǐng)不要吐槽為什么顏色好像應(yīng)該反過(guò)來(lái)。
紫色是感染者。被僵尸抓到的人類就會(huì)這樣,不會(huì)動(dòng)。可以理解為啃翻在地上,過(guò)一會(huì)兒就要變成僵尸起來(lái)。
所有的格子都是可以由玩家自行布置的。因此這是個(gè)樂(lè)趣在于 YY 的沙盒游戲。
點(diǎn)擊 "humans flee" 按鈕則人類移動(dòng)一回合,點(diǎn)擊 "zombies stalk" 按鈕則僵尸移動(dòng)一回合。它們采取的尋路策略都是廣度優(yōu)先搜索。游戲不會(huì)結(jié)束,你可以在這個(gè)沙盒中給自己安排勝利條件。布置各種各樣的場(chǎng)面看著它們行動(dòng),也還能支撐個(gè)半小時(shí)的樂(lè)趣,是到目前為止制作的可玩性最強(qiáng)的游戲……
同樣的,這個(gè)游戲也是一個(gè)具有充分?jǐn)U展性的游戲。感染者會(huì)不會(huì)轉(zhuǎn)化成僵尸?人類能不能拿到武器反擊僵尸?僵尸中間會(huì)不會(huì)有特殊感染者,能夠范圍攻擊、遠(yuǎn)程拉住人類、能跳來(lái)跳去或者會(huì)爆炸?玩家這個(gè)上帝的力量有多大?跳出「玩家扮演游戲中的某個(gè)角色」的框框,會(huì)發(fā)現(xiàn)沙盒類游戲的樂(lè)趣所在。
第十二周:猜詞游戲猜詞游戲就是這樣:你指定一個(gè)詞,電腦會(huì)搜索詞庫(kù),將這個(gè)詞的字母能組成的所有詞以星號(hào)遮住,你逐個(gè)嘗試將他們列出來(lái)的游戲。
這個(gè)游戲中第一次涉及到讀取文件。
為了成功的讀取到輸入的詞匯并且匹配所有可能組成的詞,我們需要使用一個(gè) merge_sort() 方法來(lái)將一個(gè)打亂的列表變成有序的。這時(shí)我第一次接觸到「遞歸(recursion)」。
要理解遞歸,首先要理解遞歸(誤)。也就是說(shuō)這個(gè)方法自己不斷引用自己。看起來(lái)就像
merge_sort(something): ... merge_sort(something_again) ...
這樣。
設(shè)計(jì)一個(gè)遞歸方法前,首先要明確停止遞歸的條件(base case)。在這個(gè)基礎(chǔ)上推算每一步應(yīng)該怎么辦。可以拿一個(gè)簡(jiǎn)單的例子在紙上演示,無(wú)誤后寫出來(lái)看看效果。
我的設(shè)想中,當(dāng)給出一個(gè) list 后,首先應(yīng)當(dāng)將其分成兩半,當(dāng)字母的個(gè)數(shù)小于等于 1 就應(yīng)該停止遞歸。
最后寫成的方法看起來(lái)像這樣:
def merge_sort(list1): """ Sort the elements of list1. Return a new sorted list with the same elements as list1. This function should be recursive. """ new_list = list(list1) # base case: when length is 1 or 0 if len(new_list) <= 1: return new_list # recurrences: if len(new_list) > 1: # split in half mid = len(new_list) / 2 half_list1 = new_list[0:mid] half_list2 = new_list[mid:] # call merge_sort on each half list1_sorted = merge_sort(half_list1) list2_sorted = merge_sort(half_list2) # and merge each sorted <- 在這個(gè)方法中會(huì)對(duì)2個(gè)元素進(jìn)行排序 return merge(list1_sorted, list2_sorted)
對(duì)我來(lái)說(shuō)遞歸還是挺復(fù)雜的。一個(gè)簡(jiǎn)單的遞歸就要想很久,不過(guò)想清楚了之后的效果還是不錯(cuò)的。不少?gòu)?fù)雜的游戲設(shè)計(jì)中都會(huì)出現(xiàn)類似的規(guī)則。
當(dāng)然,你也可以不使用遞歸,而是設(shè)定一些條件重復(fù)地調(diào)用一個(gè)方法。但那樣的話代碼量就變得很大,執(zhí)行效率可能也會(huì)變慢。你是要犧牲易理解性換取效率,還是犧牲效率換取易理解性呢?很多時(shí)候玩家也會(huì)試圖來(lái)理解你游戲的內(nèi)在邏輯,能不能讓他們輕松辦到呢?
第十三周:九宮格(tic-tac-toe)九宮格,世界各地的小朋友可能都玩過(guò)的經(jīng)典游戲。放大到5連就是五子棋。
為這個(gè)游戲編寫電腦對(duì)手采用的是所謂的「蒙特卡羅方法」。也就是從目前這一步開(kāi)始,推算出每一個(gè)可能的游戲結(jié)果。勝則加分,負(fù)則扣分,和則不加不減;最后選定分?jǐn)?shù)最高的一步落子。這種算法在棋盤復(fù)雜的的情況下很難實(shí)用,但應(yīng)付九宮格是綽綽有余。
然后,為了測(cè)試這個(gè)對(duì)手到底強(qiáng)不強(qiáng),我把游戲規(guī)則反了一下變成「逆九宮格」。也就是誰(shuí)先連到 3 個(gè)就算輸。這種模式下,沒(méi)有下中間那個(gè)位置的不敗手,更能看出電腦的實(shí)力。第一盤我還沒(méi)反應(yīng)過(guò)來(lái),結(jié)果輸?shù)袅恕?/p>
逆九宮格:先達(dá)成三個(gè)一線者負(fù)
到這里,我編寫的 AI 就擺脫了特別直覺(jué)的 if-else 或者廣度優(yōu)先搜索規(guī)則,進(jìn)入了一個(gè)發(fā)揮其強(qiáng)大計(jì)算力的時(shí)代。假如把棋盤擴(kuò)大幾倍,勝利條件相應(yīng)放大,人類就很難戰(zhàn)勝電腦了。
第十四周:數(shù)字推盤游戲(n-Puzzle)一開(kāi)始的游戲是15個(gè)方格,數(shù)字錯(cuò)亂了,需要你來(lái)把它們移動(dòng)回正確的位置。有一種改進(jìn)型就是拼圖,首先你要找出圖片的正確順序,然后還要推回正確位置。
游戲本身的規(guī)則不難,但要做一個(gè)自動(dòng)解 Puzzle 的 AI 就有點(diǎn)意思了,根據(jù)反復(fù)試玩觀察,一個(gè)盤面可以分為幾個(gè)區(qū)域,各自有固定解法:
第二行以下第一列右側(cè)的的
第二行以下最左邊一列的
第一行的
第二行的
最末階段左上角的4個(gè)
大家可以觀察動(dòng)畫里面解開(kāi)的過(guò)程,研究一下在這些區(qū)域我讓電腦怎么動(dòng)作的……
一個(gè)個(gè)模塊分別編寫和測(cè)試,在內(nèi)部再分情況討論,真是件體力活!但只要測(cè)試無(wú)誤,無(wú)論這個(gè) puzzle 擴(kuò)展到多大,解開(kāi)它也就是時(shí)間問(wèn)題。以后誰(shuí)再拿這種東西為難你,只要把題目輸入進(jìn)去,就能看著電腦瞬間自動(dòng)解開(kāi)并且給你一個(gè)操作順序了。
結(jié)語(yǔ)在整個(gè)的 14 周過(guò)程中間,我從能寫簡(jiǎn)單的幾十行程序,逐漸進(jìn)步到能完成較復(fù)雜的600行程序(不含UI部分)。在此過(guò)程中,我逐步學(xué)到和應(yīng)用的知識(shí)有:
python 基礎(chǔ)語(yǔ)法
變量
list
方法(function)
類(class)
各種算法
遞歸
編程的 style 要求
……等等,族繁不及備載。這些知識(shí)以及應(yīng)用的方法有可能忘卻,但在此過(guò)程中有著更多東西是令我體會(huì)深刻,很難忘記的:
將「手感好」、「手感不好」等感覺(jué)分析成多個(gè)具體部分,進(jìn)行調(diào)整。
評(píng)估各種實(shí)現(xiàn)某個(gè)功能的手段,依據(jù)其復(fù)雜程度或者實(shí)現(xiàn)效率。
分步計(jì)劃并實(shí)現(xiàn)你期望的功能,最后組合成完整的游戲。
這些是在布魯姆教育目標(biāo)分類法被列為比較高級(jí)的認(rèn)知類型。知識(shí)可以被忘記,理解和應(yīng)用的過(guò)程會(huì)讓你有一些印象,而分析、評(píng)估、合成的過(guò)程則可以逐步內(nèi)化成你自己的能力。你從別人那里聽(tīng)來(lái)的經(jīng)驗(yàn)是知識(shí),也許你在自己行事的過(guò)程中能夠理解一些、應(yīng)用一些,但更高級(jí)的認(rèn)知,則非親手實(shí)踐不能取得。
如果你在游戲或者互聯(lián)網(wǎng)行業(yè),但你并不知道程序同學(xué)們?cè)趺垂ぷ鳌⑾胄┦裁矗换蛘呖傆X(jué)得自己的設(shè)想與實(shí)現(xiàn)之間有著一道障壁。也許自己親手實(shí)現(xiàn)(implement)自己設(shè)想的過(guò)程會(huì)帶給你啟發(fā)。
至少我在這 14 周每周做一個(gè)游戲的過(guò)程中,確實(shí)有這樣的體會(huì)。除此之外,親手實(shí)現(xiàn)設(shè)計(jì)的快感,掌握自己作品的快感,也是無(wú)可比擬的。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/37395.html
摘要:大家好,我是冰河有句話叫做投資啥都不如投資自己的回報(bào)率高。馬上就十一國(guó)慶假期了,給小伙伴們分享下,從小白程序員到大廠高級(jí)技術(shù)專家我看過(guò)哪些技術(shù)類書(shū)籍。 大家好,我是...
摘要:正好,最近又有幾位不同身份的初學(xué)者來(lái)咨詢,要我推薦幾本入門書(shū)籍,而我們薦書(shū)系列已經(jīng)停更了兩個(gè)多月,所以,本期薦書(shū)就來(lái)推薦一些入門書(shū)籍吧。為了準(zhǔn)備這期薦書(shū),我專門搜集了本入門書(shū)籍,現(xiàn)在全部加入到了一份豆瓣豆列里,方便大家查看。 showImg(https://segmentfault.com/img/remote/1460000019299066?w=4790&h=3193); 本文原創(chuàng)...
摘要:如果你仍然無(wú)法抉擇,那請(qǐng)選擇,畢竟這是未來(lái)的趨勢(shì),參考知乎回答還是編輯器該如何選我推薦社區(qū)版,配置簡(jiǎn)單功能強(qiáng)大使用起來(lái)省時(shí)省心,對(duì)初學(xué)者友好。 這是一篇 Python 入門指南,針對(duì)那些沒(méi)有任何編程經(jīng)驗(yàn),從零開(kāi)始學(xué)習(xí) Python 的同學(xué)。不管你學(xué)習(xí)的出發(fā)點(diǎn)是興趣驅(qū)動(dòng)、拓展思維,還是工作需要、想要轉(zhuǎn)行,都可以此文作為一個(gè)參考。 在這個(gè)信息爆炸的時(shí)代,以 Python入門 為關(guān)鍵字搜索出...
閱讀 1317·2019-08-30 15:44
閱讀 2032·2019-08-30 13:49
閱讀 1661·2019-08-26 13:54
閱讀 3494·2019-08-26 10:20
閱讀 3268·2019-08-23 17:18
閱讀 3303·2019-08-23 17:05
閱讀 2137·2019-08-23 15:38
閱讀 1022·2019-08-23 14:35