<commit_before>package apple

import (
	"fmt"
	"sync"

	"github.com/pquerna/ffjson/ffjson"

	"github.com/ivan1993spb/snake-server/engine"
	"github.com/ivan1993spb/snake-server/world"
)

type Apple struct {
	world    *world.World
	location engine.Location
	mux      *sync.RWMutex
}

type ErrCreateApple string

func (e ErrCreateApple) Error() string {
	return "cannot create apple: " + string(e)
}

// NewApple creates and locates new apple
func NewApple(world *world.World) (*Apple, error) {
	apple := &Apple{
		mux: &sync.RWMutex{},
	}

	location, err := world.CreateObjectRandomDot(apple)
	if err != nil {
		return nil, ErrCreateApple(err.Error())
	}

	apple.mux.Lock()
	apple.location = location
	apple.world = world
	apple.mux.Unlock()

	return apple, nil
}

func (a *Apple) String() string {
	a.mux.RLock()
	defer a.mux.RUnlock()
	return fmt.Sprintf("apple %s", a.location)
}

func (a *Apple) NutritionalValue(dot engine.Dot) uint16 {
	a.mux.RLock()
	defer a.mux.RUnlock()

	if a.location.Equals(engine.Location{dot}) {
		// TODO: Handle error.
		a.world.DeleteObject(a, a.location)
		return 1
	}

	return 0
}

func (a *Apple) MarshalJSON() ([]byte, error) {
	a.mux.RLock()
	defer a.mux.RUnlock()
	return ffjson.Marshal(a.location)
}<commit_msg>Refactor apple. Create valid apple json marshaling<commit_after>package apple

import (
	"fmt"
	"sync"

	"github.com/pquerna/ffjson/ffjson"
	"github.com/satori/go.uuid"

	"github.com/ivan1993spb/snake-server/engine"
	"github.com/ivan1993spb/snake-server/world"
)

type Apple struct {
	uuid  string
	world *world.World
	dot   engine.Dot
	mux   *sync.RWMutex
}

type ErrCreateApple string

func (e ErrCreateApple) Error() string {
	return "cannot create apple: " + string(e)
}

// NewApple creates and locates new apple
func NewApple(world *world.World) (*Apple, error) {
	apple := &Apple{
		uuid: uuid.Must(uuid.NewV4()).String(),
		mux:  &sync.RWMutex{},
	}

	location, err := world.CreateObjectRandomDot(apple)
	if err != nil {
		return nil, ErrCreateApple(err.Error())
	}
	if len(location) == 0 {
		return nil, ErrCreateApple("created empty location")
	}

	apple.mux.Lock()
	apple.dot = location.Dot(0)
	apple.world = world
	apple.mux.Unlock()

	return apple, nil
}

func (a *Apple) String() string {
	a.mux.RLock()
	defer a.mux.RUnlock()
	return fmt.Sprintf("apple %s", a.dot)
}

func (a *Apple) NutritionalValue(dot engine.Dot) uint16 {
	a.mux.RLock()
	defer a.mux.RUnlock()

	if a.dot.Equals(dot) {
		// TODO: Handle error?
		a.world.DeleteObject(a, engine.Location{a.dot})
		return 1
	}

	return 0
}

func (a *Apple) MarshalJSON() ([]byte, error) {
	a.mux.RLock()
	defer a.mux.RUnlock()
	return ffjson.Marshal(&apple{
		UUID: a.uuid,
		Dot:  a.dot,
		Type: "apple",
	})
}

type apple struct {
	UUID string     `json:"uuid"`
	Dot  engine.Dot `json:"dot"`
	Type string     `json:"type"`
}
{'fraction_non_alphanumeric': 0.1498944405348346, 'fraction_numerical': 0.009500351864883884, 'mean_word_length': 3.876500857632933, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '199989', 'n_tokens_mistral': 1142, 'n_tokens_neox': 1076, 'n_words': 251}