Решение на Фабрика за регулярни изрази от Мартин Добрев

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

Към профила на Мартин Добрев

Резултати

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

Код

package main
import (
"errors"
"regexp"
"strconv"
"sync"
)
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
//Създава нова поръчка с подадените думи и канал. Тази функция трябва да генерира уникално Id.
func NewOrder(words []string, channel chan *Order) *Order {
result := new(Order)
result.Id = strconv.Itoa(nextId)
nextId++
result.Status = ENQUEUED
result.Words = make([]string, 0)
result.Result = ""
result.Channel = channel
return result
}
type Factory struct {
materials map[string]uint16
OrderChan chan *Order
Orders []*Order
stop chan interface{}
pushEvent chan interface{}
mutex sync.Mutex
}
func runWorker(factory *Factory) {
for {
select {
case o, _ := <-factory.OrderChan:
o.Result, _ = factory.generateRegexp(o.Words)
o.Status = DONE
case _, _ = <-factory.stop:
break
}
}
}
//Създава фабрика с подадения брой работници и започва да изпълнява поръчки.
func NewFactory(workers uint8) *Factory {
result := new(Factory)
result.materials = make(map[string]uint16)
result.Orders = make([]*Order, 0)
result.pushEvent = make(chan interface{})
result.stop = make(chan interface{})
for i := uint8(0); i < workers; i++ {
go runWorker(result)
}
return result
}
//Добавя поръчката в списъка на чакащите да бъдат изпълнени.
func (f *Factory) Enqueue(order *Order) {
f.mutex.Lock()
defer f.mutex.Unlock()
f.Orders = append(f.Orders, order)
go func(pushEvent chan interface{}) {
_, _ = <-pushEvent
}(f.pushEvent)
}
//Започва да изпълнява поръчки.
func (f *Factory) StartProducing() {
for {
for _, val := range f.Orders {
val.Status = IN_PROGRESS
f.OrderChan <- val
}
f.pushEvent <- struct{}{}
}
}
//Прекратява производството като изпълнява само поръчките със статус IN_PROGRESS.
func (f *Factory) StopProducing() {
close(f.stop)
}
//Приема map с материал: количество и добавя съответните материали и техните количества в склада.
func (f *Factory) StorageAdd(materials map[string]uint16) {
f.mutex.Lock()
defer f.mutex.Unlock()
for key, val := range materials {
f.materials[key] += val
}
}
//приема стрингове и връша парче което мачва навалото на всички стрингове ако няма такова връща ""
func (f *Factory) recursiveGenerateRegexp(words []string, materials map[string]uint16) []string {
for idx, _ := range materials {
nextStepWords := make([]string, 0)
for _, word := range words {
r, err := regexp.Compile("^" + idx)
if err != nil {
continue
}
if r.MatchString(word) {
nextStepWords = append(nextStepWords, r.ReplaceAllString(word, ""))
}
}
if len(nextStepWords) != len(words) {
continue
}
nextStep := false
for _, newWord := range nextStepWords {
if newWord != "" {
nextStep = true
break
}
}
if nextStep {
nMaterials := make(map[string]uint16)
for k, v := range materials {
nMaterials[k] = v
}
nMaterials[idx] -= 1
tokens := f.recursiveGenerateRegexp(nextStepWords, nMaterials)
if len(tokens) != 0 {
result := make([]string, 0)
result = append(result, idx)
result = append(result, tokens...)
return result
}
} else {
result := make([]string, 0)
return append(result, idx)
}
}
return make([]string, 0)
}
//Генерира регулярен израз (или връща грешка при недостатъчно материали), който match-ва всички думи в слайса words. Върнатият регулярен израз трябва да започва с ^ и да завършва с $.
func (f *Factory) generateRegexp(words []string) (string, error) {
mat := make(map[string]uint16)
mat = f.materials
result := f.recursiveGenerateRegexp(words, mat)
pay := func(tokens []string, factory *Factory) bool {
factory.mutex.Lock()
defer factory.mutex.Unlock()
for idx, val := range tokens {
_, ok := factory.materials[val]
if !ok {
for ; idx > 0; idx-- {
factory.materials[tokens[idx]] += 1
}
return false
}
factory.materials[val] -= 1
}
return true
}
stringResult := ""
if pay(result, f) && len(result) != 0 {
for _, val := range result {
stringResult += val
}
} else {
return "", errors.New("Not enough materials")
}
return "^" + stringResult + "$", nil
}
type Client struct {
Name string
Orders map[string]*Order // Всички поръчки от този клиент
// където ключът е Order.Id
Channel chan *Order // Канал, по който клиентът
// получава поръчка в момента,
// в който тя бъде приключена
}
//Създава нов клиент с подаденото име.
func NewClient(name string) *Client {
result := new(Client)
result.Name = name
result.Orders = make(map[string]*Order)
return result
}
//Създава нова поръчка с думи, изпраща я на подадената фабрика и връща id-то на поръчката.
func (c *Client) Order(factory *Factory, words []string) string {
result := NewOrder(words, c.Channel)
factory.Enqueue(result)
c.Orders[result.Id] = result
return result.Id
}
//Проверява статуса на клиентска поръчка с подаденото id.
func (c *Client) CheckStatus(id string) int {
_, ok := c.Orders[id]
if ok {
return c.Orders[id].Status
}
return DOES_NOT_EXIST
}

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

PASS
ok  	_/tmp/d20150111-18989-1iqw905	0.003s
PASS
ok  	_/tmp/d20150111-18989-1iqw905	0.003s
PASS
ok  	_/tmp/d20150111-18989-1iqw905	0.003s
PASS
ok  	_/tmp/d20150111-18989-1iqw905	0.003s
PASS
ok  	_/tmp/d20150111-18989-1iqw905	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-1iqw905	0.003s
PASS
ok  	_/tmp/d20150111-18989-1iqw905	0.003s
PASS
ok  	_/tmp/d20150111-18989-1iqw905	0.003s
PASS
ok  	_/tmp/d20150111-18989-1iqw905	0.003s

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

Мартин обнови решението на 31.12.2014 15:46 (преди над 3 години)

+package main
+
+import (
+ "errors"
+ "regexp"
+ "strconv"
+ "sync"
+)
+
+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
+
+//Създава нова поръчка с подадените думи и канал. Тази функция трябва да генерира уникално Id.
+func NewOrder(words []string, channel chan *Order) *Order {
+ result := new(Order)
+ result.Id = strconv.Itoa(nextId)
+ nextId++
+ result.Status = ENQUEUED
+ result.Words = make([]string, 0)
+ result.Result = ""
+ result.Channel = channel
+ return result
+
+}
+
+type Factory struct {
+ materials map[string]uint16
+ OrderChan chan *Order
+ Orders []*Order
+ stop chan interface{}
+ pushEvent chan interface{}
+ mutex sync.Mutex
+}
+
+func runWorker(factory *Factory) {
+ for {
+ select {
+ case o, _ := <-factory.OrderChan:
+ o.Result, _ = factory.generateRegexp(o.Words)
+ o.Status = DONE
+ case _, _ = <-factory.stop:
+ break
+ }
+ }
+}
+
+//Създава фабрика с подадения брой работници и започва да изпълнява поръчки.
+func NewFactory(workers uint8) *Factory {
+ result := new(Factory)
+ result.materials = make(map[string]uint16)
+ result.Orders = make([]*Order, 0)
+ result.pushEvent = make(chan interface{})
+ result.stop = make(chan interface{})
+ for i := uint8(0); i < workers; i++ {
+ go runWorker(result)
+ }
+ return result
+}
+
+//Добавя поръчката в списъка на чакащите да бъдат изпълнени.
+func (f *Factory) Enqueue(order *Order) {
+ f.mutex.Lock()
+ defer f.mutex.Unlock()
+ f.Orders = append(f.Orders, order)
+ go func(pushEvent chan interface{}) {
+ _, _ = <-pushEvent
+ }(f.pushEvent)
+}
+
+//Започва да изпълнява поръчки.
+func (f *Factory) StartProducing() {
+ for {
+ for _, val := range f.Orders {
+ val.Status = IN_PROGRESS
+ f.OrderChan <- val
+ }
+ f.pushEvent <- struct{}{}
+ }
+
+}
+
+//Прекратява производството като изпълнява само поръчките със статус IN_PROGRESS.
+func (f *Factory) StopProducing() {
+ close(f.stop)
+}
+
+//Приема map с материал: количество и добавя съответните материали и техните количества в склада.
+func (f *Factory) StorageAdd(materials map[string]uint16) {
+ f.mutex.Lock()
+ defer f.mutex.Unlock()
+ for key, val := range materials {
+ f.materials[key] += val
+ }
+}
+
+//приема стрингове и връша парче което мачва навалото на всички стрингове ако няма такова връща ""
+func (f *Factory) recursiveGenerateRegexp(words []string, materials map[string]uint16) []string {
+ for idx, _ := range materials {
+ nextStepWords := make([]string, 0)
+ for _, word := range words {
+ r, err := regexp.Compile("^" + idx)
+ if err != nil {
+ continue
+ }
+ if r.MatchString(word) {
+ nextStepWords = append(nextStepWords, r.ReplaceAllString(word, ""))
+ }
+ }
+ if len(nextStepWords) != len(words) {
+ continue
+ }
+ nextStep := false
+ for _, newWord := range nextStepWords {
+ if newWord != "" {
+ nextStep = true
+ break
+ }
+ }
+ if nextStep {
+ nMaterials := make(map[string]uint16)
+ nMaterials = materials
+ nMaterials[idx] -= 1
+ tokens := f.recursiveGenerateRegexp(nextStepWords, nMaterials)
+ if len(tokens) != 0 {
+ result := make([]string, 0)
+ result = append(result, idx)
+ result = append(result, tokens...)
+ return result
+ }
+ } else {
+ result := make([]string, 0)
+ return append(result, idx)
+ }
+ }
+ return make([]string, 0)
+}
+
+//Генерира регулярен израз (или връща грешка при недостатъчно материали), който match-ва всички думи в слайса words. Върнатият регулярен израз трябва да започва с ^ и да завършва с $.
+func (f *Factory) generateRegexp(words []string) (string, error) {
+
+ mat := make(map[string]uint16)
+ mat = f.materials
+ result := f.recursiveGenerateRegexp(words, mat)
+ pay := func(tokens []string, factory *Factory) bool {
+ factory.mutex.Lock()
+ defer factory.mutex.Unlock()
+ for idx, val := range tokens {
+ _, ok := factory.materials[val]
+ if !ok {
+
+ for ; idx > 0; idx-- {
+ factory.materials[tokens[idx]] += 1
+ }
+ return false
+ }
+ factory.materials[val] -= 1
+ }
+
+ return true
+ }
+ stringResult := ""
+ if pay(result, f) && len(result) != 0 {
+ for _, val := range result {
+ stringResult += val
+ }
+ } else {
+ return "", errors.New("Not enough materials")
+ }
+ return "^" + stringResult + "$", nil
+}
+
+type Client struct {
+ Name string
+ Orders map[string]*Order // Всички поръчки от този клиент
+ // където ключът е Order.Id
+ Channel chan *Order // Канал, по който клиентът
+ // получава поръчка в момента,
+ // в който тя бъде приключена
+}
+
+//Създава нов клиент с подаденото име.
+func NewClient(name string) *Client {
+ result := new(Client)
+ result.Name = name
+ result.Orders = make(map[string]*Order)
+ return result
+
+}
+
+//Създава нова поръчка с думи, изпраща я на подадената фабрика и връща id-то на поръчката.
+func (c *Client) Order(factory *Factory, words []string) string {
+
+ result := NewOrder(words, c.Channel)
+ factory.Enqueue(result)
+ c.Orders[result.Id] = result
+ return result.Id
+}
+
+//Проверява статуса на клиентска поръчка с подаденото id.
+func (c *Client) CheckStatus(id string) int {
+ _, ok := c.Orders[id]
+ if ok {
+ return c.Orders[id].Status
+ }
+ return DOES_NOT_EXIST
+}

Мартин обнови решението на 31.12.2014 18:03 (преди над 3 години)

package main
import (
"errors"
"regexp"
"strconv"
"sync"
)
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
//Създава нова поръчка с подадените думи и канал. Тази функция трябва да генерира уникално Id.
func NewOrder(words []string, channel chan *Order) *Order {
result := new(Order)
result.Id = strconv.Itoa(nextId)
nextId++
result.Status = ENQUEUED
result.Words = make([]string, 0)
result.Result = ""
result.Channel = channel
return result
}
type Factory struct {
materials map[string]uint16
OrderChan chan *Order
Orders []*Order
stop chan interface{}
pushEvent chan interface{}
mutex sync.Mutex
}
func runWorker(factory *Factory) {
for {
select {
case o, _ := <-factory.OrderChan:
o.Result, _ = factory.generateRegexp(o.Words)
o.Status = DONE
case _, _ = <-factory.stop:
break
}
}
}
//Създава фабрика с подадения брой работници и започва да изпълнява поръчки.
func NewFactory(workers uint8) *Factory {
result := new(Factory)
result.materials = make(map[string]uint16)
result.Orders = make([]*Order, 0)
result.pushEvent = make(chan interface{})
result.stop = make(chan interface{})
for i := uint8(0); i < workers; i++ {
go runWorker(result)
}
return result
}
//Добавя поръчката в списъка на чакащите да бъдат изпълнени.
func (f *Factory) Enqueue(order *Order) {
f.mutex.Lock()
defer f.mutex.Unlock()
f.Orders = append(f.Orders, order)
go func(pushEvent chan interface{}) {
_, _ = <-pushEvent
}(f.pushEvent)
}
//Започва да изпълнява поръчки.
func (f *Factory) StartProducing() {
for {
for _, val := range f.Orders {
val.Status = IN_PROGRESS
f.OrderChan <- val
}
f.pushEvent <- struct{}{}
}
}
//Прекратява производството като изпълнява само поръчките със статус IN_PROGRESS.
func (f *Factory) StopProducing() {
close(f.stop)
}
//Приема map с материал: количество и добавя съответните материали и техните количества в склада.
func (f *Factory) StorageAdd(materials map[string]uint16) {
f.mutex.Lock()
defer f.mutex.Unlock()
for key, val := range materials {
f.materials[key] += val
}
}
//приема стрингове и връша парче което мачва навалото на всички стрингове ако няма такова връща ""
func (f *Factory) recursiveGenerateRegexp(words []string, materials map[string]uint16) []string {
for idx, _ := range materials {
nextStepWords := make([]string, 0)
for _, word := range words {
r, err := regexp.Compile("^" + idx)
if err != nil {
continue
}
if r.MatchString(word) {
nextStepWords = append(nextStepWords, r.ReplaceAllString(word, ""))
}
}
if len(nextStepWords) != len(words) {
continue
}
nextStep := false
for _, newWord := range nextStepWords {
if newWord != "" {
nextStep = true
break
}
}
if nextStep {
nMaterials := make(map[string]uint16)
- nMaterials = materials
+ for k, v := range materials {
+ nMaterials[k] = v
+ }
nMaterials[idx] -= 1
tokens := f.recursiveGenerateRegexp(nextStepWords, nMaterials)
if len(tokens) != 0 {
result := make([]string, 0)
result = append(result, idx)
result = append(result, tokens...)
return result
}
} else {
result := make([]string, 0)
return append(result, idx)
}
}
return make([]string, 0)
}
//Генерира регулярен израз (или връща грешка при недостатъчно материали), който match-ва всички думи в слайса words. Върнатият регулярен израз трябва да започва с ^ и да завършва с $.
func (f *Factory) generateRegexp(words []string) (string, error) {
mat := make(map[string]uint16)
mat = f.materials
result := f.recursiveGenerateRegexp(words, mat)
pay := func(tokens []string, factory *Factory) bool {
factory.mutex.Lock()
defer factory.mutex.Unlock()
for idx, val := range tokens {
_, ok := factory.materials[val]
if !ok {
for ; idx > 0; idx-- {
factory.materials[tokens[idx]] += 1
}
return false
}
factory.materials[val] -= 1
}
return true
}
stringResult := ""
if pay(result, f) && len(result) != 0 {
for _, val := range result {
stringResult += val
}
} else {
return "", errors.New("Not enough materials")
}
return "^" + stringResult + "$", nil
}
type Client struct {
Name string
Orders map[string]*Order // Всички поръчки от този клиент
// където ключът е Order.Id
Channel chan *Order // Канал, по който клиентът
// получава поръчка в момента,
// в който тя бъде приключена
}
//Създава нов клиент с подаденото име.
func NewClient(name string) *Client {
result := new(Client)
result.Name = name
result.Orders = make(map[string]*Order)
return result
}
//Създава нова поръчка с думи, изпраща я на подадената фабрика и връща id-то на поръчката.
func (c *Client) Order(factory *Factory, words []string) string {
result := NewOrder(words, c.Channel)
factory.Enqueue(result)
c.Orders[result.Id] = result
return result.Id
}
//Проверява статуса на клиентска поръчка с подаденото id.
func (c *Client) CheckStatus(id string) int {
_, ok := c.Orders[id]
if ok {
return c.Orders[id].Status
}
return DOES_NOT_EXIST
}