Implemented array sorting utility script command

This commit is contained in:
Jittapan Pluemsumran 2018-01-10 23:13:41 +07:00
parent 48d79cef43
commit 12d5d99a4d
2 changed files with 140 additions and 0 deletions

View File

@ -2244,6 +2244,25 @@ array, shifting all the elements beyond this towards the beginning.
---------------------------------------
*sortarray(<array name>);
This command will do an in-place sort on an array specified in <array name>.
Original ordering of the array before execution of this command will be lost.
Example:
setarray .@a,31, 44, 14, 18, 24, 42, 39, 47, 30, 17, 36, 45, 34, 21, 38, 41, 23, 25, 13, 20, 8, 5, 22, 9, 2, 12, 19, 35, 48, 37;
sortarray(.@a);
.@size = getarraysize(.@a);
for(.@i = 0; .@size; .@i++) {
.@msg$ = .@msg$ + .@a[.@i] + " ";
}
debugmes(.@msg$);
Output: 2 5 8 9 12 13 14 17 18 19 20 21 22 23 24 25 30 31 34 35 36 37 38 39 41 42 44 45 47 48
---------------------------------------
======================================
|2.- Information-retrieving commands.|
======================================

View File

@ -9,6 +9,8 @@
#include "script.hpp"
#include <stack>
#include <math.h>
#include <stdlib.h> // atoi, strtol, strtoll, exit
#include <setjmp.h>
@ -23728,6 +23730,124 @@ BUILDIN_FUNC(getequiptradability) {
return SCRIPT_CMD_SUCCESS;
}
/**
* Swaps position of two array elements.
* This function does not guarantee that the array is accessible, so the burden fall to the caller.
* @param st Current script state
* @param sd The player owning the variable, can be nullptr
* @param array_ The array containing elements to be swapped
* @param idx1 index of first element
* @param idx2 index of second element
*/
void swap_array_element(script_state *st, map_session_data *sd, script_data* array_, int idx1, int idx2) {
void *v1, *v2;
auto id = reference_getid(array_);
auto name = reference_getname(array_);
auto ref = reference_getref(array_);
v1 = get_val2(st, reference_uid(id, idx1), ref);
v2 = get_val2(st, reference_uid(id, idx2), ref);
set_reg(st, sd, reference_uid(id, idx2), name, v1, ref);
set_reg(st, sd, reference_uid(id, idx1), name, v2, ref);
script_removetop(st, -2, 0);
}
/**
* Partition an array to be used in quick sort with Hoare's partitioning
* This function does not guarantee that the array is accessible, so the burden fall to the caller.
* @param st Current script state
* @param sd The player owning the variable, can be nullptr
* @param array_ The array to be partitioned
* @param start Starting index
* @param end Ending index
*/
int partition_array(script_state *st, map_session_data *sd, script_data *array_, int start, int end) {
auto ref = reference_getref(array_);
auto id = reference_getid(array_);
int i = start, j = end;
int pivotidx = rnd() % (end - start);
int pivot = reinterpret_cast<int>(__64BPRTSIZE(get_val2(st, reference_uid(id, start + pivotidx), ref)));
script_removetop(st, -1, 0);
while (i < j) {
while (true) {
int tmp = reinterpret_cast<int>(__64BPRTSIZE(get_val2(st, reference_uid(id, i), ref)));
script_removetop(st, -1, 0);
if (tmp >= pivot)
break;
i++;
}
while (true) {
int tmp = reinterpret_cast<int>(__64BPRTSIZE(get_val2(st, reference_uid(id, j), ref)));
script_removetop(st, -1, 0);
if (tmp <= pivot)
break;
j--;
}
swap_array_element(st, sd, array_, i, j);
}
return j;
}
/**
* Sort an array
* sortarray(<array>);
*/
BUILDIN_FUNC(sortarray) {
map_session_data *sd = nullptr;
script_data *array_ = script_getdata(st, 2);
reg_db *ref;
char* name;
if (!data_isreference(array_)) {
ShowError("buildin_sortarray: Not a variable!\n");
script_reportdata(array_);
st->state = END;
return SCRIPT_CMD_FAILURE;
}
name = reference_getname(array_);
ref = reference_getref(array_);
if (not_server_variable(name[0])) {
if (!script_rid2sd(sd))
return SCRIPT_CMD_FAILURE;
}
std::stack<int> stack;
auto size = script_array_highest_key(st, sd, name, ref);
// Push initial indices
stack.push(0);
stack.push(size - 1);
while (!stack.empty()) {
int end, start, p;
end = stack.top();
stack.pop();
start = stack.top();
stack.pop();
p = partition_array(st, sd, array_, start, end);
if(p - 1 > start) {
stack.push(start);
stack.push(p - 1);
}
if(p + 1 < end) {
stack.push(p + 1);
stack.push(end);
}
}
return SCRIPT_CMD_SUCCESS;
}
#include "../custom/script.inc"
// declarations that were supposed to be exported from npc_chat.c
@ -24376,6 +24496,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF2(round, "ceil", "i"),
BUILDIN_DEF2(round, "floor", "i"),
BUILDIN_DEF(getequiptradability, "i?"),
BUILDIN_DEF(sortarray, "r"),
#include "../custom/script_def.inc"
{NULL,NULL,NULL},