Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# solution
Solved using golang::

Data models in /models,

Solution functions in /solve,

Utility functions in /utils

you can insert new filenames in main.go


# Qube Cinemas Challenge 2019
Qube delivers the movie content to theatres all around the world. There are multiple delivery partners to help us deliver the content.

Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module challenge2019

go 1.19
30 changes: 30 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

import (
"challenge2019/models"
"challenge2019/solve"
"log"
)

var filenames = models.FileDetails{
Partners: "partners.csv",
Capacities: "capacities.csv",
Input: "input.csv",
Solution1: "output1.csv",
Solution2: "output2.csv",
}

func main() {
//..To "catch" panic and exit gracefully
defer func() {
if err := recover(); err != nil {
log.Fatal("panic occurred:", err)
}
}()
log.Println("Solving....")

if err := solve.Solution(&filenames); err != nil {
log.Fatal(err)
}

}
3 changes: 3 additions & 0 deletions models/capacityDetails.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package models

type CapacityMap map[string]int
10 changes: 10 additions & 0 deletions models/filedetails.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package models

// Filedetails stores names of i/o csv files
type FileDetails struct {
Partners string
Capacities string
Input string
Solution1 string
Solution2 string
}
7 changes: 7 additions & 0 deletions models/inputDetails.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package models

type InputDetails struct {
DeliveryID string
Size int
TheatreID string
}
14 changes: 14 additions & 0 deletions models/outputDetails.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package models

type OutputDetails struct {
DeliveryID string
Feasibility bool
PartnerID string
Cost int
}

type TotalDataPerPartner struct {
Data int
//indivisible data unit map, maps dataunit to output 1
DataUnitsMap map[int]int
}
16 changes: 16 additions & 0 deletions models/partnerDetails.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package models

type PartnerDetails struct {
TheatreID string
SizeSlab Slab
MinimumCost int
CostPerGB int
PartnerID string
}

type Slab struct {
Min int
Max int
}
type PartnerMap map[string][]PartnerDetails
type TheatreMap map[string]PartnerMap
34 changes: 34 additions & 0 deletions solve/solution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package solve

import (
"challenge2019/models"
"challenge2019/utils"
"fmt"
)

func Solution(f *models.FileDetails) error {
//Getting input partners and capacities from csv files
input, err := utils.GetInput(f.Input)
if err != nil {
return fmt.Errorf("solve/Solution(): error reading input: \n %w", err)
}
partners, err := utils.GetPartners(f.Partners)
if err != nil {
return fmt.Errorf("solve/Solution(): error reading partners: \n %w", err)
}
capacityMap, err := utils.GetCapacities(f.Capacities)
if err != nil {
return fmt.Errorf("solve/Solution(): error reading capacities: \n %w", err)
}

output1Map, totalDataPerPartner := solution1(input, partners)
if err := utils.GenerateOut(f.Solution1, output1Map); err != nil {
return fmt.Errorf("solve/Solution(): error generating output files:%s \n %w", f.Solution1, err)
}

output2Map := solution2(input, capacityMap, totalDataPerPartner, output1Map, partners)
if err := utils.GenerateOut(f.Solution2, output2Map); err != nil {
return fmt.Errorf("solve/Solution(): error generating output files:%s \n %w", f.Solution2, err)
}
return nil
}
58 changes: 58 additions & 0 deletions solve/solution1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package solve

import "challenge2019/models"

func solution1(input []models.InputDetails, partners models.TheatreMap) ([]models.OutputDetails, map[string]models.TotalDataPerPartner) {
//Solving Problem Statements
output1Map := make([]models.OutputDetails, len(input))
totalDataPerPartner := make(map[string]models.TotalDataPerPartner)
for i, in := range input {
output1 := models.OutputDetails{
DeliveryID: in.DeliveryID,
Feasibility: false,
PartnerID: "",
Cost: 0,
}
for _, theatreData := range partners[in.TheatreID] {
for _, FesibilityData := range theatreData {
//solving Problem Statement 1
if in.Size >= FesibilityData.SizeSlab.Min && in.Size <= FesibilityData.SizeSlab.Max {
cost := FesibilityData.CostPerGB * in.Size
if cost < FesibilityData.MinimumCost {
cost = FesibilityData.MinimumCost
}
if output1.Cost != 0 {
if output1.Cost > cost {
output1.Cost = cost
output1.PartnerID = FesibilityData.PartnerID
}
} else {
output1.Cost = cost
output1.PartnerID = FesibilityData.PartnerID
output1.Feasibility = true
}
}

}
}
output1Map[i] = output1
if output1.PartnerID == "" {
continue
}
totaldata, ok := totalDataPerPartner[output1.PartnerID]
if ok {
totaldata.Data += in.Size
totaldata.DataUnitsMap[in.Size] = i
totalDataPerPartner[output1.PartnerID] = totaldata
} else {
newData := models.TotalDataPerPartner{}
newData.Data = in.Size
dataMap := make(map[int]int)
dataMap[in.Size] = i
newData.DataUnitsMap = dataMap
totalDataPerPartner[output1.PartnerID] = newData
}

}
return output1Map, totalDataPerPartner
}
144 changes: 144 additions & 0 deletions solve/solution2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package solve

import (
"challenge2019/models"
"sort"
)

func solution2(input []models.InputDetails, capacityMap models.CapacityMap, totalDataPerPartner map[string]models.TotalDataPerPartner, output1Map []models.OutputDetails, partners models.TheatreMap) []models.OutputDetails {
for partner, dm := range totalDataPerPartner {
if capacityMap[partner] < dm.Data {
//geting first i.e smallest suitable element from dataunit map
//sorting the keys
keys := make([]int, 0, len(dm.DataUnitsMap))
for k := range dm.DataUnitsMap {
keys = append(keys, k)
}
sort.Ints(keys)
for k, v := range dm.DataUnitsMap {
newKey, ok := checkIfAddPartner(partners, input[v], output1Map[v], capacityMap, totalDataPerPartner)

if ok {
delete(dm.DataUnitsMap, k)
dm.Data -= k
totalDataPerPartner[partner] = dm
update, updateok := totalDataPerPartner[newKey]
if updateok {
update.Data += k
update.DataUnitsMap[k] = v
totalDataPerPartner[newKey] = update
} else {
newupdate := models.TotalDataPerPartner{}
newupdate.Data = k
newDataUnitmap := make(map[int]int)
newDataUnitmap[k] = v
newupdate.DataUnitsMap = newDataUnitmap
totalDataPerPartner[newKey] = newupdate
}
if capacityMap[partner] < dm.Data {
continue
} else {
break
}
} else {
output1Map[v].Feasibility = false
output1Map[v].Cost = 0
output1Map[v].PartnerID = ""
}
}

}
}
//mutating output
outputMap := updateTrueOutput(input, output1Map, totalDataPerPartner, partners)
return outputMap
}

func checkIfAddPartner(partners models.TheatreMap, in models.InputDetails, output models.OutputDetails, capacityMap models.CapacityMap, totalDataPerPartner map[string]models.TotalDataPerPartner) (string, bool) {
Tid := in.TheatreID
Pid := output.PartnerID
replacement := ""
status := false
cost := 0
for i, patnerDetailsPerTheatre := range partners[Tid] {
if i != Pid {
for _, Tdata := range patnerDetailsPerTheatre {
if Tdata.SizeSlab.Max >= in.Size && Tdata.SizeSlab.Min <= in.Size {

if cost != 0 {

Tempcost := Tdata.CostPerGB * in.Size
if Tempcost < Tdata.MinimumCost {
Tempcost = Tdata.MinimumCost
}

if Tempcost < cost {
cost = Tdata.CostPerGB * in.Size
if cost < Tdata.MinimumCost {
cost = Tdata.MinimumCost
if capacityMap[i] >= (totalDataPerPartner[i].Data + in.Size) {
replacement = i
status = true
}

}
}

} else {

cost = Tdata.CostPerGB * in.Size
if cost < Tdata.MinimumCost {
cost = Tdata.MinimumCost
}

if capacityMap[i] >= (totalDataPerPartner[i].Data + in.Size) {
replacement = i
status = true
}
}

}
}
}

}
return replacement, status
}

func updateTrueOutput(input []models.InputDetails,
output1Map []models.OutputDetails,
totalDataPerPartner map[string]models.TotalDataPerPartner,
partners models.TheatreMap) []models.OutputDetails {
for i, out := range output1Map {
if out.Feasibility {
for pid, v := range totalDataPerPartner {

var cost int
//finding the cost for updated value
for _, value := range partners[input[i].TheatreID][pid] {
for key, value2 := range v.DataUnitsMap {
if value2 == i {
if key >= value.SizeSlab.Min && key <= value.SizeSlab.Max {
cost = key * value.CostPerGB
if cost < value.MinimumCost {
cost = value.MinimumCost
}
out.PartnerID = pid
out.Cost = cost
out.Feasibility = true
output1Map[i] = out
//can be replaced with multiple flag and break
goto label
}
}

}

}

}
label:
}
}
return output1Map
}
31 changes: 31 additions & 0 deletions utils/generateOut.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package utils

import (
"challenge2019/models"
"fmt"
"os"
"strconv"
)

func GenerateOut(f string, outArray []models.OutputDetails) error {
file, err := os.Create(f)
if err != nil {
return err
}

defer file.Close()
for _, out := range outArray {
line := out.DeliveryID
if out.Feasibility {
line = fmt.Sprintf("%s,%s,%s,%s\n", line, "true ", out.PartnerID, strconv.Itoa(out.Cost))
} else {
line = fmt.Sprintf("%s,%s,%s,%s\n", line, "false", "\"\"", "\"\"")
}
_, err = file.WriteString(line)

if err != nil {
return err
}
}
return nil
}
Loading