3. Model: entitas (lokasi, penumpang, bus)
“Entitas” adalah benda-benda yang ada di sistem. Berkas ini menjelaskan cara data mereka disiapkan dan dipakai. Kejadian yang memakai mereka ada di berkas 4.
3.1 Location (baris 255 sampai 277)
src/bus-sim.c baris 255-277
/* Entity: location. The route 3 -> 1 -> 2 -> 3 is defined here only. */
void location_init(void)
{
location_set(LOC_TERMINAL_1, "Air terminal 1", ARRIVAL_RATE_T1,
LOC_TERMINAL_2, DIST_T1_TO_T2);
location_set(LOC_TERMINAL_2, "Air terminal 2", ARRIVAL_RATE_T2,
LOC_CAR_RENTAL, DIST_T2_TO_RENTAL);
location_set(LOC_CAR_RENTAL, "Car rental", ARRIVAL_RATE_RENTAL,
LOC_TERMINAL_1, DIST_RENTAL_TO_T1);
}
void location_set(int id, const char *name, double arrival_rate,
int next_stop, double distance_to_next)
{
/* Rate is per hour and speed is miles per hour; convert both to minutes. */
locations[id].name = name;
locations[id].mean_interarrival = MINUTES_PER_HOUR / arrival_rate;
locations[id].next_stop = next_stop;
locations[id].travel_time_to_next = distance_to_next / BUS_SPEED_MPH * MINUTES_PER_HOUR;
}
| Sintaks | Arti |
|---|---|
location_set(LOC_TERMINAL_1, "Air terminal 1", ARRIVAL_RATE_T1, LOC_TERMINAL_2, DIST_T1_TO_T2) | isi satu baris tabel lokasi: nama, laju, lokasi berikutnya, jarak ke lokasi berikutnya |
locations[id].name = name; | isi field name pada elemen ke-id |
MINUTES_PER_HOUR / arrival_rate | 60 ÷ laju per jam = menit per orang |
distance_to_next / BUS_SPEED_MPH * MINUTES_PER_HOUR | jarak ÷ kecepatan = jam, lalu × 60 = menit |
Logika: location_init mengisi tiga baris tabel. Rute hanya didefinisikan di sini:
| id | next_stop | rata-rata antar-kedatangan | waktu tempuh ke berikutnya |
|---|---|---|---|
| 1 | 2 | 60 ÷ 14 = 4,29 menit | 1,0 ÷ 30 × 60 = 2 menit |
| 2 | 3 | 60 ÷ 10 = 6 menit | 4,5 ÷ 30 × 60 = 9 menit |
| 3 | 1 | 60 ÷ 24 = 2,5 menit | 4,5 ÷ 30 × 60 = 9 menit |
Kenapa begini: konversi jam ke menit dilakukan di satu fungsi, dan mengubah rute atau laju cukup di
location_init.
3.2 Passenger (baris 278 sampai 323)
src/bus-sim.c baris 278-323
/* Entity: passenger. Only these functions use transfer[] for passengers. */
Passenger passenger_create(int origin)
{
Passenger p;
p.arrival_time = sim_time;
p.origin = origin;
/* Terminal arrivals go to the car rental; car-rental arrivals go to
terminal 1 (prob. 0.583) or terminal 2, decided with stream 6. */
if (origin == LOC_CAR_RENTAL) {
if (lcgrand(STREAM_DESTINATION) < PROB_RENTAL_TO_T1)
p.destination = LOC_TERMINAL_1;
else
p.destination = LOC_TERMINAL_2;
} else {
p.destination = LOC_CAR_RENTAL;
}
return p;
}
void passenger_file(const Passenger *p, int list)
{
transfer[ATTR_ARRIVAL_TIME] = p->arrival_time;
transfer[ATTR_ORIGIN] = (double) p->origin;
transfer[ATTR_DESTINATION] = (double) p->destination;
list_file(LAST, list);
}
Passenger passenger_remove_first(int list)
{
Passenger p;
/* Copy right away: event_schedule() and timing() overwrite transfer[]. */
list_remove(FIRST, list);
p.arrival_time = transfer[ATTR_ARRIVAL_TIME];
p.origin = (int) transfer[ATTR_ORIGIN];
p.destination = (int) transfer[ATTR_DESTINATION];
return p;
}
| Sintaks | Arti |
|---|---|
Passenger passenger_create(int origin) | fungsi yang mengembalikan satu Passenger |
Passenger p; lalu p.arrival_time = sim_time; | variabel struct; isi field dengan titik |
lcgrand(STREAM_DESTINATION) < PROB_RENTAL_TO_T1 | ambil satu angka acak (0 sampai 1) dari stream 6, bandingkan dengan 0,583 |
const Passenger *p | p menunjuk ke penumpang yang tidak boleh diubah fungsi ini |
p->origin | field origin dari yang ditunjuk p |
transfer[ATTR_ARRIVAL_TIME] = ... | tulis ke kolom 1 larik transfer milik SIMLIB |
list_file(LAST, list) | masukkan isi transfer ke ujung list nomor list |
list_remove(FIRST, list) | ambil dari depan list; isinya muncul di transfer |
Logika passenger_create: orang baru dibuat dengan arrival_time = sim_time (kapan ia tiba). Dari
terminal tujuannya pasti rental mobil. Dari rental, tujuan diundi sekali dari stream 6: angka acak di
bawah 0,583 berarti terminal 1, selain itu terminal 2.
Logika passenger_file dan passenger_remove_first: satu menyalin struct ke transfer lalu memasukkan ke
list; satunya mengambil dari list lalu langsung menyalin hasilnya kembali ke struct.
Kenapa begini: event_schedule dan timing milik SIMLIB menimpa kolom 1 dan 2 transfer. Kalau data
orang dibiarkan di transfer, ia bisa rusak. Dengan disalin ke struct segera, data aman, dan hanya dua fungsi
ini yang menyentuh transfer.
3.3 Bus (baris 324 sampai 377)
src/bus-sim.c baris 324-377
/* Entity: bus. Passengers on board are in lists 4-6, one per destination. */
void bus_init(void)
{
/* At t = 0 the bus has just left the car rental, heading to terminal 1. */
bus.location = locations[LOC_CAR_RENTAL].next_stop;
bus.status = BUS_MOVING;
bus.min_stop_reached = 0;
bus.arrival_time = 0.0;
bus.last_rental_departure = 0.0;
bus.current.arrival_time = 0.0;
bus.current.origin = 0;
bus.current.destination = 0;
}
int bus_passenger_count(void)
{
int dest;
int count;
count = 0;
for (dest = 1; dest <= NUM_LOCATIONS; ++dest)
count += list_size[LIST_BUS(dest)];
return count;
}
int bus_is_full(void)
{
return bus_passenger_count() >= BUS_CAPACITY;
}
int bus_has_passenger_for(int destination)
{
return list_size[LIST_BUS(destination)] > 0;
}
/* Called at the end of loading. */
void bus_board(const Passenger *p)
{
passenger_file(p, LIST_BUS(p->destination));
stats_bus_count_changed(bus_passenger_count());
}
/* Called at the start of unloading; FIFO among passengers for this stop. */
Passenger bus_alight(int destination)
{
Passenger p;
p = passenger_remove_first(LIST_BUS(destination));
stats_bus_count_changed(bus_passenger_count());
return p;
}
| Sintaks | Arti |
|---|---|
bus.location = locations[LOC_CAR_RENTAL].next_stop; | ambil next_stop dari lokasi 3 (yaitu 1) |
for (dest = 1; dest <= NUM_LOCATIONS; ++dest) count += list_size[LIST_BUS(dest)]; | jumlahkan isi tiga list bus |
return count; | kembalikan hasil ke pemanggil |
return bus_passenger_count() >= BUS_CAPACITY; | hasil perbandingan (0 atau 1) langsung dikembalikan |
Logika:
| Fungsi | Tugas |
|---|---|
bus_init | di t = 0 bus sudah meninggalkan rental: status BUS_MOVING, menuju lokasi 1 |
bus_passenger_count | jumlah di bus = jumlah isi list 4, 5, 6 |
bus_is_full | benar bila jumlah sudah 20 |
bus_has_passenger_for | benar bila ada penumpang yang tujuannya destination |
bus_board | masukkan penumpang ke list tujuannya, lalu panggil hook stats_bus_count_changed |
bus_alight | keluarkan penumpang pertama list tujuan itu, lalu panggil hook stats_bus_count_changed |
Kenapa begini: jumlah di bus dihitung dengan menjumlahkan list (bukan variabel penghitung terpisah), jadi
tidak mungkin tidak sinkron dengan isi sebenarnya. Hook dipanggil di bus_board dan bus_alight karena
hanya di dua tempat itu jumlah di bus berubah; hook itu menyuplai statistik (c).