mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-08 14:58:14 +03:00
This also fixes a bug of vmArray.AroundRect (although it does not affect Mamanyonyo).
941 lines
26 KiB
C
941 lines
26 KiB
C
/* Copyright (C) 2024 kichikuou <KichikuouChrome@gmail.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
|
|
#include "hll.h"
|
|
#include "vm/page.h"
|
|
|
|
static bool is_even(int x) { return !(x & 1); }
|
|
static bool is_odd(int x) { return x & 1; }
|
|
|
|
static void check_array(struct page *array)
|
|
{
|
|
if (array->type != ARRAY_PAGE || array->a_type != AIN_ARRAY_INT || array->array.rank != 1)
|
|
VM_ERROR("Not a flat integer array");
|
|
}
|
|
|
|
//int vmArray_GetAdd(struct page *array, int index);
|
|
//int vmArray_GetSub(struct page *array, int index);
|
|
//int vmArray_GetMul(struct page *array, int index);
|
|
//int vmArray_GetDiv(struct page *array, int index);
|
|
//int vmArray_GetAnd(struct page *array, int index);
|
|
//int vmArray_GetOr(struct page *array, int index);
|
|
//int vmArray_GetXor(struct page *array, int index);
|
|
|
|
static void transform(struct page *array, int index, int (*func)(int, void *), void *data)
|
|
{
|
|
if (!array)
|
|
return;
|
|
check_array(array);
|
|
|
|
if (index >= 0) {
|
|
for (int i = index; i < array->nr_vars; i++) {
|
|
array->values[i].i = func(array->values[i].i, data);
|
|
}
|
|
} else {
|
|
for (int i = -index - 1; i >= 0; --i) {
|
|
array->values[i].i = func(array->values[i].i, data);
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline int32_t clamp(int64_t val)
|
|
{
|
|
if (val > INT32_MAX)
|
|
return INT32_MAX;
|
|
if (val < INT32_MIN)
|
|
return INT32_MIN;
|
|
return val;
|
|
}
|
|
|
|
static int trans_add(int x, void *data)
|
|
{
|
|
int64_t y = *(int*)data;
|
|
return clamp(x + y);
|
|
}
|
|
|
|
static int trans_sub(int x, void *data)
|
|
{
|
|
int64_t y = *(int*)data;
|
|
return clamp(x - y);
|
|
}
|
|
|
|
static int trans_mul(int x, void *data)
|
|
{
|
|
int64_t y = *(int*)data;
|
|
return clamp(x * y);
|
|
}
|
|
|
|
static int trans_div(int x, void *data)
|
|
{
|
|
int64_t y = *(int*)data;
|
|
return clamp(x / y);
|
|
}
|
|
|
|
static int trans_and(int x, void *data)
|
|
{
|
|
int y = *(int*)data;
|
|
return x & y;
|
|
}
|
|
|
|
static int trans_or(int x, void *data)
|
|
{
|
|
int y = *(int*)data;
|
|
return x | y;
|
|
}
|
|
|
|
static int trans_xor(int x, void *data)
|
|
{
|
|
int y = *(int*)data;
|
|
return x ^ y;
|
|
}
|
|
|
|
static void vmArray_AddNum(struct page **array, int index, int num)
|
|
{
|
|
transform(*array, index, trans_add, &num);
|
|
}
|
|
|
|
static void vmArray_SubNum(struct page **array, int index, int num)
|
|
{
|
|
transform(*array, index, trans_sub, &num);
|
|
}
|
|
|
|
static void vmArray_MulNum(struct page **array, int index, int num)
|
|
{
|
|
transform(*array, index, trans_mul, &num);
|
|
}
|
|
|
|
static void vmArray_DivNum(struct page **array, int index, int num)
|
|
{
|
|
if (num != 0)
|
|
transform(*array, index, trans_div, &num);
|
|
}
|
|
|
|
static void vmArray_AndNum(struct page **array, int index, int num)
|
|
{
|
|
transform(*array, index, trans_and, &num);
|
|
}
|
|
|
|
static void vmArray_OrNum(struct page **array, int index, int num)
|
|
{
|
|
transform(*array, index, trans_or, &num);
|
|
}
|
|
|
|
static void vmArray_XorNum(struct page **array, int index, int num)
|
|
{
|
|
transform(*array, index, trans_xor, &num);
|
|
}
|
|
|
|
//void vmArray_MinNum(struct page **array, int index, int num);
|
|
//void vmArray_MaxNum(struct page **array, int index, int num);
|
|
|
|
struct vmarray_iter {
|
|
struct page *array;
|
|
int index;
|
|
};
|
|
|
|
static int trans_add_array(int x, void *data)
|
|
{
|
|
struct vmarray_iter *iter = data;
|
|
return clamp((int64_t)x + iter->array->values[iter->index++].i);
|
|
}
|
|
|
|
static int trans_sub_array(int x, void *data)
|
|
{
|
|
struct vmarray_iter *iter = data;
|
|
return clamp((int64_t)x - iter->array->values[iter->index++].i);
|
|
}
|
|
|
|
static int trans_mul_array(int x, void *data)
|
|
{
|
|
struct vmarray_iter *iter = data;
|
|
return clamp((int64_t)x * iter->array->values[iter->index++].i);
|
|
}
|
|
|
|
static int trans_div_array(int x, void *data)
|
|
{
|
|
struct vmarray_iter *iter = data;
|
|
int rhs = iter->array->values[iter->index++].i;
|
|
return rhs ? x / rhs : x;
|
|
}
|
|
|
|
static int trans_and_array(int x, void *data)
|
|
{
|
|
struct vmarray_iter *iter = data;
|
|
return x & iter->array->values[iter->index++].i;
|
|
}
|
|
|
|
static int trans_or_array(int x, void *data)
|
|
{
|
|
struct vmarray_iter *iter = data;
|
|
return x | iter->array->values[iter->index++].i;
|
|
}
|
|
|
|
static int trans_xor_array(int x, void *data)
|
|
{
|
|
struct vmarray_iter *iter = data;
|
|
return x ^ iter->array->values[iter->index++].i;
|
|
}
|
|
|
|
static void vmArray_AddArray(struct page **d_array, int index, struct page *s_array)
|
|
{
|
|
struct vmarray_iter iter = { s_array, 0 };
|
|
transform(*d_array, index, trans_add_array, &iter);
|
|
}
|
|
|
|
static void vmArray_SubArray(struct page **d_array, int index, struct page *s_array)
|
|
{
|
|
struct vmarray_iter iter = { s_array, 0 };
|
|
transform(*d_array, index, trans_sub_array, &iter);
|
|
}
|
|
|
|
static void vmArray_MulArray(struct page **d_array, int index, struct page *s_array)
|
|
{
|
|
struct vmarray_iter iter = { s_array, 0 };
|
|
transform(*d_array, index, trans_mul_array, &iter);
|
|
}
|
|
|
|
static void vmArray_DivArray(struct page **d_array, int index, struct page *s_array)
|
|
{
|
|
struct vmarray_iter iter = { s_array, 0 };
|
|
transform(*d_array, index, trans_div_array, &iter);
|
|
}
|
|
|
|
static void vmArray_AndArray(struct page **d_array, int index, struct page *s_array)
|
|
{
|
|
struct vmarray_iter iter = { s_array, 0 };
|
|
transform(*d_array, index, trans_and_array, &iter);
|
|
}
|
|
|
|
static void vmArray_OrArray(struct page **d_array, int index, struct page *s_array)
|
|
{
|
|
struct vmarray_iter iter = { s_array, 0 };
|
|
transform(*d_array, index, trans_or_array, &iter);
|
|
}
|
|
|
|
static void vmArray_XorArray(struct page **d_array, int index, struct page *s_array)
|
|
{
|
|
struct vmarray_iter iter = { s_array, 0 };
|
|
transform(*d_array, index, trans_xor_array, &iter);
|
|
}
|
|
|
|
//void vmArray_MinArray(struct page **d_array, int index, struct page *s_array);
|
|
//void vmArray_MaxArray(struct page **d_array, int index, struct page *s_array);
|
|
|
|
static bool pred_equal(int x, void *data)
|
|
{
|
|
int y = *(int*)data;
|
|
return x == y;
|
|
}
|
|
|
|
static bool pred_not_equal(int x, void *data)
|
|
{
|
|
int y = *(int*)data;
|
|
return x != y;
|
|
}
|
|
|
|
static bool pred_low(int x, void *data)
|
|
{
|
|
int y = *(int*)data;
|
|
return x <= y;
|
|
}
|
|
|
|
static bool pred_high(int x, void *data)
|
|
{
|
|
int y = *(int*)data;
|
|
return y <= x;
|
|
}
|
|
|
|
struct range {
|
|
int min;
|
|
int max;
|
|
};
|
|
|
|
static bool pred_in_range(int x, void *data)
|
|
{
|
|
struct range *r = data;
|
|
return r->min <= x && x <= r->max;
|
|
}
|
|
|
|
static int count_if(struct page *array, int index, bool (*pred)(int, void *), void *data)
|
|
{
|
|
if (!array)
|
|
return 0;
|
|
check_array(array);
|
|
|
|
int count = 0;
|
|
for (int i = index; i < array->nr_vars; i++) {
|
|
if (pred(array->values[i].i, data))
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
static int vmArray_EnumEquNum(struct page *array, int index, int num)
|
|
{
|
|
return count_if(array, index, pred_equal, &num);
|
|
}
|
|
|
|
static int vmArray_EnumNotNum(struct page *array, int index, int num)
|
|
{
|
|
return count_if(array, index, pred_not_equal, &num);
|
|
}
|
|
|
|
static int vmArray_EnumLowNum(struct page *array, int index, int num)
|
|
{
|
|
return count_if(array, index, pred_low, &num);
|
|
}
|
|
|
|
static int vmArray_EnumHighNum(struct page *array, int index, int num)
|
|
{
|
|
return count_if(array, index, pred_high, &num);
|
|
}
|
|
|
|
static int vmArray_EnumRangeNum(struct page *array, int index, int min, int max)
|
|
{
|
|
struct range r = { .min = min, .max = max };
|
|
return count_if(array, index, pred_in_range, &r);
|
|
}
|
|
|
|
static void replace(struct page *array, int index, int n, bool (*pred)(int, void *), void *data)
|
|
{
|
|
if (!array)
|
|
return;
|
|
check_array(array);
|
|
|
|
for (int i = index; i < array->nr_vars; i++) {
|
|
if (pred(array->values[i].i, data))
|
|
array->values[i].i = n;
|
|
}
|
|
}
|
|
|
|
static void vmArray_ChangeEquNum(struct page **array, int index, int num, int exg)
|
|
{
|
|
replace(*array, index, exg, pred_equal, &num);
|
|
}
|
|
|
|
static void vmArray_ChangeNotNum(struct page **array, int index, int num, int exg)
|
|
{
|
|
replace(*array, index, exg, pred_not_equal, &num);
|
|
}
|
|
|
|
static void vmArray_ChangeLowNum(struct page **array, int index, int num, int exg)
|
|
{
|
|
replace(*array, index, exg, pred_low, &num);
|
|
}
|
|
|
|
static void vmArray_ChangeHighNum(struct page **array, int index, int num, int exg)
|
|
{
|
|
replace(*array, index, exg, pred_high, &num);
|
|
}
|
|
|
|
static void vmArray_ChangeRangeNum(struct page **array, int index, int min, int max, int exg)
|
|
{
|
|
struct range r = { .min = min, .max = max };
|
|
replace(*array, index, exg, pred_in_range, &r);
|
|
}
|
|
|
|
static int find(struct page *array, int index, bool (*pred)(int, void *), void *data, int *out_index)
|
|
{
|
|
if (!array)
|
|
return 0;
|
|
check_array(array);
|
|
|
|
if (index >= 0) {
|
|
for (int i = index; i < array->nr_vars; i++) {
|
|
if (pred(array->values[i].i, data)) {
|
|
*out_index = i;
|
|
return 1;
|
|
}
|
|
}
|
|
} else {
|
|
for (int i = -index - 1; i >= 0; --i) {
|
|
if (pred(array->values[i].i, data)) {
|
|
*out_index = i;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int vmArray_GrepEquNum(struct page *array, int index, int num, int *out_index)
|
|
{
|
|
return find(array, index, pred_equal, &num, out_index);
|
|
}
|
|
|
|
static int vmArray_GrepNotNum(struct page *array, int index, int num, int *out_index)
|
|
{
|
|
return find(array, index, pred_not_equal, &num, out_index);
|
|
}
|
|
|
|
static int vmArray_GrepLowNum(struct page *array, int index, int num, int *out_index)
|
|
{
|
|
return find(array, index, pred_low, &num, out_index);
|
|
}
|
|
|
|
static int vmArray_GrepHighNum(struct page *array, int index, int num, int *out_index)
|
|
{
|
|
return find(array, index, pred_high, &num, out_index);
|
|
}
|
|
|
|
static int vmArray_GrepRangeNum(struct page *array, int index, int min, int max, int *out_index)
|
|
{
|
|
struct range r = { .min = min, .max = max };
|
|
return find(array, index, pred_in_range, &r, out_index);
|
|
}
|
|
|
|
static int vmArray_GrepLowOrder(struct page *s_array, int index, struct page **d_array_, int *out_index)
|
|
{
|
|
struct page *d_array = *d_array_;
|
|
check_array(s_array);
|
|
check_array(d_array);
|
|
|
|
if (index < 0)
|
|
VM_ERROR("not implemented");
|
|
|
|
int min_index = -1, min_value;
|
|
for (int i = index; i < s_array->nr_vars; i++) {
|
|
if (d_array->values[i].i)
|
|
continue;
|
|
int val = s_array->values[i].i;
|
|
if (min_index < 0 || val < min_value) {
|
|
min_index = i;
|
|
min_value = val;
|
|
}
|
|
}
|
|
if (min_index < 0)
|
|
return 0;
|
|
*out_index = min_index;
|
|
d_array->values[min_index].i = 1;
|
|
return 1;
|
|
}
|
|
|
|
static int vmArray_GrepHighOrder(struct page *s_array, int index, struct page **d_array_, int *out_index)
|
|
{
|
|
struct page *d_array = *d_array_;
|
|
check_array(s_array);
|
|
check_array(d_array);
|
|
|
|
if (index < 0)
|
|
VM_ERROR("not implemented");
|
|
|
|
int max_index = -1, max_value;
|
|
for (int i = index; i < s_array->nr_vars; i++) {
|
|
if (d_array->values[i].i)
|
|
continue;
|
|
int val = s_array->values[i].i;
|
|
if (max_index < 0 || val > max_value) {
|
|
max_index = i;
|
|
max_value = val;
|
|
}
|
|
}
|
|
if (max_index < 0)
|
|
return 0;
|
|
*out_index = max_index;
|
|
d_array->values[max_index].i = 1;
|
|
return 1;
|
|
}
|
|
|
|
static void map_predicate(struct page *s_array, int index, bool (*pred)(int, void *), void *data, struct page *d_array)
|
|
{
|
|
if (!s_array || !d_array)
|
|
return;
|
|
check_array(s_array);
|
|
check_array(d_array);
|
|
|
|
if (index >= 0) {
|
|
for (int i = index; i < s_array->nr_vars; i++) {
|
|
d_array->values[i].i = pred(s_array->values[i].i, data) ? 1 : 0;
|
|
}
|
|
} else {
|
|
for (int i = -index - 1; i >= 0; --i) {
|
|
d_array->values[i].i = pred(s_array->values[i].i, data) ? 1 : 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void vmArray_SetEquNum(struct page *s_array, int index, int num, struct page **d_array)
|
|
{
|
|
map_predicate(s_array, index, pred_equal, &num, *d_array);
|
|
}
|
|
|
|
static void vmArray_SetNotNum(struct page *s_array, int index, int num, struct page **d_array)
|
|
{
|
|
map_predicate(s_array, index, pred_not_equal, &num, *d_array);
|
|
}
|
|
|
|
static void vmArray_SetLowNum(struct page *s_array, int index, int num, struct page **d_array)
|
|
{
|
|
map_predicate(s_array, index, pred_low, &num, *d_array);
|
|
}
|
|
|
|
static void vmArray_SetHighNum(struct page *s_array, int index, int num, struct page **d_array)
|
|
{
|
|
map_predicate(s_array, index, pred_high, &num, *d_array);
|
|
}
|
|
|
|
static void vmArray_SetRangeNum(struct page *s_array, int index, int min, int max, struct page **d_array)
|
|
{
|
|
struct range r = { .min = min, .max = max };
|
|
map_predicate(s_array, index, pred_in_range, &r, *d_array);
|
|
}
|
|
|
|
//void vmArray_AndEquNum(struct page *pISVMArray, int index, int num, struct page **pIDVMArray);
|
|
//void vmArray_AndNotNum(struct page *pISVMArray, int index, int num, struct page **pIDVMArray);
|
|
//void vmArray_AndLowNum(struct page *pISVMArray, int index, int num, struct page **pIDVMArray);
|
|
//void vmArray_AndHighNum(struct page *pISVMArray, int index, int num, struct page **pIDVMArray);
|
|
//void vmArray_AndRangeNum(struct page *pISVMArray, int index, int nMin, int nMax, struct page **pIDVMArray);
|
|
|
|
static void set_if(struct page *s_array, int index, bool (*pred)(int, void *), void *data, struct page *d_array)
|
|
{
|
|
if (!s_array || !d_array)
|
|
return;
|
|
check_array(s_array);
|
|
check_array(d_array);
|
|
|
|
if (index >= 0) {
|
|
for (int i = index; i < s_array->nr_vars; i++) {
|
|
if (pred(s_array->values[i].i, data))
|
|
d_array->values[i].i = 1;
|
|
}
|
|
} else {
|
|
for (int i = -index - 1; i >= 0; --i) {
|
|
if (pred(s_array->values[i].i, data))
|
|
d_array->values[i].i = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void vmArray_OrEquNum(struct page *s_array, int index, int num, struct page **d_array)
|
|
{
|
|
set_if(s_array, index, pred_equal, &num, *d_array);
|
|
}
|
|
|
|
static void vmArray_OrNotNum(struct page *s_array, int index, int num, struct page **d_array)
|
|
{
|
|
set_if(s_array, index, pred_not_equal, &num, *d_array);
|
|
}
|
|
|
|
static void vmArray_OrLowNum(struct page *s_array, int index, int num, struct page **d_array)
|
|
{
|
|
set_if(s_array, index, pred_low, &num, *d_array);
|
|
}
|
|
|
|
static void vmArray_OrHighNum(struct page *s_array, int index, int num, struct page **d_array)
|
|
{
|
|
set_if(s_array, index, pred_high, &num, *d_array);
|
|
}
|
|
|
|
static void vmArray_OrRangeNum(struct page *s_array, int index, int min, int max, struct page **d_array)
|
|
{
|
|
struct range r = { .min = min, .max = max };
|
|
set_if(s_array, index, pred_in_range, &r, *d_array);
|
|
}
|
|
|
|
// Find num by visiting elements spirally around (x, y).
|
|
static int vmArray_AroundRect(struct page *array, int width, int height, int x, int y, int length, int num, int *out_x, int *out_y)
|
|
{
|
|
for (int dist = 1;; dist++) {
|
|
// walk one step north
|
|
if (--length < 0)
|
|
return 0;
|
|
y--;
|
|
if (0 <= x && x < width && 0 <= y && y < height && array->values[y * width + x].i == num)
|
|
goto found;
|
|
|
|
// walk southeast
|
|
for (int i = 0; i < dist; i++) {
|
|
if (--length < 0)
|
|
return 0;
|
|
x++;
|
|
y++;
|
|
if (0 <= x && x < width && 0 <= y && y < height && array->values[y * width + x].i == num)
|
|
goto found;
|
|
}
|
|
// walk southwest
|
|
for (int i = 0; i < dist; i++) {
|
|
if (--length < 0)
|
|
return 0;
|
|
x--;
|
|
y++;
|
|
if (0 <= x && x < width && 0 <= y && y < height && array->values[y * width + x].i == num)
|
|
goto found;
|
|
}
|
|
// walk northwest
|
|
for (int i = 0; i < dist; i++) {
|
|
if (--length < 0)
|
|
return 0;
|
|
x--;
|
|
y--;
|
|
if (0 <= x && x < width && 0 <= y && y < height && array->values[y * width + x].i == num)
|
|
goto found;
|
|
}
|
|
// walk northeast
|
|
for (int i = 0; i < dist - 1; i++) {
|
|
if (--length < 0)
|
|
return 0;
|
|
x++;
|
|
y--;
|
|
if (0 <= x && x < width && 0 <= y && y < height && array->values[y * width + x].i == num)
|
|
goto found;
|
|
}
|
|
x++;
|
|
y--;
|
|
}
|
|
found:
|
|
*out_x = x;
|
|
*out_y = y;
|
|
return 1;
|
|
}
|
|
|
|
/* Hex boards are indexed like this (width = 5, height = 3, for example):
|
|
*
|
|
* +--+ +--+ +--+
|
|
* | 0|--| 2|--| 4|
|
|
* |--| 1|--| 3|--|
|
|
* | 5|--| 7|--| 9|
|
|
* |--| 6|--| 8|--|
|
|
* |10|--|12|--|14|
|
|
* +--+ +--+ +--+
|
|
*
|
|
* Note that odd-numbered columns are one height lower. Because of this, indices
|
|
* 11 and 13 are unused.
|
|
*/
|
|
static bool is_valid_hex(int x, int y, int w, int h) {
|
|
return 0 <= x && x < w && 0 <= y && y < h && !(y == h - 1 && is_odd(x));
|
|
}
|
|
|
|
// Find num by visiting elements spirally around (x, y).
|
|
static int vmArray_AroundHexa(struct page *array, int width, int height, int x, int y, int length, int num, int *out_x, int *out_y)
|
|
{
|
|
for (int dist = 1;; dist++) {
|
|
// walk one step north
|
|
if (--length < 0)
|
|
return 0;
|
|
y--;
|
|
if (is_valid_hex(x, y, width, height) && array->values[y * width + x].i == num)
|
|
goto found;
|
|
// walk southeast
|
|
for (int i = 0; i < dist; i++) {
|
|
if (--length < 0)
|
|
return 0;
|
|
if (is_even(++x))
|
|
y++;
|
|
if (is_valid_hex(x, y, width, height) && array->values[y * width + x].i == num)
|
|
goto found;
|
|
}
|
|
// walk south
|
|
for (int i = 0; i < dist; i++) {
|
|
if (--length < 0)
|
|
return 0;
|
|
y++;
|
|
if (is_valid_hex(x, y, width, height) && array->values[y * width + x].i == num)
|
|
goto found;
|
|
}
|
|
// walk southwest
|
|
for (int i = 0; i < dist; i++) {
|
|
if (--length < 0)
|
|
return 0;
|
|
if (is_even(--x))
|
|
y++;
|
|
if (is_valid_hex(x, y, width, height) && array->values[y * width + x].i == num)
|
|
goto found;
|
|
}
|
|
// walk northwest
|
|
for (int i = 0; i < dist; i++) {
|
|
if (--length < 0)
|
|
return 0;
|
|
if (is_odd(--x))
|
|
y--;
|
|
if (is_valid_hex(x, y, width, height) && array->values[y * width + x].i == num)
|
|
goto found;
|
|
}
|
|
// walk north
|
|
for (int i = 0; i < dist; i++) {
|
|
if (--length < 0)
|
|
return 0;
|
|
y--;
|
|
if (is_valid_hex(x, y, width, height) && array->values[y * width + x].i == num)
|
|
goto found;
|
|
}
|
|
// walk northeast
|
|
for (int i = 0; i < dist - 1; i++) {
|
|
if (--length < 0)
|
|
return 0;
|
|
if (is_odd(++x))
|
|
y--;
|
|
if (is_valid_hex(x, y, width, height) && array->values[y * width + x].i == num)
|
|
goto found;
|
|
}
|
|
if (is_odd(++x))
|
|
y--;
|
|
}
|
|
found:
|
|
*out_x = x;
|
|
*out_y = y;
|
|
return 1;
|
|
}
|
|
|
|
static int vmArray_PaintRect(struct page **array_, int width, int height, int x, int y, int length)
|
|
{
|
|
struct page *array = *array_;
|
|
check_array(array);
|
|
if (array->nr_vars < width * height || x >= width || y >= height || length < 0)
|
|
return 0;
|
|
|
|
int size = width * height;
|
|
for (int i = 0; i < size; i++) {
|
|
array->values[i].i = array->values[i].i < 0 ? -2 : -1;
|
|
}
|
|
|
|
int count = 0;
|
|
array->values[y * width + x].i = 0;
|
|
for (int dist = 0; dist < length; dist++) {
|
|
for (int i = 0; i < size; i++) {
|
|
if (array->values[i].i != dist)
|
|
continue;
|
|
if (i / width > 0 && array->values[i - width].i == -1) {
|
|
array->values[i - width].i = dist + 1;
|
|
count++;
|
|
}
|
|
if (i / width < height - 1 && array->values[i + width].i == -1) {
|
|
array->values[i + width].i = dist + 1;
|
|
count++;
|
|
}
|
|
if (i % width > 0 && array->values[i - 1].i == -1) {
|
|
array->values[i - 1].i = dist + 1;
|
|
count++;
|
|
}
|
|
if (i % width < width - 1 && array->values[i + 1].i == -1) {
|
|
array->values[i + 1].i = dist + 1;
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
static int vmArray_PaintHexa(struct page **array_, int width, int height, int cx, int cy, int length)
|
|
{
|
|
struct page *array = *array_;
|
|
check_array(array);
|
|
|
|
if (width <= 0 || height <= 0 || cx >= width || cy >= height || length < 0)
|
|
return 0;
|
|
|
|
for (int y = 0; y < height; y++) {
|
|
for (int x = 0; x < width; x++) {
|
|
int val = array->values[y * width + x].i < 0 ? -2 : -1;
|
|
if (y == height - 1 && is_odd(x))
|
|
val = -2;
|
|
array->values[y * width + x].i = val;
|
|
}
|
|
}
|
|
|
|
int count = 0;
|
|
array->values[width * cy + cx].i = 0;
|
|
for (int dist = 0; dist < length; dist++) {
|
|
for (int i = 0; i < width * height; i++) {
|
|
if (array->values[i].i != dist)
|
|
continue;
|
|
int y = i / width;
|
|
if (y > 0 && array->values[i - width].i == -1) {
|
|
array->values[i - width].i = dist + 1;
|
|
count++;
|
|
}
|
|
if (y < height - 1 && array->values[i + width].i == -1) {
|
|
array->values[i + width].i = dist + 1;
|
|
count++;
|
|
}
|
|
int x = i % width;
|
|
if (x > 0 && array->values[i - 1].i == -1) {
|
|
array->values[i - 1].i = dist + 1;
|
|
count++;
|
|
}
|
|
if (x < width - 1 && array->values[i + 1].i == -1) {
|
|
array->values[i + 1].i = dist + 1;
|
|
count++;
|
|
}
|
|
if (is_even(x)) {
|
|
if (y > 0 && x > 0 && array->values[i - width - 1].i == -1) {
|
|
array->values[i - width - 1].i = dist + 1;
|
|
count++;
|
|
}
|
|
if (y > 0 && x < width - 1 && array->values[i - width + 1].i == -1) {
|
|
array->values[i - width + 1].i = dist + 1;
|
|
count++;
|
|
}
|
|
} else {
|
|
if (y < height - 1 && x > 0 && array->values[i + width - 1].i == -1) {
|
|
array->values[i + width - 1].i = dist + 1;
|
|
count++;
|
|
}
|
|
if (y < height - 1 && x < width - 1 && array->values[i + width + 1].i == -1) {
|
|
array->values[i + width + 1].i = dist + 1;
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
static int vmArray_CopyRectToRect(struct page **d_array_, int dw, int dh, int dx, int dy, struct page *s_array, int sw, int sh, int sx, int sy, int w, int h)
|
|
{
|
|
struct page *d_array = *d_array_;
|
|
check_array(s_array);
|
|
check_array(d_array);
|
|
if (s_array->nr_vars < sw * sh || d_array->nr_vars < dw * dh)
|
|
return 0;
|
|
|
|
for (int y = 0; y < h; y++) {
|
|
for (int x = 0; x < w; x++) {
|
|
if (dx + x < 0 || dx + x >= dw || dy + y < 0 || dy + y >= dh)
|
|
continue;
|
|
if (sx + x < 0 || sx + x >= sw || sy + y < 0 || sy + y >= sh)
|
|
continue;
|
|
d_array->values[(dy + y) * dw + dx + x] = s_array->values[(sy + y) * sw + sx + x];
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int vmArray_CopyHexaToHexa(struct page **d_array_, int dw, int dh, int dx, int dy, struct page *s_array, int sw, int sh, int sx, int sy, int cw, int ch)
|
|
{
|
|
struct page *d_array = *d_array_;
|
|
check_array(s_array);
|
|
check_array(d_array);
|
|
|
|
if (is_even(sx) == is_even(dx)) {
|
|
for (int y = 0; y < ch; y++) {
|
|
for (int x = 0; x < cw; x++) {
|
|
if (is_valid_hex(sx + x, sy + y, sw, sh) && is_valid_hex(dx + x, dy + y, dw, dh)) {
|
|
d_array->values[(dy + y) * dw + dx + x] = s_array->values[(sy + y) * sw + sx + x];
|
|
}
|
|
}
|
|
}
|
|
} else if (is_even(dx)) { // odd sx, even dx
|
|
for (int y = 0; y < ch; y++) {
|
|
for (int x = 0; x < cw; x++) {
|
|
int syy = is_even(sx + x) ? sy + y + 1 : sy + y;
|
|
if (is_valid_hex(sx + x, syy, sw, sh) && is_valid_hex(dx + x, dy + y, dw, dh)) {
|
|
d_array->values[(dy + y) * dw + dx + x] = s_array->values[syy * sw + sx + x];
|
|
}
|
|
}
|
|
}
|
|
} else { // even sx, odd dx
|
|
for (int y = 0; y < ch; y++) {
|
|
for (int x = 0; x < cw; x++) {
|
|
int dyy = is_odd(sx + x) ? dy + y + 1 : dy + y;
|
|
if (is_valid_hex(sx + x, sy + y, sw, sh) && is_valid_hex(dx + x, dyy, dw, dh)) {
|
|
d_array->values[dyy * dw + dx + x] = s_array->values[(sy + y) * sw + sx + x];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// Transpose s_array (as a 2D array of s_width * s_height) into d_array.
|
|
static int vmArray_ConvertRectSide(struct page **d_array_, struct page *s_array, int s_width, int s_height, int side)
|
|
{
|
|
struct page *d_array = *d_array_;
|
|
check_array(s_array);
|
|
check_array(d_array);
|
|
int w = side ? s_width : s_height;
|
|
int h = side ? s_height : s_width;
|
|
|
|
if (s_array->nr_vars < w * h || d_array->nr_vars < w * h)
|
|
return 0;
|
|
|
|
for (int y = 0; y < h; y++) {
|
|
for (int x = 0; x < w; x++) {
|
|
d_array->values[x * h + y] = s_array->values[y * w + x];
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
HLL_LIBRARY(vmArray,
|
|
HLL_TODO_EXPORT(GetAdd, vmArray_GetAdd),
|
|
HLL_TODO_EXPORT(GetSub, vmArray_GetSub),
|
|
HLL_TODO_EXPORT(GetMul, vmArray_GetMul),
|
|
HLL_TODO_EXPORT(GetDiv, vmArray_GetDiv),
|
|
HLL_TODO_EXPORT(GetAnd, vmArray_GetAnd),
|
|
HLL_TODO_EXPORT(GetOr, vmArray_GetOr),
|
|
HLL_TODO_EXPORT(GetXor, vmArray_GetXor),
|
|
HLL_EXPORT(AddNum, vmArray_AddNum),
|
|
HLL_EXPORT(SubNum, vmArray_SubNum),
|
|
HLL_EXPORT(MulNum, vmArray_MulNum),
|
|
HLL_EXPORT(DivNum, vmArray_DivNum),
|
|
HLL_EXPORT(AndNum, vmArray_AndNum),
|
|
HLL_EXPORT(OrNum, vmArray_OrNum),
|
|
HLL_EXPORT(XorNum, vmArray_XorNum),
|
|
HLL_TODO_EXPORT(MinNum, vmArray_MinNum),
|
|
HLL_TODO_EXPORT(MaxNum, vmArray_MaxNum),
|
|
HLL_EXPORT(AddArray, vmArray_AddArray),
|
|
HLL_EXPORT(SubArray, vmArray_SubArray),
|
|
HLL_EXPORT(MulArray, vmArray_MulArray),
|
|
HLL_EXPORT(DivArray, vmArray_DivArray),
|
|
HLL_EXPORT(AndArray, vmArray_AndArray),
|
|
HLL_EXPORT(OrArray, vmArray_OrArray),
|
|
HLL_EXPORT(XorArray, vmArray_XorArray),
|
|
HLL_TODO_EXPORT(MinArray, vmArray_MinArray),
|
|
HLL_TODO_EXPORT(MaxArray, vmArray_MaxArray),
|
|
HLL_EXPORT(EnumEquNum, vmArray_EnumEquNum),
|
|
HLL_EXPORT(EnumNotNum, vmArray_EnumNotNum),
|
|
HLL_EXPORT(EnumLowNum, vmArray_EnumLowNum),
|
|
HLL_EXPORT(EnumHighNum, vmArray_EnumHighNum),
|
|
HLL_EXPORT(EnumRangeNum, vmArray_EnumRangeNum),
|
|
HLL_EXPORT(ChangeEquNum, vmArray_ChangeEquNum),
|
|
HLL_EXPORT(ChangeNotNum, vmArray_ChangeNotNum),
|
|
HLL_EXPORT(ChangeLowNum, vmArray_ChangeLowNum),
|
|
HLL_EXPORT(ChangeHighNum, vmArray_ChangeHighNum),
|
|
HLL_EXPORT(ChangeRangeNum, vmArray_ChangeRangeNum),
|
|
HLL_EXPORT(GrepEquNum, vmArray_GrepEquNum),
|
|
HLL_EXPORT(GrepNotNum, vmArray_GrepNotNum),
|
|
HLL_EXPORT(GrepLowNum, vmArray_GrepLowNum),
|
|
HLL_EXPORT(GrepHighNum, vmArray_GrepHighNum),
|
|
HLL_EXPORT(GrepRangeNum, vmArray_GrepRangeNum),
|
|
HLL_EXPORT(GrepLowOrder, vmArray_GrepLowOrder),
|
|
HLL_EXPORT(GrepHighOrder, vmArray_GrepHighOrder),
|
|
HLL_EXPORT(SetEquNum, vmArray_SetEquNum),
|
|
HLL_EXPORT(SetNotNum, vmArray_SetNotNum),
|
|
HLL_EXPORT(SetLowNum, vmArray_SetLowNum),
|
|
HLL_EXPORT(SetHighNum, vmArray_SetHighNum),
|
|
HLL_EXPORT(SetRangeNum, vmArray_SetRangeNum),
|
|
HLL_TODO_EXPORT(AndEquNum, vmArray_AndEquNum),
|
|
HLL_TODO_EXPORT(AndNotNum, vmArray_AndNotNum),
|
|
HLL_TODO_EXPORT(AndLowNum, vmArray_AndLowNum),
|
|
HLL_TODO_EXPORT(AndHighNum, vmArray_AndHighNum),
|
|
HLL_TODO_EXPORT(AndRangeNum, vmArray_AndRangeNum),
|
|
HLL_EXPORT(OrEquNum, vmArray_OrEquNum),
|
|
HLL_EXPORT(OrNotNum, vmArray_OrNotNum),
|
|
HLL_EXPORT(OrLowNum, vmArray_OrLowNum),
|
|
HLL_EXPORT(OrHighNum, vmArray_OrHighNum),
|
|
HLL_EXPORT(OrRangeNum, vmArray_OrRangeNum),
|
|
HLL_EXPORT(AroundRect, vmArray_AroundRect),
|
|
HLL_EXPORT(AroundHexa, vmArray_AroundHexa),
|
|
HLL_EXPORT(PaintRect, vmArray_PaintRect),
|
|
HLL_EXPORT(PaintHexa, vmArray_PaintHexa),
|
|
HLL_EXPORT(CopyRectToRect, vmArray_CopyRectToRect),
|
|
HLL_EXPORT(CopyHexaToHexa, vmArray_CopyHexaToHexa),
|
|
HLL_EXPORT(ConvertRectSide, vmArray_ConvertRectSide)
|
|
);
|