【閑暇一寫】用Python編寫2048游戲(命令行版)

来源:https://www.cnblogs.com/qinyu6/archive/2023/09/28/17736441.html
-Advertisement-
Play Games

本篇博文圍繞使用Python開發熱門游戲2048 GAME(命令行版本) 代碼未做任何優化(原生且隨意)、全程以面向過程、MVC的設計思想為主、開發環境是Ubuntu系統下的Pycharm 2048是我很久以前學習Python過程中的一個作業,接下來直入正題—— 一、瞭解游戲 1. 介紹 《2048 ...


本篇博文圍繞使用Python開發熱門游戲2048 GAME(命令行版本)

代碼未做任何優化(原生且隨意)、全程以面向過程MVC的設計思想為主、開發環境是Ubuntu系統下的Pycharm

2048是我很久以前學習Python過程中的一個作業,接下來直入正題——

一、瞭解游戲

1. 介紹

2048》是一款單人線上和移動端游戲,由19歲的義大利人Gabriele Cirulli於2014年3月開發。游戲任務是在一個網格上滑動小方塊來進行組合,直到形成一個帶有有數字2048的方塊(來源:維基百科

2. 玩法規則

  1. 通過方向鍵讓方塊整體上下左右移動
  2. 如果兩個帶有相同數字的方塊在移動中碰撞,則它們會相加合併為一個新方塊
  3. 每次出現方塊移動時,都會有一個值為2或者4的新方塊出現
  4. 初始開局時,4*4的方塊,隨機2個方塊賦值2或者4
  5. 其中所出現的數字都是2的冪,2,4,8,16......

二、MVC設計

Model:無
View:終端界面(有時間再研究一下pyQt),列印二維列表,輸入輸出控制
Controller:二維列表-矩陣、數據控制、上下左右操作、計分機制、方塊合併處理等等

三、核心函數

截圖_20230928194512

通過觀察游戲界面,可知數據由二維數組(線性代數--方陣)存儲,將上圖映射到如下代碼:

source = [
    [0, 0, 0, 0],
    [0, 0, 2, 2],
    [0, 0, 0, 0],
    [0, 0, 0, 0]
]

通過玩法規則第1條可知,方向鍵上下左右移動,四種移動必然存在相似的操作,祁天暄講師通過分析向左移動來書寫後續代碼,我這裡也會以向左移動來分析如何寫後續的代碼。

截圖_20230928194603

[0, 0, 2, 2]

取上述一行,按左方向鍵移動後,可以看到兩個方塊2持續左移(如果左邊還有非0的方塊,那麼就會頂住該非0的方塊),然後相撞變成方塊4,因為有方塊移動,所以隨機挑選一個方塊0進行填充成2(不限於當前行,也可能發生在其他行):
截圖_20230928194619

本行規律:

[0, 0, 2, 2] >發生滑動> [2, 2, 0, 0] >相等相撞求和> [4, 0, 0, 0] >隨機填充> [4, 0, 0, 2]

經過多局游戲結合上方的規律,可以得知以下規律:

[0, 0, 2, 2] >發生滑動> [2, 2, 0, 0] >相等相撞求和> [4, 0, 0, 0] >隨機填充> [4, 0, 0, 2]
[4, 0, 2, 2] >發生滑動> [4, 2, 2, 0] >相等相撞求和> [4, 4, 0, 0] >隨機填充> [4, 4, 0, 4]
[4, 4, 2, 2] >發生滑動,不動> [4, 4, 2, 2] >相等相撞求和> [8, 4, 0, 0] >隨機填充> [4, 0, 0, 2]

1. 滑動處理

發生滑動的環節,可以得出一個規律,有0在非0元素的前方則必滑動,否則不動

[0, 0, 2, 2] >發生滑動> [2, 2, 0, 0]
[4, 0, 2, 2] >發生滑動> [4, 2, 2, 0]
[4, 4, 2, 2] >發生滑動,不動> [4, 4, 2, 2]

所以此處構造一個zero_to_end函數,功能就是將0移至末尾處,並保持非0元素應有的順序,先看一下中規中矩的方式(冒泡式的移動,時間複雜度較高):

def zero_to_end(list_data):
    for i in range(3, -1, -1):
        for j in range(i):
            if list_data[j] == 0:
                list_data[j], list_data[j + 1] = list_data[j + 1], list_data[j]

再看一下另一種寫法(採用該函數,時間複雜度為O(n)):

def zero_to_end(list_data):
    """
    重排序函數(核心演算法)
    非0元素移至最前(保持順序),0元素移至最後,充當中間人處理列表的角色
    :param list_data: list 一維列表
    :return: None
    """
    for i in range(3, -1, -1):
        if not list_data[i]:
            del list_data[i]
            list_data.append(0)

2. 相等相撞求和

經上一函數,每一行列表都被處理成:若幹非0元素有序在前,若幹0元素在後

[2, 2, 0, 0] >相等相撞求和> [4, 0, 0, 0]
[4, 2, 2, 0] >相等相撞求和> [4, 4, 0, 0]
[4, 4, 2, 2] >相等相撞求和> [8, 4, 0, 0]

相等相撞求和這個過程肯定要統一函數處理,增加復用性,因此需要詳細拆分該流程的細節:

[4, 2, 2, 0]
如果第1個元素等==第2個元素:
    則第1個元素 + 第2個元素,並賦給第1個元素的位置
    刪除第2個元素
    末尾追加一個0
[4, 2, 2, 0]
如果第2個元素==第3個元素(符合條件)
    則第2個元素 + 第3個元素,並賦給第2個元素的位置[4, 4, 2, 0]
    刪除第3個元素[4, 2, 0]
    末尾追加一個0[4, 2, 0, 0]
[4, 2, 0, 0]
如果第3個元素==第4個元素
    則第3個元素 + 第4個元素,並賦給第3個元素的位置
    刪除第4個元素
    末尾追加一個0

也就是說,相鄰且相等的兩個元素相加,應賦值給前方位置的元素,然後刪除後方位置的元素,刪除了一個,肯定還要湊回去的,根據游戲規則,補0即可

其實上方的邏輯還可以進行優化,當檢測到當前位置的元素為0時,直接打斷迴圈即可(因為已經被zero_to_end函數處理過了),封裝成merge_single函數如下:

def merge_single(list_data):
    """
    合併元素函數(核心演算法)
    重排序後,左邊兩個相鄰相同的非0元素相加,後方補0,並加分(可diy)
    如果兩個相鄰的元素不同或者為0,則不做其他操作
    :param list_data: list 一維列表
    :return: None
    """
    zero_to_end(list_data)  # 處理一維列表
    for i in range(3):
        if list_data[i] == 0: break  # 檢測到當前位置為0,後方就不管了,直接打斷
        if list_data[i] == list_data[i + 1]:
            list_data[i] *= 2  # 等價於 += list_data[i + 1]
            del list_data[i + 1]  # 刪除 [i + 1]位置的元素
            list_data.append(0)  # 補0

有點不太放心,放一條數據進行測試:

[4, 4, 2, 2] >i = 0,相加> [8, 4, 2, 2] >刪除i + 1位置> [8, 2, 2] >補0> [8, 2, 2, 0] 
>迴圈結束第1次,i = 1,又相加> [8, 4, 2, 0] >又刪除i + 1位置> [8, 4, 0] >又補0> [8, 4, 0, 0]
> 迴圈結束第2次,i = 2,發現是0,直接跳出迴圈 

3. 隨機填充

玩法規則第3條,當游戲中,發生方塊滑動時,在0元素區域隨機抽取一個位置,隨機賦值2或者4。

因此,先定義全局變數,一個存2和4的元組,通過random模塊實現隨機索引獲取2或者4。

random_tuple = (2, 4)  # 初始添加的值、移動時添加的值

通過while迴圈不斷尋找隨機方格,直到發現該方格存儲0,那麼該方格將被賦予新值。

def random_site():
    """
    隨機填充0元素函數(非核心)
    隨機挑選0元素的位置,進行隨機填充random_list中的任意一個元素
    可通過增刪改變random_list中的元素,從而影響到隨機填充的數字
    :return: None
    """
    random_list_len = len(random_tuple)
    while True:
        x = random.randint(0, 3)
        y = random.randint(0, 3)
        if after_source[x][y] == 0:
            after_source[x][y] = random_tuple[random.randint(0, random_list_len - 1)]
            break

四、附加功能函數

通過以上三步,成功的完成了2048的核心功能,接下來逐一部署2048的初始化、游戲操作、用戶操作、列印等等函數。

1. 初始數據和矩陣比較

構造游戲初始數據,以全局變數表示:

score = 0  # 初始分數,後續累加即可
source = [
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0]
]

單純的一個source表示數據可能還不夠,我構造了兩個4*4的矩陣,分別命名為before_source和after_source:

before_source = [
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0]
]  # 操作前的矩陣
after_source = [
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0]
]  # 操作後的矩陣(當前列印的矩陣)

這兩個矩陣,用於用戶操作前的一個比較(後臺比較),假設用戶進行左向移動,那麼移動前的數據傳給before_source,移動後(即每一行調用merge_single函數後)的數據傳給after_source,after_source才是用戶需要看的,兩者在後臺進行比較後,倘若不同,則說明發生了“方塊移動”,那麼就要調用隨機填充的函數,如果相同,說明沒有方塊滑動,則不可隨機填充。假如對以下的數據發起左移操作後,是不存在元素移動的,即不會調用隨機填充:

[
    [4, 0, 0, 0],
    [0, 0, 0, 0],
    [2, 4, 2, 0],
    [8, 2, 0, 0]
]

根據上述分析,構造比較函數compare_matrix:

def compare_matrix():
    """
    二維數組比較
    操作前後的二維數組(矩陣)進行比較
    如果不相等,說明有元素可移動,當移動時調用random_site()函數
    """
    if not (before_source == after_source):
        random_site()

2. 矩陣數據列印

每次執行完移動操作後(無論是上下還是左右),肯定都要反饋給用戶數據界面,因此需要構造列印矩陣的函數:

def print_list():
    """列印游戲過程中必看的矩陣信息"""
    for single_list in after_source:
        print(single_list)

3. main入口(框架搭建)

調用程式總該需要一個入口,構造main函數。

迴圈開始階段,通過global關鍵字操作全局變數before_source,此處需要註意:應使用深拷貝(需要導入copy模塊),將當前的數據拷貝給before_source,如果採取淺拷貝,操作after_source後,before_source也會跟隨變化,這樣就導致before_source恆等於after_source。

上下左右以input輸入(w 、s、a、d)來進行移動,n表示主動認輸,q表示退出游戲。

每次執行完移動操作後,都需要進行反饋數據界面,所以迴圈末尾需要調用print_list函數和列印當前分數:

def main():
    """程式入口:初始化 + 輸入 + 輸出"""
    while True:
        global before_source
        before_source = copy.deepcopy(after_source)
        key = input("鍵入:")
        if key == "a": pass
        if key == "d": pass
        if key == "w": pass
        if key == "s": pass
        if key == "n": pass
        if key == "q": break  
        print_list()
            
            
main()  # 調用main函數,即正常游戲的入口

當準備輸入時,手動中止程式,會發現很煩人的紅色報錯

因此加上try和except簡單的處理一下:

def main():
    """程式入口:初始化 + 輸入 + 輸出"""
    while True:
        try:
            key = input("鍵入:")
            global before_source
            before_source = copy.deepcopy(after_source)
            if key == "a": pass
            if key == "d": pass
            if key == "w": pass
            if key == "s": pass
            if key == "n": pass
            if key == "q": break
            print(f"當前分數:{score}")
            print_list()
        except KeyboardInterrupt:
            break
        
            
            
main()  # 調用main函數,即正常游戲的入口

4. 實現認輸功能

構建forfeit函數,列印最終分數後,人為拋出KeyboardInterrupt異常,直接調到except執行break打斷迴圈(為了不在列印最終得分後,執行後續兩條語句):

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-JqFS4KKo-1674483797912)(/home/ronan/.config/Typora/typora-user-images/image-20230123214632123.png)]

def forfeit():
    """認輸"""
    print(f"玩家已認輸,最終得分:{score}")
    raise KeyboardInterrupt

5. 加分機制

每發生方塊碰撞合併後,相加數字即為當局加分,比如初始為0,兩個相鄰的方塊2碰撞合併後變成方塊4,當前分數+4,即分數為4。

在merge_single函數中(參考2.2的函數),list_data.append(0)語句後添加下述代碼:

global score
score += list_data[i]

即:

def merge_single(list_data):
    """
    合併元素函數(核心演算法)
    重排序後,左邊兩個相鄰相同的非0元素相加,後方補0,並加分(可diy)
    如果兩個相鄰的元素不同或者為0,則不做其他操作
    :param list_data: list 一維列表
    :return: None
    """
    zero_to_end(list_data)
    for i in range(3):
        if list_data[i] == 0: break
        if list_data[i] == list_data[i + 1]:
            list_data[i] *= 2
            del list_data[i + 1]
            list_data.append(0)
            global score
            score += list_data[i]

6. 游戲初始化

為了讓游戲設置得靈活一點,增加全局變數init_count,表示初始方塊需賦值2或者4的個數,通常為2。

init_count = 2  # 初始值的個數


def init():
    """
    游戲初始化
    :return: None
    """
    print(f"""當前分數:{score}\n操作方式:q退出 n認輸
       w(上)
a(左)  s(下)  d(右)""")
    for i in range(init_count):  # 隨機生成init_count個初始值
        random_site()
    print_list()

7. 各方向移動操作

首先要明確,核心函數中第2節的相等相撞合併函數,僅僅針對一維列表,而整個游戲以二維列表為主,因此需要復用該代碼:

def merge():
    """合併操作,詳見merge_single()函數"""
    for i in range(4):
        merge_single(after_source[i])

接下來逐一分析,左右上下操作如何實現...

(1)左(基礎操作)

調用merge函數,完成滑動合併,然後比較前後矩陣相等來決定是否調用隨機填充(即調用compare_matrix函數)

def left():
    """向左操作"""
    merge()

(2)右

最暴力無腦的辦法就是複製上述函數代碼,然後更改,但是我一直寫這些簡單清晰的函數,就是為了復用,所以這裡應該想辦法復用merge等代碼,我以向左操作為基礎,僅看merge函數,假設每一行都逆轉,再進行向左的核心操作,再逆轉回去,不就可以了嗎,比如:

[0, 2, 2, 4]向右移動操作後變成[0, 0, 4, 4]
[0, 2, 2, 4] >逆轉> [4, 2, 2, 0] >merge> [4, 4, 0, 0] >逆轉> [0, 0, 4, 4]

因此代碼如下:

def reverse():
    """逆轉2048二維列表中的每一行一維列表"""
    for i in range(4):
        after_source[i].reverse()
def right():
    """向右操作"""
    reverse()
    merge()
    reverse()

(3)上

同樣為了復用,以向左操作為基礎,僅看merge函數,假設進行矩陣轉置,然後調用merge操作,再轉置,比如:

[0, 2, 0, 0]
[4, 2, 0, 0]
[0, 0, 4, 0]
[4, 0, 0, 0]
轉置後
[0, 4, 0, 4]
[2, 2, 0, 0]
[0, 0, 4, 0]
[0, 0, 0, 0]
調用merge後
[8, 0, 0, 0]
[4, 0, 0, 0]
[4, 0, 0, 0]
[0, 0, 0, 0]
再轉置回來,得到結果
[8, 4, 4, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]

因此代碼如下(3種轉置均可):

def transposition():
    """二維列表轉置(矩陣轉置)"""
    for x in range(4):
        for y in range(x, 4):
            after_source[x][y], after_source[y][x] = after_source[y][x], after_source[x][y]

def transposition():
    """二維列表轉置(矩陣轉置)"""
    new_map = [list(item) for item in zip(*after_source)]
    after_source.clear()
    after_source.extend(new_map)

def transposition():
    """二維列表轉置(矩陣轉置)"""
    new_map = [list(item) for item in zip(*after_source)]
    after_source[:] = new_map
def up():
    """向上操作"""
    transposition()
    merge()
    transposition()

(3)下

根據上移和右移操作所得的靈感,同樣是以左移為基礎操作。假設進行矩陣轉置,逆轉後,調用merge操作,再逆轉,再轉置,比如:

[0, 2, 0, 0]
[4, 2, 0, 0]
[0, 0, 4, 0]
[4, 0, 0, 0]
轉置後
[0, 4, 0, 4]
[2, 2, 0, 0]
[0, 0, 4, 0]
[0, 0, 0, 0]
逆轉每一行後
[4, 0, 4, 0]
[0, 0, 2, 2]
[0, 4, 0, 0]
[0, 0, 0, 0]
調用merge後
[8, 0, 0, 0]
[4, 0, 0, 0]
[4, 0, 0, 0]
[0, 0, 0, 0]
再逆轉回來
[0, 0, 0, 8]
[0, 0, 0, 4]
[0, 0, 0, 4]
[0, 0, 0, 0]
再轉置回來,得到結果
[0, 0, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0]
[8, 4, 4, 0]

因此代碼如下:

def down():
    """向下操作"""
    transposition()
    reverse()
    merge()
    reverse()
    transposition()

五、最終代碼

"""
    2048 GAME
"""
import random
import copy

score = 0  # 分數
init_count = 2  # 初始值的個數
before_source = [
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0]
]  # 操作前的矩陣
after_source = [
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0]
]  # 操作後的矩陣(當前列印的矩陣)
random_tuple = (2, 4)  # 初始添加的值、移動時添加的值


# Controller層
def zero_to_end(list_data):
    """
    重排序函數(核心演算法)
    非0元素移至最前(保持順序),0元素移至最後,充當中間人處理列表的角色
    :param list_data: list 一維列表
    :return: None
    """
    for i in range(3, -1, -1):
        if not list_data[i]:
            del list_data[i]
            list_data.append(0)


def merge_single(list_data):
    """
    合併元素函數(核心演算法)
    重排序後,左邊兩個相鄰相同的非0元素相加,後方補0,並加分(可diy)
    如果兩個相鄰的元素不同或者為0,則不做其他操作
    :param list_data: list 一維列表
    :return: None
    """
    zero_to_end(list_data)
    for i in range(3):
        if list_data[i] == 0: break
        if list_data[i] == list_data[i + 1]:
            list_data[i] *= 2
            del list_data[i + 1]
            list_data.append(0)
            global score
            score += list_data[i]


def random_site():
    """
    隨機填充0元素函數(非核心)
    隨機挑選0元素的位置,進行隨機填充random_list中的任意一個元素
    可通過增刪改變random_list中的元素,從而影響到隨機填充的數字
    :return: None
    """
    random_list_len = len(random_tuple)
    while True:
        x = random.randint(0, 3)
        y = random.randint(0, 3)
        if after_source[x][y] == 0:
            after_source[x][y] = random_tuple[random.randint(0, random_list_len - 1)]
            break


def merge():
    """合併操作,詳見merge_single()函數"""
    for i in range(4):
        merge_single(after_source[i])


def reverse():
    """逆轉2048二維列表中的每一行一維列表"""
    for i in range(4):
        after_source[i].reverse()


def transposition():
    """二維列表轉置(矩陣轉置)"""
    for x in range(4):
        for y in range(x, 4):
            after_source[x][y], after_source[y][x] = after_source[y][x], after_source[x][y]


def compare_matrix():
    """
    二維數組比較
    操作前後的二維數組(矩陣)進行比較
    如果不相等,說明有元素可移動,當移動時調用random_site()函數
    """
    if not (before_source == after_source):
        random_site()


def left():
    """向左操作"""
    merge()


def right():
    """向右操作"""
    reverse()
    merge()
    reverse()


def up():
    """向上操作"""
    transposition()
    merge()
    transposition()


def down():
    """向下操作"""
    transposition()
    reverse()
    merge()
    reverse()
    transposition()


# View層
def init():
    """
    游戲初始化
    :return: None
    """
    print(f"""當前分數:{score}\n操作方式:q退出 n認輸
       w(上)
a(左)  s(下)  d(右)""")
    for i in range(init_count):  # 隨機生成init_count個初始值
        random_site()
    print_list()


def print_list():
    """列印游戲過程中必看的矩陣信息"""
    for single_list in after_source:
        print(single_list)


def forfeit():
    """認輸"""
    print(f"玩家已認輸,最終得分:{score}")
    raise KeyboardInterrupt


def main():
    """程式入口:初始化 + 輸入 + 輸出"""
    init()
    while True:
        try:
            global before_source
            before_source = copy.deepcopy(after_source)
            key = input("鍵入:")
            if key == "a": left()
            if key == "d": right()
            if key == "w": up()
            if key == "s": down()
            if key == "n": forfeit()
            if key == "q": break
            compare_matrix()
            print(f"當前分數:{score}")
            print_list()
        except KeyboardInterrupt:
            break


main()


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 趁著國慶前夕整了一個vite4結合react18搭建後臺管理模板,搭配上位元組團隊react組件庫ArcoDesign,整體操作功能非常絲滑。目前功能支持多種模板佈局、暗黑/亮色模式、國際化、許可權驗證、多級路由菜單、tabview標簽欄快捷菜單、全屏控制等功能。極簡非凡的佈局界面、高定製化模塊,用心打 ...
  • 針對改動範圍大、影響面廣的需求,我通常會問上線了最壞情況是什麼?應急預案是什麼?你帶開關了嗎?。當然開關也是有成本的,接下來本篇跟大家一起交流下高頻發佈支撐下的功能開關技術理論與實踐結合的點點滴滴。 ...
  • RPC,Remote Procedure Call 即遠程過程調用,與之相對的是本地服務調用,即LPC(Local Procedure Call)。本地服務調用比較常用,像我們應用內部程式(註意此處是程式而不是方法,程式包含方法)互相調用即為本地過程調用,而遠程過程調用是指在本地調取遠程過程進行使用... ...
  • 使用雙指針進行原地移除元素 題目描述 給定一個數組 nums 和一個值 val,需要將數組中所有等於 val 的元素原地刪除,並返回刪除後數組的新長度。 要求: 不使用額外的數組空間 只能使用 O(1) 額外空間 數組中超過新長度後面的元素可以忽略 示例 1: 輸入:nums = [3,2,2,3] ...
  • 在Python中,字元串可以用單引號或雙引號括起來。'hello' 與 "hello" 是相同的。您可以使用print()函數顯示字元串文字: 示例: print("Hello") print('Hello') 將字元串分配給變數是通過變數名後跟等號和字元串完成的: 示例 a = "Hello" p ...
  • 前言 ThreadLocal可以用來存儲線程的本地數據,做到線程數據的隔離 ThreadLocal的使用不當可能會導致記憶體泄漏,排查記憶體泄漏的問題,不僅需要熟悉JVM、利用好各種分析工具還耗費人工 如果能明白其原理並正確使用,就不會導致各種意外發生 本文將從使用場景、實現原理、記憶體泄漏、設計思想等層 ...
  • 目錄場景1 定義全部異常處理類2 替換request引用3 代碼優化總結 場景 本文前端用的是阿裡的Ant-Design框架,其他框架也有全局攔截器,思路是相同,具體實現自行百度下吧 因為每次都需要調介面,都需要單獨處理異常情況(code !=0),因此前端需要對後端返回的通用響應進行統一處理,比如 ...
  • 在Dart學習的第02天,我們通過基礎語法說明和樣例代碼的方式,學習了Dart的16個基礎語法,這些基礎語法給我們後面編寫的Flutter程式打下來堅實基礎。今天,我們繼續深入學習Dart乃至所有編程語言都非常重要的部分:可迭代的集合…… ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...