CMD:
go run main.go R1C4 R1C6 R2C3 R2C7 R3C9 R3C10
then enter the number of seats you want to reserve
Last active
March 3, 2021 12:57
-
-
Save squiidz/0aa472a0d4604a811e0067fd6e918af0 to your computer and use it in GitHub Desktop.
Seats assignment
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"errors" | |
"fmt" | |
"math" | |
"os" | |
"regexp" | |
"strconv" | |
) | |
var ( | |
// Qualities is only used to print seats with different color based on their quality | |
Qualities = map[int]string{ | |
-1: "\u001b[30m%s\033[92m", | |
0: "\u001b[32m%s\033[92m", | |
1: "\u001b[33m%s\033[92m", | |
2: "\u001b[33;1m%s\033[92m", | |
3: "\033[94m%s\033[92m", | |
4: "\033[91m%s\033[92m", | |
5: "\033[91m%s\033[92m", | |
6: "\033[91m%s\033[92m", | |
7: "\033[91m%s\033[92m", | |
} | |
) | |
// Scene contains the rows | |
type Scene struct { | |
Rows []*Row | |
} | |
// NewScene intiniate a new Scene pointer with all the rows already created | |
func NewScene(nbRows int, nbSeats int) (*Scene, error) { | |
if nbSeats%nbRows != 0 { | |
return nil, errors.New("Unbalance seats:rows") | |
} | |
nbCols := nbSeats / nbRows | |
scene := &Scene{} | |
for i := 0; i < nbRows; i++ { | |
row := &Row{} | |
for j := 0; j < nbCols; j++ { | |
qual := (nbCols / 2) - j | |
if qual < 0 { | |
qual = j - (nbCols / 2) | |
} | |
row.Seats = append(row.Seats, &Seat{ | |
Quality: qual + i, | |
Taken: false, | |
Tag: NewTag(i+1, j+1), | |
}) | |
} | |
scene.Rows = append(scene.Rows, row) | |
} | |
return scene, nil | |
} | |
// ReserveN will try to find N seats available by quality | |
func (s *Scene) ReserveN(nbSeats int) (string, error) { | |
if nbSeats >= 10 { | |
return "", errors.New("Not Available") | |
} | |
var bestSeats []*Seat | |
bs := math.MaxInt32 | |
for _, r := range s.Rows { | |
ss, err := r.Fit(nbSeats) | |
if err != nil || len(ss) <= 0 { | |
continue | |
} | |
if ns := Score(ss); ns < bs { | |
bestSeats = ss | |
bs = ns | |
} | |
} | |
for _, s := range bestSeats { | |
if err := s.Reserve(); err != nil { | |
return "", err | |
} | |
} | |
if len(bestSeats) <= 0 { | |
return "", fmt.Errorf("can't find %d available seats", nbSeats) | |
} | |
return rangeStr(bestSeats), nil | |
} | |
// Reserve is used to reserve specific seats | |
func (s *Scene) Reserve(strs ...string) error { | |
for _, str := range strs { | |
r, c, err := ParseTag(str) | |
if err != nil { | |
return err | |
} | |
if err := s.Rows[r-1].Seats[c-1].Reserve(); err != nil { | |
return err | |
} | |
} | |
return nil | |
} | |
// String is used to implement the String inteface and be able to pretty print scene struct | |
func (s *Scene) String() string { | |
var str string | |
for _, r := range s.Rows { | |
str = fmt.Sprintf("%s%v\n", str, r) | |
} | |
return str | |
} | |
// Row contains the seats by rows | |
type Row struct { | |
Seats []*Seat | |
} | |
// Fit try to find the best match for the number of seats needed | |
func (r *Row) Fit(n int) ([]*Seat, error) { | |
if n > len(r.Seats) { | |
return nil, errors.New("row don't have enough seats") | |
} | |
bms := math.MaxInt16 | |
bh, bt := 0, 0 | |
h, t := 0, 0 | |
for i := 0; i < len(r.Seats); i++ { | |
h, t = i, i | |
if r.Seats[i].Taken { | |
continue | |
} | |
for j := i; j < len(r.Seats); j++ { | |
if !r.Seats[j].Taken { | |
t++ | |
} else { | |
break | |
} | |
if t-h == n { | |
if score := Score(r.Seats[h:t]); score < bms { | |
bms = score | |
bh = h | |
bt = t | |
} | |
} | |
} | |
} | |
return r.Seats[bh:bt], nil | |
} | |
// String is used to implement the String inteface and be able to pretty print Row struct | |
func (r *Row) String() string { | |
var str string | |
for _, s := range r.Seats { | |
str = fmt.Sprintf("%s%s\t", str, s.String()) | |
} | |
return str | |
} | |
// Seat contains the Tag "ex : R4C2", the Quality and if it's already taken | |
type Seat struct { | |
Tag string | |
Quality int | |
Taken bool | |
} | |
// Reserve sets the values for the seat so that it's consider reserved | |
func (s *Seat) Reserve() error { | |
if !s.Taken { | |
s.Taken = true | |
s.Quality = -1 | |
return nil | |
} | |
return errors.New("seat already taken") | |
} | |
// String is used to implement the String inteface and be able to pretty print seat struct | |
func (s *Seat) String() string { | |
return fmt.Sprintf(Qualities[s.Quality], s.Tag) | |
} | |
// NewTag is use to generate a tag based on the row and col | |
func NewTag(row int, col int) string { | |
return fmt.Sprintf("R%dC%d", row, col) | |
} | |
// ParseTag returns the values for the row and column in the tag | |
func ParseTag(tag string) (row int, col int, err error) { | |
reg := regexp.MustCompile("[0-9]+") | |
v := reg.FindAllString(tag, -1) | |
r, err := strconv.Atoi(v[0]) | |
if err != nil { | |
return 0, 0, errors.New("invalid row number") | |
} | |
c, err := strconv.Atoi(v[1]) | |
if err != nil { | |
return 0, 0, errors.New("invalid col number") | |
} | |
return r, c, nil | |
} | |
// Score calculate the quality score for an array of seats | |
func Score(seats []*Seat) int { | |
score := 0 | |
for _, s := range seats { | |
score += s.Quality | |
} | |
return score | |
} | |
// rangeStr is used to print the seats range found | |
func rangeStr(ss []*Seat) string { | |
if len(ss) == 1 { | |
return fmt.Sprintf("%s", ss[0].Tag) | |
} | |
return fmt.Sprintf("%s - %s", ss[0].Tag, ss[len(ss)-1].Tag) | |
} | |
func main() { | |
scene, err := NewScene(3, 33) | |
if err != nil { | |
panic(err) | |
} | |
err = scene.Reserve(os.Args[1:]...) | |
if err != nil { | |
panic(err) | |
} | |
fmt.Println(scene) | |
scanner := bufio.NewScanner(os.Stdin) | |
for { | |
fmt.Print("Number of Seats >> ") | |
scanner.Scan() | |
in := scanner.Text() | |
if len(in) != 0 { | |
n, err := strconv.Atoi(in) | |
if err != nil { | |
fmt.Println("Invalid input") | |
continue | |
} | |
r, err := scene.ReserveN(n) | |
if err != nil { | |
fmt.Println(err) | |
continue | |
} | |
fmt.Printf("%s reserved\n", r) | |
fmt.Println(scene) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment