Александър обнови решението на 31.12.2014 19:18 (преди над 3 години)
+package main
+
+import (
+ "errors"
+ "regexp"
+ "strconv"
+ "sync"
+)
+
+var idCnt int
+
+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 {
+ var tmp Order
+ tmp.Id = strconv.Itoa(idCnt)
+ idCnt++
+ tmp.Status = ENQUEUED
+ tmp.Words = words
+ tmp.Result = ""
+ tmp.Channel = make(chan *Order)
+ return &tmp
+}
+
+type Client struct {
+ Name string
+ Orders map[string]*Order
+ Channel chan *Order
+}
+
+func NewClient(name string) *Client {
+ var tmp Client
+ tmp.Name = name
+ tmp.Orders = make(map[string]*Order)
+ tmp.Channel = make(chan *Order)
+ return &tmp
+}
+
+func (c *Client) Order(factory *Factory, words []string) string {
+ order := NewOrder(words, c.Channel)
+ c.Orders[order.Id] = order
+ factory.Enqueue(order)
+ return order.Id
+}
+
+func (c *Client) CheckStatus(id string) int {
+ val, ok := c.Orders[id]
+ if !ok {
+ return DOES_NOT_EXIST
+ }
+ return val.Status
+}
+
+type Factory struct {
+ WorkersCnt uint8
+ Materials map[string]uint16
+ working bool
+ Queue chan *Order
+ mutex sync.Mutex
+}
+
+func NewFactory(workers uint8) *Factory {
+ var tmp Factory
+ tmp.WorkersCnt = workers
+ tmp.Materials = make(map[string]uint16, 0)
+ tmp.Queue = make(chan *Order, 1024)
+ tmp.working = false
+ return &tmp
+}
+
+func (f *Factory) Enqueue(order *Order) {
+ f.Queue <- order
+}
+
+func (f *Factory) work() {
+ for f.working {
+ if f.WorkersCnt != 0 {
+ go f.processOrder()
+ f.mutex.Lock()
+ f.WorkersCnt--
+ f.mutex.Unlock()
+ }
+ }
+}
+
+func (f *Factory) StartProducing() {
+ f.working = true
+ go f.work()
+}
+
+func (f *Factory) StopProducing() {
+ f.working = false
+}
+
+func (f *Factory) StorageAdd(materials map[string]uint16) {
+ for key, val := range materials {
+ if _, ok := f.Materials[key]; ok {
+ f.Materials[key] += val
+ } else {
+ f.Materials[key] = val
+ }
+ }
+}
+
+func (f *Factory) processOrder() {
+ order := <-f.Queue
+ order.Status = IN_PROGRESS
+ res, err := f.generateRegexp(order.Words)
+ if err != nil {
+ order.Result = ""
+ order.Status = UNABLE_TO_PRODUCE
+ } else {
+ order.Result = res
+ order.Status = DONE
+ }
+ f.mutex.Lock()
+ f.WorkersCnt++
+ f.mutex.Unlock()
+
+}
+
+func (f *Factory) genRegexp(needed []string, tmpMat map[string]uint16) []string {
+ res := make([]string, 0)
+ for idx, _ := range tmpMat {
+ regex, err := regexp.Compile("^" + idx)
+ if err != nil {
+ continue
+ }
+
+ nextNeeded := make([]string, 0)
+ for _, word := range needed {
+ if regex.MatchString(word) {
+ nextNeeded = append(nextNeeded, regex.ReplaceAllString(word, ""))
+ }
+ }
+
+ if len(nextNeeded) == len(needed) {
+ res = append(res, idx)
+ for _, newWord := range nextNeeded {
+ if newWord != "" {
+ newTmpMat := make(map[string]uint16)
+ newTmpMat = tmpMat
+ newTmpMat[idx] -= 1
+ newParts := f.genRegexp(nextNeeded, newTmpMat)
+ res = append(res, newParts...)
+ break
+ }
+ }
+ return res
+ }
+ }
+ return res
+}
+
+func (f *Factory) generateRegexp(words []string) (string, error) {
+
+ tmpMat := make(map[string]uint16)
+ tmpMat = f.Materials
+ regArr := f.genRegexp(words, tmpMat)
+ res := ""
+ if ok := f.GetMaterials(regArr); ok {
+ for _, val := range regArr {
+ res += val
+ }
+ } else {
+ return res, errors.New("Unable to produce!")
+ }
+ return "^" + res + "$", nil
+}
+
+func (f *Factory) GetMaterials(needed []string) bool {
+ f.mutex.Lock()
+ defer f.mutex.Unlock()
+ for idx, val := range needed {
+ if _, ok := f.Materials[val]; ok {
+ if f.Materials[val] == 0 {
+ delete(f.Materials, val)
+ } else {
+ f.Materials[val]--
+ }
+ } else {
+ for i := 0; i < idx; i++ {
+ add := map[string]uint16{needed[i]: 1}
+ f.StorageAdd(add)
+ }
+ return false
+ }
+ }
+ return true
+}