corewar

šŸ¤– Corewar, a programming game in which two or more battle programs compete for control of a virtual computer. These battle programs are written in an abstract assembly language.

View the Project on GitHub rizkyario/corewar

Corewar

A game that takes place in a virtual arena where programs written in a simplistic language fight one another. They attempt to stop each other by overwriting instructions that are about to be executed.

We explored the design of a VM (with the relevant instructions, records, etc.) and challenges related to compiling an assembly language into bytecode.

Installation:

git clone --recurse-submodules https://github.com/rizkyario/corewar.git && cd corewar && make

Wiki

Usage:

Assembler:

usage: ./asm [-a] sourcefile.s
       ./asm [-a] [-m] sourcefile.s ...
    -a : Prints a stripped and annoted version of the code
    -m : Allows processing of multiple files

asm_usage_gif

make assemble: compile every player within subdirectory tests/

Virtual Machine:

usage: ./corewar [options] [-n number] champion1.cor ...

OPTIONS
       -dump  nbr_cycles  : Dump the memory after nbr_cycles
       -dumpc nbr_cycles  : Colorized -dump
       -v N : Verbosity levels, can be added together to enable several
                - 2  : Show cycles
                - 4  : Show operations
                - 8  : Show deaths
                - 16 : Show PC movements (Except for jumps)
       -u : Decompile .cor back to .s
       -g : Printf  visualization
       -G : Ncurses visualization

vm_usage_gif

In action:

Visualizer using printf:

corewar in action_printf

Visualizer using ncurses:

corewar_in_action_ncurses

Test Suite:

make tests: run an extensive set of tests of both the assembler and virtual machine\ make tests_asm: test only the assembler\ make tests_vm : test only the virtual machine

All test cases:

<img src=ā€https://github.com/rizkyario/corewar/blob/assets/make_tests_large.pngā€ width=80%>

Code snippets:

Assembler:

Parsing with our own regex library:

int asm_get_paramtype(int opcode, t_param *param)
{
	if (ft_re_match("^r\\d+$", (*param).str) == 0)
	{
		(*param).value = asm_get_paramval((*param).str, "\\d+");
		(*param).size = 1;
		return (T_REG);
	}
	else if (ft_re_match("^%:[\\w_\\d]+$", (*param).str) == 0 ||
                     ft_re_match("^%-?\\d+$", (*param).str) == 0)
	{
		(ft_re_match("^%:[\\w_\\d]+$", (*param).str) == 0) ?
			(*param).is_label = 1 : 0;
		(*param).value = asm_get_paramval((*param).str, "-?\\d+");
		(*param).size = g_op_dict[opcode].d_size;
		return (T_DIR);
	}
	else if (ft_re_match("^:[\\w_\\d]+$", (*param).str) == 0 ||
			ft_re_match("^-?\\d+$", (*param).str) == 0)
	{
		!ft_re_match(":[\\w_\\d]+$", (*param).str) ? (*param).is_label = 1 : 0;
		(*param).value = asm_get_paramval((*param).str, "-?\\d+");
		(*param).size = 2;
		return (T_IND);
	}
	else
		return (-1);
}

Virtual Machine:

Main function:

int         main(int ac, char **av)
{
    t_vm            vm;
    time_t          start;
    static t_array  processes = NEW_ARRAY(t_process);

    ft_bzero(&vm, sizeof(t_vm));
    vm.processes = processes;
    if (ac < 2 || vm_options(av, &vm) == -1)
        return (vm_print_usage(av, -1));
    if (vm_get_champions(av, &vm) == -1)
        return (vm_error(vm.champ_size < 1 ? CHAMP_MIN : CHAMP_MAX, -1, NULL));
    if (vm_read_binaries(vm.players, &vm) == -1)
        return (-1);
    vm_load_champs(&vm);
    while (vm_checker(&vm))
    {
        vm_executor(&vm);
        if ((vm.dump && vm.cycles == g_cycles) ||
            (vm.option_g[VISU_2] && vm_start_ncurses(&start, vm) == -1))
            break ;
    }
    (!vm.dump || g_cycles < vm.cycles) ?
    ft_printfln("Contestant %d, \"%s\", has won !",
        vm.winner + 1, vm.champ[vm.winner].header.prog_name) : 0;
    vm_free(&vm);
    return (0);
}

For a closer look at the projectā€™s development history, refer to the branches ā€˜feature/assemblerā€™ and ā€˜feature/virtual-machineā€™

Credits

Collaboration between

Rizky Ario Fabian Petras Julianto Yeo Martin Jozan