整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Python 實現生命游戲

          Python 實現生命游戲

          者:Pleiades

          來源:http://www.cnblogs.com/pleiades/p/8353713.html

          生命游戲是英國數學家約翰·何頓·康威在1970年發明的細胞自動機。它包括一個二維矩形世界,這個世界中的每個方格居住著一個活著的或死了的細胞。一個細胞在下一個時刻生死取決于相鄰八個方格中活著的或死了的細胞的數量。如果相鄰方格活著的細胞數量過多,這個細胞會因為資源匱乏而在下一個時刻死去;相反,如果周圍活細胞過少,這個細胞會因太孤單而死去。

          規則看起來很簡單,但卻能演繹出無窮無盡的內容。

          滑翔者:每4個回合"它"會向右下角走一格。雖然細胞早就是不同的細胞了,但它能保持原本的形態。

          輕量級飛船:它的周期是4,每2個回合會向右邊走一格。

          脈沖星:它的周期為3,看起來像一顆周期爆發的星星。

          更復雜的圖案。

          來體會一下這些作品的腦洞以及震撼:

          史詩般的生命游戲http://www.iqiyi.com/w_19rsq435c9.html

          用生命游戲實現生命游戲:http://www.bilibili.com/video/av616329/index.html

          生命游戲的規則其實很簡單。我們可以把計算機中的宇宙想象成是一堆方格子構成的封閉空間,尺寸為N的空間就有NN個格子。而每一個格子都可以看成是一個生命體,每個生命都有生和死兩種狀態,如果該格子生就顯示藍色,死則顯示白色。每一個格子旁邊都有鄰居格子存在,如果我們把33的9個格子構成的正方形看成一個基本單位的話,那么這個正方形中心的格子的鄰居就是它旁邊的8個格子。

          每個格子的生死遵循下面的原則:

          1. 如果一個細胞周圍有3個細胞為生(一個細胞周圍共有8個細胞),則該細胞為生(即該細胞若原先為死,則轉為生,若原先為生,則保持不變) 。

          2. 如果一個細胞周圍有2個細胞為生,則該細胞的生死狀態保持不變;

          3. 在其它情況下,該細胞為死(即該細胞若原先為生,則轉為死,若原先為死,則保持不變)

          設定圖像中每個像素的初始狀態后依據上述的游戲規則演繹生命的變化,由于初始狀態和迭代次數不同,將會得到令人嘆服的優美圖案。

          我們用#代表活的細胞,空格表示死的細胞,那么我們可以用控制臺打印字符、清屏來模擬生命游戲。我的代碼在github上:

          https://github.com/Pleiades0428/GameOfLife/blob/master/Demo/gameOfLife.py

          游戲世界尺寸為60x20,隨機生成初始狀態,循環邊界,按任意鍵進入下一幀,q退出。

          單純的看這段程序,好像并沒有什么問題,代碼邏輯正確、清晰。

          效果圖:

          我們來嘗試一些python的高級特性,比如列表生成式。

          例如,在生成初始值時,我們一般這樣寫:

          1. 1 screen=

          2. 2 width=60

          3. 3 height=20

          4. 4 def Init:

          5. 5 for i in range(height):

          6. 6 line=

          7. 7 for j in range(width):

          8. 8 if random.random > 0.8:

          9. 9 line.append('#')

          10. 10 else:

          11. 11 line.append(' ')

          12. 12 screen.append(line)

          如果用列表生成式,我們可以這樣寫:

          1. 1 def Init:

          2. 2 global screen

          3. 3 screen=[['#' if random.random() > 0.8 else ' ' for i in range(width)] for j in range(height)]

          注意這里必須用global聲明,否則screen將默認作為函數內的局部變量。這里用了兩層列表生成式來生成一個二維數組。

          列表生成式很好很強大,如果用好能大大提高效率。但會犧牲一定的可讀性,如果單個表達式寫的過于復雜,那就變成write-only了。尤其是在團隊開發情況下,可讀性日益重要。

          重寫后的代碼:

          https://github.com/Pleiades0428/GameOfLife/blob/master/Demo/gameOfLife.1.py

          如果僅僅是作為練習,這樣就已經足夠好了,簡潔易讀。

          可是我們還不能滿足,我們來給生命插上面向對象的翅膀,在模塊化的天空中翱翔。對,就是讓他跟別的模塊搞對象!

          先來定義一個類GameOfLifeWorld,之前那些丑陋的全局變量,讓他們統統變成成員變量,再也不能在外興風作浪。

          1. class GameOfLifeWorld:

          2. width=100

          3. height=100

          4. cells=

          5. …略

          然后把UI層剝離,只保留游戲的核心邏輯。

          代碼:

          https://github.com/Pleiades0428/GameOfLife/blob/master/Demo/gameOfLifeWorld.py

          有了上一步的鋪墊,我們終于可以讓Tkinter粉墨登場了。Tkinter是著名的UI庫,Python自帶的Tkinter是一個精簡版,不過也夠我們用的了。

          我們這里用到的主要是Canvas,Button控件。Canvas畫布用來繪制游戲區,Button用來交互。

          效果:

          以上就是這樣,項目我還會繼續改進,希望大家喜歡。

          題圖:pexels,CC0 授權。

          ython 實現生命游戲

          這次我們使用 Python 來實現生命游戲,這是一種簡單的元胞自動機。基于一定規則,程序可以自動從當前狀態推演到下一狀態。制作的成品如下:

          先來說說生命游戲的規則:

          在生命游戲中,每個單元格有兩種狀態,生與死。在我們的實現中,黃色的單元格代表活著的細胞,紅色單元格表示死亡的細胞。而每一個細胞的下一狀態,是由該細胞及周圍的八個細胞的當前狀態決定的。

          具體而言:

          當前細胞為活細胞

          1. 周圍有兩個或者三個活細胞,下一世代,該細胞仍然活著。
          2. 周圍少于兩個活細胞,該細胞死于孤立。
          3. 周圍多于三個活細胞,該細胞死于擁擠。

          當前細胞為死細胞

          • 周圍恰好三個活細胞,下一世代,活細胞將繁殖到該單元格。

          所需模塊

          無需安裝的標準庫:

          • argparse(命令行參數)
          • enum(枚舉)

          第三方庫:

          • numpy
          • matplotlib

          導入模塊:

          import argparse
          from enum import IntEnum
          import matplotlib.pyplot as plt
          import matplotlib.animation as animation # 制作動圖
          import numpy as np
          

          編程要點

          首先,我們要知道細胞的生存空間是 N * N 的方陣,每個細胞都有兩種狀態:on, off。on 為 255,off 為 0。我們使用 numpy 產生 N * N 的方陣。np.random.choice 是在 State.on 和 State.off ,等概率隨機抽取一個元素構造 N * N 的方陣。

          class State(IntEnum):
           on=255
           off=0
          ?
          def random_data(length=4, seed=420) -> np.array:
           np.random.seed(seed)
           return np.random.choice([State.off, State.on], size=(length, length), p=[0.5, 0.5])
          

          其次我們要明白如何計算細胞周圍活細胞的個數,尤其是邊界一圈的細胞。我們可以采用余數的方式,假設棋盤大小為 9 * 9,那么對于左右邊界而言,左邊界的左邊一個元素的計算方式: - 1 % 9=8,自動折到右邊界上。將細胞周圍八個單元格的數值加起來,除以 255,就可以得到細胞周圍活細胞的個數。

          def _count(data, row, col):
           shape=data.shape[0]
           up=(row - 1) % shape
           down=(row + 1) % shape
           right=(col + 1) % shape
           left=(col - 1) % shape
           return (data[up, right] + data[up, left] +
           data[down, right] + data[down, left] +
           data[row, right] + data[row, left] +
           data[up, col] + data[down, col]) // 255
          

          接下來是對規則的翻譯,即根據當前世代的狀態,推演出下一世代,細胞的狀態。initial 為當前世代的矩陣,data為下一世代的矩陣,我們根據 initial 的數值,計算出 data 的數值。total 為周圍活細胞的個數,如果當前為活細胞,total 大于三或者小于二,下一世代就會死去。如果當前為死細胞,total 等于三,下一世代活細胞就會繁殖到該單元格上。

          def count(initial, data, row, col):
           total=_count(initial, row, col)
           if initial[row, col]:
           if (total < 2) or (total > 3):
           data[row, col]=State.off
           else:
           if total==3:
           data[row, col]=State.on
          

          接下來是制作動圖的過程,前面幾行是繪圖的基本操作。之后,我們使用到了 matplotlib.animation 的方法。其中,FuncAnimation 接受的參數含義:fig 為圖像句柄,generate 函數是我們更新每一幀圖像所需數據的函數,下面會有介紹,fargs 為 genrate 函數的除去第一個參數的其他參數,第一個參數由 FuncAnimation 指定 framenum(幀數) 傳給 generate 函數。frames 是幀數,interval 是更新圖像間隔,save_count 為從幀到緩存的值的數量。

          如果指定保存路徑(html),則保存為 html 動畫。

          def update(data, save_name):
           update_interval=50
           fig, ax=plt.subplots()
           ax.set_xticks([])
           ax.set_yticks([])
           img=ax.imshow(data, cmap='autumn', interpolation='nearest')
           ani=animation.FuncAnimation(fig, generate, fargs=(img, plt, data),
           frames=20,
           interval=update_interval,
           save_count=50)
           if save_name:
           ani.save(save_name, fps=30, extra_args=['-vcodec', 'libx264'])
           plt.show()
          

          下面我們來看 generate 函數,NUM 為當迭代次數,frame_num 接收來自 FuncAnimation 的幀數。通過嵌套的 for 循環,我們逐個地更新方陣中各元素的狀態。

          NUM=0
          ?
          def generate(frame_num, img, plt, initial):
           global NUM
           NUM +=1
           plt.title(f'{NUM} generation')
           data=initial.copy()
           rows, cols=data.shape
           for row in range(rows):
           for col in range(cols):
           count(initial, data, row, col)
           img.set_data(data)
           initial[:]=data[:]
           return img
          

          最后,我們可以通過命令行參數,運行我們的程序:

          -- size 參數為棋盤大小,--seed 為隨機種子,用于產生不同的隨機方陣。

          python conway.py --size 50 --seed 18
          

          高斯帕滑翔機槍(Gosper Glider Gun)

          可將 --gosper 更改為 --glider 滑翔機。--save 為動圖保存的地址。

          python conway.py --size 80 --gosper --save gosper.html
          

          點擊鏈接,回復 2019527, 獲取源代碼。

          https://mp.weixin.qq.com/s/6ys7zyIV11NX2EVaVtlQIQ

          類是社會動物,而人類的社會活動則既簡單又復雜。長期以來,數學家、計算機科學家和社會學家們一直試圖用簡單明了的方式方法去刻畫錯綜復雜的社會現象,其中“生命游戲”提供了一個“寓科學于娛樂”的活動框架。

          【一】導引

          讓我們先來玩一個簡單的棋子游戲。

          在一個充分大的圍棋棋盤上,為簡單起見每個空格表示已經放有一個白子(而白子就不標畫出來了)。如果空格內出現一個黑子,就表示黑子取代了原有的白子。現在,讓黑子表示“生”而白子表示“死”。另外,在棋盤上的任何9個格子組成的正方形區域里(見圖1),對處于中心位置的黑子或白子來說,它上下左右和兩對角線外的8個黑子(如果它們存在的話)都稱為是它的鄰居。

          我們的棋子游戲有4條規則,在整個過程中每一步都同時應用于棋盤上所有的黑子和白子上。規則如下:

          (1)如果一個黑子只有1個或者沒有黑子鄰居的話,它在下一步就會死去,如圖1(a) 所示。這操作表示該黑子在社會里太孤單了,它不能繼續生存下去。

          (2)如果一個黑子有2個或者3個黑子鄰居的話,它在下一步就繼續存在,如圖1(b) 的第一步所示。這操作表示該黑子有合適的社會環境,它可以繼續生存下去。

          (3)如果一個黑子有4個或者更多黑子鄰居的話,它在下一步也會死去,如圖1(c) 的中心黑子(為了不影響這一說明,其它黑子和白子同時發生的變化暫且不表示出來)。這操作表示該黑子所處的社會環境太擁擠了,它不能繼續生存下去。

          (4)如果一個白子有恰好3個黑子鄰居的話,它在下一步就會變成黑子,如圖1(d) 所示。這操作表示該白子具有良好的社會環境,它可以誕生或復活。

          明白了這幾條簡單規則之后,你就可以開始玩這個棋子游戲了。當然,只放少許幾個黑棋子的話,你可以在書桌上玩一陣子,但棋子數目稍多,你就得編程在電腦上玩了。

          你很自然會有一個感覺,就是開始時放入多少個黑子以及怎樣放置它們,這對于游戲如何一步一步地演變下去會有決定性的影響。比如圖1(d)中四個黑子處于穩定狀態,它們永遠都不會死去,即是“長生不老”,而其它初始放置方式(圖1(a)、(b)、(c))則會讓黑子在若干步之內全部死光。

          你這個感覺是對的:游戲的初始條件(即放入多少個黑子以及怎樣放置它們)的確很重要,它們會生成各式各樣的黑子組合斑圖以及許多不同的最終結果。比如圖1(d) 就生成一個永遠不變的斑圖,稱為“靜物”(still life);圖2(a) 則生成周期-2的“振蕩器”(oscillator);圖2(b) 卻生成一種會移動的周期“宇航船”(spaceship)。后面這種情形特別有趣,它在一步一步變化的過程中,起始的5個黑子不會減少也不會增多,但會頻繁地改變位置,像一艘不斷變形的宇航船一直往右方和下方移動。在第四步,它變回到了初始狀態,不過整個斑圖的位置向右方和下方各移動了一格。之后,它繼續往前移動,期間斑圖的變化不斷重復前面的過程。這是一艘移動的周期-4振蕩宇航船,稱為“滑翔機”(glider),它永遠不停地向右下方滑翔前進。你看,這個滑翔機會永遠無休止地生存并移動下去,期間代表“生”和“死”的黑子和白子交替出沒,整個族群在發展和演變過程中就像有“生命”一樣,對吧?

          圖1 游戲4條規則

          圖2 “振蕩器”和“滑翔機”例子

          至此,你看到了,這個棋子游戲的規則是固定的,但初始條件(黑子的個數和位置)可以有許多不同的選擇。因此,容易想象,你能夠嘗試著去生成多種多樣的“最終趨于死亡”、“不同周期振蕩”和“永遠變化生存”斑圖。由于這個游戲可以用來描繪一些社會生命現象,故此設計師把它叫做“生命游戲”(Game of Life)。

          上面介紹的這個趣味橫生的生命游戲簡單而復雜,它的設計師是數學家約翰·康威(John Horton Conway,1937-2020)。關于康威的生平和貢獻,筆者曾有過簡單介紹[1]。康威在開發這個有趣的生命游戲時是英國劍橋大學數學講師。1970年10月,科普作家馬丁·加德納(Martin Gardner,1914-2010)在《科學美國人》雜志的“數學游戲”專欄對這個生命游戲作了詳細介紹。從此,學界和民間對游戲的興趣和熱情一發而不可收拾。據說,在那個生命游戲風靡世界的年代,全球有四分之一的電腦都在玩這個游戲。

          2010年,物理學家史蒂芬·霍金(Stephen W. Hawking,1942-2018)在他的科普著作《大設計》(The Grand Design)中寫道:“我們可以想象,像‘生命游戲’這樣的玩兒,它只有一些基本規則,便可以產生高度復雜的功能,甚至智慧。當然它可能需要包含數十億個正方形的網格。但這并不困難,我們大腦中就有數千億個細胞。”

          【二】簡史

          現在,我們來說說“生命游戲” 的前世今生。

          康威并不是構思出這類具有深刻數學原理和社會學意義的生命游戲的第一人。游戲的基本思想要追溯到兩位美國數學家:波蘭裔的斯塔尼斯拉夫·烏拉姆(Stanislaw Ulam,1909-1984)和匈牙利裔的約翰·馮·諾伊曼(John von Neumann,1903-1957),他們在上世紀40-50年代為模擬生物細胞的自我復制提出了“元胞自動機理論”(Cellular Automata)的雛形。當年,由于沒有高速大型電腦,他們的構想沒有得到驗證因而未受學術界的重視。1970年,馬丁·加德納在《科學美國人》雜志介紹了康威的生命游戲之后,元胞自動機理論才受到了越來越廣泛的關注。

          在眾多卓有成效的元胞自動機理論研究者中,特別值得提及的是美國電腦科學家史蒂芬·沃爾夫勒姆(Stephen Wolfram,1959-)。

          沃爾夫勒姆是個很有故事的人物。他1959年出生于倫敦,12歲編寫了一部關于物理學的詞典草稿,13-14歲間寫了三本關于粒子物理的手稿,15歲發表了第一篇學術論文,17歲進入了牛津大學。1978年,19歲的沃爾夫勒姆接到美國物理學家默里·蓋爾曼(Murray Gell-Mann,1929-2019)的電話邀請,來到了加州理工學院就讀研究生。蓋爾曼因發現基本粒子夸克在1969年獲諾貝爾物理學獎,他是圣塔菲研究所首任所長。1979年,在加州理工學院讀書期間,沃爾夫勒姆便開創了自己的第一個大型電腦語言SMP,用以輔助物理學研究。該語言是后來著名數學軟件Mathematica和電腦Wolfram語言的前身。1980年,21歲的沃爾夫勒姆獲得了理論物理學博士學位,其答辯委員會成員包括有諾貝爾物理獎得主理查德·費曼(Richard P. Feynman,1918-1988)。之后,沃爾夫勒姆留校任教,隨即獲得MacArthur獎。接下來,23歲的他開始推動并主導了關于“復雜系統”的科學研究,并在27歲時創立了自己的Stephen Wolfram公司,從事數學軟件和電腦軟件開發。如所周知,他獲得了巨大成功,不過那是后話了。

          1983年,由于知識產權糾紛,沃爾夫勒姆離開了加州理工學院,到了普林斯頓大學自然科學學院工作。沒過多久,他就發明了元胞自動機的計算程序。沃爾夫勒姆后來回憶說:“我開始時并不覺得簡單的元胞自動機有什么有趣之處,不過還是利用電腦試著對它們做了些試驗。令我十分驚訝的是,就算是構造極為簡單的元胞自動機,它們仍然有著極其復雜的行為,這對傳統的科學教條是個莫大的沖擊。過了些日子,我才意識到它的巨大潛力。那是我寫這本《一種新科學》(A New Kind of Science)的最早動機。”我們知道,該書實際上代表了一條與圣塔菲研究所不一樣的復雜性科學研究路線。

          當年,沃爾夫勒姆使用電腦模擬對基本元胞自動機的類別進行了系統性的分析,對一維基本元胞自動機的256種規則所產生的模型進行了深入的研究,并用熵(entropy)的概念來描述元胞自動機的演化行為。他根據復雜性理論將元胞自動機大致分為平穩型、周期型、混沌型和復雜型。從幾乎所有的隨機初始模式開始,平穩型將演化為穩定靜止狀態,周期型將演化為穩定振蕩狀態,混沌型將演化為偽隨機混沌狀態,復雜型將變化為相互作用繁復狀態且其局部結構會在長時間內甚至永遠地存在。沃爾夫勒姆發現,絕大多數的生命游戲演化是無法被決定的(undecidable):即使給定了初始模式,依然找不到或者根本就不存在一個算法可以用來判斷后續模式是否會出現和何時會出現。沃爾夫勒姆指出110號規則對應的元胞自動機具有圖靈完備性(Turing completeness)。在電腦科學中,圖靈完備性是指具有無限存儲能力的通用編程語言,它可以通過一系列數據操作規則來模擬圖靈數學邏輯機。沃爾夫勒姆發現,凡是可以通過編寫程序去計算的復雜系統演化行為,都可以用元胞自動機來實現。順便提及,沃爾夫勒姆從分類開始時就已經看到了元胞自動機理論和美國數學家史蒂芬·斯梅爾(Stephen Smale,1930–)的艱深混沌數學理論的內在聯系,因為生命游戲的無法決定性和混沌的長期不可預測性[2]是類似的。

          上面討論的只是平面上的生命游戲和元胞自動機理論。對于任意一條游戲規則,每個格點的黑子和白子鄰居的組合共有29=512種,而每種組合都可以用二進制的0–1序列來表示并且是各自獨立變化的,于是總共有2512種可能。即便排除了那些沒有靜止、旋轉和反射對稱可能的不重要情形,剩下來的依然是一個天文數字。至于三維和更高維數的生命游戲和元胞自動機理論,那就復雜得無法描述了,只能用幾個簡單文字來概括:超乎想象的豐富多彩!

          【三】應用

          故事講到這里,你一定會好奇,這迷人的元胞自動機理論及其計算程序會有什么實際應用呢?

          作為回應,我們簡單地介紹一下元胞自動機技術在電腦科學、生物學、化學、物理學和音樂藝術方面的幾個具體應用或潛在應用[3]。

          圖3 芋螺貝殼和Wolfram 30號規則生成的班圖[4]

          (1)電腦科學:

          元胞自動機處理器是該概念的物理實現,它通過計算方式來處理信息。元胞的狀態僅通過與相鄰鄰居元胞的相互作用來確定,而不需要也不存在與更遠的元胞進行直接通信。一種典型的元胞自動機處理器具有脈動陣列配置,其中元胞相互作用通過電荷、磁性、振動或其他物理手段來實現。

          Wolfram 30號規則最初被建議作為一種可能的分組密碼用于密碼學。二維元胞自動機可用于構建偽隨機數發生器,而且元胞自動機的演化是單向函數,其逆很難破解,即容易計算未來狀態,但回算先前的狀態卻異常困難。元胞自動機后來也被提議用于公鑰密碼學并用來設計各種糾錯碼。

          (2)生物學:

          一些漂亮的海螺貝殼圖案可以用元胞自動機生成,例如分布廣泛的芋螺纖維(conus textile)具有類似于 Wolfram 30號規則的班圖(圖3),因而元胞自動機理論能夠用來解釋和研究貝殼的顏色細胞自然生長內在規律。

          動物體內的成纖維細胞(fibroblast)與元胞自動機有很多相似之處,例如每個成纖維細胞只與其鄰居相互發生作用。

          植物調節氣體吸入和呼出的機制類似于元胞自動機的演化過程,例如樹葉上的每個氣孔有呼和吸兩個動作,對應于一個元胞的兩種狀態。

          頭足類(cephalopod)動物例如烏賊的皮膚班圖中,每個狀態對應于色素細胞的展開和收縮,可以用二維元胞自動機進行模擬和解釋。

          生物神經元的活動甚至動物識別和學習等復雜行為都可以用閾值自動機來模擬。

          (3)化學:

          化學中的Belousov–Zhabotinsky反應是一種時空化學振蕩過程,它可以通過元胞自動機來進行模擬和分析。例如一層單薄而均勻的丙二酸、酸化溴酸鹽和高鈰鹽混合在一起時,迷人的幾何圖案如同心圓和螺旋曲線便在介質中傳播,所產生的波形與某種元胞自動機生成的圖案非常相似。

          (4)物理學:

          概率元胞自動機可用于統計學和凝聚態物理學的研究中,去分析流體動力學和相變等現象。伊辛(Ising)模型是一個典型的例子,其中每個單元格可以處于“向上”或“向下”狀態,從而用于理想化地表示磁鐵。通過調整元胞自動機模型參數,可以改變處于相同狀態的元胞比例,解釋了為何對鐵磁體加熱可以消磁。物理學中還有一種格子氣體元胞自動機,可以用來模擬液體流動并對之給予合理解釋。

          (5)音樂藝術:

          元胞自動機可用來生成一些新穎動聽的音樂作品和設計電子游戲。某些類型的元胞自動機還可用于生成各種迷宮。兩個著名的元胞自動機迷宮Maze和Mazectric類似于前面介紹的“生命游戲”,復雜而有趣。此外,元胞自動機還能生成豐富多彩的圖案用于藝術設計。

          今天,元胞自動機理論及各種數學游戲的研究仍在繼續。我們期待在不久的將來會得到更豐富更有趣的成果。

          注:原文發表在《復雜學》2024年第2卷第2期45-52頁,經作者授權轉載

          【參考文獻】

          [1] 陳關榮(2023),愛玩的天才數學家康威,《數學文化》第14卷第4 期,36-46頁,https://www.global-sci.com/intro/article_detail/mc/22165. html

          [2] 陳關榮(2022 年),這門復雜性科學有個別致的名稱―混沌,《復雜學》第1 卷第1 期,69-75頁

          [3] Wikipedia: Cellular automaton,https://en.wikipedia.org/wiki/Cellular_automaton

          [4] Stephen Wolfram (2019), Announcing the rule 30 prizes,https://writings.stephenwolfram.com/2019/10/announcing-the-rule-30-prizes/


          主站蜘蛛池模板: 狠狠做深爱婷婷综合一区| 三上悠亚日韩精品一区在线| 99久久精品国产免看国产一区| 久久国产精品免费一区| 国产成人精品一区二三区 | 色窝窝无码一区二区三区成人网站| 成人中文字幕一区二区三区| 色窝窝无码一区二区三区| 国产精品日本一区二区在线播放| 精品乱子伦一区二区三区高清免费播放 | 国产一区中文字幕在线观看| 91精品乱码一区二区三区| 国产精品合集一区二区三区 | 久久精品国产一区二区三区不卡 | 日韩AV片无码一区二区不卡| 国产高清在线精品一区小说| 国产精品高清一区二区三区| 中文字幕精品一区二区2021年| 日本一区中文字幕日本一二三区视频 | 国产av一区最新精品| 一区二区视频在线免费观看| 国产在线aaa片一区二区99 | 免费观看日本污污ww网站一区 | 无码精品人妻一区二区三区人妻斩 | 人妻av综合天堂一区| 亚洲乱码一区二区三区在线观看| 亚洲一区二区中文| 一区二区三区免费精品视频| 国产主播福利一区二区| 精品一区二区三区中文字幕| 好吊妞视频一区二区| 日韩精品一区二区三区中文| 日本一区二区三区在线网| 国产精品高清一区二区三区不卡| 久久国产香蕉一区精品| 波多野结衣一区二区三区88 | 亚洲欧美日韩中文字幕一区二区三区| 一区二区三区四区精品| 国产精品无码亚洲一区二区三区| 国产成人精品无码一区二区三区 | 青娱乐国产官网极品一区|