werewolf

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 24, 2025 License: Apache-2.0 Imports: 4 Imported by: 0

README

Werewolf Game Engine

Go Version License

一个纯 Go 实现的狼人杀游戏引擎库。状态机驱动,声明式配置,零外部依赖。

特性

  • 状态机驱动 - 清晰的阶段流转,声明式规则配置
  • 规则可配置 - 女巫自救、守卫连守等规则可自定义
  • 单包设计 - 只需 import "github.com/Zereker/werewolf"
  • 零外部依赖 - 仅使用 Go 标准库
  • 线程安全 - 所有状态操作都有锁保护

安装

go get github.com/Zereker/werewolf

快速开始

package main

import (
    "fmt"

    "github.com/Zereker/werewolf"
    pb "github.com/Zereker/werewolf/proto"
)

func main() {
    // 1. 创建引擎(使用默认配置)
    engine := werewolf.NewEngine(nil)

    // 2. 添加玩家
    engine.AddPlayer("p1", pb.RoleType_ROLE_TYPE_WEREWOLF, pb.Camp_CAMP_EVIL)
    engine.AddPlayer("p2", pb.RoleType_ROLE_TYPE_WEREWOLF, pb.Camp_CAMP_EVIL)
    engine.AddPlayer("p3", pb.RoleType_ROLE_TYPE_SEER, pb.Camp_CAMP_GOOD)
    engine.AddPlayer("p4", pb.RoleType_ROLE_TYPE_WITCH, pb.Camp_CAMP_GOOD)
    engine.AddPlayer("p5", pb.RoleType_ROLE_TYPE_GUARD, pb.Camp_CAMP_GOOD)
    engine.AddPlayer("p6", pb.RoleType_ROLE_TYPE_VILLAGER, pb.Camp_CAMP_GOOD)

    // 3. 开始游戏
    engine.Start()

    // 4. 提交技能使用
    engine.SubmitSkillUse(&werewolf.SkillUse{
        PlayerID: "p1",
        Skill:    pb.SkillType_SKILL_TYPE_KILL,
        TargetID: "p6",
    })

    // 5. 结束阶段,解析技能效果
    effects, _ := engine.EndPhase()

    for _, effect := range effects {
        fmt.Printf("Effect: %v -> %v\n", effect.Type, effect.TargetID)
    }
}

核心概念

Engine(游戏引擎)

轻量级状态机,负责:

  • 管理游戏状态
  • 收集技能使用
  • 驱动阶段流转
  • 判定胜负条件
engine := werewolf.NewEngine(config)
engine.Start()
engine.SubmitSkillUse(use)
effects, _ := engine.EndPhase()
GameConfig(游戏配置)

声明式规则配置:

config := &werewolf.GameConfig{
    WitchCanSaveSelf:     false, // 女巫不能自救
    GuardCanProtectSelf:  true,  // 守卫可以自守
    GuardCanRepeat:       false, // 守卫不能连续守同一人
    SameGuardKillIsEmpty: true,  // 同守同杀是空刀
}
PhaseConfig(阶段配置)

声明式阶段步骤:

nightPhase := &werewolf.PhaseConfig{
    Type: pb.PhaseType_PHASE_TYPE_NIGHT,
    Steps: []werewolf.PhaseStep{
        {Role: pb.RoleType_ROLE_TYPE_GUARD, Skill: pb.SkillType_SKILL_TYPE_PROTECT, Order: 1},
        {Role: pb.RoleType_ROLE_TYPE_WEREWOLF, Skill: pb.SkillType_SKILL_TYPE_KILL, Order: 2, Multiple: true},
        {Role: pb.RoleType_ROLE_TYPE_WITCH, Skill: pb.SkillType_SKILL_TYPE_ANTIDOTE, Order: 3},
        {Role: pb.RoleType_ROLE_TYPE_WITCH, Skill: pb.SkillType_SKILL_TYPE_POISON, Order: 4},
        {Role: pb.RoleType_ROLE_TYPE_SEER, Skill: pb.SkillType_SKILL_TYPE_CHECK, Order: 5},
    },
}
Resolver(冲突解析器)

处理技能冲突的核心逻辑:

  • NightResolver - 夜晚技能解析(守卫保护 > 狼人击杀 > 女巫救人/毒人)
  • VoteResolver - 投票结果解析(统计票数,处理平票)
  • DayResolver - 白天发言(无状态变化)
Effect(效果)

技能执行的结果描述:

type Effect struct {
    Type     EffectType  // Kill, Protect, Save, Poison, Check, Vote, Eliminate
    SourceID string      // 效果来源
    TargetID string      // 效果目标
    Canceled bool        // 是否被取消(如被守卫保护)
    Reason   string      // 取消原因
}

游戏流程

Start → Night → Day → Vote → Night → ... → End
         ↑                      │
         └──────────────────────┘
  1. Night(夜晚) - 狼人杀人、预言家查验、女巫救人/毒人、守卫守护
  2. Day(白天) - 玩家发言讨论
  3. Vote(投票) - 所有玩家投票驱逐

支持的角色

角色 阵营 技能
Werewolf(狼人) 狼人阵营 夜晚杀人
Seer(预言家) 好人阵营 夜晚查验身份
Witch(女巫) 好人阵营 解药救人、毒药杀人
Guard(守卫) 好人阵营 夜晚守护
Hunter(猎人) 好人阵营 死亡时可以开枪
Villager(村民) 好人阵营 无特殊技能

项目结构

werewolf/
├── config.go         # 游戏配置、阶段配置
├── effect.go         # 效果类型定义
├── engine.go         # 核心引擎(状态机)
├── errors.go         # 错误定义
├── phase_manager.go  # 阶段管理器
├── resolver.go       # 冲突解析器
├── state.go          # 游戏状态
├── proto/            # Protobuf 定义
└── docs/             # 文档
    └── ARCHITECTURE.md

架构设计

详见 ARCHITECTURE.md

设计理念:

  • 状态机驱动 - 不是事件驱动,而是显式的阶段流转
  • Phase 为中心 - 阶段决定规则,而非角色
  • 声明式配置 - 规则用数据描述,而非代码

测试

go test ./...

许可证

MIT License. 详见 LICENSE


Made with Go by Zereker

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrPlayerNotFound  = &GameError{Code: pb.ErrorCode_ERROR_CODE_PLAYER_NOT_FOUND, Message: "player not found"}
	ErrPlayerDead      = &GameError{Code: pb.ErrorCode_ERROR_CODE_PLAYER_DEAD, Message: "player is dead"}
	ErrTargetNotFound  = &GameError{Code: pb.ErrorCode_ERROR_CODE_TARGET_NOT_FOUND, Message: "target not found"}
	ErrTargetDead      = &GameError{Code: pb.ErrorCode_ERROR_CODE_TARGET_DEAD, Message: "target is dead"}
	ErrSkillNotAllowed = &GameError{Code: pb.ErrorCode_ERROR_CODE_SKILL_NOT_ALLOWED, Message: "skill not allowed in this phase"}
	ErrGameNotStarted  = &GameError{Code: pb.ErrorCode_ERROR_CODE_GAME_NOT_STARTED, Message: "game not started"}
	ErrGameEnded       = &GameError{Code: pb.ErrorCode_ERROR_CODE_GAME_ENDED, Message: "game has ended"}
	ErrInvalidPhase    = &GameError{Code: pb.ErrorCode_ERROR_CODE_INVALID_PHASE, Message: "invalid phase"}
)

预定义错误

Functions

func GetErrorCode added in v1.0.0

func GetErrorCode(err error) pb.ErrorCode

GetErrorCode 从错误获取错误码

func IsErrorCode added in v1.0.0

func IsErrorCode(err error, code pb.ErrorCode) bool

IsErrorCode 检查错误是否匹配指定错误码

Types

type DayResolver added in v1.0.0

type DayResolver struct{}

DayResolver 白天阶段解析器(主要处理发言,无状态变化)

func NewDayResolver added in v1.0.0

func NewDayResolver() *DayResolver

NewDayResolver 创建白天解析器

func (*DayResolver) Resolve added in v1.0.0

func (r *DayResolver) Resolve(uses []*SkillUse, state *State, config *GameConfig) []*Effect

Resolve 解析白天行动(发言不产生状态变化)

type Effect added in v1.0.0

type Effect struct {
	Type     pb.EventType
	SourceID string                 // 效果来源(玩家ID)
	TargetID string                 // 效果目标(玩家ID)
	Data     map[string]interface{} // 附加数据
	Canceled bool                   // 是否被取消(如被保护)
	Reason   string                 // 取消原因
}

Effect 效果 - 状态变更的描述

func NewEffect added in v1.0.0

func NewEffect(eventType pb.EventType, sourceID, targetID string) *Effect

NewEffect 创建效果

func (*Effect) Cancel added in v1.0.0

func (e *Effect) Cancel(reason string)

Cancel 取消效果

func (*Effect) ToEvent added in v1.0.0

func (e *Effect) ToEvent() *pb.Event

ToEvent 转换为事件(用于通知外部)

func (*Effect) WithData added in v1.0.0

func (e *Effect) WithData(key string, value interface{}) *Effect

WithData 添加附加数据

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine 游戏引擎(轻量状态机)

func NewEngine

func NewEngine(config *GameConfig) *Engine

NewEngine 创建游戏引擎

func (*Engine) AddPlayer

func (e *Engine) AddPlayer(id string, role pb.RoleType, camp pb.Camp)

AddPlayer 添加玩家

func (*Engine) EndPhase added in v1.0.0

func (e *Engine) EndPhase() ([]*Effect, error)

EndPhase 结束当前阶段,解析技能,流转到下一阶段

func (*Engine) EndSubStep added in v1.0.0

func (e *Engine) EndSubStep() ([]*Effect, error)

EndSubStep 结束当前子阶段(子步骤模式) 返回当前子阶段产生的效果

func (*Engine) GetAllowedSkills added in v1.0.0

func (e *Engine) GetAllowedSkills(playerID string) []pb.SkillType

GetAllowedSkills 获取玩家当前可用的技能

func (*Engine) GetCurrentPhase added in v1.0.0

func (e *Engine) GetCurrentPhase() pb.PhaseType

GetCurrentPhase 获取当前阶段

func (*Engine) GetCurrentRound added in v1.0.0

func (e *Engine) GetCurrentRound() int

GetCurrentRound 获取当前回合

func (*Engine) GetCurrentSubStep added in v1.0.0

func (e *Engine) GetCurrentSubStep() int

GetCurrentSubStep 获取当前子步骤

func (*Engine) GetNightKillTarget added in v1.0.0

func (e *Engine) GetNightKillTarget() string

GetNightKillTarget 获取当晚被狼人击杀的目标(女巫可查询)

func (*Engine) GetState

func (e *Engine) GetState() *State

GetState 获取当前游戏状态(只读)

func (*Engine) GetWolfTeammates added in v1.0.0

func (e *Engine) GetWolfTeammates(playerID string) []string

GetWolfTeammates 获取狼人队友

func (*Engine) IsGameOver added in v1.0.0

func (e *Engine) IsGameOver() bool

IsGameOver 游戏是否结束

func (*Engine) OnEvent added in v1.0.0

func (e *Engine) OnEvent(handler EventHandler)

OnEvent 注册事件处理器

func (*Engine) Start

func (e *Engine) Start() error

Start 开始游戏

func (*Engine) StartSubStepMode added in v1.0.0

func (e *Engine) StartSubStepMode() error

StartSubStepMode 启动子步骤模式(从 START 进入第一个子阶段)

func (*Engine) SubmitSkillUse added in v1.0.0

func (e *Engine) SubmitSkillUse(use *SkillUse) error

SubmitSkillUse 提交技能使用

type EventHandler

type EventHandler func(event *pb.Event)

EventHandler 事件处理器

type GameConfig added in v1.0.0

type GameConfig struct {
	// 规则变体
	WitchCanSaveSelf     bool // 女巫能否自救
	GuardCanProtectSelf  bool // 守卫能否自守
	GuardCanRepeat       bool // 守卫能否连续守同一人
	SameGuardKillIsEmpty bool // 同守同杀是否空刀

	// 阶段配置
	Phases map[pb.PhaseType]*PhaseConfig

	// 超时配置
	DefaultTimeout time.Duration
}

GameConfig 游戏配置

func DefaultGameConfig added in v1.0.0

func DefaultGameConfig() *GameConfig

DefaultGameConfig 默认游戏配置

func SubStepGameConfig added in v1.0.0

func SubStepGameConfig() *GameConfig

SubStepGameConfig 子步骤模式的游戏配置

type GameError added in v1.0.0

type GameError struct {
	Code    pb.ErrorCode
	Message string
}

GameError 游戏错误(实现 error 接口)

func NewGameError added in v1.0.0

func NewGameError(code pb.ErrorCode, message string) *GameError

NewGameError 创建游戏错误

func WrapError added in v1.0.0

func WrapError(code pb.ErrorCode, format string, args ...interface{}) *GameError

WrapError 包装错误并添加上下文

func (*GameError) Error added in v1.0.0

func (e *GameError) Error() string

Error 实现 error 接口

type GuardResolver added in v1.0.0

type GuardResolver struct{}

GuardResolver 守卫阶段解析器

func NewGuardResolver added in v1.0.0

func NewGuardResolver() *GuardResolver

func (*GuardResolver) Resolve added in v1.0.0

func (r *GuardResolver) Resolve(uses []*SkillUse, state *State, config *GameConfig) []*Effect

type NightResolver added in v1.0.0

type NightResolver struct{}

NightResolver 夜晚冲突解析器

func NewNightResolver added in v1.0.0

func NewNightResolver() *NightResolver

NewNightResolver 创建夜晚解析器

func (*NightResolver) Resolve added in v1.0.0

func (r *NightResolver) Resolve(uses []*SkillUse, state *State, config *GameConfig) []*Effect

Resolve 解析夜晚技能冲突 规则优先级:

  1. 守卫保护
  2. 狼人击杀
  3. 女巫解药(救人)
  4. 女巫毒药(毒人)
  5. 预言家查验(不产生状态变化)

type Phase added in v1.0.0

type Phase struct {
	// contains filtered or unexported fields
}

Phase 阶段管理器

func NewPhase added in v1.0.0

func NewPhase(config *GameConfig) *Phase

NewPhase 创建阶段管理器

func (*Phase) GetAllowedSkills added in v1.0.0

func (p *Phase) GetAllowedSkills(phase pb.PhaseType, role pb.RoleType) []pb.SkillType

GetAllowedSkills 获取指定角色在当前阶段允许的技能

func (*Phase) GetAllowedSkillsForSubStep added in v1.0.0

func (p *Phase) GetAllowedSkillsForSubStep(phase pb.PhaseType, subStep int, role pb.RoleType) []pb.SkillType

GetAllowedSkillsForSubStep 获取指定角色在当前子步骤允许的技能

func (*Phase) GetCurrentStepRole added in v1.0.0

func (p *Phase) GetCurrentStepRole(phase pb.PhaseType, subStep int) pb.RoleType

GetCurrentStepRole 获取当前子步骤需要行动的角色

func (*Phase) GetPhaseConfig added in v1.0.0

func (p *Phase) GetPhaseConfig(phase pb.PhaseType) *PhaseConfig

GetPhaseConfig 获取阶段配置

func (*Phase) GetRequiredRoles added in v1.0.0

func (p *Phase) GetRequiredRoles(phase pb.PhaseType) []pb.RoleType

GetRequiredRoles 获取当前阶段需要行动的角色

func (*Phase) GetResolver added in v1.0.0

func (p *Phase) GetResolver(phase pb.PhaseType) Resolver

GetResolver 获取阶段解析器

func (*Phase) NextPhase added in v1.0.0

func (p *Phase) NextPhase(current pb.PhaseType) pb.PhaseType

NextPhase 计算下一阶段(批量模式)

func (*Phase) NextSubPhase added in v1.0.0

func (p *Phase) NextSubPhase(current pb.PhaseType) pb.PhaseType

NextSubPhase 计算下一子阶段(子步骤模式)

func (*Phase) ValidateSkillUse added in v1.0.0

func (p *Phase) ValidateSkillUse(use *SkillUse, state *State) error

ValidateSkillUse 验证技能使用是否合法(批量模式,检查整个阶段)

func (*Phase) ValidateSkillUseForSubStep added in v1.0.0

func (p *Phase) ValidateSkillUseForSubStep(use *SkillUse, state *State) error

ValidateSkillUseForSubStep 验证技能使用是否合法(子步骤模式)

type PhaseConfig added in v1.0.0

type PhaseConfig struct {
	Type    pb.PhaseType  // 阶段类型
	Steps   []PhaseStep   // 步骤列表
	Timeout time.Duration // 超时时间
}

PhaseConfig 阶段配置

func NightGuardPhase added in v1.0.0

func NightGuardPhase() *PhaseConfig

NightGuardPhase 守卫阶段配置

func NightSeerPhase added in v1.0.0

func NightSeerPhase() *PhaseConfig

NightSeerPhase 预言家阶段配置

func NightWitchPhase added in v1.0.0

func NightWitchPhase() *PhaseConfig

NightWitchPhase 女巫阶段配置

func NightWolfPhase added in v1.0.0

func NightWolfPhase() *PhaseConfig

NightWolfPhase 狼人阶段配置

func StandardDayPhase added in v1.0.0

func StandardDayPhase() *PhaseConfig

StandardDayPhase 标准白天阶段配置

func StandardNightPhase added in v1.0.0

func StandardNightPhase() *PhaseConfig

StandardNightPhase 标准夜晚阶段配置

func StandardVotePhase added in v1.0.0

func StandardVotePhase() *PhaseConfig

StandardVotePhase 标准投票阶段配置

type PhaseStep added in v1.0.0

type PhaseStep struct {
	Role     pb.RoleType  // 哪个角色
	Skill    pb.SkillType // 使用什么技能
	Order    int          // 执行顺序
	Required bool         // 是否必须行动
	Multiple bool         // 是否允许多个玩家(如多狼)
}

PhaseStep 阶段步骤

type PlayerState

type PlayerState struct {
	ID        string
	Role      pb.RoleType
	Camp      pb.Camp
	Alive     bool
	Protected bool // 本回合是否被保护
}

PlayerState 玩家状态

type Resolver added in v1.0.0

type Resolver interface {
	Resolve(uses []*SkillUse, state *State, config *GameConfig) []*Effect
}

Resolver 冲突解析器接口

type SeerResolver added in v1.0.0

type SeerResolver struct{}

SeerResolver 预言家阶段解析器

func NewSeerResolver added in v1.0.0

func NewSeerResolver() *SeerResolver

func (*SeerResolver) Resolve added in v1.0.0

func (r *SeerResolver) Resolve(uses []*SkillUse, state *State, config *GameConfig) []*Effect

type SkillUse added in v1.0.0

type SkillUse struct {
	PlayerID string
	Skill    pb.SkillType
	TargetID string
	Phase    pb.PhaseType
	Round    int
}

SkillUse 技能使用记录

type State added in v1.0.0

type State struct {
	Phase   pb.PhaseType            // 当前阶段
	SubStep int                     // 当前子步骤(夜晚阶段使用)
	Round   int                     // 当前回合
	Players map[string]*PlayerState // 玩家状态

	// 夜晚临时状态(子步骤间共享)
	NightKillTarget string // 狼人击杀目标(女巫可查询)
	// contains filtered or unexported fields
}

State 游戏状态

func NewState added in v1.0.0

func NewState() *State

NewState 创建游戏状态

func (*State) AddPlayer added in v1.0.0

func (s *State) AddPlayer(id string, role pb.RoleType, camp pb.Camp)

AddPlayer 添加玩家

func (*State) ApplyEffect added in v1.0.0

func (s *State) ApplyEffect(effect *Effect)

ApplyEffect 应用效果

func (*State) CheckVictory added in v1.0.0

func (s *State) CheckVictory() (bool, pb.Camp)

CheckVictory 检查胜利条件

func (*State) GetAlivePlayers added in v1.0.0

func (s *State) GetAlivePlayers() []*PlayerState

GetAlivePlayers 获取存活玩家

func (*State) GetAlivePlayersByCamp added in v1.0.0

func (s *State) GetAlivePlayersByCamp(camp pb.Camp) []*PlayerState

GetAlivePlayersByCamp 获取指定阵营的存活玩家

func (*State) GetAlivePlayersByRole added in v1.0.0

func (s *State) GetAlivePlayersByRole(role pb.RoleType) []*PlayerState

GetAlivePlayersByRole 获取指定角色的存活玩家

func (*State) GetPlayer added in v1.0.0

func (s *State) GetPlayer(id string) (*PlayerState, bool)

GetPlayer 获取玩家

func (*State) GetWolfTeammates added in v1.0.0

func (s *State) GetWolfTeammates(playerID string) []string

GetWolfTeammates 获取狼人队友(不包括自己)

func (*State) NextPhase added in v1.0.0

func (s *State) NextPhase(phase pb.PhaseType)

NextPhase 切换到下一阶段

func (*State) ResetRoundState added in v1.0.0

func (s *State) ResetRoundState()

ResetRoundState 重置回合状态(每回合开始时调用)

type VoteResolver added in v1.0.0

type VoteResolver struct{}

VoteResolver 投票阶段解析器

func NewVoteResolver added in v1.0.0

func NewVoteResolver() *VoteResolver

NewVoteResolver 创建投票解析器

func (*VoteResolver) Resolve added in v1.0.0

func (r *VoteResolver) Resolve(uses []*SkillUse, state *State, config *GameConfig) []*Effect

Resolve 解析投票结果

type WitchResolver added in v1.0.0

type WitchResolver struct{}

WitchResolver 女巫阶段解析器

func NewWitchResolver added in v1.0.0

func NewWitchResolver() *WitchResolver

func (*WitchResolver) Resolve added in v1.0.0

func (r *WitchResolver) Resolve(uses []*SkillUse, state *State, config *GameConfig) []*Effect

type WolfResolver added in v1.0.0

type WolfResolver struct{}

WolfResolver 狼人阶段解析器

func NewWolfResolver added in v1.0.0

func NewWolfResolver() *WolfResolver

func (*WolfResolver) Resolve added in v1.0.0

func (r *WolfResolver) Resolve(uses []*SkillUse, state *State, config *GameConfig) []*Effect

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL