Решение на Фабрика за регулярни изрази от Александър Ваканин

Обратно към всички решения

Към профила на Александър Ваканин

Резултати

  • 9 точки от тестове
  • 0 бонус точки
  • 9 точки общо
  • 8 успешни тест(а)
  • 1 неуспешни тест(а)

Код

package main
import (
"fmt"
"regexp"
"sync"
"time"
)
var (
wg sync.WaitGroup
errUnableToProduce = fmt.Errorf("Unable to produce")
)
const (
DOES_NOT_EXIST = iota
ENQUEUED
IN_PROGRESS
UNABLE_TO_PRODUCE
DONE
)
type Order struct {
Id string
Status int
Words []string
Result string
Channel chan *Order
}
func NewOrder(words []string, channel chan *Order) *Order {
order := new(Order)
order.Id = time.Now().String()
order.Status = DOES_NOT_EXIST
order.Words = words[:]
order.Result = "^"
order.Channel = channel
return order
}
type Factory struct {
Workers []*Worker
Orders map[string]*Order
Storage *Storage
}
func NewFactory(workers uint8) *Factory {
factory := new(Factory)
factory.Workers = make([]*Worker, workers)
factory.Orders = make(map[string]*Order)
factory.Storage = NewStorage()
var i uint8
for i = 0; i < workers; i++ {
factory.Workers[i] = NewWorker(factory.Storage)
}
go factory.StartProducing()
return factory
}
func (f *Factory) Enqueue(order *Order) {
order.Status = ENQUEUED
f.Orders[order.Id] = order
}
func (f *Factory) StartProducing() {
for _, worker := range f.Workers {
for _, order := range f.Orders {
if order.Status == ENQUEUED {
order.Status = IN_PROGRESS
wg.Add(1)
go func() {
defer wg.Done()
if !worker.ExecuteOrder(order) {
order.Status = UNABLE_TO_PRODUCE
fmt.Printf("Cannot match order with id: %s\n", order.Id)
} else {
order.Status = DONE
}
}()
break
}
}
}
}
func (f *Factory) StopProducing() {
wg.Wait()
}
func (f *Factory) StorageAdd(materials map[string]uint16) {
f.Storage.AddMaterials(materials)
}
func (f *Factory) ReturnResult(order *Order) {
for _, order := range f.Orders {
if order.Status == DONE {
order.Channel <- order
}
}
}
func (f *Factory) generateRegexp(words []string) (string, error) {
worker := NewWorker(f.Storage)
ch := make(chan *Order)
order := NewOrder(words, ch)
if worker.ExecuteOrder(order) {
return order.Result, nil
} else {
return "", errUnableToProduce
}
}
//===============================================================================
type Client struct {
Name string
Orders map[string]*Order
Channel chan *Order
}
func NewClient(name string) *Client {
client := new(Client)
client.Name = name
client.Orders = make(map[string]*Order)
client.Channel = make(chan *Order)
return client
}
func (c *Client) Order(factory *Factory, words []string) string {
order := NewOrder(words, c.Channel)
order.Status = DOES_NOT_EXIST
c.Orders[order.Id] = order
factory.Enqueue(order)
return order.Id
}
func (c *Client) CheckStatus(id string) int {
order, ok := c.Orders[id]
if ok {
return order.Status
} else {
return DOES_NOT_EXIST
}
}
//==================================================================================================
type Storage struct {
Materials map[string]uint16
sync.Mutex
}
func NewStorage() *Storage {
storage := new(Storage)
storage.Materials = make(map[string]uint16)
return storage
}
func (s *Storage) AddMaterials(materials map[string]uint16) {
s.Lock()
defer s.Unlock()
for key, value := range materials {
if oldValue, ok := s.Materials[key]; ok {
value += oldValue
}
s.Materials[key] = value
}
}
//===============================================================================================
type Worker struct {
Storage *Storage
sync.Mutex
}
func NewWorker(storage *Storage) *Worker {
worker := new(Worker)
worker.Storage = storage
return worker
}
func Check(words []string, expression string) bool {
r, err := regexp.Compile(expression)
if err != nil {
return false
}
for _, word := range words {
if !r.MatchString(word) {
return false
}
}
return true
}
func StartingWith(words []string, expression string) bool {
r, err := regexp.Compile(expression)
if err != nil {
return false
}
for _, word := range words {
if r.FindStringIndex(word) == nil {
return false
}
}
return true
}
func (w *Worker) ExecuteOrder(order *Order) bool {
w.Lock()
defer w.Unlock()
beginings := []string{""}
newBeginings := make([]string, 1)
for beginings != nil {
for _, begin := range beginings {
for material, value := range w.Storage.Materials {
if value > 0 {
solution := "^" + begin + material + "$"
start := begin + material
if Check(order.Words, solution) {
order.Result = solution
for _, materialForRemove := range beginings {
quantity := w.Storage.Materials[materialForRemove]
if quantity > 0 {
w.Storage.Materials[materialForRemove] = quantity - 1
}
}
return true
} else {
if StartingWith(order.Words, start) {
newBeginings = append(newBeginings, start)
}
}
}
}
}
beginings = newBeginings[:]
newBeginings = nil
}
return false
}

Лог от изпълнението

PASS
ok  	_/tmp/d20150111-18989-11xxma0	0.003s
PASS
ok  	_/tmp/d20150111-18989-11xxma0	0.003s
PASS
ok  	_/tmp/d20150111-18989-11xxma0	0.003s
PASS
ok  	_/tmp/d20150111-18989-11xxma0	0.003s
PASS
ok  	_/tmp/d20150111-18989-11xxma0	0.003s
--- FAIL: TestProcessWithoutEnoughMaterials (0.00 seconds)
	solution_test.go:76: Generated regexp without enough materials and got ^bambam$
FAIL
exit status 1
FAIL	_/tmp/d20150111-18989-11xxma0	0.003s
PASS
ok  	_/tmp/d20150111-18989-11xxma0	0.004s
PASS
ok  	_/tmp/d20150111-18989-11xxma0	0.003s
PASS
ok  	_/tmp/d20150111-18989-11xxma0	0.003s

История (1 версия и 0 коментара)

Александър обнови решението на 30.12.2014 22:19 (преди над 3 години)

+package main
+
+import (
+ "fmt"
+ "regexp"
+ "sync"
+ "time"
+)
+
+var (
+ wg sync.WaitGroup
+ errUnableToProduce = fmt.Errorf("Unable to produce")
+)
+
+const (
+ DOES_NOT_EXIST = iota
+ ENQUEUED
+ IN_PROGRESS
+ UNABLE_TO_PRODUCE
+ DONE
+)
+
+type Order struct {
+ Id string
+ Status int
+ Words []string
+ Result string
+ Channel chan *Order
+}
+
+func NewOrder(words []string, channel chan *Order) *Order {
+ order := new(Order)
+ order.Id = time.Now().String()
+ order.Status = DOES_NOT_EXIST
+ order.Words = words[:]
+ order.Result = "^"
+ order.Channel = channel
+ return order
+}
+
+type Factory struct {
+ Workers []*Worker
+ Orders map[string]*Order
+ Storage *Storage
+}
+
+func NewFactory(workers uint8) *Factory {
+ factory := new(Factory)
+ factory.Workers = make([]*Worker, workers)
+ factory.Orders = make(map[string]*Order)
+ factory.Storage = NewStorage()
+ var i uint8
+ for i = 0; i < workers; i++ {
+ factory.Workers[i] = NewWorker(factory.Storage)
+ }
+ go factory.StartProducing()
+ return factory
+}
+
+func (f *Factory) Enqueue(order *Order) {
+ order.Status = ENQUEUED
+ f.Orders[order.Id] = order
+}
+
+func (f *Factory) StartProducing() {
+ for _, worker := range f.Workers {
+ for _, order := range f.Orders {
+ if order.Status == ENQUEUED {
+ order.Status = IN_PROGRESS
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ if !worker.ExecuteOrder(order) {
+ order.Status = UNABLE_TO_PRODUCE
+ fmt.Printf("Cannot match order with id: %s\n", order.Id)
+ } else {
+ order.Status = DONE
+ }
+ }()
+ break
+ }
+ }
+ }
+}
+
+func (f *Factory) StopProducing() {
+ wg.Wait()
+}
+
+func (f *Factory) StorageAdd(materials map[string]uint16) {
+ f.Storage.AddMaterials(materials)
+}
+
+func (f *Factory) ReturnResult(order *Order) {
+ for _, order := range f.Orders {
+ if order.Status == DONE {
+ order.Channel <- order
+ }
+ }
+}
+
+func (f *Factory) generateRegexp(words []string) (string, error) {
+ worker := NewWorker(f.Storage)
+ ch := make(chan *Order)
+ order := NewOrder(words, ch)
+ if worker.ExecuteOrder(order) {
+ return order.Result, nil
+ } else {
+ return "", errUnableToProduce
+ }
+}
+
+//===============================================================================
+type Client struct {
+ Name string
+ Orders map[string]*Order
+ Channel chan *Order
+}
+
+func NewClient(name string) *Client {
+ client := new(Client)
+ client.Name = name
+ client.Orders = make(map[string]*Order)
+ client.Channel = make(chan *Order)
+ return client
+}
+
+func (c *Client) Order(factory *Factory, words []string) string {
+ order := NewOrder(words, c.Channel)
+ order.Status = DOES_NOT_EXIST
+ c.Orders[order.Id] = order
+ factory.Enqueue(order)
+ return order.Id
+}
+
+func (c *Client) CheckStatus(id string) int {
+ order, ok := c.Orders[id]
+ if ok {
+ return order.Status
+ } else {
+ return DOES_NOT_EXIST
+ }
+}
+
+//==================================================================================================
+type Storage struct {
+ Materials map[string]uint16
+ sync.Mutex
+}
+
+func NewStorage() *Storage {
+ storage := new(Storage)
+ storage.Materials = make(map[string]uint16)
+ return storage
+}
+
+func (s *Storage) AddMaterials(materials map[string]uint16) {
+ s.Lock()
+ defer s.Unlock()
+ for key, value := range materials {
+ if oldValue, ok := s.Materials[key]; ok {
+ value += oldValue
+ }
+ s.Materials[key] = value
+ }
+}
+
+//===============================================================================================
+type Worker struct {
+ Storage *Storage
+ sync.Mutex
+}
+
+func NewWorker(storage *Storage) *Worker {
+ worker := new(Worker)
+ worker.Storage = storage
+ return worker
+}
+
+func Check(words []string, expression string) bool {
+ r, err := regexp.Compile(expression)
+ if err != nil {
+ return false
+ }
+ for _, word := range words {
+ if !r.MatchString(word) {
+ return false
+ }
+ }
+ return true
+}
+
+func StartingWith(words []string, expression string) bool {
+ r, err := regexp.Compile(expression)
+ if err != nil {
+ return false
+ }
+ for _, word := range words {
+ if r.FindStringIndex(word) == nil {
+ return false
+ }
+ }
+ return true
+}
+
+func (w *Worker) ExecuteOrder(order *Order) bool {
+ w.Lock()
+ defer w.Unlock()
+ beginings := []string{""}
+ newBeginings := make([]string, 1)
+ for beginings != nil {
+ for _, begin := range beginings {
+ for material, value := range w.Storage.Materials {
+ if value > 0 {
+ solution := "^" + begin + material + "$"
+ start := begin + material
+ if Check(order.Words, solution) {
+ order.Result = solution
+ for _, materialForRemove := range beginings {
+ quantity := w.Storage.Materials[materialForRemove]
+ if quantity > 0 {
+ w.Storage.Materials[materialForRemove] = quantity - 1
+ }
+ }
+ return true
+ } else {
+ if StartingWith(order.Words, start) {
+ newBeginings = append(newBeginings, start)
+ }
+ }
+ }
+ }
+ }
+ beginings = newBeginings[:]
+ newBeginings = nil
+ }
+ return false
+}