Skip to content

Commit 3eeca62

Browse files
committed
User Friendly Update
A lot of small quality-of-life improvements to make it more like a playable game! [ADDED] - Optional pointer to an element (used in selection sort and quicksort) - Swapping animation for all sorts and sorting animation for merge sort - Persistent high score with moves-per-second tier ranking system - Configurable simulation size and speed - Quicksort (using Lomuto partition scheme) [CHANGED] - Replaced useless end screen with a view of sorted array
2 parents f13d0b7 + bd5b6c6 commit 3eeca62

29 files changed

+649
-230
lines changed

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
name: Bug report
3+
about: Create a report to help us improve
4+
title: ''
5+
labels: bug
6+
assignees: ''
7+
8+
---
9+
10+
**Describe the bug**
11+
A clear and concise description of what the bug is.
12+
13+
**To Reproduce**
14+
Steps to reproduce the behavior:
15+
1. Go to '...'
16+
2. Click on '....'
17+
3. Scroll down to '....'
18+
4. See error
19+
20+
**Expected behavior**
21+
A clear and concise description of what you expected to happen.
22+
23+
**Screenshots**
24+
If applicable, add screenshots to help explain your problem.
25+
26+
**Desktop (please complete the following information):**
27+
- OS: [e.g. iOS]
28+
- Browser [e.g. chrome, safari]
29+
- Version [e.g. 22]
30+
31+
**Smartphone (please complete the following information):**
32+
- Device: [e.g. iPhone6]
33+
- OS: [e.g. iOS8.1]
34+
- Browser [e.g. stock browser, safari]
35+
- Version [e.g. 22]
36+
37+
**Additional context**
38+
Add any other context about the problem here.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
name: Feature request
3+
about: Suggest an idea for this project
4+
title: ''
5+
labels: enhancement
6+
assignees: ''
7+
8+
---
9+
10+
**Is your feature request related to a problem? Please describe.**
11+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12+
13+
**Describe the solution you'd like**
14+
A clear and concise description of what you want to happen.
15+
16+
**Describe alternatives you've considered**
17+
A clear and concise description of any alternative solutions or features you've considered.
18+
19+
**Additional context**
20+
Add any other context or screenshots about the feature request here.

CONTRIBUTING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
As I would like to submit this project to the Congressional App
2+
Challenge, I unfortunately cannot accept contributions until Monday,
3+
October 19th, 2020 at the earliest. Kindly hold any issues and pull
4+
requests until then.

README.md

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,35 @@
1-
# Human Computer Simulator
2-
*Human Computer Simulator* is a game where you get to become your
3-
favorite algorithm and or data structure.
4-
5-
# Screenshots
6-
![Level Select](assets/levels.png)
7-
8-
# Download
9-
This software is in an alpha stage of development and I do not plan on
10-
releasing ready-to-run builds until a stable v1.0 release. However, it
11-
is very easy to run it yourself. Just grab the free and open source
12-
[Godot game engine](https://godotengine.org), import the `project.godot`
13-
file, and hit the play button.
1+
<br />
2+
<p align="center">
3+
<img src="assets/icon.png" alt="Logo" width="80" height="80">
4+
5+
<h1 align="center">Human Computer Simulator</h1>
6+
7+
<p align="center">
8+
A game where you get to become your favorite algorithm or data structure!
9+
<br />
10+
<a href="https://github.com/DanielZTing/human-computer-simulator/issues/new?template=bug_report.md">Report Bug</a>
11+
·
12+
<a href="https://github.com/DanielZTing/human-computer-simulator/issues/new?template=feature_request.md">Request Feature</a>
13+
</p>
14+
</p>
15+
16+
## Table of Contents
17+
18+
* [About the Project](#about-the-project)
19+
* [Getting Started](#getting-started)
20+
21+
## About The Project
22+
23+
![Level select screen](assets/levels.png)
24+
25+
You may have come across the famous [15 Sorting Algorithms in 6 Minutes](https://www.youtube.com/watch?v=kPRA0W1kECg) video by [Timo Bingoman](https://github.com/bingmann) at some point in your computer science career. There is currently no shortage of neat visualizations of all kinds of algorithms, but what if you could become the algorithm itself?
26+
27+
In *Human Computer Simulator*, you control an algorithm operating on some data structure. Right now, the game is limited to sorting arrays. The end vision is to have a library of interactive, playable levels on anything from a search on a binary tree to Dijkstra's shortest path on a graph.
28+
29+
It's written using the Godot game engine and licensed with [almost no restrictions](LICENSE.txt). Use it to make a lecture a bit more interesting, review for an assignment, or just kill time. Hope you enjoy.
30+
31+
## Getting Started
32+
33+
This software is in an alpha stage of development and I do not plan on releasing ready-to-run builds until a stable v1.0 release. However, it is very easy to run and hack the source code yourself. Just grab the lightweight free and open source [Godot game engine](https://godotengine.org/download), import the `project.godot` file, and hit the play button.
34+
35+
A demo version (large download warning: ~20 MB) is available on this repository's [Github Pages](https://danielzting.github.io/human-computer-simulator). It requires a desktop browser with support for WebAssembly and WebGL; mobile is not currently supported. Since this is still in alpha, some things might be dumb, make no sense whatsoever, or just break outright. I welcome any feedback you may have.

assets/levels.png

-61 KB
Loading

assets/theme.theme

-5 Bytes
Binary file not shown.

levels/bubble_sort.gd

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ If the two highlighted elements are out of order, hit LEFT ARROW to swap
1414
them. Otherwise, hit RIGHT ARROW to continue.
1515
"""
1616

17+
const ACTIONS = {
18+
"SWAP": "Left",
19+
"CONTINUE": "Right",
20+
}
1721
var _index = 0 # First of two elements being compared
1822
var _end = array.size # Beginning of sorted subarray
1923
var _swapped = false
@@ -27,7 +31,7 @@ func next(action):
2731
return emit_signal("mistake")
2832
array.swap(_index, _index + 1)
2933
_swapped = true
30-
elif action != null and action != ACTIONS.NO_SWAP:
34+
elif action != null and action != ACTIONS.CONTINUE:
3135
return emit_signal("mistake")
3236
_index += 1
3337
# Prevent player from having to spam tap through the end

levels/comparison_sort.gd

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,6 @@ extends Node
44
signal done
55
signal mistake
66

7-
const ACTIONS = {
8-
"SWAP": "ui_left",
9-
"NO_SWAP": "ui_right",
10-
11-
"LEFT": "ui_left",
12-
"RIGHT": "ui_right",
13-
}
14-
157
const EFFECTS = {
168
"NONE": GlobalTheme.GREEN,
179
"HIGHLIGHTED": GlobalTheme.ORANGE,
@@ -22,6 +14,8 @@ const DISABLE_TIME = 1.0
2214

2315
var array: ArrayModel
2416
var active = true
17+
var done = false
18+
var moves = 0
2519

2620
var _timer = Timer.new()
2721

@@ -32,19 +26,29 @@ func _init(array):
3226
_timer.connect("timeout", self, "_on_Timer_timeout")
3327
add_child(_timer)
3428
self.connect("mistake", self, "_on_ComparisonSort_mistake")
29+
self.connect("done", self, "_on_ComparisonSort_done")
3530

3631
func _input(event):
3732
"""Pass input events for checking and take appropriate action."""
38-
if not active:
33+
if done or not active:
3934
return
40-
for action in ACTIONS.values():
41-
if event.is_action_pressed(action):
42-
return next(action)
35+
if event.is_pressed():
36+
moves += 1
37+
return next(event.as_text())
4338

4439
func next(action):
4540
"""Check the action and advance state or emit signal as needed."""
4641
push_error("NotImplementedError")
4742

43+
func get_effect(i):
44+
return get_effect(i)
45+
46+
func _get_effect(i):
47+
push_error("NotImplementedError")
48+
49+
func _on_ComparisonSort_done():
50+
done = true
51+
4852
func _on_ComparisonSort_mistake():
4953
"""Disable the controls for one second."""
5054
active = false

levels/insertion_sort.gd

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ out of order. When this is no longer the case, hit RIGHT ARROW to
1515
advance.
1616
"""
1717

18+
const ACTIONS = {
19+
"SWAP": "Left",
20+
"CONTINUE": "Right",
21+
}
1822
var _end = 1 # Size of the sorted subarray
1923
var _index = 1 # Position of element currently being inserted
2024

@@ -30,14 +34,14 @@ func next(action):
3034
if _index == 0:
3135
_grow()
3236
else:
33-
if action != null and action != ACTIONS.NO_SWAP:
37+
if action != null and action != ACTIONS.CONTINUE:
3438
return emit_signal("mistake")
3539
_grow()
3640

3741
func get_effect(i):
3842
if i == _index or i == _index - 1:
3943
return EFFECTS.HIGHLIGHTED
40-
if i < _end:
44+
if i <= _end:
4145
return EFFECTS.DIMMED
4246
return EFFECTS.NONE
4347

levels/merge_sort.gd

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ highlighted element is on. If you've reached the end of one side, press
1515
the other side's ARROW KEY.
1616
"""
1717

18+
const ACTIONS = {
19+
"LEFT": "Left",
20+
"RIGHT": "Right",
21+
}
1822
var _left = 0 # Index of left subarray pointer
1923
var _right = 1 # Index of right subarray pointer
2024
var _sub_size = 2 # Combined size of left and right subarrays
@@ -27,18 +31,22 @@ func next(action):
2731
if _left == _get_middle():
2832
if action != null and action != ACTIONS.RIGHT:
2933
return emit_signal("mistake")
34+
array.emit_signal("removed", _right)
3035
_right += 1
3136
elif _right == _get_end():
3237
if action != null and action != ACTIONS.LEFT:
3338
return emit_signal("mistake")
39+
array.emit_signal("removed", _left)
3440
_left += 1
3541
elif array.at(_left) <= array.at(_right):
3642
if action != null and action != ACTIONS.LEFT:
3743
return emit_signal("mistake")
44+
array.emit_signal("removed", _left)
3845
_left += 1
3946
else:
4047
if action != null and action != ACTIONS.RIGHT:
4148
return emit_signal("mistake")
49+
array.emit_signal("removed", _right)
4250
_right += 1
4351
# If both ends have been reached, merge and advance to next block
4452
if _left == _get_middle() and _right == _get_end():

levels/quick_sort.gd

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
class_name QuickSort
2+
extends ComparisonSort
3+
4+
const NAME = "QUICKSORT"
5+
const ABOUT = """
6+
Quicksort designates the last element as the pivot and puts everything
7+
less than the pivot before it and everything greater after it. This
8+
partitioning is done by iterating through the array while keeping track
9+
of a pointer initially set to the first element. Every time an element
10+
less than the pivot is encountered, it is swapped with the pointed
11+
element and the pointer moves forward. At the end, the pointer and pivot
12+
are swapped, and the process is repeated on the left and right halves.
13+
"""
14+
const CONTROLS = """
15+
If the highlighted element is less than the pivot or the pivot has been
16+
reached, press LEFT ARROW to swap it with the pointer. Otherwise, press
17+
RIGHT ARROW to move on.
18+
"""
19+
20+
const ACTIONS = {
21+
"SWAP": "Left",
22+
"CONTINUE": "Right",
23+
}
24+
var _index = 0
25+
var _pointer = 0
26+
# Bookkeep simulated recursion with a binary tree of subarray bounds
27+
var _stack = BinaryTreeModel.new(Vector2(0, array.size - 1))
28+
29+
func _init(array).(array):
30+
pass
31+
32+
func next(action):
33+
if _index == _pivot():
34+
if action != null and action != ACTIONS.SWAP:
35+
return emit_signal("mistake")
36+
array.swap(_index, _pointer)
37+
if _pointer - _begin() > 1:
38+
_stack.left = BinaryTreeModel.new(Vector2(_begin(), _pointer - 1))
39+
_stack = _stack.left
40+
elif _pivot() - _pointer > 1:
41+
_stack.right = BinaryTreeModel.new(Vector2(_pointer + 1, _pivot()))
42+
_stack = _stack.right
43+
else:
44+
while (_stack.parent.right != null
45+
or _stack.parent.left.value.y + 2 >= _stack.parent.value.y):
46+
_stack = _stack.parent
47+
if _stack.parent == null:
48+
return emit_signal("done")
49+
_stack.parent.right = BinaryTreeModel.new(Vector2(
50+
_stack.parent.left.value.y + 2, _stack.parent.value.y))
51+
_stack = _stack.parent.right
52+
_index = _begin()
53+
_pointer = _index
54+
elif array.at(_index) < array.at(_pivot()):
55+
if action != null and action != ACTIONS.SWAP:
56+
return emit_signal("mistake")
57+
array.swap(_index, _pointer)
58+
_index += 1
59+
_pointer += 1
60+
else:
61+
if action != null and action != ACTIONS.CONTINUE:
62+
return emit_signal("mistake")
63+
_index += 1
64+
65+
func _begin():
66+
return _stack.value.x
67+
68+
func _pivot():
69+
return _stack.value.y
70+
71+
func get_effect(i):
72+
if i < _begin() or i > _pivot():
73+
return EFFECTS.DIMMED
74+
if i == _index or i == _pivot():
75+
return EFFECTS.HIGHLIGHTED
76+
return EFFECTS.NONE
77+
78+
func get_pointer():
79+
return _pointer

levels/selection_sort.gd

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ smaller than the left highlighted element, then hit LEFT ARROW and
1515
repeat.
1616
"""
1717

18+
const ACTIONS = {
19+
"SWAP": "Left",
20+
"CONTINUE": "Right",
21+
}
1822
var _base = 0 # Size of sorted subarray
1923
var _min = 0 # Index of smallest known element
2024
var _index = 1 # Element currently being compared
@@ -27,7 +31,7 @@ func next(action):
2731
if action != null and action != ACTIONS.SWAP:
2832
return emit_signal("mistake")
2933
_min = _index
30-
elif action != null and action != ACTIONS.NO_SWAP:
34+
elif action != null and action != ACTIONS.CONTINUE:
3135
return emit_signal("mistake")
3236
_index += 1
3337
if _index == array.size:
@@ -44,3 +48,6 @@ func get_effect(i):
4448
if i < _base:
4549
return EFFECTS.DIMMED
4650
return EFFECTS.NONE
51+
52+
func get_pointer():
53+
return _min

0 commit comments

Comments
 (0)