forked from ashishps1/awesome-low-level-design
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request ashishps1#35 from mukulagarwal08/parking-lot-golang
Golang Parking Lot
- Loading branch information
Showing
11 changed files
with
327 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"github.com/ashishps1/awesome-low-level-design/parking-lot/vehicles" | ||
) | ||
|
||
type Level struct { | ||
Floor int | ||
ParkingSpots map[vehicles.VehicleType]map[int]*ParkingSpot | ||
} | ||
|
||
// NewLevel returns a default level with 30 bike parking, 20 car parking, 10 truck parking | ||
func NewLevel(floor int) *Level { | ||
parkingSpots := make(map[vehicles.VehicleType]map[int]*ParkingSpot) | ||
|
||
carSpots := make(map[int]*ParkingSpot) | ||
|
||
for spotNo := 1; spotNo <= 20; spotNo++ { | ||
carSpots[spotNo] = NewParkingSpot(vehicles.CAR, spotNo) | ||
} | ||
|
||
truckSpots := make(map[int]*ParkingSpot) | ||
|
||
for spotNo := 1; spotNo <= 10; spotNo++ { | ||
truckSpots[spotNo] = NewParkingSpot(vehicles.TRUCK, spotNo) | ||
} | ||
|
||
bikeSpots := make(map[int]*ParkingSpot) | ||
|
||
for spotNo := 1; spotNo <= 30; spotNo++ { | ||
bikeSpots[spotNo] = NewParkingSpot(vehicles.BIKE, spotNo) | ||
} | ||
|
||
parkingSpots[vehicles.CAR] = carSpots | ||
parkingSpots[vehicles.TRUCK] = truckSpots | ||
parkingSpots[vehicles.BIKE] = bikeSpots | ||
|
||
return &Level{ | ||
Floor: floor, | ||
ParkingSpots: parkingSpots, | ||
} | ||
} | ||
|
||
func (l *Level) FindParkingSpot(v vehicles.Vehicle) *ParkingSpot { | ||
for _, spot := range l.ParkingSpots[v.Type()] { | ||
if spot.CurrentVehicle == nil { | ||
return spot | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (l *Level) DisplayAvailability() { | ||
for vtype, spotMap := range l.ParkingSpots { | ||
count := 0 | ||
for _, spot := range spotMap { | ||
if spot.CurrentVehicle == nil { | ||
count++ | ||
} | ||
} | ||
fmt.Printf("%s: %d\n", vtype.String(), count) | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"github.com/ashishps1/awesome-low-level-design/parking-lot/vehicles" | ||
"sync" | ||
"time" | ||
) | ||
|
||
func main() { | ||
var wg sync.WaitGroup | ||
|
||
parkingLots := make(map[int]*ParkingLot) | ||
|
||
// testing if singleton working in parking lot | ||
for i := 1; i <= 10; i++ { | ||
for j := 0; j < 5; j++ { | ||
wg.Add(1) | ||
go func(ind int) { | ||
parkingLots[ind] = GetInstance(ind) | ||
wg.Done() | ||
}(i) | ||
} | ||
} | ||
|
||
wg.Wait() | ||
// test if park is thread safe | ||
parkingLot := parkingLots[1] | ||
parkingLot.AddLevel(0) | ||
parkingLot.AddLevel(1) | ||
|
||
parkingLot.DisplayAvailability() | ||
|
||
// try to park 10 cars using different routines | ||
for i := 1; i <= 10; i++ { | ||
wg.Add(1) | ||
go func(ind int) { | ||
car := vehicles.NewCar(fmt.Sprintf("car-%d", ind)) | ||
parkingLot.ParkVehicle(car) | ||
wg.Done() | ||
}(i) | ||
} | ||
wg.Wait() | ||
parkingLot.DisplayAvailability() | ||
|
||
//unpark any one vehicle | ||
ticket, _ := parkingLot.ParkVehicle(vehicles.NewTruck("truck-1")) | ||
|
||
time.Sleep(10 * time.Second) | ||
parkingLot.UnParkVehicle(ticket) | ||
fmt.Printf("ticket = %+v\n", ticket) | ||
|
||
fmt.Printf("bill for %s = %d", ticket.Vehicle.RegisNo(), ticket.TotalBill) | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"github.com/ashishps1/awesome-low-level-design/parking-lot/vehicles" | ||
"sync" | ||
) | ||
|
||
var ( | ||
singletonMap map[int]*ParkingLot | ||
once sync.Once | ||
instanceLock sync.Mutex | ||
parkLock sync.Mutex | ||
) | ||
|
||
type ParkingLot struct { | ||
Name string | ||
Address string // this could be another struct but keeping it simple for now | ||
Levels []*Level | ||
} | ||
|
||
func GetInstance(id int) *ParkingLot { | ||
once.Do(func() { | ||
singletonMap = make(map[int]*ParkingLot) | ||
}) | ||
if _, isPresent := singletonMap[id]; !isPresent { | ||
instanceLock.Lock() | ||
if _, isPresent = singletonMap[id]; !isPresent { | ||
fmt.Printf("Creating new parking lot for id: %d\n", id) | ||
pLot := ParkingLot{} | ||
singletonMap[id] = &pLot | ||
} | ||
instanceLock.Unlock() | ||
} | ||
return singletonMap[id] | ||
} | ||
|
||
func (p *ParkingLot) ParkVehicle(vehicle vehicles.Vehicle) (*Ticket, error) { | ||
// Find the best spot available | ||
parkLock.Lock() | ||
defer parkLock.Unlock() | ||
|
||
fmt.Printf("Parking vehicle no: %s\n", vehicle.RegisNo()) | ||
var spot *ParkingSpot | ||
for _, level := range p.Levels { | ||
if spot = level.FindParkingSpot(vehicle); spot != nil { | ||
break | ||
} else { | ||
return nil, errors.New("parking full") | ||
} | ||
} | ||
// Mark spot as occupied | ||
spot.CurrentVehicle = vehicle | ||
// Generate ticket and return | ||
ticket := NewTicket(spot, vehicle) | ||
|
||
return ticket, nil | ||
} | ||
|
||
func (p *ParkingLot) DisplayAvailability() { | ||
fmt.Println("Following no of spots available:") | ||
for floor, level := range p.Levels { | ||
fmt.Printf("level %d:\n", floor) | ||
level.DisplayAvailability() | ||
fmt.Println() | ||
} | ||
fmt.Println() | ||
} | ||
|
||
func (p *ParkingLot) UnParkVehicle(ticket *Ticket) { | ||
// empty the spot | ||
ticket.ParkingSpot.CurrentVehicle = nil | ||
// calculate the amount | ||
ticket.CalculateAmount() | ||
} | ||
|
||
func (p *ParkingLot) AddLevel(floor int) { | ||
p.Levels = append(p.Levels, NewLevel(floor)) | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package main | ||
|
||
import "github.com/ashishps1/awesome-low-level-design/parking-lot/vehicles" | ||
|
||
type ParkingSpot struct { | ||
SpotNo int | ||
VehicleType vehicles.VehicleType | ||
CurrentVehicle vehicles.Vehicle | ||
} | ||
|
||
func NewParkingSpot(vType vehicles.VehicleType, spotNo int) *ParkingSpot { | ||
return &ParkingSpot{SpotNo: spotNo, VehicleType: vType} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/ashishps1/awesome-low-level-design/parking-lot/vehicles" | ||
"time" | ||
) | ||
|
||
type Ticket struct { | ||
EntryTime time.Time | ||
ExitTime time.Time | ||
ParkingSpot *ParkingSpot | ||
Vehicle vehicles.Vehicle | ||
TotalBill int | ||
} | ||
|
||
func NewTicket(spot *ParkingSpot, vehicle vehicles.Vehicle) *Ticket { | ||
return &Ticket{ | ||
EntryTime: time.Now(), | ||
ExitTime: time.Time{}, | ||
ParkingSpot: spot, | ||
Vehicle: vehicle, | ||
TotalBill: 0, | ||
} | ||
} | ||
|
||
func (t *Ticket) CalculateAmount() { | ||
t.ExitTime = time.Now() | ||
timeSpent := int(t.ExitTime.Sub(t.EntryTime).Seconds()) | ||
t.TotalBill = timeSpent * t.Vehicle.Cost() | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package vehicles | ||
|
||
type Bike struct { | ||
vehicleBase | ||
} | ||
|
||
func NewBike(regNo string) *Bike { | ||
return &Bike{vehicleBase{ | ||
RegistrationNo: regNo, | ||
VehicleType: BIKE, | ||
}} | ||
} | ||
|
||
func (c *Bike) Cost() int { | ||
return 10 | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package vehicles | ||
|
||
type Car struct { | ||
vehicleBase | ||
} | ||
|
||
func NewCar(regNo string) *Car { | ||
return &Car{vehicleBase{ | ||
RegistrationNo: regNo, | ||
VehicleType: CAR, | ||
}} | ||
} | ||
|
||
func (c *Car) Cost() int { | ||
return 20 | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package vehicles | ||
|
||
type Truck struct { | ||
vehicleBase | ||
} | ||
|
||
func NewTruck(regNo string) *Truck { | ||
return &Truck{vehicleBase{ | ||
RegistrationNo: regNo, | ||
VehicleType: TRUCK, | ||
}} | ||
} | ||
|
||
func (c *Truck) Cost() int { | ||
return 30 | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package vehicles | ||
|
||
type vehicleBase struct { | ||
RegistrationNo string | ||
VehicleType VehicleType | ||
} | ||
|
||
type Vehicle interface { | ||
RegisNo() string | ||
Type() VehicleType | ||
Cost() int | ||
} | ||
|
||
func (v *vehicleBase) RegisNo() string { | ||
return v.RegistrationNo | ||
} | ||
|
||
func (v *vehicleBase) Type() VehicleType { | ||
return v.VehicleType | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package vehicles | ||
|
||
type VehicleType int | ||
|
||
const ( | ||
CAR VehicleType = iota + 1 | ||
TRUCK | ||
BIKE | ||
) | ||
|
||
func (v VehicleType) String() string { | ||
return [...]string{"Car", "Truck", "Bike"}[v-1] | ||
} | ||
|
||
func (v VehicleType) EnumIndex() int { | ||
return int(v) | ||
} |