tft每日頭條

 > 科技

 > go ai編程

go ai編程

科技 更新时间:2024-12-13 11:44:33

端到端的實現

go ai編程(七爪源碼用Go)1

我們大多數人都喜歡知識競賽,對吧? 有許多應用程序可以通過讓我們回答來自不同職業的問題來解渴。

在這篇文章中,我将解釋我是如何使用 Golang 實現一個實時競賽應用程序的。

申請流程

go ai編程(七爪源碼用Go)2

需要遵循一些業務規則。

  • 當連接用戶達到兩個時,比賽将在 3 秒内自動開始。
  • 我們的比賽共有三個州。這些是 NOT_STARTED、STARTED、FINISHED。
  • 問題有四個選項,用戶必須在 10 秒内回答一個問題。
  • 比賽結束後,向用戶展示排行榜以查看比賽結果。

我的架構決策

在本節中,我将嘗試解釋為什麼我做出了一些決定,并在開始之前嘗試對我們的項目提出一些觀點。這部分就像電影劇透一樣。

  • Websocket 是實現實時應用程序的基本協議。它提供客戶端和服務器之間的雙向通信。有很多技術文章介紹了它的概念,我就不贅述了。我用它來發送問題并獲得連接用戶的答案。
  • 我為每個連接的用戶使用了一個唯一的 id(如 Session-id)。這樣做,我可以輕松區分用戶。在我們的例子中,我們用他們的會話 ID 存儲我們的用戶,我們的服務器使用它們來管理讀寫操作。
  • 為了支持并發讀寫操作,我使用了 sync.Map 。我使用 sessionID 作為鍵,使用 Client 結構作為如下所示的值。客戶端結構由兩個字段組成,一個用于寫入和讀取的客戶端 WebSocket 連接以及用于計算排行榜的 totalScore。

go ai編程(七爪源碼用Go)3

  • 廣播是一個特殊術語,表示同時将消息傳輸給所有接收者的方法。 不幸的是,gorilla/websocket 中沒有廣播方法; 因此,我們将使用我們自定義的廣播方法向所有用戶發送消息。

go ai編程(七爪源碼用Go)4

  • 要将問題發送給我們的用戶,我們需要定義一個模型。 在我們的應用程序中,我不想使用 Question 結構,因為它具有 correct_answer 字段。 我想對連接的用戶隐藏這些信息,所以我創建了另一個名為 QuestionDTO 的模型,如下所示。

go ai編程(七爪源碼用Go)5

比賽流程

我曾經使用 RunCompetition() 方法管理比賽流程,如下所示。

我通過創建一個 goroutine 在應用程序的主要流程中調用了這個函數。

func RunCompetition() { CompetitionState = CompetitionNotStartedState for { if CompetitionState == CompetitionNotStartedState { time.Sleep(CompetitionStateDuration) numberOfClients := CountClient() msg := DetermineCompetitionState(numberOfClients) BroadcastMessage([]byte(msg)) if numberOfClients == 2 { time.Sleep(CompetitionStartDuration) CompetitionState = CompetitionStartedState } } else if CompetitionState == CompetitionStartedState { PrepaRequestions() StartSendingQuestions() CompetitionState = CompetitionFinish } else if CompetitionState == CompetitionFinish { leaderBoard := CreateLeaderBoard() jsonBytes, _ := json.Marshal(leaderBoard) BroadcastMessage(jsonBytes) BroadcastMessage([]byte(CompetitionFinishedStateMessage)) break } } }

RunCompetition() 方法中有三個 CompetitionState。

  • CompetitionNotStartedState:要開始比賽,必須有兩個用戶。 當 numberOfClients 等于 2 時,狀态變為 CompetitionStartedState。
  • CompetitionStartedState:在這種狀态下,我們每 10 秒向所有連接的用戶發送問題。

func StartSendingQuestions() { for i := range Questions { Questions[i].IsTimeout = false questionDTO := Questions[i].ToDTO() questionDTOBytes, _ := json.Marshal(questionDTO) BroadcastMessage(questionDTOBytes) time.Sleep(QuestionResponseIntervalDuration) Questions[i].IsTimeout = true } }

發送問題時,我們将 Question 結構體轉換為 questionDTO 以向連接的用戶隐藏正确答案以防止作弊。

10 秒後,我們将 IsTimeout 更改為 true,因為給問題的時間到了。

  • CompetitionFinish:發送完所有問題後, CompetitionState 變為 CompetitionFinish。 比賽結束後,我們必須創建排行榜并将其發送給所有連接的用戶。

處理客戶端應答流

我們需要從用戶那裡得到答案來檢查和計算他們的分數。

func HandleClientAnswer(sessionID string, message []byte) { var ClientMsg ClientMessage json.Unmarshal(message, &ClientMsg) for _, question := range Questions { if question.ID == ClientMsg.QuestionId { if question.IsTimeout == true { fmt.Println("Response Time is out") } else { load, _ := Clients.Load(sessionID) client := load.(Client) if ClientMsg.Answer == question.CorrectAnswer { client.totalScore = ScoreForCorrectAnswer Clients.Store(sessionID, client) fmt.Printf("Right Answer!!! SessionId: %s, TotalScore: %d\n", sessionID, client.totalScore) } else { fmt.Printf("Wrong Answer!! Your Answer is : %s, Right Answer is : %s, SessionId: %s, TotalScore: %d\n", ClientMsg.Answer, question.CorrectAnswer, sessionID, client.totalScore) } } } } }

用戶在指定的時間間隔内正确回答問題可以獲得分數( 10)。

這裡有一些重要的點:

  • IsTimeout:指定時間間隔
  • 比較 question.ID 和 ClientMsg.QuestionId :判斷是否被問到問題
  • 比較 ClientMsg.Answer 和 question.CorrectAnswer :判斷用戶是否給出了正确答案。

滿足這些條件後,用戶的分數通過 sessionID 存儲在地圖上。 我們在 ws() 方法中調用這個函數。

func ws(c echo.Context) error { numberOfClients := CountClient() if numberOfClients >= 2 { return c.string(http.StatusBadRequest, "") } wsConn, err := Upgrader.Upgrade(c.Response(), c.Request(), nil) if err != nil { return err } defer wsConn.Close() sessionID := IDGenerator() Clients.Store(sessionID, Client{ wsConn: wsConn, totalScore: 0, }) for { _, message, err := wsConn.ReadMessage() if err != nil { Clients.Delete(sessionID) c.Logger().Errorf("Client disconnect msg=%s err=%s", string(message), err.Error()) return nil } HandleClientAnswer(sessionID, message) } }

為了讓我們的應用程序簡單,比賽将從兩個用戶開始。 如果用戶的數量大于 2,我們的應用會發送 http.StatusBadRequest 給用戶。

關注七爪網,獲取更多APP/小程序/網站源碼資源!

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关科技资讯推荐

热门科技资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved