Skip to content

Commit 11b1770

Browse files
committed
done
1 parent 89ca114 commit 11b1770

5 files changed

Lines changed: 88 additions & 246 deletions

File tree

β€Žfreight_project/backend/freight_trading.pyβ€Ž

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,13 @@ def assign_loads(self):
9595
# Check every truck to see which one is best
9696
for truck_idx, truck in self.trucks.iterrows():
9797
if truck['assigned_load'] is None: # only free trucks
98-
s = self.score(truck_idx, load_idx)
99-
if s < best_score:
100-
best_score = s
98+
dist = self.haversine(truck['lat'], truck['lng'],
99+
self.cities.at[load['origin_idx'], 'lat'],
100+
self.cities.at[load['origin_idx'], 'lng'])
101+
capacity_penalty = 0 if truck['capacity'] >= load['weight'] else 1000
102+
score = dist + capacity_penalty
103+
if score < best_score:
104+
best_score = score
101105
best_truck_idx = truck_idx
102106
# Assign best truck found
103107
if best_truck_idx is not None:
@@ -116,10 +120,8 @@ def update_trucks(self):
116120
dest = self.cities.iloc[load['dest_idx']]
117121

118122
# Move halfway closer to destination each time we call this
119-
truck_lat = truck['lat']
120-
truck_lng = truck['lng']
121-
truck_lat += (dest['lat'] - truck_lat) * 0.5
122-
truck_lng += (dest['lng'] - truck_lng) * 0.5
123+
truck_lat = truck['lat'] + (dest['lat'] - truck['lat']) * 0.5
124+
truck_lng = truck['lng'] + (dest['lng'] - truck['lng']) * 0.5
123125

124126
# Update truck’s position
125127
self.trucks.at[idx, 'lat'] = truck_lat
@@ -132,18 +134,4 @@ def update_trucks(self):
132134
print(f"βœ… Truck {truck['truck_id']} arrived at {dest['city']}, {dest['state_name']}")
133135
# Remove load (delivered)
134136
self.loads = self.loads[self.loads['load_id'] != load['load_id']]
135-
136-
# --- Example simulation run ---
137-
if __name__ == "__main__":
138-
sim = FreightSim("uscities.csv", num_trucks=10)
139-
140-
# Make 5 random shipments
141-
for _ in range(5):
142-
sim.create_random_load()
143-
144-
# Assign trucks to those shipments
145-
sim.assign_loads()
146-
147-
# Move trucks step by step until some deliveries finish
148-
for _ in range(10):
149-
sim.update_trucks()
137+
print(f"πŸ“¦ Load {load['load_id']} delivered and removed from system.")

β€Žfreight_project/cli/main.pyβ€Ž

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,18 @@ def main():
1313
sim = FreightSim("uscities.csv", num_trucks=num_trucks, min_pop=min_pop)
1414

1515
# Create loads
16-
for _ in range(loads):
16+
for _ in range(num_loads):
1717
sim.create_random_load()
1818

1919
# Assign loads to trucks
2020
sim.assign_loads()
2121

2222
# Simulate step by step
2323
for step in range(num_steps):
24-
print(f"\n--- Simulation Step {step+1} ---")
24+
print(f"\n--- Step {step+1} ---")
2525
sim.update_trucks()
26+
print(sim.trucks[['truck_id','city','status','assigned_load']])
27+
print(sim.loads[['load_id','weight','assigned_truck']])
2628

2729
if __name__ == "__main__":
2830
main()

β€Žfreight_project/frontend/index.htmlβ€Ž

Lines changed: 15 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -2,103 +2,25 @@
22
<html>
33
<head>
44
<title>Freight Simulation</title>
5-
<meta charset="utf-8" />
5+
<meta charset="utf-8">
6+
<link rel="stylesheet" href="style.css">
67
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
78
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
89
</head>
910
<body>
1011
<h1>Freight Simulation Dashboard</h1>
11-
<div class="control-panel">
12-
<label>Number of Trucks:</label>
13-
<input id="numTrucks" type="number" value="50" />
14-
15-
<label>Number of Loads:</label>
16-
<input id="numLoads" type="number" value="20" />
17-
18-
<label>Minimum Population:</label>
19-
<input id="minPop" type="number" value="100000" />
20-
21-
<button onclick="startSimulation()">Start Simulation</button>
22-
<button onclick="createLoad()">Create Random Load</button>
23-
</div>
24-
25-
<div id="map"></div>
26-
<script>
27-
// Initialize Leaflet map centered on the US
28-
const map = L.map('map').setView([39.5, -98.35], 4);
29-
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
30-
attribution: 'Β© OpenStreetMap'
31-
}).addTo(map);
32-
33-
let truckMarkers = {};
34-
let loadLines = {};
35-
36-
// Function to refresh truck positions and status from backend
37-
async function refresh() {
38-
const res = await fetch("http://127.0.0.1:8000/status");
39-
const data = await res.json();
40-
41-
// Update or create markers for each truck
42-
data.trucks.forEach(truck => {
43-
if (truckMarkers[truck.truck_id]) {
44-
// Move existing marker to new position
45-
truckMarkers[truck.truck_id].setLatLng([truck.lat, truck.lon]);
46-
truckMarkers[truck.truck_id].bindPopup(`Truck: ${truck.truck_id}<br>Status: ${truck.status}`);
47-
} else {
48-
// Create a new marker
49-
truckMarkers[truck.truck_id] = L.circleMarker([truck.lat, truck.lon], {
50-
radius: 6,
51-
color: truck.status === "Idle" ? "green" : "orange" // color by status
52-
}).addTo(map)
53-
.bindPopup(`Truck: ${truck.truck_id}<br>Status: ${truck.status}`);
54-
}
55-
});
56-
57-
// Draw lines between trucks and their loads
58-
data.loads.forEach(load => {
59-
const lineId = load.load_id;
60-
const originLatLng = [parseFloat(load.origin_lat || 0), parseFloat(load.origin_lon || 0)];
61-
const destLatLng = [parseFloat(load.dest_lat || 0), parseFloat(load.dest_lon || 0)];
62-
63-
// Create or update polyline
64-
if (!loadLines[lineId]) {
65-
loadLines[lineId] = L.polyline([originLatLng, destLatLng], {
66-
color: "orange",
67-
weight: 2,
68-
dashArray: '5, 5'
69-
}).addTo(map);
70-
}
71-
});
72-
73-
// Remove lines for delivered loads
74-
Object.keys(loadLines).forEach(lineId => {
75-
const stillExists = data.loads.some(l => l.load_id === lineId);
76-
if (!stillExists) {
77-
map.removeLayer(loadLines[lineId]);
78-
delete loadLines[lineId];
79-
}
80-
});
81-
82-
}
83-
// Function to start simulation with dynamic user inputs
84-
async function startSimulation() {
85-
const numTrucks = parseInt(document.getElementById("numTrucks").value);
86-
const numLoads = parseInt(document.getElementById("numLoads").value);
87-
const minPop = parseInt(document.getElementById("minPop").value);
88-
89-
// Call backend endpoint to initialize simulation
90-
await fetch(`http://127.0.0.1:8000/init?num_trucks=${numTrucks}&num_loads=${numLoads}&min_pop=${minPop}`);
91-
alert("Simulation started!");
92-
}
93-
94-
// Function to create a new random load
95-
async function createLoad() {
96-
await fetch("http://127.0.0.1:8000/create_load");
97-
}
98-
99-
// Initial refresh and periodic updates every 1 second
100-
refresh();
101-
setInterval(refresh, 1000);
102-
</script>
12+
<div class="input-box">
13+
<label>Number of Trucks:</label>
14+
<input id="numTrucks" type="number" value="50">
15+
<label>Number of Loads:</label>
16+
<input id="numLoads" type="number" value="20">
17+
<label>Minimum Population:</label>
18+
<input id="minPop" type="number" value="50000">
19+
<button onclick="startSimulation()">Start Simulation</button>
20+
<button onclick="createLoad()">Create Random Load</button>
21+
</div>
22+
<div id="map"></div>
23+
<div id="output"></div>
24+
<script src="script.js"></script>
10325
</body>
10426
</html>
Lines changed: 53 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,63 @@
1-
let cities = [];
2-
3-
// Load CSV file dynamically
4-
Papa.parse("uscities.csv", {
5-
download: true,
6-
header: true,
7-
complete: (results) => {
8-
cities = results.data;
9-
console.log("Loaded cities:", cities.length);
10-
}
11-
});
12-
13-
// Pick a random city filtered by min population
14-
function randomCity(minPop) {
15-
const filtered = cities.filter(c => parseInt(c.population) > minPop);
16-
return filtered[Math.floor(Math.random() * filtered.length)];
17-
}
18-
19-
// Haversine distance calculator (miles)
20-
function haversine(lat1, lon1, lat2, lon2) {
21-
const R = 3956;
22-
const toRad = x => (x * Math.PI) / 180;
23-
24-
const dLat = toRad(lat2 - lat1);
25-
const dLon = toRad(lon2 - lon1);
26-
const a =
27-
Math.sin(dLat / 2)**2 +
28-
Math.cos(toRad(lat1)) *
29-
Math.cos(toRad(lat2)) *
30-
Math.sin(dLon / 2)**2;
31-
32-
return 2 * R * Math.asin(Math.sqrt(a));
33-
}
34-
35-
function startSimulation() {
36-
const numTrucks = parseInt(document.getElementById("trucks").value);
37-
const numLoads = parseInt(document.getElementById("loads").value);
38-
const minPop = parseInt(document.getElementById("min_pop").value);
39-
40-
let output = "";
41-
42-
//----------------------------------
43-
// 1. Create trucks
44-
//----------------------------------
45-
let trucks = [];
46-
for (let i = 0; i < numTrucks; i++) {
47-
let c = randomCity(minPop);
48-
trucks.push({
49-
id: "T" + (i+1),
50-
city: c.city,
51-
lat: parseFloat(c.lat),
52-
lon: parseFloat(c.lng),
53-
status: "Idle",
54-
capacity: Math.floor(Math.random() * 20) + 10
1+
const map = L.map('map').setView([39.5, -98.35], 4);
2+
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
3+
4+
let truckMarkers = {};
5+
let loadLines = {};
6+
7+
async function refresh() {
8+
const res = await fetch("http://127.0.0.1:8000/status");
9+
const data = await res.json();
10+
11+
// Trucks
12+
data.trucks.forEach(truck => {
13+
if (truckMarkers[truck.truck_id]) {
14+
truckMarkers[truck.truck_id].setLatLng([truck.lat, truck.lon]);
15+
truckMarkers[truck.truck_id].bindPopup(`${truck.truck_id} - ${truck.status}`);
16+
} else {
17+
truckMarkers[truck.truck_id] = L.circleMarker([truck.lat, truck.lon], {
18+
radius: 6,
19+
color: truck.status === "Idle" ? "green" : "orange"
20+
}).addTo(map).bindPopup(`${truck.truck_id} - ${truck.status}`);
21+
}
5522
});
56-
}
57-
58-
//----------------------------------
59-
// 2. Create loads
60-
//----------------------------------
61-
let loads = [];
62-
for (let i = 0; i < numLoads; i++) {
63-
let origin = randomCity(minPop);
64-
let dest = randomCity(minPop);
6523

66-
loads.push({
67-
id: "L" + (i+1),
68-
origin: origin.city,
69-
dest: dest.city,
70-
latO: parseFloat(origin.lat),
71-
lonO: parseFloat(origin.lng),
72-
latD: parseFloat(dest.lat),
73-
lonD: parseFloat(dest.lng),
74-
weight: Math.floor(Math.random() * 20) + 5
24+
// Loads (polylines)
25+
data.loads.forEach(load => {
26+
const lineId = load.load_id;
27+
const origin = [load.latO || load.dest_lat, load.lonO || load.dest_lon];
28+
const dest = [load.dest_lat, load.dest_lon];
29+
30+
if (!loadLines[lineId]) {
31+
loadLines[lineId] = L.polyline([origin, dest], {
32+
color: "orange",
33+
weight: 2,
34+
dashArray: '5,5'
35+
}).addTo(map);
36+
}
7537
});
76-
}
77-
78-
//----------------------------------
79-
// 3. Assign loads to trucks
80-
//----------------------------------
81-
loads.forEach(load => {
82-
let bestTruck = null;
83-
let bestScore = Infinity;
84-
85-
trucks.forEach(truck => {
86-
if (truck.status === "Idle") {
87-
if (truck.capacity < load.weight) return;
8838

89-
let dist = haversine(truck.lat, truck.lon, load.latO, load.lonO);
90-
91-
if (dist < bestScore) {
92-
bestScore = dist;
93-
bestTruck = truck;
39+
// Remove delivered loads
40+
Object.keys(loadLines).forEach(lineId => {
41+
if (!data.loads.some(l => l.load_id === lineId)) {
42+
map.removeLayer(loadLines[lineId]);
43+
delete loadLines[lineId];
9444
}
95-
}
9645
});
46+
}
9747

98-
if (bestTruck) {
99-
bestTruck.status = "Assigned β†’ " + load.id;
100-
load.assigned = bestTruck.id;
101-
} else {
102-
load.assigned = "NO AVAILABLE TRUCK";
103-
}
104-
});
105-
106-
//----------------------------------
107-
// Output
108-
//----------------------------------
109-
output += "πŸš› TRUCKS:\n";
110-
trucks.forEach(t => {
111-
output += `${t.id} β€” ${t.city} β€” ${t.status} β€” cap ${t.capacity}\n`;
112-
});
48+
// Initialize simulation
49+
async function startSimulation() {
50+
const numTrucks = document.getElementById("numTrucks").value;
51+
const numLoads = document.getElementById("numLoads").value;
52+
const minPop = document.getElementById("minPop").value;
11353

114-
output += "\nπŸ“¦ LOADS:\n";
115-
loads.forEach(l => {
116-
output += `${l.id} β€” ${l.origin} β†’ ${l.dest} β€” weight ${l.weight} β€” assigned: ${l.assigned}\n`;
117-
});
54+
await fetch(`http://127.0.0.1:8000/init?num_trucks=${numTrucks}&num_loads=${numLoads}&min_pop=${minPop}`);
55+
alert("Simulation started!");
56+
}
11857

119-
document.getElementById("output").innerText = output;
58+
async function createLoad() {
59+
await fetch("http://127.0.0.1:8000/create_load");
12060
}
61+
62+
// Auto-refresh every 1 second
63+
setInterval(refresh, 1000);

0 commit comments

Comments
Β (0)