<commit_before>// Copyright 2013 com authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package com

import (
	"archive/tar"
	"archive/zip"
	"compress/gzip"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
)

// get filepath base name
func Basename(file string) string {
	return path.Base(file)
}

// get filepath dir name
func Dirname(file string) string {
	return path.Dir(file)
}

// get absolute filepath, based on built excutable file
func RealPath(file string) (string, error) {
	if path.IsAbs(file) {
		return file, nil
	}
	wd, err := os.Getwd()
	return path.Join(wd, file), err
}

// get file modified time
func FileMTime(file string) (int64, error) {
	f, e := os.Stat(file)
	if e != nil {
		return 0, e
	}
	return f.ModTime().Unix(), nil
}

// get file size as how many bytes
func FileSize(file string) (int64, error) {
	f, e := os.Stat(file)
	if e != nil {
		return 0, e
	}
	return f.Size(), nil
}

// copy file to new path
func Copy(file string, to string) (bool, error) {
	sf, e := os.Open(file)
	if e != nil {
		return false, e
	}
	defer sf.Close()
	df, e2 := os.Create(to)
	if e2 != nil {
		return false, e2
	}
	defer df.Close()
	// buffer reader, do chunk transfer
	buf := make([]byte, 1024)
	for {
		// read a chunk
		n, err := sf.Read(buf)
		if err != nil && err != io.EOF {
			return false, err
		}
		if n == 0 {
			break
		}
		// write a chunk
		if _, err := df.Write(buf[:n]); err != nil {
			return false, err
		}
	}
	return true, nil
}

// move file to new path
func Move(file string, to string) (bool, error) {
	// copy
	r, e := Copy(file, to)
	if e != nil {
		return r, e
	}
	// then remove
	e = os.Remove(file)
	if e != nil {
		r = false
	}
	return r, e
}

// delete file
func Unlink(file string) error {
	return os.Remove(file)
}

// rename file name
func Rename(file string, to string) error {
	return os.Rename(file, to)
}

// IsFile checks whether the path is a file,
// it returns false when it's a directory or does not exist.
func IsFile(filePath string) bool {
	f, e := os.Stat(filePath)
	if e != nil {
		return false
	}
	return !f.IsDir()
}

// IsExist returns whether a file or directory exists.
func IsExist(path string) bool {
	_, err := os.Stat(path)
	return err == nil || os.IsExist(err)
}

// SaveFile saves content type '[]byte' to file by given path.
// It returns error when fail to finish operation.
func SaveFile(filePath string, b []byte) (int, error) {
	os.MkdirAll(path.Dir(filePath), os.ModePerm)
	fw, err := os.Create(filePath)
	if err != nil {
		return 0, err
	}
	defer fw.Close()
	return fw.Write(b)
}

// SaveFileS saves content type 'string' to file by given path.
// It returns error when fail to finish operation.
func SaveFileS(filePath string, s string) (int, error) {
	return SaveFile(filePath, []byte(s))
}

// ReadFile reads data type '[]byte' from file by given path.
// It returns error when fail to finish operation.
func ReadFile(filePath string) ([]byte, error) {
	b, err := ioutil.ReadFile(filePath)
	if err != nil {
		return []byte(""), err
	}
	return b, nil
}

// ReadFileS reads data type 'string' from file by given path.
// It returns error when fail to finish operation.
func ReadFileS(filePath string) (string, error) {
	b, err := ReadFile(filePath)
	return string(b), err
}

// Unzip unzips .zip file to 'destPath' and returns sub-directories.
// It returns error when fail to finish operation.
func Unzip(srcPath, destPath string) ([]string, error) {
	// Open a zip archive for reading
	r, err := zip.OpenReader(srcPath)
	if err != nil {
		return nil, err
	}
	defer r.Close()

	dirs := make([]string, 0, 5)
	// Iterate through the files in the archive
	for _, f := range r.File {
		// Get files from archive
		rc, err := f.Open()
		if err != nil {
			return nil, err
		}

		fn := strings.TrimSuffix(f.FileInfo().Name(), "/")
		dir := path.Dir(fn)
		// Create diretory before create file
		os.MkdirAll(destPath+"/"+dir, os.ModePerm)
		dirs = AppendStr(dirs, dir)

		// Write data to file
		fw, _ := os.Create(destPath + "/" + fn)
		if err != nil {
			return nil, err
		}
		_, err = io.Copy(fw, rc)
		fw.Close()
		if err != nil {
			return nil, err
		}
	}
	return dirs, nil
}

// UnTarGz ungzips and untars .tar.gz file to 'destPath' and returns sub-directories.
// It returns error when fail to finish operation.
func UnTarGz(srcFilePath string, destDirPath string) ([]string, error) {
	// Create destination directory
	os.Mkdir(destDirPath, os.ModePerm)

	fr, err := os.Open(srcFilePath)
	if err != nil {
		return nil, err
	}
	defer fr.Close()

	// Gzip reader
	gr, err := gzip.NewReader(fr)
	if err != nil {
		return nil, err
	}
	defer gr.Close()

	// Tar reader
	tr := tar.NewReader(gr)

	dirs := make([]string, 0, 5)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			// End of tar archive
			break
		}

		// Check if it is diretory or file
		if hdr.Typeflag != tar.TypeDir {
			// Get files from archive
			// Create diretory before create file
			dir := path.Dir(hdr.Name)
			os.MkdirAll(destDirPath+"/"+dir, os.ModePerm)
			dirs = AppendStr(dirs, dir)

			// Write data to file
			fw, _ := os.Create(destDirPath + "/" + hdr.Name)
			if err != nil {
				return nil, err
			}
			_, err = io.Copy(fw, tr)
			if err != nil {
				return nil, err
			}
		}
	}
	return dirs, nil
}
<commit_msg>Updated func: Unzip<commit_after>// Copyright 2013 com authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package com

import (
	"archive/tar"
	"archive/zip"
	"compress/gzip"
	"io"
	"io/ioutil"
	"os"
	"path"
)

// get filepath base name
func Basename(file string) string {
	return path.Base(file)
}

// get filepath dir name
func Dirname(file string) string {
	return path.Dir(file)
}

// get absolute filepath, based on built excutable file
func RealPath(file string) (string, error) {
	if path.IsAbs(file) {
		return file, nil
	}
	wd, err := os.Getwd()
	return path.Join(wd, file), err
}

// get file modified time
func FileMTime(file string) (int64, error) {
	f, e := os.Stat(file)
	if e != nil {
		return 0, e
	}
	return f.ModTime().Unix(), nil
}

// get file size as how many bytes
func FileSize(file string) (int64, error) {
	f, e := os.Stat(file)
	if e != nil {
		return 0, e
	}
	return f.Size(), nil
}

// copy file to new path
func Copy(file string, to string) (bool, error) {
	sf, e := os.Open(file)
	if e != nil {
		return false, e
	}
	defer sf.Close()
	df, e2 := os.Create(to)
	if e2 != nil {
		return false, e2
	}
	defer df.Close()
	// buffer reader, do chunk transfer
	buf := make([]byte, 1024)
	for {
		// read a chunk
		n, err := sf.Read(buf)
		if err != nil && err != io.EOF {
			return false, err
		}
		if n == 0 {
			break
		}
		// write a chunk
		if _, err := df.Write(buf[:n]); err != nil {
			return false, err
		}
	}
	return true, nil
}

// move file to new path
func Move(file string, to string) (bool, error) {
	// copy
	r, e := Copy(file, to)
	if e != nil {
		return r, e
	}
	// then remove
	e = os.Remove(file)
	if e != nil {
		r = false
	}
	return r, e
}

// delete file
func Unlink(file string) error {
	return os.Remove(file)
}

// rename file name
func Rename(file string, to string) error {
	return os.Rename(file, to)
}

// IsFile checks whether the path is a file,
// it returns false when it's a directory or does not exist.
func IsFile(filePath string) bool {
	f, e := os.Stat(filePath)
	if e != nil {
		return false
	}
	return !f.IsDir()
}

// IsExist returns whether a file or directory exists.
func IsExist(path string) bool {
	_, err := os.Stat(path)
	return err == nil || os.IsExist(err)
}

// SaveFile saves content type '[]byte' to file by given path.
// It returns error when fail to finish operation.
func SaveFile(filePath string, b []byte) (int, error) {
	os.MkdirAll(path.Dir(filePath), os.ModePerm)
	fw, err := os.Create(filePath)
	if err != nil {
		return 0, err
	}
	defer fw.Close()
	return fw.Write(b)
}

// SaveFileS saves content type 'string' to file by given path.
// It returns error when fail to finish operation.
func SaveFileS(filePath string, s string) (int, error) {
	return SaveFile(filePath, []byte(s))
}

// ReadFile reads data type '[]byte' from file by given path.
// It returns error when fail to finish operation.
func ReadFile(filePath string) ([]byte, error) {
	b, err := ioutil.ReadFile(filePath)
	if err != nil {
		return []byte(""), err
	}
	return b, nil
}

// ReadFileS reads data type 'string' from file by given path.
// It returns error when fail to finish operation.
func ReadFileS(filePath string) (string, error) {
	b, err := ReadFile(filePath)
	return string(b), err
}

// Unzip unzips .zip file to 'destPath' and returns sub-directories.
// It returns error when fail to finish operation.
func Unzip(srcPath, destPath string) ([]string, error) {
	// Open a zip archive for reading
	r, err := zip.OpenReader(srcPath)
	if err != nil {
		return nil, err
	}
	defer r.Close()

	dirs := make([]string, 0, 5)
	// Iterate through the files in the archive
	for _, f := range r.File {
		// Get files from archive
		rc, err := f.Open()
		if err != nil {
			return nil, err
		}

		dir := path.Dir(f.FileInfo().Name())
		// Create diretory before create file
		os.MkdirAll(destPath+"/"+dir, os.ModePerm)
		dirs = AppendStr(dirs, dir)

		if f.FileInfo().IsDir() {
			continue
		}

		// Write data to file
		fw, _ := os.Create(destPath + "/" + f.FileInfo().Name())
		if err != nil {
			return nil, err
		}
		_, err = io.Copy(fw, rc)
		fw.Close()
		if err != nil {
			return nil, err
		}
	}
	return dirs, nil
}

// UnTarGz ungzips and untars .tar.gz file to 'destPath' and returns sub-directories.
// It returns error when fail to finish operation.
func UnTarGz(srcFilePath string, destDirPath string) ([]string, error) {
	// Create destination directory
	os.Mkdir(destDirPath, os.ModePerm)

	fr, err := os.Open(srcFilePath)
	if err != nil {
		return nil, err
	}
	defer fr.Close()

	// Gzip reader
	gr, err := gzip.NewReader(fr)
	if err != nil {
		return nil, err
	}
	defer gr.Close()

	// Tar reader
	tr := tar.NewReader(gr)

	dirs := make([]string, 0, 5)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			// End of tar archive
			break
		}

		// Check if it is diretory or file
		if hdr.Typeflag != tar.TypeDir {
			// Get files from archive
			// Create diretory before create file
			dir := path.Dir(hdr.Name)
			os.MkdirAll(destDirPath+"/"+dir, os.ModePerm)
			dirs = AppendStr(dirs, dir)

			// Write data to file
			fw, _ := os.Create(destDirPath + "/" + hdr.Name)
			if err != nil {
				return nil, err
			}
			_, err = io.Copy(fw, tr)
			if err != nil {
				return nil, err
			}
		}
	}
	return dirs, nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/cli"
)

var Flags = []cli.Flag{
	cli.StringFlag{
		Name:  "pattern, p",
		Value: "",
		Usage: "Pattern to extract imports (example: '^import\\s+(\\S+)')",
	},
	cli.StringFlag{
		Name:  "module, m",
		Value: "",
		Usage: "Pattern to extract module names (example: '^module\\s+(\\S+)')",
	},
	cli.StringFlag{
		Name:  "start, s",
		Value: "",
		Usage: "Pattern to start matching",
	},
	cli.StringFlag{
		Name:  "end, e",
		Value: "",
		Usage: "Pattern to end matching",
	},
	cli.BoolFlag{
		Name:  "recursive, r",
		Usage: "Recursively inspect files in subdirectories",
	},
	cli.StringFlag{
		Name:  "format, f",
		Value: "",
		Usage: "Specify the format of the output; `default', `dot', `csv' and `json' are available.",
	},
	cli.BoolFlag{
		Name:  "trimext, t",
		Usage: "Trim the file extension.",
	},
	cli.BoolFlag{
		Name:  "help, h",
		Usage: "Shows the help of the command",
	},
}
<commit_msg>improve flag.go: remove short option for --format<commit_after>package main

import (
	"github.com/codegangsta/cli"
)

var Flags = []cli.Flag{
	cli.StringFlag{
		Name:  "pattern, p",
		Value: "",
		Usage: "Pattern to extract imports (example: '^import\\s+(\\S+)')",
	},
	cli.StringFlag{
		Name:  "module, m",
		Value: "",
		Usage: "Pattern to extract module names (example: '^module\\s+(\\S+)')",
	},
	cli.StringFlag{
		Name:  "start, s",
		Value: "",
		Usage: "Pattern to start matching",
	},
	cli.StringFlag{
		Name:  "end, e",
		Value: "",
		Usage: "Pattern to end matching",
	},
	cli.BoolFlag{
		Name:  "recursive, r",
		Usage: "Recursively inspect files in subdirectories",
	},
	cli.StringFlag{
		Name:  "format",
		Value: "",
		Usage: "Specify the format of the output; `default', `dot', `csv' and `json' are available.",
	},
	cli.BoolFlag{
		Name:  "trimext, t",
		Usage: "Trim the file extension.",
	},
	cli.BoolFlag{
		Name:  "help, h",
		Usage: "Shows the help of the command",
	},
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"go/ast"
	"go/token"
	"regexp"
	"strings"
)

var (
	ErrNotSupported = errors.New("not supported")
	ErrParse        = errors.New("parser error")
)

var (
	regexFlagCall  = regexp.MustCompile(`^[Ff]lags?\.(Bool|Duration|Float|Float64|Int|Int64|String|Uint|Uint64)(Var)?$`)
	regexBackquote = regexp.MustCompile("`(.*)`")
)

type FunctionCall struct {
	Line int
	Expr string
	Name string
	Args []string
}

func NewFunctionCall(fs *token.FileSet, n *ast.CallExpr) (*FunctionCall, error) {
	parts := make([]string, 0)
	ast.Inspect(n.Fun, func(n ast.Node) bool {
		if n == nil {
			return true
		}
		switch obj := n.(type) {
		case *ast.SelectorExpr:
			// do nothing, just avoid the default case
			break
		case *ast.Ident:
			parts = append(parts, obj.Name)
		default:
			return false
		}
		return true
	})
	if len(parts) == 0 {
		return nil, ErrNotSupported
	}
	args := make([]string, len(n.Args))
	for i, arg := range n.Args {
		ast.Inspect(arg, func(n ast.Node) bool {
			switch t := n.(type) {
			case *ast.Ident:
				args[i] = t.Name
			case *ast.BasicLit:
				args[i] = t.Value
			}
			return true
		})
	}
	return &FunctionCall{
		Line: fs.Position(n.Pos()).Line,
		Expr: strings.Join(parts, "."),
		Name: parts[len(parts)-1],
		Args: args,
	}, nil
}

type FlagType uint32

const (
	UnkownFlag FlagType = iota
	BoolFlag
	DurationFlag
	FloatFlag
	IntFlag
	UintFlag
	StringFlag
)

var flagTypes = map[string]FlagType{
	"Bool":     BoolFlag,
	"Duration": DurationFlag,
	"Float":    FloatFlag,
	"Float64":  FloatFlag,
	"Int":      IntFlag,
	"Int64":    IntFlag,
	"String":   StringFlag,
	"Uint":     UintFlag,
	"Uint64":   UintFlag,
}

// flagParam maps flag types to their default parameter names. These
// parameter names will be used if the usage string does not contain a
// backquoted name.
var flagParam = map[FlagType]string{
	DurationFlag: "duration",
	FloatFlag:    "float",
	IntFlag:      "int",
	StringFlag:   "string",
	UintFlag:     "uint",
}

type Flag struct {
	Type     FlagType
	Line     int
	Variable string // Pointer name (only set for ...Var() calls)
	Name     string // Name of the flag
	Short    string // Shorthand name of the flag
	Usage    string // Usage of the flag
	Param    string // User specified parameter name (back-quoted word in usage)
	Doc      string // Comment above flag declaration
}

const Quotes = "\"`"

func NewFlag(fs *token.FileSet, n *ast.CallExpr) (*Flag, error) {
	call, err := NewFunctionCall(fs, n)
	if err != nil {
		return nil, err
	}
	match := regexFlagCall.FindStringSubmatch(call.Expr)
	if match == nil {
		return nil, ErrNotSupported
	}
	// Pad to 4 arguments.
	if len(call.Args) == 3 {
		call.Args = append([]string{""}, call.Args...)
	}
	result := &Flag{
		Type:     flagTypes[match[1]],
		Line:     call.Line,
		Variable: call.Args[0],
		Name:     strings.Trim(call.Args[1], Quotes),
		Usage:    strings.Trim(call.Args[3], Quotes),
	}
	// Check if there's a backquoted parameter name in the usage string.
	if match := regexBackquote.FindStringSubmatch(result.Usage); match != nil {
		result.Param = match[1]
		result.Usage = strings.Replace(result.Usage, "`", "", -1)
	} else {
		result.Param = flagParam[result.Type]
	}
	return result, nil
}

func assignIfEmpty(d *string, v string) {
	if *d == "" {
		*d = v
	}
}

func (o *Flag) merge(v *Flag) {
	if len(o.Name) < len(v.Name) {
		o.Short = o.Name
		o.Name = v.Name
	} else {
		o.Short = v.Name
	}
	assignIfEmpty(&o.Doc, v.Doc)
	assignIfEmpty(&o.Param, v.Param)
	assignIfEmpty(&o.Usage, v.Usage)
}
<commit_msg>fix string unquote<commit_after>package main

import (
	"errors"
	"go/ast"
	"go/token"
	"regexp"
	"strings"
)

var (
	ErrNotSupported = errors.New("not supported")
	ErrParse        = errors.New("parser error")
)

var (
	regexFlagCall  = regexp.MustCompile(`^[Ff]lags?\.(Bool|Duration|Float|Float64|Int|Int64|String|Uint|Uint64)(Var)?$`)
	regexBackquote = regexp.MustCompile("`(.*)`")
)

type FunctionCall struct {
	Line int
	Expr string
	Name string
	Args []string
}

func NewFunctionCall(fs *token.FileSet, n *ast.CallExpr) (*FunctionCall, error) {
	parts := make([]string, 0)
	ast.Inspect(n.Fun, func(n ast.Node) bool {
		if n == nil {
			return true
		}
		switch obj := n.(type) {
		case *ast.SelectorExpr:
			// do nothing, just avoid the default case
			break
		case *ast.Ident:
			parts = append(parts, obj.Name)
		default:
			return false
		}
		return true
	})
	if len(parts) == 0 {
		return nil, ErrNotSupported
	}
	args := make([]string, len(n.Args))
	for i, arg := range n.Args {
		ast.Inspect(arg, func(n ast.Node) bool {
			switch t := n.(type) {
			case *ast.Ident:
				args[i] = t.Name
			case *ast.BasicLit:
				args[i] = t.Value
			}
			return true
		})
	}
	return &FunctionCall{
		Line: fs.Position(n.Pos()).Line,
		Expr: strings.Join(parts, "."),
		Name: parts[len(parts)-1],
		Args: args,
	}, nil
}

type FlagType uint32

const (
	UnkownFlag FlagType = iota
	BoolFlag
	DurationFlag
	FloatFlag
	IntFlag
	UintFlag
	StringFlag
)

var flagTypes = map[string]FlagType{
	"Bool":     BoolFlag,
	"Duration": DurationFlag,
	"Float":    FloatFlag,
	"Float64":  FloatFlag,
	"Int":      IntFlag,
	"Int64":    IntFlag,
	"String":   StringFlag,
	"Uint":     UintFlag,
	"Uint64":   UintFlag,
}

// flagParam maps flag types to their default parameter names. These
// parameter names will be used if the usage string does not contain a
// backquoted name.
var flagParam = map[FlagType]string{
	DurationFlag: "duration",
	FloatFlag:    "float",
	IntFlag:      "int",
	StringFlag:   "string",
	UintFlag:     "uint",
}

type Flag struct {
	Type     FlagType
	Line     int
	Variable string // Pointer name (only set for ...Var() calls)
	Name     string // Name of the flag
	Short    string // Shorthand name of the flag
	Usage    string // Usage of the flag
	Param    string // User specified parameter name (back-quoted word in usage)
	Doc      string // Comment above flag declaration
}

func trimQuotes(s string) string {
	if len(s) == 0 {
		return ""
	}
	if (s[0] == '`' || s[0] == '"') && s[0] == s[len(s)-1] {
		s = s[1 : len(s)-1]
	}
	return s
}

func NewFlag(fs *token.FileSet, n *ast.CallExpr) (*Flag, error) {
	call, err := NewFunctionCall(fs, n)
	if err != nil {
		return nil, err
	}
	match := regexFlagCall.FindStringSubmatch(call.Expr)
	if match == nil {
		return nil, ErrNotSupported
	}
	// Pad to 4 arguments.
	if len(call.Args) == 3 {
		call.Args = append([]string{""}, call.Args...)
	}
	result := &Flag{
		Type:     flagTypes[match[1]],
		Line:     call.Line,
		Variable: call.Args[0],
		Name:     trimQuotes(call.Args[1]),
		Usage:    trimQuotes(call.Args[3]),
	}
	// Check if there's a backquoted parameter name in the usage string.
	if match := regexBackquote.FindStringSubmatch(result.Usage); match != nil {
		result.Param = match[1]
		result.Usage = strings.Replace(result.Usage, "`", "", -1)
	} else {
		result.Param = flagParam[result.Type]
	}
	return result, nil
}

func assignIfEmpty(d *string, v string) {
	if *d == "" {
		*d = v
	}
}

func (o *Flag) merge(v *Flag) {
	if len(o.Name) < len(v.Name) {
		o.Short = o.Name
		o.Name = v.Name
	} else {
		o.Short = v.Name
	}
	assignIfEmpty(&o.Doc, v.Doc)
	assignIfEmpty(&o.Param, v.Param)
	assignIfEmpty(&o.Usage, v.Usage)
}
<|endoftext|>


<commit_before>package multiconfig

import (
	"flag"
	"fmt"
	"os"
	"reflect"
	"strings"

	"github.com/fatih/camelcase"
	"github.com/fatih/structs"
)

// FlagLoader satisfies the loader interface. It creates on the fly flags based
// on the field names and parses them to load into the given pointer of struct
// s.
type FlagLoader struct {
	// Prefix prepends the prefix to each flag name i.e:
	// --foo is converted to --prefix-foo.
	// --foo-bar is converted to --prefix-foo-bar.
	Prefix string

	// Flatten doesn't add prefixes for nested structs. So previously if we had
	// a nested struct `type T struct{Name struct{ ...}}`, this would generate
	// --name-foo, --name-bar, etc. When Flatten is enabled, the flags will be
	// flattend to the form: --foo, --bar, etc.. Panics if the nested structs
	// has a duplicate field name in the root level of the struct (outer
	// struct). Use this option only if you know what you do.
	Flatten bool

	// CamelCase adds a seperator for field names in camelcase form. A
	// fieldname of "AccessKey" would generate a flag name "--accesskey". If
	// CamelCase is enabled, the flag name will be generated in the form of
	// "--access-key"
	CamelCase bool

	// EnvPrefix is just a placeholder to print the correct usages when an
	// EnvLoader is used
	EnvPrefix string

	// Args defines a custom argument list. If nil, os.Args[1:] is used.
	Args []string
}

// Load loads the source into the config defined by struct s
func (f *FlagLoader) Load(s interface{}) error {
	strct := structs.New(s)
	structName := strct.Name()

	flagSet := flag.NewFlagSet(structName, flag.ExitOnError)

	for _, field := range strct.Fields() {
		f.processField(flagSet, field.Name(), field)
	}

	flagSet.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flagSet.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\nGenerated environment variables:\n")
		e := &EnvironmentLoader{
			Prefix:    f.EnvPrefix,
			CamelCase: f.CamelCase,
		}
		e.PrintEnvs(s)
		fmt.Println("")
	}

	args := os.Args[1:]
	if f.Args != nil {
		args = f.Args
	}

	return flagSet.Parse(args)
}

// processField generates a flag based on the given field and fieldName. If a
// nested struct is detected, a flag for each field of that nested struct is
// generated too.
func (f *FlagLoader) processField(flagSet *flag.FlagSet, fieldName string, field *structs.Field) error {
	if !field.IsExported() {
		return nil
	}

	if f.CamelCase {
		fieldName = strings.Join(camelcase.Split(fieldName), "-")
	}

	switch {
	case field.Kind() == reflect.Struct && !implementsTextUnmarshaler(field):
		for _, ff := range field.Fields() {
			flagName := field.Name() + "-" + ff.Name()

			if f.Flatten {
				// first check if it's set or not, because if we have duplicate
				// we don't want to break the flag. Panic by giving a readable
				// output
				flagSet.VisitAll(func(fl *flag.Flag) {
					if strings.ToLower(ff.Name()) == fl.Name {
						// already defined
						panic(fmt.Sprintf("flag '%s' is already defined in outer struct", fl.Name))
					}
				})

				flagName = ff.Name()
			}

			if err := f.processField(flagSet, flagName, ff); err != nil {
				return err
			}
		}
	case field.Kind() == reflect.Ptr:
		field.InitElem()
		return f.processField(flagSet, fieldName, field)
	default:
		// Add custom prefix to the flag if it's set
		if f.Prefix != "" {
			fieldName = f.Prefix + "-" + fieldName
		}

		flagSet.Var(newFieldValue(field), flagName(fieldName), flagUsage(fieldName))
	}

	return nil
}

// fieldValue satisfies the flag.Value and flag.Getter interfaces
type fieldValue structs.Field

func newFieldValue(f *structs.Field) *fieldValue {
	fl := fieldValue(*f)
	return &fl
}

func (f *fieldValue) Set(val string) error {
	field := (*structs.Field)(f)
	return fieldSet(field, val)
}

func (f *fieldValue) String() string {
	fl := (*structs.Field)(f)
	return fmt.Sprintf("%v", fl.Value())
}

func (f *fieldValue) Get() interface{} {
	fl := (*structs.Field)(f)
	return fl.Value()
}

// This is an unexported interface, be careful about it.
// https://code.google.com/p/go/source/browse/src/pkg/flag/flag.go?name=release#101
func (f *fieldValue) IsBoolFlag() bool {
	fl := (*structs.Field)(f)
	if fl.Kind() == reflect.Bool {
		return true
	}
	return false
}

func flagUsage(name string) string { return fmt.Sprintf("Change value of %s.", name) }

func flagName(name string) string { return strings.ToLower(name) }
<commit_msg>fix missing parent name in flag names of deep nested structs<commit_after>package multiconfig

import (
	"flag"
	"fmt"
	"os"
	"reflect"
	"strings"

	"github.com/fatih/camelcase"
	"github.com/fatih/structs"
)

// FlagLoader satisfies the loader interface. It creates on the fly flags based
// on the field names and parses them to load into the given pointer of struct
// s.
type FlagLoader struct {
	// Prefix prepends the prefix to each flag name i.e:
	// --foo is converted to --prefix-foo.
	// --foo-bar is converted to --prefix-foo-bar.
	Prefix string

	// Flatten doesn't add prefixes for nested structs. So previously if we had
	// a nested struct `type T struct{Name struct{ ...}}`, this would generate
	// --name-foo, --name-bar, etc. When Flatten is enabled, the flags will be
	// flattend to the form: --foo, --bar, etc.. Panics if the nested structs
	// has a duplicate field name in the root level of the struct (outer
	// struct). Use this option only if you know what you do.
	Flatten bool

	// CamelCase adds a seperator for field names in camelcase form. A
	// fieldname of "AccessKey" would generate a flag name "--accesskey". If
	// CamelCase is enabled, the flag name will be generated in the form of
	// "--access-key"
	CamelCase bool

	// EnvPrefix is just a placeholder to print the correct usages when an
	// EnvLoader is used
	EnvPrefix string

	// Args defines a custom argument list. If nil, os.Args[1:] is used.
	Args []string
}

// Load loads the source into the config defined by struct s
func (f *FlagLoader) Load(s interface{}) error {
	strct := structs.New(s)
	structName := strct.Name()

	flagSet := flag.NewFlagSet(structName, flag.ExitOnError)

	for _, field := range strct.Fields() {
		f.processField(flagSet, field.Name(), field)
	}

	flagSet.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flagSet.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\nGenerated environment variables:\n")
		e := &EnvironmentLoader{
			Prefix:    f.EnvPrefix,
			CamelCase: f.CamelCase,
		}
		e.PrintEnvs(s)
		fmt.Println("")
	}

	args := os.Args[1:]
	if f.Args != nil {
		args = f.Args
	}

	return flagSet.Parse(args)
}

// processField generates a flag based on the given field and fieldName. If a
// nested struct is detected, a flag for each field of that nested struct is
// generated too.
func (f *FlagLoader) processField(flagSet *flag.FlagSet, fieldName string, field *structs.Field) error {
	if !field.IsExported() {
		return nil
	}

	if f.CamelCase {
		fieldName = strings.Join(camelcase.Split(fieldName), "-")
	}

	switch {
	case field.Kind() == reflect.Struct && !implementsTextUnmarshaler(field):
		for _, ff := range field.Fields() {
			flagName := fieldName + "-" + ff.Name()

			if f.Flatten {
				// first check if it's set or not, because if we have duplicate
				// we don't want to break the flag. Panic by giving a readable
				// output
				flagSet.VisitAll(func(fl *flag.Flag) {
					if strings.ToLower(ff.Name()) == fl.Name {
						// already defined
						panic(fmt.Sprintf("flag '%s' is already defined in outer struct", fl.Name))
					}
				})

				flagName = ff.Name()
			}

			if err := f.processField(flagSet, flagName, ff); err != nil {
				return err
			}
		}
	case field.Kind() == reflect.Ptr:
		field.InitElem()
		return f.processField(flagSet, fieldName, field)
	default:
		// Add custom prefix to the flag if it's set
		if f.Prefix != "" {
			fieldName = f.Prefix + "-" + fieldName
		}

		flagSet.Var(newFieldValue(field), flagName(fieldName), flagUsage(fieldName))
	}

	return nil
}

// fieldValue satisfies the flag.Value and flag.Getter interfaces
type fieldValue structs.Field

func newFieldValue(f *structs.Field) *fieldValue {
	fl := fieldValue(*f)
	return &fl
}

func (f *fieldValue) Set(val string) error {
	field := (*structs.Field)(f)
	return fieldSet(field, val)
}

func (f *fieldValue) String() string {
	fl := (*structs.Field)(f)
	return fmt.Sprintf("%v", fl.Value())
}

func (f *fieldValue) Get() interface{} {
	fl := (*structs.Field)(f)
	return fl.Value()
}

// This is an unexported interface, be careful about it.
// https://code.google.com/p/go/source/browse/src/pkg/flag/flag.go?name=release#101
func (f *fieldValue) IsBoolFlag() bool {
	fl := (*structs.Field)(f)
	if fl.Kind() == reflect.Bool {
		return true
	}
	return false
}

func flagUsage(name string) string { return fmt.Sprintf("Change value of %s.", name) }

func flagName(name string) string { return strings.ToLower(name) }
<|endoftext|>


<commit_before>package gkvlite

import (
	"sync/atomic"
	"unsafe"
)

var reclaimable_node = &node{} // Sentinel.

func (t *Collection) markReclaimable(n *node) {
	if n == nil || n.next != nil || n == reclaimable_node {
		return
	}
	n.next = reclaimable_node // Use next pointer as sentinel.
}

func (t *Collection) reclaimNodes(n *node) {
	if n == nil {
		return
	}
	if n.next != reclaimable_node {
		return
	}
	var left *node
	var right *node
	if !n.left.isEmpty() {
		left = n.left.Node()
	}
	if !n.right.isEmpty() {
		right = n.right.Node()
	}
	t.freeNode(n)
	t.reclaimNodes(left)
	t.reclaimNodes(right)
}

// Assumes that the caller serializes invocations.
func (t *Collection) mkNode(itemIn *itemLoc, leftIn *nodeLoc, rightIn *nodeLoc,
	numNodesIn uint64, numBytesIn uint64) *node {
	t.stats.MkNodes++
	t.freeLock.Lock()
	n := t.freeNodes
	if n == nil {
		t.freeLock.Unlock()
		atomic.AddUint64(&t.store.nodeAllocs, 1)
		t.stats.AllocNodes++
		n = &node{}
	} else {
		t.freeNodes = n.next
		t.freeLock.Unlock()
	}
	n.item.Copy(itemIn)
	n.left.Copy(leftIn)
	n.right.Copy(rightIn)
	n.numNodes = numNodesIn
	n.numBytes = numBytesIn
	n.next = nil
	return n
}

func (t *Collection) freeNode(n *node) {
	return

	if n == nil || n == reclaimable_node {
		return
	}
	if n.next != nil && n.next != reclaimable_node {
		panic("double free node")
	}
	n.item = *empty_itemLoc
	n.left = *empty_nodeLoc
	n.right = *empty_nodeLoc
	n.numNodes = 0
	n.numBytes = 0

	t.freeLock.Lock()
	n.next = t.freeNodes
	t.freeNodes = n
	t.stats.FreeNodes++
	t.freeLock.Unlock()
}

// Assumes that the caller serializes invocations.
func (t *Collection) mkNodeLoc(n *node) *nodeLoc {
	t.stats.MkNodeLocs++
	nloc := t.freeNodeLocs
	if nloc == nil {
		t.stats.AllocNodeLocs++
		nloc = &nodeLoc{}
	}
	t.freeNodeLocs = nloc.next
	nloc.loc = unsafe.Pointer(nil)
	nloc.node = unsafe.Pointer(n)
	nloc.next = nil
	return nloc
}

// Assumes that the caller serializes invocations.
func (t *Collection) freeNodeLoc(nloc *nodeLoc) {
	if nloc == nil || nloc == empty_nodeLoc {
		return
	}
	if nloc.next != nil {
		panic("double free nloc")
	}
	t.stats.FreeNodeLocs++
	nloc.loc = unsafe.Pointer(nil)
	nloc.node = unsafe.Pointer(nil)
	nloc.next = t.freeNodeLocs
	t.freeNodeLocs = nloc
}

func (t *Collection) mkRootNodeLoc(root *nodeLoc) *rootNodeLoc {
	t.freeLock.Lock()
	rnl := t.freeRootNodeLocs
	if rnl == nil {
		t.freeLock.Unlock()
		rnl = &rootNodeLoc{}
	} else {
		t.freeRootNodeLocs = rnl.next
		t.freeLock.Unlock()
	}
	rnl.refs = 1
	rnl.root = root
	rnl.next = nil
	return rnl
}

func (t *Collection) freeRootNodeLoc(rnl *rootNodeLoc) {
	if rnl == nil {
		return
	}
	rnl.refs = 0
	rnl.root = nil

	t.freeLock.Lock()
	rnl.next = t.freeRootNodeLocs
	t.freeRootNodeLocs = rnl
	t.freeLock.Unlock()
}
<commit_msg>No rootNodeLoc reclaimation due to ABA issue.<commit_after>package gkvlite

import (
	"sync/atomic"
	"unsafe"
)

var reclaimable_node = &node{} // Sentinel.

func (t *Collection) markReclaimable(n *node) {
	if n == nil || n.next != nil || n == reclaimable_node {
		return
	}
	n.next = reclaimable_node // Use next pointer as sentinel.
}

func (t *Collection) reclaimNodes(n *node) {
	if n == nil {
		return
	}
	if n.next != reclaimable_node {
		return
	}
	var left *node
	var right *node
	if !n.left.isEmpty() {
		left = n.left.Node()
	}
	if !n.right.isEmpty() {
		right = n.right.Node()
	}
	t.freeNode(n)
	t.reclaimNodes(left)
	t.reclaimNodes(right)
}

// Assumes that the caller serializes invocations.
func (t *Collection) mkNode(itemIn *itemLoc, leftIn *nodeLoc, rightIn *nodeLoc,
	numNodesIn uint64, numBytesIn uint64) *node {
	t.stats.MkNodes++
	t.freeLock.Lock()
	n := t.freeNodes
	if n == nil {
		t.freeLock.Unlock()
		atomic.AddUint64(&t.store.nodeAllocs, 1)
		t.stats.AllocNodes++
		n = &node{}
	} else {
		t.freeNodes = n.next
		t.freeLock.Unlock()
	}
	n.item.Copy(itemIn)
	n.left.Copy(leftIn)
	n.right.Copy(rightIn)
	n.numNodes = numNodesIn
	n.numBytes = numBytesIn
	n.next = nil
	return n
}

func (t *Collection) freeNode(n *node) {
	return

	if n == nil || n == reclaimable_node {
		return
	}
	if n.next != nil && n.next != reclaimable_node {
		panic("double free node")
	}
	n.item = *empty_itemLoc
	n.left = *empty_nodeLoc
	n.right = *empty_nodeLoc
	n.numNodes = 0
	n.numBytes = 0

	t.freeLock.Lock()
	n.next = t.freeNodes
	t.freeNodes = n
	t.stats.FreeNodes++
	t.freeLock.Unlock()
}

// Assumes that the caller serializes invocations.
func (t *Collection) mkNodeLoc(n *node) *nodeLoc {
	t.stats.MkNodeLocs++
	nloc := t.freeNodeLocs
	if nloc == nil {
		t.stats.AllocNodeLocs++
		nloc = &nodeLoc{}
	}
	t.freeNodeLocs = nloc.next
	nloc.loc = unsafe.Pointer(nil)
	nloc.node = unsafe.Pointer(n)
	nloc.next = nil
	return nloc
}

// Assumes that the caller serializes invocations.
func (t *Collection) freeNodeLoc(nloc *nodeLoc) {
	if nloc == nil || nloc == empty_nodeLoc {
		return
	}
	if nloc.next != nil {
		panic("double free nloc")
	}
	t.stats.FreeNodeLocs++
	nloc.loc = unsafe.Pointer(nil)
	nloc.node = unsafe.Pointer(nil)
	nloc.next = t.freeNodeLocs
	t.freeNodeLocs = nloc
}

func (t *Collection) mkRootNodeLoc(root *nodeLoc) *rootNodeLoc {
	t.freeLock.Lock()
	rnl := t.freeRootNodeLocs
	if rnl == nil {
		t.freeLock.Unlock()
		rnl = &rootNodeLoc{}
	} else {
		t.freeRootNodeLocs = rnl.next
		t.freeLock.Unlock()
	}
	rnl.refs = 1
	rnl.root = root
	rnl.next = nil
	return rnl
}

func (t *Collection) freeRootNodeLoc(rnl *rootNodeLoc) {
	// No rootNodeLoc reclaimation for now to avoid ABA issue.
	return

	if rnl == nil {
		return
	}
	rnl.refs = 0
	rnl.root = nil

	t.freeLock.Lock()
	rnl.next = t.freeRootNodeLocs
	t.freeRootNodeLocs = rnl
	t.freeLock.Unlock()
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
)

type Game struct {
	clock    InstanceClock
	handlers HandlerContainer
	units    UnitContainer

	w InstanceOutputWriter
}

// NewGame returns a Game
func NewGame(clock InstanceClock, w InstanceOutputWriter) *Game {
	return &Game{
		clock:    clock,
		handlers: MakeHandlerSet(),
		units:    NewUnitMap(),

		w: w,
	}
}

// Clear clears the game state
func (g *Game) Clear() {
	g.handlers = MakeHandlerSet()
	g.units.Clear()
}

// SyncGame sends the game state
func (g *Game) SyncGame(w InstanceOutputWriter) {
	g.units.Each(func(u *Unit) {
		w.Write(OutputUnitJoin{
			UnitID:    u.ID(),
			UnitGroup: u.Group(),
			UnitName:  u.Name(),
			ClassName: u.ClassName(),
			Health:    u.Health(),
			HealthMax: u.HealthMax(),
			Mana:      u.Mana(),
			ManaMax:   u.ManaMax(),
		})
	})
}

// SyncUnit sends the unit information
func (g *Game) SyncUnit(w InstanceOutputWriter, id UnitID) {
	// TODO refactor
	u := g.units.Find(id)
	// TODO handle the error
	if u == nil {
		return
	}
	as := make([]OutputPlayerAbility, 4)
	for i := 0; i < 4; i++ {
		dts := make([]string, 0)
		for _, dt := range u.Abilities()[i].DisableTypes {
			switch dt {
			case DisableTypeSilence:
				dts = append(dts, "Silence")
			case DisableTypeStun:
				dts = append(dts, "Stun")
			}
		}
		as[i] = OutputPlayerAbility{
			Name:               u.Abilities()[i].Name,
			Description:        u.Abilities()[i].Description,
			TargetType:         u.Abilities()[i].TargetType,
			HealthCost:         u.Abilities()[i].HealthCost,
			ManaCost:           u.Abilities()[i].ManaCost,
			ActivationDuration: u.Abilities()[i].ActivationDuration,
			CooldownDuration:   u.Abilities()[i].CooldownDuration,
			DisableTypes:       dts,
		}
	}
	w.Write(OutputPlayer{
		UnitID: id,
		Q:      as[0],
		W:      as[1],
		E:      as[2],
		R:      as[3],
	})
}

// Join creates a Unit and adds it to the game
func (g *Game) Join(group UnitGroup, name UnitName, class *Class) (id UnitID, err error) {
	u, err := g.units.Join(group, name, class)
	if err != nil {
		return
	}
	id = u.ID()
	g.w.Write(OutputUnitJoin{
		UnitID:    u.ID(),
		UnitGroup: u.Group(),
		UnitName:  u.Name(),
		ClassName: u.ClassName(),
		Health:    u.Health(),
		HealthMax: u.HealthMax(),
		Mana:      u.Mana(),
		ManaMax:   u.ManaMax(),
	})
	return
}

// Leave removes the Unit
func (g *Game) Leave(id UnitID) (err error) {
	if err = g.units.Leave(id); err != nil {
		return
	}
	g.w.Write(OutputUnitLeave{
		UnitID: id,
	})
	return
}

// Ability activates the ability
func (g *Game) Ability(sid UnitID, oid *UnitID, abilityName string) error {
	s := g.units.Find(sid)
	if s == nil {
		return errors.New("Unknown subject UnitID")
	}
	var o *Unit
	if oid != nil {
		o = g.units.Find(*oid)
		if o == nil {
			return errors.New("Unknown object UnitID")
		}
	}
	a := s.Ability(abilityName)
	if a == nil {
		return errors.New("Unknown ability name")
	}
	g.Activating(s, o, a)
	return nil
}

// PerformGameTick performs the game tick routine
func (g *Game) PerformGameTick() {
	g.units.Each(func(u *Unit) {
		if u.IsDead() {
			return
		}
		u.TriggerEvent(EventGameTick)
	})
}

// PerformPeriodicalTick performs the periodical rick routine
func (g *Game) PerformPeriodicalTick() {
	g.units.Each(func(u *Unit) {
		if u.IsDead() {
			return
		}
		u.TriggerEvent(EventPeriodicalTick)
	})
}

// PerformRegenerationTick performs the regeneration tick routine
func (g *Game) PerformRegenerationTick() {
	g.units.Each(func(u *Unit) {
		if u.IsDead() {
			return
		}
		u.ModifyHealth(g.w, u.HealthRegeneration())
		u.ModifyMana(g.w, u.ManaRegeneration())
	})
}
<commit_msg>Change AbilityName interpretation<commit_after>package main

import (
	"errors"
)

type Game struct {
	clock    InstanceClock
	handlers HandlerContainer
	units    UnitContainer

	w InstanceOutputWriter
}

// NewGame returns a Game
func NewGame(clock InstanceClock, w InstanceOutputWriter) *Game {
	return &Game{
		clock:    clock,
		handlers: MakeHandlerSet(),
		units:    NewUnitMap(),

		w: w,
	}
}

// Clear clears the game state
func (g *Game) Clear() {
	g.handlers = MakeHandlerSet()
	g.units.Clear()
}

// SyncGame sends the game state
func (g *Game) SyncGame(w InstanceOutputWriter) {
	g.units.Each(func(u *Unit) {
		w.Write(OutputUnitJoin{
			UnitID:    u.ID(),
			UnitGroup: u.Group(),
			UnitName:  u.Name(),
			ClassName: u.ClassName(),
			Health:    u.Health(),
			HealthMax: u.HealthMax(),
			Mana:      u.Mana(),
			ManaMax:   u.ManaMax(),
		})
	})
}

// SyncUnit sends the unit information
func (g *Game) SyncUnit(w InstanceOutputWriter, id UnitID) {
	// TODO refactor
	u := g.units.Find(id)
	// TODO handle the error
	if u == nil {
		return
	}
	as := make([]OutputPlayerAbility, 4)
	for i := 0; i < 4; i++ {
		dts := make([]string, 0)
		for _, dt := range u.Abilities()[i].DisableTypes {
			switch dt {
			case DisableTypeSilence:
				dts = append(dts, "Silence")
			case DisableTypeStun:
				dts = append(dts, "Stun")
			}
		}
		as[i] = OutputPlayerAbility{
			Name:               u.Abilities()[i].Name,
			Description:        u.Abilities()[i].Description,
			TargetType:         u.Abilities()[i].TargetType,
			HealthCost:         u.Abilities()[i].HealthCost,
			ManaCost:           u.Abilities()[i].ManaCost,
			ActivationDuration: u.Abilities()[i].ActivationDuration,
			CooldownDuration:   u.Abilities()[i].CooldownDuration,
			DisableTypes:       dts,
		}
	}
	w.Write(OutputPlayer{
		UnitID: id,
		Q:      as[0],
		W:      as[1],
		E:      as[2],
		R:      as[3],
	})
}

// Join creates a Unit and adds it to the game
func (g *Game) Join(group UnitGroup, name UnitName, class *Class) (id UnitID, err error) {
	u, err := g.units.Join(group, name, class)
	if err != nil {
		return
	}
	id = u.ID()
	g.w.Write(OutputUnitJoin{
		UnitID:    u.ID(),
		UnitGroup: u.Group(),
		UnitName:  u.Name(),
		ClassName: u.ClassName(),
		Health:    u.Health(),
		HealthMax: u.HealthMax(),
		Mana:      u.Mana(),
		ManaMax:   u.ManaMax(),
	})
	return
}

// Leave removes the Unit
func (g *Game) Leave(id UnitID) (err error) {
	if err = g.units.Leave(id); err != nil {
		return
	}
	g.w.Write(OutputUnitLeave{
		UnitID: id,
	})
	return
}

// Ability activates the ability
func (g *Game) Ability(sid UnitID, oid *UnitID, abilityName string) error {
	s := g.units.Find(sid)
	if s == nil {
		return errors.New("Unknown subject UnitID")
	}
	var o *Unit
	if oid != nil {
		o = g.units.Find(*oid)
		if o == nil {
			return errors.New("Unknown object UnitID")
		}
	}
	// TODO refactor
	switch abilityName {
	case "Q":
		g.Activating(s, o, s.Abilities()[0])
	case "W":
		g.Activating(s, o, s.Abilities()[1])
	case "E":
		g.Activating(s, o, s.Abilities()[2])
	case "R":
		g.Activating(s, o, s.Abilities()[3])
	default:
		return errors.New("Unknown ability name")
	}
	return nil
}

// PerformGameTick performs the game tick routine
func (g *Game) PerformGameTick() {
	g.units.Each(func(u *Unit) {
		if u.IsDead() {
			return
		}
		u.TriggerEvent(EventGameTick)
	})
}

// PerformPeriodicalTick performs the periodical rick routine
func (g *Game) PerformPeriodicalTick() {
	g.units.Each(func(u *Unit) {
		if u.IsDead() {
			return
		}
		u.TriggerEvent(EventPeriodicalTick)
	})
}

// PerformRegenerationTick performs the regeneration tick routine
func (g *Game) PerformRegenerationTick() {
	g.units.Each(func(u *Unit) {
		if u.IsDead() {
			return
		}
		u.ModifyHealth(g.w, u.HealthRegeneration())
		u.ModifyMana(g.w, u.ManaRegeneration())
	})
}
<|endoftext|>


<commit_before>package game

import (
	"errors"
	"github.com/svera/acquire/board"
	"github.com/svera/acquire/corporation"
	"github.com/svera/acquire/fsm"
	"github.com/svera/acquire/player"
	"github.com/svera/acquire/tileset"
)

const totalCorporations = 7
const (
	ActionNotAllowed          = "action_not_allowed"
	WrongNumberPlayers        = "wrong_number_players"
	StockSharesNotBuyable     = "stock_shares_not_buyable"
	NotEnoughStockShares      = "not_enough_stock_shares"
	TileTemporaryUnplayable   = "tile_temporary_unplayable"
	TilePermanentlyUnplayable = "tile_permanently_unplayable"
	NotEnoughCash             = "not_enough_cash"
	TooManyStockSharesToBuy   = "too_many_stock_shares_to_buy"
	CorpIdNotUnique           = "corp_id_not_unique"
	WrongNumberCorpsClass     = "wrong_number_corps_class"
)

type Game struct {
	board         board.Interface
	state         fsm.State
	players       []player.Interface
	corporations  [7]corporation.Interface
	tileset       tileset.Interface
	currentPlayer int
}

func New(
	board board.Interface, players []player.Interface, corporations [7]corporation.Interface, tileset tileset.Interface) (*Game, error) {
	if len(players) < 3 || len(players) > 6 {
		return nil, errors.New(WrongNumberPlayers)
	}
	if !areIdsUnique(corporations) {
		return nil, errors.New(CorpIdNotUnique)
	}
	if !isNumberOfCorpsPerClassRight(corporations) {
		return nil, errors.New(WrongNumberCorpsClass)
	}
	gm := Game{
		board:         board,
		players:       players,
		corporations:  corporations,
		tileset:       tileset,
		currentPlayer: 0,
		state:         &fsm.PlayTile{},
	}
	for _, plyr := range gm.players {
		gm.giveInitialTileset(plyr)
	}

	return &gm, nil
}

// Check that the passed corporations have unique IDs
func areIdsUnique(corporations [7]corporation.Interface) bool {
	for i, corp1 := range corporations {
		if i < len(corporations)-1 {
			for _, corp2 := range corporations[i+1:] {
				if corp1.Id() == corp2.Id() {
					return false
				}
			}
		}
	}
	return true
}

// Check that the number of corporations per class is right
func isNumberOfCorpsPerClassRight(corporations [7]corporation.Interface) bool {
	corpsPerClass := [3]int{0, 0, 0}
	for _, corp := range corporations {
		corpsPerClass[corp.Class()]++
	}
	if corpsPerClass[0] != 2 || corpsPerClass[1] != 3 || corpsPerClass[2] != 2 {
		return false
	}
	return true
}

// Initialises player hand of tiles
func (g *Game) giveInitialTileset(plyr player.Interface) {
	for i := 0; i < 6; i++ {
		tile, _ := g.tileset.Draw()
		plyr.PickTile(tile)
	}
}

// Check if game end conditions are reached
func (g *Game) AreEndConditionsReached() bool {
	active := g.getActiveCorporations()
	if len(active) == 0 {
		return false
	}
	for _, corp := range active {
		if corp.Size() >= 41 {
			return true
		}
		if !corp.IsSafe() {
			return false
		}
	}
	return true
}

// Returns all corporations on the board
func (g *Game) getActiveCorporations() []corporation.Interface {
	active := []corporation.Interface{}
	for _, corp := range g.corporations {
		if corp.IsActive() {
			active = append(active, corp)
		}
	}
	return active
}

// Calculates and returns bonus amounts to be paid to owners of stock of a
// defunct corporation
func (g *Game) PayBonusesForDefunctCorporation(corp corporation.Interface) {
	stockHolders := g.GetMainStockHolders(corp)
	numberMajorityHolders := len(stockHolders["majority"])
	numberMinorityHolders := len(stockHolders["minority"])

	for _, majorityStockHolder := range stockHolders["majority"] {
		majorityStockHolder.ReceiveBonus(corp.MajorityBonus() / int(numberMajorityHolders))
	}
	for _, minorityStockHolder := range stockHolders["minority"] {
		minorityStockHolder.ReceiveBonus(corp.MinorityBonus() / int(numberMinorityHolders))
	}
}

// Taken from the game rules:
// "If only one player owns stock in the defunct corporation, that player gets both bonuses. If there's
// a tie for majority stockholder, add the majority and minority bonuses and divide evenly (the minority
// shareholder gets no bonus. If there's a tie for minority stockholder, split the minority bonus among
// the tied players"
func (g *Game) GetMainStockHolders(corp corporation.Interface) map[string][]player.ShareInterface {
	mainStockHolders := map[string][]player.ShareInterface{"majority": {}, "minority": {}}
	stockHolders := g.getStockHolders(corp)

	if len(stockHolders) == 1 {
		return map[string][]player.ShareInterface{
			"majority": {stockHolders[0]},
			"minority": {stockHolders[0]},
		}
	}

	mainStockHolders["majority"] = stockHoldersWithSameAmount(0, stockHolders, corp)
	if len(mainStockHolders["majority"]) > 1 {
		return mainStockHolders
	}
	mainStockHolders["minority"] = stockHoldersWithSameAmount(1, stockHolders, corp)
	return mainStockHolders
}

// Loop stockHolders from start to get all stock holders with the same amount of shares for
// the passed corporation
func stockHoldersWithSameAmount(start int, stockHolders []player.ShareInterface, corp corporation.Interface) []player.ShareInterface {
	group := []player.ShareInterface{stockHolders[start]}

	i := start + 1
	for i < len(stockHolders) && stockHolders[start].Shares(corp) == stockHolders[i].Shares(corp) {
		group = append(group, stockHolders[i])
		i++
	}
	return group
}

// Get players who have stock of the passed corporation, ordered descendently by number of stock shares
// of that corporation
func (g *Game) getStockHolders(corp corporation.Interface) []player.ShareInterface {
	var stockHolders []player.ShareInterface
	sharesDesc := func(p1, p2 player.ShareInterface) bool {
		return p1.Shares(corp) > p2.Shares(corp)
	}

	for _, player := range g.players {
		if player.Shares(corp) > 0 {
			stockHolders = append(stockHolders, player)
		}
	}
	player.By(sharesDesc).Sort(stockHolders)
	return stockHolders
}

// Returns true if a tile is permanently unplayable, that is,
// that putting it on the board would merge two or more safe corporations
func (g *Game) isTileUnplayable(tile tileset.Position) bool {
	adjacents := g.board.AdjacentCells(tile)
	safeNeighbours := 0
	for _, adjacent := range adjacents {
		boardCell := g.board.Cell(adjacent)
		if boardCell != board.Empty && boardCell != board.OrphanTile {
			if g.corporations[boardCell].IsSafe() {
				safeNeighbours++
			}
		}
		if safeNeighbours == 2 {
			return true
		}
	}
	return false
}

// Returns true if a tile is temporarily unplayable, that is,
// that putting it on the board would create an 8th corporation
func (g *Game) isTileTemporaryUnplayable(tile tileset.Position) bool {
	if len(g.getActiveCorporations()) < totalCorporations {
		return false
	}
	adjacents := g.board.AdjacentCells(tile)
	for _, adjacent := range adjacents {
		boardCell := g.board.Cell(adjacent)
		if boardCell == board.OrphanTile {
			return true
		}
	}
	return false
}

// Returns player currently in turn
func (g *Game) CurrentPlayer() player.Interface {
	return g.players[g.currentPlayer]
}

func (g *Game) PlayTile(tile tileset.Position) error {
	if _, ok := g.state.(*fsm.PlayTile); !ok {
		return errors.New(ActionNotAllowed)
	}
	if g.isTileTemporaryUnplayable(tile) {
		return errors.New(TileTemporaryUnplayable)
	}
	if err := g.CurrentPlayer().DiscardTile(tile); err != nil {
		return err
	}
	/*
		if merge, tiles := g.board.TileMergeCorporations(tile); merge {
			// move state machine status
		} else */if found, _ := g.board.TileFoundCorporation(tile); found {
		g.state, _ = g.state.ToFoundCorp()
	} else if grow, tiles, corporationId := g.board.TileGrowCorporation(tile); grow {
		g.growCorporation(g.corporations[corporationId], tiles)
	} else {
		g.board.PutTile(tile)
		g.state, _ = g.state.ToBuyStock()
	}
	return nil
}

func (g *Game) growCorporation(corp corporation.Interface, tiles []tileset.Position) {
	g.board.SetTiles(corp, tiles)
	corp.AddTiles(tiles)
	g.state, _ = g.state.ToBuyStock()
}

// Increases the number which specifies the current player
func (g *Game) nextPlayer() {
	g.currentPlayer++
	if g.currentPlayer == len(g.players) {
		g.currentPlayer = 0
	}
}

// Buys stock from corporations
func (g *Game) BuyStock(buys map[int]int) error {
	if _, ok := g.state.(*fsm.BuyStock); !ok {
		return errors.New(ActionNotAllowed)
	}

	if err := g.checkBuy(buys); err != nil {
		return err
	}

	for corporationId, amount := range buys {
		corp := g.corporations[corporationId]
		g.CurrentPlayer().Buy(corp, amount)
	}

	return g.drawTile()
}

func (g *Game) checkBuy(buys map[int]int) error {
	var totalStock, totalPrice int = 0, 0
	for corporationId, amount := range buys {
		corp := g.corporations[corporationId]
		if corp.Size() == 0 {
			return errors.New(StockSharesNotBuyable)
		}
		if amount > corp.Stock() {
			return errors.New(NotEnoughStockShares)
		}
		totalStock += amount
		totalPrice += corp.StockPrice() * amount
	}
	if totalStock > 3 {
		return errors.New(TooManyStockSharesToBuy)
	}

	if totalPrice > g.CurrentPlayer().Cash() {
		return errors.New(NotEnoughCash)
	}
	return nil
}

// A player takes a tile from the facedown cluster to replace
// the one he/she played. This is not done until the end of
// the turn.
func (g *Game) drawTile() error {
	var tile tileset.Position
	var err error
	if tile, err = g.tileset.Draw(); err != nil {
		return err
	}
	g.CurrentPlayer().PickTile(tile)

	if err = g.replaceUnplayableTiles(); err != nil {
		return err
	}

	g.state.ToPlayTile()
	g.nextPlayer()
	return nil
}

// if a player has any permanently
// unplayable tiles that player discard the unplayable tiles
// and draws an equal number of replacement tiles. This can
// only be done once per turn.
func (g *Game) replaceUnplayableTiles() error {
	for _, tile := range g.CurrentPlayer().Tiles() {
		if g.isTileUnplayable(tile) {

			g.CurrentPlayer().DiscardTile(tile)
			if newTile, err := g.tileset.Draw(); err == nil {
				g.CurrentPlayer().PickTile(newTile)
			} else {
				return err
			}
		}
	}

	return nil
}
<commit_msg>Minor change<commit_after>package game

import (
	"errors"
	"github.com/svera/acquire/board"
	"github.com/svera/acquire/corporation"
	"github.com/svera/acquire/fsm"
	"github.com/svera/acquire/player"
	"github.com/svera/acquire/tileset"
)

const totalCorporations = 7
const (
	ActionNotAllowed          = "action_not_allowed"
	WrongNumberPlayers        = "wrong_number_players"
	StockSharesNotBuyable     = "stock_shares_not_buyable"
	NotEnoughStockShares      = "not_enough_stock_shares"
	TileTemporaryUnplayable   = "tile_temporary_unplayable"
	TilePermanentlyUnplayable = "tile_permanently_unplayable"
	NotEnoughCash             = "not_enough_cash"
	TooManyStockSharesToBuy   = "too_many_stock_shares_to_buy"
	CorpIdNotUnique           = "corp_id_not_unique"
	WrongNumberCorpsClass     = "wrong_number_corps_class"
)

type Game struct {
	board         board.Interface
	state         fsm.State
	players       []player.Interface
	corporations  [7]corporation.Interface
	tileset       tileset.Interface
	currentPlayer int
}

func New(
	board board.Interface, players []player.Interface, corporations [7]corporation.Interface, tileset tileset.Interface) (*Game, error) {
	if len(players) < 3 || len(players) > 6 {
		return nil, errors.New(WrongNumberPlayers)
	}
	if !areIdsUnique(corporations) {
		return nil, errors.New(CorpIdNotUnique)
	}
	if !isNumberOfCorpsPerClassRight(corporations) {
		return nil, errors.New(WrongNumberCorpsClass)
	}
	gm := Game{
		board:         board,
		players:       players,
		corporations:  corporations,
		tileset:       tileset,
		currentPlayer: 0,
		state:         &fsm.PlayTile{},
	}
	for _, plyr := range gm.players {
		gm.giveInitialTileset(plyr)
	}

	return &gm, nil
}

// Check that the passed corporations have unique IDs
func areIdsUnique(corporations [7]corporation.Interface) bool {
	for i, corp1 := range corporations {
		if i < len(corporations)-1 {
			for _, corp2 := range corporations[i+1:] {
				if corp1.Id() == corp2.Id() {
					return false
				}
			}
		}
	}
	return true
}

// Check that the number of corporations per class is right
func isNumberOfCorpsPerClassRight(corporations [7]corporation.Interface) bool {
	corpsPerClass := [3]int{0, 0, 0}
	for _, corp := range corporations {
		corpsPerClass[corp.Class()]++
	}
	if corpsPerClass[0] != 2 || corpsPerClass[1] != 3 || corpsPerClass[2] != 2 {
		return false
	}
	return true
}

// Initialises player hand of tiles
func (g *Game) giveInitialTileset(plyr player.Interface) {
	for i := 0; i < 6; i++ {
		tile, _ := g.tileset.Draw()
		plyr.PickTile(tile)
	}
}

// Check if game end conditions are reached
func (g *Game) AreEndConditionsReached() bool {
	active := g.getActiveCorporations()
	if len(active) == 0 {
		return false
	}
	for _, corp := range active {
		if corp.Size() >= 41 {
			return true
		}
		if !corp.IsSafe() {
			return false
		}
	}
	return true
}

// Returns all corporations on the board
func (g *Game) getActiveCorporations() []corporation.Interface {
	active := []corporation.Interface{}
	for _, corp := range g.corporations {
		if corp.IsActive() {
			active = append(active, corp)
		}
	}
	return active
}

// Calculates and returns bonus amounts to be paid to owners of stock of a
// defunct corporation
func (g *Game) PayBonusesForDefunctCorporation(corp corporation.Interface) {
	stockHolders := g.GetMainStockHolders(corp)
	numberMajorityHolders := len(stockHolders["majority"])
	numberMinorityHolders := len(stockHolders["minority"])

	for _, majorityStockHolder := range stockHolders["majority"] {
		majorityStockHolder.ReceiveBonus(corp.MajorityBonus() / int(numberMajorityHolders))
	}
	for _, minorityStockHolder := range stockHolders["minority"] {
		minorityStockHolder.ReceiveBonus(corp.MinorityBonus() / int(numberMinorityHolders))
	}
}

// Taken from the game rules:
// "If only one player owns stock in the defunct corporation, that player gets both bonuses. If there's
// a tie for majority stockholder, add the majority and minority bonuses and divide evenly (the minority
// shareholder gets no bonus. If there's a tie for minority stockholder, split the minority bonus among
// the tied players"
func (g *Game) GetMainStockHolders(corp corporation.Interface) map[string][]player.ShareInterface {
	mainStockHolders := map[string][]player.ShareInterface{"majority": {}, "minority": {}}
	stockHolders := g.getStockHolders(corp)

	if len(stockHolders) == 1 {
		return map[string][]player.ShareInterface{
			"majority": {stockHolders[0]},
			"minority": {stockHolders[0]},
		}
	}

	mainStockHolders["majority"] = stockHoldersWithSameAmount(0, stockHolders, corp)
	if len(mainStockHolders["majority"]) > 1 {
		return mainStockHolders
	}
	mainStockHolders["minority"] = stockHoldersWithSameAmount(1, stockHolders, corp)
	return mainStockHolders
}

// Loop stockHolders from start to get all stock holders with the same amount of shares for
// the passed corporation
func stockHoldersWithSameAmount(start int, stockHolders []player.ShareInterface, corp corporation.Interface) []player.ShareInterface {
	group := []player.ShareInterface{stockHolders[start]}

	i := start + 1
	for i < len(stockHolders) && stockHolders[start].Shares(corp) == stockHolders[i].Shares(corp) {
		group = append(group, stockHolders[i])
		i++
	}
	return group
}

// Get players who have stock of the passed corporation, ordered descendently by number of stock shares
// of that corporation
func (g *Game) getStockHolders(corp corporation.Interface) []player.ShareInterface {
	var stockHolders []player.ShareInterface
	sharesDesc := func(p1, p2 player.ShareInterface) bool {
		return p1.Shares(corp) > p2.Shares(corp)
	}

	for _, player := range g.players {
		if player.Shares(corp) > 0 {
			stockHolders = append(stockHolders, player)
		}
	}
	player.By(sharesDesc).Sort(stockHolders)
	return stockHolders
}

// Returns true if a tile is permanently unplayable, that is,
// that putting it on the board would merge two or more safe corporations
func (g *Game) isTileUnplayable(tile tileset.Position) bool {
	adjacents := g.board.AdjacentCells(tile)
	safeNeighbours := 0
	for _, adjacent := range adjacents {
		boardCell := g.board.Cell(adjacent)
		if boardCell != board.Empty && boardCell != board.OrphanTile {
			if g.corporations[boardCell].IsSafe() {
				safeNeighbours++
			}
		}
		if safeNeighbours == 2 {
			return true
		}
	}
	return false
}

// Returns true if a tile is temporarily unplayable, that is,
// that putting it on the board would create an 8th corporation
func (g *Game) isTileTemporaryUnplayable(tile tileset.Position) bool {
	if len(g.getActiveCorporations()) < totalCorporations {
		return false
	}
	adjacents := g.board.AdjacentCells(tile)
	for _, adjacent := range adjacents {
		boardCell := g.board.Cell(adjacent)
		if boardCell == board.OrphanTile {
			return true
		}
	}
	return false
}

// Returns player currently in turn
func (g *Game) CurrentPlayer() player.Interface {
	return g.players[g.currentPlayer]
}

func (g *Game) PlayTile(tile tileset.Position) error {
	if _, ok := g.state.(*fsm.PlayTile); !ok {
		return errors.New(ActionNotAllowed)
	}
	if g.isTileTemporaryUnplayable(tile) {
		return errors.New(TileTemporaryUnplayable)
	}
	if err := g.CurrentPlayer().DiscardTile(tile); err != nil {
		return err
	}
	/*
		if merge, tiles := g.board.TileMergeCorporations(tile); merge {
			// move state machine status
		} else */if found, _ := g.board.TileFoundCorporation(tile); found {
		g.state, _ = g.state.ToFoundCorp()
	} else if grow, tiles, corporationId := g.board.TileGrowCorporation(tile); grow {
		g.growCorporation(g.corporations[corporationId], tiles)
		g.state, _ = g.state.ToBuyStock()
	} else {
		g.board.PutTile(tile)
		g.state, _ = g.state.ToBuyStock()
	}
	return nil
}

func (g *Game) growCorporation(corp corporation.Interface, tiles []tileset.Position) {
	g.board.SetTiles(corp, tiles)
	corp.AddTiles(tiles)
}

// Increases the number which specifies the current player
func (g *Game) nextPlayer() {
	g.currentPlayer++
	if g.currentPlayer == len(g.players) {
		g.currentPlayer = 0
	}
}

// Buys stock from corporations
func (g *Game) BuyStock(buys map[int]int) error {
	if _, ok := g.state.(*fsm.BuyStock); !ok {
		return errors.New(ActionNotAllowed)
	}

	if err := g.checkBuy(buys); err != nil {
		return err
	}

	for corporationId, amount := range buys {
		corp := g.corporations[corporationId]
		g.CurrentPlayer().Buy(corp, amount)
	}

	return g.drawTile()
}

func (g *Game) checkBuy(buys map[int]int) error {
	var totalStock, totalPrice int = 0, 0
	for corporationId, amount := range buys {
		corp := g.corporations[corporationId]
		if corp.Size() == 0 {
			return errors.New(StockSharesNotBuyable)
		}
		if amount > corp.Stock() {
			return errors.New(NotEnoughStockShares)
		}
		totalStock += amount
		totalPrice += corp.StockPrice() * amount
	}
	if totalStock > 3 {
		return errors.New(TooManyStockSharesToBuy)
	}

	if totalPrice > g.CurrentPlayer().Cash() {
		return errors.New(NotEnoughCash)
	}
	return nil
}

// A player takes a tile from the facedown cluster to replace
// the one he/she played. This is not done until the end of
// the turn.
func (g *Game) drawTile() error {
	var tile tileset.Position
	var err error
	if tile, err = g.tileset.Draw(); err != nil {
		return err
	}
	g.CurrentPlayer().PickTile(tile)

	if err = g.replaceUnplayableTiles(); err != nil {
		return err
	}

	g.state.ToPlayTile()
	g.nextPlayer()
	return nil
}

// if a player has any permanently
// unplayable tiles that player discard the unplayable tiles
// and draws an equal number of replacement tiles. This can
// only be done once per turn.
func (g *Game) replaceUnplayableTiles() error {
	for _, tile := range g.CurrentPlayer().Tiles() {
		if g.isTileUnplayable(tile) {

			g.CurrentPlayer().DiscardTile(tile)
			if newTile, err := g.tileset.Draw(); err == nil {
				g.CurrentPlayer().PickTile(newTile)
			} else {
				return err
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package gotf

import (
	//"log"
	"bytes"
	"encoding/gob"
	"fmt"
	"sync"
	//"errors"
)

type Process struct {
	Addr string
}

type OldViewError struct {
	OldView View
	NewView View
}

func (e OldViewError) Error() string {
	return fmt.Sprint("OLD_VIEW")
}

type WriteOlderError struct {
	WriteTimestamp  int
	ServerTimestamp int
}

func (e WriteOlderError) Error() string {
	return fmt.Sprintf("error: write request has timestamp %v but server has more updated timestamp %v", e.WriteTimestamp, e.ServerTimestamp)
}

func init() {
	gob.Register(new(OldViewError))
	gob.Register(new(WriteOlderError))
}

type updateType string

const (
	Join  updateType = "+"
	Leave updateType = "-"
)

type Update struct {
	Type    updateType
	Process Process
}

type View struct {
	Entries map[Update]bool
	Members map[Process]bool
	mu      sync.RWMutex
}

func NewView() View {
	v := View{}
	v.Entries = make(map[Update]bool)
	v.Members = make(map[Process]bool)
	return v
}

func (v View) String() string {
	v.mu.RLock()
	defer v.mu.RUnlock()

	var b bytes.Buffer
	fmt.Fprintf(&b, "{")
	first := true
	fmt.Fprintf(&b, "{")
	for k, _ := range v.Entries {
		if !first {
			fmt.Fprintf(&b, ", ")
		}
		fmt.Fprintf(&b, "<%v, %v>", k.Type, k.Process)
		first = false
	}
	fmt.Fprintf(&b, "}")
	fmt.Fprintf(&b, "{")
	first = true
	for k, _ := range v.Members {
		if !first {
			fmt.Fprintf(&b, ", ")
		}
		fmt.Fprintf(&b, "%v", k.Addr)
		first = false
	}
	fmt.Fprintf(&b, "}")
	fmt.Fprintf(&b, "}")
	return b.String()
}

func (v *View) Set(v2 View) {
	v.mu.Lock()
	defer v.mu.Unlock()

	v2.mu.RLock()
	defer v2.mu.RUnlock()

	v.Entries = v2.Entries
	v.Members = v2.Members
}

func (v View) Contains(v2 View) bool {
	v.mu.RLock()
	defer v.mu.RUnlock()

	v2.mu.RLock()
	defer v2.mu.RUnlock()

	for k2, _ := range v2.Entries {
		if _, ok := v.Entries[k2]; !ok {
			return false
		}
	}
	return true
}

func (v View) Equal(v2 View) bool {
	return v.Contains(v2) && v2.Contains(v)
}

func (v *View) AddUpdate(u Update) {
	v.mu.Lock()
	defer v.mu.Unlock()

	v.Entries[u] = true

	switch u.Type {
	case Join:
		v.Members[u.Process] = true
	case Leave:
		delete(v.Members, u.Process)
	}
}

func (v View) GetMembers() []Process {
	v.mu.RLock()
	defer v.mu.RUnlock()

	l := make([]Process, 0)
	for k, _ := range v.Members {
		l = append(l, k)
	}
	return l
}

func (v View) QuorunSize() int {
	v.mu.RLock()
	defer v.mu.RUnlock()

	n := len(v.Members) + 1
	return n/2 + n%2
}

func (v View) N() int {
	v.mu.RLock()
	defer v.mu.RUnlock()

	return len(v.Members)
}
<commit_msg>Add F()<commit_after>package gotf

import (
	//"log"
	"bytes"
	"encoding/gob"
	"fmt"
	"sync"
	//"errors"
)

type OldViewError struct {
	OldView View
	NewView View
}

func (e OldViewError) Error() string {
	return fmt.Sprint("OLD_VIEW")
}

type WriteOlderError struct {
	WriteTimestamp  int
	ServerTimestamp int
}

func (e WriteOlderError) Error() string {
	return fmt.Sprintf("error: write request has timestamp %v but server has more updated timestamp %v", e.WriteTimestamp, e.ServerTimestamp)
}

func init() {
	gob.Register(new(OldViewError))
	gob.Register(new(WriteOlderError))
}

type updateType string

const (
	Join  updateType = "+"
	Leave updateType = "-"
)

type Process struct {
	Addr string
}

type Update struct {
	Type    updateType
	Process Process
}

type View struct {
	Entries map[Update]bool
	Members map[Process]bool
	mu      sync.RWMutex
}

func NewView() View {
	v := View{}
	v.Entries = make(map[Update]bool)
	v.Members = make(map[Process]bool)
	return v
}

func (v View) String() string {
	v.mu.RLock()
	defer v.mu.RUnlock()

	var b bytes.Buffer
	fmt.Fprintf(&b, "{")
	first := true
	fmt.Fprintf(&b, "{")
	for k, _ := range v.Entries {
		if !first {
			fmt.Fprintf(&b, ", ")
		}
		fmt.Fprintf(&b, "<%v, %v>", k.Type, k.Process)
		first = false
	}
	fmt.Fprintf(&b, "}")
	fmt.Fprintf(&b, "{")
	first = true
	for k, _ := range v.Members {
		if !first {
			fmt.Fprintf(&b, ", ")
		}
		fmt.Fprintf(&b, "%v", k.Addr)
		first = false
	}
	fmt.Fprintf(&b, "}")
	fmt.Fprintf(&b, "}")
	return b.String()
}

func (v *View) Set(v2 View) {
	v.mu.Lock()
	defer v.mu.Unlock()

	v2.mu.RLock()
	defer v2.mu.RUnlock()

	v.Entries = v2.Entries
	v.Members = v2.Members
}

func (v View) Contains(v2 View) bool {
	v.mu.RLock()
	defer v.mu.RUnlock()

	v2.mu.RLock()
	defer v2.mu.RUnlock()

	for k2, _ := range v2.Entries {
		if _, ok := v.Entries[k2]; !ok {
			return false
		}
	}
	return true
}

func (v View) Equal(v2 View) bool {
	return v.Contains(v2) && v2.Contains(v)
}

func (v *View) AddUpdate(u Update) {
	v.mu.Lock()
	defer v.mu.Unlock()

	v.Entries[u] = true

	switch u.Type {
	case Join:
		v.Members[u.Process] = true
	case Leave:
		delete(v.Members, u.Process)
	}
}

func (v View) GetMembers() []Process {
	v.mu.RLock()
	defer v.mu.RUnlock()

	l := make([]Process, 0)
	for k, _ := range v.Members {
		l = append(l, k)
	}
	return l
}

func (v View) QuorunSize() int {
	v.mu.RLock()
	defer v.mu.RUnlock()

	n := len(v.Members) + 1
	return n/2 + n%2
}

func (v View) N() int {
	v.mu.RLock()
	defer v.mu.RUnlock()

	return len(v.Members)
}

func (v View) F() int {
	v.mu.RLock()
	defer v.mu.RUnlock()

	n := len(v.Members) + 1
	return (n - 1) - (n/2 + n%2)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"regexp"
	"path/filepath"
	"io/ioutil"
	"net/http"
	"errors"
)

type User struct {
	Name string
	Dir string
}

func GetUsers(installationDir string) ([]User, error) {
	userdataDir := filepath.Join(installationDir, "userdata")
	files, err := ioutil.ReadDir(userdataDir)
	if err != nil {
		return nil, err
	}

	users := make([]User, 0)

	for _, userDir := range files {
		userId := userDir.Name()
		userDir := filepath.Join(userdataDir, userId, "config")
		configFile := filepath.Join(userDir, "localconfig.vdf")

		configBytes, err := ioutil.ReadFile(configFile)
		if err != nil {
			return nil, err
		}
		pattern := regexp.MustCompile(`"PersonaName"\s*"(.+?)"`)
		username := pattern.FindStringSubmatch(string(configBytes))[1]
		users = append(users, User{username, userDir})
	}

	return users, nil
}

const urlFormat = `http://steamcommunity.com/id/%v/games?tab=all`
func GetProfile(username string) (string, error) {
	response, err := http.Get(fmt.Sprintf(urlFormat, username))
	if err != nil {
		return "", err
	}

	contentBytes, err := ioutil.ReadAll(response.Body)
	response.Body.Close()
	if err != nil {
		return "", err
	}

	return string(contentBytes), nil
}

type Game struct {
	Id string
	Name string
}

const gamePattern = `\{"appid":\s*(\d+),\s*"name":\s*"(.+?)"`
func GetGames(username string) ([]Game, error) {
	pattern := regexp.MustCompile(gamePattern)

	games := make([]Game, 0)

	profile, err := GetProfile(username)
	if err != nil {
		return nil, err
	}

	for _, groups := range pattern.FindAllStringSubmatch(profile, -1) {
		games = append(games, Game{groups[1], groups[2]})
	}

	return games, nil
}

const imageUrlFormat = `http://cdn.steampowered.com/v/gfx/apps/%v/header.jpg`
func DownloadImage(gameId string, gridDir string) error {
	url := fmt.Sprintf(imageUrlFormat, gameId)
	filename := filepath.Join(gridDir, filepath.Base(url))

	if _, err := os.Stat(filename); err == nil {
		// File already exists, skip it.
		return nil
	}

	response, err := http.Get(url)
	if err != nil {
		return err
	}

	imageBytes, err := ioutil.ReadAll(response.Body)
	response.Body.Close()
	return ioutil.WriteFile(filename, imageBytes, 0666)
}

func GetSteamInstallation() (path string, err error) {
	if len(os.Args) == 2 {
		argDir := os.Args[1]
		_, err := os.Stat(argDir)
		if err == nil {
			return argDir, nil
		} else {
			return "", errors.New("Argument must be a valid Steam directory, or empty for auto detection. Got: " + argDir)
		}
	}

	programFiles86Dir := filepath.Join(os.Getenv("ProgramFiles(x86)"), "Steam")
	if _, err = os.Stat(programFiles86Dir); err == nil {
		return programFiles86Dir, nil
	}

	programFilesDir := filepath.Join(os.Getenv("ProgramFiles"), "Steam")
	if _, err = os.Stat(programFilesDir); err == nil {
		return programFilesDir, nil
	}

	return "", errors.New("Could not find Steam installation folder.")
}

func main() {
	installationDir, err := GetSteamInstallation()
	if err != nil {
		panic(err)
	}

	users, err := GetUsers(installationDir)
	if err != nil {
		panic(err)
	}

	for _, user := range users {
		fmt.Printf("Found user %v. Fetching game list...\n", user.Name)
		continue

		games, err := GetGames(user.Name)
		if err != nil {
			panic(err)
		}

		fmt.Printf("Found %v games. Download images...\n", len(games))
		for _, game := range games {
			gridDir := filepath.Join(user.Dir, "grid")
			err := DownloadImage(game.Id, gridDir)
			fmt.Printf("Downloaded image for %v (%v)\n", game.Name, game.Id)
			if err != nil {
				panic(err)
			}
		}
	}
}
<commit_msg>Add PrintProgress function<commit_after>package main

import (
	"fmt"
	"os"
	"regexp"
	"path/filepath"
	"io/ioutil"
	"net/http"
	"errors"
)

type User struct {
	Name string
	Dir string
}

func GetUsers(installationDir string) ([]User, error) {
	userdataDir := filepath.Join(installationDir, "userdata")
	files, err := ioutil.ReadDir(userdataDir)
	if err != nil {
		return nil, err
	}

	users := make([]User, 0)

	for _, userDir := range files {
		userId := userDir.Name()
		userDir := filepath.Join(userdataDir, userId, "config")
		configFile := filepath.Join(userDir, "localconfig.vdf")

		configBytes, err := ioutil.ReadFile(configFile)
		if err != nil {
			return nil, err
		}
		pattern := regexp.MustCompile(`"PersonaName"\s*"(.+?)"`)
		username := pattern.FindStringSubmatch(string(configBytes))[1]
		users = append(users, User{username, userDir})
	}

	return users, nil
}

const urlFormat = `http://steamcommunity.com/id/%v/games?tab=all`
func GetProfile(username string) (string, error) {
	response, err := http.Get(fmt.Sprintf(urlFormat, username))
	if err != nil {
		return "", err
	}

	contentBytes, err := ioutil.ReadAll(response.Body)
	response.Body.Close()
	if err != nil {
		return "", err
	}

	return string(contentBytes), nil
}

type Game struct {
	Id string
	Name string
}

const gamePattern = `\{"appid":\s*(\d+),\s*"name":\s*"(.+?)"`
func GetGames(username string) ([]Game, error) {
	pattern := regexp.MustCompile(gamePattern)

	games := make([]Game, 0)

	profile, err := GetProfile(username)
	if err != nil {
		return nil, err
	}

	for _, groups := range pattern.FindAllStringSubmatch(profile, -1) {
		games = append(games, Game{groups[1], groups[2]})
	}

	return games, nil
}

const imageUrlFormat = `http://cdn.steampowered.com/v/gfx/apps/%v/header.jpg`
func DownloadImage(gameId string, gridDir string) error {
	url := fmt.Sprintf(imageUrlFormat, gameId)
	filename := filepath.Join(gridDir, filepath.Base(url))

	if _, err := os.Stat(filename); err == nil {
		// File already exists, skip it.
		return nil
	}

	response, err := http.Get(url)
	if err != nil {
		return err
	}

	imageBytes, err := ioutil.ReadAll(response.Body)
	response.Body.Close()
	return ioutil.WriteFile(filename, imageBytes, 0666)
}

func GetSteamInstallation() (path string, err error) {
	if len(os.Args) == 2 {
		argDir := os.Args[1]
		_, err := os.Stat(argDir)
		if err == nil {
			return argDir, nil
		} else {
			return "", errors.New("Argument must be a valid Steam directory, or empty for auto detection. Got: " + argDir)
		}
	}

	programFiles86Dir := filepath.Join(os.Getenv("ProgramFiles(x86)"), "Steam")
	if _, err = os.Stat(programFiles86Dir); err == nil {
		return programFiles86Dir, nil
	}

	programFilesDir := filepath.Join(os.Getenv("ProgramFiles"), "Steam")
	if _, err = os.Stat(programFilesDir); err == nil {
		return programFilesDir, nil
	}

	return "", errors.New("Could not find Steam installation folder.")
}

func PrintProgress(current int, total int) {
	fmt.Print("\r[")
	printedHead := false
	for i := 0; i < 40; i++ {
		part := int(float64(i) * (float64(total) / 40.0))
		if part < current {
			fmt.Print("=")
		} else if !printedHead {
			printedHead = true
			fmt.Print(">")
		} else {
			fmt.Print(" ")
		}
	}
	fmt.Printf("] (%v/%v)", current, total)
}

func main() {
	installationDir, err := GetSteamInstallation()
	if err != nil {
		panic(err)
	}

	users, err := GetUsers(installationDir)
	if err != nil {
		panic(err)
	}

	for _, user := range users {
		fmt.Printf("Found user %v. Fetching game list...\n", user.Name)
		continue

		games, err := GetGames(user.Name)
		if err != nil {
			panic(err)
		}

		fmt.Printf("Found %v games. Downloading images...\n", len(games))
		for i, game := range games {
			PrintProgress(i, len(games))
			gridDir := filepath.Join(user.Dir, "grid")
			err := DownloadImage(game.Id, gridDir)
			if err != nil {
				panic(err)
			}
		}
	}
}
<|endoftext|>


<commit_before>package sudoku

import (
	"io/ioutil"
	"log"
	"strings"
	"sync"
)

//TODO: Support non-squared DIMS (logic in Block() would need updating)
const BLOCK_DIM = 3
const DIM = BLOCK_DIM * BLOCK_DIM

//Constants for important aspects of the accepted format
const (
	ALT_0       = "."
	ROW_SEP     = "\n"
	COL_SEP     = "|"
	ALT_COL_SEP = "||"
)

//Constants for how important parts of the diagram are printed out
const (
	DIAGRAM_IMPOSSIBLE = " "
	DIAGRAM_RIGHT      = "|"
	DIAGRAM_BOTTOM     = "-"
	DIAGRAM_CORNER     = "+"
	DIAGRAM_NUMBER     = "•"
)

//Grid is the primary type in the package. It represents a DIMxDIM sudoku puzzle that can
//be acted on in various ways.
type Grid struct {
	initalized       bool
	cells            [DIM * DIM]Cell
	rows             [DIM]CellList
	cols             [DIM]CellList
	blocks           [DIM]CellList
	cacheRowMutex    sync.RWMutex
	cacheColMutex    sync.RWMutex
	cacheBlockMutext sync.RWMutex
	theQueue         *finiteQueue
	numFilledCells   int
	invalidCells     map[*Cell]bool
	cachedSolutions  []*Grid
	cachedDifficulty float64
}

var gridCache chan *Grid

const _MAX_GRIDS = 100

//TODO:Allow num solver threads to be set at runtime
const _NUM_SOLVER_THREADS = 4

func init() {
	gridCache = make(chan *Grid, _MAX_GRIDS)
}

func getGrid() *Grid {
	select {
	case grid := <-gridCache:
		return grid
	default:
		return NewGrid()
	}
	return nil
}

func dropGrids() {
	for {
		select {
		case <-gridCache:
			//Keep on going
		default:
			return
		}
	}
}

func returnGrid(grid *Grid) {
	grid.ResetOverrides()
	select {
	case gridCache <- grid:
		//Returned it to the queue.
	default:
		//Drop it on the floor.
	}
}

//NewGrid creates a new, blank grid with all of its cells unfilled.
func NewGrid() *Grid {
	result := &Grid{}

	result.invalidCells = make(map[*Cell]bool)

	i := 0
	for r := 0; r < DIM; r++ {
		for c := 0; c < DIM; c++ {
			result.cells[i] = newCell(result, r, c)
			//The cell can't insert itself because it doesn't know where it will actually live in memory yet.
			i++
		}
	}
	result.initalized = true
	return result
}

func (self *Grid) queue() *finiteQueue {
	if self.theQueue == nil {
		self.theQueue = newFiniteQueue(1, DIM)
		for i := range self.cells {
			//If we did i, cell, cell would just be the temp variable. So we'll grab it via the index.
			self.theQueue.Insert(&self.cells[i])
		}
	}
	return self.theQueue
}

//Done marks the grid as ready to be used by another consumer of it. This potentially allows
//grids to be reused (but not currently).
func (self *Grid) Done() {
	//We're done using this grid; it's okay use to use it again.
	returnGrid(self)
}

//Load takes the string data and parses it into the puzzle. The format is the 'sdk' format:
//a `.` marks an empty cell, a number denotes a filled cell, and a newline marks a new row.
//Load also accepts other variations on the sdk format, including one with a `|` between each cell.
//For other sudoku formats see the sdkconverter subpackage.
func (self *Grid) Load(data string) {
	//All col separators are basically just to make it easier to read. Remove them.
	data = strings.Replace(data, ALT_COL_SEP, COL_SEP, -1)
	data = strings.Replace(data, COL_SEP, "", -1)
	//TODO: shouldn't we have more error checking, like for wrong dimensions?
	for r, row := range strings.Split(data, ROW_SEP) {
		for c, data := range strings.Split(row, "") {
			cell := self.Cell(r, c)
			cell.load(data)
		}
	}
}

//LoadFromFile is a simple convenience wrapper around Load that loads a grid based on the contents
//of the file at the given path.
func (self *Grid) LoadFromFile(path string) bool {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return false
	}
	self.Load(string(data))
	return true
}

//Copy returns a new grid that has all of the same numbers and excludes filled in it.
func (self *Grid) Copy() *Grid {
	//TODO: ideally we'd have some kind of smart SparseGrid or something that we can return.
	result := NewGrid()
	result.replace(self)
	return result
}

//Copies the state of the other grid into self, so they look the same.
func (self *Grid) replace(other *Grid) {
	self.Load(other.DataString())
	//Also set excludes
	for _, otherCell := range other.cells {
		selfCell := otherCell.InGrid(self)
		for i := 0; i < DIM; i++ {
			selfCell.excluded[i] = otherCell.excluded[i]
		}
	}
}

func (self *Grid) transpose() *Grid {
	//Returns a new grid that is the same as this grid (ignoring overrides, which are nulled), but with rows and cols swapped.
	result := NewGrid()
	for r := 0; r < DIM; r++ {
		for c := 0; c < DIM; c++ {
			original := self.Cell(r, c)
			copy := result.Cell(c, r)
			copy.SetNumber(original.Number())
		}
	}
	return result
}

func (self *Grid) ResetOverrides() {
	for _, cell := range self.cells {
		cell.ResetExcludes()
	}
}

func (self *Grid) Row(index int) CellList {
	if index < 0 || index >= DIM {
		log.Println("Invalid index passed to Row: ", index)
		return nil
	}
	self.cacheRowMutex.RLock()
	result := self.rows[index]
	self.cacheRowMutex.RUnlock()
	if result == nil {
		self.cacheRowMutex.Lock()
		self.rows[index] = self.cellList(index, 0, index, DIM-1)
		result = self.rows[index]
		self.cacheRowMutex.Unlock()
	}
	return result
}

func (self *Grid) Col(index int) CellList {
	if index < 0 || index >= DIM {
		log.Println("Invalid index passed to Col: ", index)
		return nil
	}
	self.cacheColMutex.RLock()
	result := self.cols[index]
	self.cacheColMutex.RUnlock()

	if result == nil {
		self.cacheColMutex.Lock()
		self.cols[index] = self.cellList(0, index, DIM-1, index)
		result = self.cols[index]
		self.cacheColMutex.Unlock()
	}
	return result
}

func (self *Grid) Block(index int) CellList {
	if index < 0 || index >= DIM {
		log.Println("Invalid index passed to Block: ", index)
		return nil
	}

	self.cacheBlockMutext.RLock()
	result := self.blocks[index]
	self.cacheBlockMutext.RUnlock()

	if result == nil {
		topRow, topCol, bottomRow, bottomCol := self.blockExtents(index)
		self.cacheBlockMutext.Lock()
		self.blocks[index] = self.cellList(topRow, topCol, bottomRow, bottomCol)
		result = self.blocks[index]
		self.cacheBlockMutext.Unlock()
	}
	return result
}

func (self *Grid) blockExtents(index int) (topRow int, topCol int, bottomRow int, bottomCol int) {
	//Conceptually, we'll pretend like the grid is made up of blocks that are arrayed with row/column
	//Once we find the block r/c, we'll multiply by the actual dim to get the upper left corner.

	blockCol := index % BLOCK_DIM
	blockRow := (index - blockCol) / BLOCK_DIM

	col := blockCol * BLOCK_DIM
	row := blockRow * BLOCK_DIM

	return row, col, row + BLOCK_DIM - 1, col + BLOCK_DIM - 1
}

func (self *Grid) blockForCell(row int, col int) int {
	blockCol := col / BLOCK_DIM
	blockRow := row / BLOCK_DIM
	return blockRow*BLOCK_DIM + blockCol
}

func (self *Grid) blockHasNeighbors(index int) (top bool, right bool, bottom bool, left bool) {
	topRow, topCol, bottomRow, bottomCol := self.blockExtents(index)
	top = topRow != 0
	bottom = bottomRow != DIM-1
	left = topCol != 0
	right = bottomCol != DIM-1
	return
}

func (self *Grid) Cell(row int, col int) *Cell {
	index := row*DIM + col
	if index >= DIM*DIM || index < 0 {
		log.Println("Invalid row/col index passed to Cell: ", row, ", ", col)
		return nil
	}
	return &self.cells[index]
}

func (self *Grid) cellList(rowOne int, colOne int, rowTwo int, colTwo int) CellList {
	length := (rowTwo - rowOne + 1) * (colTwo - colOne + 1)
	result := make([]*Cell, length)
	currentRow := rowOne
	currentCol := colOne
	for i := 0; i < length; i++ {
		result[i] = self.Cell(currentRow, currentCol)
		if colTwo > currentCol {
			currentCol++
		} else {
			if rowTwo > currentRow {
				currentRow++
				currentCol = colOne
			} else {
				//This should only happen the last time through the loop.
			}
		}
	}
	return CellList(result)
}

func (self *Grid) Solved() bool {
	//TODO: use numFilledCells here.
	if self.numFilledCells != len(self.cells) {
		return false
	}
	return !self.Invalid()
}

//We separate this so that we can call it repeatedly within fillSimpleCells, and because we know we won't break the more expensive tests.
func (self *Grid) cellsInvalid() bool {
	if len(self.invalidCells) > 0 {
		return true
	}
	return false
}

//Grid will never be invalid based on moves made by the solver; it will detect times that
//someone called SetNumber with an impossible number after the fact, though.
func (self *Grid) Invalid() bool {
	if self.cellsInvalid() {
		return true
	}
	for i := 0; i < DIM; i++ {
		row := self.Row(i)
		rowCheck := make(map[int]bool)
		for _, cell := range row {
			if cell.Number() == 0 {
				continue
			}
			if rowCheck[cell.Number()] {
				return true
			}
			rowCheck[cell.Number()] = true
		}
		col := self.Col(i)
		colCheck := make(map[int]bool)
		for _, cell := range col {
			if cell.Number() == 0 {
				continue
			}
			if colCheck[cell.Number()] {
				return true
			}
			colCheck[cell.Number()] = true
		}
		block := self.Block(i)
		blockCheck := make(map[int]bool)
		for _, cell := range block {
			if cell.Number() == 0 {
				continue
			}
			if blockCheck[cell.Number()] {
				return true
			}
			blockCheck[cell.Number()] = true
		}
	}
	return false
}

//Called by cells when they notice they are invalid and the grid might not know that.
func (self *Grid) cellIsInvalid(cell *Cell) {
	//Doesn't matter if it was already set.
	self.invalidCells[cell] = true
}

//Called by cells when they notice they are valid and think the grid might not know that.
func (self *Grid) cellIsValid(cell *Cell) {
	delete(self.invalidCells, cell)
}

func (self *Grid) cellModified(cell *Cell) {
	self.cachedSolutions = nil
	self.cachedDifficulty = 0.0
	if cell.Number() == 0 {
		self.numFilledCells--
	} else {
		self.numFilledCells++
	}
}

func (self *Grid) cellRankChanged(cell *Cell) {
	if self.theQueue != nil {
		self.theQueue.Insert(cell)
	}
}

func (self *Grid) rank() int {
	return len(self.cells) - self.numFilledCells
}

func (self *Grid) DataString() string {
	var rows []string
	for r := 0; r < DIM; r++ {
		var row []string
		for c := 0; c < DIM; c++ {
			row = append(row, self.cells[r*DIM+c].dataString())
		}
		rows = append(rows, strings.Join(row, COL_SEP))
	}
	return strings.Join(rows, ROW_SEP)
}

func (self *Grid) String() string {
	var rows []string
	for r := 0; r < DIM; r++ {
		var row []string
		for c := 0; c < DIM; c++ {
			row = append(row, self.cells[r*DIM+c].String())
		}
		rows = append(rows, strings.Join(row, COL_SEP))
	}
	return strings.Join(rows, ROW_SEP)
}

func (self *Grid) Diagram() string {
	var rows []string

	//Generate a block boundary row to use later.
	var blockBoundaryRow string
	{
		var blockBoundarySegments []string
		blockBoundaryBlockPiece := strings.Repeat(DIAGRAM_BOTTOM, BLOCK_DIM*BLOCK_DIM+BLOCK_DIM-1)
		for i := 0; i < BLOCK_DIM; i++ {
			blockBoundarySegments = append(blockBoundarySegments, blockBoundaryBlockPiece)
		}
		blockBoundaryRow = strings.Join(blockBoundarySegments, DIAGRAM_CORNER+DIAGRAM_CORNER)
	}

	for r := 0; r < DIM; r++ {
		var tempRows []string
		tempRows = self.Cell(r, 0).diagramRows()
		for c := 1; c < DIM; c++ {
			cellRows := self.Cell(r, c).diagramRows()
			for i, _ := range tempRows {
				tempRows[i] += cellRows[i]
				//Are we at a block boundary?
				if c%BLOCK_DIM == BLOCK_DIM-1 && c != DIM-1 {
					tempRows[i] += DIAGRAM_RIGHT + DIAGRAM_RIGHT
				}
			}

		}
		rows = append(rows, tempRows...)
		//Are we at a block boundary?
		if r%BLOCK_DIM == BLOCK_DIM-1 && r != DIM-1 {
			rows = append(rows, blockBoundaryRow, blockBoundaryRow)
		}
	}
	return strings.Join(rows, "\n")
}
<commit_msg>Grid.ResetOverrides renamed to Grid.ResetExcludes to match the Cell method name.<commit_after>package sudoku

import (
	"io/ioutil"
	"log"
	"strings"
	"sync"
)

//TODO: Support non-squared DIMS (logic in Block() would need updating)
const BLOCK_DIM = 3
const DIM = BLOCK_DIM * BLOCK_DIM

//Constants for important aspects of the accepted format
const (
	ALT_0       = "."
	ROW_SEP     = "\n"
	COL_SEP     = "|"
	ALT_COL_SEP = "||"
)

//Constants for how important parts of the diagram are printed out
const (
	DIAGRAM_IMPOSSIBLE = " "
	DIAGRAM_RIGHT      = "|"
	DIAGRAM_BOTTOM     = "-"
	DIAGRAM_CORNER     = "+"
	DIAGRAM_NUMBER     = "•"
)

//Grid is the primary type in the package. It represents a DIMxDIM sudoku puzzle that can
//be acted on in various ways.
type Grid struct {
	initalized       bool
	cells            [DIM * DIM]Cell
	rows             [DIM]CellList
	cols             [DIM]CellList
	blocks           [DIM]CellList
	cacheRowMutex    sync.RWMutex
	cacheColMutex    sync.RWMutex
	cacheBlockMutext sync.RWMutex
	theQueue         *finiteQueue
	numFilledCells   int
	invalidCells     map[*Cell]bool
	cachedSolutions  []*Grid
	cachedDifficulty float64
}

var gridCache chan *Grid

const _MAX_GRIDS = 100

//TODO:Allow num solver threads to be set at runtime
const _NUM_SOLVER_THREADS = 4

func init() {
	gridCache = make(chan *Grid, _MAX_GRIDS)
}

func getGrid() *Grid {
	select {
	case grid := <-gridCache:
		return grid
	default:
		return NewGrid()
	}
	return nil
}

func dropGrids() {
	for {
		select {
		case <-gridCache:
			//Keep on going
		default:
			return
		}
	}
}

func returnGrid(grid *Grid) {
	grid.ResetExcludes()
	select {
	case gridCache <- grid:
		//Returned it to the queue.
	default:
		//Drop it on the floor.
	}
}

//NewGrid creates a new, blank grid with all of its cells unfilled.
func NewGrid() *Grid {
	result := &Grid{}

	result.invalidCells = make(map[*Cell]bool)

	i := 0
	for r := 0; r < DIM; r++ {
		for c := 0; c < DIM; c++ {
			result.cells[i] = newCell(result, r, c)
			//The cell can't insert itself because it doesn't know where it will actually live in memory yet.
			i++
		}
	}
	result.initalized = true
	return result
}

func (self *Grid) queue() *finiteQueue {
	if self.theQueue == nil {
		self.theQueue = newFiniteQueue(1, DIM)
		for i := range self.cells {
			//If we did i, cell, cell would just be the temp variable. So we'll grab it via the index.
			self.theQueue.Insert(&self.cells[i])
		}
	}
	return self.theQueue
}

//Done marks the grid as ready to be used by another consumer of it. This potentially allows
//grids to be reused (but not currently).
func (self *Grid) Done() {
	//We're done using this grid; it's okay use to use it again.
	returnGrid(self)
}

//Load takes the string data and parses it into the puzzle. The format is the 'sdk' format:
//a `.` marks an empty cell, a number denotes a filled cell, and a newline marks a new row.
//Load also accepts other variations on the sdk format, including one with a `|` between each cell.
//For other sudoku formats see the sdkconverter subpackage.
func (self *Grid) Load(data string) {
	//All col separators are basically just to make it easier to read. Remove them.
	data = strings.Replace(data, ALT_COL_SEP, COL_SEP, -1)
	data = strings.Replace(data, COL_SEP, "", -1)
	//TODO: shouldn't we have more error checking, like for wrong dimensions?
	for r, row := range strings.Split(data, ROW_SEP) {
		for c, data := range strings.Split(row, "") {
			cell := self.Cell(r, c)
			cell.load(data)
		}
	}
}

//LoadFromFile is a simple convenience wrapper around Load that loads a grid based on the contents
//of the file at the given path.
func (self *Grid) LoadFromFile(path string) bool {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return false
	}
	self.Load(string(data))
	return true
}

//Copy returns a new grid that has all of the same numbers and excludes filled in it.
func (self *Grid) Copy() *Grid {
	//TODO: ideally we'd have some kind of smart SparseGrid or something that we can return.
	result := NewGrid()
	result.replace(self)
	return result
}

//Copies the state of the other grid into self, so they look the same.
func (self *Grid) replace(other *Grid) {
	self.Load(other.DataString())
	//Also set excludes
	for _, otherCell := range other.cells {
		selfCell := otherCell.InGrid(self)
		for i := 0; i < DIM; i++ {
			selfCell.excluded[i] = otherCell.excluded[i]
		}
	}
}

func (self *Grid) transpose() *Grid {
	//Returns a new grid that is the same as this grid (ignoring overrides, which are nulled), but with rows and cols swapped.
	result := NewGrid()
	for r := 0; r < DIM; r++ {
		for c := 0; c < DIM; c++ {
			original := self.Cell(r, c)
			copy := result.Cell(c, r)
			copy.SetNumber(original.Number())
		}
	}
	return result
}

//ResetExcludes calls ResetExcludes on all cells in the grid. See Cell.SetExcluded for more about excludes.
func (self *Grid) ResetExcludes() {
	for _, cell := range self.cells {
		cell.ResetExcludes()
	}
}

func (self *Grid) Row(index int) CellList {
	if index < 0 || index >= DIM {
		log.Println("Invalid index passed to Row: ", index)
		return nil
	}
	self.cacheRowMutex.RLock()
	result := self.rows[index]
	self.cacheRowMutex.RUnlock()
	if result == nil {
		self.cacheRowMutex.Lock()
		self.rows[index] = self.cellList(index, 0, index, DIM-1)
		result = self.rows[index]
		self.cacheRowMutex.Unlock()
	}
	return result
}

func (self *Grid) Col(index int) CellList {
	if index < 0 || index >= DIM {
		log.Println("Invalid index passed to Col: ", index)
		return nil
	}
	self.cacheColMutex.RLock()
	result := self.cols[index]
	self.cacheColMutex.RUnlock()

	if result == nil {
		self.cacheColMutex.Lock()
		self.cols[index] = self.cellList(0, index, DIM-1, index)
		result = self.cols[index]
		self.cacheColMutex.Unlock()
	}
	return result
}

func (self *Grid) Block(index int) CellList {
	if index < 0 || index >= DIM {
		log.Println("Invalid index passed to Block: ", index)
		return nil
	}

	self.cacheBlockMutext.RLock()
	result := self.blocks[index]
	self.cacheBlockMutext.RUnlock()

	if result == nil {
		topRow, topCol, bottomRow, bottomCol := self.blockExtents(index)
		self.cacheBlockMutext.Lock()
		self.blocks[index] = self.cellList(topRow, topCol, bottomRow, bottomCol)
		result = self.blocks[index]
		self.cacheBlockMutext.Unlock()
	}
	return result
}

func (self *Grid) blockExtents(index int) (topRow int, topCol int, bottomRow int, bottomCol int) {
	//Conceptually, we'll pretend like the grid is made up of blocks that are arrayed with row/column
	//Once we find the block r/c, we'll multiply by the actual dim to get the upper left corner.

	blockCol := index % BLOCK_DIM
	blockRow := (index - blockCol) / BLOCK_DIM

	col := blockCol * BLOCK_DIM
	row := blockRow * BLOCK_DIM

	return row, col, row + BLOCK_DIM - 1, col + BLOCK_DIM - 1
}

func (self *Grid) blockForCell(row int, col int) int {
	blockCol := col / BLOCK_DIM
	blockRow := row / BLOCK_DIM
	return blockRow*BLOCK_DIM + blockCol
}

func (self *Grid) blockHasNeighbors(index int) (top bool, right bool, bottom bool, left bool) {
	topRow, topCol, bottomRow, bottomCol := self.blockExtents(index)
	top = topRow != 0
	bottom = bottomRow != DIM-1
	left = topCol != 0
	right = bottomCol != DIM-1
	return
}

func (self *Grid) Cell(row int, col int) *Cell {
	index := row*DIM + col
	if index >= DIM*DIM || index < 0 {
		log.Println("Invalid row/col index passed to Cell: ", row, ", ", col)
		return nil
	}
	return &self.cells[index]
}

func (self *Grid) cellList(rowOne int, colOne int, rowTwo int, colTwo int) CellList {
	length := (rowTwo - rowOne + 1) * (colTwo - colOne + 1)
	result := make([]*Cell, length)
	currentRow := rowOne
	currentCol := colOne
	for i := 0; i < length; i++ {
		result[i] = self.Cell(currentRow, currentCol)
		if colTwo > currentCol {
			currentCol++
		} else {
			if rowTwo > currentRow {
				currentRow++
				currentCol = colOne
			} else {
				//This should only happen the last time through the loop.
			}
		}
	}
	return CellList(result)
}

func (self *Grid) Solved() bool {
	//TODO: use numFilledCells here.
	if self.numFilledCells != len(self.cells) {
		return false
	}
	return !self.Invalid()
}

//We separate this so that we can call it repeatedly within fillSimpleCells, and because we know we won't break the more expensive tests.
func (self *Grid) cellsInvalid() bool {
	if len(self.invalidCells) > 0 {
		return true
	}
	return false
}

//Grid will never be invalid based on moves made by the solver; it will detect times that
//someone called SetNumber with an impossible number after the fact, though.
func (self *Grid) Invalid() bool {
	if self.cellsInvalid() {
		return true
	}
	for i := 0; i < DIM; i++ {
		row := self.Row(i)
		rowCheck := make(map[int]bool)
		for _, cell := range row {
			if cell.Number() == 0 {
				continue
			}
			if rowCheck[cell.Number()] {
				return true
			}
			rowCheck[cell.Number()] = true
		}
		col := self.Col(i)
		colCheck := make(map[int]bool)
		for _, cell := range col {
			if cell.Number() == 0 {
				continue
			}
			if colCheck[cell.Number()] {
				return true
			}
			colCheck[cell.Number()] = true
		}
		block := self.Block(i)
		blockCheck := make(map[int]bool)
		for _, cell := range block {
			if cell.Number() == 0 {
				continue
			}
			if blockCheck[cell.Number()] {
				return true
			}
			blockCheck[cell.Number()] = true
		}
	}
	return false
}

//Called by cells when they notice they are invalid and the grid might not know that.
func (self *Grid) cellIsInvalid(cell *Cell) {
	//Doesn't matter if it was already set.
	self.invalidCells[cell] = true
}

//Called by cells when they notice they are valid and think the grid might not know that.
func (self *Grid) cellIsValid(cell *Cell) {
	delete(self.invalidCells, cell)
}

func (self *Grid) cellModified(cell *Cell) {
	self.cachedSolutions = nil
	self.cachedDifficulty = 0.0
	if cell.Number() == 0 {
		self.numFilledCells--
	} else {
		self.numFilledCells++
	}
}

func (self *Grid) cellRankChanged(cell *Cell) {
	if self.theQueue != nil {
		self.theQueue.Insert(cell)
	}
}

func (self *Grid) rank() int {
	return len(self.cells) - self.numFilledCells
}

func (self *Grid) DataString() string {
	var rows []string
	for r := 0; r < DIM; r++ {
		var row []string
		for c := 0; c < DIM; c++ {
			row = append(row, self.cells[r*DIM+c].dataString())
		}
		rows = append(rows, strings.Join(row, COL_SEP))
	}
	return strings.Join(rows, ROW_SEP)
}

func (self *Grid) String() string {
	var rows []string
	for r := 0; r < DIM; r++ {
		var row []string
		for c := 0; c < DIM; c++ {
			row = append(row, self.cells[r*DIM+c].String())
		}
		rows = append(rows, strings.Join(row, COL_SEP))
	}
	return strings.Join(rows, ROW_SEP)
}

func (self *Grid) Diagram() string {
	var rows []string

	//Generate a block boundary row to use later.
	var blockBoundaryRow string
	{
		var blockBoundarySegments []string
		blockBoundaryBlockPiece := strings.Repeat(DIAGRAM_BOTTOM, BLOCK_DIM*BLOCK_DIM+BLOCK_DIM-1)
		for i := 0; i < BLOCK_DIM; i++ {
			blockBoundarySegments = append(blockBoundarySegments, blockBoundaryBlockPiece)
		}
		blockBoundaryRow = strings.Join(blockBoundarySegments, DIAGRAM_CORNER+DIAGRAM_CORNER)
	}

	for r := 0; r < DIM; r++ {
		var tempRows []string
		tempRows = self.Cell(r, 0).diagramRows()
		for c := 1; c < DIM; c++ {
			cellRows := self.Cell(r, c).diagramRows()
			for i, _ := range tempRows {
				tempRows[i] += cellRows[i]
				//Are we at a block boundary?
				if c%BLOCK_DIM == BLOCK_DIM-1 && c != DIM-1 {
					tempRows[i] += DIAGRAM_RIGHT + DIAGRAM_RIGHT
				}
			}

		}
		rows = append(rows, tempRows...)
		//Are we at a block boundary?
		if r%BLOCK_DIM == BLOCK_DIM-1 && r != DIM-1 {
			rows = append(rows, blockBoundaryRow, blockBoundaryRow)
		}
	}
	return strings.Join(rows, "\n")
}
<|endoftext|>