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
15會員
131內容數
寫點東西自娛娛人
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
ysf的沙龍 的其他內容
隨機漫步看似簡單,但卻是模擬許多自然界現象的基礎,相關的觀念及程式實作方式,對於瞭解亂數、機率、Perlin noise等工具,會有相當大的幫助。
在這一章中,會透過介紹在螢幕上模擬物體移動時,其背後的原理與實作方法,來介紹亂數(random number)、隨機分布(random distribution)、Perlin noise等,這些可以用來引入隨機性的工具。
隨機漫步看似簡單,但卻是模擬許多自然界現象的基礎,相關的觀念及程式實作方式,對於瞭解亂數、機率、Perlin noise等工具,會有相當大的幫助。
在這一章中,會透過介紹在螢幕上模擬物體移動時,其背後的原理與實作方法,來介紹亂數(random number)、隨機分布(random distribution)、Perlin noise等,這些可以用來引入隨機性的工具。
你可能也想看
Google News 追蹤
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
這一章節旨在介紹 PHP 中的物件導向編程(OOP)概念。通過詳細講解類別、建構子、訪問修飾符(公開、私有、受保護)、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等概念,使讀者能夠理解和應用這些 OOP 技術來編寫更具結構性和可維護性的 PHP 代碼。
Thumbnail
這篇文章介紹了面試時以及開始工作後可能會遇到的問題,包括物件導向OOP、SOLID 設計原則、測試方式,以及 Cookie、Session 與 Cache 的相似處與不同處。提供了豐富的相關資訊。
※ class類別 什麼是class? class是創造consturctor function時的語法糖,本質上與使用function創造物件(object)的行為沒有不同。 class的作用: 用來定義、描述要創造的物件(object)具有那些屬性、行為的一個表達式。就像是「車子的設計圖
※ Object(物件) & Constructor Function(建構式函式) Object(物件)是什麼? 物件是一種「可以將資料、程式碼包含在其中」的資料結構。 Object(物件)的兩種創造方式: 匿名物件:直接使用"{}"。沒有特別的名字,直接從Object中繼承過來的一個物件
※ OPP(Object-oriented programming)簡介 什麼是OPP? OPP是一種軟體開發的風格方式。 是一種撰寫程式時的思考模式。 OPP的目的: 企圖將電腦世界的資料類比到現實中「物件」的概念。 將函數化的資料處理方式用類比到現實世界的互動關係,來簡化思考的難度。
Thumbnail
本文介紹了Python中的物件導向程式設計的重要概念,包括類別、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda表達式、泛型和反射。每個概念都有對應的程式碼範例來說明其用法和功能。這些概念對於理解和使用Python進行物件導向程式設計至關重要。
Thumbnail
本階段深掘PHP中類別與物件的應用,從基本定義到屬性與方法的運用,並特別著重於訪問控制和靜態成員的概念。學生將學會如何有效地利用公開、保護、私有屬性,以及如何在不實例化的情況下透過類別名稱直接訪問靜態屬性和方法,進一步鞏固物件導向程式設計的核心知識。
Thumbnail
本階段介紹物件導向程式設計(OOP)基礎,從OOP概念、類別與物件基本原理,到PHP中類別與物件的應用,並深入探討封裝、繼承等OOP特性,最後以實際練習加強理解。此階段為學生掌握PHP OOP打下堅實基礎。
Thumbnail
從基本的OOP概念、PHP基礎回顧,到類別與物件的深入探討、進階概念如繼承、介面與抽象類別,再到實戰應用與設計模式入門,最後以課程總結與未來學習資源提供作結。此課程架構確保學生能夠從基礎到進階,全面掌握PHP物件導向程式設計的核心概念與技術。
Thumbnail
本文讓我們來淺談一下類別是什麼? 若想看詳細一點的python官方教學可點此連結 Python 的類別(Class)是一種面向物件導向程式設計的概念,讓你能夠創建具有屬性和方法的物件。類別是對現實世界中事物的抽象,它包含數據和操作這些數據的方法。它非常的抽象,想像一個類別就像是一個蛋糕模具,
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
這一章節旨在介紹 PHP 中的物件導向編程(OOP)概念。通過詳細講解類別、建構子、訪問修飾符(公開、私有、受保護)、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等概念,使讀者能夠理解和應用這些 OOP 技術來編寫更具結構性和可維護性的 PHP 代碼。
Thumbnail
這篇文章介紹了面試時以及開始工作後可能會遇到的問題,包括物件導向OOP、SOLID 設計原則、測試方式,以及 Cookie、Session 與 Cache 的相似處與不同處。提供了豐富的相關資訊。
※ class類別 什麼是class? class是創造consturctor function時的語法糖,本質上與使用function創造物件(object)的行為沒有不同。 class的作用: 用來定義、描述要創造的物件(object)具有那些屬性、行為的一個表達式。就像是「車子的設計圖
※ Object(物件) & Constructor Function(建構式函式) Object(物件)是什麼? 物件是一種「可以將資料、程式碼包含在其中」的資料結構。 Object(物件)的兩種創造方式: 匿名物件:直接使用"{}"。沒有特別的名字,直接從Object中繼承過來的一個物件
※ OPP(Object-oriented programming)簡介 什麼是OPP? OPP是一種軟體開發的風格方式。 是一種撰寫程式時的思考模式。 OPP的目的: 企圖將電腦世界的資料類比到現實中「物件」的概念。 將函數化的資料處理方式用類比到現實世界的互動關係,來簡化思考的難度。
Thumbnail
本文介紹了Python中的物件導向程式設計的重要概念,包括類別、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda表達式、泛型和反射。每個概念都有對應的程式碼範例來說明其用法和功能。這些概念對於理解和使用Python進行物件導向程式設計至關重要。
Thumbnail
本階段深掘PHP中類別與物件的應用,從基本定義到屬性與方法的運用,並特別著重於訪問控制和靜態成員的概念。學生將學會如何有效地利用公開、保護、私有屬性,以及如何在不實例化的情況下透過類別名稱直接訪問靜態屬性和方法,進一步鞏固物件導向程式設計的核心知識。
Thumbnail
本階段介紹物件導向程式設計(OOP)基礎,從OOP概念、類別與物件基本原理,到PHP中類別與物件的應用,並深入探討封裝、繼承等OOP特性,最後以實際練習加強理解。此階段為學生掌握PHP OOP打下堅實基礎。
Thumbnail
從基本的OOP概念、PHP基礎回顧,到類別與物件的深入探討、進階概念如繼承、介面與抽象類別,再到實戰應用與設計模式入門,最後以課程總結與未來學習資源提供作結。此課程架構確保學生能夠從基礎到進階,全面掌握PHP物件導向程式設計的核心概念與技術。
Thumbnail
本文讓我們來淺談一下類別是什麼? 若想看詳細一點的python官方教學可點此連結 Python 的類別(Class)是一種面向物件導向程式設計的概念,讓你能夠創建具有屬性和方法的物件。類別是對現實世界中事物的抽象,它包含數據和操作這些數據的方法。它非常的抽象,想像一個類別就像是一個蛋糕模具,