Skip to content

RealImage challenge 2016 #205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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
90 changes: 63 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,77 @@
# Real Image Challenge 2016

In the cinema business, a feature film is usually provided to a regional distributor based on a contract for exhibition in a particular geographical territory.
This project implements a hierarchical distribution rights management system in Go.

Each authorization is specified by a combination of included and excluded regions. For example, a distributor might be authorzied in the following manner:
```
Permissions for DISTRIBUTOR1
INCLUDE: INDIA
INCLUDE: UNITEDSTATES
EXCLUDE: KARNATAKA-INDIA
EXCLUDE: CHENNAI-TAMILNADU-INDIA
## Code Structure

### Distributor Structure
```go
type Distributor struct {
Name string
Includes map[string]bool
Excludes map[string]bool
Parent *Distributor
}
```
This allows `DISTRIBUTOR1` to distribute in any city inside the United States and India, *except* cities in the state of Karnataka (in India) and the city of Chennai (in Tamil Nadu, India).
The Distributor struct represents a distribution entity with:
- Name: Identifier for the distributor
- Includes: Locations where distribution is allowed
- Excludes: Locations where distribution is blocked
- Parent: Reference to parent distributor for hierarchical rights

At this point, asking your program if `DISTRIBUTOR1` has permission to distribute in `CHICAGO-ILLINOIS-UNITEDSTATES` should get `YES` as the answer, and asking if distribution can happen in `CHENNAI-TAMILNADU-INDIA` should of course be `NO`. Asking if distribution is possible in `BANGALORE-KARNATAKA-INDIA` should also be `NO`, because the whole state of Karnataka has been excluded.
### Key Functions

Sometimes, a distributor might split the work of distribution amount smaller sub-distiributors inside their authorized geographies. For instance, `DISTRIBUTOR1` might assign the following permissions to `DISTRIBUTOR2`:
1. **LoadLocations**
- Reads location data from a CSV file
- Creates a map of cities with their corresponding province and country
- Format: `map[CITY] = [PROVINCE, COUNTRY]`

```
Permissions for DISTRIBUTOR2 < DISTRIBUTOR1
INCLUDE: INDIA
EXCLUDE: TAMILNADU-INDIA
```
Now, `DISTRIBUTOR2` can distribute the movie anywhere in `INDIA`, except inside `TAMILNADU-INDIA` and `KARNATAKA-INDIA` - `DISTRIBUTOR2`'s permissions are always a subset of `DISTRIBUTOR1`'s permissions. It's impossible/invalid for `DISTRIBUTOR2` to have `INCLUDE: CHINA`, for example, because `DISTRIBUTOR1` isn't authorized to do that in the first place.
2. **IsallowedtoDistribute**
- Determines if distribution is allowed for a given location
- Checks hierarchy in following order:
1. Excluded locations (city, state-country, city-state-country)
2. Included locations (city, state-country, city-state-country)
3. Parent distributor permissions

If `DISTRIBUTOR2` authorizes `DISTRIBUTOR3` to handle just the city of Hubli, Karnataka, India, for example:
```
Permissions for DISTRIBUTOR3 < DISTRIBUTOR2 < DISTRIBUTOR1
INCLUDE: HUBLI-KARNATAKA-INDIA
```
Again, `DISTRIBUTOR2` cannot authorize `DISTRIBUTOR3` with a region that they themselves do not have access to.
### Distribution Rules
- Excludes take precedence over includes
- If location is not explicitly included/excluded, check parent distributor
- If no parent exists and no explicit inclusion, distribution is denied

## Example Usage

We've provided a CSV with the list of all countries, states and cities in the world that we know of - please use the data mentioned there for this program. *The codes you see there may be different from what you see here, so please always use the codes in the CSV*. This Readme is only an example.
```go
// Create root distributor
distributor1 := &Distributor{
Name: "DISTRIBUTOR1",
Includes: make(map[string]bool),
Excludes: make(map[string]bool),
}

Write a program in any language you want (If you're here from Gophercon, use Go :D) that does this. Feel free to make your own input and output format / command line tool / GUI / Webservice / whatever you want. Feel free to hold the dataset in whatever structure you want, but try not to use external databases - as far as possible stick to your langauage without bringing in MySQL/Postgres/MongoDB/Redis/Etc.
// Set permissions
distributor1.AddInclude("INDIA")
distributor1.AddExclude("KARNATAKA-INDIA")

To submit a solution, fork this repo and send a Pull Request on Github.
// Check distribution rights
isAllowed := distributor1.IsallowedtoDistribute(location, locations[location])
```

For any questions or clarifications, raise an issue on this repo and we'll answer your questions as fast as we can.
## CSV File Format
The program expects a CSV file with the following columns:
- Column 4: City
- Column 5: Province/State
- Column 6: Country

## Dependencies
- Standard Go libraries:
- encoding/csv
- strings
- fmt
- os

## Running the Program
```bash
go run main.go
```
The program will read from `cities.csv` and output distribution rights for each location.

3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/praveen-kumar-04/real_image_challenge

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

import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"github.com/praveen-kumar-04/real_image_challenge/services"
)

func checking_list_cities(current_distributor *services.Distributor,locations map[string][]string){
for location, _ := range locations {
if current_distributor.IsallowedtoDistribute(location,locations[location]) {
fmt.Printf("%s is allowed to distribute in %s-%s-%s :=> Yes\n",current_distributor.Name,location,locations[location][0],locations[location][1])

}else{
fmt.Printf("%s is allowed to distribute in %s-%s-%s :=> No\n",current_distributor.Name,location,locations[location][0],locations[location][1])
}
}

}

func distributors_list(list_of_distributors []*services.Distributor){
fmt.Println("List of Distributors")
for ind,distributor := range list_of_distributors {
fmt.Println(ind+1,"=>",distributor.Name)
}
}

func read_data_from_user() int{
reader := bufio.NewReader(os.Stdin)
fmt.Println("Enter the ID of the distributor")
distributor_id, _ := reader.ReadString('\n')
distributor_id = strings.TrimSuffix(distributor_id, "\n")
distributor_id = strings.TrimSuffix(distributor_id, "\r")
id, _ := strconv.Atoi(distributor_id)
return id

}


func main(){
locations, err := services.LoadLocations("cities.csv")

if err != nil {
fmt.Println("Error loading CSV:", err)
return
}

distributor1 := &services.Distributor{
Name: "DISTRIBUTOR1",
Includes: make(map[string]bool),
Excludes: make(map[string]bool),
}

distributor1.AddInclude("INDIA")
distributor1.AddInclude("UNITEDSTATES")
distributor1.AddExclude("KARNATAKA-INDIA")
distributor1.AddExclude("CHENNAI-TAMILNADU-INDIA")

distributor2 := &services.Distributor{
Name: "DISTRIBUTOR2",
Includes: make(map[string]bool),
Excludes: make(map[string]bool),
Parent: distributor1,
}

distributor2.AddInclude("INDIA")
distributor2.AddExclude("TAMILNADU-INDIA")


distributor3 := &services.Distributor{
Name: "DISTRIBUTOR3",
Includes: make(map[string]bool),
Excludes: make(map[string]bool),
Parent: distributor2,
}

distributor3.AddInclude("HUBLI-KARNATAKA-INDIA")


list_of_distributors := []*services.Distributor{distributor1,distributor2,distributor3}

for {
distributors_list(list_of_distributors)
checking_list_cities(list_of_distributors[read_data_from_user()-1],locations)
fmt.Println("Do you want to check for another distributor? (yes/no)")
reader := bufio.NewReader(os.Stdin)
choice, _ := reader.ReadString('\n')
choice = strings.TrimSuffix(choice, "\n")
choice = strings.TrimSuffix(choice, "\r")
if choice == "no" {
break
}
}
}
47 changes: 47 additions & 0 deletions services/distributor_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package services

import(
"strings"
)

type Distributor struct {
Name string
Includes map[string]bool
Excludes map[string]bool
Parent *Distributor
}

func (d *Distributor) AddInclude(location string) {
location = strings.ToUpper(location)
d.Includes[location] = true
}

func (d *Distributor) AddExclude(location string) {
location = strings.ToUpper(location)
d.Excludes[location] = true
}


func (d *Distributor) IsallowedtoDistribute(location string, locations []string) bool {

// checking the cities, state, country in the exluded list to identify if the location is allowed to distribute
full :=strings.Join([]string{locations[0], locations[1]}, "-")
if d.Excludes[locations[1]] || d.Excludes[strings.Join([]string{locations[0], locations[1]}, "-")] || d.Excludes[strings.Join([]string{full,location}, "-")] {
return false
}


// checking the cities, state, country in the included list
if d.Includes[locations[1]] || d.Includes[strings.Join([]string{locations[0], locations[1]}, "-")] || d.Includes[strings.Join([]string{full,location}, "-")] {
if d.Parent != nil {
return d.Parent.IsallowedtoDistribute(location, locations)
}
return true
}

if d.Parent != nil {
return d.Parent.IsallowedtoDistribute(location, locations)
}

return false
}
29 changes: 29 additions & 0 deletions services/loader_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package services
import (
"encoding/csv"
"os"
"strings"
)

// Loading the csv file and storing the city, state, country in the map
func LoadLocations(fileloc string) (map[string][]string, error) {
locations := make(map[string][]string)
file, err := os.Open(fileloc)
if err != nil {
return locations, err
}
defer file.Close()

reader := csv.NewReader(file)
lines, err := reader.ReadAll()
if err != nil {
return locations, err
}

for _, line := range lines[1:] {
city, province, country := line[3], line[4], line[5]
locations[strings.ToUpper(city)] = []string{strings.ToUpper(province),strings.ToUpper(country)}
}

return locations, nil
}