elifbasboga commited on
Commit
890628b
·
1 Parent(s): baf4622

Save my local changes before pulling

Browse files
.idea/encodings.xml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="Encoding">
4
+ <file url="file://$PROJECT_DIR$/src/src/ParcelSortX.java" charset="UTF-8" />
5
+ <file url="file://$PROJECT_DIR$/src/src/ParcelSortXGUI.java" charset="UTF-8" />
6
+ </component>
7
+ </project>
.idea/modules.xml CHANGED
@@ -2,7 +2,7 @@
2
  <project version="4">
3
  <component name="ProjectModuleManager">
4
  <modules>
5
- <module fileurl="file://$PROJECT_DIR$/project.iml" filepath="$PROJECT_DIR$/project.iml" />
6
  </modules>
7
  </component>
8
  </project>
 
2
  <project version="4">
3
  <component name="ProjectModuleManager">
4
  <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/smart_package_sortingRouting_simulation.iml" filepath="$PROJECT_DIR$/smart_package_sortingRouting_simulation.iml" />
6
  </modules>
7
  </component>
8
  </project>
config.txt CHANGED
@@ -1,6 +1,7 @@
1
- randomParcelPerTick=2
2
- interval=3
3
- Istanbul
4
- Ankara
5
- Izmir
6
- Bursa
 
 
1
+ MAX TICKS=10
2
+ QUEUE CAPACITY=30
3
+ TERMINAL ROTATION INTERVAL=5
4
+ PARCEL PER TICK MIN=1
5
+ PARCEL PER TICK MAX=3
6
+ MISROUTING RATE=0.1
7
+ CITY LIST=Istanbul , Ankara , Izmir , Bursa , Antalya
log.txt ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [Tick 1]
2
+ New Parcels: P1_0 to Bursa (Priority 1), P1_1 to Ankara (Priority 1), P1_2 to Bursa (Priority 2)
3
+ Queue Size: 3
4
+ Sorted to BST: P1_0, P1_1, P1_2
5
+ Dispatched: No parcels for active terminal Istanbul
6
+ BST city parcels: {Ankara=1, Bursa=2}
7
+ ReturnStack Size: 0
8
+ ArrivalBuffer []
9
+ ReturnStack(top->) []
10
+ BST:
11
+ └── Bursa (2)
12
+ └── Ankara (1)
13
+
14
+
15
+ [Tick 2]
16
+ New Parcels: P2_0 to Izmir (Priority 2), P2_1 to Bursa (Priority 2)
17
+ Queue Size: 2
18
+ Sorted to BST: P2_0, P2_1
19
+ Dispatched: No parcels for active terminal Istanbul
20
+ BST city parcels: {Ankara=1, Bursa=3, Izmir=1}
21
+ ReturnStack Size: 0
22
+ ArrivalBuffer []
23
+ ReturnStack(top->) []
24
+ BST:
25
+ └── Bursa (3)
26
+ ├── Ankara (1)
27
+ └── Izmir (1)
28
+
29
+
30
+ [Tick 3]
31
+ New Parcels: P3_0 to Antalya (Priority 3)
32
+ Queue Size: 1
33
+ Sorted to BST: P3_0
34
+ Dispatched: No parcels for active terminal Istanbul
35
+ BST city parcels: {Ankara=1, Antalya=1, Bursa=3, Izmir=1}
36
+ ReturnStack Size: 0
37
+ ArrivalBuffer []
38
+ ReturnStack(top->) []
39
+ BST:
40
+ └── Bursa (3)
41
+ ├── Ankara (1)
42
+ │ └── Antalya (1)
43
+ └── Izmir (1)
44
+
45
+
46
+ [Tick 4]
47
+ New Parcels: P4_0 to Istanbul (Priority 2)
48
+ Queue Size: 1
49
+ Sorted to BST: P4_0
50
+ Returned: P4_0 misrouted -> Pushed to ReturnStack
51
+ BST city parcels: {Ankara=1, Antalya=1, Bursa=3, Istanbul=0, Izmir=1}
52
+ ReturnStack Size: 1
53
+ ArrivalBuffer []
54
+ ReturnStack(top->) [P4_0]
55
+ BST:
56
+ └── Bursa (3)
57
+ ├── Ankara (1)
58
+ │ └── Antalya (1)
59
+ └── Izmir (1)
60
+ └── Istanbul (0)
61
+
62
+
63
+ [Tick 5]
64
+ New Parcels: P5_0 to Istanbul (Priority 1), P5_1 to Antalya (Priority 2)
65
+ Queue Size: 2
66
+ Sorted to BST: P5_0, P5_1
67
+ Dispatched: P5_0 from BST to Istanbul -> Success
68
+ Rotated to: Ankara
69
+ BST city parcels: {Ankara=1, Antalya=2, Bursa=3, Istanbul=0, Izmir=1}
70
+ ReturnStack Size: 1
71
+ ArrivalBuffer []
72
+ ReturnStack(top->) [P4_0]
73
+ BST:
74
+ └── Bursa (3)
75
+ ├── Ankara (1)
76
+ │ └── Antalya (2)
77
+ └── Izmir (1)
78
+ └── Istanbul (0)
79
+
80
+
81
+ [Tick 6]
82
+ New Parcels: P6_0 to Ankara (Priority 3), P6_1 to Istanbul (Priority 1)
83
+ Queue Size: 2
84
+ Sorted to BST: P6_0, P6_1
85
+ Dispatched: P6_0 from BST to Ankara -> Success
86
+ Reprocess: Returned parcel reprocessed: P4_0
87
+ BST city parcels: {Ankara=1, Antalya=2, Bursa=3, Istanbul=2, Izmir=1}
88
+ ReturnStack Size: 0
89
+ ArrivalBuffer []
90
+ ReturnStack(top->) []
91
+ BST:
92
+ └── Bursa (3)
93
+ ├── Ankara (1)
94
+ │ └── Antalya (2)
95
+ └── Izmir (1)
96
+ └── Istanbul (2)
97
+
98
+
99
+ [Tick 7]
100
+ New Parcels: P7_0 to Ankara (Priority 3), P7_1 to Antalya (Priority 3), P7_2 to Bursa (Priority 3)
101
+ Queue Size: 3
102
+ Sorted to BST: P7_0, P7_1, P7_2
103
+ Dispatched: P7_0 from BST to Ankara -> Success
104
+ BST city parcels: {Ankara=1, Antalya=3, Bursa=4, Istanbul=2, Izmir=1}
105
+ ReturnStack Size: 0
106
+ ArrivalBuffer []
107
+ ReturnStack(top->) []
108
+ BST:
109
+ └── Bursa (4)
110
+ ├── Ankara (1)
111
+ │ └── Antalya (3)
112
+ └── Izmir (1)
113
+ └── Istanbul (2)
114
+
115
+
116
+ [Tick 8]
117
+ New Parcels: P8_0 to Ankara (Priority 3)
118
+ Queue Size: 1
119
+ Sorted to BST: P8_0
120
+ Dispatched: P8_0 from BST to Ankara -> Success
121
+ BST city parcels: {Ankara=1, Antalya=3, Bursa=4, Istanbul=2, Izmir=1}
122
+ ReturnStack Size: 0
123
+ ArrivalBuffer []
124
+ ReturnStack(top->) []
125
+ BST:
126
+ └── Bursa (4)
127
+ ├── Ankara (1)
128
+ │ └── Antalya (3)
129
+ └── Izmir (1)
130
+ └── Istanbul (2)
131
+
132
+
133
+ [Tick 9]
134
+ New Parcels: P9_0 to Bursa (Priority 2)
135
+ Queue Size: 1
136
+ Sorted to BST: P9_0
137
+ Dispatched: P1_1 from BST to Ankara -> Success
138
+ BST city parcels: {Ankara=0, Antalya=3, Bursa=5, Istanbul=2, Izmir=1}
139
+ ReturnStack Size: 0
140
+ ArrivalBuffer []
141
+ ReturnStack(top->) []
142
+ BST:
143
+ └── Bursa (5)
144
+ ├── Ankara (0)
145
+ │ └── Antalya (3)
146
+ └── Izmir (1)
147
+ └── Istanbul (2)
148
+
149
+
150
+ [Tick 10]
151
+ New Parcels: P10_0 to Ankara (Priority 1), P10_1 to Antalya (Priority 2), P10_2 to Antalya (Priority 2)
152
+ Queue Size: 3
153
+ Sorted to BST: P10_0, P10_1, P10_2
154
+ Dispatched: P10_0 from BST to Ankara -> Success
155
+ Rotated to: Izmir
156
+ BST city parcels: {Ankara=0, Antalya=5, Bursa=5, Istanbul=2, Izmir=1}
157
+ ReturnStack Size: 0
158
+ ArrivalBuffer []
159
+ ReturnStack(top->) []
160
+ BST:
161
+ └── Bursa (5)
162
+ ├── Ankara (0)
163
+ │ └── Antalya (5)
164
+ └── Izmir (1)
165
+ └── Istanbul (2)
166
+
167
+
report.txt ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 📄 Final Simulation Report
2
+
3
+ Ticks
4
+
5
+ 10
6
+
7
+ Dispatched
8
+
9
+ 6
10
+
11
+ Returned
12
+
13
+ 1
14
+
15
+ Max Queue
16
+
17
+ 3
18
+
19
+ Max Stack
20
+
21
+ 1
22
+
23
+ 📦 All Tracked Parcels (19 total)
24
+
25
+ ID Destination Priority Size Tick Returns Status
26
+
27
+ P1_0 Bursa 1 Large 1 0 Sorted
28
+
29
+ P2_0 Izmir 2 Small 2 0 Sorted
30
+
31
+ P1_1 Ankara 1 Large 1 0 Dispatched
32
+
33
+ P3_0 Antalya 3 Small 3 0 Sorted
34
+
35
+ P2_1 Bursa 2 Small 2 0 Sorted
36
+
37
+ P1_2 Bursa 2 Large 1 0 Sorted
38
+
39
+ P4_0 Istanbul 2 Medium 4 2 Sorted
40
+
41
+ P5_0 Istanbul 1 Large 5 0 Dispatched
42
+
43
+ P6_0 Ankara 3 Small 6 0 Dispatched
44
+
45
+ P5_1 Antalya 2 Medium 5 0 Sorted
46
+
47
+ P7_0 Ankara 3 Large 7 0 Dispatched
48
+
49
+ P6_1 Istanbul 1 Large 6 0 Sorted
50
+
51
+ P8_0 Ankara 3 Large 8 0 Dispatched
52
+
53
+ P7_1 Antalya 3 Medium 7 0 Sorted
54
+
55
+ P9_0 Bursa 2 Small 9 0 Sorted
56
+
57
+ P7_2 Bursa 3 Large 7 0 Sorted
58
+
59
+ P10_0 Ankara 1 Medium 10 0 Dispatched
60
+
61
+ P10_1 Antalya 2 Small 10 0 Sorted
62
+
63
+ P10_2 Antalya 2 Medium 10 0 Sorted
64
+
65
+ 🏙️ City-Wise Parcel Distribution
66
+
67
+ ANKARA (0 parcels)
68
+
69
+ ID Priority Size Tick Returns
70
+
71
+ ANTALYA (5 parcels)
72
+
73
+ ID Priority Size Tick Returns
74
+
75
+ P5_1 2 Medium 5 0
76
+
77
+ P10_1 2 Small 10 0
78
+
79
+ P10_2 2 Medium 10 0
80
+
81
+ P3_0 3 Small 3 0
82
+
83
+ P7_1 3 Medium 7 0
84
+
85
+ BURSA (5 parcels)
86
+
87
+ ID Priority Size Tick Returns
88
+
89
+ P1_0 1 Large 1 0
90
+
91
+ P1_2 2 Large 1 0
92
+
93
+ P2_1 2 Small 2 0
94
+
95
+ P9_0 2 Small 9 0
96
+
97
+ P7_2 3 Large 7 0
98
+
99
+ ISTANBUL (2 parcels)
100
+
101
+ ID Priority Size Tick Returns
102
+
103
+ P6_1 1 Large 6 0
104
+
105
+ P4_0 2 Medium 4 2
106
+
107
+ IZMİR (1 parcels)
108
+
109
+ ID Priority Size Tick Returns
110
+
111
+ P2_0 2 Small 2 0
112
+
113
+ ✅ Report generated successfully!
route_config.txt DELETED
@@ -1,4 +0,0 @@
1
- Istanbul
2
- Ankara
3
- Izmir
4
- Bursa
 
 
 
 
 
src/src/ParcelSortX.java CHANGED
@@ -3,407 +3,593 @@ package src;
3
  import java.io.*;
4
  import java.util.*;
5
 
6
- // ------------------ PARCEL CLASS ------------------
7
- class Parcel {
8
- String id;
9
- String destination;
10
- int priority;
11
- int arrivalTick;
12
- int returnCount;
13
- String status;
14
-
15
- public Parcel(String id, String destination, int priority, int arrivalTick) {
16
- this.id = id;
17
- this.destination = destination;
18
- this.priority = priority;
19
- this.arrivalTick = arrivalTick;
20
- this.returnCount = 0;
21
- this.status = "Pending";
22
- }
23
-
24
- @Override
25
- public String toString() {
26
- return "[" + id + ", Dest: " + destination + ", Priority: " + priority +
27
- ", ArrivalTick: " + arrivalTick + ", ReturnCount: " + returnCount +
28
- ", Status: " + status + "]";
29
- }
30
- }
31
-
32
- // ------------------ QUEUE ------------------
33
- class ParcelQueue {
34
- private Queue<Parcel> queue;
35
-
36
- public ParcelQueue() {
37
- this.queue = new LinkedList<>();
38
- }
39
-
40
- public void enqueue(Parcel p) {
41
- queue.add(p);
42
- }
43
-
44
- public Parcel dequeue() {
45
- return queue.poll();
46
- }
47
-
48
- public boolean isEmpty() {
49
- return queue.isEmpty();
50
- }
51
- }
52
-
53
- // ------------------ STACK ------------------
54
- class ParcelStack {
55
- private List<Parcel> stack = new ArrayList<>();
56
-
57
- public void push(Parcel p) {
58
- stack.add(p);
59
- }
60
-
61
- public Parcel pop() {
62
- if (isEmpty()) return null;
63
- return stack.remove(stack.size() - 1);
64
- }
65
-
66
- public boolean isEmpty() {
67
- return stack.isEmpty();
68
- }
69
- }
70
-
71
- // ------------------ HASH TABLE ------------------
72
- class HashEntry {
73
- String key;
74
- Parcel value;
75
- HashEntry next;
76
-
77
- public HashEntry(String key, Parcel value) {
78
- this.key = key;
79
- this.value = value;
80
- }
81
- }
82
-
83
- class ManualHashTable {
84
- private HashEntry[] buckets;
85
- private int capacity;
86
 
87
- public ManualHashTable(int capacity) {
88
- this.capacity = capacity;
89
- this.buckets = new HashEntry[capacity];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  }
91
 
92
- private int getBucketIndex(String key) {
93
- return Math.abs(key.hashCode()) % capacity;
94
- }
 
 
95
 
96
- public void put(String key, Parcel value) {
97
- int index = getBucketIndex(key);
98
- HashEntry head = buckets[index];
99
- while (head != null) {
100
- if (head.key.equals(key)) {
101
- head.value = value;
102
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  }
104
- head = head.next;
 
105
  }
106
- HashEntry newEntry = new HashEntry(key, value);
107
- newEntry.next = buckets[index];
108
- buckets[index] = newEntry;
109
  }
110
 
111
- public Parcel get(String key) {
112
- int index = getBucketIndex(key);
113
- HashEntry head = buckets[index];
114
- while (head != null) {
115
- if (head.key.equals(key)) return head.value;
116
- head = head.next;
 
 
 
117
  }
118
- return null;
119
- }
120
-
121
- public void printAll() {
122
- for (HashEntry head : buckets) {
123
- while (head != null) {
124
- System.out.println(" " + head.value);
125
- head = head.next;
 
 
126
  }
 
 
127
  }
128
  }
129
- }
130
-
131
- class ParcelTracker {
132
- ManualHashTable table = new ManualHashTable(32);
133
-
134
- public void track(Parcel p) {
135
- table.put(p.id, p);
136
- log("Tracking parcel: " + p);
137
- }
138
-
139
- public Parcel get(String id) {
140
- return table.get(id);
141
- }
142
 
143
- public void printAllTracked() {
144
- table.printAll();
145
- }
146
-
147
- private void log(String msg) {
148
- System.out.println("[Tracker Log] " + msg);
149
- }
150
- }
151
-
152
- // ------------------ CITY BST ------------------
153
- class CityBST {
154
- private class TreeNode {
155
- String cityName;
156
- List<Parcel> parcels;
157
- TreeNode left, right;
158
-
159
- TreeNode(String cityName) {
160
- this.cityName = cityName;
161
- this.parcels = new ArrayList<>();
162
- left = right = null;
163
  }
164
- }
165
-
166
- private TreeNode root;
167
-
168
- public CityBST() {
169
- root = null;
170
- }
171
-
172
- // Paketi BST'ye ekler
173
- public void addParcel(Parcel p) {
174
- root = insert(root, p);
175
- p.status = "Dispatched";
176
- }
177
 
178
- private TreeNode insert(TreeNode node, Parcel p) {
179
- if (node == null) {
180
- TreeNode newNode = new TreeNode(p.destination);
181
- newNode.parcels.add(p);
182
- return newNode;
183
  }
184
-
185
- int cmp = p.destination.compareToIgnoreCase(node.cityName);
186
- if (cmp < 0) {
187
- node.left = insert(node.left, p);
188
- } else if (cmp > 0) {
189
- node.right = insert(node.right, p);
190
- } else {
191
- node.parcels.add(p);
 
 
 
 
 
 
 
 
 
192
  }
193
- return node;
194
- }
195
-
196
- // Verilen şehirdeki paketleri döner (null değil, boş liste bile olabilir)
197
- public List<Parcel> getParcels(String city) {
198
- TreeNode node = search(root, city);
199
- if (node != null) return node.parcels;
200
- else return new ArrayList<>();
201
- }
202
-
203
- private TreeNode search(TreeNode node, String city) {
204
- if (node == null) return null;
205
- int cmp = city.compareToIgnoreCase(node.cityName);
206
- if (cmp == 0) return node;
207
- else if (cmp < 0) return search(node.left, city);
208
- else return search(node.right, city);
209
- }
210
-
211
- // Ağacı sıralı şekilde yazdırır
212
- public void printAllParcels() {
213
- System.out.println("City BST Parcel Distribution:");
214
- inOrder(root);
215
- }
216
-
217
- private void inOrder(TreeNode node) {
218
- if (node == null) return;
219
- inOrder(node.left);
220
- System.out.println("[" + node.cityName + "] (" + node.parcels.size() + " parcels)");
221
- for (Parcel p : node.parcels) {
222
- System.out.println(" → " + p);
223
  }
224
- inOrder(node.right);
225
- }
226
- }
227
-
228
- // ------------------ ROUTE ------------------
229
- class RouteNode {
230
- String location;
231
- RouteNode next;
232
-
233
- public RouteNode(String location) {
234
- this.location = location;
235
- }
236
- }
237
-
238
- class RouteCircularList {
239
- private RouteNode head = null;
240
- private RouteNode current = null;
241
- public int rotationInterval = 3;
242
-
243
- public void loadFromConfig(String filePath) {
244
- try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
245
- String line;
246
- RouteNode prev = null;
247
- while ((line = br.readLine()) != null) {
248
- line = line.trim();
249
- if (line.startsWith("interval=")) {
250
- rotationInterval = Integer.parseInt(line.split("=")[1].trim());
251
- continue;
252
- }
253
-
254
- if (line.isEmpty()) continue;
255
- RouteNode node = new RouteNode(line);
256
- if (head == null) head = node;
257
- else prev.next = node;
258
- prev = node;
259
  }
260
- if (prev != null) {
261
- prev.next = head;
262
- current = head;
263
- } else {
264
- System.out.println("[Route Log] No cities loaded in route.");
265
- head = null;
266
- current = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
  }
268
- } catch (IOException e) {
269
- System.out.println("[Route Log] Error reading config: " + e.getMessage());
270
- head = null;
271
- current = null;
272
  }
273
  }
274
 
275
- public boolean isLoaded() {
276
- return head != null && current != null;
277
- }
278
-
279
- public void rotateAndLogDeliveries() {
280
- if (current == null) {
281
- System.out.println("[Route Log] No route loaded.");
282
- return;
283
  }
284
-
285
- for (int i = 0; i < rotationInterval; i++) {
286
- System.out.println("[Route Log] Delivering to: " + current.location);
287
- current = current.next;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  }
289
-
290
- System.out.println("[Route Log] Active terminal: " + current.location);
291
  }
292
 
293
- public String getCurrentLocation() {
294
- return current != null ? current.location : null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  }
296
- }
297
 
298
- // ------------------ MAIN SIMULATION ------------------
299
- public class ParcelSortX {
300
- private static int randomParcelPerTick = 2;
301
-
302
- private static int totalGenerated = 0;
303
- private static int totalDispatched = 0;
304
- private static int totalReturned = 0;
305
-
306
- private static void log(String msg) {
307
- System.out.println("[Main Log] " + msg);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  }
309
 
310
- private static String[] possibleCities = {"Istanbul", "Ankara", "Izmir", "Bursa"};
311
-
312
- private static Parcel generateRandomParcel(int tick, int idSuffix) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  Random rand = new Random();
314
- String id = "P" + tick + String.format("%02d", idSuffix);
315
- String dest = possibleCities[rand.nextInt(possibleCities.length)];
316
- int priority = rand.nextInt(3) + 1;
317
- totalGenerated++;
318
- return new Parcel(id, dest, priority, tick);
319
- }
320
-
321
- public static void loadGlobalConfig(String filePath) {
322
- try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
323
- String line;
324
- while ((line = br.readLine()) != null) {
325
- if (line.startsWith("randomParcelPerTick=")) {
326
- randomParcelPerTick = Integer.parseInt(line.split("=")[1].trim());
327
- }
328
- }
329
  } catch (IOException e) {
330
- System.out.println("[Config Log] Error reading config: " + e.getMessage());
331
  }
332
- }
333
-
334
- public static void main(String[] args) {
335
 
336
- loadGlobalConfig("config.txt");
337
-
338
- ParcelQueue incoming = new ParcelQueue();
339
- ParcelStack sortingStack = new ParcelStack();
340
- CityBST cityBST = new CityBST();
341
- ParcelTracker tracker = new ParcelTracker();
342
- RouteCircularList route = new RouteCircularList();
343
- route.loadFromConfig("route_config.txt");
344
-
345
- int maxTick = 10;
346
-
347
- for (int tick = 1; tick <= maxTick; tick++) {
348
- log("Tick " + tick + " started");
349
-
350
- // 1) Yeni rastgele paket üret
351
- for (int i = 0; i < randomParcelPerTick; i++) {
352
- Parcel p = generateRandomParcel(tick, i);
353
- incoming.enqueue(p);
354
- tracker.track(p);
355
- log("Generated and queued: " + p);
356
  }
357
-
358
- // 2) Gelen kuyruktan stack'e aktar (sıraya göre)
359
- while (!incoming.isEmpty()) {
360
- Parcel p = incoming.dequeue();
361
- sortingStack.push(p);
362
- log("Moved from queue to stack: " + p);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
  }
364
 
365
- // 3) Stack'ten paketleri işleyip şehirlere dağıt (BST'ye ekle)
366
- while (!sortingStack.isEmpty()) {
367
- Parcel p = sortingStack.pop();
368
-
369
- // Eğer iade sayısı 3 veya üstü ise paket sistemden atılır
370
- if (p.returnCount >= 3) {
371
- log("Discarding parcel due to too many returns: " + p);
372
- continue;
 
 
 
 
 
373
  }
 
 
374
 
375
- cityBST.addParcel(p);
376
- totalDispatched++;
377
- log("Dispatched parcel to BST city: " + p);
378
  }
379
 
380
- // 4) Rotasyonu yap ve aktif terminali yazdır
381
- if (route.isLoaded()) {
382
- route.rotateAndLogDeliveries();
383
- } else {
384
- log("No delivery route loaded.");
 
 
 
 
 
 
385
  }
386
 
387
- // 5) Örnek: 1 paket iade edelim (demo amaçlı)
388
- // Normalde iade mantığı daha kapsamlı olabilir
389
- if (tick % 4 == 0) { // 4. tickte iade testi
390
- Parcel someParcel = new Parcel("ReturnedP" + tick, "Ankara", 2, tick);
391
- someParcel.returnCount++;
392
- someParcel.status = "Returned";
393
- sortingStack.push(someParcel);
394
- totalReturned++;
395
- log("Demo: Parcel returned and pushed back to stack: " + someParcel);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
396
  }
 
 
397
 
398
- log("Tick " + tick + " ended\n");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  }
400
 
401
- // Son rapor
402
- System.out.println("\n===== FINAL REPORT =====");
403
- System.out.println("Total parcels generated: " + totalGenerated);
404
- System.out.println("Total parcels dispatched: " + totalDispatched);
405
- System.out.println("Total parcels returned: " + totalReturned);
406
- cityBST.printAllParcels();
407
- tracker.printAllTracked();
408
  }
 
 
409
  }
 
3
  import java.io.*;
4
  import java.util.*;
5
 
6
+ public class ParcelSortX {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
+ // --- ENUMS & PARCEL CLASS ---
9
+ public enum ParcelStatus { InQueue, Sorted, Dispatched, Returned }
10
+
11
+ public static class Parcel {
12
+ public String parcelID;
13
+ public String destinationCity;
14
+ public int priority;
15
+ public String size;
16
+ public int arrivalTick;
17
+ public int returnCount;
18
+ public int dispatchTick = -1;
19
+ public ParcelStatus status;
20
+
21
+ public Parcel(String id, String city, int prio, String sz, int tick) {
22
+ this.parcelID = id;
23
+ this.destinationCity = city;
24
+ this.priority = prio;
25
+ this.size = sz;
26
+ this.arrivalTick = tick;
27
+ this.returnCount = 0;
28
+ this.status = ParcelStatus.InQueue;
29
+ }
30
+ @Override
31
+ public String toString() {
32
+ return "[" + parcelID + ", Dest: " + destinationCity + ", Priority: " + priority +
33
+ ", Size: " + size + ", ArrivalTick: " + arrivalTick + ", ReturnCount: " + returnCount +
34
+ ", Status: " + status + "]";
35
+ }
36
  }
37
 
38
+ // --- QUEUE (ArrivalBuffer) ---
39
+ public static class ParcelQueue {
40
+ public final Parcel[] arr;
41
+ public final int capacity;
42
+ public int front, rear, count;
43
 
44
+ public ParcelQueue(int capacity) {
45
+ this.capacity = capacity;
46
+ arr = new Parcel[capacity];
47
+ front = 0;
48
+ rear = -1;
49
+ count = 0;
50
+ }
51
+ public boolean enqueue(Parcel p) {
52
+ if (isFull()) return false;
53
+ rear = (rear + 1) % capacity;
54
+ arr[rear] = p;
55
+ count++;
56
+ return true;
57
+ }
58
+ public Parcel dequeue() {
59
+ if (isEmpty()) return null;
60
+ Parcel p = arr[front];
61
+ arr[front] = null;
62
+ front = (front + 1) % capacity;
63
+ count--;
64
+ return p;
65
+ }
66
+ public Parcel peek() {
67
+ if (isEmpty()) return null;
68
+ return arr[front];
69
+ }
70
+ public boolean isFull() { return count == capacity; }
71
+ public boolean isEmpty() { return count == 0; }
72
+ public int size() { return count; }
73
+ public String asciiView() {
74
+ StringBuilder sb = new StringBuilder("ArrivalBuffer [");
75
+ for (int i = 0, idx = front; i < count; i++, idx = (idx+1)%capacity) {
76
+ sb.append(arr[idx].parcelID);
77
+ if (i < count-1) sb.append(" ");
78
  }
79
+ sb.append("]");
80
+ return sb.toString();
81
  }
 
 
 
82
  }
83
 
84
+ // --- STACK (ReturnStack) ---
85
+ public static class ParcelStack {
86
+ public static class Node { public Parcel p; public Node next; public Node(Parcel p, Node n) {this.p=p;this.next=n;} }
87
+ public Node top;
88
+ public int count = 0;
89
+ public void push(Parcel p) { top = new Node(p, top); count++; }
90
+ public Parcel pop() {
91
+ if (isEmpty()) return null;
92
+ Parcel ret = top.p; top = top.next; count--; return ret;
93
  }
94
+ public Parcel peek() { return isEmpty() ? null : top.p; }
95
+ public boolean isEmpty() { return top == null; }
96
+ public int size() { return count; }
97
+ public String asciiView() {
98
+ StringBuilder sb = new StringBuilder("ReturnStack(top->) [");
99
+ Node n = top;
100
+ while (n != null) {
101
+ sb.append(n.p.parcelID);
102
+ if (n.next != null) sb.append(" ");
103
+ n = n.next;
104
  }
105
+ sb.append("]");
106
+ return sb.toString();
107
  }
108
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
+ // --- BST (DestinationSorter) ---
111
+ public static class CityAVL {
112
+ public static class Node {
113
+ public String cityName;
114
+ public Queue<Parcel> parcels = new LinkedList<>();
115
+ public Node left, right;
116
+ public int height;
117
+ public Node(String city) {cityName=city; height=1;}
 
 
 
 
 
 
 
 
 
 
 
 
118
  }
119
+ public Node root;
 
 
 
 
 
 
 
 
 
 
 
 
120
 
121
+ public void insertParcel(Parcel p) {
122
+ root = insert(root, p);
 
 
 
123
  }
124
+ private Node insert(Node node, Parcel p) {
125
+ if (node==null) { Node n=new Node(p.destinationCity); n.parcels.offer(p); return n; }
126
+ int cmp = p.destinationCity.compareToIgnoreCase(node.cityName);
127
+ if (cmp<0) node.left = insert(node.left, p);
128
+ else if (cmp>0) node.right = insert(node.right, p);
129
+ else node.parcels.offer(p);
130
+ node.height = 1 + Math.max(getHeight(node.left), getHeight(node.right));
131
+ int balance = getBalance(node);
132
+ if (balance > 1 && p.destinationCity.compareToIgnoreCase(node.left.cityName) < 0) return rightRotate(node);
133
+ if (balance < -1 && p.destinationCity.compareToIgnoreCase(node.right.cityName) > 0) return leftRotate(node);
134
+ if (balance > 1 && p.destinationCity.compareToIgnoreCase(node.left.cityName) > 0) {
135
+ node.left = leftRotate(node.left); return rightRotate(node);
136
+ }
137
+ if (balance < -1 && p.destinationCity.compareToIgnoreCase(node.right.cityName) < 0) {
138
+ node.right = rightRotate(node.right); return leftRotate(node);
139
+ }
140
+ return node;
141
  }
142
+ private int getHeight(Node n) { return n==null ? 0 : n.height; }
143
+ private int getBalance(Node n) { return n==null ? 0 : getHeight(n.left) - getHeight(n.right); }
144
+ private Node rightRotate(Node y) {
145
+ Node x = y.left; Node T2 = x.right;
146
+ x.right = y; y.left = T2;
147
+ y.height = 1 + Math.max(getHeight(y.left), getHeight(y.right));
148
+ x.height = 1 + Math.max(getHeight(x.left), getHeight(x.right));
149
+ return x;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  }
151
+ private Node leftRotate(Node x) {
152
+ Node y = x.right; Node T2 = y.left;
153
+ y.left = x; x.right = T2;
154
+ x.height = 1 + Math.max(getHeight(x.left), getHeight(x.right));
155
+ y.height = 1 + Math.max(getHeight(y.left), getHeight(y.right));
156
+ return y;
157
+ }
158
+ public Parcel removeParcelWithPriority(String city) {
159
+ Node node = root;
160
+ while (node != null) {
161
+ int cmp = city.compareToIgnoreCase(node.cityName);
162
+ if (cmp == 0) {
163
+ Parcel maxP = null;
164
+ for (Parcel p : node.parcels)
165
+ if (maxP == null || p.priority > maxP.priority)
166
+ maxP = p;
167
+ if (maxP != null) node.parcels.remove(maxP);
168
+ return maxP;
169
+ } else if (cmp < 0) node = node.left;
170
+ else node = node.right;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  }
172
+ return null;
173
+ }
174
+ public void inOrderTraversal(Map<String,Integer> cityCounts) {
175
+ inOrder(root, cityCounts);
176
+ }
177
+ private void inOrder(Node node, Map<String,Integer> cityCounts) {
178
+ if (node==null) return;
179
+ inOrder(node.left, cityCounts);
180
+ cityCounts.put(node.cityName, node.parcels.size());
181
+ inOrder(node.right, cityCounts);
182
+ }
183
+ public Map<String,List<Parcel>> getAllCityParcels() {
184
+ Map<String,List<Parcel>> map = new TreeMap<>();
185
+ collect(root, map);
186
+ return map;
187
+ }
188
+ private void collect(Node node, Map<String,List<Parcel>> map) {
189
+ if (node==null) return;
190
+ collect(node.left, map);
191
+ map.put(node.cityName, new ArrayList<>(node.parcels));
192
+ collect(node.right, map);
193
+ }
194
+ public String asciiView() {
195
+ StringBuilder sb = new StringBuilder("BST:\n");
196
+ asciiBSTTreeStyle(root, sb, "", true);
197
+ return sb.toString();
198
+ }
199
+ private void asciiBSTTreeStyle(Node node, StringBuilder sb, String prefix, boolean isTail) {
200
+ if (node == null) return;
201
+ sb.append(prefix)
202
+ .append(isTail ? "└── " : "├── ")
203
+ .append(node.cityName)
204
+ .append(" (").append(node.parcels.size()).append(")\n");
205
+ List<Node> children = new ArrayList<>();
206
+ if (node.left != null) children.add(node.left);
207
+ if (node.right != null) children.add(node.right);
208
+ for (int i = 0; i < children.size(); i++) {
209
+ asciiBSTTreeStyle(
210
+ children.get(i),
211
+ sb,
212
+ prefix + (isTail ? " " : "│ "),
213
+ i == children.size() - 1
214
+ );
215
  }
 
 
 
 
216
  }
217
  }
218
 
219
+ // --- HASH TABLE (ParcelTracker) ---
220
+ public static class ParcelTracker {
221
+ public static class Entry {
222
+ public String key; public Parcel value; public Entry next;
223
+ public Entry(String k, Parcel v, Entry n) { key=k; value=v; next=n; }
 
 
 
224
  }
225
+ public Entry[] table;
226
+ public int size, capacity;
227
+ public ParcelTracker(int cap) {
228
+ capacity=cap; table=new Entry[capacity]; size=0;
229
+ }
230
+ private int hash(String k) { return Math.abs(k.hashCode())%capacity; }
231
+ public void insert(Parcel p) {
232
+ int idx = hash(p.parcelID);
233
+ Entry e = table[idx];
234
+ while (e!=null) { if (e.key.equals(p.parcelID)) return; e=e.next; }
235
+ table[idx] = new Entry(p.parcelID, p, table[idx]);
236
+ size++;
237
+ }
238
+ public boolean exists(String k) {
239
+ int idx=hash(k); Entry e=table[idx];
240
+ while (e!=null) { if (e.key.equals(k)) return true; e=e.next; }
241
+ return false;
242
+ }
243
+ public Parcel get(String k) {
244
+ int idx=hash(k); Entry e=table[idx];
245
+ while (e!=null) { if (e.key.equals(k)) return e.value; e=e.next; }
246
+ return null;
247
+ }
248
+ public void updateStatus(String k, ParcelStatus s) {
249
+ Parcel p = get(k); if (p!=null) p.status=s;
250
+ }
251
+ public void incrementReturnCount(String k) {
252
+ Parcel p = get(k); if (p!=null) p.returnCount++;
253
+ }
254
+ public double loadFactor() { return (double)size/capacity; }
255
+ public List<Parcel> allParcels() {
256
+ List<Parcel> ret = new ArrayList<>();
257
+ for (Entry e : table) for (;e!=null;e=e.next) ret.add(e.value);
258
+ return ret;
259
  }
 
 
260
  }
261
 
262
+ // --- CIRCULAR LINKED LIST (TerminalRotator) ---
263
+ public static class TerminalRotator {
264
+ public static class Node { public String city; public Node next; public Node(String c) {city=c;} }
265
+ public Node head, current;
266
+ public int interval;
267
+ public TerminalRotator(String[] cities, int interval) {
268
+ this.interval = interval;
269
+ Node prev=null; for (String c : cities) {
270
+ Node n = new Node(c.trim());
271
+ if (head==null) head=n;
272
+ else prev.next=n;
273
+ prev=n;
274
+ }
275
+ if (prev!=null) prev.next=head;
276
+ current=head;
277
+ }
278
+ public void advance() { current=current.next; }
279
+ public String getActive() { return current.city; }
280
+ public int getInterval() { return interval; }
281
+ public List<String> getAllCities() {
282
+ List<String> list=new ArrayList<>();
283
+ Node n=head; do { list.add(n.city); n=n.next; } while (n!=head);
284
+ return list;
285
+ }
286
  }
 
287
 
288
+ // --- CONFIG READ ---
289
+ public static class Config {
290
+ public int MAX_TICKS=30, QUEUE_CAPACITY=20, ROT_INTERVAL=5, HASH_CAP=64;
291
+ public int PARCEL_MIN=1, PARCEL_MAX=3;
292
+ public double MISROUTING_RATE=0.1;
293
+ public String[] CITIES = {"Istanbul","Ankara","Izmir","Bursa"};
294
+ public static Config read(String fname) {
295
+ Config c = new Config();
296
+ try (BufferedReader br=new BufferedReader(new FileReader(fname))) {
297
+ String l; while ((l=br.readLine())!=null) {
298
+ l=l.trim(); if (l.isEmpty()||l.startsWith("#")) continue;
299
+ String[] p=l.split("=");
300
+ if (p.length<2) continue;
301
+ String k=p[0].trim().toUpperCase(), v=p[1].trim();
302
+ switch (k) {
303
+ case "MAX TICKS": c.MAX_TICKS=Integer.parseInt(v); break;
304
+ case "QUEUE CAPACITY": c.QUEUE_CAPACITY=Integer.parseInt(v); break;
305
+ case "TERMINAL ROTATION INTERVAL": c.ROT_INTERVAL=Integer.parseInt(v); break;
306
+ case "PARCEL PER TICK MIN": c.PARCEL_MIN=Integer.parseInt(v); break;
307
+ case "PARCEL PER TICK MAX": c.PARCEL_MAX=Integer.parseInt(v); break;
308
+ case "MISROUTING RATE": c.MISROUTING_RATE=Double.parseDouble(v); break;
309
+ case "CITY LIST": c.CITIES=Arrays.stream(v.split(",")).map(String::trim).toArray(String[]::new); break;
310
+ }
311
+ }
312
+ } catch (Exception e) {}
313
+ return c;
314
+ }
315
  }
316
 
317
+ // --- STATICS FOR GUI PANEL ---
318
+ public static ParcelQueue currentQueue;
319
+ public static ParcelStack currentStack;
320
+ public static CityAVL currentBST;
321
+
322
+ // --- SIMULATION ENGINE ---
323
+ static int totalDispatched = 0, totalReturned = 0;
324
+ static int maxQueue = 0, maxStack = 0, finalTick = 0;
325
+ static CityAVL bstForReport;
326
+ static ParcelTracker trackerForReport;
327
+ static Config configForReport;
328
+
329
+ public static void runSimulation(Appender appender) {
330
+ Config cfg = Config.read("config.txt");
331
+ configForReport = cfg;
332
+ ParcelQueue queue = new ParcelQueue(cfg.QUEUE_CAPACITY);
333
+ ParcelStack stack = new ParcelStack();
334
+ CityAVL bst = new CityAVL();
335
+ ParcelTracker tracker = new ParcelTracker(cfg.HASH_CAP);
336
+ bstForReport = bst;
337
+ trackerForReport = tracker;
338
+ TerminalRotator rotator = new TerminalRotator(cfg.CITIES, cfg.ROT_INTERVAL);
339
  Random rand = new Random();
340
+ currentQueue = queue;
341
+ currentStack = stack;
342
+ currentBST = bst;
343
+ totalDispatched = 0;
344
+ totalReturned = 0;
345
+ maxQueue = 0;
346
+ maxStack = 0;
347
+ finalTick = 0;
348
+ int tick = 0;
349
+
350
+ PrintWriter logWriter = null;
351
+ try {
352
+ logWriter = new PrintWriter(new FileWriter("log.txt", false));
 
 
353
  } catch (IOException e) {
354
+ e.printStackTrace();
355
  }
 
 
 
356
 
357
+ for (tick=1; tick<=cfg.MAX_TICKS; tick++) {
358
+ StringBuilder tickLog = new StringBuilder();
359
+ tickLog.append("[Tick ").append(tick).append("]").append(System.lineSeparator());
360
+
361
+ tickLog.append("New Parcels: ");
362
+ int n = cfg.PARCEL_MIN + rand.nextInt(cfg.PARCEL_MAX-cfg.PARCEL_MIN+1);
363
+ List<String> createdParcels = new ArrayList<>();
364
+ for (int i=0; i<n; i++) {
365
+ String pid = "P" + tick + "_" + i;
366
+ String city = cfg.CITIES[rand.nextInt(cfg.CITIES.length)];
367
+ int prio = 1+rand.nextInt(3);
368
+ String size = rand.nextBoolean() ? "Small" : (rand.nextBoolean() ? "Medium" : "Large");
369
+ Parcel p = new Parcel(pid, city, prio, size, tick);
370
+ if (!queue.enqueue(p)) {
371
+ tickLog.append("[OVERFLOW: ").append(p.parcelID).append("->").append(p.destinationCity).append("] ");
372
+ } else {
373
+ tracker.insert(p);
374
+ createdParcels.add(p.parcelID + " to " + p.destinationCity + " (Priority " + p.priority + ")");
375
+ }
 
376
  }
377
+ tickLog.append(String.join(", ", createdParcels)).append(System.lineSeparator());
378
+
379
+ maxQueue = Math.max(maxQueue, queue.size());
380
+ tickLog.append("Queue Size: ").append(queue.size()).append(System.lineSeparator());
381
+
382
+ List<String> sortedParcels = new ArrayList<>();
383
+ while (!queue.isEmpty()) {
384
+ Parcel p = queue.dequeue();
385
+ p.status = ParcelStatus.Sorted;
386
+ bst.insertParcel(p);
387
+ tracker.updateStatus(p.parcelID, ParcelStatus.Sorted);
388
+ sortedParcels.add(p.parcelID);
389
+ }
390
+ tickLog.append("Sorted to BST: ").append(String.join(", ", sortedParcels)).append(System.lineSeparator());
391
+
392
+ String active = rotator.getActive();
393
+ Parcel disp = bst.removeParcelWithPriority(active);
394
+ if (disp != null) {
395
+ if (rand.nextDouble() < cfg.MISROUTING_RATE) {
396
+ disp.status = ParcelStatus.Returned;
397
+ disp.returnCount++;
398
+ stack.push(disp);
399
+ tracker.updateStatus(disp.parcelID, ParcelStatus.Returned);
400
+ tracker.incrementReturnCount(disp.parcelID);
401
+ tickLog.append("Returned: ").append(disp.parcelID).append(" misrouted -> Pushed to ReturnStack").append(System.lineSeparator());
402
+ totalReturned++;
403
+ } else {
404
+ disp.status = ParcelStatus.Dispatched;
405
+ disp.dispatchTick = tick;
406
+ tracker.updateStatus(disp.parcelID, ParcelStatus.Dispatched);
407
+ tickLog.append("Dispatched: ").append(disp.parcelID).append(" from BST to ").append(active).append(" -> Success").append(System.lineSeparator());
408
+ totalDispatched++;
409
+ }
410
+ } else {
411
+ tickLog.append("Dispatched: No parcels for active terminal ").append(active).append(System.lineSeparator());
412
  }
413
 
414
+ if (tick%3==0) {
415
+ int reproc=0;
416
+ while (!stack.isEmpty() && reproc<2) {
417
+ Parcel ret = stack.pop();
418
+ if (ret.returnCount<3) {
419
+ ret.status = ParcelStatus.Sorted;
420
+ bst.insertParcel(ret);
421
+ tracker.updateStatus(ret.parcelID, ParcelStatus.Sorted);
422
+ tickLog.append("Reprocess: Returned parcel reprocessed: ").append(ret.parcelID).append(System.lineSeparator());
423
+ } else {
424
+ tickLog.append("Discarded: Parcel ").append(ret.parcelID).append(" discarded due to excessive returns.").append(System.lineSeparator());
425
+ }
426
+ reproc++;
427
  }
428
+ }
429
+ maxStack = Math.max(maxStack, stack.size());
430
 
431
+ if (tick % cfg.ROT_INTERVAL == 0) {
432
+ rotator.advance();
433
+ tickLog.append("Rotated to: ").append(rotator.getActive()).append(System.lineSeparator());
434
  }
435
 
436
+ Map<String,Integer> cityCounts = new TreeMap<>();
437
+ bst.inOrderTraversal(cityCounts);
438
+ tickLog.append("BST city parcels: ").append(cityCounts).append(System.lineSeparator());
439
+ tickLog.append("ReturnStack Size: ").append(stack.size()).append(System.lineSeparator());
440
+ tickLog.append(queue.asciiView()).append(System.lineSeparator());
441
+ tickLog.append(stack.asciiView()).append(System.lineSeparator());
442
+ tickLog.append(bst.asciiView()).append(System.lineSeparator());
443
+
444
+ if (logWriter != null) {
445
+ logWriter.println(tickLog.toString());
446
+ logWriter.flush();
447
  }
448
 
449
+ StringBuilder guiTickHtml = new StringBuilder();
450
+ guiTickHtml.append("<hr><b>• Tick " + tick + "</b><br>");
451
+ guiTickHtml.append("<table border='1' cellspacing='0' cellpadding='4' style='border-collapse:collapse; font-size:14px; width:100%;'>");
452
+ guiTickHtml.append("<tr><th>Event</th><th>Parcel</th></tr>");
453
+ if (!createdParcels.isEmpty())
454
+ guiTickHtml.append("<tr><td><font color='#ffd600'>📦 New Parcel</font></td><td>").append(String.join(", ", createdParcels)).append("</td></tr>");
455
+ guiTickHtml.append("<tr><td><font color='#90caf9'>🚚 Dispatch</font></td><td>").append((disp!=null?disp.parcelID:"-")).append("</td></tr>");
456
+ guiTickHtml.append("</table>");
457
+ guiTickHtml.append("<div style='margin:4px 0 12px 0;'><b>Queue size:</b> "+queue.size()+", <b>Stack size:</b> "+stack.size()+", <b>BST city parcels:</b> "+cityCounts+"</div>");
458
+ guiTickHtml.append("<div style='border:1px solid #444;background:#23272a;border-radius:7px;margin:10px 0 18px 0;'>"
459
+ + "<div style='padding:7px 0 2px 12px;color:#ffd600;font-size:13px;font-family:Segoe UI,Arial,sans-serif;font-weight:bold;'>Data Structures (ASCII):</div>"
460
+ + "<pre style='margin:0;padding:7px 12px 7px 16px;background:transparent;color:#b9f6ca;font-family:Courier New,monospace;font-size:12px;'>"
461
+ + queue.asciiView() + "\n"
462
+ + stack.asciiView() + "\n"
463
+ + bst.asciiView()
464
+ + "</pre></div>");
465
+ appender.append(guiTickHtml.toString());
466
+ }
467
+
468
+ if (logWriter != null) logWriter.close();
469
+ finalTick = tick-1;
470
+ writeReportTxt(getFinalReportHtml());
471
+ }
472
+
473
+ private static String stripHtmlForReport(String html) {
474
+ html = html.replaceAll("(?s)<style.*?>.*?</style>", "");
475
+ html = html.replaceAll("(?i)<br */?>", "\n");
476
+ html = html.replaceAll("(?i)<hr */?>", "\n------------------------------\n");
477
+ html = html.replaceAll("(?i)</?(div|tr|h[1-6])[^>]*>", "\n");
478
+ html = html.replaceAll("(?i)</?(td|th)[^>]*>", "\t");
479
+ html = html.replaceAll("(?i)</?table[^>]*>", "\n");
480
+ html = html.replaceAll("(?i)</?(span|b|font|pre|strong)[^>]*>", "");
481
+ html = html.replaceAll("<[^>]+>", "");
482
+ html = html.replace("&nbsp;", " ");
483
+ html = html.replace("&lt;", "<").replace("&gt;", ">").replace("&amp;", "&");
484
+ html = html.replaceAll("[ \\t]+", " ");
485
+ html = html.replaceAll(" *\n *", "\n");
486
+ html = html.replaceAll("\n{2,}", "\n\n");
487
+ return html.trim();
488
+ }
489
+
490
+ public static void writeReportTxt(String html) {
491
+ try (PrintWriter reportWriter = new PrintWriter(new FileWriter("report.txt", false))) {
492
+ reportWriter.println(stripHtmlForReport(html));
493
+ } catch (IOException e) {
494
+ e.printStackTrace();
495
+ }
496
+ }
497
+
498
+ // --------- FINAL HTML REPORT ---------
499
+
500
+ public static String getFinalReportHtml() {
501
+ StringBuilder htmlBuilder = new StringBuilder();
502
+ htmlBuilder.append("<html><head><style>")
503
+ .append("body{font-family:'Segoe UI','Roboto',Arial,sans-serif;background:#f5f5f5;}")
504
+ .append(".fancy-table{border-radius:12px;box-shadow:0 2px 18px 0 #e0e0e0;background:#fff;overflow:hidden;border-collapse:separate;border-spacing:0;margin:10px 0 24px 0;}")
505
+ .append(".fancy-table th,.fancy-table td{padding:10px 16px;text-align:left;}")
506
+ .append(".fancy-table th{background:#f1f8e9;color:#388e3c;font-size:16px;}")
507
+ .append(".fancy-table tr{transition:background 0.2s;}")
508
+ .append(".fancy-table tr:hover{background:#f9fbe7;}")
509
+ .append(".fancy-table td{border-bottom:1px solid #e0e0e0;font-size:15px;}")
510
+ .append(".fancy-table tr:last-child td{border-bottom:none;}")
511
+ .append(".stat-card{background:#e3f2fd;border-radius:12px;padding:18px 40px;min-width:130px;text-align:center;display:inline-block;margin:0 8px;}")
512
+ .append(".stat-card-title{color:#1976d2;font-size:15px;}")
513
+ .append(".stat-card-value{font-size:22px;font-weight:bold;}")
514
+ .append(".stat-card-green{background:#e8f5e9;}.stat-card-yellow{background:#fffde7;}")
515
+ .append(".stat-card-green .stat-card-title{color:#388e3c;}.stat-card-green .stat-card-value{color:#388e3c;}")
516
+ .append(".stat-card-yellow .stat-card-title{color:#fbc02d;}.stat-card-yellow .stat-card-value{color:#fbc02d;}")
517
+ .append(".badge{display:inline-block;background:#1976d2;color:#fff;padding:3px 12px;border-radius:10px;font-size:13px;}")
518
+ .append("</style></head><body>");
519
+
520
+ htmlBuilder.append("<div style=\"background:#43a047;color:#fff;padding:18px 0;font-size:26px;text-align:center;border-radius:12px 12px 0 0;font-weight:bold;letter-spacing:2px;box-shadow:0 4px 16px #e0e0e0;\">")
521
+ .append("<span style=\"font-size:28px;vertical-align:middle;\">📄</span> ")
522
+ .append("<span style=\"vertical-align:middle;\">Final Simulation Report</span></div>");
523
+ htmlBuilder.append("<div style=\"padding:24px;\">");
524
+
525
+ htmlBuilder.append("<div style=\"text-align:center;margin:12px 0;\">")
526
+ .append("<span class=\"stat-card\"><div class=\"stat-card-title\">Ticks</div><div class=\"stat-card-value\">").append(finalTick).append("</div></span>")
527
+ .append("<span class=\"stat-card\"><div class=\"stat-card-title\">Dispatched</div><div class=\"stat-card-value\">").append(totalDispatched).append("</div></span>")
528
+ .append("<span class=\"stat-card stat-card-yellow\"><div class=\"stat-card-title\">Returned</div><div class=\"stat-card-value\">").append(totalReturned).append("</div></span>")
529
+ .append("<span class=\"stat-card stat-card-green\"><div class=\"stat-card-title\">Max Queue</div><div class=\"stat-card-value\">").append(maxQueue).append("</div></span>")
530
+ .append("<span class=\"stat-card stat-card-green\"><div class=\"stat-card-title\">Max Stack</div><div class=\"stat-card-value\">").append(maxStack).append("</div></span>")
531
+ .append("</div>");
532
+
533
+ if (trackerForReport != null) {
534
+ List<Parcel> allParcels = trackerForReport.allParcels();
535
+ htmlBuilder.append("<h2 style=\"color:#1976d2;\">📦 All Tracked Parcels <span style='font-size:18px;color:#888;'>(")
536
+ .append(allParcels.size()).append(" total)</span></h2>");
537
+ htmlBuilder.append("<div style='max-height:220px;overflow:auto;border:1px solid #e0e0e0;border-radius:6px;'>");
538
+ htmlBuilder.append("<table class=\"fancy-table\">")
539
+ .append("<tr><th>ID</th><th>Destination</th><th>Priority</th><th>Size</th><th>Tick</th><th>Returns</th><th>Status</th></tr>");
540
+ for (Parcel p : allParcels) {
541
+ String statusColor = (p.status==ParcelStatus.Dispatched) ? "#4CAF50" :
542
+ (p.status==ParcelStatus.Returned) ? "#FFD600" : "#E57373";
543
+ String priorityColor = p.priority == 1 ? "#e57373" :
544
+ p.priority == 2 ? "#ffd600" : "#4caf50";
545
+ htmlBuilder.append("<tr>")
546
+ .append("<td>").append(p.parcelID).append("</td>")
547
+ .append("<td>").append(p.destinationCity).append("</td>")
548
+ .append("<td><span class=\"badge\" style=\"background:").append(priorityColor).append(";\">").append(p.priority).append("</span></td>")
549
+ .append("<td>").append(p.size).append("</td>")
550
+ .append("<td>").append(p.arrivalTick).append("</td>")
551
+ .append("<td>").append(p.returnCount).append("</td>")
552
+ .append("<td><span class=\"badge\" style=\"background:").append(statusColor).append(";\">").append(p.status).append("</span></td>")
553
+ .append("</tr>");
554
  }
555
+ htmlBuilder.append("</table></div>");
556
+ }
557
 
558
+ if (bstForReport != null) {
559
+ Map<String, List<Parcel>> cityParcels = bstForReport.getAllCityParcels();
560
+ htmlBuilder.append("<h2 style=\"color:#2196f3;\">🏙️ City-Wise Parcel Distribution</h2>");
561
+ for (Map.Entry<String, List<Parcel>> entry : cityParcels.entrySet()) {
562
+ String city = entry.getKey();
563
+ List<Parcel> parcels = entry.getValue();
564
+
565
+ htmlBuilder.append("<div style='margin:16px 0 10px 0;'>")
566
+ .append("<span style='background:#1976d2;color:#fff;padding:6px 24px;border-radius:16px;font-weight:bold;font-size:18px;letter-spacing:1.5px;'>")
567
+ .append(city.toUpperCase()).append(" <span style='color:#FFD600;font-size:13px;'>(").append(parcels.size()).append(" parcels)</span></span></div>");
568
+ htmlBuilder.append("<table class=\"fancy-table\">")
569
+ .append("<tr><th>ID</th><th>Priority</th><th>Size</th><th>Tick</th><th>Returns</th></tr>");
570
+ parcels.sort((p1, p2) -> {
571
+ if (p1.priority != p2.priority) return Integer.compare(p1.priority, p2.priority);
572
+ return Integer.compare(p1.arrivalTick, p2.arrivalTick);
573
+ });
574
+ for (Parcel p : parcels) {
575
+ String priorityColor = p.priority == 1 ? "#e57373" :
576
+ p.priority == 2 ? "#ffd600" : "#4caf50";
577
+ htmlBuilder.append("<tr>")
578
+ .append("<td>").append(p.parcelID).append("</td>")
579
+ .append("<td><span class=\"badge\" style=\"background:").append(priorityColor).append(";\">").append(p.priority).append("</span></td>")
580
+ .append("<td>").append(p.size).append("</td>")
581
+ .append("<td>").append(p.arrivalTick).append("</td>")
582
+ .append("<td>").append(p.returnCount).append("</td>")
583
+ .append("</tr>");
584
+ }
585
+ htmlBuilder.append("</table>");
586
+ }
587
  }
588
 
589
+ htmlBuilder.append("<div style='margin:20px 0 10px 0;text-align:center;'><span style='background:#4CAF50;color:#fff;padding:8px 36px;border-radius:18px;font-size:16px;'>✅ Report generated successfully!</span></div>");
590
+ htmlBuilder.append("</div></body></html>");
591
+ return htmlBuilder.toString();
 
 
 
 
592
  }
593
+
594
+ public interface Appender { void append(String text); }
595
  }
src/src/ParcelSortXGUI.java CHANGED
@@ -1,4 +1,229 @@
1
  package src;
2
 
3
- public class ParcelSortXGUI {
4
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  package src;
2
 
3
+ import javax.swing.*;
4
+ import java.awt.*;
5
+
6
+ public class ParcelSortXGUI extends JFrame {
7
+ private JTextPane textPane;
8
+ private JButton startButton;
9
+ private JButton reportButton;
10
+ private StringBuilder htmlContent;
11
+ private boolean simulationCompleted = false;
12
+ private JPanel buttonPanel;
13
+
14
+ public ParcelSortXGUI() {
15
+ setTitle("ParcelSortX Simulation");
16
+ setSize(900, 700);
17
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
18
+ setLocationRelativeTo(null);
19
+
20
+ JLabel title = new JLabel("\uD83D\uDCE6 ParcelSortX Simulator", SwingConstants.CENTER);
21
+ title.setFont(new Font("Segoe UI", Font.BOLD, 24));
22
+ title.setOpaque(true);
23
+ title.setBackground(new Color(38, 50, 56));
24
+ title.setForeground(Color.WHITE);
25
+ title.setBorder(BorderFactory.createEmptyBorder(20, 10, 20, 10));
26
+
27
+ textPane = new JTextPane();
28
+ textPane.setContentType("text/html");
29
+ textPane.setEditable(false);
30
+ textPane.setFont(new Font("Segoe UI", Font.PLAIN, 15));
31
+ textPane.setBackground(new Color(33, 33, 33));
32
+ textPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
33
+ htmlContent = new StringBuilder();
34
+ htmlContent.append("<html><head>")
35
+ .append("<style>")
36
+ .append("pre { background: #23272a; color: #b9f6ca; font-family: 'Courier New', Courier, monospace; font-size: 12px; border-radius: 7px; margin: 0 0 0 0; padding: 7px 12px 7px 16px; overflow-x: auto; white-space: pre; }")
37
+ .append("table { margin-bottom: 8px; }")
38
+ .append("</style>")
39
+ .append("</head><body style='font-family: Segoe UI, Roboto, Arial, sans-serif; font-size: 15px; background: #181818; color: #e0e0e0;'>");
40
+
41
+ JScrollPane scrollPane = new JScrollPane(textPane);
42
+ scrollPane.setBorder(BorderFactory.createLineBorder(new Color(60, 60, 60)));
43
+
44
+ buttonPanel = new JPanel(new FlowLayout());
45
+ buttonPanel.setBackground(new Color(33, 33, 33));
46
+
47
+ startButton = new JButton("▶ Start Simulation");
48
+ startButton.setBackground(new Color(33, 150, 243));
49
+ startButton.setForeground(Color.WHITE);
50
+ startButton.setFont(new Font("Segoe UI", Font.BOLD, 16));
51
+ startButton.setFocusPainted(false);
52
+ startButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
53
+ startButton.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20));
54
+
55
+ reportButton = new JButton("\uD83D\uDCC4 View Final Report");
56
+ reportButton.setBackground(new Color(76, 175, 80));
57
+ reportButton.setForeground(Color.WHITE);
58
+ reportButton.setFont(new Font("Segoe UI", Font.BOLD, 16));
59
+ reportButton.setFocusPainted(false);
60
+ reportButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
61
+ reportButton.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20));
62
+
63
+ startButton.addMouseListener(new java.awt.event.MouseAdapter() {
64
+ public void mouseEntered(java.awt.event.MouseEvent evt) {
65
+ if (startButton.isEnabled()) {
66
+ startButton.setBackground(new Color(30, 136, 229));
67
+ }
68
+ }
69
+ public void mouseExited(java.awt.event.MouseEvent evt) {
70
+ if (startButton.isEnabled()) {
71
+ startButton.setBackground(new Color(33, 150, 243));
72
+ }
73
+ }
74
+ });
75
+ reportButton.addMouseListener(new java.awt.event.MouseAdapter() {
76
+ public void mouseEntered(java.awt.event.MouseEvent evt) {
77
+ if (reportButton.isEnabled()) {
78
+ reportButton.setBackground(new Color(69, 160, 73));
79
+ }
80
+ }
81
+ public void mouseExited(java.awt.event.MouseEvent evt) {
82
+ if (reportButton.isEnabled()) {
83
+ reportButton.setBackground(new Color(76, 175, 80));
84
+ }
85
+ }
86
+ });
87
+
88
+ buttonPanel.add(startButton);
89
+ buttonPanel.add(Box.createHorizontalStrut(20));
90
+ buttonPanel.add(reportButton);
91
+ startButton.setVisible(true);
92
+ startButton.setEnabled(true);
93
+ reportButton.setVisible(false);
94
+ reportButton.setEnabled(false);
95
+
96
+ this.setLayout(new BorderLayout());
97
+ this.add(title, BorderLayout.NORTH);
98
+ JPanel centerPanel = new JPanel(new BorderLayout());
99
+ centerPanel.add(scrollPane, BorderLayout.CENTER);
100
+ this.add(centerPanel, BorderLayout.CENTER);
101
+ this.add(buttonPanel, BorderLayout.SOUTH);
102
+
103
+ startButton.addActionListener(e -> {
104
+ startButton.setEnabled(false);
105
+ simulationCompleted = false;
106
+ htmlContent = new StringBuilder();
107
+ htmlContent.append("<html><head>")
108
+ .append("<style>")
109
+ .append("pre { background: #23272a; color: #b9f6ca; font-family: 'Courier New', Courier, monospace; font-size: 12px; border-radius: 7px; margin: 0 0 0 0; padding: 7px 12px 7px 16px; overflow-x: auto; white-space: pre; }")
110
+ .append("table { margin-bottom: 8px; }")
111
+ .append("</style>")
112
+ .append("</head><body style='font-family: Segoe UI, Roboto, Arial, sans-serif; font-size: 15px; background: #181818; color: #e0e0e0;'>");
113
+ textPane.setText("");
114
+
115
+ startButton.setVisible(true);
116
+ startButton.setEnabled(false);
117
+ reportButton.setVisible(false);
118
+ reportButton.setEnabled(false);
119
+
120
+ buttonPanel.revalidate();
121
+ buttonPanel.repaint();
122
+
123
+ new Thread(() -> {
124
+ ParcelSortX.runSimulation(new ParcelSortX.Appender() {
125
+ @Override
126
+ public void append(String text) {
127
+ SwingUtilities.invokeLater(() -> {
128
+ htmlContent.append(text);
129
+ textPane.setText(htmlContent.toString() + "</body></html>");
130
+ textPane.setCaretPosition(textPane.getDocument().getLength());
131
+ });
132
+ }
133
+ });
134
+
135
+ SwingUtilities.invokeLater(() -> {
136
+ htmlContent.append("</body></html>");
137
+ startButton.setEnabled(true);
138
+ simulationCompleted = true;
139
+
140
+ startButton.setVisible(true);
141
+ startButton.setEnabled(true);
142
+ reportButton.setVisible(true);
143
+ reportButton.setEnabled(true);
144
+
145
+ buttonPanel.revalidate();
146
+ buttonPanel.repaint();
147
+ });
148
+ }).start();
149
+ });
150
+
151
+ reportButton.addActionListener(e -> {
152
+ if (simulationCompleted) {
153
+ showFinalReport();
154
+ } else {
155
+ JOptionPane.showMessageDialog(this,
156
+ "Please run the simulation first!",
157
+ "No Data Available",
158
+ JOptionPane.WARNING_MESSAGE);
159
+ }
160
+ });
161
+ }
162
+
163
+ private void showFinalReport() {
164
+ JFrame reportFrame = new JFrame("Final Report");
165
+ reportFrame.setSize(800, 600);
166
+ reportFrame.setLocationRelativeTo(this);
167
+
168
+ JLabel reportTitle = new JLabel("\uD83D\uDCC4 Final Simulation Report", SwingConstants.CENTER);
169
+ reportTitle.setFont(new Font("Segoe UI", Font.BOLD, 20));
170
+ reportTitle.setOpaque(true);
171
+ reportTitle.setBackground(new Color(76, 175, 80));
172
+ reportTitle.setForeground(Color.WHITE);
173
+ reportTitle.setBorder(BorderFactory.createEmptyBorder(15, 10, 15, 10));
174
+
175
+ JTextPane reportPane = new JTextPane();
176
+ reportPane.setContentType("text/html");
177
+ reportPane.setEditable(false);
178
+ reportPane.setFont(new Font("Segoe UI", Font.PLAIN, 14));
179
+ reportPane.setBackground(new Color(33, 33, 33));
180
+ reportPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
181
+
182
+ String styledReport = ParcelSortX.getFinalReportHtml();
183
+ reportPane.setContentType("text/html");
184
+ reportPane.setText(styledReport);
185
+
186
+ JScrollPane scroll = new JScrollPane(reportPane);
187
+ scroll.setBorder(BorderFactory.createLineBorder(new Color(60, 60, 60)));
188
+
189
+ JButton closeButton = new JButton("✕ Close Report");
190
+ closeButton.setBackground(new Color(244, 67, 54));
191
+ closeButton.setForeground(Color.WHITE);
192
+ closeButton.setFont(new Font("Segoe UI", Font.BOLD, 14));
193
+ closeButton.setFocusPainted(false);
194
+ closeButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
195
+ closeButton.setBorder(BorderFactory.createEmptyBorder(8, 15, 8, 15));
196
+
197
+ closeButton.addMouseListener(new java.awt.event.MouseAdapter() {
198
+ public void mouseEntered(java.awt.event.MouseEvent evt) {
199
+ closeButton.setBackground(new Color(229, 57, 53));
200
+ }
201
+ public void mouseExited(java.awt.event.MouseEvent evt) {
202
+ closeButton.setBackground(new Color(244, 67, 54));
203
+ }
204
+ });
205
+
206
+ closeButton.addActionListener(e -> reportFrame.dispose());
207
+
208
+ JPanel closePanel = new JPanel(new FlowLayout());
209
+ closePanel.setBackground(new Color(33, 33, 33));
210
+ closePanel.add(closeButton);
211
+
212
+ reportFrame.setLayout(new BorderLayout());
213
+ reportFrame.add(reportTitle, BorderLayout.NORTH);
214
+ reportFrame.add(scroll, BorderLayout.CENTER);
215
+ reportFrame.add(closePanel, BorderLayout.SOUTH);
216
+
217
+ reportFrame.setVisible(true);
218
+ }
219
+
220
+ public static void main(String[] args) {
221
+ try {
222
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
223
+ } catch (Exception e) {
224
+ }
225
+ SwingUtilities.invokeLater(() -> {
226
+ new ParcelSortXGUI().setVisible(true);
227
+ });
228
+ }
229
+ }