重啟撲克機器人之路 - 1:從Python開始的新嘗試

更新於 發佈於 閱讀時間約 11 分鐘

今天開始了新的撲克機器人Project,這次選擇用Python而不是OpenHoldem的C++。其實挺有趣的,以前總覺得要寫機器人是件很困難的事,但現在連我這種程式小白都能靠著插件和LLM寫出基本的框架,這讓我開始思考是不是能把機器學習也加進來。

目前用ADB和OpenCV來處理手機截圖和畫面識別,雖然都還很陽春,但至少驗證了可行性。不過下一步的撲克牌辨識就讓我陷入了思考 - 單純用OpenCV的template matching感覺太過脆弱,平台改版或換平台就得重來。想起之前上fast.ai課程時學過的圖像辨識,或許能用那個方向來處理卡牌識別。

策略核心這塊還在想該怎麼處理。之前的經驗告訴我,直接套用solver策略行不通,自己寫死的腳本又太容易被識破是機器人。這讓我意識到可能需要更靈活的方式,但目前還沒有明確的想法。決定先專注在最基礎的部分 - 確保程式能穩定連接到poker app並正確辨識桌面狀況。

想起之前做Pio bot和Spin bot的經驗,我更清楚知道這次要怎麼規劃開發流程。就像之前寫過的,初期投入成本要控制,要隨時準備接受feedback並調整方向。這次選擇Python作為開發語言,某種程度上也是降低入門門檻的選擇,讓我能更專注在核心邏輯而不是語言本身的學習上。

我用來截取template的code:

import cv2

import numpy as np

from ppadb.client import Client as AdbClient

import os



class CardTemplateCapture:

def __init__(self):

# Create output directory if it doesn't exist

self.output_dir = 'card_templates'

if not os.path.exists(self.output_dir):

os.makedirs(self.output_dir)

# Initialize ADB connection

self.adb = AdbClient(host="127.0.0.1", port=5037)

self.devices = self.adb.devices()

if not self.devices:

raise Exception("No devices found. Make sure your emulator is running.")

self.device = self.devices[0]

# Initialize variables for region selection

self.start_point = None

self.end_point = None

self.drawing = False

self.current_image = None

self.original_image = None

self.template_count = 0

# Set target display height (adjust this based on your screen)

self.target_height = 1200

def take_screenshot(self):

"""Take a screenshot and return both original and resized versions."""

screenshot_data = self.device.screencap()

nparr = np.frombuffer(screenshot_data, np.uint8)

self.original_image = cv2.imdecode(nparr, cv2.IMREAD_COLOR)

# Calculate scaling factor to fit screen height

scale = self.target_height / self.original_image.shape[0]

new_width = int(self.original_image.shape[1] * scale)

# Resize image for display

self.current_image = cv2.resize(self.original_image, (new_width, self.target_height))

return self.current_image.copy()

def get_scale_factor(self):

"""Calculate the scale factor between original and display images."""

return self.original_image.shape[0] / self.current_image.shape[0]

def mouse_callback(self, event, x, y, flags, param):

"""Handle mouse events for selecting regions."""

if event == cv2.EVENT_LBUTTONDOWN:

self.drawing = True

self.start_point = (x, y)

elif event == cv2.EVENT_MOUSEMOVE and self.drawing:

temp_img = self.current_image.copy()

cv2.rectangle(temp_img, self.start_point, (x, y), (0, 255, 0), 2)

cv2.imshow('Capture Cards', temp_img)

elif event == cv2.EVENT_LBUTTONUP:

self.drawing = False

self.end_point = (x, y)

# Calculate rectangle coordinates on display image

x1 = min(self.start_point[0], self.end_point[0])

y1 = min(self.start_point[1], self.end_point[1])

x2 = max(self.start_point[0], self.end_point[0])

y2 = max(self.start_point[1], self.end_point[1])

# Scale coordinates to original image size

scale = self.get_scale_factor()

orig_x1 = int(x1 * scale)

orig_y1 = int(y1 * scale)

orig_x2 = int(x2 * scale)

orig_y2 = int(y2 * scale)

# Extract and save the selected region from original image

if (orig_x2 - orig_x1) > 0 and (orig_y2 - orig_y1) > 0:

card = self.original_image[orig_y1:orig_y2, orig_x1:orig_x2]

filename = os.path.join(self.output_dir, f'card_{self.template_count}.png')

cv2.imwrite(filename, card)

print(f"Saved {filename}")

self.template_count += 1

def capture_templates(self):

"""Main loop for capturing templates."""

print("Instructions:")

print("1. Click and drag to select card regions")

print("2. Press 'r' to refresh screenshot")

print("3. Press 'q' to quit")

# Create window with scrollbars

cv2.namedWindow('Capture Cards', cv2.WINDOW_NORMAL)

cv2.resizeWindow('Capture Cards', 800, 1200) # Set initial window size

cv2.setMouseCallback('Capture Cards', self.mouse_callback)

# Initial screenshot

screen = self.take_screenshot()

cv2.imshow('Capture Cards', screen)

while True:

key = cv2.waitKey(50) & 0xFF

if key == ord('q'):

break

elif key == ord('r'):

print("Refreshing screenshot...")

screen = self.take_screenshot()

cv2.imshow('Capture Cards', screen)

cv2.destroyAllWindows()



def main():

try:

capturer = CardTemplateCapture()

capturer.capture_templates()

except Exception as e:

print(f"Error: {e}")



if __name__ == "__main__":

main()
留言
avatar-img
留言分享你的想法!
avatar-img
傑劉的沙龍
3會員
18內容數
傑劉的沙龍的其他內容
2025/03/16
記錄了對撲克數據庫程式碼的深入理解,以及如何通過精確的查詢獲得準確的分析結果。通過重新組織action type的分類,讓後續的數據分析變得更加高效。這個數據庫將是撲克機器人專案的重要組成部分,用於建立更精確的對手模型。
Thumbnail
2025/03/16
記錄了對撲克數據庫程式碼的深入理解,以及如何通過精確的查詢獲得準確的分析結果。通過重新組織action type的分類,讓後續的數據分析變得更加高效。這個數據庫將是撲克機器人專案的重要組成部分,用於建立更精確的對手模型。
Thumbnail
2025/03/14
記錄了在建構撲克數據庫過程中遇到的挑戰和收穫。探討了自建系統與現成工具的差異,以及如何確保數據準確性。同時反思了精確表達查詢需求的重要性,以及自建系統潛在的長期價值。
Thumbnail
2025/03/14
記錄了在建構撲克數據庫過程中遇到的挑戰和收穫。探討了自建系統與現成工具的差異,以及如何確保數據準確性。同時反思了精確表達查詢需求的重要性,以及自建系統潛在的長期價值。
Thumbnail
2025/03/13
記錄了在撲克機器人開發中從機器學習模型轉向建立自定義數據庫的過程,以及這個策略轉變背後的思考。通過分析真實玩家的行動分布,希望能訓練出更有效的撲克機器人。
Thumbnail
2025/03/13
記錄了在撲克機器人開發中從機器學習模型轉向建立自定義數據庫的過程,以及這個策略轉變背後的思考。通過分析真實玩家的行動分布,希望能訓練出更有效的撲克機器人。
Thumbnail
看更多
你可能也想看
Thumbnail
今天打開GPT,發現GPT編輯已經可以使用了, 便開心的試起水溫。 我創作了一個可以抽塔羅和解讀的機器人, 有興趣的讀者也可以點進去, 抽塔羅牌詢問她問題。 以下是我嘗試用塔羅來抽牌並且解牌的結果。 另外製作的過程非常簡單, 首先可以先點進去更新版的GPT這裡。 然後再跟著GPT問的問題
Thumbnail
今天打開GPT,發現GPT編輯已經可以使用了, 便開心的試起水溫。 我創作了一個可以抽塔羅和解讀的機器人, 有興趣的讀者也可以點進去, 抽塔羅牌詢問她問題。 以下是我嘗試用塔羅來抽牌並且解牌的結果。 另外製作的過程非常簡單, 首先可以先點進去更新版的GPT這裡。 然後再跟著GPT問的問題
Thumbnail
不是摸魚,是因為前幾天上班超認真,處理了一堆事,今天突然就沒事了,運氣真好,希望不要被主管發現我現在沒事做在聽歌~~~ https://youtu.be/8MG--WuNW1Y?t=37
Thumbnail
不是摸魚,是因為前幾天上班超認真,處理了一堆事,今天突然就沒事了,運氣真好,希望不要被主管發現我現在沒事做在聽歌~~~ https://youtu.be/8MG--WuNW1Y?t=37
Thumbnail
Hi,我是茶桁。 在过去的两讲中,我们已经使用 OpenAI 提供的 Embedding 接口完成了文本分类的功能。现在,我们回到 Completion 接口,这一讲将带你更深入地了解该接口的使用。除此之外,我们还将快速搭建一个有界面的聊天机器人,这将让你更好地理解 Completion 接口的应
Thumbnail
Hi,我是茶桁。 在过去的两讲中,我们已经使用 OpenAI 提供的 Embedding 接口完成了文本分类的功能。现在,我们回到 Completion 接口,这一讲将带你更深入地了解该接口的使用。除此之外,我们还将快速搭建一个有界面的聊天机器人,这将让你更好地理解 Completion 接口的应
Thumbnail
本文詳述如何將大型語言模型(LLM)與程式碼深度整合,運用於3C賣場的客服助理示例,透過接收並解析使用者訊息,提取產品資訊,並與後端產品資料庫整合。接著,將整合資訊回傳給LLM生成最終回應訊息。同時,也探討了中英文理解差距及解決方法,並展示如何利用Python模擬資料庫提取詳細資訊。
Thumbnail
本文詳述如何將大型語言模型(LLM)與程式碼深度整合,運用於3C賣場的客服助理示例,透過接收並解析使用者訊息,提取產品資訊,並與後端產品資料庫整合。接著,將整合資訊回傳給LLM生成最終回應訊息。同時,也探討了中英文理解差距及解決方法,並展示如何利用Python模擬資料庫提取詳細資訊。
Thumbnail
這堂課闡述開發ChatGPT所需的重要概念和工具。涵蓋語言模型如何處理文字(Token),LLM的兩種類型(Base LLM和Instruction tuned LLM),系統、助手和用戶的角色定義。並介紹以Prompting簡化AI開發流程,且透過實戰教學說明如何進行分類和預防注入提示
Thumbnail
這堂課闡述開發ChatGPT所需的重要概念和工具。涵蓋語言模型如何處理文字(Token),LLM的兩種類型(Base LLM和Instruction tuned LLM),系統、助手和用戶的角色定義。並介紹以Prompting簡化AI開發流程,且透過實戰教學說明如何進行分類和預防注入提示
Thumbnail
由于 ChatGPT 的出現讓我們看到了聊天機器人的新可能性,我們這篇文章的目的,就是要來製作第一個屬於自己的聊天機器人。 我們先來準備範例的程式碼,並且稍後會再跟大家介紹要設計自己的 ChatGPT 聊天機器人的重要概念。 初始專案與環境設定 下載程式碼 請先使用下面這一段指令下載我們的範例程式碼
Thumbnail
由于 ChatGPT 的出現讓我們看到了聊天機器人的新可能性,我們這篇文章的目的,就是要來製作第一個屬於自己的聊天機器人。 我們先來準備範例的程式碼,並且稍後會再跟大家介紹要設計自己的 ChatGPT 聊天機器人的重要概念。 初始專案與環境設定 下載程式碼 請先使用下面這一段指令下載我們的範例程式碼
Thumbnail
這篇文章我想要參加Chat gpt的主題徵文 主要是讓chat gpt自行生成成語接龍遊戲的遊戲代碼
Thumbnail
這篇文章我想要參加Chat gpt的主題徵文 主要是讓chat gpt自行生成成語接龍遊戲的遊戲代碼
Thumbnail
前言 ChatGPT 的熱門程度早已想當然而,企業們爭相開始導入 OpenAI 技術的應用,好比進入了 AI 群雄割據的年代,不過 Microsoft Copilot 的主權宣示,這個重視高生產力時代,將會暫時遠離一場腥風血雨的爭鬥。 回歸本次的主角「AI 客服機器人」,筆者將他應用於課程回覆的狀況
Thumbnail
前言 ChatGPT 的熱門程度早已想當然而,企業們爭相開始導入 OpenAI 技術的應用,好比進入了 AI 群雄割據的年代,不過 Microsoft Copilot 的主權宣示,這個重視高生產力時代,將會暫時遠離一場腥風血雨的爭鬥。 回歸本次的主角「AI 客服機器人」,筆者將他應用於課程回覆的狀況
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News