diff --git a/Main.go b/Main.go index 2978253..af9fbe2 100644 --- a/Main.go +++ b/Main.go @@ -38,7 +38,6 @@ type Message struct { } //go:generate go-bindata static/... locales templates -//go:generate rsrc -ico static/icon.ico -o FILE.syso //go:generate go-astilectron-bindata -c // map of all supported languages diff --git a/build/build.sh b/build/build.sh index cd17735..893eff8 100755 --- a/build/build.sh +++ b/build/build.sh @@ -1,5 +1,7 @@ #!/bin/bash +RELEASENAME=GreatMall + buildTarget() { export GOOS=$1 export GOARCH=$2 @@ -16,21 +18,29 @@ buildTarget() { if [ "$GOOS" == "windows" ] then - cp ../GroupMatcherDE.lnk tmp/ - cp ../GroupMatcherEN.lnk tmp/ + rsrc -ico ../static/icon.ico -o ../FILE.syso + cp ../GroupMatcherDE.exe tmp/ + cp ../GroupMatcherEN.exe tmp/ fi cd tmp if [ "$GOOS" == "windows" ] then go build -ldflags -H=windowsgui github.com/veecue/GroupMatcher - zip -r ../out/GroupMatcher-GreatMall-$GOOS-$GOARCH.zip * + echo packing zip file... + zip -r ../out/GroupMatcher-$RELEASENAME-$GOOS-$GOARCH.zip * else go build github.com/veecue/GroupMatcher echo packing tar file... - tar -czf ../out/GroupMatcher-GreatMall-$GOOS-$GOARCH.tar.gz * + tar -czf ../out/GroupMatcher-$RELEASENAME-$GOOS-$GOARCH.tar.gz * fi cd .. + + if [ "$GOOS" == "windows" ] + then + rm ../FILE.syso + fi + rm -rf tmp } rm -rf out @@ -38,7 +48,8 @@ mkdir out COPY_FILES="locales static" -OS="linux darwin windows" +#OS="linux darwin windows" +OS="windows" ARCH="386 amd64" for o in $OS diff --git a/matching/Combination.go b/matching/Combination.go index 8ac2812..830bc76 100644 --- a/matching/Combination.go +++ b/matching/Combination.go @@ -1,65 +1,63 @@ package matching -import( - -) +import () type Combination struct { - Quantity int - Configuration []Part + Quantity int + Configuration []Part } type Part struct { - Group *Group - CandidateAmount int + Group *Group + CandidateAmount int } //adds a configuration to all combinations it fitts to func addToAnyIfFitting(config []*Group, c []Combination) bool { - var wasAdded bool - for i := range c { - if c[i].addIfFitting(config) { - wasAdded = true - } - } - return wasAdded + var wasAdded bool + for i := range c { + if c[i].addIfFitting(config) { + wasAdded = true + } + } + return wasAdded } //adds config to the combination c if it fitts func (c *Combination) addIfFitting(config []*Group) bool { - if c.isFitting(config) { - //if config is a subconfiguration of c.Configuration (has less wishes, but the rest is equal) it is added, - //but the function returns false, so that config is also added as a own combination - c.Quantity++ - if len(config) == len(c.Configuration){ - return true - }else { - return false - } - } - return false + if c.isFitting(config) { + //if config is a subconfiguration of c.Configuration (has less wishes, but the rest is equal) it is added, + //but the function returns false, so that config is also added as a own combination + c.Quantity++ + if len(config) == len(c.Configuration) { + return true + } else { + return false + } + } + return false } //check if config is equal to c.Configuration (the order doesn't matter) func (c *Combination) isFitting(config []*Group) bool { - var count int - for i := range c.Configuration { - for j := range config { - if c.Configuration[i].Group.Name == config[j].Name { - count++ - } - } - } - if count == len(config) { - for i := range c.Configuration { - for j := range config { - if c.Configuration[i].Group.Name == config[j].Name { - c.Configuration[i].CandidateAmount++ - } - } - } - return true - }else { - return false - } + var count int + for i := range c.Configuration { + for j := range config { + if c.Configuration[i].Group.Name == config[j].Name { + count++ + } + } + } + if count == len(config) { + for i := range c.Configuration { + for j := range config { + if c.Configuration[i].Group.Name == config[j].Name { + c.Configuration[i].CandidateAmount++ + } + } + } + return true + } else { + return false + } } diff --git a/matching/Group.go b/matching/Group.go index d817667..4b5f8c2 100644 --- a/matching/Group.go +++ b/matching/Group.go @@ -41,7 +41,7 @@ func (g *Group) deletePerson(p *Person) { //adds a fitting person to the given group func (g *Group) insertBestFrom(candidates []*Person, m *Matcher) { //searching with decreasing preference priority - for i := 0;i < 3;i++ { + for i := 0; i < 3; i++ { //j := range candidates isn't possible because of changing slice length for j := len(candidates) - 1; j >= 0; j-- { if candidates[j].Preferences[i] == g { @@ -54,7 +54,6 @@ func (g *Group) insertBestFrom(candidates []*Person, m *Matcher) { return } - func FindGroup(name string, groups []*Group) *Group { for i := 0; i < len(groups); i++ { if groups[i].Name == name { diff --git a/matching/Matcher.go b/matching/Matcher.go index c7d5de4..3af0c96 100644 --- a/matching/Matcher.go +++ b/matching/Matcher.go @@ -2,11 +2,11 @@ package matching import ( + "errors" + "fmt" "log" "sync" - "errors" "time" - "fmt" ) type Matcher struct { @@ -96,7 +96,7 @@ func (m *Matcher) matchMany(n int, hardTimeout time.Duration, softTimeout time.D start := time.Now() found := false - defer func(){ + defer func() { dur := time.Since(start) if dur > hardTimeout { err = errors.New("hardtimeout") @@ -132,8 +132,8 @@ func (m *Matcher) matchMany(n int, hardTimeout time.Duration, softTimeout time.D }(i) } wg.Wait() - matchers = make([]*Matcher,0) - for _,m := range ms { + matchers = make([]*Matcher, 0) + for _, m := range ms { if m != nil { matchers = append(matchers, m) } @@ -168,11 +168,11 @@ func (m *Matcher) correct() bool { for j := range m.Groups { if len(m.Groups[j].Members) < m.Groups[j].MinSize { amountNeeded := m.Groups[j].MinSize - len(m.Groups[j].Members) - for k := 0;k < amountNeeded;k++ { + for k := 0; k < amountNeeded; k++ { freeC, neededC := m.getCandidates(m.Groups[j]) if len(freeC) != 0 { m.Groups[j].insertBestFrom(freeC, m) - }else{ + } else { m.Groups[j].insertBestFrom(neededC, m) flag = false } @@ -182,13 +182,13 @@ func (m *Matcher) correct() bool { } if flag { return true - }else{ + } else { return false } } //returns all candidates for a special group -func (m *Matcher) getCandidates(preference *Group) (freeC, neededC []*Person){ +func (m *Matcher) getCandidates(preference *Group) (freeC, neededC []*Person) { var pref, group, member int for pref = 0; pref < m.getMaxPref(); pref++ { for group = range m.Groups { @@ -198,7 +198,7 @@ func (m *Matcher) getCandidates(preference *Group) (freeC, neededC []*Person){ if m.Groups[group].Members[member].Preferences[pref] == preference { if m.Groups[group].MinSize >= len(m.Groups[group].Members) { neededC = append(neededC, m.Groups[group].Members[member]) - }else{ + } else { freeC = append(freeC, m.Groups[group].Members[member]) } } @@ -250,11 +250,11 @@ func (m *Matcher) CheckMatcher() (error, string) { } //check for basic combination problems - //the algorithm doesn't detect an error if there are two combinations which necessaryly need space in one group + //the algorithm doesn't detect an error if there are two combinations which necessaryly need space in one group needComma = false var combinations []Combination //get all combinations and subcombinations - m.sortByPrefLen()//sort persons by preference length, so that subconfigurations are also put into the main-configuration + m.sortByPrefLen() //sort persons by preference length, so that subconfigurations are also put into the main-configuration for i := range m.Persons { if !addToAnyIfFitting(m.Persons[i].Preferences, combinations) { var configuration []Part @@ -273,7 +273,7 @@ func (m *Matcher) CheckMatcher() (error, string) { //the capacity a group adds to the totalCapacity is limited by the larger one of Capacity or CandidateAmount if combinations[i].Configuration[j].Group.Capacity < combinations[i].Configuration[j].CandidateAmount { totalCapacity = totalCapacity + combinations[i].Configuration[j].Group.Capacity - }else{ + } else { totalCapacity = totalCapacity + combinations[i].Configuration[j].CandidateAmount } } @@ -297,7 +297,6 @@ func (m *Matcher) CheckMatcher() (error, string) { return errors.New("combination_overfilled"), errString } - //ceck for total person amount var totalMin, totalCap int for i := range m.Groups { @@ -334,7 +333,7 @@ func enoughCandidates(group *Group, persons []*Person) bool { //return number of assigned persons func (m *Matcher) numberAssigned() (n int) { for i := range m.Groups { - n+=len(m.Groups[i].Members) + n += len(m.Groups[i].Members) } return } @@ -352,10 +351,10 @@ func (m *Matcher) CalcQuote() (quote, percentage float64) { } } if nMaxQuote == 0 { - return 0,0 + return 0, 0 } - quote = 1 + float64(nQuote) / float64(nAssigned) - percentage = 100 * (1 - float64(nQuote) / float64(nMaxQuote)) + quote = 1 + float64(nQuote)/float64(nAssigned) + percentage = 100 * (1 - float64(nQuote)/float64(nMaxQuote)) return } @@ -372,8 +371,8 @@ func (m *Matcher) getHostGroup(p *Person) *Group { } //get maximum length of a persons Preferences -func (m *Matcher)getMaxPref() (max int) { - for _,person := range m.Persons { +func (m *Matcher) getMaxPref() (max int) { + for _, person := range m.Persons { if max < len(person.Preferences) { max = len(person.Preferences) } @@ -382,12 +381,12 @@ func (m *Matcher)getMaxPref() (max int) { } //orders the persons from many to few wishes -func (m *Matcher) sortByPrefLen(){ +func (m *Matcher) sortByPrefLen() { var persons []*Person currLen := m.getMaxPref() for currLen >= 0 { - for i := range m.Persons{ - if currLen == len(m.Persons[i].Preferences){ + for i := range m.Persons { + if currLen == len(m.Persons[i].Preferences) { persons = append(persons, m.Persons[i]) } } @@ -397,7 +396,7 @@ func (m *Matcher) sortByPrefLen(){ } //print groups (testing purpose) -func (m *Matcher) printMatcher(){ +func (m *Matcher) printMatcher() { q, p := m.CalcQuote() fmt.Println() @@ -405,12 +404,12 @@ func (m *Matcher) printMatcher(){ fmt.Println("Quote:\t", q, "( ~ ", p, " %)") fmt.Println() - for i := 0;i < len(m.Groups);i++{ + for i := 0; i < len(m.Groups); i++ { fmt.Println() fmt.Println("--------------------------------------------------------------------------------------") - fmt.Println("Gruppenname: ",m.Groups[i].Name, "\t( ", len(m.Groups[i].Members) ," )") + fmt.Println("Gruppenname: ", m.Groups[i].Name, "\t( ", len(m.Groups[i].Members), " )") for j := 0; j < len(m.Groups[i].Members); j++ { - fmt.Println(j,"\t:\t\t", m.Groups[i].Members[j].Name, "\t (", m.Groups[i].Members[j].Preferences[0].Name, ")\t(", m.Groups[i].Members[j].Preferences[1].Name, ")\t(", m.Groups[i].Members[j].Preferences[0].Name, ")") + fmt.Println(j, "\t:\t\t", m.Groups[i].Members[j].Name, "\t (", m.Groups[i].Members[j].Preferences[0].Name, ")\t(", m.Groups[i].Members[j].Preferences[1].Name, ")\t(", m.Groups[i].Members[j].Preferences[0].Name, ")") } } } diff --git a/matching/Person.go b/matching/Person.go index cebe73c..374f991 100644 --- a/matching/Person.go +++ b/matching/Person.go @@ -2,8 +2,8 @@ package matching import ( "math/rand" - "strings" "sort" + "strings" ) type Person struct { @@ -50,12 +50,12 @@ func (s slicePerson) Len() int { return len(s) } -func (s slicePerson) Less(i,j int) bool { +func (s slicePerson) Less(i, j int) bool { return strings.Compare(s[i].Name, s[j].Name) < 0 } -func (s slicePerson) Swap(i,j int) { - s[i],s[j] = s[j],s[i] +func (s slicePerson) Swap(i, j int) { + s[i], s[j] = s[j], s[i] } func Sort(s []*Person) { diff --git a/parseInput/Input.go b/parseInput/Input.go index a0e7be3..96d72ee 100644 --- a/parseInput/Input.go +++ b/parseInput/Input.go @@ -2,18 +2,17 @@ package parseInput import ( - "github.com/veecue/GroupMatcher/matching" "bufio" "bytes" "errors" "fmt" + "github.com/tealeg/xlsx" + "github.com/veecue/GroupMatcher/matching" "io" "strconv" "strings" - "github.com/tealeg/xlsx" ) - //Converts the current groups and persons (of package matcher) into a .xlsx document and saves into the project folder func FormatGroupsAndPersonsToExcel(groups []*matching.Group, persons []*matching.Person, l map[string]string, printTotal bool) (*xlsx.File, error) { //create file @@ -33,57 +32,57 @@ func FormatGroupsAndPersonsToExcel(groups []*matching.Group, persons []*matching //create group header sheet.AddRow() - addCell(sheet, len(sheet.Rows) - 1, l["group name"]) - addCell(sheet, len(sheet.Rows) - 1, l["min_size"]) - addCell(sheet, len(sheet.Rows) - 1, l["max_size"]) - addCell(sheet, len(sheet.Rows) - 1, l["group_size"]) + addCell(sheet, len(sheet.Rows)-1, l["group name"]) + addCell(sheet, len(sheet.Rows)-1, l["min_size"]) + addCell(sheet, len(sheet.Rows)-1, l["max_size"]) + addCell(sheet, len(sheet.Rows)-1, l["group_size"]) //insert groups for i := range groups { sheet.AddRow() - addCell(sheet, len(sheet.Rows) - 1, groups[i].Name) - addCell(sheet, len(sheet.Rows) - 1, strconv.Itoa(groups[i].MinSize)) - addCell(sheet, len(sheet.Rows) - 1, strconv.Itoa(groups[i].Capacity)) - addCell(sheet, len(sheet.Rows) - 1, strconv.Itoa(len(groups[i].Members))) + addCell(sheet, len(sheet.Rows)-1, groups[i].Name) + addCell(sheet, len(sheet.Rows)-1, strconv.Itoa(groups[i].MinSize)) + addCell(sheet, len(sheet.Rows)-1, strconv.Itoa(groups[i].Capacity)) + addCell(sheet, len(sheet.Rows)-1, strconv.Itoa(len(groups[i].Members))) } //create persons header sheet.AddRow() sheet.AddRow() - addCell(sheet, len(sheet.Rows) - 1, l["person name"]) - addCell(sheet, len(sheet.Rows) - 1, l["1stchoice"]) - addCell(sheet, len(sheet.Rows) - 1, l["2ndchoice"]) - addCell(sheet, len(sheet.Rows) - 1, l["3rdchoice"]) + addCell(sheet, len(sheet.Rows)-1, l["person name"]) + addCell(sheet, len(sheet.Rows)-1, l["1stchoice"]) + addCell(sheet, len(sheet.Rows)-1, l["2ndchoice"]) + addCell(sheet, len(sheet.Rows)-1, l["3rdchoice"]) //insert persons - for i := range persons{ + for i := range persons { sheet.AddRow() - addCell(sheet, len(sheet.Rows) - 1, persons[i].Name) + addCell(sheet, len(sheet.Rows)-1, persons[i].Name) assigned := persons[i].GetGroup(groups) for j := range persons[i].Preferences { - addCell(sheet, len(sheet.Rows) - 1, persons[i].Preferences[j].Name) + addCell(sheet, len(sheet.Rows)-1, persons[i].Preferences[j].Name) //set different style for active preference if assigned != nil { if assigned.Name == persons[i].Preferences[j].Name { - sheet.Rows[len(sheet.Rows) - 1].Cells[len(sheet.Rows[len(sheet.Rows) - 1].Cells) - 1].SetStyle(activeStyle) + sheet.Rows[len(sheet.Rows)-1].Cells[len(sheet.Rows[len(sheet.Rows)-1].Cells)-1].SetStyle(activeStyle) } } } } - }else { + } else { //create persons header sheet.AddRow() - addCell(sheet, len(sheet.Rows) - 1, l["person name"]) - addCell(sheet, len(sheet.Rows) - 1, l["group_assigned"]) + addCell(sheet, len(sheet.Rows)-1, l["person name"]) + addCell(sheet, len(sheet.Rows)-1, l["group_assigned"]) //insert persons - for i := range persons{ + for i := range persons { sheet.AddRow() - addCell(sheet, len(sheet.Rows) - 1, persons[i].Name) + addCell(sheet, len(sheet.Rows)-1, persons[i].Name) assigned := persons[i].GetGroup(groups) if assigned != nil { - addCell(sheet, len(sheet.Rows) - 1, assigned.Name) + addCell(sheet, len(sheet.Rows)-1, assigned.Name) } } } @@ -171,7 +170,6 @@ func ParseGroupsAndPersons(data io.Reader) ([]*matching.Group, []*matching.Perso text := scanner.Text() text = strings.TrimSpace(text) - if len(text) != 0 { //if line contains person initializer set reading mode to 1, foundPersons to true and continue with next line if text == "P" { @@ -202,12 +200,12 @@ func ParseGroupsAndPersons(data io.Reader) ([]*matching.Group, []*matching.Perso if !foundGroups { //in case groups were not declared before person initializer was found return nil, nil, errors.New("group_initializer_not_found") - }else { + } else { //otherwise add line number to error message errString = err.Error() + strconv.Itoa(count) } return nil, nil, errors.New(errString) - }else{ + } else { //if no error occured add person to persons slice persons = append(persons, person) } @@ -224,7 +222,7 @@ func ParseGroupsAndPersons(data io.Reader) ([]*matching.Group, []*matching.Perso errString = "person_initializer_not_found" } return nil, nil, errors.New(errString) - }else { + } else { //check for double use of a group name if matching.FindGroup(group.Name, groups) != nil { errString := "group_name_not_unique" + strconv.Itoa(count) @@ -340,9 +338,8 @@ func parseGroup(str string, minSize, capacity int) (*matching.Group, error) { return matching.NewGroup(name, cap, min), nil } - //adds a Cell to the given row of a .xlsx sheet func addCell(sheet *xlsx.Sheet, row int, value string) { sheet.Rows[row].AddCell() - sheet.Rows[row].Cells[len(sheet.Rows[row].Cells) - 1].SetValue(value) + sheet.Rows[row].Cells[len(sheet.Rows[row].Cells)-1].SetValue(value) }