Golang multi-threaded simple fight

Multithreading, channel, read-write lock (single write and multiple read), random (shuffle) are the main knowledge points involved in this article.

Let’s take a look at the results. Because it is an experimental procedure, there is still a gap with the real landlord. Long live the understanding!

[Dealer]: Shuffle the cards.
Swipe...
[ Dealer ]: The cards are shuffled.
[Dealer]: Start the deal.
[Dealer]: 17 cards per person.
[Dealer]: Grab the landlord.
[fang]: Haha, I am a landlord!
Fang's hand is [♣9 ♦9 ♥A ♠9 ♣6 ♣5 ♦3 ♣10 ♥5 ♣8 ♠Q ♠A ♠8 ♦4 ♥4 ♦K ♥7 ♣A ♠K ♥3], a total of 20 .
Dong's card is [大王 ♦8 ♠5 Xiao Wang♠6 ♣Q ♠10 ♣7 ♠3 ♦A ♦Q ♥J ♣K ♥6 ♥9 ♥Q ♣2], a total of 17 cards.
er's card is [♣A ♠K ♥3 ♥2 ♠4 ♦2 ♦5 ♥K ♦10 ♠2 ♥8 ♦6 ♣4 ♦J ♣3 ♣J ♠7], a total of 17 cards.
[fang]: I started playing cards.
[er]: I started playing cards.
[dong]: I started playing cards.
The winner is er.
The basic process is shuffle -> deal -> grab the landlord -> play cards ->gg.

Haha, the essence of this program is that because there is a (xie) limit (le) in the time (lan) (de), which thread of the card game grabs it, it will play the card, until the card is out, it will win. (Multi-threaded writing Doudizhu is an experimental project of my university’s operating system course. At that time, the Doudizhu algorithm was completely implemented, using C++ and MFC, and you can play cards interactively on the interface)

Look at the code changes.

Main function

func main() { // Shuffle cards := shuffle() // Deal cards dealCards := deal(cards) // Landlord fmt.Println("[Dealer]: Landlord.") go player(order [0], dealCards[0]) go player(order[1], dealCards[1]) go player(order[2], dealCards[2]) // Winner winner := <-winner fmt.Printf("Winner It is %s.\n”, winner) } Analysis:













1. Main is the steps of playing cards, shuffle, deal, grab landlords, play cards, gg.
2. With go player(), 3 threads are opened, that is, 3 players.
3. When the cards are dealt, there are 3 hole cards left, which are stored in the channel "bottom". When the landlord is grabbed, the 3 threads will take it. Whoever gets it first is the landlord.
4. At the end of the card game, the value will be written into the other channel "winner". Whoever finishes the game first will save his name.
5.3 When a player is playing cards, the main is blocked, waiting to read the value from the channel "winner". After a player has finished playing, the channel "winner" has a value, and it is activated.
Shuffle function

func shuffle() []string { fmt.Println("[Dealer]: Shuffle the cards.") fmt.Println("Swipe...") cards := cards() rand.Seed(time.Now( ).UnixNano()) rand.Shuffle(len(cards), func(i, j int) { cards[i], cards[j] = cards[j], cards[i] }) fmt.Println("[ Dealer]: The cards are shuffled.")







return cards

}
Analysis:

1. Rand is false random by default, because it is the same no matter how many times it runs. You need to set the seed, time.Now().UnixNano(), so that each random result is different.
2.rand.Shuffle() shuffles the cards and exchanges the positions of 2 cards randomly.
Dealing function

func deal(cards []string) [][]string { fmt.Println("[Dealer]: Start dealing cards.") var dealCards [][]string dealCards = append(dealCards, cards[0:17] ) dealCards = append(dealCards, cards[17:34]) dealCards = append(dealCards, cards[34:51]) fmt.Println("[Dealer]: 17 cards per person.")





go leaveBottom(cards[51:54])

return dealCards

}
Analysis:

1. Because the cards have been shuffled, directly cut 3 cards out first, each with 17 cards.
2. Leave 3 hole cards and put them in the channel "bottom".
3. If the thread is no longer opened here, a deadlock will occur! Because main itself is also a thread, if you directly store the channel, it will block main until a thread reads out the value of the channel; and after main is blocked, the subsequent code cannot be executed, and three more player threads cannot be started. Once the value is read, a deadlock will occur.
4. So leaveBottom() starts a separate thread.
Desk table

type Desk struct {
mutex sync.RWMutex
playCards []string
}

func (d *Desk) write(card string) {
d.mutex.Lock()
defer d.mutex.Unlock()
d.playCards = append(d.playCards, card)
}

func (d *Desk) read() []string {
d.mutex.RLock()
defer d.mutex.RUnlock()
return d.playCards
}
解析:

1. The Desk structure is defined, including the read-write lock and the cards played on the table.
2. Two functions of write() and read() are defined. Three threads can read at the same time, but they can only write once, that is, single write and multiple read locks.
player function

func player(name string, hands []string) { landlord := <-bottom if len(landlord)> 0 { fmt.Printf("[%s]: Haha, I am the landlord!\n", name) hands = append(hands, landlord…) desk.write(name) } fmt.Printf("%s's card is %s, a total of %d cards.\n", name, hands, len(hands))






time.Sleep(time.Second)

i := 0
for true {
	playCards := desk.read()
	if playCards[len(playCards)-1] == name {
		if i == 1 {
			fmt.Printf("[%s]:我开始出牌了。\n", name)
		}
		desk.write(hands[i])
		desk.write(order[(getOrderID(name)+1)%3])
		i += 1
		if i == len(hands) {
			winner <- name
			break
		}
	}
}

}
Amazon evaluation www.yisuping.com

Guess you like

Origin blog.csdn.net/weixin_45032957/article/details/108599378