lugo4go

package module
v2.0.0 Latest Latest
Warning

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

Go to latest
Published: Jul 14, 2023 License: GPL-3.0 Imports: 10 Imported by: 2

README

Lugo4Go - A Lugo Bots Client

Build Status GoDoc Go Report Card

Lugo4Go is a Go implementation of a client player for Lugo game.

It is not a bot that plays the game, it is only the client for the game server.

This client implements a brainless player in the game. So, this library implements many methods that does not affect the player intelligence/behaviour/decisions. It is meant to reduce the developer concerns on communication, protocols, attributes, etc.

Using this client, you just need to implement the Artificial Intelligence of your player and some other few methods to support your strategy (see the project The Dummies as an example).

Documentation

(usage examples below)

Requirements
Installation
git get https://github.com/lugobots/lugo4go.git
Usage

There are two ways to use Lugo4Go client:

See example

Lugo4Go PlayAsBot implements a very basic logic to reduce the code boilerplate. This client will wrap most repetitive code that handles the raw data got by the bot and will identify the player state.

The Bot interface requires the methods to handle each player state based on the ball possession.


type Bot struct {
	
}

// OnDisputing is called when no one has the ball possession
func (b *Bot) OnDisputing(ctx context.Context, sender lugo4go.TurnOrdersSender, snapshot *proto.GameSnapshot) error {
	// the magic code comes here
	return ...
}

// OnDefending is called when an opponent player has the ball possession
func (b *Bot) OnDefending(ctx context.Context, sender lugo4go.TurnOrdersSender, snapshot *proto.GameSnapshot) error {
	// the magic code comes here
	return ...
}

// OnHolding is called when this bot has the ball possession
func (b *Bot) OnHolding(ctx context.Context, sender lugo4go.TurnOrdersSender, snapshot *proto.GameSnapshot) error {
	// the magic code comes here
	return ...
}

// OnSupporting is called when a teammate player has the ball possession
func (b *Bot) OnSupporting(ctx context.Context, sender lugo4go.TurnOrdersSender, snapshot *proto.GameSnapshot) error {
	// the magic code comes here
	return ...
}

// AsGoalkeeper is only called when this bot is the goalkeeper (number 1). This method is called on every turn,
// and the player state is passed at the last parameter.
func (b *Bot) AsGoalkeeper(ctx context.Context, sender lugo4go.TurnOrdersSender, snapshot *proto.GameSnapshot, state lugo4go.PlayerState) error {
	// the magic code comes here
	return ...
}
Implementing the turn handler (a little more work)

See example

If you rather to handle everything on your side, you only need to implement the TurnHandler interface.

The TurnHandler will receive the turn context and the turn snapshot for each turn.

Your bot will need a lugo4go.OrderSender to send the orders back to the Game Server during each turn.


type Bot struct {
    OrderSender lugo4go.OrderSender
}

func (b *Bot) Handle(ctx context.Context, snapshot *proto.GameSnapshot) {
	// the magic code comes here
	resp, err := b.OrderSender.Send(ctx, snapshot.Turn, orders, "")
}

Kick-start

  1. Copy one of the examples from the example directory as a new Golang project.

  2. Run the game server using the command

    docker run -p 8080:8080  lugobots/server:v1.1 play --dev-mode
    
  3. Now you will need to start your team processes. Each team must have 11 process (one for each player).

    Option A: You may start your team players manually executing the command go run main.go -team=home -number=[1-11] eleven times.

    or

    Option B: You can use the script in examples directory to do this automatically for you: ./play.sh home

  4. And, if your have not started the away team, you may do the same for the other team.

    You play against your own team repeating the last step, but in the away side:

    ./play.sh away
    
Next steps

As you may have noticed, the bot player in the example directory does not play well. Now, you may start your bot by implementing its behaviour.

Deploying you bots

After developing your bot, you may share it with other developers.

Please find the instructions for uploading your bot on lugobots.dev.

There is a Dockerfile template in the example directory to guide you how to create a container.

Field Library

There are a many things that you will repeatedly need to do on your bot code, e.g. getting your bot position, creating a move/kick/catch order, finding your teammates positions, etc.

The Field library brings a collection of functions that will help you get that data from the game snapshot:

Examples (see all functions on the documentation page)


myTeamGoal := field.GetTeamsGoal(proto.Team_HOME)

moveOrder, err := field.MakeOrderMoveMaxSpeed(*me.Position, myTeamGoal)

Mapper and Region

The Field library also provides a quite useful pair: the Mapper interface and Region struct.

The Mapper

Mapper slices the field in columns and rows, so your bot does not have to care about precise coordinates or the team side. The mapper will automatically translate the map position to the bot side.

And you may define how many columns/rows your field will be divided into.


// let's create a map 10x5 
fieldMapper, err := field.NewMapper(10, 5, proto.Team_HOME)

aRegion, err := fieldMapper.GetRegion(2, 4)

The Region

The Mapper will slice the field into Regions. The Region struct helps your bot to move over the field without caring about coordinates or team side.


regionInFrontOfMe _:= aRegion.Front()

moveOrder, err_ := field.MakeOrderMoveMaxSpeed(*me.Position, regionInFrontOfMe.Center())

Documentation

Index

Constants

View Source
const (
	// ErrGRPCConnectionClosed identifies when the error returned is cased by the connection has been closed
	ErrGRPCConnectionClosed = Error("grpc connection closed by the server")

	// ErrGRPCConnectionLost identifies that something unexpected broke the gRPC connection
	ErrGRPCConnectionLost = Error("grpc stream error")
)
View Source
const (
	ErrNilSnapshot    = Error("invalid snapshot state (nil)")
	ErrPlayerNotFound = Error("player not found in the game snapshot")
	ErrNoBall         = Error("no ball found in the snapshot")
)
View Source
const ProtocolVersion = "0.0.1"

ProtocolVersion defines the current game protocol

Variables

This section is empty.

Functions

This section is empty.

Types

type Bot

type Bot interface {
	// OnDisputing is called when no one has the ball possession
	OnDisputing(ctx context.Context, sender TurnOrdersSender, snapshot *proto.GameSnapshot) error
	// OnDefending is called when an opponent player has the ball possession
	OnDefending(ctx context.Context, sender TurnOrdersSender, snapshot *proto.GameSnapshot) error
	// OnHolding is called when this bot has the ball possession
	OnHolding(ctx context.Context, sender TurnOrdersSender, snapshot *proto.GameSnapshot) error
	// OnSupporting is called when a teammate player has the ball possession
	OnSupporting(ctx context.Context, sender TurnOrdersSender, snapshot *proto.GameSnapshot) error
	// AsGoalkeeper is only called when this bot is the goalkeeper (number 1). This method is called on every turn,
	// and the player state is passed at the last parameter.
	AsGoalkeeper(ctx context.Context, sender TurnOrdersSender, snapshot *proto.GameSnapshot, state PlayerState) error
}

type Client

type Client struct {
	Stream     proto.Game_JoinATeamClient
	GRPCClient proto.GameClient

	Handler TurnHandler
	Logger  Logger
	// contains filtered or unexported fields
}

Client handle the gRPC stuff and provide you an easy way to handle the game messages

func NewClient

func NewClient(config util.Config) (*Client, error)

NewClient creates a Lugo4Go client that will hide common logic and let you focus on your bot.

func (*Client) HandleConn

func (c *Client) HandleConn(_ context.Context, sts stats.ConnStats)

HandleConn implements the interface required by gRPC handler

func (*Client) HandleRPC

func (c *Client) HandleRPC(context.Context, stats.RPCStats)

HandleRPC implements the interface required by gRPC handler

func (*Client) Play

func (c *Client) Play(handler TurnHandler) error

Play starts the player communication with the server. The TurnHandler will receive the raw snapshot from the game server. The context passed to the handler will be canceled as soon a new turn starts.

func (*Client) PlayAsBot

func (c *Client) PlayAsBot(bot Bot, logger Logger) error

PlayAsBot is a sugared Play mode that uses an TurnHandler from coach package. Coach TurnHandler creates basic player states to help the development of new bots.

func (*Client) Stop

func (c *Client) Stop() error

Stop drops the communication with the gRPC server.

func (*Client) TagConn

func (c *Client) TagConn(ctx context.Context, _ *stats.ConnTagInfo) context.Context

TagConn implements the interface required by gRPC handler

func (*Client) TagRPC

func (c *Client) TagRPC(ctx context.Context, _ *stats.RPCTagInfo) context.Context

TagRPC implements the interface required by gRPC handler

type Error

type Error string

Error is used to identify internal errors

func (Error) Error

func (e Error) Error() string

Error implements the native golang error interface

type Handler

type Handler struct {
	Logger       Logger
	Sender       OrderSender
	PlayerNumber uint32
	Side         proto.Team_Side
	Bot          Bot
}

Handler is a Lugo4go client handler that allow you to create an interface to follow a basic strategy based on team states.

func NewHandler

func NewHandler(bot Bot, sender OrderSender, logger Logger, playerNumber uint32, side proto.Team_Side) *Handler

func (*Handler) Handle

func (h *Handler) Handle(ctx context.Context, snapshot *proto.GameSnapshot)

type Logger

type Logger interface {
	Debug(args ...interface{})
	Debugf(template string, args ...interface{})
	Infof(template string, args ...interface{})
	Warnf(template string, args ...interface{})
	Errorf(template string, args ...interface{})
	Fatalf(template string, args ...interface{})
}

type OrderSender

type OrderSender interface {
	Send(ctx context.Context, turn uint32, orders []proto.PlayerOrder, debugMsg string) (*proto.OrderResponse, error)
}

type PlayerState

type PlayerState string

PlayerState defines states specific for players

const (
	// Supporting identifies the player supporting the teammate
	Supporting PlayerState = "supporting"
	// HoldingTheBall identifies the player holding	the ball
	HoldingTheBall PlayerState = "holding"
	// Defending identifies the player defending against the opponent team
	Defending PlayerState = "defending"
	// DisputingTheBall identifies the player disputing the ball
	DisputingTheBall PlayerState = "disputing"
)

func DefineMyState

func DefineMyState(snapshot *proto.GameSnapshot, playerNumber uint32, side proto.Team_Side) (PlayerState, error)

type Sender

type Sender struct {
	GRPCClient proto.GameClient
}

func NewSender

func NewSender(grpcClient proto.GameClient) *Sender

func (*Sender) Send

func (s *Sender) Send(ctx context.Context, turn uint32, orders []proto.PlayerOrder, debugMsg string) (*proto.OrderResponse, error)

type TurnData

type TurnData struct {
	Me       *proto.Player
	Snapshot *proto.GameSnapshot
}

type TurnHandler

type TurnHandler interface {

	// Handle is called every turn with the new game state
	Handle(ctx context.Context, snapshot *proto.GameSnapshot)
}

TurnHandler is required by the Lugo4Go client to handle each turn snapshot

type TurnOrdersSender

type TurnOrdersSender interface {
	Send(ctx context.Context, orders []proto.PlayerOrder, debugMsg string) (*proto.OrderResponse, error)
}

Directories

Path Synopsis
examples
pkg
geo

Jump to

Keyboard shortcuts

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