Skip to content

Instantly share code, notes, and snippets.

@alairock
Created February 6, 2024 05:22
Show Gist options
  • Save alairock/68e3789f47211a7c0b4db519a6f62a7e to your computer and use it in GitHub Desktop.
Save alairock/68e3789f47211a7c0b4db519a6f62a7e to your computer and use it in GitHub Desktop.
Secret Hitler Night Phase Code
package sh
import (
"errors"
"math/rand"
)
type Game struct{}
type GameState struct {
IsHitler bool
IsFascist bool
OtherFascists []string
HitlerID string
}
// create error with name ErrInvalidNumberOfPlayers
var ErrInvalidNumberOfPlayers = errors.New("invalid number of players")
func (g Game) Night(users []string) (map[string]*GameState, error) {
if len(users) < 5 || len(users) > 10 {
return nil, ErrInvalidNumberOfPlayers
}
userStates := make(map[string]*GameState)
// Shuffle the list
rand.Shuffle(len(users), func(i, j int) {
users[i], users[j] = users[j], users[i]
})
numberOfFascists := 1
if len(users) >= 7 && len(users) <= 10 {
numberOfFascists = len(users) / 3
}
// assign roles to each user
fascistIds := make([]string, 0)
for i, user := range users {
state := &GameState{IsHitler: false, IsFascist: false, OtherFascists: []string{}, HitlerID: ""}
if i < numberOfFascists {
state.IsFascist = true
fascistIds = append(fascistIds, user)
} else if i == numberOfFascists {
state.IsHitler = true
state.IsFascist = true
}
userStates[user] = state
}
// if there are only 5 or 6 players, then we let hitler know who the other fascists are
if len(users) == 5 || len(users) == 6 {
userStates[users[numberOfFascists]].OtherFascists = fascistIds
}
// Now we let the fascists know who eachother and hitler are. (This is the rule for all games with 5-10 players.)
for i := 0; i < len(fascistIds); i++ {
userStates[fascistIds[i]].OtherFascists = fascistIds
userStates[fascistIds[i]].HitlerID = users[numberOfFascists]
}
return userStates, nil
}
package sh
import (
"testing"
)
func TestGame_Night(t *testing.T) {
game := Game{}
users := []string{"ZAlice", "Bob", "Charlie", "Diana"}
_, err := game.Night(users)
if err != nil {
if err != ErrInvalidNumberOfPlayers {
t.Errorf("Expected error to be ErrInvalidNumberOfPlayers, got %v", err)
}
}
users = []string{"ZAlice", "Bob", "Charlie", "Diana", "Eve", "Frank", "Grace", "Hannah", "Ivan", "Jack", "Katie"}
_, err = game.Night(users)
if err != nil {
if err != ErrInvalidNumberOfPlayers {
t.Errorf("Expected error to be ErrInvalidNumberOfPlayers, got %v", err)
}
}
// 5 users
users = []string{"Alice", "Bob", "Charlie", "Diana", "Eve"}
AssertFascistsAndHitler(t, users, 1, 1)
// 6 users
users = []string{"Alice", "Bob", "Charlie", "Diana", "Eve", "Frank"}
AssertFascistsAndHitler(t, users, 1, 1)
// 7 users
users = []string{"Alice", "Bob", "Charlie", "Diana", "Eve", "Frank", "Grace"}
AssertFascistsAndHitler(t, users, 2, 1)
// 8 users
users = []string{"Alice", "Bob", "Charlie", "Diana", "Eve", "Frank", "Grace", "Hannah"}
AssertFascistsAndHitler(t, users, 2, 1)
// 9 users
users = []string{"Alice", "Bob", "Charlie", "Diana", "Eve", "Frank", "Grace", "Hannah", "Ivan"}
AssertFascistsAndHitler(t, users, 3, 1)
// 10 users
users = []string{"Alice", "Bob", "Charlie", "Diana", "Eve", "Frank", "Grace", "Hannah", "Ivan", "Jack"}
AssertFascistsAndHitler(t, users, 3, 1)
}
func AssertFascistsAndHitler(t *testing.T, users []string, expectedFascists int, expectedHitler int) {
game := Game{}
states, err := game.Night(users)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
// Test for correct number of fascists and Hitler
fascistsCount := 0
hitlerCount := 0
for _, state := range states {
if state.IsFascist && !state.IsHitler {
fascistsCount++
}
if state.IsHitler {
hitlerCount++
}
}
if fascistsCount != expectedFascists {
t.Errorf("Expected %d fascists, got %d", expectedFascists, fascistsCount)
}
if hitlerCount != expectedHitler {
t.Errorf("Expected 1 Hitler, got %d", hitlerCount)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment