Александър обнови решението на 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
+}
