From 198830a4241644541008b2323442f3cb7cca0be1 Mon Sep 17 00:00:00 2001 From: moxitech Date: Thu, 3 Oct 2024 01:06:09 +0700 Subject: [PATCH 1/2] Drone simulation logic: steps, models, structs TODO: data_rate, coverage, loss --- src/server/cmd/main.go | 76 +++++++- src/server/package/math/{ => loss}/loss.go | 0 .../math/simulator/simulation_model.go | 1 + .../package/math/simulator/simulator.go | 177 ++++++++++++++++++ 4 files changed, 245 insertions(+), 9 deletions(-) rename src/server/package/math/{ => loss}/loss.go (100%) create mode 100644 src/server/package/math/simulator/simulation_model.go create mode 100644 src/server/package/math/simulator/simulator.go diff --git a/src/server/cmd/main.go b/src/server/cmd/main.go index 1fc2f06..eab1f4f 100644 --- a/src/server/cmd/main.go +++ b/src/server/cmd/main.go @@ -1,23 +1,81 @@ package main import ( - "moxitech/dns/internal/database" - "moxitech/dns/internal/server" + // "moxitech/dns/internal/database" + // "moxitech/dns/internal/server" + "moxitech/dns/package/math/simulator" "os" ) +// var wg sync.WaitGroup = sync.WaitGroup{} + func main() { - D_EXPORT_VARS() - err := database.NewDBConnection() - if err != nil { - panic(err) + // Пример карты высот, замените на настоящие данные + heightData := [][]float64{ + {0, 10, 15, 20}, + {5, 15, 25, 30}, + {10, 20, 35, 40}, + {15, 25, 40, 50}, } - err = server.SpawnServer() - if err != nil { - panic(err) + + // Определяем карту высот + mapObj := &simulator.Map{ + Name: "Example Map", + MinBound: [3]float64{-1000, -1000, 0}, + MaxBound: [3]float64{1000, 1000, 500}, + HeightData: heightData, } + // Определяем дронов + drones := []*simulator.Drone{ + { + ID: 1, + Name: "Drone 1", + Coords: [3]float64{100, 100, 50}, + Params: simulator.DroneParams{ + AntennaRadius: 500, + AntennaDirection: [3]float64{1, 0, 0}, + Waypoints: [][3]float64{{200, 200, 50}}, + Speed: 10, + MeshName: "MeshA", + }, + }, + } + // Определяем базовые станции + baseStations := []*simulator.BaseStation{ + { + ID: 1, + Name: "BaseStation1", + Coords: [3]float64{0, 0, 0}, + Params: simulator.BaseStationParams{ + AntennaRadius: 2000, + AntennaDirection: [3]float64{1, 0, 0}, + }, + }, + } + // Создаем симуляцию + sim := &simulator.NetworkSimulation{ + Map: mapObj, + Drones: drones, + BaseStations: baseStations, + TimeStep: 5, + } + // Запуск симуляции на 30 секунд + sim.Simulate(300) + } +// func main() { +// D_EXPORT_VARS() +// err := database.NewDBConnection() +// if err != nil { +// panic(err) +// } +// err = server.SpawnServer() +// if err != nil { +// panic(err) +// } +// } + func D_EXPORT_VARS() { os.Setenv("SERVER_BASE_ADDRESS", "0.0.0.0:8080") } diff --git a/src/server/package/math/loss.go b/src/server/package/math/loss/loss.go similarity index 100% rename from src/server/package/math/loss.go rename to src/server/package/math/loss/loss.go diff --git a/src/server/package/math/simulator/simulation_model.go b/src/server/package/math/simulator/simulation_model.go new file mode 100644 index 0000000..71a1702 --- /dev/null +++ b/src/server/package/math/simulator/simulation_model.go @@ -0,0 +1 @@ +package simulator diff --git a/src/server/package/math/simulator/simulator.go b/src/server/package/math/simulator/simulator.go new file mode 100644 index 0000000..93e7027 --- /dev/null +++ b/src/server/package/math/simulator/simulator.go @@ -0,0 +1,177 @@ +package simulator + +import ( + "math" + "sync" +) + +type Map struct { + Name string + MinBound [3]float64 + MaxBound [3]float64 + HeightData [][]float64 // Двумерный массив с высотами карты +} + +type DroneParams struct { + AntennaRadius float64 + AntennaDirection [3]float64 + Waypoints [][3]float64 + Speed float64 + MeshName string +} + +type Drone struct { + ID int + Name string + Coords [3]float64 + CurrentCoords [3]float64 + Params DroneParams +} + +type BaseStationParams struct { + AntennaRadius float64 + AntennaDirection [3]float64 +} + +type BaseStation struct { + ID int + Name string + Coords [3]float64 + Params BaseStationParams +} + +type NetworkSimulation struct { + Map *Map + Drones []*Drone + BaseStations []*BaseStation + TimeStep int +} + +// Simulate запускает симуляцию с параллельной обработкой дронов +func (sim *NetworkSimulation) Simulate(totalTime int) { + var wg sync.WaitGroup + times := totalTime / sim.TimeStep + + for t := 0; t < times; t++ { + wg.Add(len(sim.Drones)) + + // Параллельная обработка каждого дрона + for _, drone := range sim.Drones { + go func(d *Drone) { + defer wg.Done() + + // Перемещение дрона + d.Move(sim.TimeStep) + + // Проверка соединения с базовой станцией + if !IsDroneInNetwork(d, sim.BaseStations, sim.Map) { + // Если дрон имеет mesh-сеть, ищем другой дрон для ретрансляции + closestDrone := FindClosestDroneToBaseStation(d, sim.Drones, sim.BaseStations[0], sim.Map) + if closestDrone != nil { + // Дрон может передавать данные через другой дрон + // Можно добавить логику для регистрации передачи данных + } + } + }(drone) + } + + wg.Wait() // Ожидание завершения всех горутин + } +} + +// IsInLOS проверяет, находится ли дрон в зоне прямой видимости с базовой станцией +func IsInLOS(drone *Drone, baseStation *BaseStation, mapObj *Map) bool { + return CheckLineOfSight(drone.CurrentCoords, baseStation.Coords, mapObj) +} + +// CheckLineOfSight проверяет прямую видимость между двумя точками с учетом рельефа карты +func CheckLineOfSight(from, to [3]float64, mapObj *Map) bool { + steps := 100 // Количество шагов для дискретизации + dx := (to[0] - from[0]) / float64(steps) + dy := (to[1] - from[1]) / float64(steps) + dz := (to[2] - from[2]) / float64(steps) + + for i := 0; i <= steps; i++ { + x := from[0] + float64(i)*dx + y := from[1] + float64(i)*dy + z := from[2] + float64(i)*dz + + if z <= GetHeightAt(mapObj, x, y) { + return false + } + } + return true +} + +// GetHeightAt возвращает высоту рельефа на карте для данной координаты +func GetHeightAt(mapObj *Map, x, y float64) float64 { + // Предположим, что высота карты представлена как двумерный массив + // x, y должны быть приведены к индексам этого массива + if x < mapObj.MinBound[0] || x > mapObj.MaxBound[0] || y < mapObj.MinBound[1] || y > mapObj.MaxBound[1] { + return mapObj.MinBound[2] // Если за пределами карты, возвращаем минимальную высоту + } + + // Преобразуем координаты в индексы + xIndex := int((x - mapObj.MinBound[0]) / (mapObj.MaxBound[0] - mapObj.MinBound[0]) * float64(len(mapObj.HeightData[0]))) + yIndex := int((y - mapObj.MinBound[1]) / (mapObj.MaxBound[1] - mapObj.MinBound[1]) * float64(len(mapObj.HeightData))) + + // Возвращаем соответствующую высоту + return mapObj.HeightData[yIndex][xIndex] +} + +// IsDroneInNetwork проверяет, может ли дрон подключиться к базовой станции +func IsDroneInNetwork(drone *Drone, baseStations []*BaseStation, mapObj *Map) bool { + for _, base := range baseStations { + if IsInLOS(drone, base, mapObj) && euclideanDistance(drone.CurrentCoords, base.Coords) <= base.Params.AntennaRadius { + return true + } + } + return false +} + +// Move перемещает дрон по точкам следования +func (d *Drone) Move(timeStep int) { + if len(d.Params.Waypoints) > 0 { + target := d.Params.Waypoints[0] + direction := [3]float64{ + target[0] - d.CurrentCoords[0], + target[1] - d.CurrentCoords[1], + target[2] - d.CurrentCoords[2], + } + + distance := math.Sqrt(direction[0]*direction[0] + direction[1]*direction[1] + direction[2]*direction[2]) + moveDistance := d.Params.Speed * float64(timeStep) + + // Обновляем координаты + for i := 0; i < 3; i++ { + d.CurrentCoords[i] += direction[i] / distance * moveDistance + } + } +} + +// FindClosestDroneToBaseStation находит ближайший дрон к базовой станции в mesh-сети +func FindClosestDroneToBaseStation(drone *Drone, allDrones []*Drone, baseStation *BaseStation, mapObj *Map) *Drone { + var closestDrone *Drone + minDistance := math.MaxFloat64 + + for _, otherDrone := range allDrones { + if otherDrone.ID == drone.ID || otherDrone.Params.MeshName != drone.Params.MeshName { + continue + } + + if IsInLOS(otherDrone, baseStation, mapObj) { + distance := euclideanDistance(otherDrone.CurrentCoords, baseStation.Coords) + if distance < minDistance { + minDistance = distance + closestDrone = otherDrone + } + } + } + + return closestDrone +} + +// euclideanDistance рассчитывает евклидово расстояние между двумя точками +func euclideanDistance(p1, p2 [3]float64) float64 { + return math.Sqrt(math.Pow(p2[0]-p1[0], 2) + math.Pow(p2[1]-p1[1], 2) + math.Pow(p2[2]-p1[2], 2)) +} From 46180110d43f9cd60e0c22534e97a2da2fd0b3cf Mon Sep 17 00:00:00 2001 From: moxitech Date: Sat, 5 Oct 2024 00:36:05 +0700 Subject: [PATCH 2/2] Simulation over network! --- src/server/cmd/main.go | 139 +++++++++-------- src/server/package/math/coverage/coverage.go | 2 +- src/server/package/math/distance/distance.go | 8 + .../package/math/simulator/simulator.go | 140 +++++++++++++----- src/server/package/utils/sorting/sorting.go | 23 +++ 5 files changed, 209 insertions(+), 103 deletions(-) create mode 100644 src/server/package/math/distance/distance.go create mode 100644 src/server/package/utils/sorting/sorting.go diff --git a/src/server/cmd/main.go b/src/server/cmd/main.go index eab1f4f..92c97d8 100644 --- a/src/server/cmd/main.go +++ b/src/server/cmd/main.go @@ -1,81 +1,90 @@ package main import ( - // "moxitech/dns/internal/database" - // "moxitech/dns/internal/server" - "moxitech/dns/package/math/simulator" + "moxitech/dns/internal/database" + "moxitech/dns/internal/server" + + // "fmt" + // "moxitech/dns/package/math/simulator" + // u_sorting "moxitech/dns/package/utils/sorting" "os" ) // var wg sync.WaitGroup = sync.WaitGroup{} -func main() { - // Пример карты высот, замените на настоящие данные - heightData := [][]float64{ - {0, 10, 15, 20}, - {5, 15, 25, 30}, - {10, 20, 35, 40}, - {15, 25, 40, 50}, - } - - // Определяем карту высот - mapObj := &simulator.Map{ - Name: "Example Map", - MinBound: [3]float64{-1000, -1000, 0}, - MaxBound: [3]float64{1000, 1000, 500}, - HeightData: heightData, - } - // Определяем дронов - drones := []*simulator.Drone{ - { - ID: 1, - Name: "Drone 1", - Coords: [3]float64{100, 100, 50}, - Params: simulator.DroneParams{ - AntennaRadius: 500, - AntennaDirection: [3]float64{1, 0, 0}, - Waypoints: [][3]float64{{200, 200, 50}}, - Speed: 10, - MeshName: "MeshA", - }, - }, - } - // Определяем базовые станции - baseStations := []*simulator.BaseStation{ - { - ID: 1, - Name: "BaseStation1", - Coords: [3]float64{0, 0, 0}, - Params: simulator.BaseStationParams{ - AntennaRadius: 2000, - AntennaDirection: [3]float64{1, 0, 0}, - }, - }, - } - // Создаем симуляцию - sim := &simulator.NetworkSimulation{ - Map: mapObj, - Drones: drones, - BaseStations: baseStations, - TimeStep: 5, - } - // Запуск симуляции на 30 секунд - sim.Simulate(300) - -} - // func main() { -// D_EXPORT_VARS() -// err := database.NewDBConnection() -// if err != nil { -// panic(err) +// // Пример карты высот, замените на настоящие данные +// heightData := [][]float64{ +// {0, 10, 15, 20}, +// {5, 15, 25, 30}, +// {10, 20, 35, 40}, +// {15, 25, 40, 50}, // } -// err = server.SpawnServer() -// if err != nil { -// panic(err) + +// // Определяем карту высот +// mapObj := &simulator.Map{ +// Name: "Example Map", +// MinBound: [3]float64{-1000, -1000, 0}, +// MaxBound: [3]float64{1000, 1000, 500}, +// HeightData: heightData, // } +// // Определяем дронов +// drones := []*simulator.Drone{ +// { +// ID: 1, +// Name: "Drone 1", +// Coords: [3]float64{100, 100, 50}, +// Params: simulator.DroneParams{ +// AntennaRadius: 500, +// AntennaDirection: [3]float64{1, 0, 0}, +// Waypoints: [][3]float64{{200, 200, 50}}, +// Speed: 10, +// MeshName: "MeshA", +// }, +// }, +// } +// // Определяем базовые станции +// baseStations := []*simulator.BaseStation{ +// { +// ID: 1, +// Name: "BaseStation1", +// Coords: [3]float64{0, 0, 0}, +// Params: simulator.BaseStationParams{ +// AntennaRadius: 2000, +// AntennaDirection: [3]float64{1, 0, 0}, +// }, +// }, +// } +// // Создаем симуляцию +// sim := &simulator.NetworkSimulation{ +// Map: mapObj, +// Drones: drones, +// BaseStations: baseStations, +// TimeStep: 2, +// } +// // Запуск симуляции на 300 секунд +// result_sim := sim.Simulate(300) +// result := u_sorting.SortMap(result_sim) +// for time, state := range result { +// for localstate, f := range state { +// fmt.Printf("%v| %v sec :: %v\n", time, localstate, f) +// } +// } + // } +func main() { + D_EXPORT_VARS() + err := database.NewDBConnection() + if err != nil { + panic(err) + } + err = server.SpawnServer() + if err != nil { + panic(err) + } +} + func D_EXPORT_VARS() { os.Setenv("SERVER_BASE_ADDRESS", "0.0.0.0:8080") } diff --git a/src/server/package/math/coverage/coverage.go b/src/server/package/math/coverage/coverage.go index 6fe40cd..c628382 100644 --- a/src/server/package/math/coverage/coverage.go +++ b/src/server/package/math/coverage/coverage.go @@ -4,7 +4,7 @@ import ( "fmt" "math" model "moxitech/dns/entity/math" - loss "moxitech/dns/package/math" + loss "moxitech/dns/package/math/loss" ) // CalculateCoverage Расчет зон радиопокрытия diff --git a/src/server/package/math/distance/distance.go b/src/server/package/math/distance/distance.go new file mode 100644 index 0000000..b0d1c8e --- /dev/null +++ b/src/server/package/math/distance/distance.go @@ -0,0 +1,8 @@ +package distance + +import "math" + +// euclideanDistance рассчитывает евклидово расстояние между двумя точками +func EuclideanDistance(p1, p2 [3]float64) float64 { + return math.Sqrt(math.Pow(p2[0]-p1[0], 2) + math.Pow(p2[1]-p1[1], 2) + math.Pow(p2[2]-p1[2], 2)) +} diff --git a/src/server/package/math/simulator/simulator.go b/src/server/package/math/simulator/simulator.go index 93e7027..de4310d 100644 --- a/src/server/package/math/simulator/simulator.go +++ b/src/server/package/math/simulator/simulator.go @@ -2,6 +2,7 @@ package simulator import ( "math" + "moxitech/dns/package/math/distance" "sync" ) @@ -18,6 +19,9 @@ type DroneParams struct { Waypoints [][3]float64 Speed float64 MeshName string + Modulation string // Тип модуляции (например, QPSK, QAM, OFDM) + Bandwidth float64 // Полоса частот в MHz + DataRate float64 // Скорость передачи данных в Mbps } type Drone struct { @@ -31,6 +35,9 @@ type Drone struct { type BaseStationParams struct { AntennaRadius float64 AntennaDirection [3]float64 + Modulation string // Тип модуляции + Bandwidth float64 // Полоса частот + DataRate float64 // Скорость передачи данных } type BaseStation struct { @@ -47,12 +54,21 @@ type NetworkSimulation struct { TimeStep int } -// Simulate запускает симуляцию с параллельной обработкой дронов -func (sim *NetworkSimulation) Simulate(totalTime int) { +// Simulate запускает симуляцию и возвращает состояние сети на каждую секунду +func (sim *NetworkSimulation) Simulate(totalTime int) map[int]map[string][]interface{} { var wg sync.WaitGroup times := totalTime / sim.TimeStep + simulationData := make(map[int]map[string][]interface{}) for t := 0; t < times; t++ { + currentTime := t * sim.TimeStep + + // Создаем временное хранилище для дронов и базовых станций в данной секунде + secondState := map[string][]interface{}{ + "drones": make([]interface{}, 0), + // "baseStations": make([]interface{}, 0), + } + wg.Add(len(sim.Drones)) // Параллельная обработка каждого дрона @@ -69,14 +85,40 @@ func (sim *NetworkSimulation) Simulate(totalTime int) { closestDrone := FindClosestDroneToBaseStation(d, sim.Drones, sim.BaseStations[0], sim.Map) if closestDrone != nil { // Дрон может передавать данные через другой дрон - // Можно добавить логику для регистрации передачи данных + // Логику передачи можно добавить сюда } } + + // Добавляем данные о дроне в текущее состояние + // Пример в симуляции, где обновляется информация о дроне + secondState["drones"] = append(secondState["drones"], map[string]interface{}{ + "id": d.ID, + "name": d.Name, + "coords": d.CurrentCoords, + "speed": d.Params.Speed, + "dataRate": CalculateDataRate(d.Params.Modulation, d.Params.Bandwidth), // Добавляем расчет скорости передачи + }) + }(drone) } wg.Wait() // Ожидание завершения всех горутин + + // Добавляем параметры базовых станций в текущее состояние + // TODO : для возможности динамической смены параметров базовой станции + // for _, baseStation := range sim.BaseStations { + // secondState["baseStations"] = append(secondState["baseStations"], map[string]interface{}{ + // "id": baseStation.ID, + // "name": baseStation.Name, + // "coords": baseStation.Coords, + // }) + // } + + // Сохраняем состояние для данной секунды + simulationData[currentTime] = secondState } + + return simulationData } // IsInLOS проверяет, находится ли дрон в зоне прямой видимости с базовой станцией @@ -84,25 +126,6 @@ func IsInLOS(drone *Drone, baseStation *BaseStation, mapObj *Map) bool { return CheckLineOfSight(drone.CurrentCoords, baseStation.Coords, mapObj) } -// CheckLineOfSight проверяет прямую видимость между двумя точками с учетом рельефа карты -func CheckLineOfSight(from, to [3]float64, mapObj *Map) bool { - steps := 100 // Количество шагов для дискретизации - dx := (to[0] - from[0]) / float64(steps) - dy := (to[1] - from[1]) / float64(steps) - dz := (to[2] - from[2]) / float64(steps) - - for i := 0; i <= steps; i++ { - x := from[0] + float64(i)*dx - y := from[1] + float64(i)*dy - z := from[2] + float64(i)*dz - - if z <= GetHeightAt(mapObj, x, y) { - return false - } - } - return true -} - // GetHeightAt возвращает высоту рельефа на карте для данной координаты func GetHeightAt(mapObj *Map, x, y float64) float64 { // Предположим, что высота карты представлена как двумерный массив @@ -122,7 +145,7 @@ func GetHeightAt(mapObj *Map, x, y float64) float64 { // IsDroneInNetwork проверяет, может ли дрон подключиться к базовой станции func IsDroneInNetwork(drone *Drone, baseStations []*BaseStation, mapObj *Map) bool { for _, base := range baseStations { - if IsInLOS(drone, base, mapObj) && euclideanDistance(drone.CurrentCoords, base.Coords) <= base.Params.AntennaRadius { + if IsInLOS(drone, base, mapObj) && distance.EuclideanDistance(drone.CurrentCoords, base.Coords) <= base.Params.AntennaRadius { return true } } @@ -131,24 +154,50 @@ func IsDroneInNetwork(drone *Drone, baseStations []*BaseStation, mapObj *Map) bo // Move перемещает дрон по точкам следования func (d *Drone) Move(timeStep int) { - if len(d.Params.Waypoints) > 0 { - target := d.Params.Waypoints[0] - direction := [3]float64{ - target[0] - d.CurrentCoords[0], - target[1] - d.CurrentCoords[1], - target[2] - d.CurrentCoords[2], - } + if len(d.Params.Waypoints) == 0 { + return // Если нет путевых точек, дрон останавливается + } - distance := math.Sqrt(direction[0]*direction[0] + direction[1]*direction[1] + direction[2]*direction[2]) - moveDistance := d.Params.Speed * float64(timeStep) + target := d.Params.Waypoints[0] + direction := [3]float64{ + target[0] - d.CurrentCoords[0], + target[1] - d.CurrentCoords[1], + target[2] - d.CurrentCoords[2], + } - // Обновляем координаты + distance := math.Sqrt(direction[0]*direction[0] + direction[1]*direction[1] + direction[2]*direction[2]) + moveDistance := d.Params.Speed * float64(timeStep) + + if moveDistance >= distance { + d.CurrentCoords = target + d.Params.Waypoints = d.Params.Waypoints[1:] // Удаляем достигнутую точку + } else { for i := 0; i < 3; i++ { d.CurrentCoords[i] += direction[i] / distance * moveDistance } } } +// CheckLineOfSight проверяет прямую видимость между двумя точками с учетом рельеф +func CheckLineOfSight(from, to [3]float64, mapObj *Map) bool { + distance := distance.EuclideanDistance(from, to) + steps := int(distance * 10) // Используем шаги, пропорциональные длине пути + dx := (to[0] - from[0]) / float64(steps) + dy := (to[1] - from[1]) / float64(steps) + dz := (to[2] - from[2]) / float64(steps) + + for i := 0; i <= steps; i++ { + x := from[0] + float64(i)*dx + y := from[1] + float64(i)*dy + z := from[2] + float64(i)*dz + + if z <= GetHeightAt(mapObj, x, y) { + return false + } + } + return true +} + // FindClosestDroneToBaseStation находит ближайший дрон к базовой станции в mesh-сети func FindClosestDroneToBaseStation(drone *Drone, allDrones []*Drone, baseStation *BaseStation, mapObj *Map) *Drone { var closestDrone *Drone @@ -160,7 +209,7 @@ func FindClosestDroneToBaseStation(drone *Drone, allDrones []*Drone, baseStation } if IsInLOS(otherDrone, baseStation, mapObj) { - distance := euclideanDistance(otherDrone.CurrentCoords, baseStation.Coords) + distance := distance.EuclideanDistance(otherDrone.CurrentCoords, baseStation.Coords) if distance < minDistance { minDistance = distance closestDrone = otherDrone @@ -171,7 +220,24 @@ func FindClosestDroneToBaseStation(drone *Drone, allDrones []*Drone, baseStation return closestDrone } -// euclideanDistance рассчитывает евклидово расстояние между двумя точками -func euclideanDistance(p1, p2 [3]float64) float64 { - return math.Sqrt(math.Pow(p2[0]-p1[0], 2) + math.Pow(p2[1]-p1[1], 2) + math.Pow(p2[2]-p1[2], 2)) +// CalculateDataRate рассчитывает скорость передачи данных на основе типа модуляции и полосы частот +func CalculateDataRate(modulation string, bandwidth float64) float64 { + var spectralEfficiency float64 + + switch modulation { + case "QPSK": + spectralEfficiency = 2.0 // биты/Гц + case "16QAM": + spectralEfficiency = 4.0 + case "64QAM": + spectralEfficiency = 6.0 + case "256QAM": + spectralEfficiency = 8.0 + case "OFDM": + spectralEfficiency = 10.0 + default: + spectralEfficiency = 1.0 // базовый случай + } + + return spectralEfficiency * bandwidth // скорость передачи данных в Mbps } diff --git a/src/server/package/utils/sorting/sorting.go b/src/server/package/utils/sorting/sorting.go new file mode 100644 index 0000000..7433d10 --- /dev/null +++ b/src/server/package/utils/sorting/sorting.go @@ -0,0 +1,23 @@ +package u_sorting + +import "sort" + +// Функция сортировки карты по ключам int +func SortMap(m map[int]map[string][]interface{}) []map[int]map[string][]interface{} { + // Извлечь ключи карты + keys := make([]int, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + + // Отсортировать ключи + sort.Ints(keys) + + // Подготовить результат с отсортированными ключами + sorted := make([]map[int]map[string][]interface{}, 0, len(m)) + for _, k := range keys { + sorted = append(sorted, map[int]map[string][]interface{}{k: m[k]}) + } + + return sorted +}