Skip to content

Feat/qube cinema #195

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 4 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
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Current Go File",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${file}",
"env": {},
"args": [],
"showLog": true
}
]
}
81 changes: 52 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,64 @@
# 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.
# Go Based Distribution Program

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
```
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).


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.
## Overview

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`:

```
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.
This command-line tool, written in Go, allows you to manage distributors and their permissions based on geographic regions. With this program, you can:

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.


- **Create Distributors:** Define distributors with specific authorized regions.

- **Add Regions:** Add new regions to a distributor’s authorized list.

- **Exclude Regions:** Exclude certain regions from a distributor’s effective permissions.

- **Establish Parent-Child Relationships:** Set up hierarchical relationships so that a child's permissions are always a subset of its parent's.

- **Check Permissions:** Verify if a distributor is permitted to operate in a given region.



## Getting Started

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.

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.
### Prerequisites

To submit a solution, fork this repo and send a Pull Request on Github.

For any questions or clarifications, raise an issue on this repo and we'll answer your questions as fast as we can.
- **Go:** Ensure you have Go installed (version 1.16 or later).

- **CSV File:** The program requires a `cities.csv` file (located in the `internal/assets` folder) with region data. The CSV should include columns like:

- City Code

- Province Code

- Country Code

- City Name

- Province Name

- Country Name

### How to Run?

1. **Build the Program:**

```bash
cd cmd
go build main
```

1. **Run the Program:**


```bash
./main
```
225 changes: 225 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
package main

import (
"CHALLENGE2016/internal/models/distributor"
"CHALLENGE2016/internal/models/region"
"bufio"
"encoding/csv"
"fmt"
"os"
"strings"
)

// initializeRegions reads the CSV file and adds regions to the RegionManager
func initializeRegions(rm *region.RegionManager, csvFile string) error {
file, err := os.Open(csvFile)
if err != nil {
return fmt.Errorf("failed to open CSV file: %w", err)
}
defer file.Close()

reader := csv.NewReader(file)
lines, err := reader.ReadAll()
if err != nil {
return fmt.Errorf("failed to read CSV file: %w", err)
}

for i, line := range lines {
if i == 0 {
continue
}
if len(line) < 6 {
continue
}
cityName := line[3]
provinceName := line[4]
countryName := line[5]

regionPath := fmt.Sprintf("%s-%s-%s", countryName, provinceName, cityName)
rm.AddRegion(regionPath)
}
return nil
}

func main() {
// Initialize RegionManager and load regions from CSV
rm := region.NewRegionManager()
err := initializeRegions(rm, "../internal/assets/cities.csv")
if err != nil {
fmt.Println("Error initializing regions:", err)
return
}

distributors := make(map[string]*distributor.Distributor)

scanner := bufio.NewScanner(os.Stdin)

for {
fmt.Println("\n----- Menu -----")
fmt.Println("1. Create Distributor")
fmt.Println("2. Add Region to Distributor")
fmt.Println("3. Exclude Region from Distributor")
fmt.Println("4. Add Parent to Distributor")
fmt.Println("5. Check Distributor Permission")
fmt.Println("6. List Distributors")
fmt.Println("7. Exit")
fmt.Print("Enter option: ")

if !scanner.Scan() {
break
}
option := strings.TrimSpace(scanner.Text())

switch option {
case "1":
// Create a new distributor
fmt.Print("Enter distributor ID (unique string): ")
scanner.Scan()
id := strings.TrimSpace(scanner.Text())

fmt.Print("Enter distributor Name: ")
scanner.Scan()
name := strings.TrimSpace(scanner.Text())

// Input authorized regions as comma-separated region paths
fmt.Print("Enter authorized region paths (comma separated, e.g. 'India-Tamil Nadu-Keelakarai, India-Jammu and Kashmir-Punch'): ")
scanner.Scan()
regionsInput := scanner.Text()
regionPaths := strings.Split(regionsInput, ",")

authRegions := make(map[string]*region.Region)
for _, rp := range regionPaths {
rp = strings.TrimSpace(rp)
if rp == "" {
continue
}
if r, exists := rm.GetRegion(rp); exists {
authRegions[rp] = r
} else {
fmt.Printf("Region '%s' not found. Skipping.\n", rp)
}
}

dist := distributor.AddDistributor(id, name, authRegions)
distributors[id] = dist
fmt.Println("Distributor created.")

case "2":
// Add a region to a distributor.
fmt.Print("Enter distributor ID: ")
scanner.Scan()
id := strings.TrimSpace(scanner.Text())
dist, ok := distributors[id]
if !ok {
fmt.Println("Distributor not found.")
break
}

fmt.Print("Enter region path to add (e.g. 'India-Tamil Nadu-Keelakarai'): ")
scanner.Scan()
rp := strings.TrimSpace(scanner.Text())
if r, exists := rm.GetRegion(rp); exists {
if err := dist.AddRegion(r); err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Region added to distributor.")
}
} else {
fmt.Println("Region not found.")
}

case "3":
// Exclude a region from a distributor
fmt.Print("Enter distributor ID: ")
scanner.Scan()
id := strings.TrimSpace(scanner.Text())
dist, ok := distributors[id]
if !ok {
fmt.Println("Distributor not found.")
break
}

fmt.Print("Enter region path to exclude: ")
scanner.Scan()
rp := strings.TrimSpace(scanner.Text())
if r, exists := rm.GetRegion(rp); exists {
dist.ExcludeRegion(r)
fmt.Println("Region excluded from distributor.")
} else {
fmt.Println("Region not found.")
}

case "4":
// Add a parent distributor
fmt.Print("Enter child distributor ID: ")
scanner.Scan()
childID := strings.TrimSpace(scanner.Text())
childDist, ok := distributors[childID]
if !ok {
fmt.Println("Child distributor not found.")
break
}

fmt.Print("Enter parent distributor ID: ")
scanner.Scan()
parentID := strings.TrimSpace(scanner.Text())
parentDist, ok := distributors[parentID]
if !ok {
fmt.Println("Parent distributor not found.")
break
}

childDist.AddParent(parentDist)
fmt.Println("Parent added to distributor.")

case "5":

// Check if a distributor has permission for a given region.
fmt.Print("Enter distributor ID: ")
scanner.Scan()
id := strings.TrimSpace(scanner.Text())
dist, ok := distributors[id]
if !ok {
fmt.Println("Distributor not found.")
break
}

fmt.Print("Enter region path to check (e.g. 'India-Tamil Nadu-Keelakarai'): ")
scanner.Scan()
rp := strings.TrimSpace(scanner.Text())
if r, exists := rm.GetRegion(rp); exists {
if dist.HasPermission(r) {
fmt.Println("Permission granted!")
} else {
fmt.Println("Permission denied!")
}
} else {
fmt.Println("Region not found.")
}

case "6":
// List all distributors.
fmt.Println("Listing Distributors:")
for id, dist := range distributors {
fmt.Println("--------------------------------")
fmt.Printf("ID: %s, Name: %s\n", id, dist.Name)
fmt.Print("\n Excluded Regions: ")
for regID := range dist.ExcludedRegions {
fmt.Printf("%s ", regID)
}
fmt.Print("\n Effective Authorized Regions: ")
for regID := range dist.EffectiveAuthorizedRegions {
fmt.Printf("%s ", regID)
}
fmt.Println("\n--------------------------------")
}

case "7":
fmt.Println("Exiting.")
return

default:
fmt.Println("Invalid option. Please try again.")
}
}
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module CHALLENGE2016

go 1.24.0
File renamed without changes.
Loading