Skip to content

Instantly share code, notes, and snippets.

@myndzi
Last active April 22, 2017 02:21
Show Gist options
  • Save myndzi/950207f5d531aec1dae9d3804f75b9b6 to your computer and use it in GitHub Desktop.
Save myndzi/950207f5d531aec1dae9d3804f75b9b6 to your computer and use it in GitHub Desktop.
// values 0 through 6 represent tetris pieces
// heap[1] is always the piece that has been seen the
// fewest number of times (or is tied with it)
heap = [unused, 0, 1, 2, 3, 4, 5, 6]
update(piece_id) {
// find the piece to update
for (ptr = 1; ptr <= 8; ptr++) {
if (heap[ptr] & 0x07 == piece_id) break;
}
if (ptr == 8) {
// piece_id was not valid; do nothing
return;
}
if (heap[ptr] >= 0xF8) {
// we're at the max possible value, we need to reduce everything
// so we have headroom
reduce_heap();
}
if (heap[ptr] < 0xF8) {
// increment seen-count
// it's possible that reduce_heap() had no effect, so we have
// to check the bounds once more, here
heap[ptr] += 8;
} else {
// we didn't change anything, no need to update heap
// optional early exit
return;
}
// update heap
// this could be written as an unrolled loop if you have
// more instructions available than cycles, since the size
// of the heap is bounded -- max swaps will be 2
while (ptr <= 3) {
// positions > 3 have no children and can't move down any farther
child = heap[2*ptr];
if (heap[child] > heap[child+1]) {
// it's a min-heap, so we swap with the smallest child;
// children are located at loc*2 and loc*2+1, so we compare
// loc*2 (child) with loc*2+1 (child+1), and if child is
// larger, we change it to point to child+1
child++;
}
if (heap[ptr] <= heap[child]) {
// ptr is not larger than its children, heap property
// is satisfied
return;
}
// swap children (xor swap); using a temp var
// might be faster, depending?
heap[ptr] = heap[ptr] ^ heap[child];
heap[child] = heap[ptr] ^ heap[child];
heap[ptr] = heap[ptr] ^ heap[child];
// the value we updated (ptr) is now at index child
ptr = child;
}
}
reduce_heap() {
// chop off the piece value so we only change the count
min = heap[1] & 0xF8;
if (min == 0) {
// nothing to do; optional early exit
return;
}
for (ptr = 1; ptr <= 7; ptr++) {
// the heap property guarantees every value is greater than
// or equal to the first index (min-heap), so this subtraction
// should always result in a count >= 0
heap[ptr] -= min;
}
}
// MRU list for fun. may not be particularly optimized?
// index = piece id, from 0-6; index 7 points to
// the head of the list. list[7] is always the
// most-recently-seen piece
list = [1, 2, 3, 4, 5, 6, 255, 0]
update(piece_id) {
if (piece_id > 6) {
// invalid piece id
return;
}
// find the item in the list that points to piece_id
ptr = list[7];
// a for-loop would be safer here, in case the links
// got messed up, but this approach should be fewer
// cycles?
while (list[ptr] != piece_id) { ptr = list[ptr]; }
// A->B->C => A->C
list[ptr] = list[piece_id];
// B->C => B->X
list[piece_id] = list[7];
// HEAD->X => HEAD->B
list[7] = piece_id;
}
get_oldest() {
ptr = list[7];
// move the pointer 6 times to get the 7th value
for (i = 0; i <= 5; i++) {
ptr = list[ptr];
}
return ptr;
}
// or:
get_oldest() {
ptr = list[7];
ptr = list[ptr];
ptr = list[ptr];
ptr = list[ptr];
ptr = list[ptr];
ptr = list[ptr];
ptr = list[ptr];
return ptr;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment