--
zpe_print
function zpe_print(...$values) {
  foreach ($values as $value) {
    echo zpe_stringify($value);
  }
  echo PHP_EOL;
}
--
zpe_out
function zpe_out(...$values) {
  foreach ($values as $value) {
    echo zpe_stringify($value);
  }
}
--
zpe_input
function zpe_input(...$prompt) {
  zpe_out(...$prompt);
  $line = fgets(STDIN);
  return $line === false ? "" : rtrim($line, "\r\n");
}
--
zpe_auto_input
function zpe_auto_input(...$prompt) {
  $value = zpe_input(...$prompt);
  if (is_numeric($value)) return strpos($value, ".") === false ? (int) $value : (float) $value;
  if ($value === "true" || $value === "false") return $value === "true";
  return $value;
}
--
zpe_time
function zpe_time() {
  return (int) floor(microtime(true) * 1000);
}
--
zpe_put
function zpe_put(&$container, $key, $value = null) {
  if (is_array($container)) {
    if (zpe_is_list($container) && func_num_args() === 2) {
      $container[] = $key;
    } else {
      $container[$key] = $value;
    }
  }
  return $container;
}
--
zpe_list_add_element
function zpe_list_add_element(&$list, $value) {
  $list[] = $value;
  return $list;
}
--
zpe_list_remove_element
function zpe_list_remove_element(&$list, $index) {
  unset($list[$index]);
  return array_values($list);
}
--
zpe_list_set_at_index
function zpe_list_set_at_index(&$list, $index, $value) {
  while (count($list) <= $index) $list[] = null;
  $list[$index] = $value;
  return $list;
}
--
zpe_list_swap_elements
function zpe_list_swap_elements(&$list, $first, $second) {
  $value = $list[$first];
  $list[$first] = $list[$second];
  $list[$second] = $value;
  return $list;
}
--
zpe_map_contains
function zpe_map_contains($map, $key) {
  return is_array($map) && array_key_exists($key, $map);
}
--
zpe_string_contains
function zpe_string_contains($text, $part) {
  return strpos((string) $text, (string) $part) !== false;
}
--
zpe_string_starts_with
function zpe_string_starts_with($text, $prefix) {
  return substr((string) $text, 0, strlen((string) $prefix)) === (string) $prefix;
}
--
zpe_string_ends_with
function zpe_string_ends_with($text, $suffix) {
  $suffix = (string) $suffix;
  return $suffix === "" || substr((string) $text, -strlen($suffix)) === $suffix;
}
--
zpe_string_split
function zpe_string_split($text, $delimiter) {
  return explode((string) $delimiter, (string) $text);
}
--
zpe_is_list
function zpe_is_list($value) {
  if (!is_array($value)) return false;
  if ($value === []) return true;
  return array_keys($value) === range(0, count($value) - 1);
}
--
zpe_stringify
function zpe_stringify($value) {
  if ($value === null) return "null";
  if (is_bool($value)) return $value ? "true" : "false";
  if (is_array($value)) {
    $parts = [];
    if (zpe_is_list($value)) {
      foreach ($value as $item) $parts[] = zpe_stringify($item);
    } else {
      foreach ($value as $key => $item) {
        $parts[] = zpe_stringify($key) . " => " . zpe_stringify($item);
      }
    }
    return "[" . implode(", ", $parts) . "]";
  }
  if (is_object($value)) {
    return method_exists($value, "__toString") ? (string) $value : get_class($value);
  }
  return (string) $value;
}
--
zpe_concat
function zpe_concat($left, $right) {
  return zpe_stringify($left) . zpe_stringify($right);
}
--
zpe_iterable
function zpe_iterable($value) {
  if (is_string($value)) return str_split($value);
  if (is_array($value)) return $value;
  if ($value instanceof Traversable) return iterator_to_array($value);
  return [];
}
--
zpe_type
function zpe_type($value) {
  if ($value === null) return "NULL";
  if (is_bool($value)) return "BOOLEAN";
  if (is_int($value) || is_float($value)) return "NUMBER";
  if (is_string($value)) return "STRING";
  if (is_array($value)) return zpe_is_list($value) ? "LIST" : "MAP";
  if (is_callable($value)) return "FUNCTION";
  if (is_object($value)) return "OBJECT";
  return "UNDEFINED";
}
--
random_number
function random_number($max, $min = 0) {
  return random_int((int) $min, (int) $max);
}
--
factorial
function factorial($number) {
  $number = (int) $number;
  if ($number < 0) throw new InvalidArgumentException("factorial() requires a non-negative number");
  $result = 1;
  for ($i = 2; $i <= $number; $i++) $result *= $i;
  return $result;
}
--
map_create_ordered
function map_create_ordered(...$pairs) {
  $result = [];
  foreach ($pairs as $pair) {
    if (is_array($pair) && count($pair) >= 2) $result[$pair[0]] = $pair[1];
  }
  return $result;
}
--
throw_error
function throw_error($message) {
  throw new RuntimeException((string) $message);
}
--
print_error
function print_error($message) {
  fwrite(STDERR, zpe_stringify($message) . PHP_EOL);
}
--
value
function value($input) {
  if (is_int($input) || is_float($input)) return $input;
  if (is_string($input) && is_numeric($input)) {
    return strpos($input, ".") === false ? (int) $input : (float) $input;
  }
  return 0;
}
--
max_integer
function max_integer() {
  return PHP_INT_MAX;
}
--
string_compare
function string_compare($left, $right) {
  $result = strcmp((string) $left, (string) $right);
  return $result < 0 ? -1 : ($result > 0 ? 1 : 0);
}
--
zpe_modulo
function zpe_modulo($left, $right) {
  $result = fmod((float) $left, (float) $right);
  return floor($result) == $result ? (int) $result : $result;
}
