feat: smarter bot
This commit is contained in:
+85
-28
@@ -36,10 +36,11 @@ func botChooseTrump(hand []game.Card) game.Suit {
|
||||
return best
|
||||
}
|
||||
|
||||
// botPlay کارتی که بات باید بازی کند را برمیگرداند.
|
||||
func botPlay(hand []game.Card, trick []game.TrickCard, trump, lead game.Suit) game.Card {
|
||||
// botPlay کارتی که بات باید بازی کند را برمیگرداند. seen حافظهی کارتهای
|
||||
// بازیشدهی این هَند است (کارتشماری برای تصمیمِ بهتر).
|
||||
func botPlay(hand []game.Card, trick []game.TrickCard, trump, lead game.Suit, seen [4]uint16) game.Card {
|
||||
if len(trick) == 0 {
|
||||
return botLead(hand, trump)
|
||||
return botLead(hand, trump, seen)
|
||||
}
|
||||
|
||||
best := trickBest(trick, trump, lead)
|
||||
@@ -72,41 +73,97 @@ func botPlay(hand []game.Card, trick []game.TrickCard, trump, lead game.Suit) ga
|
||||
return lowestDiscard(hand, trump) // حکمت هم نمیبرد ⇒ دورریز
|
||||
}
|
||||
|
||||
// botLead راهبردِ رهبریِ دست: آسِ غیرِحکم را نقد کن؛ وگرنه از بلندترین خالِ
|
||||
// غیرِحکم کارتِ کم بریز؛ اگر فقط حکم داری، بالاترین حکم را بزن تا حکمها را بکشی.
|
||||
func botLead(hand []game.Card, trump game.Suit) game.Card {
|
||||
// آسِ غیرِحکم (برندهی تقریباً قطعی).
|
||||
var ace *game.Card
|
||||
for i := range hand {
|
||||
if hand[i].Suit != trump && hand[i].Rank == game.Ace {
|
||||
c := hand[i]
|
||||
ace = &c
|
||||
break
|
||||
}
|
||||
}
|
||||
if ace != nil {
|
||||
return *ace
|
||||
}
|
||||
// botLead راهبردِ رهبریِ دست با کارتشماری:
|
||||
// ۱. کارتِ «برندهی قطعی» (بالاترین کارتِ باقیماندهی یک خالِ غیرِحکم) را نقد کن.
|
||||
// ۲. اگر کنترلِ حکم داری (بالاترین حکمِ باقیمانده + ۳ حکم یا بیشتر) حکم بکِش.
|
||||
// ۳. وگرنه از کوتاهترین خالِ غیرِحکم کارتِ کم بریز تا زود void شوی و بعداً بِبُری
|
||||
// (اگر حکم داری)؛ در نبودِ حکم از بلندترین خال کارتِ کم.
|
||||
func botLead(hand []game.Card, trump game.Suit, seen [4]uint16) game.Card {
|
||||
counts := suitCounts(hand)
|
||||
|
||||
// بلندترین خالِ غیرِحکم.
|
||||
var counts [4]int
|
||||
for _, c := range hand {
|
||||
counts[c.Suit]++
|
||||
}
|
||||
bestSuit, bestLen := game.Suit(255), -1
|
||||
for _, c := range hand {
|
||||
// ۱. برندهی قطعی: کارتی از خالِ غیرِحکم که هیچ کارتِ بالاتری از آن بیرون نمانده.
|
||||
var boss *game.Card
|
||||
for i := range hand {
|
||||
c := hand[i]
|
||||
if c.Suit == trump {
|
||||
continue
|
||||
}
|
||||
if counts[c.Suit] > bestLen {
|
||||
bestLen, bestSuit = counts[c.Suit], c.Suit
|
||||
if higherOut(seen, hand, c.Suit, c.Rank) == 0 {
|
||||
if boss == nil || counts[c.Suit] > counts[boss.Suit] ||
|
||||
(counts[c.Suit] == counts[boss.Suit] && c.Rank > boss.Rank) {
|
||||
cc := c
|
||||
boss = &cc
|
||||
}
|
||||
}
|
||||
}
|
||||
if boss != nil {
|
||||
return *boss
|
||||
}
|
||||
|
||||
// ۲. کشیدنِ حکم: اگر بالاترین حکمِ باقیمانده دستِ ماست و حکمِ زیاد داریم.
|
||||
trumps := cardsOfSuit(hand, trump)
|
||||
if len(trumps) >= 3 {
|
||||
top := highest(trumps)
|
||||
if higherOut(seen, hand, trump, top.Rank) == 0 {
|
||||
return top
|
||||
}
|
||||
}
|
||||
|
||||
// ۳. کوتاهترین خالِ غیرِحکم (برای void شدن) اگر حکم داریم؛ وگرنه بلندترین.
|
||||
haveTrump := len(trumps) > 0
|
||||
bestSuit, bestLen := game.Suit(255), -1
|
||||
for s := game.Suit(0); s < 4; s++ {
|
||||
if s == trump || counts[s] == 0 {
|
||||
continue
|
||||
}
|
||||
better := false
|
||||
if bestLen < 0 {
|
||||
better = true
|
||||
} else if haveTrump {
|
||||
better = counts[s] < bestLen // کوتاهترین
|
||||
} else {
|
||||
better = counts[s] > bestLen // بلندترین
|
||||
}
|
||||
if better {
|
||||
bestLen, bestSuit = counts[s], s
|
||||
}
|
||||
}
|
||||
if bestSuit != game.Suit(255) {
|
||||
return lowest(cardsOfSuit(hand, bestSuit))
|
||||
}
|
||||
// فقط حکم مانده ⇒ بالاترین حکم را بزن.
|
||||
return highest(cardsOfSuit(hand, trump))
|
||||
return highest(trumps)
|
||||
}
|
||||
|
||||
// suitCounts تعدادِ کارتِ هر خال در دست.
|
||||
func suitCounts(hand []game.Card) [4]int {
|
||||
var c [4]int
|
||||
for _, x := range hand {
|
||||
c[x.Suit]++
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// higherOut تعدادِ کارتهای همخالِ بالاتر از rank که هنوز بازی نشدهاند و در دستِ
|
||||
// خودِ بات هم نیستند (یعنی دستِ حریف/شریکاند). ۰ یعنی این کارت «برندهی خال» است.
|
||||
func higherOut(seen [4]uint16, hand []game.Card, suit game.Suit, rank game.Rank) int {
|
||||
n := 0
|
||||
for r := rank + 1; r <= game.Ace; r++ {
|
||||
if seen[suit]&(1<<(r-2)) != 0 {
|
||||
continue // بازی شده
|
||||
}
|
||||
held := false
|
||||
for _, c := range hand {
|
||||
if c.Suit == suit && c.Rank == r {
|
||||
held = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !held {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// --- کمکیها ---
|
||||
|
||||
Reference in New Issue
Block a user