<commit_before>package spvwallet

import (
	"fmt"
	"github.com/btcsuite/btcd/blockchain"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/wire"
	"math/big"
	"sort"
	"sync"
	"time"
)

// Blockchain settings.  These are kindof Bitcoin specific, but not contained in
// chaincfg.Params so they'll go here.  If you're into the [ANN]altcoin scene,
// you may want to paramaterize these constants.
const (
	targetTimespan      = time.Hour * 24 * 14
	targetSpacing       = time.Minute * 10
	epochLength         = int32(targetTimespan / targetSpacing) // 2016
	maxDiffAdjust       = 4
	minRetargetTimespan = int64(targetTimespan / maxDiffAdjust)
	maxRetargetTimespan = int64(targetTimespan * maxDiffAdjust)
	medianTimeBlocks    = 11
)

type ChainState int

const (
	SYNCING = 0
	WAITING = 1
)

// Wrapper around Headers implementation that handles all blockchain operations
type Blockchain struct {
	lock   *sync.Mutex
	params *chaincfg.Params
	db     Headers
	state  ChainState
}

func NewBlockchain(filePath string, walletCreationDate time.Time, params *chaincfg.Params) (*Blockchain, error) {
	hdb, err := NewHeaderDB(filePath)
	if err != nil {
		return nil, err
	}
	b := &Blockchain{
		lock:   new(sync.Mutex),
		params: params,
		db:     hdb,
	}

	h, err := b.db.Height()
	if h == 0 || err != nil {
		log.Info("Initializing headers db with checkpoints")
		checkpoint := GetCheckpoint(walletCreationDate, params)
		// Put the checkpoint to the db
		sh := StoredHeader{
			header:    checkpoint.Header,
			height:    checkpoint.Height,
			totalWork: big.NewInt(0),
		}
		err := b.db.Put(sh, true)
		if err != nil {
			return nil, err
		}
	}
	return b, nil
}

func (b *Blockchain) CommitHeader(header wire.BlockHeader) (bool, *StoredHeader, uint32, error) {
	b.lock.Lock()
	defer b.lock.Unlock()
	newTip := false
	var commonAncestor *StoredHeader
	// Fetch our current best header from the db
	bestHeader, err := b.db.GetBestHeader()
	if err != nil {
		return false, nil, 0, err
	}
	tipHash := bestHeader.header.BlockHash()
	var parentHeader StoredHeader

	// If the tip is also the parent of this header, then we can save a database read by skipping
	// the lookup of the parent header. Otherwise (ophan?) we need to fetch the parent.
	if header.PrevBlock.IsEqual(&tipHash) {
		parentHeader = bestHeader
	} else {
		parentHeader, err = b.db.GetPreviousHeader(header)
		if err != nil {
			return false, nil, 0, fmt.Errorf("Header %s does not extend any known headers", header.BlockHash().String())
		}
	}
	valid := b.CheckHeader(header, parentHeader)
	if !valid {
		return false, nil, 0, nil
	}
	// If this block is already the tip, return
	headerHash := header.BlockHash()
	if tipHash.IsEqual(&headerHash) {
		return newTip, nil, 0, nil
	}
	// Add the work of this header to the total work stored at the previous header
	cumulativeWork := new(big.Int).Add(parentHeader.totalWork, blockchain.CalcWork(header.Bits))

	// If the cumulative work is greater than the total work of our best header
	// then we have a new best header. Update the chain tip and check for a reorg.
	if cumulativeWork.Cmp(bestHeader.totalWork) == 1 {
		newTip = true
		prevHash := parentHeader.header.BlockHash()
		// If this header is not extending the previous best header then we have a reorg.
		if !tipHash.IsEqual(&prevHash) {
			commonAncestor, err = b.GetCommonAncestor(StoredHeader{header: header, height: parentHeader.height + 1}, bestHeader)
			if err != nil {
				log.Errorf("Error calculating common ancestor: %s", err.Error())
				return newTip, commonAncestor, 0, err
			}
			log.Warningf("REORG!!! REORG!!! REORG!!! At block %d, Wiped out %d blocks", int(bestHeader.height), int(bestHeader.height-commonAncestor.height))
		}
	}
	newHeight := parentHeader.height + 1
	// Put the header to the database
	err = b.db.Put(StoredHeader{
		header:    header,
		height:    newHeight,
		totalWork: cumulativeWork,
	}, newTip)
	if err != nil {
		return newTip, commonAncestor, 0, err
	}
	return newTip, commonAncestor, newHeight, nil
}

func (b *Blockchain) CheckHeader(header wire.BlockHeader, prevHeader StoredHeader) bool {
	// Get hash of n-1 header
	prevHash := prevHeader.header.BlockHash()
	height := prevHeader.height

	// Check if headers link together.  That whole 'blockchain' thing.
	if prevHash.IsEqual(&header.PrevBlock) == false {
		log.Errorf("Headers %d and %d don't link.\n", height, height+1)
		return false
	}

	// Check the header meets the difficulty requirement
	if !b.params.ReduceMinDifficulty {
		diffTarget, err := b.calcRequiredWork(header, int32(height+1), prevHeader)
		if err != nil {
			log.Errorf("Error calclating difficulty", err)
			return false
		}
		if header.Bits != diffTarget {
			log.Warningf("Block %d %s incorrect difficulty.  Read %d, expect %d\n",
				height+1, header.BlockHash().String(), header.Bits, diffTarget)
			return false
		}
	}

	// Check if there's a valid proof of work.  That whole "Bitcoin" thing.
	if !checkProofOfWork(header, b.params) {
		log.Debugf("Block %d bad proof of work.\n", height+1)
		return false
	}

	return true // it must have worked if there's no errors and got to the end.
}

// Get the PoW target this block should meet. We may need to handle a difficulty adjustment
// or testnet difficulty rules.
func (b *Blockchain) calcRequiredWork(header wire.BlockHeader, height int32, prevHeader StoredHeader) (uint32, error) {
	// If this is not a difficulty adjustment period
	if height%epochLength != 0 {
		// If we are on testnet
		if b.params.ReduceMinDifficulty {
			// If it's been more than 20 minutes since the last header return the minimum difficulty
			if header.Timestamp.After(prevHeader.header.Timestamp.Add(targetSpacing * 2)) {
				return b.params.PowLimitBits, nil
			} else { // Otherwise return the difficulty of the last block not using special difficulty rules
				for {
					var err error = nil
					for err == nil && int32(prevHeader.height)%epochLength != 0 && prevHeader.header.Bits == b.params.PowLimitBits {
						var sh StoredHeader
						sh, err = b.db.GetPreviousHeader(prevHeader.header)
						// Error should only be non-nil if prevHeader is the checkpoint.
						// In that case we should just return checkpoint bits
						if err == nil {
							prevHeader = sh
						}

					}
					return prevHeader.header.Bits, nil
				}
			}
		}
		// Just return the bits from the last header
		return prevHeader.header.Bits, nil
	}
	// We are on a difficulty adjustment period so we need to correctly calculate the new difficulty.
	epoch, err := b.GetEpoch()
	if err != nil {
		log.Error(err)
		return 0, err
	}
	return calcDiffAdjust(*epoch, prevHeader.header, b.params), nil
}

func (b *Blockchain) CalcMedianTimePast(header *wire.BlockHeader) (time.Time, error) {
	iterNode := StoredHeader{header: *header}
	var err error

	timestamps := make([]int64, medianTimeBlocks)
	numNodes := 0

	for i := 0; i < medianTimeBlocks; i++ {
		numNodes++
		timestamps[i] = iterNode.header.Timestamp.Unix()
		iterNode, err = b.db.GetHeader(header.BlockHash())
		if err != nil {
			return time.Time{}, err
		}
	}
	timestamps = timestamps[:numNodes]
	sort.Sort(timeSorter(timestamps))
	medianTimestamp := timestamps[numNodes/2]
	return time.Unix(medianTimestamp, 0), nil
}

func (b *Blockchain) GetEpoch() (*wire.BlockHeader, error) {
	sh, err := b.db.GetBestHeader()
	if err != nil {
		return &sh.header, err
	}
	for i := 0; i < 2015; i++ {
		sh, err = b.db.GetPreviousHeader(sh.header)
		if err != nil {
			return &sh.header, err
		}
	}
	log.Debug("Epoch", sh.header.BlockHash().String())
	return &sh.header, nil
}

func (b *Blockchain) GetNPrevBlockHashes(n int) []*chainhash.Hash {
	var ret []*chainhash.Hash
	hdr, err := b.db.GetBestHeader()
	if err != nil {
		return ret
	}
	tipSha := hdr.header.BlockHash()
	ret = append(ret, &tipSha)
	for i := 0; i < n-1; i++ {
		hdr, err = b.db.GetPreviousHeader(hdr.header)
		if err != nil {
			return ret
		}
		shaHash := hdr.header.BlockHash()
		ret = append(ret, &shaHash)
	}
	return ret
}

func (b *Blockchain) GetBlockLocatorHashes() []*chainhash.Hash {
	var ret []*chainhash.Hash
	parent, err := b.db.GetBestHeader()
	if err != nil {
		return ret
	}

	rollback := func(parent StoredHeader, n int) (StoredHeader, error) {
		for i := 0; i < n; i++ {
			parent, err = b.db.GetPreviousHeader(parent.header)
			if err != nil {
				return parent, err
			}
		}
		return parent, nil
	}

	step := 1
	start := 0
	for {
		if start >= 9 {
			step *= 2
			start = 0
		}
		hash := parent.header.BlockHash()
		ret = append(ret, &hash)
		if len(ret) == 500 {
			break
		}
		parent, err = rollback(parent, step)
		if err != nil {
			break
		}
		start += 1
	}
	return ret
}

// Returns last header before reorg point
func (b *Blockchain) GetCommonAncestor(bestHeader, prevBestHeader StoredHeader) (*StoredHeader, error) {
	var err error
	rollback := func(parent StoredHeader, n int) (StoredHeader, error) {
		for i := 0; i < n; i++ {
			parent, err = b.db.GetPreviousHeader(parent.header)
			if err != nil {
				return parent, err
			}
		}
		return parent, nil
	}

	majority := bestHeader
	minority := prevBestHeader
	if bestHeader.height > prevBestHeader.height {
		majority, err = rollback(majority, int(bestHeader.height-prevBestHeader.height))
		if err != nil {
			return nil, err
		}
	} else if prevBestHeader.height > bestHeader.height {
		minority, err = rollback(minority, int(prevBestHeader.height-bestHeader.height))
		if err != nil {
			return nil, err
		}
	}

	for {
		majorityHash := majority.header.BlockHash()
		minorityHash := minority.header.BlockHash()
		if majorityHash.IsEqual(&minorityHash) {
			return &majority, nil
		}
		majority, err = b.db.GetPreviousHeader(majority.header)
		if err != nil {
			return nil, err
		}
		minority, err = b.db.GetPreviousHeader(minority.header)
		if err != nil {
			return nil, err
		}
	}
}

func (b *Blockchain) ChainState() ChainState {
	return b.state
}

func (b *Blockchain) SetChainState(state ChainState) {
	b.state = state
}

func (b *Blockchain) Close() {
	b.lock.Lock()
	b.db.Close()
}

// Verifies the header hashes into something lower than specified by the 4-byte bits field.
func checkProofOfWork(header wire.BlockHeader, p *chaincfg.Params) bool {
	target := blockchain.CompactToBig(header.Bits)

	// The target must more than 0.  Why can you even encode negative...
	if target.Sign() <= 0 {
		log.Debugf("Block target %064x is neagtive(??)\n", target.Bytes())
		return false
	}
	// The target must be less than the maximum allowed (difficulty 1)
	if target.Cmp(p.PowLimit) > 0 {
		log.Debugf("Block target %064x is "+
			"higher than max of %064x", target, p.PowLimit.Bytes())
		return false
	}
	// The header hash must be less than the claimed target in the header.
	blockHash := header.BlockHash()
	hashNum := blockchain.HashToBig(&blockHash)
	if hashNum.Cmp(target) > 0 {
		log.Debugf("Block hash %064x is higher than "+
			"required target of %064x", hashNum, target)
		return false
	}
	return true
}

// This function takes in a start and end block header and uses the timestamps in each
// to calculate how much of a difficulty adjustment is needed. It returns a new compact
// difficulty target.
func calcDiffAdjust(start, end wire.BlockHeader, p *chaincfg.Params) uint32 {
	duration := end.Timestamp.UnixNano() - start.Timestamp.UnixNano()
	if duration < minRetargetTimespan {
		log.Debugf("Whoa there, block %s off-scale high 4X diff adjustment!",
			end.BlockHash().String())
		duration = minRetargetTimespan
	} else if duration > maxRetargetTimespan {
		log.Debugf("Uh-oh! block %s off-scale low 0.25X diff adjustment!\n",
			end.BlockHash().String())
		duration = maxRetargetTimespan
	}

	// calculation of new 32-byte difficulty target
	// first turn the previous target into a big int
	prevTarget := blockchain.CompactToBig(end.Bits)
	// new target is old * duration...
	newTarget := new(big.Int).Mul(prevTarget, big.NewInt(duration))
	// divided by 2 weeks
	newTarget.Div(newTarget, big.NewInt(int64(targetTimespan)))

	// clip again if above minimum target (too easy)
	if newTarget.Cmp(p.PowLimit) > 0 {
		newTarget.Set(p.PowLimit)
	}

	return blockchain.BigToCompact(newTarget)
}
<commit_msg>Fix CalcMedianTimePast<commit_after>package spvwallet

import (
	"fmt"
	"github.com/btcsuite/btcd/blockchain"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/wire"
	"math/big"
	"sort"
	"sync"
	"time"
)

// Blockchain settings.  These are kindof Bitcoin specific, but not contained in
// chaincfg.Params so they'll go here.  If you're into the [ANN]altcoin scene,
// you may want to paramaterize these constants.
const (
	targetTimespan      = time.Hour * 24 * 14
	targetSpacing       = time.Minute * 10
	epochLength         = int32(targetTimespan / targetSpacing) // 2016
	maxDiffAdjust       = 4
	minRetargetTimespan = int64(targetTimespan / maxDiffAdjust)
	maxRetargetTimespan = int64(targetTimespan * maxDiffAdjust)
	medianTimeBlocks    = 11
)

type ChainState int

const (
	SYNCING = 0
	WAITING = 1
)

// Wrapper around Headers implementation that handles all blockchain operations
type Blockchain struct {
	lock   *sync.Mutex
	params *chaincfg.Params
	db     Headers
	state  ChainState
}

func NewBlockchain(filePath string, walletCreationDate time.Time, params *chaincfg.Params) (*Blockchain, error) {
	hdb, err := NewHeaderDB(filePath)
	if err != nil {
		return nil, err
	}
	b := &Blockchain{
		lock:   new(sync.Mutex),
		params: params,
		db:     hdb,
	}

	h, err := b.db.Height()
	if h == 0 || err != nil {
		log.Info("Initializing headers db with checkpoints")
		checkpoint := GetCheckpoint(walletCreationDate, params)
		// Put the checkpoint to the db
		sh := StoredHeader{
			header:    checkpoint.Header,
			height:    checkpoint.Height,
			totalWork: big.NewInt(0),
		}
		err := b.db.Put(sh, true)
		if err != nil {
			return nil, err
		}
	}
	return b, nil
}

func (b *Blockchain) CommitHeader(header wire.BlockHeader) (bool, *StoredHeader, uint32, error) {
	b.lock.Lock()
	defer b.lock.Unlock()
	newTip := false
	var commonAncestor *StoredHeader
	// Fetch our current best header from the db
	bestHeader, err := b.db.GetBestHeader()
	if err != nil {
		return false, nil, 0, err
	}
	tipHash := bestHeader.header.BlockHash()
	var parentHeader StoredHeader

	// If the tip is also the parent of this header, then we can save a database read by skipping
	// the lookup of the parent header. Otherwise (ophan?) we need to fetch the parent.
	if header.PrevBlock.IsEqual(&tipHash) {
		parentHeader = bestHeader
	} else {
		parentHeader, err = b.db.GetPreviousHeader(header)
		if err != nil {
			return false, nil, 0, fmt.Errorf("Header %s does not extend any known headers", header.BlockHash().String())
		}
	}
	valid := b.CheckHeader(header, parentHeader)
	if !valid {
		return false, nil, 0, nil
	}
	// If this block is already the tip, return
	headerHash := header.BlockHash()
	if tipHash.IsEqual(&headerHash) {
		return newTip, nil, 0, nil
	}
	// Add the work of this header to the total work stored at the previous header
	cumulativeWork := new(big.Int).Add(parentHeader.totalWork, blockchain.CalcWork(header.Bits))

	// If the cumulative work is greater than the total work of our best header
	// then we have a new best header. Update the chain tip and check for a reorg.
	if cumulativeWork.Cmp(bestHeader.totalWork) == 1 {
		newTip = true
		prevHash := parentHeader.header.BlockHash()
		// If this header is not extending the previous best header then we have a reorg.
		if !tipHash.IsEqual(&prevHash) {
			commonAncestor, err = b.GetCommonAncestor(StoredHeader{header: header, height: parentHeader.height + 1}, bestHeader)
			if err != nil {
				log.Errorf("Error calculating common ancestor: %s", err.Error())
				return newTip, commonAncestor, 0, err
			}
			log.Warningf("REORG!!! REORG!!! REORG!!! At block %d, Wiped out %d blocks", int(bestHeader.height), int(bestHeader.height-commonAncestor.height))
		}
	}
	newHeight := parentHeader.height + 1
	// Put the header to the database
	err = b.db.Put(StoredHeader{
		header:    header,
		height:    newHeight,
		totalWork: cumulativeWork,
	}, newTip)
	if err != nil {
		return newTip, commonAncestor, 0, err
	}
	return newTip, commonAncestor, newHeight, nil
}

func (b *Blockchain) CheckHeader(header wire.BlockHeader, prevHeader StoredHeader) bool {
	// Get hash of n-1 header
	prevHash := prevHeader.header.BlockHash()
	height := prevHeader.height

	// Check if headers link together.  That whole 'blockchain' thing.
	if prevHash.IsEqual(&header.PrevBlock) == false {
		log.Errorf("Headers %d and %d don't link.\n", height, height+1)
		return false
	}

	// Check the header meets the difficulty requirement
	if !b.params.ReduceMinDifficulty {
		diffTarget, err := b.calcRequiredWork(header, int32(height+1), prevHeader)
		if err != nil {
			log.Errorf("Error calclating difficulty", err)
			return false
		}
		if header.Bits != diffTarget {
			log.Warningf("Block %d %s incorrect difficulty.  Read %d, expect %d\n",
				height+1, header.BlockHash().String(), header.Bits, diffTarget)
			return false
		}
	}

	// Check if there's a valid proof of work.  That whole "Bitcoin" thing.
	if !checkProofOfWork(header, b.params) {
		log.Debugf("Block %d bad proof of work.\n", height+1)
		return false
	}

	return true // it must have worked if there's no errors and got to the end.
}

// Get the PoW target this block should meet. We may need to handle a difficulty adjustment
// or testnet difficulty rules.
func (b *Blockchain) calcRequiredWork(header wire.BlockHeader, height int32, prevHeader StoredHeader) (uint32, error) {
	// If this is not a difficulty adjustment period
	if height%epochLength != 0 {
		// If we are on testnet
		if b.params.ReduceMinDifficulty {
			// If it's been more than 20 minutes since the last header return the minimum difficulty
			if header.Timestamp.After(prevHeader.header.Timestamp.Add(targetSpacing * 2)) {
				return b.params.PowLimitBits, nil
			} else { // Otherwise return the difficulty of the last block not using special difficulty rules
				for {
					var err error = nil
					for err == nil && int32(prevHeader.height)%epochLength != 0 && prevHeader.header.Bits == b.params.PowLimitBits {
						var sh StoredHeader
						sh, err = b.db.GetPreviousHeader(prevHeader.header)
						// Error should only be non-nil if prevHeader is the checkpoint.
						// In that case we should just return checkpoint bits
						if err == nil {
							prevHeader = sh
						}

					}
					return prevHeader.header.Bits, nil
				}
			}
		}
		// Just return the bits from the last header
		return prevHeader.header.Bits, nil
	}
	// We are on a difficulty adjustment period so we need to correctly calculate the new difficulty.
	epoch, err := b.GetEpoch()
	if err != nil {
		log.Error(err)
		return 0, err
	}
	return calcDiffAdjust(*epoch, prevHeader.header, b.params), nil
}

func (b *Blockchain) CalcMedianTimePast(header wire.BlockHeader) (time.Time, error) {
	timestamps := make([]int64, medianTimeBlocks)
	numNodes := 0
	iterNode := StoredHeader{header: header}
	var err error

	for i := 0; i < medianTimeBlocks; i++ {
		numNodes++
		timestamps[i] = iterNode.header.Timestamp.Unix()
		iterNode, err = b.db.GetPreviousHeader(iterNode.header)
		if err != nil {
			return time.Time{}, err
		}
	}
	timestamps = timestamps[:numNodes]
	sort.Sort(timeSorter(timestamps))
	medianTimestamp := timestamps[numNodes/2]
	return time.Unix(medianTimestamp, 0), nil
}

func (b *Blockchain) GetEpoch() (*wire.BlockHeader, error) {
	sh, err := b.db.GetBestHeader()
	if err != nil {
		return &sh.header, err
	}
	for i := 0; i < 2015; i++ {
		sh, err = b.db.GetPreviousHeader(sh.header)
		if err != nil {
			return &sh.header, err
		}
	}
	log.Debug("Epoch", sh.header.BlockHash().String())
	return &sh.header, nil
}

func (b *Blockchain) GetNPrevBlockHashes(n int) []*chainhash.Hash {
	var ret []*chainhash.Hash
	hdr, err := b.db.GetBestHeader()
	if err != nil {
		return ret
	}
	tipSha := hdr.header.BlockHash()
	ret = append(ret, &tipSha)
	for i := 0; i < n-1; i++ {
		hdr, err = b.db.GetPreviousHeader(hdr.header)
		if err != nil {
			return ret
		}
		shaHash := hdr.header.BlockHash()
		ret = append(ret, &shaHash)
	}
	return ret
}

func (b *Blockchain) GetBlockLocatorHashes() []*chainhash.Hash {
	var ret []*chainhash.Hash
	parent, err := b.db.GetBestHeader()
	if err != nil {
		return ret
	}

	rollback := func(parent StoredHeader, n int) (StoredHeader, error) {
		for i := 0; i < n; i++ {
			parent, err = b.db.GetPreviousHeader(parent.header)
			if err != nil {
				return parent, err
			}
		}
		return parent, nil
	}

	step := 1
	start := 0
	for {
		if start >= 9 {
			step *= 2
			start = 0
		}
		hash := parent.header.BlockHash()
		ret = append(ret, &hash)
		if len(ret) == 500 {
			break
		}
		parent, err = rollback(parent, step)
		if err != nil {
			break
		}
		start += 1
	}
	return ret
}

// Returns last header before reorg point
func (b *Blockchain) GetCommonAncestor(bestHeader, prevBestHeader StoredHeader) (*StoredHeader, error) {
	var err error
	rollback := func(parent StoredHeader, n int) (StoredHeader, error) {
		for i := 0; i < n; i++ {
			parent, err = b.db.GetPreviousHeader(parent.header)
			if err != nil {
				return parent, err
			}
		}
		return parent, nil
	}

	majority := bestHeader
	minority := prevBestHeader
	if bestHeader.height > prevBestHeader.height {
		majority, err = rollback(majority, int(bestHeader.height-prevBestHeader.height))
		if err != nil {
			return nil, err
		}
	} else if prevBestHeader.height > bestHeader.height {
		minority, err = rollback(minority, int(prevBestHeader.height-bestHeader.height))
		if err != nil {
			return nil, err
		}
	}

	for {
		majorityHash := majority.header.BlockHash()
		minorityHash := minority.header.BlockHash()
		if majorityHash.IsEqual(&minorityHash) {
			return &majority, nil
		}
		majority, err = b.db.GetPreviousHeader(majority.header)
		if err != nil {
			return nil, err
		}
		minority, err = b.db.GetPreviousHeader(minority.header)
		if err != nil {
			return nil, err
		}
	}
}

func (b *Blockchain) ChainState() ChainState {
	return b.state
}

func (b *Blockchain) SetChainState(state ChainState) {
	b.state = state
}

func (b *Blockchain) Close() {
	b.lock.Lock()
	b.db.Close()
}

// Verifies the header hashes into something lower than specified by the 4-byte bits field.
func checkProofOfWork(header wire.BlockHeader, p *chaincfg.Params) bool {
	target := blockchain.CompactToBig(header.Bits)

	// The target must more than 0.  Why can you even encode negative...
	if target.Sign() <= 0 {
		log.Debugf("Block target %064x is neagtive(??)\n", target.Bytes())
		return false
	}
	// The target must be less than the maximum allowed (difficulty 1)
	if target.Cmp(p.PowLimit) > 0 {
		log.Debugf("Block target %064x is "+
			"higher than max of %064x", target, p.PowLimit.Bytes())
		return false
	}
	// The header hash must be less than the claimed target in the header.
	blockHash := header.BlockHash()
	hashNum := blockchain.HashToBig(&blockHash)
	if hashNum.Cmp(target) > 0 {
		log.Debugf("Block hash %064x is higher than "+
			"required target of %064x", hashNum, target)
		return false
	}
	return true
}

// This function takes in a start and end block header and uses the timestamps in each
// to calculate how much of a difficulty adjustment is needed. It returns a new compact
// difficulty target.
func calcDiffAdjust(start, end wire.BlockHeader, p *chaincfg.Params) uint32 {
	duration := end.Timestamp.UnixNano() - start.Timestamp.UnixNano()
	if duration < minRetargetTimespan {
		log.Debugf("Whoa there, block %s off-scale high 4X diff adjustment!",
			end.BlockHash().String())
		duration = minRetargetTimespan
	} else if duration > maxRetargetTimespan {
		log.Debugf("Uh-oh! block %s off-scale low 0.25X diff adjustment!\n",
			end.BlockHash().String())
		duration = maxRetargetTimespan
	}

	// calculation of new 32-byte difficulty target
	// first turn the previous target into a big int
	prevTarget := blockchain.CompactToBig(end.Bits)
	// new target is old * duration...
	newTarget := new(big.Int).Mul(prevTarget, big.NewInt(duration))
	// divided by 2 weeks
	newTarget.Div(newTarget, big.NewInt(int64(targetTimespan)))

	// clip again if above minimum target (too easy)
	if newTarget.Cmp(p.PowLimit) > 0 {
		newTarget.Set(p.PowLimit)
	}

	return blockchain.BigToCompact(newTarget)
}
<|endoftext|>


<commit_before>package socket

import (
	"sync"
	"sync/atomic"

	"github.com/davyxu/cellnet"
)

type SessionManager struct {
	sesMap map[int64]cellnet.Session

	sesIDAcc    int64
	sesMapGuard sync.RWMutex
}

const totalTryCount = 100

func (self *SessionManager) Add(ses cellnet.Session) {

	self.sesMapGuard.Lock()
	defer self.sesMapGuard.Unlock()

	var tryCount int = totalTryCount

	var id int64

	// id翻越处理
	for tryCount > 0 {

		id = atomic.AddInt64(&self.sesIDAcc, 1)

		if _, ok := self.sesMap[id]; !ok {
			break
		}

		tryCount--
	}

	if tryCount == 0 {
		log.Warnln("sessionID override!", id)
	}

	socketSes := ses.(*SocketSession)

	socketSes.id = id

	self.sesMap[id] = ses

}

func (self *SessionManager) Remove(ses cellnet.Session) {
	self.sesMapGuard.Lock()
	delete(self.sesMap, ses.ID())
	self.sesMapGuard.Unlock()
}

// 获得一个连接
func (self *SessionManager) GetSession(id int64) cellnet.Session {
	self.sesMapGuard.RLock()
	defer self.sesMapGuard.RUnlock()

	v, ok := self.sesMap[id]
	if ok {
		return v
	}

	return nil
}

func (self *SessionManager) VisitSession(callback func(cellnet.Session) bool) {
	self.sesMapGuard.RLock()
	defer self.sesMapGuard.RUnlock()

	for _, ses := range self.sesMap {
		if !callback(ses) {
			break
		}
	}

}

func (self *SessionManager) CloseAllSession() {

	self.VisitSession(func(ses cellnet.Session) bool {

		ses.Close()

		return true
	})
}

func (self *SessionManager) SessionCount() int {
	self.sesMapGuard.Lock()
	defer self.sesMapGuard.Unlock()

	return len(self.sesMap)
}

func NewSessionManager() *SessionManager {
	return &SessionManager{
		sesMap: make(map[int64]cellnet.Session),
	}
}
<commit_msg>修复: 编译问题<commit_after><|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/markbates/going/defaults"
	"github.com/markbates/pop"
	"github.com/spf13/cobra"
)

var cfgFile string
var env string
var version bool

var RootCmd = &cobra.Command{
	Use:     "soda",
	Aliases: []string{"db"},
	Short:   "A tasty treat for all your database needs",
	PersistentPreRun: func(c *cobra.Command, args []string) {
		fmt.Printf("Soda v%s\n\n", Version)
		env = defaults.String(os.Getenv("GO_ENV"), env)
		setConfigLocation()
	},
	Run: func(cmd *cobra.Command, args []string) {
		if !version {
			cmd.Help()
		}
	},
}

func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	RootCmd.Flags().BoolVarP(&version, "version", "v", false, "Show version information")
	RootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "The configuration file you would like to use.")
	RootCmd.PersistentFlags().StringVarP(&env, "env", "e", "development", "The environment you want to run migrations against. Will use $GO_ENV if set.")
	RootCmd.PersistentFlags().BoolVarP(&pop.Debug, "debug", "d", false, "Use debug/verbose mode")
}

func setConfigLocation() {
	if cfgFile != "" {
		abs, err := filepath.Abs(cfgFile)
		if err != nil {
			return
		}
		dir, file := filepath.Split(abs)
		pop.AddLookupPaths(dir)
		pop.ConfigName = file
	}
	pop.LoadConfig()
}

func getConn() *pop.Connection {
	conn := pop.Connections[env]
	if conn == nil {
		fmt.Printf("There is no connection named %s defined!\n", env)
		os.Exit(1)
	}
	return conn
}
<commit_msg>removed the word Soda from the version printout<commit_after>package cmd

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/markbates/going/defaults"
	"github.com/markbates/pop"
	"github.com/spf13/cobra"
)

var cfgFile string
var env string
var version bool

var RootCmd = &cobra.Command{
	Use:     "soda",
	Aliases: []string{"db"},
	Short:   "A tasty treat for all your database needs",
	PersistentPreRun: func(c *cobra.Command, args []string) {
		fmt.Printf("v%s\n\n", Version)
		env = defaults.String(os.Getenv("GO_ENV"), env)
		setConfigLocation()
	},
	Run: func(cmd *cobra.Command, args []string) {
		if !version {
			cmd.Help()
		}
	},
}

func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	RootCmd.Flags().BoolVarP(&version, "version", "v", false, "Show version information")
	RootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "The configuration file you would like to use.")
	RootCmd.PersistentFlags().StringVarP(&env, "env", "e", "development", "The environment you want to run migrations against. Will use $GO_ENV if set.")
	RootCmd.PersistentFlags().BoolVarP(&pop.Debug, "debug", "d", false, "Use debug/verbose mode")
}

func setConfigLocation() {
	if cfgFile != "" {
		abs, err := filepath.Abs(cfgFile)
		if err != nil {
			return
		}
		dir, file := filepath.Split(abs)
		pop.AddLookupPaths(dir)
		pop.ConfigName = file
	}
	pop.LoadConfig()
}

func getConn() *pop.Connection {
	conn := pop.Connections[env]
	if conn == nil {
		fmt.Printf("There is no connection named %s defined!\n", env)
		os.Exit(1)
	}
	return conn
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/binary"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"path/filepath"
	"syscall"
)

const (
	GETATTR  = 0x01
	READLINK = 0x02
	GETDIR   = 0x03
	MKNOD    = 0x04
	MKDIR    = 0x05
	SYMLINK  = 0x06
	UNLINK   = 0x07
	RMDIR    = 0x08
	RENAME   = 0x09
	CHMOD    = 0x0A
	CHOWN    = 0x0B
	TRUNCATE = 0x0C
	UTIME    = 0x0D
	OPEN     = 0x0E
	READ     = 0x0F
	WRITE    = 0x10
	READDIR  = 0x11
	RELEASE  = 0x12
	CREATE   = 0x13
)

func handleConn(conn net.Conn) {
	var err error
	buf := make([]byte, 4096*1024) // 4MB
	openedFile := map[uintptr]*os.File{}
	rootdir := "/home/gle/code_repo/cloud_lib/tcfs-go/rootdir"
	for {
		_, err = io.ReadFull(conn, buf[:4])
		if err != nil {
			break
		}
		msglen := binary.BigEndian.Uint32(buf[:4])
		if msglen < 4 || msglen > (4096*1024) {
			log.Fatal("msglen = ", msglen)
		}
		_, err = io.ReadFull(conn, buf[:msglen])

		tcfsOp := binary.BigEndian.Uint32(buf[0:4])
		msgbuf := buf[4:msglen]
		switch tcfsOp {
		case GETATTR:
			fixpath := rootdir + string(msgbuf)
			var stat syscall.Stat_t
			err = syscall.Lstat(fixpath, &stat)
			if err != nil {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				var ret int32 = -2
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 11*4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			binary.BigEndian.PutUint32(buf[8:12], uint32(stat.Dev))
			binary.BigEndian.PutUint32(buf[12:16], uint32(stat.Ino))
			binary.BigEndian.PutUint32(buf[16:20], stat.Mode)
			binary.BigEndian.PutUint32(buf[20:24], uint32(stat.Nlink))
			binary.BigEndian.PutUint32(buf[24:28], stat.Uid)
			binary.BigEndian.PutUint32(buf[28:32], stat.Gid)
			binary.BigEndian.PutUint32(buf[32:36], uint32(stat.Size))
			binary.BigEndian.PutUint32(buf[36:40], uint32(stat.Atim.Sec))
			binary.BigEndian.PutUint32(buf[40:44], uint32(stat.Mtim.Sec))
			binary.BigEndian.PutUint32(buf[44:48], uint32(stat.Ctim.Sec))
			conn.Write(buf[:48])
		case READLINK:
		case GETDIR:
		case MKNOD:
		case MKDIR:
			mode := binary.BigEndian.Uint32(msgbuf[0:4])
			fixpath := rootdir + string(msgbuf[4:])
			if err := os.MkdirAll(fixpath, os.FileMode(mode)); err != nil {
				log.Print("Can't create dir", err)
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		case SYMLINK:
		case UNLINK:
			// FIXME
			fixpath := rootdir + string(msgbuf[1])
			if err := os.Remove(fixpath); err != nil {
				log.Print("Can't rmdir", err)
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		case RMDIR:
			fixpath := rootdir + string(msgbuf[1])
			if err := os.Remove(fixpath); err != nil {
				log.Print("Can't rmdir", err)
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		case RENAME:
		case CHMOD:
			mode := binary.BigEndian.Uint32(msgbuf[0:4])
			fixpath := rootdir + string(msgbuf[4:])
			err := os.Chmod(fixpath, os.FileMode(mode))
			if err != nil {
				log.Print("Can't chmod", err)
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		case CHOWN:
		case TRUNCATE:
			newSize := binary.BigEndian.Uint32(msgbuf[0:4])
			fixpath := rootdir + string(msgbuf[4:])
			err := os.Truncate(fixpath, int64(newSize))
			if err != nil {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -13 // EACCES
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		case UTIME:
			atime := binary.BigEndian.Uint64(msgbuf[0:8])
			mtime := binary.BigEndian.Uint64(msgbuf[8:16])
			fixpath := rootdir + string(msgbuf[16:])
			err := syscall.Utime(fixpath, &syscall.Utimbuf{int64(atime), int64(mtime)})
			if err != nil {
				log.Print("Can't create", err)
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		case OPEN:
			flag := binary.BigEndian.Uint32(msgbuf[0:4])
			fixpath := rootdir + string(msgbuf[4:])
			f, err := os.OpenFile(fixpath, int(flag), os.ModePerm)
			if err != nil {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				var ret int32 = -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			fd := f.Fd()
			openedFile[fd] = f
			binary.BigEndian.PutUint32(buf[0:4], 8)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			binary.BigEndian.PutUint32(buf[8:12], uint32(fd))
			conn.Write(buf[:12])
		case READ:
			findex := binary.BigEndian.Uint32(msgbuf[:4])
			offset := binary.BigEndian.Uint32(msgbuf[4:8])
			size := binary.BigEndian.Uint32(msgbuf[8:12])
			f := openedFile[uintptr(findex)]
			readbuf := make([]byte, size)
			readed, err := f.ReadAt(readbuf, int64(offset))
			if err != nil && err != io.EOF {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				var ret int32 = -9
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			if readed == 0 {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				binary.BigEndian.PutUint32(buf[4:8], 0)
				conn.Write(buf[:8])
			} else if readed > 0 {
				binary.BigEndian.PutUint32(buf[0:4], 4+uint32(readed))
				binary.BigEndian.PutUint32(buf[4:8], uint32(readed))
				copy(buf[8:], readbuf)
				conn.Write(buf[:8+readed])
			}
		case WRITE:
			findex := binary.BigEndian.Uint32(msgbuf[:4])
			offset := binary.BigEndian.Uint32(msgbuf[4:8])
			size := binary.BigEndian.Uint32(msgbuf[8:12])
			fmt.Println(size)
			fmt.Println(len(msgbuf))
			wbuf := msgbuf[12 : 12+size]
			f := openedFile[uintptr(findex)]
			writed, _ := f.WriteAt(wbuf, int64(offset))
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], uint32(writed))
			conn.Write(buf[:8])
		case READDIR:
			fixpath := rootdir + string(msgbuf)
			fileList := []byte{}
			err = filepath.Walk(fixpath, func(path string, f os.FileInfo, err error) error {
				rp, _ := filepath.Rel(rootdir, path)
				fileList = append(fileList, rp...)
				fileList = append(fileList, 0)
				return nil
			})
			binary.BigEndian.PutUint32(buf[:4], uint32(len(fileList))+4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			copy(buf[8:], fileList)
			conn.Write(buf[:len(fileList)+8])
		case RELEASE:
			findex := binary.BigEndian.Uint32(msgbuf[:4])
			f := openedFile[uintptr(findex)]
			err := f.Close()
			if err != nil {
				fmt.Println(err)
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -9
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		case CREATE:
			// mode := binary.BigEndian.Uint32([]byte(matched[1])[0:4])
			fixpath := rootdir + string(msgbuf[4:])
			f, err := os.Create(fixpath)
			if err != nil {
				log.Print("Can't create", err)
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			fd := f.Fd()
			openedFile[fd] = f
			binary.BigEndian.PutUint32(buf[0:4], 8)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			binary.BigEndian.PutUint32(buf[8:12], uint32(fd))
			conn.Write(buf[:12])
		default:
			log.Print("bad tcfsOp: ", tcfsOp)
		}
	}
	fmt.Println("xxxxxxxxxxx, close")
}

var (
	port = flag.String("port", ":9876", "port to listen to")
)

func main() {
	flag.Parse()
	l, e := net.Listen("tcp", *port)
	if e != nil {
		log.Fatal(e)
	}
	for {
		conn, e := l.Accept()
		if e != nil {
			log.Print(e)
			continue
		}
		go handleConn(conn)
	}
}
<commit_msg>add defer conn.Close()<commit_after>package main

import (
	"encoding/binary"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"path/filepath"
	"syscall"
)

const (
	GETATTR  = 0x01
	READLINK = 0x02
	GETDIR   = 0x03
	MKNOD    = 0x04
	MKDIR    = 0x05
	SYMLINK  = 0x06
	UNLINK   = 0x07
	RMDIR    = 0x08
	RENAME   = 0x09
	CHMOD    = 0x0A
	CHOWN    = 0x0B
	TRUNCATE = 0x0C
	UTIME    = 0x0D
	OPEN     = 0x0E
	READ     = 0x0F
	WRITE    = 0x10
	READDIR  = 0x11
	RELEASE  = 0x12
	CREATE   = 0x13
)

func handleConn(conn net.Conn) {
	defer conn.Close()
	var err error
	buf := make([]byte, 4096*1024) // 4MB
	openedFile := map[uintptr]*os.File{}
	rootdir := "/home/gle/code_repo/cloud_lib/tcfs-go/rootdir"
	for {
		_, err = io.ReadFull(conn, buf[:4])
		if err != nil {
			break
		}
		msglen := binary.BigEndian.Uint32(buf[:4])
		if msglen < 4 || msglen > (4096*1024) {
			log.Fatal("msglen = ", msglen)
		}
		_, err = io.ReadFull(conn, buf[:msglen])

		tcfsOp := binary.BigEndian.Uint32(buf[0:4])
		msgbuf := buf[4:msglen]
		switch tcfsOp {
		case GETATTR:
			fixpath := rootdir + string(msgbuf)
			var stat syscall.Stat_t
			err = syscall.Lstat(fixpath, &stat)
			if err != nil {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				var ret int32 = -2
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 11*4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			binary.BigEndian.PutUint32(buf[8:12], uint32(stat.Dev))
			binary.BigEndian.PutUint32(buf[12:16], uint32(stat.Ino))
			binary.BigEndian.PutUint32(buf[16:20], stat.Mode)
			binary.BigEndian.PutUint32(buf[20:24], uint32(stat.Nlink))
			binary.BigEndian.PutUint32(buf[24:28], stat.Uid)
			binary.BigEndian.PutUint32(buf[28:32], stat.Gid)
			binary.BigEndian.PutUint32(buf[32:36], uint32(stat.Size))
			binary.BigEndian.PutUint32(buf[36:40], uint32(stat.Atim.Sec))
			binary.BigEndian.PutUint32(buf[40:44], uint32(stat.Mtim.Sec))
			binary.BigEndian.PutUint32(buf[44:48], uint32(stat.Ctim.Sec))
			conn.Write(buf[:48])
		case READLINK:
		case GETDIR:
		case MKNOD:
		case MKDIR:
			mode := binary.BigEndian.Uint32(msgbuf[0:4])
			fixpath := rootdir + string(msgbuf[4:])
			if err := os.MkdirAll(fixpath, os.FileMode(mode)); err != nil {
				log.Print("Can't create dir", err)
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		case SYMLINK:
		case UNLINK:
			// FIXME
			fixpath := rootdir + string(msgbuf[1])
			if err := os.Remove(fixpath); err != nil {
				log.Print("Can't rmdir", err)
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		case RMDIR:
			fixpath := rootdir + string(msgbuf[1])
			if err := os.Remove(fixpath); err != nil {
				log.Print("Can't rmdir", err)
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		case RENAME:
		case CHMOD:
			mode := binary.BigEndian.Uint32(msgbuf[0:4])
			fixpath := rootdir + string(msgbuf[4:])
			err := os.Chmod(fixpath, os.FileMode(mode))
			if err != nil {
				log.Print("Can't chmod", err)
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		case CHOWN:
		case TRUNCATE:
			newSize := binary.BigEndian.Uint32(msgbuf[0:4])
			fixpath := rootdir + string(msgbuf[4:])
			err := os.Truncate(fixpath, int64(newSize))
			if err != nil {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -13 // EACCES
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		case UTIME:
			atime := binary.BigEndian.Uint64(msgbuf[0:8])
			mtime := binary.BigEndian.Uint64(msgbuf[8:16])
			fixpath := rootdir + string(msgbuf[16:])
			err := syscall.Utime(fixpath, &syscall.Utimbuf{int64(atime), int64(mtime)})
			if err != nil {
				log.Print("Can't create", err)
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		case OPEN:
			flag := binary.BigEndian.Uint32(msgbuf[0:4])
			fixpath := rootdir + string(msgbuf[4:])
			f, err := os.OpenFile(fixpath, int(flag), os.ModePerm)
			if err != nil {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				var ret int32 = -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			fd := f.Fd()
			openedFile[fd] = f
			binary.BigEndian.PutUint32(buf[0:4], 8)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			binary.BigEndian.PutUint32(buf[8:12], uint32(fd))
			conn.Write(buf[:12])
		case READ:
			findex := binary.BigEndian.Uint32(msgbuf[:4])
			offset := binary.BigEndian.Uint32(msgbuf[4:8])
			size := binary.BigEndian.Uint32(msgbuf[8:12])
			f := openedFile[uintptr(findex)]
			readbuf := make([]byte, size)
			readed, err := f.ReadAt(readbuf, int64(offset))
			if err != nil && err != io.EOF {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				var ret int32 = -9
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			if readed == 0 {
				binary.BigEndian.PutUint32(buf[0:4], 4)
				binary.BigEndian.PutUint32(buf[4:8], 0)
				conn.Write(buf[:8])
			} else if readed > 0 {
				binary.BigEndian.PutUint32(buf[0:4], 4+uint32(readed))
				binary.BigEndian.PutUint32(buf[4:8], uint32(readed))
				copy(buf[8:], readbuf)
				conn.Write(buf[:8+readed])
			}
		case WRITE:
			findex := binary.BigEndian.Uint32(msgbuf[:4])
			offset := binary.BigEndian.Uint32(msgbuf[4:8])
			size := binary.BigEndian.Uint32(msgbuf[8:12])
			fmt.Println(size)
			fmt.Println(len(msgbuf))
			wbuf := msgbuf[12 : 12+size]
			f := openedFile[uintptr(findex)]
			writed, _ := f.WriteAt(wbuf, int64(offset))
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], uint32(writed))
			conn.Write(buf[:8])
		case READDIR:
			fixpath := rootdir + string(msgbuf)
			fileList := []byte{}
			err = filepath.Walk(fixpath, func(path string, f os.FileInfo, err error) error {
				rp, _ := filepath.Rel(rootdir, path)
				fileList = append(fileList, rp...)
				fileList = append(fileList, 0)
				return nil
			})
			binary.BigEndian.PutUint32(buf[:4], uint32(len(fileList))+4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			copy(buf[8:], fileList)
			conn.Write(buf[:len(fileList)+8])
		case RELEASE:
			findex := binary.BigEndian.Uint32(msgbuf[:4])
			f := openedFile[uintptr(findex)]
			err := f.Close()
			if err != nil {
				fmt.Println(err)
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -9
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			binary.BigEndian.PutUint32(buf[0:4], 4)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			conn.Write(buf[:8])
		case CREATE:
			// mode := binary.BigEndian.Uint32([]byte(matched[1])[0:4])
			fixpath := rootdir + string(msgbuf[4:])
			f, err := os.Create(fixpath)
			if err != nil {
				log.Print("Can't create", err)
				binary.BigEndian.PutUint32(buf[0:4], 4)
				ret := -13
				binary.BigEndian.PutUint32(buf[4:8], uint32(ret))
				conn.Write(buf[:8])
				continue
			}
			fd := f.Fd()
			openedFile[fd] = f
			binary.BigEndian.PutUint32(buf[0:4], 8)
			binary.BigEndian.PutUint32(buf[4:8], 0)
			binary.BigEndian.PutUint32(buf[8:12], uint32(fd))
			conn.Write(buf[:12])
		default:
			log.Print("bad tcfsOp: ", tcfsOp)
		}
	}
	fmt.Println("xxxxxxxxxxx, close")
}

var (
	port = flag.String("port", ":9876", "port to listen to")
)

func main() {
	flag.Parse()
	l, e := net.Listen("tcp", *port)
	if e != nil {
		log.Fatal(e)
	}
	for {
		conn, e := l.Accept()
		if e != nil {
			log.Print(e)
			continue
		}
		go handleConn(conn)
	}
}
<|endoftext|>


<commit_before>package alertmanager

import (
	"sort"

	"github.com/cloudflare/unsee/models"
	"github.com/cloudflare/unsee/slices"
)

// DedupAlerts will collect alert groups from all defined Alertmanager
// upstreams and deduplicate them, so we only return unique alerts
func DedupAlerts() []models.AlertGroup {
	uniqueGroups := map[string][]models.AlertGroup{}

	upstreams := GetAlertmanagers()
	for _, am := range upstreams {
		groups := am.Alerts()
		for _, ag := range groups {
			if _, found := uniqueGroups[ag.ID]; !found {
				uniqueGroups[ag.ID] = []models.AlertGroup{}
			}
			uniqueGroups[ag.ID] = append(uniqueGroups[ag.ID], ag)
		}
	}

	dedupedGroups := []models.AlertGroup{}
	for _, agList := range uniqueGroups {
		alerts := map[string]models.Alert{}
		for _, ag := range agList {
			for _, alert := range ag.Alerts {
				alertLFP := alert.LabelsFingerprint()
				a, found := alerts[alertLFP]
				if found {
					for _, am := range alert.Alertmanager {
						a.Alertmanager = append(a.Alertmanager, am)
						alerts[alertLFP] = a
					}
				} else {
					alerts[alertLFP] = alert
				}
			}
		}
		ag := models.AlertGroup(agList[0])
		ag.Alerts = models.AlertList{}
		for _, alert := range alerts {
			ag.Alerts = append(ag.Alerts, alert)
		}
		sort.Sort(ag.Alerts)
		ag.Hash = ag.ContentFingerprint()
		dedupedGroups = append(dedupedGroups, ag)
	}

	return dedupedGroups
}

// DedupColors returns a color map merged from all Alertmanager upstream color
// maps
func DedupColors() models.LabelsColorMap {
	dedupedColors := models.LabelsColorMap{}

	upstreams := GetAlertmanagers()

	for _, am := range upstreams {
		colors := am.Colors()
		// map[string]map[string]LabelColors
		for labelName, valueMap := range colors {
			if _, found := dedupedColors[labelName]; !found {
				dedupedColors[labelName] = map[string]models.LabelColors{}
			}
			for labelVal, labelColors := range valueMap {
				if _, found := dedupedColors[labelName][labelVal]; !found {
					dedupedColors[labelName][labelVal] = labelColors
				}
			}
		}
	}

	return dedupedColors
}

// DedupAutocomplete returns a list of autocomplete hints merged from all
// Alertmanager upstreams
func DedupAutocomplete() []models.Autocomplete {
	dedupedAutocomplete := []models.Autocomplete{}
	uniqueAutocomplete := map[string]*models.Autocomplete{}

	upstreams := GetAlertmanagers()

	for _, am := range upstreams {
		ac := am.Autocomplete()
		for _, hint := range ac {
			h, found := uniqueAutocomplete[hint.Value]
			if found {
				for _, token := range hint.Tokens {
					if !slices.StringInSlice(h.Tokens, token) {
						h.Tokens = append(h.Tokens, token)
					}
				}
			} else {
				uniqueAutocomplete[hint.Value] = &models.Autocomplete{
					Value:  hint.Value,
					Tokens: hint.Tokens,
				}
			}
		}
	}

	for _, hint := range uniqueAutocomplete {
		dedupedAutocomplete = append(dedupedAutocomplete, *hint)
	}

	return dedupedAutocomplete
}
<commit_msg>Sort alert groups so they are returned in a stable order<commit_after>package alertmanager

import (
	"sort"

	"github.com/cloudflare/unsee/models"
	"github.com/cloudflare/unsee/slices"
)

// DedupAlerts will collect alert groups from all defined Alertmanager
// upstreams and deduplicate them, so we only return unique alerts
func DedupAlerts() []models.AlertGroup {
	uniqueGroups := map[string][]models.AlertGroup{}

	upstreams := GetAlertmanagers()
	for _, am := range upstreams {
		groups := am.Alerts()
		for _, ag := range groups {
			if _, found := uniqueGroups[ag.ID]; !found {
				uniqueGroups[ag.ID] = []models.AlertGroup{}
			}
			uniqueGroups[ag.ID] = append(uniqueGroups[ag.ID], ag)
		}
	}

	dedupedGroups := []models.AlertGroup{}
	for _, agList := range uniqueGroups {
		alerts := map[string]models.Alert{}
		for _, ag := range agList {
			for _, alert := range ag.Alerts {
				alertLFP := alert.LabelsFingerprint()
				a, found := alerts[alertLFP]
				if found {
					for _, am := range alert.Alertmanager {
						a.Alertmanager = append(a.Alertmanager, am)
						alerts[alertLFP] = a
					}
				} else {
					alerts[alertLFP] = alert
				}
			}
		}
		ag := models.AlertGroup(agList[0])
		ag.Alerts = models.AlertList{}
		for _, alert := range alerts {
			ag.Alerts = append(ag.Alerts, alert)
		}
		sort.Sort(ag.Alerts)
		ag.Hash = ag.ContentFingerprint()
		dedupedGroups = append(dedupedGroups, ag)
	}

	// sort alert groups so they are always returned in the same order
	// use group ID which is unique and immutable
	sort.Slice(dedupedGroups, func(i, j int) bool { return dedupedGroups[i].ID < dedupedGroups[j].ID })

	return dedupedGroups
}

// DedupColors returns a color map merged from all Alertmanager upstream color
// maps
func DedupColors() models.LabelsColorMap {
	dedupedColors := models.LabelsColorMap{}

	upstreams := GetAlertmanagers()

	for _, am := range upstreams {
		colors := am.Colors()
		// map[string]map[string]LabelColors
		for labelName, valueMap := range colors {
			if _, found := dedupedColors[labelName]; !found {
				dedupedColors[labelName] = map[string]models.LabelColors{}
			}
			for labelVal, labelColors := range valueMap {
				if _, found := dedupedColors[labelName][labelVal]; !found {
					dedupedColors[labelName][labelVal] = labelColors
				}
			}
		}
	}

	return dedupedColors
}

// DedupAutocomplete returns a list of autocomplete hints merged from all
// Alertmanager upstreams
func DedupAutocomplete() []models.Autocomplete {
	dedupedAutocomplete := []models.Autocomplete{}
	uniqueAutocomplete := map[string]*models.Autocomplete{}

	upstreams := GetAlertmanagers()

	for _, am := range upstreams {
		ac := am.Autocomplete()
		for _, hint := range ac {
			h, found := uniqueAutocomplete[hint.Value]
			if found {
				for _, token := range hint.Tokens {
					if !slices.StringInSlice(h.Tokens, token) {
						h.Tokens = append(h.Tokens, token)
					}
				}
			} else {
				uniqueAutocomplete[hint.Value] = &models.Autocomplete{
					Value:  hint.Value,
					Tokens: hint.Tokens,
				}
			}
		}
	}

	for _, hint := range uniqueAutocomplete {
		dedupedAutocomplete = append(dedupedAutocomplete, *hint)
	}

	return dedupedAutocomplete
}
<|endoftext|>


<commit_before>package server

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestMAILParsing(t *testing.T) {
	from, err := ParseMAIL("From:<foo@bar>")
	assert.Equal(t, from, "foo@bar")
	assert.Nil(t, err)

	from, err = ParseMAIL("From:<foo@bar.com>")
	assert.Equal(t, from, "foo@bar.com")
	assert.Nil(t, err)

	from, err = ParseMAIL("From:<foo>")
	assert.Equal(t, from, "foo")
	assert.Nil(t, err)

	from, err = ParseMAIL("To:<foo@bar>")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid sender")

	from, err = ParseMAIL("To:<foo@bar.com>")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid sender")

	from, err = ParseMAIL("To:<foo>")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid sender")

	from, err = ParseMAIL("INVALID")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid sender")

	from, err = ParseMAIL("From:INVALID")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid sender")

	from, err = ParseMAIL("From:foo")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid sender")

	from, err = ParseMAIL("From:foo@bar")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid sender")

	from, err = ParseMAIL("From: <foo@bar>")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid sender")
}

func TestRCPTParsing(t *testing.T) {
	from, err := ParseRCPT("To:<foo@bar>")
	assert.Equal(t, from, "foo@bar")
	assert.Nil(t, err)

	from, err = ParseRCPT("To:<foo@bar.com>")
	assert.Equal(t, from, "foo@bar.com")
	assert.Nil(t, err)

	from, err = ParseRCPT("To:<foo>")
	assert.Equal(t, from, "foo")
	assert.Nil(t, err)

	from, err = ParseRCPT("From:<foo@bar>")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid recipient")

	from, err = ParseRCPT("From:<foo@bar.com>")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid recipient")

	from, err = ParseRCPT("From:<foo>")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid recipient")

	from, err = ParseRCPT("INVALID")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid recipient")

	from, err = ParseRCPT("To:INVALID")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid recipient")

	from, err = ParseRCPT("To:foo")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid recipient")

	from, err = ParseRCPT("To:foo@bar")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid recipient")

	from, err = ParseRCPT("To: <foo@bar>")
	assert.Equal(t, from, "")
	assert.NotNil(t, err)
	assert.Equal(t, err.Error(), "Invalid recipient")
}
<commit_msg>Remove old session tests and add basic validation handler tests<commit_after>package server

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestValidateAuthentication(t *testing.T) {
	Convey("validateAuthentication is always successful", t, func() {
		c := &Session{}

		err, ok := c.validateAuthentication("OINK")
		So(err, ShouldBeNil)
		So(ok, ShouldBeTrue)

		err, ok = c.validateAuthentication("OINK", "arg1")
		So(err, ShouldBeNil)
		So(ok, ShouldBeTrue)

		err, ok = c.validateAuthentication("OINK", "arg1", "arg2")
		So(err, ShouldBeNil)
		So(ok, ShouldBeTrue)
	})
}

func TestValidateRecipient(t *testing.T) {
	Convey("validateRecipient is always successful", t, func() {
		c := &Session{}

		So(c.validateRecipient("OINK"), ShouldBeTrue)
		So(c.validateRecipient("foo@bar.mailhog"), ShouldBeTrue)
	})
}

func TestValidateSender(t *testing.T) {
	Convey("validateSender is always successful", t, func() {
		c := &Session{}

		So(c.validateSender("OINK"), ShouldBeTrue)
		So(c.validateSender("foo@bar.mailhog"), ShouldBeTrue)
	})
}
<|endoftext|>


<commit_before>package tenho

import (
	"fmt"
	"math/rand"
	"sort"
	"time"
)

type OptionStruct struct {
	NoKokushi      bool
	NoChitoitsu    bool
	NoNormal       bool
	OutputPerTrial int
}

var option OptionStruct

func Start(o OptionStruct) {
	option = o

	start := time.Now().UnixNano()
	var i float64
	i = 0
	var hand Hand
	var ok bool
	for {
		i++
		seed := time.Now().UnixNano()
		hand, ok = tryOnce(seed)
		if ok || int(i)%option.OutputPerTrial == 0 {
			end := time.Now().UnixNano()
			diff := float64(end-start) / 1000000000
			m := i / diff
			out := 0
			if m >= 0 {
				out = int(m)
			}
			hai := hand.HaiString()
			fmt.Printf("\r%v回試行  %v秒経過 %v回/秒 %v", i, diff, out, hai)
		}
		if ok {
			break
		}
	}
	fmt.Printf("\n")
}

func tryOnce(seed int64) (Hand, bool) {
	hand := ShuffledHand(seed)
	ok := hand.Solve()
	return hand, ok
}

// http://d.hatena.ne.jp/hake/20150930/p1
func shuffle(hand Hand) {
	for i := len(hand); i > 1; i-- {
		j := rand.Intn(i) // 0 .. i-1 の乱数発生
		hand[i-1], hand[j] = hand[j], hand[i-1]
	}
}

const HandSize = 14
const MahjongSetSize = 136

var defaultSet []int

func GetMahjongSet() []int {
	if defaultSet == nil {
		size := MahjongSetSize
		defaultSet = make([]int, size, size)
		for i := 0; i < size; i++ {
			defaultSet[i] = i / 4
		}
	}
	return defaultSet
}

func ShuffledHand(seed int64) Hand {
	rand.Seed(seed)

	hand := make([]int, MahjongSetSize, MahjongSetSize)
	copy(hand, GetMahjongSet())
	hand2 := make([]int, 0, 0)
	var j int

	for k := MahjongSetSize; k > MahjongSetSize-HandSize; k-- {
		j = rand.Intn(k)
		hand2 = append(hand2, hand[j])
		hand = append(hand[:j], hand[j+1:]...)
	}

	sort.Ints(hand2)

	retval := *new(Hand)
	for i := 0; i < 14; i++ {
		retval[i] = hand2[i]
	}
	return retval
}

type Hand [14]int

// 牌文字への変換(スペース区切り)
func (hand Hand) HaiString() string {
	// http://qiita.com/ruiu/items/2bb83b29baeae2433a79
	// サイズ0、内部バッファの長さ69の[]byteの値を割り当てる
	b := make([]byte, 0, 70)

	// bに文字列を追加
	for j := 0; j < HandSize; j++ {
		// コードポイント上、普通の麻雀牌はU+1F000からの34個。
		// U+1F000 is 'MAHJONG TILE EAST WIND' ('東')
		// https://codepoints.net/U+1F000
		b = append(b, string(hand[j]+0x1F000)...) // appendするには...が必要
		// 自分のMacではスペース区切りでないとうまく表示されないためスペースを挿入する
		// U+0020 is 'SPACE'
		// https://codepoints.net/U+0020
		b = append(b, string(0x20)...) // appendするには...が必要
	}
	return string(b)
}

// 七対子判定
func (hand Hand) solveChitoitsu() bool {
	//カウンタ
	c := map[int]int{}

	for _, v := range hand {
		count, ok := c[v]
		if ok {
			if count == 1 {
				c[v] = 2
			} else {
				// c[v] == 2
				return false
			}
		} else {
			c[v] = 1
		}
		//8個チェック
		if len(c) >= 8 {
			return false
		}
	}
	return true
}

// 国士無双判定
func (hand Hand) solveKokushi() bool {
	//あがりパターン列挙
	agaris := [13][14]int{
		[14]int{0, 0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33, 33},
	}
	for _, v := range agaris {
		if v == hand {
			return true
		}
	}
	return false
}

// あがり判定する
func (hand Hand) Solve() bool {
	return (!(option.NoKokushi) && hand.solveKokushi()) || (!(option.NoChitoitsu) && hand.solveChitoitsu()) || (!(option.NoNormal) && hand.GroupSuit().Solve())
}

type SuitGroup struct {
	innerSuitGroup
	color int
}

type innerSuitGroup []int

func NewSuitGroup(color int) *SuitGroup {
	s := SuitGroup{innerSuitGroup{}, color}
	return &s
}

type SuitsGroupedHand map[int]SuitGroup

const (
	Jihai = iota
	Manzu
	Sozu
	Pinzu
)

// スート分類
func (hand Hand) GroupSuit() SuitsGroupedHand {
	m := SuitsGroupedHand{
		Jihai: *NewSuitGroup(Jihai),
		Manzu: *NewSuitGroup(Manzu),
		Sozu:  *NewSuitGroup(Sozu),
		Pinzu: *NewSuitGroup(Pinzu),
	}
	for _, i := range hand {
		quo := (i - 7 + 9) / 9
		var mod int
		if i-7 >= 0 {
			mod = (i - 7) % 9
		} else {
			mod = i
		}
		s := m[quo]
		s.append(mod)
		m[quo] = s
	}
	return m
}

func (m SuitsGroupedHand) Solve() bool {
	return m.a_pair_existible() && m.valid_33332()
}
func (m SuitsGroupedHand) a_pair_existible() bool {
	//スートのサイズを3で割った時
	//あまりが2であるスートグループが1つであること
	c := 0
	for _, a := range m {
		switch len(a.list()) % 3 {
		case 0:
			// noop
		case 1:
			return false
		case 2:
			c++
		}
	}
	return c == 1
}

func (m SuitsGroupedHand) valid_33332() bool {
	for i := 0; i < 4; i++ {
		if !m[i].valid_suit_group(i) {
			return false
		}
	}
	return true
}

func (a innerSuitGroup) list() innerSuitGroup {
	return a
}

func (a *innerSuitGroup) SetSuitGroup(b innerSuitGroup) {
	*a = b
}

func (a *innerSuitGroup) append(w int) {
	*a = append(*a, w)
}

// 33332形を形成するスートグループがどうかを判定
func (a SuitGroup) valid_suit_group(i int) bool {
	// 対子が含まれているスートグループがただ1つある前提

	if len(a.list())%3 == 2 {
		//ペアを探す
		pair_numbers := a.pairable_numbers()
		//ペア候補がなかったらぬける
		if len(pair_numbers) == 0 {
			return false
		}
		//ペア候補毎に繰り返し処理
		for _, v := range pair_numbers {
			//ペアとなる２枚を除去
			rest := NewSuitGroup(i)
			c := 2
			for _, w := range a.list() {
				// ペア候補以外は新スライスに入れる
				// ペア候補は３枚目以降は新スライスに入れる
				if w != v || c <= 0 {
					rest.SetSuitGroup(append(rest.list(), w))
				}
				if w == v {
					c--
				}
			}
			if rest.valid_3cards() {
				return true
			} else {
				continue
			}
		}
		return false
	} else if len(a.list())%3 == 0 {
		return a.valid_3cards()
	}
	// 到達しないはず
	panic("到達しないはず")
}

func (a SuitGroup) valid_3cards() bool {
	// 刻子や順子のみで構成されている場合true
	// a is sorted
	// a.size % 3 is0
	for {
		if a.remove_kotsu() {
			continue
		}
		break
	}

	// 字牌でなければ順子チェック
	if a.color != Jihai {
		for {
			if a.remove_shuntsu() {
				continue
			}
			break
		}
	}
	return len(a.list()) == 0
}

func (a *innerSuitGroup) remove_kotsu() bool {
	// 刻子を除去できればtrue
	// a is sorted
	x := *a
	if len(x) < 3 {
		return false
	}
	if x[0] == x[1] && x[0] == x[2] {
		*a = x[3:]
		return true
	}
	return false
}

func (a *innerSuitGroup) remove_shuntsu() bool {
	// 順子を除去できればtrue
	// a is sorted
	rest := innerSuitGroup{}
	first := -1
	second := -1
	found := false
	for _, v := range *a {
		if found {
			rest = append(rest, v)
			continue
		}
		if first == -1 {
			first = v
		} else if second == -1 && first+1 == v {
			second = v
		} else if second != -1 && first+2 == v {
			//flush
			first = -1
			second = -1
			found = true
		} else {
			rest = append(rest, v)
		}
	}
	*a = rest
	return found
}

func (a innerSuitGroup) pairable_numbers() innerSuitGroup {
	// a is sorted
	counter := []int{}
	var x, y int // 2つ前と1つ前
	for _, v := range a {
		if y == v && x != v {
			counter = append(counter, v)
		} else {
			y = v
		}
	}
	return counter
}
<commit_msg>Use const<commit_after>package tenho

import (
	"fmt"
	"math/rand"
	"sort"
	"time"
)

type OptionStruct struct {
	NoKokushi      bool
	NoChitoitsu    bool
	NoNormal       bool
	OutputPerTrial int
}

var option OptionStruct

func Start(o OptionStruct) {
	option = o

	start := time.Now().UnixNano()
	var i float64
	i = 0
	var hand Hand
	var ok bool
	for {
		i++
		seed := time.Now().UnixNano()
		hand, ok = tryOnce(seed)
		if ok || int(i)%option.OutputPerTrial == 0 {
			end := time.Now().UnixNano()
			diff := float64(end-start) / 1000000000
			m := i / diff
			out := 0
			if m >= 0 {
				out = int(m)
			}
			hai := hand.HaiString()
			fmt.Printf("\r%v回試行  %v秒経過 %v回/秒 %v", i, diff, out, hai)
		}
		if ok {
			break
		}
	}
	fmt.Printf("\n")
}

func tryOnce(seed int64) (Hand, bool) {
	hand := ShuffledHand(seed)
	ok := hand.Solve()
	return hand, ok
}

// http://d.hatena.ne.jp/hake/20150930/p1
func shuffle(hand Hand) {
	for i := len(hand); i > 1; i-- {
		j := rand.Intn(i) // 0 .. i-1 の乱数発生
		hand[i-1], hand[j] = hand[j], hand[i-1]
	}
}

const HandSize = 14
const MahjongSetSize = 136

var defaultSet []int

func GetMahjongSet() []int {
	if defaultSet == nil {
		size := MahjongSetSize
		defaultSet = make([]int, size, size)
		for i := 0; i < size; i++ {
			defaultSet[i] = i / 4
		}
	}
	return defaultSet
}

func ShuffledHand(seed int64) Hand {
	rand.Seed(seed)

	hand := make([]int, MahjongSetSize, MahjongSetSize)
	copy(hand, GetMahjongSet())
	hand2 := make([]int, 0, 0)
	var j int

	for k := MahjongSetSize; k > MahjongSetSize-HandSize; k-- {
		j = rand.Intn(k)
		hand2 = append(hand2, hand[j])
		hand = append(hand[:j], hand[j+1:]...)
	}

	sort.Ints(hand2)

	retval := *new(Hand)
	for i := 0; i < HandSize; i++ {
		retval[i] = hand2[i]
	}
	return retval
}

type Hand [HandSize]int

// 牌文字への変換(スペース区切り)
func (hand Hand) HaiString() string {
	// http://qiita.com/ruiu/items/2bb83b29baeae2433a79
	// サイズ0、内部バッファの長さ69の[]byteの値を割り当てる
	b := make([]byte, 0, 70)

	// bに文字列を追加
	for j := 0; j < HandSize; j++ {
		// コードポイント上、普通の麻雀牌はU+1F000からの34個。
		// U+1F000 is 'MAHJONG TILE EAST WIND' ('東')
		// https://codepoints.net/U+1F000
		b = append(b, string(hand[j]+0x1F000)...) // appendするには...が必要
		// 自分のMacではスペース区切りでないとうまく表示されないためスペースを挿入する
		// U+0020 is 'SPACE'
		// https://codepoints.net/U+0020
		b = append(b, string(0x20)...) // appendするには...が必要
	}
	return string(b)
}

// 七対子判定
func (hand Hand) solveChitoitsu() bool {
	//カウンタ
	c := map[int]int{}

	for _, v := range hand {
		count, ok := c[v]
		if ok {
			if count == 1 {
				c[v] = 2
			} else {
				// c[v] == 2
				return false
			}
		} else {
			c[v] = 1
		}
		//8個チェック
		if len(c) >= 8 {
			return false
		}
	}
	return true
}

// 国士無双判定
func (hand Hand) solveKokushi() bool {
	//あがりパターン列挙
	agaris := [13][14]int{
		[14]int{0, 0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33, 33},
	}
	for _, v := range agaris {
		if v == hand {
			return true
		}
	}
	return false
}

// あがり判定する
func (hand Hand) Solve() bool {
	return (!(option.NoKokushi) && hand.solveKokushi()) || (!(option.NoChitoitsu) && hand.solveChitoitsu()) || (!(option.NoNormal) && hand.GroupSuit().Solve())
}

type SuitGroup struct {
	innerSuitGroup
	color int
}

type innerSuitGroup []int

func NewSuitGroup(color int) *SuitGroup {
	s := SuitGroup{innerSuitGroup{}, color}
	return &s
}

type SuitsGroupedHand map[int]SuitGroup

const (
	Jihai = iota
	Manzu
	Sozu
	Pinzu
)

// スート分類
func (hand Hand) GroupSuit() SuitsGroupedHand {
	m := SuitsGroupedHand{
		Jihai: *NewSuitGroup(Jihai),
		Manzu: *NewSuitGroup(Manzu),
		Sozu:  *NewSuitGroup(Sozu),
		Pinzu: *NewSuitGroup(Pinzu),
	}
	for _, i := range hand {
		quo := (i - 7 + 9) / 9
		var mod int
		if i-7 >= 0 {
			mod = (i - 7) % 9
		} else {
			mod = i
		}
		s := m[quo]
		s.append(mod)
		m[quo] = s
	}
	return m
}

func (m SuitsGroupedHand) Solve() bool {
	return m.a_pair_existible() && m.valid_33332()
}
func (m SuitsGroupedHand) a_pair_existible() bool {
	//スートのサイズを3で割った時
	//あまりが2であるスートグループが1つであること
	c := 0
	for _, a := range m {
		switch len(a.list()) % 3 {
		case 0:
			// noop
		case 1:
			return false
		case 2:
			c++
		}
	}
	return c == 1
}

func (m SuitsGroupedHand) valid_33332() bool {
	for i := 0; i < 4; i++ {
		if !m[i].valid_suit_group(i) {
			return false
		}
	}
	return true
}

func (a innerSuitGroup) list() innerSuitGroup {
	return a
}

func (a *innerSuitGroup) SetSuitGroup(b innerSuitGroup) {
	*a = b
}

func (a *innerSuitGroup) append(w int) {
	*a = append(*a, w)
}

// 33332形を形成するスートグループがどうかを判定
func (a SuitGroup) valid_suit_group(i int) bool {
	// 対子が含まれているスートグループがただ1つある前提

	if len(a.list())%3 == 2 {
		//ペアを探す
		pair_numbers := a.pairable_numbers()
		//ペア候補がなかったらぬける
		if len(pair_numbers) == 0 {
			return false
		}
		//ペア候補毎に繰り返し処理
		for _, v := range pair_numbers {
			//ペアとなる２枚を除去
			rest := NewSuitGroup(i)
			c := 2
			for _, w := range a.list() {
				// ペア候補以外は新スライスに入れる
				// ペア候補は３枚目以降は新スライスに入れる
				if w != v || c <= 0 {
					rest.SetSuitGroup(append(rest.list(), w))
				}
				if w == v {
					c--
				}
			}
			if rest.valid_3cards() {
				return true
			} else {
				continue
			}
		}
		return false
	} else if len(a.list())%3 == 0 {
		return a.valid_3cards()
	}
	// 到達しないはず
	panic("到達しないはず")
}

func (a SuitGroup) valid_3cards() bool {
	// 刻子や順子のみで構成されている場合true
	// a is sorted
	// a.size % 3 is0
	for {
		if a.remove_kotsu() {
			continue
		}
		break
	}

	// 字牌でなければ順子チェック
	if a.color != Jihai {
		for {
			if a.remove_shuntsu() {
				continue
			}
			break
		}
	}
	return len(a.list()) == 0
}

func (a *innerSuitGroup) remove_kotsu() bool {
	// 刻子を除去できればtrue
	// a is sorted
	x := *a
	if len(x) < 3 {
		return false
	}
	if x[0] == x[1] && x[0] == x[2] {
		*a = x[3:]
		return true
	}
	return false
}

func (a *innerSuitGroup) remove_shuntsu() bool {
	// 順子を除去できればtrue
	// a is sorted
	rest := innerSuitGroup{}
	first := -1
	second := -1
	found := false
	for _, v := range *a {
		if found {
			rest = append(rest, v)
			continue
		}
		if first == -1 {
			first = v
		} else if second == -1 && first+1 == v {
			second = v
		} else if second != -1 && first+2 == v {
			//flush
			first = -1
			second = -1
			found = true
		} else {
			rest = append(rest, v)
		}
	}
	*a = rest
	return found
}

func (a innerSuitGroup) pairable_numbers() innerSuitGroup {
	// a is sorted
	counter := []int{}
	var x, y int // 2つ前と1つ前
	for _, v := range a {
		if y == v && x != v {
			counter = append(counter, v)
		} else {
			y = v
		}
	}
	return counter
}
<|endoftext|>


<commit_before>package tenho

import (
	"fmt"
	"math/rand"
	"sort"
	"time"
)

type OptionStruct struct {
	NoKokushi      bool
	NoChitoitsu    bool
	NoNormal       bool
	OutputPerTrial int
}

var option OptionStruct

func Start(o OptionStruct) {
	option = o

	start := time.Now().UnixNano()
	var i float64
	i = 0
	var hai string
	var ok bool
	for {
		i++
		seed := time.Now().UnixNano()
		hai, ok = tryOnce(seed)
		if int(i)%option.OutputPerTrial == 0 {
			end := time.Now().UnixNano()
			diff := float64(end-start) / 1000000000
			m := i / diff
			out := 0
			if m >= 0 {
				out = int(m)
			}
			fmt.Printf("\r%v回試行  %v秒経過 %v回/秒 %v", i, diff, out, hai)
		}
		if ok {
			end := time.Now().UnixNano()
			diff := float64(end-start) / 1000000000
			m := i / diff
			out := 0
			if m >= 0 {
				out = int(m)
			}
			fmt.Printf("\r%v回試行  %v秒経過 %v回/秒 %v", i, diff, out, hai)
			break
		}
	}
	fmt.Printf("\n")
}

func tryOnce(seed int64) (string, bool) {
	hand := ShuffledHand(seed)
	hai := hand.HaiString()
	ok := hand.Solve()
	return hai, ok
}

// http://d.hatena.ne.jp/hake/20150930/p1
func shuffle(hand Hand) {
	for i := len(hand); i > 1; i-- {
		j := rand.Intn(i) // 0 .. i-1 の乱数発生
		hand[i-1], hand[j] = hand[j], hand[i-1]
	}
}

const HandSize = 14
const MahjongSetSize = 136

var defaultSet []int

func GetMahjongSet() []int {
	if defaultSet == nil {
		size := MahjongSetSize
		defaultSet = make([]int, size, size)
		for i := 0; i < size; i++ {
			defaultSet[i] = i / 4
		}
	}
	return defaultSet
}

func ShuffledHand(seed int64) Hand {
	rand.Seed(seed)

	hand := make(Hand, MahjongSetSize, MahjongSetSize)
	copy(hand, GetMahjongSet())
	hand2 := make(Hand, 0, 0)
	var j int

	for k := MahjongSetSize; k > MahjongSetSize-HandSize; k-- {
		j = rand.Intn(k)
		hand2 = append(hand2, hand[j])
		hand = append(hand[:j], hand[j+1:]...)
	}

	return hand2
}

type Hand []int

// 牌文字への変換(スペース区切り)
func (hand Hand) HaiString() string {
	// http://qiita.com/ruiu/items/2bb83b29baeae2433a79
	// サイズ0、内部バッファの長さ69の[]byteの値を割り当てる
	b := make([]byte, 0, 70)

	// bに文字列を追加
	for j := 0; j < HandSize; j++ {
		// コードポイント上、普通の麻雀牌はU+1F000からの34個。
		// U+1F000 is 'MAHJONG TILE EAST WIND' ('東')
		// https://codepoints.net/U+1F000
		b = append(b, string(hand[j]+0x1F000)...) // appendするには...が必要
		// 自分のMacではスペース区切りでないとうまく表示されないためスペースを挿入する
		// U+0020 is 'SPACE'
		// https://codepoints.net/U+0020
		b = append(b, string(0x20)...) // appendするには...が必要
	}
	return string(b)
}

// 七対子判定
func (hand Hand) solveChitoitsu() bool {
	//カウンタ
	c := map[int]int{}

	for _, v := range hand {
		count, ok := c[v]
		if ok {
			if count == 1 {
				c[v] = 2
			} else {
				// c[v] == 2
				return false
			}
		} else {
			c[v] = 1
		}
		//8個チェック
		if len(c) >= 8 {
			return false
		}
	}
	return true
}

// 国士無双判定
func (hand Hand) solveKokushi() bool {
	sort.Ints(hand)
	//比較するために配列にする
	var a [HandSize]int
	for i := 0; i < HandSize; i++ {
		a[i] = hand[i]
	}

	//あがりパターン列挙
	agaris := [13][14]int{
		[14]int{0, 0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33, 33},
	}
	for _, v := range agaris {
		if v == a {
			return true
		}
	}
	return false
}

// あがり判定する
func (hand Hand) Solve() bool {
	return (!(option.NoKokushi) && hand.solveKokushi()) || (!(option.NoChitoitsu) && hand.solveChitoitsu()) || (!(option.NoNormal) && hand.GroupSuit().Solve())
}

type SuitGroup struct {
	innerSuitGroup
	color int
}

type innerSuitGroup []int

func NewSuitGroup(color int) *SuitGroup {
	s := SuitGroup{innerSuitGroup{}, color}
	return &s
}

type SuitsGroupedHand map[int]SuitGroup

const (
	Jihai = iota
	Manzu
	Sozu
	Pinzu
)

// スート分類
func (hand Hand) GroupSuit() SuitsGroupedHand {
	m := SuitsGroupedHand{
		Jihai: *NewSuitGroup(Jihai),
		Manzu: *NewSuitGroup(Manzu),
		Sozu:  *NewSuitGroup(Sozu),
		Pinzu: *NewSuitGroup(Pinzu),
	}
	for _, i := range hand {
		quo := (i - 7 + 9) / 9
		var mod int
		if i-7 >= 0 {
			mod = (i - 7) % 9
		} else {
			mod = i
		}
		s := m[quo]
		s.append(mod)
		m[quo] = s
	}
	return m
}

func (m SuitsGroupedHand) Solve() bool {
	return m.a_pair_existible() && m.valid_33332()
}
func (m SuitsGroupedHand) a_pair_existible() bool {
	//スートのサイズを3で割った時
	//あまりが2であるスートグループが1つであること
	c := 0
	for _, a := range m {
		switch len(a.list()) % 3 {
		case 0:
			// noop
		case 1:
			return false
		case 2:
			c++
		}
	}
	return c == 1
}

func (m SuitsGroupedHand) valid_33332() bool {
	for i := 0; i < 4; i++ {
		if !m[i].valid_suit_group(i) {
			return false
		}
	}
	return true
}

func (a innerSuitGroup) list() innerSuitGroup {
	return a
}

func (a *innerSuitGroup) SetSuitGroup(b innerSuitGroup) {
	*a = b
}

func (a *innerSuitGroup) append(w int) {
	*a = append(*a, w)
}

// 33332形を形成するスートグループがどうかを判定
func (a SuitGroup) valid_suit_group(i int) bool {
	// 対子が含まれているスートグループがただ1つある前提

	//ソート
	sort.Ints(a.list())
	if len(a.list())%3 == 2 {
		//ペアを探す
		pair_numbers := a.pairable_numbers()
		//ペア候補がなかったらぬける
		if len(pair_numbers) == 0 {
			return false
		}
		//ペア候補毎に繰り返し処理
		for _, v := range pair_numbers {
			//ペアとなる２枚を除去
			rest := NewSuitGroup(i)
			c := 2
			for _, w := range a.list() {
				// ペア候補以外は新スライスに入れる
				// ペア候補は３枚目以降は新スライスに入れる
				if w != v || c <= 0 {
					rest.SetSuitGroup(append(rest.list(), w))
				}
				if w == v {
					c--
				}
			}
			if rest.valid_3cards() {
				return true
			} else {
				continue
			}
		}
		return false
	} else if len(a.list())%3 == 0 {
		return a.valid_3cards()
	}
	// 到達しないはず
	panic("到達しないはず")
}

func (a SuitGroup) valid_3cards() bool {
	// 刻子や順子のみで構成されている場合true
	// a is sorted
	// a.size % 3 is0
	for {
		if a.remove_kotsu() {
			continue
		}
		break
	}

	// 字牌でなければ順子チェック
	if a.color != Jihai {
		for {
			if a.remove_shuntsu() {
				continue
			}
			break
		}
	}
	return len(a.list()) == 0
}

func (a *innerSuitGroup) remove_kotsu() bool {
	// 刻子を除去できればtrue
	// a is sorted
	x := *a
	if len(x) < 3 {
		return false
	}
	if x[0] == x[1] && x[0] == x[2] {
		*a = x[3:]
		return true
	}
	return false
}

func (a *innerSuitGroup) remove_shuntsu() bool {
	// 順子を除去できればtrue
	// a is sorted
	rest := innerSuitGroup{}
	first := -1
	second := -1
	found := false
	for _, v := range *a {
		if found {
			rest = append(rest, v)
			continue
		}
		if first == -1 {
			first = v
		} else if second == -1 && first+1 == v {
			second = v
		} else if second != -1 && first+2 == v {
			//flush
			first = -1
			second = -1
			found = true
		} else {
			rest = append(rest, v)
		}
	}
	*a = rest
	return found
}

func (a innerSuitGroup) pairable_numbers() innerSuitGroup {
	// a is sorted
	counter := []int{}
	var x, y int // 2つ前と1つ前
	for _, v := range a {
		if y == v && x != v {
			counter = append(counter, v)
		} else {
			y = v
		}
	}
	return counter
}
<commit_msg>Refactor<commit_after>package tenho

import (
	"fmt"
	"math/rand"
	"sort"
	"time"
)

type OptionStruct struct {
	NoKokushi      bool
	NoChitoitsu    bool
	NoNormal       bool
	OutputPerTrial int
}

var option OptionStruct

func Start(o OptionStruct) {
	option = o

	start := time.Now().UnixNano()
	var i float64
	i = 0
	var hai string
	var ok bool
	for {
		i++
		seed := time.Now().UnixNano()
		hai, ok = tryOnce(seed)
		if ok || int(i)%option.OutputPerTrial == 0 {
			end := time.Now().UnixNano()
			diff := float64(end-start) / 1000000000
			m := i / diff
			out := 0
			if m >= 0 {
				out = int(m)
			}
			fmt.Printf("\r%v回試行  %v秒経過 %v回/秒 %v", i, diff, out, hai)
		}
		if ok {
			break
		}
	}
	fmt.Printf("\n")
}

func tryOnce(seed int64) (string, bool) {
	hand := ShuffledHand(seed)
	hai := hand.HaiString()
	ok := hand.Solve()
	return hai, ok
}

// http://d.hatena.ne.jp/hake/20150930/p1
func shuffle(hand Hand) {
	for i := len(hand); i > 1; i-- {
		j := rand.Intn(i) // 0 .. i-1 の乱数発生
		hand[i-1], hand[j] = hand[j], hand[i-1]
	}
}

const HandSize = 14
const MahjongSetSize = 136

var defaultSet []int

func GetMahjongSet() []int {
	if defaultSet == nil {
		size := MahjongSetSize
		defaultSet = make([]int, size, size)
		for i := 0; i < size; i++ {
			defaultSet[i] = i / 4
		}
	}
	return defaultSet
}

func ShuffledHand(seed int64) Hand {
	rand.Seed(seed)

	hand := make(Hand, MahjongSetSize, MahjongSetSize)
	copy(hand, GetMahjongSet())
	hand2 := make(Hand, 0, 0)
	var j int

	for k := MahjongSetSize; k > MahjongSetSize-HandSize; k-- {
		j = rand.Intn(k)
		hand2 = append(hand2, hand[j])
		hand = append(hand[:j], hand[j+1:]...)
	}

	return hand2
}

type Hand []int

// 牌文字への変換(スペース区切り)
func (hand Hand) HaiString() string {
	// http://qiita.com/ruiu/items/2bb83b29baeae2433a79
	// サイズ0、内部バッファの長さ69の[]byteの値を割り当てる
	b := make([]byte, 0, 70)

	// bに文字列を追加
	for j := 0; j < HandSize; j++ {
		// コードポイント上、普通の麻雀牌はU+1F000からの34個。
		// U+1F000 is 'MAHJONG TILE EAST WIND' ('東')
		// https://codepoints.net/U+1F000
		b = append(b, string(hand[j]+0x1F000)...) // appendするには...が必要
		// 自分のMacではスペース区切りでないとうまく表示されないためスペースを挿入する
		// U+0020 is 'SPACE'
		// https://codepoints.net/U+0020
		b = append(b, string(0x20)...) // appendするには...が必要
	}
	return string(b)
}

// 七対子判定
func (hand Hand) solveChitoitsu() bool {
	//カウンタ
	c := map[int]int{}

	for _, v := range hand {
		count, ok := c[v]
		if ok {
			if count == 1 {
				c[v] = 2
			} else {
				// c[v] == 2
				return false
			}
		} else {
			c[v] = 1
		}
		//8個チェック
		if len(c) >= 8 {
			return false
		}
	}
	return true
}

// 国士無双判定
func (hand Hand) solveKokushi() bool {
	sort.Ints(hand)
	//比較するために配列にする
	var a [HandSize]int
	for i := 0; i < HandSize; i++ {
		a[i] = hand[i]
	}

	//あがりパターン列挙
	agaris := [13][14]int{
		[14]int{0, 0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 4, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 5, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 6, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 7, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 15, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 16, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 24, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 25, 33},
		[14]int{0, 1, 2, 3, 4, 5, 6, 7, 15, 16, 24, 25, 33, 33},
	}
	for _, v := range agaris {
		if v == a {
			return true
		}
	}
	return false
}

// あがり判定する
func (hand Hand) Solve() bool {
	return (!(option.NoKokushi) && hand.solveKokushi()) || (!(option.NoChitoitsu) && hand.solveChitoitsu()) || (!(option.NoNormal) && hand.GroupSuit().Solve())
}

type SuitGroup struct {
	innerSuitGroup
	color int
}

type innerSuitGroup []int

func NewSuitGroup(color int) *SuitGroup {
	s := SuitGroup{innerSuitGroup{}, color}
	return &s
}

type SuitsGroupedHand map[int]SuitGroup

const (
	Jihai = iota
	Manzu
	Sozu
	Pinzu
)

// スート分類
func (hand Hand) GroupSuit() SuitsGroupedHand {
	m := SuitsGroupedHand{
		Jihai: *NewSuitGroup(Jihai),
		Manzu: *NewSuitGroup(Manzu),
		Sozu:  *NewSuitGroup(Sozu),
		Pinzu: *NewSuitGroup(Pinzu),
	}
	for _, i := range hand {
		quo := (i - 7 + 9) / 9
		var mod int
		if i-7 >= 0 {
			mod = (i - 7) % 9
		} else {
			mod = i
		}
		s := m[quo]
		s.append(mod)
		m[quo] = s
	}
	return m
}

func (m SuitsGroupedHand) Solve() bool {
	return m.a_pair_existible() && m.valid_33332()
}
func (m SuitsGroupedHand) a_pair_existible() bool {
	//スートのサイズを3で割った時
	//あまりが2であるスートグループが1つであること
	c := 0
	for _, a := range m {
		switch len(a.list()) % 3 {
		case 0:
			// noop
		case 1:
			return false
		case 2:
			c++
		}
	}
	return c == 1
}

func (m SuitsGroupedHand) valid_33332() bool {
	for i := 0; i < 4; i++ {
		if !m[i].valid_suit_group(i) {
			return false
		}
	}
	return true
}

func (a innerSuitGroup) list() innerSuitGroup {
	return a
}

func (a *innerSuitGroup) SetSuitGroup(b innerSuitGroup) {
	*a = b
}

func (a *innerSuitGroup) append(w int) {
	*a = append(*a, w)
}

// 33332形を形成するスートグループがどうかを判定
func (a SuitGroup) valid_suit_group(i int) bool {
	// 対子が含まれているスートグループがただ1つある前提

	//ソート
	sort.Ints(a.list())
	if len(a.list())%3 == 2 {
		//ペアを探す
		pair_numbers := a.pairable_numbers()
		//ペア候補がなかったらぬける
		if len(pair_numbers) == 0 {
			return false
		}
		//ペア候補毎に繰り返し処理
		for _, v := range pair_numbers {
			//ペアとなる２枚を除去
			rest := NewSuitGroup(i)
			c := 2
			for _, w := range a.list() {
				// ペア候補以外は新スライスに入れる
				// ペア候補は３枚目以降は新スライスに入れる
				if w != v || c <= 0 {
					rest.SetSuitGroup(append(rest.list(), w))
				}
				if w == v {
					c--
				}
			}
			if rest.valid_3cards() {
				return true
			} else {
				continue
			}
		}
		return false
	} else if len(a.list())%3 == 0 {
		return a.valid_3cards()
	}
	// 到達しないはず
	panic("到達しないはず")
}

func (a SuitGroup) valid_3cards() bool {
	// 刻子や順子のみで構成されている場合true
	// a is sorted
	// a.size % 3 is0
	for {
		if a.remove_kotsu() {
			continue
		}
		break
	}

	// 字牌でなければ順子チェック
	if a.color != Jihai {
		for {
			if a.remove_shuntsu() {
				continue
			}
			break
		}
	}
	return len(a.list()) == 0
}

func (a *innerSuitGroup) remove_kotsu() bool {
	// 刻子を除去できればtrue
	// a is sorted
	x := *a
	if len(x) < 3 {
		return false
	}
	if x[0] == x[1] && x[0] == x[2] {
		*a = x[3:]
		return true
	}
	return false
}

func (a *innerSuitGroup) remove_shuntsu() bool {
	// 順子を除去できればtrue
	// a is sorted
	rest := innerSuitGroup{}
	first := -1
	second := -1
	found := false
	for _, v := range *a {
		if found {
			rest = append(rest, v)
			continue
		}
		if first == -1 {
			first = v
		} else if second == -1 && first+1 == v {
			second = v
		} else if second != -1 && first+2 == v {
			//flush
			first = -1
			second = -1
			found = true
		} else {
			rest = append(rest, v)
		}
	}
	*a = rest
	return found
}

func (a innerSuitGroup) pairable_numbers() innerSuitGroup {
	// a is sorted
	counter := []int{}
	var x, y int // 2つ前と1つ前
	for _, v := range a {
		if y == v && x != v {
			counter = append(counter, v)
		} else {
			y = v
		}
	}
	return counter
}
<|endoftext|>


<commit_before>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build (darwin || dragonfly || freebsd || (linux && !android) || netbsd || openbsd) && cgo

// Note that this test does not work on Solaris: issue #22849.
// Don't run the test on Android because at least some versions of the
// C library do not define the posix_openpt function.

package signal_test

import (
	"bufio"
	"bytes"
	"context"
	"fmt"
	"io"
	"io/fs"
	"os"
	"os/exec"
	ptypkg "os/signal/internal/pty"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"testing"
	"time"
)

func TestTerminalSignal(t *testing.T) {
	const enteringRead = "test program entering read"
	if os.Getenv("GO_TEST_TERMINAL_SIGNALS") != "" {
		var b [1]byte
		fmt.Println(enteringRead)
		n, err := os.Stdin.Read(b[:])
		if n == 1 {
			if b[0] == '\n' {
				// This is what we expect
				fmt.Println("read newline")
			} else {
				fmt.Printf("read 1 byte: %q\n", b)
			}
		} else {
			fmt.Printf("read %d bytes\n", n)
		}
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		os.Exit(0)
	}

	t.Parallel()

	// The test requires a shell that uses job control.
	bash, err := exec.LookPath("bash")
	if err != nil {
		t.Skipf("could not find bash: %v", err)
	}

	scale := 1
	if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
		if sc, err := strconv.Atoi(s); err == nil {
			scale = sc
		}
	}
	pause := time.Duration(scale) * 10 * time.Millisecond
	wait := time.Duration(scale) * 5 * time.Second

	// The test only fails when using a "slow device," in this
	// case a pseudo-terminal.

	pty, procTTYName, err := ptypkg.Open()
	if err != nil {
		ptyErr := err.(*ptypkg.PtyError)
		if ptyErr.FuncName == "posix_openpt" && ptyErr.Errno == syscall.EACCES {
			t.Skip("posix_openpt failed with EACCES, assuming chroot and skipping")
		}
		t.Fatal(err)
	}
	defer pty.Close()
	procTTY, err := os.OpenFile(procTTYName, os.O_RDWR, 0)
	if err != nil {
		t.Fatal(err)
	}
	defer procTTY.Close()

	// Start an interactive shell.
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	cmd := exec.CommandContext(ctx, bash, "--norc", "--noprofile", "-i")
	// Clear HISTFILE so that we don't read or clobber the user's bash history.
	cmd.Env = append(os.Environ(), "HISTFILE=")
	cmd.Stdin = procTTY
	cmd.Stdout = procTTY
	cmd.Stderr = procTTY
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Setsid:  true,
		Setctty: true,
		Ctty:    0,
	}

	if err := cmd.Start(); err != nil {
		t.Fatal(err)
	}

	if err := procTTY.Close(); err != nil {
		t.Errorf("closing procTTY: %v", err)
	}

	progReady := make(chan bool)
	sawPrompt := make(chan bool, 10)
	const prompt = "prompt> "

	// Read data from pty in the background.
	var wg sync.WaitGroup
	wg.Add(1)
	defer wg.Wait()
	go func() {
		defer wg.Done()
		input := bufio.NewReader(pty)
		var line, handled []byte
		for {
			b, err := input.ReadByte()
			if err != nil {
				if len(line) > 0 || len(handled) > 0 {
					t.Logf("%q", append(handled, line...))
				}
				if perr, ok := err.(*fs.PathError); ok {
					err = perr.Err
				}
				// EOF means pty is closed.
				// EIO means child process is done.
				// "file already closed" means deferred close of pty has happened.
				if err != io.EOF && err != syscall.EIO && !strings.Contains(err.Error(), "file already closed") {
					t.Logf("error reading from pty: %v", err)
				}
				return
			}

			line = append(line, b)

			if b == '\n' {
				t.Logf("%q", append(handled, line...))
				line = nil
				handled = nil
				continue
			}

			if bytes.Contains(line, []byte(enteringRead)) {
				close(progReady)
				handled = append(handled, line...)
				line = nil
			} else if bytes.Contains(line, []byte(prompt)) && !bytes.Contains(line, []byte("PS1=")) {
				sawPrompt <- true
				handled = append(handled, line...)
				line = nil
			}
		}
	}()

	// Set the bash prompt so that we can see it.
	if _, err := pty.Write([]byte("PS1='" + prompt + "'\n")); err != nil {
		t.Fatalf("setting prompt: %v", err)
	}
	select {
	case <-sawPrompt:
	case <-time.After(wait):
		t.Fatal("timed out waiting for shell prompt")
	}

	// Start a small program that reads from stdin
	// (namely the code at the top of this function).
	if _, err := pty.Write([]byte("GO_TEST_TERMINAL_SIGNALS=1 " + os.Args[0] + " -test.run=TestTerminalSignal\n")); err != nil {
		t.Fatal(err)
	}

	// Wait for the program to print that it is starting.
	select {
	case <-progReady:
	case <-time.After(wait):
		t.Fatal("timed out waiting for program to start")
	}

	// Give the program time to enter the read call.
	// It doesn't matter much if we occasionally don't wait long enough;
	// we won't be testing what we want to test, but the overall test
	// will pass.
	time.Sleep(pause)

	// Send a ^Z to stop the program.
	if _, err := pty.Write([]byte{26}); err != nil {
		t.Fatalf("writing ^Z to pty: %v", err)
	}

	// Wait for the program to stop and return to the shell.
	select {
	case <-sawPrompt:
	case <-time.After(wait):
		t.Fatal("timed out waiting for shell prompt")
	}

	// Restart the stopped program.
	if _, err := pty.Write([]byte("fg\n")); err != nil {
		t.Fatalf("writing %q to pty: %v", "fg", err)
	}

	// Give the process time to restart.
	// This is potentially racy: if the process does not restart
	// quickly enough then the byte we send will go to bash rather
	// than the program. Unfortunately there isn't anything we can
	// look for to know that the program is running again.
	// bash will print the program name, but that happens before it
	// restarts the program.
	time.Sleep(10 * pause)

	// Write some data for the program to read,
	// which should cause it to exit.
	if _, err := pty.Write([]byte{'\n'}); err != nil {
		t.Fatalf("writing %q to pty: %v", "\n", err)
	}

	// Wait for the program to exit.
	select {
	case <-sawPrompt:
	case <-time.After(wait):
		t.Fatal("timed out waiting for shell prompt")
	}

	// Exit the shell with the program's exit status.
	if _, err := pty.Write([]byte("exit $?\n")); err != nil {
		t.Fatalf("writing %q to pty: %v", "exit", err)
	}

	if err = cmd.Wait(); err != nil {
		t.Errorf("subprogram failed: %v", err)
	}
}
<commit_msg>os/signal: disable GNU readline to deflake TestTerminalSignal<commit_after>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build (darwin || dragonfly || freebsd || (linux && !android) || netbsd || openbsd) && cgo

// Note that this test does not work on Solaris: issue #22849.
// Don't run the test on Android because at least some versions of the
// C library do not define the posix_openpt function.

package signal_test

import (
	"bufio"
	"bytes"
	"context"
	"fmt"
	"io"
	"io/fs"
	"os"
	"os/exec"
	ptypkg "os/signal/internal/pty"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"testing"
	"time"
)

func TestTerminalSignal(t *testing.T) {
	const enteringRead = "test program entering read"
	if os.Getenv("GO_TEST_TERMINAL_SIGNALS") != "" {
		var b [1]byte
		fmt.Println(enteringRead)
		n, err := os.Stdin.Read(b[:])
		if n == 1 {
			if b[0] == '\n' {
				// This is what we expect
				fmt.Println("read newline")
			} else {
				fmt.Printf("read 1 byte: %q\n", b)
			}
		} else {
			fmt.Printf("read %d bytes\n", n)
		}
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		os.Exit(0)
	}

	t.Parallel()

	// The test requires a shell that uses job control.
	bash, err := exec.LookPath("bash")
	if err != nil {
		t.Skipf("could not find bash: %v", err)
	}

	scale := 1
	if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
		if sc, err := strconv.Atoi(s); err == nil {
			scale = sc
		}
	}
	pause := time.Duration(scale) * 10 * time.Millisecond
	wait := time.Duration(scale) * 5 * time.Second

	// The test only fails when using a "slow device," in this
	// case a pseudo-terminal.

	pty, procTTYName, err := ptypkg.Open()
	if err != nil {
		ptyErr := err.(*ptypkg.PtyError)
		if ptyErr.FuncName == "posix_openpt" && ptyErr.Errno == syscall.EACCES {
			t.Skip("posix_openpt failed with EACCES, assuming chroot and skipping")
		}
		t.Fatal(err)
	}
	defer pty.Close()
	procTTY, err := os.OpenFile(procTTYName, os.O_RDWR, 0)
	if err != nil {
		t.Fatal(err)
	}
	defer procTTY.Close()

	// Start an interactive shell.
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	cmd := exec.CommandContext(ctx, bash, "--norc", "--noprofile", "--noediting", "-i")
	// Clear HISTFILE so that we don't read or clobber the user's bash history.
	cmd.Env = append(os.Environ(), "HISTFILE=")
	cmd.Stdin = procTTY
	cmd.Stdout = procTTY
	cmd.Stderr = procTTY
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Setsid:  true,
		Setctty: true,
		Ctty:    0,
	}

	if err := cmd.Start(); err != nil {
		t.Fatal(err)
	}

	if err := procTTY.Close(); err != nil {
		t.Errorf("closing procTTY: %v", err)
	}

	progReady := make(chan bool)
	sawPrompt := make(chan bool, 10)
	const prompt = "prompt> "

	// Read data from pty in the background.
	var wg sync.WaitGroup
	wg.Add(1)
	defer wg.Wait()
	go func() {
		defer wg.Done()
		input := bufio.NewReader(pty)
		var line, handled []byte
		for {
			b, err := input.ReadByte()
			if err != nil {
				if len(line) > 0 || len(handled) > 0 {
					t.Logf("%q", append(handled, line...))
				}
				if perr, ok := err.(*fs.PathError); ok {
					err = perr.Err
				}
				// EOF means pty is closed.
				// EIO means child process is done.
				// "file already closed" means deferred close of pty has happened.
				if err != io.EOF && err != syscall.EIO && !strings.Contains(err.Error(), "file already closed") {
					t.Logf("error reading from pty: %v", err)
				}
				return
			}

			line = append(line, b)

			if b == '\n' {
				t.Logf("%q", append(handled, line...))
				line = nil
				handled = nil
				continue
			}

			if bytes.Contains(line, []byte(enteringRead)) {
				close(progReady)
				handled = append(handled, line...)
				line = nil
			} else if bytes.Contains(line, []byte(prompt)) && !bytes.Contains(line, []byte("PS1=")) {
				sawPrompt <- true
				handled = append(handled, line...)
				line = nil
			}
		}
	}()

	// Set the bash prompt so that we can see it.
	if _, err := pty.Write([]byte("PS1='" + prompt + "'\n")); err != nil {
		t.Fatalf("setting prompt: %v", err)
	}
	select {
	case <-sawPrompt:
	case <-time.After(wait):
		t.Fatal("timed out waiting for shell prompt")
	}

	// Start a small program that reads from stdin
	// (namely the code at the top of this function).
	if _, err := pty.Write([]byte("GO_TEST_TERMINAL_SIGNALS=1 " + os.Args[0] + " -test.run=TestTerminalSignal\n")); err != nil {
		t.Fatal(err)
	}

	// Wait for the program to print that it is starting.
	select {
	case <-progReady:
	case <-time.After(wait):
		t.Fatal("timed out waiting for program to start")
	}

	// Give the program time to enter the read call.
	// It doesn't matter much if we occasionally don't wait long enough;
	// we won't be testing what we want to test, but the overall test
	// will pass.
	time.Sleep(pause)

	// Send a ^Z to stop the program.
	if _, err := pty.Write([]byte{26}); err != nil {
		t.Fatalf("writing ^Z to pty: %v", err)
	}

	// Wait for the program to stop and return to the shell.
	select {
	case <-sawPrompt:
	case <-time.After(wait):
		t.Fatal("timed out waiting for shell prompt")
	}

	// Restart the stopped program.
	if _, err := pty.Write([]byte("fg\n")); err != nil {
		t.Fatalf("writing %q to pty: %v", "fg", err)
	}

	// Give the process time to restart.
	// This is potentially racy: if the process does not restart
	// quickly enough then the byte we send will go to bash rather
	// than the program. Unfortunately there isn't anything we can
	// look for to know that the program is running again.
	// bash will print the program name, but that happens before it
	// restarts the program.
	time.Sleep(10 * pause)

	// Write some data for the program to read,
	// which should cause it to exit.
	if _, err := pty.Write([]byte{'\n'}); err != nil {
		t.Fatalf("writing %q to pty: %v", "\n", err)
	}

	// Wait for the program to exit.
	select {
	case <-sawPrompt:
	case <-time.After(wait):
		t.Fatal("timed out waiting for shell prompt")
	}

	// Exit the shell with the program's exit status.
	if _, err := pty.Write([]byte("exit $?\n")); err != nil {
		t.Fatalf("writing %q to pty: %v", "exit", err)
	}

	if err = cmd.Wait(); err != nil {
		t.Errorf("subprogram failed: %v", err)
	}
}
<|endoftext|>