<commit_before>package cryptica

import "bytes"

type Solution []Direction

func (solution *Solution) String() string {
	var buffer bytes.Buffer
	for i, dir := range *solution {
		switch {
		case i > 0:
			buffer.WriteRune(' ')
		default:
			buffer.WriteString(dir.String())
		}
	}
	return buffer.String()
}

type Game struct {
	State State
	Goal  Goal
	Steps int
}

type Solver interface {
	solve(game Game, solutions chan Solution)
}

type DepthFirstSolver struct {
}

func (solver DepthFirstSolver) solve(game Game, solutions chan Solution) {
	cache := make(map[uint64]int)
	f := func(state State, solution Solution, k interface{}) {
		n := len(solution)
		if n > game.Steps {
			return
		}
		code := state.Board.Encode(state)
		if m, exists := cache[code]; exists && m <= n {
			return
		}
		cache[code] = n
		if state.Match(game.Goal) {
			newsolution := make(Solution, len(solution))
			copy(newsolution, solution)
			solutions <- newsolution
			return
		}
		f := k.(func(State, Solution, interface{}))
		for i := Up; i <= Right; i++ {
			dir := Direction(i)
			f(state.Move(dir), append(solution, dir), k)
		}
	}
	f(game.State, make(Solution, 0), f)
}

type BreadthFirstSolver struct {
}

func (solver BreadthFirstSolver) solve(game Game, solutions chan Solution) {
	cache := make(map[uint64]Solution)
	var current, next []uint64
	{
		code := game.State.Board.Encode(game.State)
		cache[code] = make(Solution, 0)
		current = []uint64{code}
	}
	for depth := 0; depth < game.Steps && len(current) > 0; depth++ {
		next = make([]uint64, 0)
		for _, code := range current {
			solution := cache[code]
			state := game.State.Board.Decode(code)
			if state.Match(game.Goal) {
				solutions <- solution
				continue
			}
			for i := Up; i <= Right; i++ {
				dir := Direction(i)
				newstate := state.Move(dir)
				newcode := game.State.Board.Encode(newstate)
				if _, exists := cache[newcode]; !exists {
					newsolution := make(Solution, len(solution))
					copy(newsolution, solution)
					newsolution = append(newsolution, dir)
					cache[newcode] = newsolution
					next = append(next, newcode)
				}
			}
		}
		current = next
	}
}<commit_msg>ditched channels: now we return only the first solution<commit_after>package cryptica

import "bytes"

type Solution []Direction

func (solution *Solution) String() string {
	var buffer bytes.Buffer
	for i, dir := range *solution {
		switch {
		case i > 0:
			buffer.WriteRune(' ')
		default:
			buffer.WriteString(dir.String())
		}
	}
	return buffer.String()
}

type Game struct {
	State State
	Goal  Goal
	Steps int
}

type Solver interface {
	solve(game Game) (Solution, bool)
}

type DepthFirstSolver struct {
}

func (solver DepthFirstSolver) solve(game Game) (Solution, bool) {
	cache := make(map[uint64]int)
	f := func(state State, solution Solution, k interface{}) (Solution, bool) {
		n := len(solution)
		if n > game.Steps {
			return nil, false
		}
		code := state.Board.Encode(state)
		if m, exists := cache[code]; exists && m <= n {
			return nil, false
		}
		cache[code] = n
		if state.Match(game.Goal) {
			return solution, true
		}
		f := k.(func(State, Solution, interface{}) (Solution, bool))
		for i := Up; i <= Right; i++ {
			dir := Direction(i)
			if result, ok := f(state.Move(dir), append(solution, dir), k); ok {
				return result, true
			}
		}
		return nil, false
	}
	return f(game.State, make(Solution, 0), f)
}

type BreadthFirstSolver struct {
}

func (solver BreadthFirstSolver) solve(game Game) (Solution, bool) {
	cache := make(map[uint64]Solution)
	var current, next []uint64
	{
		code := game.State.Board.Encode(game.State)
		cache[code] = make(Solution, 0)
		current = []uint64{code}
	}
	for depth := 0; depth < game.Steps && len(current) > 0; depth++ {
		next = make([]uint64, 0)
		for _, code := range current {
			solution := cache[code]
			state := game.State.Board.Decode(code)
			if state.Match(game.Goal) {
				return solution, true
			}
			for i := Up; i <= Right; i++ {
				dir := Direction(i)
				newstate := state.Move(dir)
				newcode := game.State.Board.Encode(newstate)
				if _, exists := cache[newcode]; !exists {
					newsolution := make(Solution, len(solution))
					copy(newsolution, solution)
					newsolution = append(newsolution, dir)
					cache[newcode] = newsolution
					next = append(next, newcode)
				}
			}
		}
		current = next
	}
	return nil, false
}
{'fraction_non_alphanumeric': 0.1415807560137457, 'fraction_numerical': 0.007331042382588774, 'mean_word_length': 3.4642126789366054, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1926348', 'n_tokens_mistral': 1750, 'n_tokens_neox': 1499, 'n_words': 408}