108
LAMPIRAN
Lampiran 1 Kuisioner Pertanyaan
Ya Tidak
1 Apakah kamu menyukai
tampilan game ini ?
2 Apakah menurutmu game ini mudah untuk dimainkan ? 3
Apakah materi yang diberikan sesuai dengan yang kamu pelajari ?
4 Apakah bantuan pada game ini berjalan dengan semestinnya ? 5 Apakah belajar dengan game
ini terasa menyenangkan ? 6 Apakah kamu ingin memainkan
kembali game ini ?
Jawaban
No PERTANYAAN
Lampiran 2 Hasil Survei dengan beberapa siswa SD kelas 3 hingga SMP kelas 1
Nama : Kelas : Apakah Kamu menyukai tampilan dari game ini ? Apakah menurutmu game ini mudah untuk dimainkan ? Apakah materi yang diberikan sesuai dengan yang kamu pelajari ? Apakah bantuan pada game ini berjalan dengan semestinnya ? Apakah belajar dengan game ini terasa lebih menyenangkan ? Apakah kamu ingin memainkan kembali game ini ?
M Fathur SMP Kelas 1 Tidak Ya Ya Ya Ya Ya
Farhan Ramadhan R.H SMP Kelas 1 Tidak Ya Ya Ya Ya Tidak
Alisya SMP Kelas 1 Ya Ya Ya Ya Ya Ya
Farizky Salman Bachtiar SMP Kelas 1 Ya Tidak Ya Ya Ya Ya Nabila Rahmania Sholihah SMP Kelas 1 Ya Tidak Ya Ya Tidak Ya
Nabila SyaSD Kelas 6 Ya Tidak Ya Ya Tidak Ya
Daffa Dhiya Ulhaq SMP Kelas 1 Ya Ya Tidak Ya Ya Ya
Nicka Resina SD Kelas 6 Ya Ya Ya Ya Ya Ya
Erlando S.PSD Kelas 3 Ya Ya Ya Ya Ya Tidak
Muhammad Ilham Zuhruf Firdaus SMP Kelas 1 Ya Ya Ya Ya Ya Ya
Gerry Ismail SD Kelas 5 Ya Ya Ya Ya Ya Ya
Diana SMP Kelas 1 Tidak Ya Ya Ya Ya Ya
Ramadhan Miftah SMP Kelas 1 Ya Ya Tidak Ya Ya Ya
Dikky Dermawan SMP Kelas 1 Ya Ya Ya Ya Ya Ya
Tsaqiif A. SMP Kelas 1 Ya Ya Ya Ya Ya Ya
M HanifanSMP Kelas 1 Ya Tidak Ya Ya Ya Ya
SAHRIZAL ILHAM FIKRIYASA SD Kelas 4 Ya Ya Ya Ya Ya Ya
109
Lampiran 3 Listing Kode Program Algoritma Dijkstra
//Kelas Dijkstra
//MonoNehaviour berfungsi sebagai penonaktifan script bila script tersebut tidak dicentang dalam dijkstra
public class Dijkstra : MonoBehaviour {
// define node configurator
private NodeConfigurator nodeConfigurator;
//define textlog //define text log //private Text //debug;
//variable untuk menyimpan jumlah nodes private int TotalNodeCount;
void Start() {
//init nodeconfigurator
nodeConfigurator = gameObject.GetComponent<NodeConfigurator>();
//init log text
//debug = nodeConfigurator.//debug;
}
//buat struct dengan nama Results, untuk menentukan tiap path dan jaraknya
public struct Results {
// variable untuk path public int[] MinimumPath;
// variable untuk distance public float[] MinimumDistance;
public Results(int[] minimumPath, float[] minimumDistance) {
MinimumDistance = minimumDistance;
MinimumPath = minimumPath;
} }
//---method struct untuk menentukan hasil djikstra public Results Perform(int start)
{
//get starting travelcost
float[] d = GetStartingTraversalCost(start);
//set bestpath, set semua menjadi start, misal 0 int[] p = GetStartingBestPath(start);
// define basic heap
BasicHeapOne Q = new BasicHeapOne();
//tampilkan di log
//debug.text += "\n<color=#800000>Starting Traversal Cost from node 0</color>";
//jika i != total node
for (int i = 0; i != TotalNodeCount; i++)
110
{
//masukkan nilai starting path & starting travesalcost kedalam heap
Q.Push(i, d[i]);
//tampilkan di log
if (d[i] != Mathf.Infinity) {
// neighbor dr starting node
//debug.text += "\n<color=#0000ff>node "+i+" =
"+d[i]+"</color>";
} else {
//node yang belum terjamah
//debug.text += "\n<color=#0000ff>node "+i+" =
"+d[i]+"</color>";
} }
//tampilkan di //debug
//debug.text += "\n<color=#800000>Start Main Loop</color>";
// jika Q (node yang harus di cek) lebih dari 0 while (Q.Count1 > 0)
{
// buat variable v (visited / current node) dari nilai heap paling awal
int v = Q.Pop();
//tampilkan di log
////debug.text += "\n<color=blue>[---CEK NODE "+v+"---] \n>
Remaining Q = "+Q.Count+"] : </color> ";
// tampilkan di log node dan traversalcost ned yang belum terjamah / yg harus di cek
for (int i = 0; i < Q.Count1; i++) {
//tampilkan di log
//debug.text += "\nnode "+Q.getIndex(i)+" : ";
//debug.text +="cost : "+Q.getWight(i);
}
//tampilkan di log
//debug.text += "\n<color=blue>> Cek Nearby dari node "+v+ " :
</color>";
//untuk setiap neighbor dari node yang sedang di cek foreach (int w in nodeConfigurator.GetNearbyNodes(v)) {
//tampilkan di log
//debug.text += "\nnode "+v+" > node "+w;
//tentukan traversalcost dari current node ke neighbor float cost = nodeConfigurator.getTraversalCost(v, w);
//tandai node yang telah dilalui
nodeConfigurator.markCurrentPath(v, w);
//tampilkan di log :
//debug.text += ", cost = "+cost;
//jika traversal cost V + cost ke neighbor yg sedang di cek 'w' < dari traversal cost sebelumnya
if (d[v] + cost < d[w]) {
//tampilkan di log
111
//debug.text += "\nTravecost dari "+v+" > "+w+ " =
"+(d[v]+cost)+"\n<color=#660066>Lebih kecil dari cost yg sekarang =
"+d[w]+"</color>";
//masukan nilai baru hasil pertambahan current ke neighbor yang di cek ke dalam travelcost yng sedang di cek
d[w] = d[v] + cost;
//tampilkan di log
//debug.text +="\n> Set cost : dr node sebelumnya >
"+v+" > "+w+" = "+d[w];
//debug.text += "\n> Set best path menuju "+w+" dari =
"+p[w]+" menjadi = "+v;
// set best path menjadi node yang di cek p[w] = v;
//tampilkan di log
//debug.text += ">\nPush index = "+w+", weight =
"+d[w]+" ke Q untuk dicek selanjutnya";
//push node dan weightnya ke heap Q.Push(w, d[w]);
//tampilkan di log :
//debug.text += "\njadi Q = "+Q.Count;
//jika perbandingan harganya sama }
else if (d[v] + cost == d[w]) {
//tampilkan di log :
//debug.text += "\nTravecost dari "+v+" > "+w+ " =
"+(d[v]+cost)+"\n<color=#006600>Harga yang sama dari cost yg sekarang =
"+d[w]+"</color>";
//jika perbandingan harganya lebih besar }
else if (d[v] + cost > d[w]) {
//tampilkan di log :
//debug.text += "\nTravecost dari start > "+v+" > "+w+
" = "+(d[v]+cost)+"\n<color=#006600>Harga yang lebih besar dari cost yg sekarang = "+d[w]+"</color>";
} } }
//tampilkan di log
//debug.text += "\n<color=#800000>Node hasil perhitungan</color>";
// cek masing2 nilai p sekarang for (int i = 0; i < p.Length; i++) {
//tampilkan di log
//debug.text += "\nStart > node "+i+" melalui node "+p[i];
}
//tampilkan di log :
//debug.text += "\n<color=#800000>Distance dari start ke masing2 node</color>";
//cek nilai d baru
for (int i = 0; i < d.Length; i++) {
//tampilkan di log :
//debug.text += "\n> Start > "+i+" = "+d[i];
}
112
//return nilia p dan d return new Results(p, d);
}
//method untuk menentukan jarak terpendek
public int[] GetMinimumPath(int start, int finish) {
//set total node
TotalNodeCount = nodeConfigurator.NumNodes;
//lakukan pencarian dengan memanggil method 'pERFORM' Results results = Perform(start);
//Tampilkan di log :
//debug.text += "\n<color=#800000>Step menuju start point</color>";
//masukan hasil pencarian terpendek kedalam variable X, kemudian sortir
int[] x = GetMinimumPath(start, finish, results.MinimumPath);
//tampilkan di log :
//debug.text += "\n<color=#800000>Node optimal Path</color>";
//periksa setiap nilai dari x for (int i = 0; i < x.Length; i++) {
//tampilkan di log :
//debug.text += "\n> "+x[i];
}
//kembalikan nilai X return x;
}
private int[] GetMinimumPath(int start, int finish, int[] shortestPath) {
foreach (int i in shortestPath) {
//debug.text += "\n> sortestpath "+i;
}
//buat stack
Stack<int> path = new Stack<int>();
//lakukan loop sampai nilai path == nilai awal / node start do
{
//tampilkan di log :
//debug.text += "\n<color=blue>> "+finish+"</color>";
// masukan nilai paling akhir terlebih dahuli path.Push(finish);
//ganti nilai finish dengan path paling akhir //
shortestPath[finish] = path paling ahir //.. update nilai finish finish = shortestPath[finish];
}
while (finish != start);
//tampilkan di log :
//debug.text += "\n<color=blue>> "+finish+"</color>";
//push finish karena nilai paling akhir pasti start node path.Push(finish);
//return nilai stack menjadi array return path.ToArray();
}
// method untuk menentukan semua path dari 0
private int[] GetStartingBestPath(int startingNode) {
113
//get totoal node masukan ke p int[] p = new int[TotalNodeCount];
//cek semua node
for (int i = 0; i < p.Length; i++) // jadikan nilai p starting node p[i] = startingNode;
//return return p;
}
//method untuk mencari starting traversal cost private float[] GetStartingTraversalCost(int start) {
//buat variable subset dari jumalh node float[] subset = new float[TotalNodeCount];
//cek untuk setiap subset
for (int i = 0; i != subset.Length; i++) {
//rubah menjadi infinity, subset[i] = Mathf.Infinity;
}
//kecuali node start subset[start] = 0;
// dan tetangganya
foreach (int nearby in nodeConfigurator.GetNearbyNodes(start)) {
//dibuat bernilai dan tidak infinity
subset[nearby] = nodeConfigurator.getTraversalCost(start, nearby);
}
//return nilai subset return subset;
} }
Lampiran 4 Listing Kode Program NodeConfigurator
Node Configurator class : digunakan untuk set node dan path
public class NodeConfigurator : MonoBehaviour
{
//define jumlah node public int NumNodes;
//define node transform -wiring- public Transform[] Nodes;
//boolean untuk menentukan antar node mana saja yang terkoneksi public bool[,] connectionExists;
//nilai jarak antar node float[,] distances;
//array komponen line public LineRenderer[] line;
//line holder untuk menyimpan line renderer
114
public GameObject[] lineHolder;
//variable untuk menyimpan jumlah edges / garis int NumEdges;
//define start and end public int a = 0, b = 13;
//define dijkstra class public Dijkstra dijkstra;
//material untuk penanda garis
public Material lineMaterial, highlightMaterial, traveledMaterial;
//komponen text untuk log //public Text //debugText;
//variable path untuk menyimpan array step dari start ke end int[] path;
// variable untuk menyimpan jarak tempuh dari start -> end float distanceTraveled;
// string untuk menyimpan text path step string pathString = "";
//--- dipanggil ketika tombol 'run' dijalankan //berfungsi sebagai pengarah ke node terdekat public void RunPathfinder()
{
//isi path[] dengan menjalankan method RunDijksta() path = runDijkstra();
//tandai path yang harus ditempuh dengan memanggil method markPath StartCoroutine(markPath(path));
//dapatkan total jarak tempuh dari start -> end distanceTraveled = getTotalDistance(path);
//dapatkan text path tempuh pathString = getPathString(path);
//tampilkan dalam log
//debugText.text += "\n<color=#800000>=== Summary ===</color>";
//debugText.text += "\nDistance to end : " + distanceTraveled.ToString("F2");
//debugText.text += "\n" + pathString;
}
//--- dipanggil ketika scene pertama kali di play void Start()
{
//pastikan jumlah nodes = jumah objek node NumNodes = Nodes.Length;
//tampilkan di log
//debugText.text = "Jumlah Node = "+NumNodes;
//set objek nodes initializeNodes();
//set garis
initializeLines();
}
//--- dipanggil realtime tiap frame void Update()
{
// koneksikan tiap node yang sudah di set connectNodes();
115
// Update warna Start Node
Nodes[a].GetComponent<Renderer>().material.color = Color.red;
// rubah text menjadi 'start'
var CurrentCubeText = Nodes[a].Find("New Text").GetComponent(typeof(TextMesh)) as TextMesh;
CurrentCubeText.text = "Start";
CurrentCubeText.fontSize = 17;
// Update warna end node
Nodes[b].GetComponent<Renderer>().material.color = Color.red;
// rubah text menjadi 'end'
CurrentCubeText = Nodes[b].Find("New Text").GetComponent(typeof(TextMesh)) as TextMesh;
CurrentCubeText.text = "End";
CurrentCubeText.fontSize = 17;
}
//--- method untuk set Node void initializeNodes()
{
//init size connectionExists
connectionExists = new bool[NumNodes, NumNodes];
//init array distances
distances = new float[NumNodes, NumNodes];
// cek tiap node
for (int i = 0; i < NumNodes; i++) {
//pastikan textberdasarkan nomor nodes var CurrentCubeText = Nodes[i].Find("New Text").GetComponent(typeof(TextMesh)) as TextMesh;
CurrentCubeText.text = "" + i;
//ubah juga nama game objeknya
Nodes[i].gameObject.name = i.ToString();
}
//jumlah garis diisi dengan berapa jumlah antar nodes yang terkoneksi
NumEdges = determineConnections();
//tampilkan di log jumlah garis
//debugText.text += "\nJumlah Path : "+NumEdges;
}
//--- method untuk mendefinisikan garis antar nodes void initializeLines()
{
//define size variable line berasarkan jumlah garis line = new LineRenderer[NumEdges];
//... begitu juga holdernya
lineHolder = new GameObject[NumEdges];
//untuk setiap garis / edge
for (int i = 0; i < NumEdges; i++) {
//define masing-masing garis line[i] = new LineRenderer();
//... juga holder nya
lineHolder[i] = new GameObject();
//tambahkan komponen line ke objek holder
line[i] = lineHolder[i].AddComponent<LineRenderer>();
//set jumlah titik nya
116
line[i].SetVertexCount(2);
//set width garis
line[i].SetWidth(.10F, .10F);
//set material line
line[i].material = lineMaterial;
//enable line
line[i].enabled = true;
} }
//--- method untuk mengkoneksikan node (visualisasi) void connectNodes()
{
// buat variable untuk menentukan node yang di cek dan neighbor nya Vector3 nodeToCheck, neighbor;
//variable menentukan line mana yang sedang dipakai int currentLine = 0;
// untuk setiap jumlah node, cek node to check for (int i = 0; i < NumNodes; i++)
{
// node utk di cek = objek node ke 'i'
nodeToCheck = Nodes[i].gameObject.transform.position;
// untuk setiap jumlah node, check neighbor for (int j = 0; j < NumNodes; j++)
{
// neighbor = objek node ke 'j'
neighbor = Nodes[j].gameObject.transform.position;
//cek apakah current dan neighbor terkoneksi if (connectionExists[i, j])
{
//jika ya, buat garis dari current ke neighbor line[currentLine].SetPosition(0, nodeToCheck);
line[currentLine].SetPosition(1, neighbor);
//rubah nama objek holder menjadi sesuai garis
lineHolder[currentLine].name = "Line from " + i + " to
" + j;
//update variable currentLine currentLine++;
} } } }
// node untuk mengkonteksikan antara satu node ke node lainnya int determineConnections()
{
//---TO-DO : Buat menjadi loop // variable utk menentukan jarak
float distance;
// variable vector 3 utk menentukan current dan neighbor Vector3 nodeToCheck, neighbor;
// conter berfungsi untuk num of edges int counter = 0;
// ---Buat koneksi Node 0(awal) -> 1(selanjutnya) // node posisi awal
nodeToCheck = Nodes[0].gameObject.transform.position;
// node posisi neighbor
117
neighbor = Nodes[1].gameObject.transform.position;
// hitung distance-nya
distance = Vector3.Distance(nodeToCheck, neighbor);
// tampilkan ke log
//debugText.text += "\nDistance : "+0+" > "+1+" = "+distance;
// declare koneksi current dan neighbor declareConnection(1, 0, distance);
// update counter counter++;
// Buat koneksi Node dari node asal ke node selanjutnya sampai ke node tujuan nodeToCheck = Nodes[6].gameObject.transform.position;
neighbor = Nodes[9].gameObject.transform.position;
distance = Vector3.Distance(nodeToCheck, neighbor);
//debugText.text += "\nDistance : "+0+" > "+2+" = "+distance;
declareConnection(6, 9, distance);
counter++;
// return nilai counter menjadi nilai jumlah edges return counter;
//--- method untuk menentukan node mana saja yang terhubung void declareConnection(int i, int j, float distance)
{
// buat [i , j] = true
connectionExists[i, j] = true;
// isi jarak i _ j
distances[i, j] = distance;
}
//--- method untuk menandai path yang sudah di generate IEnumerator markPath(int[] path)
{
//untuk setiap objek holder ...
foreach (GameObject o in lineHolder) {
//... non-aktifkan holder o.SetActive(false);
}
//buat variable current dan neighbor Vector3 nodeToCheck, neighbor;
//tampilkan di log
//debugText.text += "\n<color=#800000>Tandai Path</color>";
//untuk setiap nilai path
for (int i = 0; i < path.Length; i++) {
//tampilkan di log
//debugText.text += "\nnode to check : "+path[i];
//current = node dengan nilai path 'i'
nodeToCheck = Nodes[path[i]].gameObject.transform.position;
//untuk setiap nilai di path
for (int j = 0; j < path.Length; j++) {
118
//neighbor = node dengan nilai path 'j'
neighbor = Nodes[path[j]].gameObject.transform.position;
//tampilkan dalam log
//debugText.text += "\ncek : "+path[i]+" + "+path[j];
//jika current dan neighbor terhubung if (connectionExists[path[i], path[j]]) {
// buat string untuk mendapatkan nama holder
string holderName = "Line from " + path[i] + " to " + path[j];
//tampilkan di log
//debugText.text += "\nTandai path "+path[i] +" >
"+path[j];
//untuk setiap lineholder
for (int k = 0; k < lineHolder.Length; k++) {
//jika line holder name = holderName if (lineHolder[k].name == holderName) {
//aktifkan objek holder
lineHolder[k].SetActive(true);
//ubah warna line
line[k].material = highlightMaterial;
yield return new WaitForSeconds(0.0f);
} } } } } }
public void markCurrentPath(int startNode, int endNode) {
string holderName = "Line from " + startNode + " to " + endNode;
for (int k = 0; k < lineHolder.Length; k++) {
if (lineHolder[k].name == holderName) {
line[k].material = traveledMaterial;
} } }
//--- method untuk mencari path string public string getPathString(int[] path)
{
string pathText = "";
// Set path text
for (int j = 0; j < path.Length; j++) {
if (j == 0)
pathText = "Path : Start ";
else if (j != path.Length - 1)
pathText = pathText + " -> " + path[j];
else
pathText = pathText + " -> " + "End";
}
119
return pathText;
}
// --- method untuk mencari total jarak tempuh dari start >
end
public float getTotalDistance(int[] nodesTraveled) {
float total = 0;
for (int i = 0; i < nodesTraveled.Length; i++) {
if (i != nodesTraveled.Length - 1) {
total += getTraversalCost(nodesTraveled[i], nodesTraveled[i + 1]);
} }
return total;
}
//--- method untuk mendapatkan traversal cost antar node public float getTraversalCost(int start, int neighbor)
{
//jika terkoneksi
if (connectionExists[start, neighbor]) //return nilai distance
return distances[start, neighbor];
//atau yg terkoneksi adalah node kebalikannya else if (connectionExists[neighbor, start]) //return juga nilai distance-nya
return distances[neighbor, start];
//jika bukan keduanya, berarti nilainya tidak didefinsisikan else return Mathf.Infinity;
}
//--- method untuk menjalankan algoritma dijkstra public int[] runDijkstra()
{
//define dijkstra class
dijkstra = gameObject.GetComponent<Dijkstra>();
//buat variable dijksttrapath dengan memanggil method dijkstra getminimumPath
int[] dijkstraPaths = dijkstra.GetMinimumPath(a, b);
//jika hasilnya sudah didapat, tampilkan di log
//debugText.text += "\n<color=#800000>Final Path</color>";
//untuk setiap path
for (int i = 0; i < dijkstraPaths.Length; i++) {
//tampilkan di log
//debugText.text +="\n<color=blue>>
"+dijkstraPaths[i]+"</color>";
}
// return nilai2 path return dijkstraPaths;
}
120
//---method untuk menampilkan nearby atau neighbor public IEnumerable<int> GetNearbyNodes(int startingNode) {
//buat list int untuk menyimpan nilai node List<int> nearbyNodes = new List<int>();
//untuk setiap node
for (int j = 0; j < NumNodes; j++) {
//cek jika node dengan starting node atau sebaliknya exist if (connectionExists[startingNode, j] || connectionExists[j, startingNode])
{
// jika ya, tambahkan ke list nearbyNodes.Add(j);
} }
//return list return nearbyNodes;
} }
Lampiran 5 Listing Kode Program BasicHeapNode
//digunakan untuk menghitung distance class BasicHeapOne
{
private List<HeapNode12> InnerList = new List<HeapNode12>();
public BasicHeapOne() {}
public int Count1 {
get {
return InnerList.Count;
} }
public float getWight(int index){
HeapNode12 result = InnerList[index];
return result.weight;
}
public float getIndex(int index){
HeapNode12 result = InnerList[index];
return result.index;
}
121
public void Push(int index, float weight) {
int p = InnerList.Count, p2;
InnerList.Add(new HeapNode12(index,weight));
do {
if (p == 0) break;
p2 = (p - 1) >> 1;
if (InnerList[p].weight<InnerList[p2].weight) {
HeapNode12 h = InnerList[p];
InnerList[p] = InnerList[p2];
InnerList[p2] = h;
p = p2;
} else break;
} while (true);
}
public int Pop() {
HeapNode12 result = InnerList[0];
int p = 0, p1, p2, pn;
InnerList[0] = InnerList[InnerList.Count - 1];
InnerList.RemoveAt(InnerList.Count - 1);
do {
pn = p;
p1 = (p << 1) + 1;
p2 = (p << 1) + 2;
if (InnerList.Count > p1 && InnerList[p].weight >
InnerList[p1].weight) p = p1;
if (InnerList.Count > p2 && InnerList[p].weight >
InnerList[p2].weight) p = p2;
if (p == pn) break;
HeapNode12 h = InnerList[p];
InnerList[p] = InnerList[pn];
InnerList[pn] = h;
} while (true);
return result.index;
} }
Lampiran 6 Listing Kode Program HeapOne
122
//untuk menentukan index nomor dan berat node public struct HeapNode12
{
public HeapNode12(int i, float w) {
index = i;
weight = w;
}
public int index;
public float weight;
}