Skip to content

Instantly share code, notes, and snippets.

@moshaad7
Created February 7, 2025 05:23
Show Gist options
  • Save moshaad7/3520eab6579c980883f82b3e4df2a1d4 to your computer and use it in GitHub Desktop.
Save moshaad7/3520eab6579c980883f82b3e4df2a1d4 to your computer and use it in GitHub Desktop.
LLD_ELEVATOR
Directory Structure:
└── ./
└── elevator_system
├── building.go
├── elevator_panel.go
├── elevator.go
├── elevatorManager.go
├── floor.go
├── hall_panel.go
└── main.go
---
File: /elevator_system/building.go
---
package main
type Building struct {
Floors []*Floor
Elevators []*Elevator
}
func NewBuilding() *Building {
building := &Building{Floors: make([]*Floor, 0)}
for i := 1; i <= 15; i++ {
floor := NewFloor(i)
building.Floors = append(building.Floors, floor)
}
for i := 1; i <= 3; i++ {
elevator := NewElevator(i)
building.Elevators = append(building.Elevators, elevator)
}
return building
}
---
File: /elevator_system/elevator_panel.go
---
package main
type ElevatorPanel struct {
PanelID int
FloorButtons [15]bool
}
func NewElevatorPanel(panelID int) *ElevatorPanel {
return &ElevatorPanel{PanelID: panelID, FloorButtons: [15]bool{}}
}
func (ep *ElevatorPanel) AddDestinationFloor(floor int) {
ep.FloorButtons[floor] = true
}
func (ep *ElevatorPanel) RemoveDestinationFloor(floor int) {
ep.FloorButtons[floor] = false
}
---
File: /elevator_system/elevator.go
---
package main
import (
"fmt"
"sync"
)
type Elevator struct {
ID int
Capacity int
CurrentFloor int
CurrentDirection Directions
CurrentLoad int
ElevatorPanel *ElevatorPanel
Destinations []int
sync.Mutex
}
func NewElevator(id int) *Elevator {
return &Elevator{ID: id, Capacity: 10, CurrentFloor: 1, CurrentDirection: Still, CurrentLoad: 0, ElevatorPanel: NewElevatorPanel(id)}
}
func (e *Elevator) AddDestination(destinationFloor int) {
e.Lock()
e.ElevatorPanel.AddDestinationFloor(destinationFloor)
e.Destinations = append(e.Destinations, destinationFloor)
fmt.Printf("Elevator %d received destination floor %d\n", e.ID, destinationFloor)
e.Unlock()
}
func (e *Elevator) RemoveDestination(destinationFloor int) {
e.Lock()
for i, floor := range e.Destinations {
if floor == destinationFloor {
e.Destinations = append(e.Destinations[:i], e.Destinations[i+1:]...)
e.ElevatorPanel.RemoveDestinationFloor(destinationFloor)
break
}
}
e.Unlock()
}
func (e *Elevator) UpdateCurrentFloor(newFloor int) {
e.Lock()
e.CurrentFloor = newFloor
e.Unlock()
}
func (e *Elevator) UpdateCurrentLoad(newLoad int) {
e.Lock()
e.CurrentLoad = newLoad
e.Unlock()
}
func (e *Elevator) UpdateCurrentDirection(newDirection Directions) {
e.Lock()
e.CurrentDirection = newDirection
e.Unlock()
}
func (e *Elevator) FarthestDestination() int {
maxFloor := 0
for _, floor := range e.Destinations {
if floor > maxFloor {
maxFloor = floor
}
}
return maxFloor
}
func (e *Elevator) NearestDestination() int {
minFloor := 100
for _, floor := range e.Destinations {
if floor < minFloor {
minFloor = floor
}
}
return minFloor
}
---
File: /elevator_system/elevatorManager.go
---
package main
import (
"fmt"
"sort"
)
type ElevatorManager struct {
Building *Building
}
func NewElevatorManager(building *Building) *ElevatorManager {
return &ElevatorManager{Building: building}
}
func (em *ElevatorManager) OperateAllElevators() {
for _, elevator := range em.Building.Elevators {
go em.OperateElevator(elevator)
}
}
func (em *ElevatorManager) OperateElevator(elevator *Elevator) {
for {
elevator.Lock()
if len(elevator.Destinations) == 0 {
elevator.CurrentDirection = Still
elevator.Unlock()
continue
}
sort.Ints(elevator.Destinations)
fmt.Printf("Elevator %d is starting from %d and going to %s\n", elevator.ID, elevator.CurrentFloor, elevator.CurrentDirection)
if elevator.CurrentDirection == Up {
em.MoveElevatorUp(elevator)
} else if elevator.CurrentDirection == Down {
em.MoveElevatorDown(elevator)
} else {
em.DecideDirection(elevator)
}
elevator.Unlock()
}
}
func (em *ElevatorManager) DecideDirection(elevator *Elevator) {
currentFloor := elevator.CurrentFloor
if len(elevator.Destinations) == 0 {
return
}
nearestDestination := elevator.Destinations[0]
if nearestDestination > currentFloor {
elevator.UpdateCurrentDirection(Up)
em.MoveElevatorUp(elevator)
} else {
elevator.UpdateCurrentDirection(Down)
em.MoveElevatorDown(elevator)
}
}
func (em *ElevatorManager) MoveElevatorUp(elevator *Elevator) {
for i := 0; i < len(elevator.Destinations); i++ {
destination := elevator.Destinations[i]
if destination >= elevator.CurrentFloor {
fmt.Printf("Elevator %d moving up to floor %d\n", elevator.ID, destination)
elevator.UpdateCurrentFloor(destination)
elevator.RemoveDestination(destination)
i--
}
}
if len(elevator.Destinations) == 0 {
elevator.UpdateCurrentDirection(Still)
} else {
elevator.UpdateCurrentDirection(Down)
}
}
func (em *ElevatorManager) MoveElevatorDown(elevator *Elevator) {
for i := len(elevator.Destinations) - 1; i >= 0; i-- {
destination := elevator.Destinations[i]
if destination <= elevator.CurrentFloor {
fmt.Printf("Elevator %d moving down to floor %d\n", elevator.ID, destination)
elevator.UpdateCurrentFloor(destination)
elevator.RemoveDestination(destination)
}
}
if len(elevator.Destinations) == 0 {
elevator.UpdateCurrentDirection(Still)
} else {
elevator.UpdateCurrentDirection(Up)
}
}
func (em *ElevatorManager) AssignElevator(floor int, direction Directions) (bestElevator *Elevator) {
bestElevator = em.FindClosestElevator(floor, direction)
if bestElevator != nil {
bestElevator.AddDestination(floor)
fmt.Printf("Elevator %d assigned to floor %d with direction %s\n", bestElevator.ID, floor, direction)
}
return bestElevator
}
func (em *ElevatorManager) FindClosestElevator(floor int, direction Directions) *Elevator {
var closestElevator *Elevator
minDistance := int(1e9)
for _, elevator := range em.Building.Elevators {
elevator.Lock()
distance := em.calculateDistance(elevator, floor, direction)
if distance < minDistance {
minDistance = distance
closestElevator = elevator
}
elevator.Unlock()
}
return closestElevator
}
func (em *ElevatorManager) calculateDistance(elevator *Elevator, floor int, direction Directions) int {
currentFloor := elevator.CurrentFloor
currentDirection := elevator.CurrentDirection
if currentDirection == Still || (currentDirection == direction && ((direction == Up && floor > currentFloor) || (direction == Down && floor < currentFloor))) {
return abs(floor - currentFloor)
}
if (currentDirection == Up && direction == Down) || (currentDirection == Down && direction == Up) {
if currentDirection == Up {
return abs(elevator.FarthestDestination()-currentFloor) + abs(elevator.FarthestDestination()-floor)
} else {
return abs(elevator.NearestDestination()-currentFloor) + abs(elevator.NearestDestination()-floor)
}
}
return 100
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
---
File: /elevator_system/floor.go
---
package main
type Floor struct {
Number int
HallPanels []*HallPanel
}
func NewFloor(number int) *Floor {
floor := &Floor{Number: number, HallPanels: make([]*HallPanel, 0)}
for i := 1; i <= 3; i++ {
hallPanel := NewHallPanel(i, number)
floor.HallPanels = append(floor.HallPanels, hallPanel)
}
return floor
}
---
File: /elevator_system/hall_panel.go
---
package main
import "fmt"
type Directions string
const (
Up Directions = "Up"
Down Directions = "Down"
Still Directions = "Still"
)
type HallPanel struct {
PanelID int
DirectionInstruction Directions
SourceFloor int
}
func NewHallPanel(panelID int, sourceFloor int) *HallPanel {
return &HallPanel{PanelID: panelID, SourceFloor: sourceFloor, DirectionInstruction: Still}
}
func (h *HallPanel) SetDirectionInstructions(directionInstruction Directions) {
h.DirectionInstruction = directionInstruction
}
func (h *HallPanel) RequestElevator(manager *ElevatorManager, direction Directions) (elevator *Elevator) {
fmt.Printf("Panel %d requesting elevator with direction %s from floor %d\n", h.PanelID, direction, h.SourceFloor)
return manager.AssignElevator(h.SourceFloor, direction)
}
---
File: /elevator_system/main.go
---
package main
import "sync"
func main() {
building := NewBuilding()
manager := NewElevatorManager(building)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
elevator := building.Floors[1].HallPanels[1].RequestElevator(manager, Up)
elevator.AddDestination(6)
}()
wg.Add(1)
go func() {
defer wg.Done()
elevator := building.Floors[8].HallPanels[2].RequestElevator(manager, Down)
elevator.AddDestination(7)
}()
wg.Add(1)
go func() {
defer wg.Done()
thirdElevator := building.Floors[3].HallPanels[0].RequestElevator(manager, Up)
thirdElevator.AddDestination(12)
}()
wg.Wait()
go manager.OperateAllElevators()
select {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment