Commit
·
890628b
1
Parent(s):
baf4622
Save my local changes before pulling
Browse files- .idea/encodings.xml +7 -0
- .idea/modules.xml +1 -1
- config.txt +7 -6
- log.txt +167 -0
- report.txt +113 -0
- route_config.txt +0 -4
- src/src/ParcelSortX.java +540 -354
- src/src/ParcelSortXGUI.java +227 -2
.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$/
|
| 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 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
|
|
|
|
|
| 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 |
-
|
| 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 |
-
|
| 88 |
-
|
| 89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
}
|
| 91 |
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
|
|
|
|
|
|
| 95 |
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
}
|
| 104 |
-
|
|
|
|
| 105 |
}
|
| 106 |
-
HashEntry newEntry = new HashEntry(key, value);
|
| 107 |
-
newEntry.next = buckets[index];
|
| 108 |
-
buckets[index] = newEntry;
|
| 109 |
}
|
| 110 |
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
|
|
|
|
|
|
|
|
|
| 117 |
}
|
| 118 |
-
return null;
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
|
|
|
|
|
|
| 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 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 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 |
-
|
| 179 |
-
|
| 180 |
-
TreeNode newNode = new TreeNode(p.destination);
|
| 181 |
-
newNode.parcels.add(p);
|
| 182 |
-
return newNode;
|
| 183 |
}
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
node.left = insert(node.left, p);
|
| 188 |
-
|
| 189 |
-
node.
|
| 190 |
-
|
| 191 |
-
node
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
}
|
| 193 |
-
return
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 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 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 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 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
if (current == null) {
|
| 281 |
-
System.out.println("[Route Log] No route loaded.");
|
| 282 |
-
return;
|
| 283 |
}
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 288 |
}
|
| 289 |
-
|
| 290 |
-
System.out.println("[Route Log] Active terminal: " + current.location);
|
| 291 |
}
|
| 292 |
|
| 293 |
-
|
| 294 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
}
|
| 296 |
-
}
|
| 297 |
|
| 298 |
-
//
|
| 299 |
-
public class
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 308 |
}
|
| 309 |
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 313 |
Random rand = new Random();
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
|
| 319 |
-
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
}
|
| 328 |
-
}
|
| 329 |
} catch (IOException e) {
|
| 330 |
-
|
| 331 |
}
|
| 332 |
-
}
|
| 333 |
-
|
| 334 |
-
public static void main(String[] args) {
|
| 335 |
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
|
| 350 |
-
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
|
| 355 |
-
log("Generated and queued: " + p);
|
| 356 |
}
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
| 361 |
-
|
| 362 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 363 |
}
|
| 364 |
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 373 |
}
|
|
|
|
|
|
|
| 374 |
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
}
|
| 379 |
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 385 |
}
|
| 386 |
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 396 |
}
|
|
|
|
|
|
|
| 397 |
|
| 398 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 399 |
}
|
| 400 |
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 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(" ", " ");
|
| 483 |
+
html = html.replace("<", "<").replace(">", ">").replace("&", "&");
|
| 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 |
-
|
| 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 |
+
}
|