typetui 0.2.1

A terminal-based typing test.
Documentation
main :: () {
    player := Player.{"Hero", 100, 50, .{0, 0}};
    print("Player: % at position %\n", player.name, player.position);
    
    player.heal(25);
    player.take_damage(10);
    print("Player health: %/%\n", player.health, player.max_health);
    
    move_player(*player, .{10, 5});
    print("New position: %\n", player.position);
    
    game := Game.{
        title = "Adventure",
        player = player,
        enemies = .[
            .{"Orc", 50, 50, .{100, 100}},
            .{"Goblin", 30, 30, .{150, 200}},
        ]
    };
    
    print("Game '%' has % enemies\n", game.title, game.enemies.count);
    
    value: Value;
    value.type = .INTEGER;
    value.data.integer = 42;
    print_value(value);
    
    value.type = .FLOAT;
    value.data.floating = 3.14;
    print_value(value);
    
    value.type = .STRING;
    value.data.str = "Hello";
    print_value(value);
    
    tagged: TaggedValue = .{type = .Int, int_val = 100};
    print_tagged(tagged);
    
    tagged = .{type = .Float, float_val = 2.718};
    print_tagged(tagged);
    
    list: LinkedList(int);
    defer free_list(*list);
    
    list_append(*list, 10);
    list_append(*list, 20);
    list_append(*list, 30);
    
    print_list(list);
    
    numbers: [..]int;
    defer array_reset(*numbers);
    
    for 1..5 array_add(*numbers, it * it);
    print("Squares: %\n", numbers);
    
    found, index := array_find(numbers, 16);
    if found print("Found 16 at index %\n", index);
    
    array_ordered_remove_by_index(*numbers, 2);
    print("After remove: %\n", numbers);
    
    unsorted: [..]int = .[5, 2, 8, 1, 9, 3];
    bubble_sort(unsorted);
    print("Sorted: %\n", unsorted);
    
    map := create_map(string, int);
    defer free_map(*map);
    
    map_insert(*map, "one", 1);
    map_insert(*map, "two", 2);
    map_insert(*map, "three", 3);
    
    val, ok := map_get(map, "two");
    if ok print("map['two'] = %\n", val);
    
    tree: *TreeNode(int);
    defer free_tree(tree);
    
    tree_insert(*tree, 50);
    tree_insert(*tree, 30);
    tree_insert(*tree, 70);
    tree_insert(*tree, 20);
    tree_insert(*tree, 40);
    
    print("Inorder: ");
    inorder_traversal(tree);
    print("\n");
    
    found_node := tree_search(tree, 40);
    print("Search 40: %\n", ifx found_node then "found" else "not found");
}

Vector2 :: struct {
    x: float;
    y: float;
}

Player :: struct {
    name: string;
    health: int;
    max_health: int;
    position: Vector2;
    
    heal :: (p: *Player, amount: int) {
        p.health = min(p.health + amount, p.max_health);
    }
    
    take_damage :: (p: *Player, amount: int) {
        p.health = max(p.health - amount, 0);
    }
}

move_player :: (p: *Player, delta: Vector2) {
    p.position.x += delta.x;
    p.position.y += delta.y;
}

Game :: struct {
    title: string;
    player: Player;
    enemies: [..]Player;
}

ValueType :: enum {
    INTEGER;
    FLOAT;
    STRING;
}

ValueData :: union {
    integer: int;
    floating: float64;
    str: string;
}

Value :: struct {
    type: ValueType;
    data: ValueData;
}

print_value :: (v: Value) {
    if v.type == {
        case .INTEGER; print("Integer: %\n", v.data.integer);
        case .FLOAT;   print("Float: %\n", v.data.floating);
        case .STRING;  print("String: %\n", v.data.str);
    }
}

TaggedValue :: struct #tagged_union {
    type: enum {
        Int;
        Float;
        Text;
    }
    
    #as u64 using type;
    
    int_val:   int    #only_if type == .Int;
    float_val: float64 #only_if type == .Float;
    text_val:  string #only_if type == .Text;
}

print_tagged :: (v: TaggedValue) {
    if #complete v.type == {
        case .Int;   print("Tagged int: %\n", v.int_val);
        case .Float; print("Tagged float: %\n", v.float_val);
        case .Text;  print("Tagged text: %\n", v.text_val);
    }
}

ListNode :: struct ($T: Type) {
    value: T;
    next: *ListNode(T);
}

LinkedList :: struct ($T: Type) {
    head: *ListNode(T);
    tail: *ListNode(T);
}

list_append :: (list: *LinkedList($T), value: T) {
    node := New(ListNode(T));
    node.value = value;
    
    if list.head == null {
        list.head = node;
        list.tail = node;
    } else {
        list.tail.next = node;
        list.tail = node;
    }
}

free_list :: (list: *LinkedList($T)) {
    current := list.head;
    while current != null {
        next := current.next;
        free(current);
        current = next;
    }
    list.* = .{};
}

print_list :: (list: LinkedList($T)) {
    current := list.head;
    print("List: ");
    while current != null {
        print("% ", current.value);
        current = current.next;
    }
    print("\n");
}

bubble_sort :: (arr: [..]$T) {
    for i: 0..arr.count-1 {
        for j: 0..arr.count-i-2 {
            if arr[j] > arr[j+1] {
                tmp := arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = tmp;
            }
        }
    }
}

SimpleMap :: struct ($K: Type, $V: Type) {
    keys: [..]K;
    values: [..]V;
}

create_map :: ($K: Type, $V: Type) -> SimpleMap(K, V) {
    return .{};
}

free_map :: (map: *SimpleMap($K, $V)) {
    array_reset(*map.keys);
    array_reset(*map.values);
}

map_insert :: (map: *SimpleMap($K, $V), key: K, value: V) {
    for map.keys {
        if it == key {
            map.values[it_index] = value;
            return;
        }
    }
    array_add(*map.keys, key);
    array_add(*map.values, value);
}

map_get :: (map: SimpleMap($K, $V), key: K) -> (V, bool) {
    for map.keys {
        if it == key {
            return map.values[it_index], true;
        }
    }
    return .{}, false;
}

TreeNode :: struct ($T: Type) {
    value: T;
    left: *TreeNode(T);
    right: *TreeNode(T);
}

tree_insert :: (root: **TreeNode($T), value: T) {
    if root.* == null {
        root.* = New(TreeNode(T));
        root.*.value = value;
        return;
    }
    
    if value < root.*.value {
        tree_insert(*root.*.left, value);
    } else {
        tree_insert(*root.*.right, value);
    }
}

tree_search :: (root: *TreeNode($T), value: T) -> bool {
    if root == null return false;
    if value == root.value return true;
    if value < root.value return tree_search(root.left, value);
    return tree_search(root.right, value);
}

inorder_traversal :: (root: *TreeNode($T)) {
    if root == null return;
    inorder_traversal(root.left);
    print("% ", root.value);
    inorder_traversal(root.right);
}

free_tree :: (root: *TreeNode($T)) {
    if root == null return;
    free_tree(root.left);
    free_tree(root.right);
    free(root);
}

#import "Basic";