The Nature of Code閱讀心得與Python實作:0.2 The Random Walker Class

更新 發佈閱讀 13 分鐘

這一節談的是用物件導向程式設計(object-oriented programming, OOP)的方式來實作隨機漫步。

既然要用到OOP,那就先來看一下,在Python官網中,關於物件(object)和類別(class)這兩個OOP術語的說明:

物件(object):在Python中,「物件」指的是具有狀態(屬性或值),以及預先定義好的行為,也就是「方法」(method)的任何資料。
類別(class):製作物件的模板。

要用OOP實作隨機漫步,我們會製作一個叫Walker的物件,這個物件具有的狀態是它在螢幕上的位置,而它的行為,也就是method,有兩個,一個是「將自己顯示在螢幕上」,另一個是「移動自己的位置」。

要製作物件,需先設計好模板,也就是類別,然後用這個模板產生我們所需要的物件。製作Walker所需的類別,可以這樣設計:

class Walker:
def __init__(self, x=0, y=0):
# pygame的畫面
self.screen = pygame.display.get_surface()

# walker的位置,預設值是(0, 0)
self.x = x
self.y = y

# 將自己顯示在螢幕上
def show(self, color=(0, 0, 0)):
self.screen.set_at((self.x, self.y), color)

# 移動位置
def step(self):
choice = random.randint(0, 3)
if choice == 0:
self.x += 1
elif choice == 1:
self.x -= 1
elif choice == 2:
self.y += 1
else:
self.y -= 1

step()這個方法裡頭,我們是利用取亂數來決定該怎麼走。這個取亂數的動作,其實就是前一節提到的丟銅板。因為螢幕是個二維的平面,有四個方向可以走,由random.randint(0, 3)所產生的是0~3間的整數亂數,就相當於是丟銅板得到的結果。根據這個結果,就可以決定要朝哪個方向走。

設計好類別之後,就可以製造我們所需的物件了。要用Walker類別製造一個名稱為walker的物件,並把它放在(10, 20)的位置上,寫法如下:

walker = Walker(10, 20)

另外,要讓walker移動的寫法為:

walker.step()

而要讓walker顯示在pygame設定的螢幕上,則寫成:

    walker.show()

下面這個例子就是利用Walker這個類別來實作隨機漫步。

Example 0.1: A Traditional Random Walk

raw-image
# python version 3.10.9
import random
import sys

import pygame # version 2.3.0


pygame.init()

pygame.display.set_caption("Example 0.1: A Traditional Random Walk")

WHITE = (255, 255, 255)

screen_size = WIDTH, HEIGHT = 640, 360
screen = pygame.display.set_mode(screen_size)

FPS = 60
frame_rate = pygame.time.Clock()

walker = Walker(WIDTH//2, HEIGHT//2)

screen.fill(WHITE)

while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()

walker.step()
walker.show()

pygame.display.update()
frame_rate.tick(FPS)

在這裡要注意的是

screen.fill(WHITE)

這一行是寫在while迴圈外,也就是說,螢幕的背景只會被填滿一次。因此,在while迴圈內畫出的任何東西,都會一直保留著,不會被抹除,這樣才看得到隨機漫步的軌跡;如果這一行是放在while迴圈裡面,那每次畫面的背景被重新填滿的時候,原先在畫面中的東西,會全部被抹除,最後在螢幕上看到的,就只會有一個點在畫面上隨機漫步,不會留下任何軌跡。

現在的Walker,可以移動的方向有4個,如下所示:

        (x, y-1)

(x-1, y) (x, y)   (x+1, y) 

(x, y+1)

但在螢幕上,每個像素會被8個像素包圍。所以,Walker應該可以加以改良,使其可以朝如下所示的8個方向移動:

(x-1, y-1) (x, y-1) (x+1, y-1)

(x-1, y)   (x, y) (x+1, y)

(x-1, y+1) (x, y+1) (x+1, y+1)

此時,Walkerstep()方法可以改寫為

def step(self):
step_x = random.randint(-1, 1)
step_y = random.randint(-1, 1)
self.x += step_x
self.y += step_y

這樣寫,Walker除了可以向8個不同的方向移動外,也包含了留在原地不動。

Python的random module裡頭有許多亂數產生器可以使用。randint()產生的,是整數亂數,如果需要浮點數亂數,可以使用random()uniform()random.random()會傳回浮點數x,且0.0 <= x < 1.0;而random.uniform(a, b)會傳回浮點數x,使得若a <= b 時,a <= x <= b;而若b < a時,b <= x <= a

所以,如果要讓Walker的步距是浮點數的話,step_xstep_y可以改成

step_x = random.uniform(-1, 1)
step_y = random.uniform(-1, 1)

因為randint()random()uniform()等亂數產生器所產生的亂數,會呈現uniform distribution,亦即其出現的機率是相同的。所以使用這些亂數產生器來決定移動方向的Walker,朝各個方向移動的機率都是一樣的。例如,當利用random.randint(0, 3)來決定移動的方向時,因為不管是0、1、2或3,出現的機率都是25%,故而往4個方向移動的機率是相等的,都是25%。

除了randint()random()uniform()之外,也可以用choice()choices()等函數來寫step()。例如移動的方向有4個的step(),可以寫成

directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
step_x, step_y = random.choice(directions)

如果希望Walker比較容易向某個方向移動,可以用choices()來寫

directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
step_x, step_y = random.choices(directions, [2, 1, 1, 1])[0]

這樣寫,(0, 1)被選中的機率,就是其他方向的兩倍。

接下來,來跑一段程式,實際來驗證看看random.randint(0, 19)所產生的亂數,是不是uniform distribution。

Example 0.2: A Random-Number Distribution

raw-image
# python version 3.10.9
import random
import sys

import pygame # version 2.3.0


pygame.init()

pygame.display.set_caption("Example 0.2: A Random-Number Distribution")

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)

screen_size = WIDTH, HEIGHT = 640, 360
screen = pygame.display.set_mode(screen_size)

FPS = 60
frame_rate = pygame.time.Clock()

counter = [0]*20
rect_width = WIDTH/len(counter)

while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()

counter[random.randint(0, 19)] += 1

screen.fill(WHITE)

for i in range(len(counter)):
rect = pygame.Rect(i*rect_width, HEIGHT-counter[i], rect_width, counter[i])
pygame.draw.rect(screen, BLACK, rect, 2)

pygame.display.update()
frame_rate.tick(FPS)

執行程式之後出現的圖形,橫軸是數字0~19,而縱軸是數字出現的次數。從執行過程中可以發現,各矩形的高度並不總是一樣高,而是有高有低,但其高度的差距,會隨著取樣次數的增加而逐漸減少。之所以會出現這樣子的現象,是因為我們說random.randint(0, 19)所產生的亂數是uniform distribution,是指在樣本數夠多的情形下所出現的分布樣態,而不是任何數量的樣本,都會呈現出這樣的分布樣態。

Pseudo-random Numbers
由程式所產生的亂數,並非真正的亂數,而是由數學函數所模擬出來的pseudo-random number。pseudo-這個字首,意味著「假定是」、「號稱是」,但實際上並非真的是。所以,由python的random module內的亂數產生器所產生的亂數,並不是真正的亂數,只要產生的數字數量夠多,這些數字還是會呈現出特定的pattern。正因為pseudo-random number有這樣的特性,所以python的官網才會有個警語,提醒當事關安全性時,不要使用random module內的亂數產生器。

Exercise 0.1

這個作業是要修改Walker,讓它移動時,比較容易向下、向右移動。要達到這樣的目的,只要修改Walkerstep()方法即可。

下列的修改方式,會讓Walker在移動時,向下、向右移動的機率都是15%,其餘方向則為10%。

def step(self):
choice = random.randint(1, 100)
if choice <= 15:
# right
self.x += 1
elif choice <= 25:
# lower right
self.x += 1
self.y += 1
elif choice <= 40:
# down
self.y += 1
elif choice <= 50:
# lower left
self.x -= 1
self.y += 1
elif choice <= 60:
# left
self.x -= 1
elif choice <= 70:
# upper left
self.x -= 1
self.y -= 1
elif choice <= 80:
# up
self.y -= 1
elif choice <= 90:
# upper right
self.x += 1
self.y -= 1

程式執行結果的截圖如下圖

raw-image


留言
avatar-img
ysf的沙龍
20會員
164內容數
寫點東西自娛娛人
ysf的沙龍的其他內容
2024/06/13
這一節的標題是A Smoother Approach with Perlin Noise,介紹由Ken Perlin所開發的Perlin noise,及其應用方式。
Thumbnail
2024/06/13
這一節的標題是A Smoother Approach with Perlin Noise,介紹由Ken Perlin所開發的Perlin noise,及其應用方式。
Thumbnail
2024/06/09
這一節介紹使用accept-reject algorithm來產生符合特定機率分布的亂數,使得random walker具備Lévy flight的能力。
Thumbnail
2024/06/09
這一節介紹使用accept-reject algorithm來產生符合特定機率分布的亂數,使得random walker具備Lévy flight的能力。
Thumbnail
2024/06/05
這一節的標題是0.4 A Normal Distribution of Random Numbers,介紹常態分布的基本概念,以及相關亂數產生器的使用方法與應用方式。
Thumbnail
2024/06/05
這一節的標題是0.4 A Normal Distribution of Random Numbers,介紹常態分布的基本概念,以及相關亂數產生器的使用方法與應用方式。
Thumbnail
看更多
你可能也想看
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
這一章節旨在介紹 PHP 中的物件導向編程(OOP)概念。通過詳細講解類別、建構子、訪問修飾符(公開、私有、受保護)、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等概念,使讀者能夠理解和應用這些 OOP 技術來編寫更具結構性和可維護性的 PHP 代碼。
Thumbnail
這一章節旨在介紹 PHP 中的物件導向編程(OOP)概念。通過詳細講解類別、建構子、訪問修飾符(公開、私有、受保護)、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等概念,使讀者能夠理解和應用這些 OOP 技術來編寫更具結構性和可維護性的 PHP 代碼。
Thumbnail
這篇文章介紹了面試時以及開始工作後可能會遇到的問題,包括物件導向OOP、SOLID 設計原則、測試方式,以及 Cookie、Session 與 Cache 的相似處與不同處。提供了豐富的相關資訊。
Thumbnail
這篇文章介紹了面試時以及開始工作後可能會遇到的問題,包括物件導向OOP、SOLID 設計原則、測試方式,以及 Cookie、Session 與 Cache 的相似處與不同處。提供了豐富的相關資訊。
Thumbnail
本章節是一個初級的 TypeScript 教學,主要介紹了 TypeScript 中物件導向程式設計的各種核心概念,包括類別、建構子、存取修飾子、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等。每個概念都通過詳細的解釋和實例代碼來進行深入的介紹。
Thumbnail
本章節是一個初級的 TypeScript 教學,主要介紹了 TypeScript 中物件導向程式設計的各種核心概念,包括類別、建構子、存取修飾子、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等。每個概念都通過詳細的解釋和實例代碼來進行深入的介紹。
Thumbnail
本章節旨在介紹JavaScript中的物件導向編程。內容包括類別(Class)的定義和使用,建構子的作用,以及公開,私有,受保護(Protected)等不同訪問修飾符的概念。此外,還涵蓋了繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda表達式、泛型、反射等物件導向的主要觀念。
Thumbnail
本章節旨在介紹JavaScript中的物件導向編程。內容包括類別(Class)的定義和使用,建構子的作用,以及公開,私有,受保護(Protected)等不同訪問修飾符的概念。此外,還涵蓋了繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda表達式、泛型、反射等物件導向的主要觀念。
Thumbnail
這一節談的是用物件導向程式設計(object-oriented programming, OOP)的方式來實作隨機漫步。
Thumbnail
這一節談的是用物件導向程式設計(object-oriented programming, OOP)的方式來實作隨機漫步。
Thumbnail
本文介紹了Python中的物件導向程式設計的重要概念,包括類別、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda表達式、泛型和反射。每個概念都有對應的程式碼範例來說明其用法和功能。這些概念對於理解和使用Python進行物件導向程式設計至關重要。
Thumbnail
本文介紹了Python中的物件導向程式設計的重要概念,包括類別、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda表達式、泛型和反射。每個概念都有對應的程式碼範例來說明其用法和功能。這些概念對於理解和使用Python進行物件導向程式設計至關重要。
Thumbnail
本階段深掘PHP中類別與物件的應用,從基本定義到屬性與方法的運用,並特別著重於訪問控制和靜態成員的概念。學生將學會如何有效地利用公開、保護、私有屬性,以及如何在不實例化的情況下透過類別名稱直接訪問靜態屬性和方法,進一步鞏固物件導向程式設計的核心知識。
Thumbnail
本階段深掘PHP中類別與物件的應用,從基本定義到屬性與方法的運用,並特別著重於訪問控制和靜態成員的概念。學生將學會如何有效地利用公開、保護、私有屬性,以及如何在不實例化的情況下透過類別名稱直接訪問靜態屬性和方法,進一步鞏固物件導向程式設計的核心知識。
Thumbnail
本階段介紹物件導向程式設計(OOP)基礎,從OOP概念、類別與物件基本原理,到PHP中類別與物件的應用,並深入探討封裝、繼承等OOP特性,最後以實際練習加強理解。此階段為學生掌握PHP OOP打下堅實基礎。
Thumbnail
本階段介紹物件導向程式設計(OOP)基礎,從OOP概念、類別與物件基本原理,到PHP中類別與物件的應用,並深入探討封裝、繼承等OOP特性,最後以實際練習加強理解。此階段為學生掌握PHP OOP打下堅實基礎。
Thumbnail
從基本的OOP概念、PHP基礎回顧,到類別與物件的深入探討、進階概念如繼承、介面與抽象類別,再到實戰應用與設計模式入門,最後以課程總結與未來學習資源提供作結。此課程架構確保學生能夠從基礎到進階,全面掌握PHP物件導向程式設計的核心概念與技術。
Thumbnail
從基本的OOP概念、PHP基礎回顧,到類別與物件的深入探討、進階概念如繼承、介面與抽象類別,再到實戰應用與設計模式入門,最後以課程總結與未來學習資源提供作結。此課程架構確保學生能夠從基礎到進階,全面掌握PHP物件導向程式設計的核心概念與技術。
Thumbnail
本文讓我們來淺談一下類別是什麼? 若想看詳細一點的python官方教學可點此連結 Python 的類別(Class)是一種面向物件導向程式設計的概念,讓你能夠創建具有屬性和方法的物件。類別是對現實世界中事物的抽象,它包含數據和操作這些數據的方法。它非常的抽象,想像一個類別就像是一個蛋糕模具,
Thumbnail
本文讓我們來淺談一下類別是什麼? 若想看詳細一點的python官方教學可點此連結 Python 的類別(Class)是一種面向物件導向程式設計的概念,讓你能夠創建具有屬性和方法的物件。類別是對現實世界中事物的抽象,它包含數據和操作這些數據的方法。它非常的抽象,想像一個類別就像是一個蛋糕模具,
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News