SoFunction
Updated on 2025-04-17

Project Practice of Go Language Implementing Weight Lottery System

Requirement description

  • Supports configuration of multiple prizes and corresponding weights
  • Ensure that the lottery results meet the weight probability distribution
  • Prevent repeated winnings
  • Provide a lottery result verification interface

Complete implementation code

package main

import (
    "crypto/rand"
    "encoding/json"
    "fmt"
    "math/big"
    "net/http"
    "sync"
)

// Prize configurationtype Prize struct {
    ID     int    `json:"id"`
    Name   string `json:"name"`
    Weight int    `json:"weight"` // Weight value (non-percentage)}

// Lottery systemtype LotterySystem struct {
    prizes       []Prize
    totalWeight  int
    issuedPrizes map[int]bool
    mu           
}

// Initialize the lottery systemfunc NewLotterySystem(prizes []Prize) *LotterySystem {
    total := 0
    for _, p := range prizes {
        total += 
    }
    return &LotterySystem{
        prizes:       prizes,
        totalWeight:  total,
        issuedPrizes: make(map[int]bool),
    }
}

// Safe random number generationfunc secureRandom(max int) (int, error) {
    n, err := (, (int64(max)))
    if err != nil {
        return 0, err
    }
    return int(n.Int64()), nil
}

// Execute the lotteryfunc (ls *LotterySystem) Draw() (*Prize, error) {
    ()
    defer ()

    if  == 0 {
        return nil, ("no available prizes")
    }

    // Generate random numbers    randomNum, err := secureRandom()
    if err != nil {
        return nil, err
    }

    // Weight selection    current := 0
    for _, p := range  {
        current += 
        if randomNum < current {
            if [] {
                continue // Skip the awards issued            }
            [] = true
            return &p, nil
        }
    }

    return nil, ("draw failed")
}

// HTTP servicefunc main() {
    // Initialize the prize pool    prizes := []Prize{
        {ID: 1, Name: "First Prize", Weight: 1},
        {ID: 2, Name: "Second Prize", Weight: 5},
        {ID: 3, Name: "Third Prize", Weight: 20},
        {ID: 4, Name: "Participation Award", Weight: 74},
    }

    lottery := NewLotterySystem(prizes)

    ("/draw", func(w , r *) {
        prize, err := ()
        if err != nil {
            (w, (), )
            return
        }

        ().Set("Content-Type", "application/json")
        (w).Encode(prize)
    })

    ("The lottery service has been started, listening port 8080")
    (":8080", nil)
}

Core function description

Weighting algorithm:

// Weight selection logiccurrent := 0
for _, p := range  {
    current += 
    if randomNum < current {
        return &p
    }
}
  • Use the cumulative weight interval algorithm
  • Ensure the accuracy of probability distribution

Safe random numbers:

// Generate safe random numbers using crypto/randfunc secureRandom(max int) (int, error) {
    n, err := (, (int64(max)))
    // ...
}
  • Avoid predictability of math/rand
  • Meet the safety lottery needs

Concurrent control:

var mu 

func (ls *LotterySystem) Draw() {
    ()
    defer ()
    // ...
}
  • Use mutex locks to ensure thread safety
  • Prevent data competition caused by concurrent lottery

Anti-repetition mechanism:

issuedPrizes map[int]bool
  • Record awards issued using memory map
  • The production environment can be replaced with persistent storage such as Redis

Extended feature suggestions

Probability visualization verification:

// Add test endpoint verification probability distribution("/test", func(w , r *) {
    results := make(map[int]int)
    for i := 0; i < 10000; i++ {
        tempLottery := NewLotterySystem(prizes)
        prize, _ := ()
        results[]++
    }
    (w).Encode(results)
})

Distributed lock extension:

// Use Redis distributed lockfunc (ls *LotterySystem) DistributedDraw() {
    lock := ("lottery_lock")
    err := ()
    // ...Raffle logic...    ()
}

Prize inventory management:

type Prize struct {
    // ...
    Stock     int // Add inventory field}
func (ls *LotterySystem) Draw() {
    // Check inventory    if  <= 0 {
        continue
    }
    // Deduct inventory    --
}

Run the test

Start the service:

go run 

Test draw:

curl http://localhost:8080/draw
# Example return:{"id":3,"name":"Third Prize","weight":20}

Probability verification test:

curl http://localhost:8080/test
# Return to the distribution of the lottery results for tens of thousands of times

Key Optimization Points

Performance optimization:

  • Use pre-calculated total weight values
  • Memory-level lock granularity control
  • Object pool reuse

Security enhancement:

  • JWT User Authentication
  • Lottery frequency limit
  • Sensitive operation log

Business expansion:

  • Support different lottery activities
  • Prize validity period management
  • List of winnings announced

This is the article about the project practice of Go's weight lottery system implementation. For more related Go's weight lottery system content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!