bytecode.cpp and surrounding ideas

This commit is contained in:
Zsolt 2025-01-28 02:56:39 +01:00
parent b21b5079a9
commit ddc9e192a7
7 changed files with 261 additions and 0 deletions

76
ideas/a.txt Normal file
View File

@ -0,0 +1,76 @@
TopVar[0]
TopVar[1]
TopVar[2]
TopVar[3]
Vektator -> [0.. (2 byte index)
V
[t1_A, t1_B, t2_Z, t2_Y, t2_U]
// flottánként van a vektátor memóriaterület, ha túl sok, nem engedünk játszani
enum BYTEKIND
{
IGNORE,
NIL,
NUMBER,
INPUT,
OUTPUT,
OPCODE,
ENGINE,
HARDWARE,
COMM,
};
void f(game_state *gs, ship_tile *st, uint8_t byte_code[4], int byte_index);
bool validate(uint8_t *byte_code, byte_code_element *byte_info)
{
if (bk <= OUTPUT) return true;
bool ok = true;
for (int i = 1; i < 4; ++i)
{
switch(byte_info->at(i))
{
case IGNORE: return true;
case NUMBER: ok &= validate_number(byte_code[i]);
case OUTPUT: ok &= validate_variable(byte_code[i]);
case INPUT: ok &= (validate_number(byte_code[i]) || validate_variable(byte_code[i]));
case HARDWARE: ok &= hardwares.find(byte_code[i]) != hardwares.end();
}
}
return true;
}
#define LEVEL 0
{OPCODE, "HULL", 'H', hull, NUMBER, NUMBER, NUMBER}, // HULL <durability: 0..1> <energy gen> <energy store (between turns)> - first command
{OPCODE, "PAR", 'p', par, OUTPUT, NUMBER, NUMBER}, // PAR <persistant name> <low limit> <high limit> after HULL, before actual code
{OPCODE, "MUL", '*', mul},
{OPCODE, "ADD", '+', add},
{OPCODE, "ENGINE", 'e', nextbyte?, ENGINE, IGNORE, IGNORE},
{OPCODE, "HW", 'h', nextbyte?, HARDWARE, IGNORE, IGNORE},
{OPCODE, "COMM", 'c', nextbyte?, COMM, IGNORE, IGNORE},
#define LEVEL 1
// ENGINE - if multiple ones are set, we choose randomly from the options given
{ENGINE, "north", 'N', NIL, NIL, IGNORE},
{"east", 'E'},
{"west", 'W'},
{"south", 'S'},
// HARDWARE
{HARDWARE, "cannon", 'c', cannon, INPUT, INPUT, IGNORE}, // destroys target ("returns" bool)
{"sonar", 's'}, // shows tile + mine (radar)
{"tracer", 't'}, // ray-trace a line ("returns" bool), doesn't detect mines
{"jumbler", 'j'}, // randomizes parameters on target
{"disruptor", 'd'}, // counters cannons
{"mine", 'm'}, // places a mine (on your tile) that activates after P1 turns. When active and hit, it explodes
{"blow", 'b'}, // blows mines towards a line (move to the next tile that is hit by the line) (should start from the end, so multiple mines don't hit each other)
// COMM
{"write", 'w'}, // HW write <channel> <info> (write a number to a ship-wide channel)
{"read", 'r'}, // HW read <channel> <output> (read a number from a ship-wide channel)
{"gps", 'G'}, // HW gps <output_X> <output_Y> (gets global coordinates)
{"fwrite", 'W'}, // HW write <channel> <info> (write a number to a fleet-wide channel)
{"fread", 'R'}, // HW read <channel> <output> (read a number to a fleet-wide channel)

131
ideas/bytecode.cpp Normal file
View File

@ -0,0 +1,131 @@
#include <string>
#include <map>
#include <stdio.h>
#include <cctype>
#include <vector>
#include <cstdint>
std::string code = "HULL 1 5 10\nPAR A 1 3 \r\nENGINE north\nMUL a A 2\nADD a a 1\nHW cannon A a\nCOMM write 1 5\n";
#define BYTEINFO(bytekind, command, bytecode, func, p1k, p2k, p3k) {command, bytecode},
static std::map<std::string, uint8_t> keywords = {
#include "opcode_list.h"
#include "enginecode_list.h"
#include "hardwarecode_list.h"
#include "commcode_list.h"
};
void write_file_bytes(const char* filename, std::vector<uint8_t>& bytes)
{
FILE * f = fopen(filename, "w");
fwrite(&bytes[0], 1, bytes.size(), f);
fclose(f);
}
bool add_if_number(std::vector<uint8_t> &result_code, const std::string &token)
{
unsigned int i = 0;
int num = 0;
int sign = 1;
if (token.length() > 4) return false;
if (token[0] == '-')
{
sign = -1;
++i;
}
else if (token[0] == '+')
{
++i;
}
if (i >= token.length()) return false;
while(i < token.length())
{
char c = token[i];
if (c >= '0' && c<='9')
{
num = num * 10 + c - '0';
}
else
{
return false;
}
++i;
}
if (num > 100) return false;
num = sign * num + 0x99; //0 -> 0x99, 1 -> 0x9A, 2 -> 0x9B, ... (variables -> [0..52])
result_code.push_back((uint8_t)num);
return true;
}
bool add_if_variable(std::vector<uint8_t> &result_code, const std::string &token)
{
if (token.length() != 1) return false;
uint8_t c = token[0];
if (c >= 'a' && c <= 'z')
{
result_code.push_back(c - 'a');
return true;
}
else if (c >= 'A' && c <= 'Z')
{
result_code.push_back(c - 'A' + 'z' - 'a' + 1);
return true;
}
return false;
}
bool add_if_keyword(std::vector<uint8_t> &result_code, const std::string &token)
{
auto token_it = keywords.find(token);
if (token_it == keywords.end())
{
return false;
}
result_code.push_back(token_it->second);
return true;
}
int main()
{
std::vector<uint8_t> result_code;
unsigned int start = 0;
int remaining = 0;
for (unsigned int i = 0; i<code.length(); ++i)
{
if (isspace(code[i]))
{
if (start < i)
{
remaining = (remaining + 3) % 4;
std::string token = code.substr(start, i - start);
printf("%s %d\n", token.c_str(), remaining);
if (!add_if_variable(result_code, token)
&& !add_if_number(result_code, token)
&& !add_if_keyword(result_code, token)
)
{
printf("Unknown token: %s\n", token.c_str());
result_code.push_back('?');
}
}
if (code[i] == '\n')
{
for (int j = 0; j< remaining; ++j)
{
printf("NULL\n");
result_code.push_back(0);
}
remaining = 0;
}
start = i + 1;
}
}
write_file_bytes("bytecode.sbc", result_code);
}

17
ideas/bytekind.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef __BYTEKIND__
#define __BYTEKIND__
enum class BYTEKIND
{
IGNORE,
NIL,
NUMBER,
INPUT,
OUTPUT,
OPCODE,
ENGINE,
HARDWARE,
COMM,
};
#endif

5
ideas/commcode_list.h Normal file
View File

@ -0,0 +1,5 @@
BYTEINFO(COMM, "write", 'w', ship_write, INPUT, INPUT, IGNORE) // COMM write <info> <channel> (write a number to a ship-wide channel)
BYTEINFO(COMM, "read", 'r', ship_read, OUTPUT, INPUT, IGNORE) // COMM read <output> <channel> (read a number from a ship-wide channel)
BYTEINFO(COMM, "gps", 'G', gps, OUTPUT, OUTPUT, IGNORE) // COMM gps <output_X> <output_Y> (gets global coordinates)
BYTEINFO(COMM, "fwrite", 'W', fleet_write, INPUT, INPUT, IGNORE) // COMM write <info> <channel> (write a number to a fleet-wide channel)
BYTEINFO(COMM, "fread", 'R', fleet_read, OUTPUT, INPUT, IGNORE) // COMM read <output> <channel> (read a number to a fleet-wide channel)

4
ideas/enginecode_list.h Normal file
View File

@ -0,0 +1,4 @@
BYTEINFO(ENGINE, "north", 'N', north, IGNORE, IGNORE, IGNORE)
BYTEINFO(ENGINE, "east", 'E', north, IGNORE, IGNORE, IGNORE)
BYTEINFO(ENGINE, "west", 'W', north, IGNORE, IGNORE, IGNORE)
BYTEINFO(ENGINE, "south", 'S', north, IGNORE, IGNORE, IGNORE)

View File

@ -0,0 +1,8 @@
BYTEINFO(HARDWARE, "cannon", 'c', cannon, INPUT, INPUT, IGNORE) // destroys target ("returns" bool)
BYTEINFO(HARDWARE, "sonar", 's', sonar, INPUT, INPUT, IGNORE) // shows tile + mine (radar) (or only say if it is something on the tile? - the turn the command was given, or the next turn?
BYTEINFO(HARDWARE, "tracer", 't', tracer, INPUT, INPUT, IGNORE) // ray-trace a line ("returns" bool), doesn't detect mines
BYTEINFO(HARDWARE, "jumbler", 'j', jumbler, INPUT, INPUT, IGNORE) // randomizes parameters on target
BYTEINFO(HARDWARE, "disruptor", 'd', disruptor, INPUT, INPUT, IGNORE) // counters cannons
BYTEINFO(HARDWARE, "mine", 'm', mine, INPUT, INPUT, IGNORE) // places a mine (on your tile) that activates after P1 turns. When active and hit, it explodes
BYTEINFO(HARDWARE, "blow", 'b', blow, INPUT, INPUT, IGNORE) // blows mines towards a line (move to the next tile that is hit by the line) (should start from the end, so multiple mines don't hit each other)

20
ideas/opcode_list.h Normal file
View File

@ -0,0 +1,20 @@
BYTEINFO(OPCODE, "HULL", 'H', hull, NUMBER, NUMBER, NUMBER) // HULL <durability: 0..1> <energy gen> <energy store (between turns)> - first command
BYTEINFO(OPCODE, "PAR", 'p', par, OUTPUT, NUMBER, NUMBER) // PAR <persistant name> <low limit> <high limit> after HULL, before actual code
BYTEINFO(OPCODE, "MUL", '*', mul, OUTPUT, INPUT, INPUT)
BYTEINFO(OPCODE, "ADD", '+', add, OUTPUT, INPUT, INPUT)
BYTEINFO(OPCODE, "SUB", '-', sub, OUTPUT, INPUT, INPUT)
BYTEINFO(OPCODE, "DIV", '/', div, OUTPUT, INPUT, INPUT)
BYTEINFO(OPCODE, "SET", ':', set, OUTPUT, INPUT, IGNORE)
BYTEINFO(OPCODE, "EQ", '=', eq, OUTPUT, INPUT, INPUT)
BYTEINFO(OPCODE, "LESS", '<', less, OUTPUT, INPUT, INPUT)
BYTEINFO(OPCODE, "MORE", '>', more, OUTPUT, INPUT, INPUT)
BYTEINFO(OPCODE, "NOT", '!', not_op, OUTPUT, INPUT, IGNORE)
BYTEINFO(OPCODE, "OR", '|', or_op, OUTPUT, INPUT, INPUT)
BYTEINFO(OPCODE, "AND", '&', and_op, OUTPUT, INPUT, INPUT)
BYTEINFO(OPCODE, "XOR", 'x', xor_op, OUTPUT, INPUT, INPUT)
BYTEINFO(OPCODE, "RAND", 'r', rand, OUTPUT, INPUT, INPUT) // random number between P1 and P2 - should we include p2?
BYTEINFO(OPCODE, "SKIP", 's', skip, INPUT, IGNORE, IGNORE) // SKIP 1 skips the next instruction (4 bytes), SKIP 0 = NOP, SKIP 10 skips the next 10 instructions. P1 >= 0
BYTEINFO(OPCODE, "STOP", 'S', stop, IGNORE, IGNORE, IGNORE) // equivalent to SKIP infinite
BYTEINFO(OPCODE, "ENGINE", 'e', engine, ENGINE, NIL, NIL) // ENGINE - if multiple ones are set, we choose randomly from the options given
BYTEINFO(OPCODE, "HW", 'h', hardware, HARDWARE, IGNORE, IGNORE)
BYTEINFO(OPCODE, "COMM", 'c', comm, COMM, IGNORE, IGNORE)