Решение на Фабрика за регулярни изрази от Любомир Коев

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

Към профила на Любомир Коев

Резултати

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

Код

package main
import "sync"
import "strconv"
import "regexp"
import "errors"
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
}
var nextId int = 0
func NewOrder(words []string, channel chan *Order) *Order {
nextId += 1
return &Order{
Id: strconv.Itoa(nextId),
Status: ENQUEUED,
Words: words,
Result: "",
Channel: channel,
}
}
type Factory struct {
sync.Mutex
materials map[string]uint16
orders chan *Order
stopChan chan struct{}
workers int
}
func NewFactory(workers uint8) *Factory {
return &Factory{
materials: make(map[string]uint16),
orders: make(chan *Order),
stopChan: make(chan struct{}, workers),
workers: int(workers),
}
}
func (f *Factory) Enqueue(order *Order) {
order.Status = ENQUEUED
go func() {
f.orders <- order
}()
}
func (f *Factory) StartProducing() {
for w := 0; w < f.workers; w += 1 {
go f.worker()
}
}
func (f *Factory) StopProducing() {
for w := 0; w < f.workers; w += 1 {
f.stopChan <- struct{}{}
}
}
func (f *Factory) StorageAdd(materials map[string]uint16) {
f.Lock()
defer f.Unlock()
for regex, count := range materials {
f.materials[regex] += count
}
}
func (f *Factory) worker() {
for {
select {
case <-f.stopChan:
return
case order := <-f.orders:
order.Status = IN_PROGRESS
if result, err := f.generateRegexp(order.Words); err == nil {
order.Result = result
order.Status = DONE
} else {
order.Status = UNABLE_TO_PRODUCE
}
go func() {
order.Channel <- order
}()
}
}
}
func getFirstMatch(words []string, parts map[string]uint16) (used []string) {
for part, count := range parts {
re, err := regexp.Compile("^" + part)
if err != nil {
continue
}
newWords := make([]string, 0)
for _, word := range words {
if re.FindStringIndex(word) == nil {
break
}
nword := re.ReplaceAllString(word, "")
newWords = append(newWords, nword)
}
if len(newWords) != len(words) {
continue
}
done := true
for _, word := range newWords {
done = done && word == ""
}
if done {
used := make([]string, 1)
used[0] = part
return used
}
leftParts := copyMap(parts)
if count == 1 {
delete(leftParts, part)
} else {
leftParts[part] = count - 1
}
used := getFirstMatch(newWords, leftParts)
if used != nil {
return append(used, part)
}
return nil
}
return nil
}
func reverseSlice(slice []string) {
for front, end := 0, len(slice)-1; front < end; front, end = front+1, end-1 {
slice[front], slice[end] = slice[end], slice[front]
}
}
func (f *Factory) generateRegexp(words []string) (result string, err error) {
f.Lock()
defer f.Unlock()
used := getFirstMatch(words, copyMap(f.materials))
reverseSlice(used)
if used != nil {
for _, word := range used {
result += word
if f.materials[word] == 1 {
delete(f.materials, word)
} else {
f.materials[word] -= 1
}
}
result = "^" + result + "$"
} else {
err = errors.New("Failed to match words")
}
return result, err
}
func copyMap(source map[string]uint16) map[string]uint16 {
dest := make(map[string]uint16)
for k, v := range source {
dest[k] = v
}
return dest
}
type Client struct {
Name string
Orders map[string]*Order
Channel chan *Order
}
func NewClient(name string) *Client {
return &Client{
Name: name,
Orders: make(map[string]*Order),
Channel: make(chan *Order),
}
}
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 {
if order, ok := c.Orders[id]; ok {
return order.Status
}
return DOES_NOT_EXIST
}

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

PASS
ok  	_/tmp/d20150111-18989-n64sw5	0.003s
PASS
ok  	_/tmp/d20150111-18989-n64sw5	0.003s
PASS
ok  	_/tmp/d20150111-18989-n64sw5	0.003s
PASS
ok  	_/tmp/d20150111-18989-n64sw5	0.003s
PASS
ok  	_/tmp/d20150111-18989-n64sw5	0.003s
PASS
ok  	_/tmp/d20150111-18989-n64sw5	0.003s
PASS
ok  	_/tmp/d20150111-18989-n64sw5	0.003s
PASS
ok  	_/tmp/d20150111-18989-n64sw5	0.002s
PASS
ok  	_/tmp/d20150111-18989-n64sw5	0.003s

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

Любомир обнови решението на 31.12.2014 20:50 (преди над 3 години)

+package main
+
+import "sync"
+import "strconv"
+import "regexp"
+import "errors"
+
+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
+}
+
+var nextId int = 0
+
+func NewOrder(words []string, channel chan *Order) *Order {
+ nextId += 1
+ return &Order{
+ Id: strconv.Itoa(nextId),
+ Status: ENQUEUED,
+ Words: words,
+ Result: "",
+ Channel: channel,
+ }
+}
+
+type Factory struct {
+ sync.Mutex
+ materials map[string]uint16
+ orders chan *Order
+ stopChan chan struct{}
+ workers int
+}
+
+func NewFactory(workers uint8) *Factory {
+ return &Factory{
+ materials: make(map[string]uint16),
+ orders: make(chan *Order),
+ stopChan: make(chan struct{}, workers),
+ workers: int(workers),
+ }
+}
+
+func (f *Factory) Enqueue(order *Order) {
+ order.Status = ENQUEUED
+ go func() {
+ f.orders <- order
+ }()
+}
+
+func (f *Factory) StartProducing() {
+ for w := 0; w < f.workers; w += 1 {
+ go f.worker()
+ }
+}
+
+func (f *Factory) StopProducing() {
+ for w := 0; w < f.workers; w += 1 {
+ f.stopChan <- struct{}{}
+ }
+}
+
+func (f *Factory) StorageAdd(materials map[string]uint16) {
+ f.Lock()
+ defer f.Unlock()
+ for regex, count := range materials {
+ f.materials[regex] += count
+ }
+}
+
+func (f *Factory) worker() {
+ for {
+ select {
+ case <-f.stopChan:
+ return
+ case order := <-f.orders:
+ order.Status = IN_PROGRESS
+ if result, err := f.generateRegexp(order.Words); err == nil {
+ order.Result = result
+ order.Status = DONE
+ } else {
+ order.Status = UNABLE_TO_PRODUCE
+ }
+ go func() {
+ order.Channel <- order
+ }()
+ }
+ }
+}
+
+func getFirstMatch(words []string, parts map[string]uint16) (used []string) {
+ for part, count := range parts {
+ re, err := regexp.Compile("^" + part)
+ if err != nil {
+ continue
+ }
+
+ newWords := make([]string, 0)
+ for _, word := range words {
+ if re.FindStringIndex(word) == nil {
+ break
+ }
+ nword := re.ReplaceAllString(word, "")
+
+ newWords = append(newWords, nword)
+ }
+
+ if len(newWords) != len(words) {
+ continue
+ }
+
+ done := true
+ for _, word := range newWords {
+ done = done && word == ""
+ }
+ if done {
+ used := make([]string, 1)
+ used[0] = part
+ return used
+ }
+
+ leftParts := copyMap(parts)
+
+ if count == 1 {
+ delete(leftParts, part)
+ } else {
+ leftParts[part] = count - 1
+ }
+
+ used := getFirstMatch(newWords, leftParts)
+ if used != nil {
+ return append(used, part)
+ }
+ return nil
+ }
+
+ return nil
+}
+
+func reverseSlice(slice []string) {
+ for front, end := 0, len(slice)-1; front < end; front, end = front+1, end-1 {
+ slice[front], slice[end] = slice[end], slice[front]
+ }
+}
+
+func (f *Factory) generateRegexp(words []string) (result string, err error) {
+ f.Lock()
+ defer f.Unlock()
+ used := getFirstMatch(words, copyMap(f.materials))
+ reverseSlice(used)
+ if used != nil {
+ for _, word := range used {
+ result += word
+ if f.materials[word] == 1 {
+ delete(f.materials, word)
+ } else {
+ f.materials[word] -= 1
+ }
+ }
+ result = "^" + result + "$"
+ } else {
+ err = errors.New("Failed to match words")
+ }
+ return result, err
+}
+
+func copyMap(source map[string]uint16) map[string]uint16 {
+ dest := make(map[string]uint16)
+ for k, v := range source {
+ dest[k] = v
+ }
+ return dest
+}
+
+type Client struct {
+ Name string
+ Orders map[string]*Order
+ Channel chan *Order
+}
+
+func NewClient(name string) *Client {
+ return &Client{
+ Name: name,
+ Orders: make(map[string]*Order),
+ Channel: make(chan *Order),
+ }
+}
+
+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 {
+ if order, ok := c.Orders[id]; ok {
+ return order.Status
+ }
+ return DOES_NOT_EXIST
+}