Code test
kraphyko.c
Some drawing code from a program written for the TI-89.
#include "drawing.h"
#include <tigcclib.h>
SCR_RECT whole_scn;
double sqr(double x) { return x * x; }
void DrawStr2(int x, int y, const char* str, short Attr) {
if (Attr != A_REVERSE) {
DrawStr(x, y, str, Attr);
} else {
ScrRectFill(&whole_scn, &whole_scn, A_XOR);
DrawStr(x, y, str, A_NORMAL);
ScrRectFill(&whole_scn, &whole_scn, A_XOR);
}
}
short GetGPix(short x, short y) {
GraySetAMSPlane(LIGHT_PLANE);
int color = GetPix(x, y);
GraySetAMSPlane(DARK_PLANE);
return color + 2 * GetPix(x, y);
}
void DrawClipPixAttr(int x, int y, int attr) {
SetCurAttr(attr);
DrawClipPix(x, y);
}
void DrawGPix(short x, short y, short color, short attr) {
int col;
if (attr) col = GetGPix(x, y);
switch (attr) {
case GA_DRAW:
GraySetAMSPlane(LIGHT_PLANE);
DrawClipPixAttr(x, y, (color & 1));
GraySetAMSPlane(DARK_PLANE);
DrawClipPixAttr(x, y, (color & 2) / 2);
break;
case GA_ROT: DrawGPix(x, y, (col + color) % 4, GA_DRAW); break;
case GA_FLIP: DrawGPix(x, y, 3 - col, GA_DRAW);
}
}
static uint32_t leftPixelsSet(int number) {
if (number == 0) return 0;
// Return a bitmask that results in the left `number` pixels being set.
uint32_t mask = (1UL << (32 - number)) - 1;
return ~mask;
}
static void DrawLineHorizontalDraw(
int mode, short rxl, short rx0, short rx1, uint32_t lmask, uint32_t rmask,
uint32_t* mem) {
if (mode) {
if (rx1 != rxl) {
memset(mem + rx0, 0xFF, sizeof(uint32_t) * (rx1 - rx0));
mem[rxl] |= lmask;
mem[rx1] |= rmask;
} else {
mem[rxl] |= lmask & rmask;
}
} else {
if (rx1 != rxl) {
memset(mem + rx0, 0x00, sizeof(uint32_t) * (rx1 - rx0));
mem[rxl] &= ~lmask;
mem[rx1] &= ~rmask;
} else {
mem[rxl] &= ~(lmask & rmask);
}
}
}
static void DrawLineHorizontalInv(
short rxl, short rx0, short rx1, uint32_t lmask, uint32_t rmask,
uint32_t* mem) {
mem[rxl] ^= lmask;
mem[rx1] ^= rmask;
for (int col = rx0; col < rx1; ++col) { mem[col] = ~mem[col]; }
}
static void
rotateColorsByBitplanes(uint32_t* l, uint32_t* d, uint32_t mask, int times) {
uint32_t light = *l, dark = *d;
// Bits not set in mask are unaffected
uint32_t bs[4] = {
~light & ~dark & mask,
light & ~dark & mask,
~light & dark & mask,
light & dark & mask,
};
// Colors 1 and 3 set the bit here; 0 and 2 reset
uint32_t newlight =
bs[(1 + 4 - times) & 3] | bs[(3 + 4 - times) & 3] | (~mask & light);
// Colors 2 and 3 set the bit here; 0 and 1 reset
uint32_t newdark =
bs[(2 + 4 - times) & 3] | bs[(3 + 4 - times) & 3] | (~mask & dark);
*l = newlight;
*d = newdark;
}
void DrawGLineHorizontal(short x0, short x1, short y, short color, short attr) {
if (y < 0 || y >= whole_scn.xy.y1) return;
if (x0 < 0) x0 = 0;
if (x0 > whole_scn.xy.x1) x0 = whole_scn.xy.x1;
if (x1 < 0) x1 = 0;
if (x1 > whole_scn.xy.x1) x1 = whole_scn.xy.x1;
++x1; // originally [x0, x1], now [x0, x1)
int pixno0 = 240 * y + x0, pixno1 = 240 * y + x1;
int rxl = pixno0 >> 5;
int rx0 = (pixno0 + 31) >> 5;
int rx1 = pixno1 >> 5;
int firstLeftBit = pixno0 & 31;
int lastRightBit = pixno1 & 31;
uint32_t* lightRow = (uint32_t*) GrayGetPlane(LIGHT_PLANE);
uint32_t* darkRow = (uint32_t*) GrayGetPlane(DARK_PLANE);
int lightActive = (color & 1) != 0;
int darkActive = (color & 2) != 0;
uint32_t lmask = ~leftPixelsSet(firstLeftBit);
uint32_t rmask = leftPixelsSet(lastRightBit);
switch (attr) {
case GA_DRAW:
DrawLineHorizontalDraw(lightActive, rxl, rx0, rx1, lmask, rmask, lightRow);
DrawLineHorizontalDraw(darkActive, rxl, rx0, rx1, lmask, rmask, darkRow);
break;
case GA_ROT:
case GA_ADD: {
for (short col = rx0; col < rx1; ++col) {
rotateColorsByBitplanes(lightRow + col, darkRow + col, -1UL, attr);
}
if (rxl != rx1) {
rotateColorsByBitplanes(lightRow + rxl, darkRow + rxl, lmask, attr);
rotateColorsByBitplanes(lightRow + rx1, darkRow + rx1, rmask, attr);
} else {
rotateColorsByBitplanes(
lightRow + rxl, darkRow + rxl, lmask & rmask, attr);
}
break;
}
case GA_FLIP:
DrawLineHorizontalInv(rxl, rx0, rx1, lmask, rmask, lightRow);
DrawLineHorizontalInv(rxl, rx0, rx1, lmask, rmask, darkRow);
default: break;
}
}
static void
lineShallow(short x0, short y0, short x1, short y1, short color, short attr) {
int dx = x1 - x0;
int dy = y1 - y0;
int yi = 1;
if (dy < 0) {
dy = -dy;
yi = -1;
}
int d = 2 * dy - dx;
int y = y0;
for (int x = x0; x <= x1; ++x) {
if (x >= 0 && y >= 0 && y < whole_scn.xy.y1 && x < whole_scn.xy.x1)
DrawGPix(x, y, color, attr);
if (d > 0) {
y += yi;
d -= 2 * dx;
}
d += 2 * dy;
}
}
static void
lineSteep(short x0, short y0, short x1, short y1, short color, short attr) {
int dx = x1 - x0;
int dy = y1 - y0;
int xi = 1;
if (dx < 0) {
dx = -dx;
xi = -1;
}
int d = 2 * dx - dy;
int x = x0;
for (int y = y0; y <= y1; ++y) {
if (x >= 0 && y >= 0 && y < whole_scn.xy.y1 && x < whole_scn.xy.x1)
DrawGPix(x, y, color, attr);
if (d > 0) {
x += xi;
d -= 2 * dy;
}
d += 2 * dx;
}
}
/*
Kraphyko 0.8_05 and earlier used floating-point math to draw lines with
the GA_ROT attribute. Later versions like this one use Bresenham's
line drawing algorithm for all attributes
(https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm).
*/
void DrawGLine(
short x0, short y0, short x1, short y1, short color, short attr) {
if (abs(y1 - y0) < abs(x1 - x0)) {
if (x0 > x1)
lineShallow(x1, y1, x0, y0, color, attr);
else
lineShallow(x0, y0, x1, y1, color, attr);
} else {
if (y0 > y1)
lineSteep(x1, y1, x0, y0, color, attr);
else
lineSteep(x0, y0, x1, y1, color, attr);
}
}
#define floord2(x) ((x) / 2)
void DrawGLine2(
short x0, short y0, short x1, short y1, short color, short attr,
char penWidth) {
if (y0 == y1) {
int it2;
for (it2 = -(penWidth - 1); it2 <= (penWidth - 1); it2 += 2) {
DrawGLine(x0, y0 + it2 / 2, x1, y1 + it2 / 2, color, attr);
}
return;
}
float mi = -(float) (x1 - x0) / ((float) (y1 - y0));
float x = 1.0 / (sqrt(1.0 + sqr(mi)));
float y = x * mi;
int it2;
for (it2 = -(penWidth - 1); it2 <= (penWidth - 1); it2 += 2) {
DrawGLine(
x0 + floord2(it2 * x), y0 + floord2(it2 * y), x1 + floord2(it2 * x),
y1 + floord2(it2 * y), color, attr);
}
}
void DrawGTriangle(
short x0, short y0, short x1, short y1, short x2, short y2, short color,
short attr, char penWidth) {
DrawGLine2(x0, y0, x1, y1, color, attr, penWidth);
DrawGLine2(x2, y2, x1, y1, color, attr, penWidth);
DrawGLine2(x0, y0, x2, y2, color, attr, penWidth);
}
void DrawGTriangleFill(
short x0, short y0, short x1, short y1, short x2, short y2, short color,
short attr) {
switch (attr) {
case GA_DRAW:
GraySetAMSPlane(LIGHT_PLANE);
FillTriangle(x0, y0, x1, y1, x2, y2, &whole_scn, (color & 1));
GraySetAMSPlane(DARK_PLANE);
FillTriangle(x0, y0, x1, y1, x2, y2, &whole_scn, (color & 2) / 2);
break;
case GA_ROT:
case GA_ADD:
GraySetAMSPlane(LIGHT_PLANE);
if (color & 1) FillTriangle(x0, y0, x1, y1, x2, y2, &whole_scn, A_NORMAL);
GraySetAMSPlane(DARK_PLANE);
if (color & 2) FillTriangle(x0, y0, x1, y1, x2, y2, &whole_scn, A_NORMAL);
break;
case GA_FLIP:
GraySetAMSPlane(LIGHT_PLANE);
FillTriangle(x0, y0, x1, y1, x2, y2, &whole_scn, A_XOR);
GraySetAMSPlane(DARK_PLANE);
FillTriangle(x0, y0, x1, y1, x2, y2, &whole_scn, A_XOR);
break;
}
}
void DrawGRect(
short x0, short y0, short x1, short y1, short color, short attr,
char penWidth) {
DrawGLine2(x0, y0, x1, y0, color, attr, penWidth);
DrawGLine2(x0, y0, x0, y1, color, attr, penWidth);
DrawGLine2(x1, y0, x1, y1, color, attr, penWidth);
DrawGLine2(x0, y1, x1, y1, color, attr, penWidth);
}
void DrawGRectFill(
short x0, short y0, short x1, short y1, short color, short attr) {
if (x1 < x0) {
short t = x1;
x1 = x0;
x0 = t;
}
if (y1 < y0) {
short t = y1;
y1 = y0;
y0 = t;
}
for (int y = y0; y <= y1; y++) {
DrawGLineHorizontal(x0, x1, y, color, attr);
}
}
static void DrawGEllipse3(
short xc, short yc, short a, short b, short color, short attr,
short intrusion) {
long a2 = ((long) a) * a;
long b2 = ((long) b) * b;
long fa2 = 4 * a2;
long fb2 = 4 * b2;
int ai = a - intrusion;
int bi = b - intrusion;
if (ai < 0) ai = 0;
if (bi < 0) bi = 0;
long ai2 = ai * ai;
long bi2 = bi * bi;
long fai2 = 4 * ai2;
long fbi2 = 4 * bi2;
// Part 1
int x = 0;
int y = b;
int yi = bi;
long sigma = 2 * b2 + a2 * (1 - 2 * b);
long sigmai = 2 * bi2 + ai2 * (1 - 2 * bi);
while (b2 * x < a2 * y) {
int ystart = yi;
if (ystart < 0) ystart = 0;
for (int i = ystart; i <= y; ++i) {
DrawGPix(xc + x, yc + i, color, attr);
if (x != 0) DrawGPix(xc - x, yc + i, color, attr);
if (i != 0) {
DrawGPix(xc + x, yc - i, color, attr);
if (x != 0) DrawGPix(xc - x, yc - i, color, attr);
}
}
if (sigma >= 0) {
sigma += fa2 * (1 - y);
--y;
}
if (sigmai >= 0) {
sigmai += fai2 * (1 - yi);
--yi;
}
sigma += b2 * ((4 * x) + 6);
sigmai += bi2 * ((4 * x) + 6);
++x;
}
// Part 2
int xlim = x;
x = a;
int xi = ai;
y = 0;
sigma = 2 * a2 + b2 * (1 - 2 * a);
sigmai = 2 * bi2 + ai2 * (1 - 2 * bi);
while (a2 * y < b2 * x) {
int xstart = xi;
if (xstart < xlim) xstart = xlim;
if (x > xstart) {
DrawGLineHorizontal(xc + xstart, xc + x, yc + y, color, attr);
if (y != 0) DrawGLineHorizontal(xc + xstart, xc + x, yc - y, color, attr);
if (xstart == 0) ++xstart;
DrawGLineHorizontal(xc - x, xc - xstart, yc + y, color, attr);
if (y != 0) DrawGLineHorizontal(xc - x, xc - xstart, yc - y, color, attr);
}
if (sigma >= 0) {
sigma += fb2 * (1 - x);
--x;
}
if (sigmai >= 0) {
sigmai += fbi2 * (1 - xi);
--xi;
}
sigma += a2 * ((4 * y) + 6);
sigmai += ai2 * ((4 * y) + 6);
++y;
}
}
/*
Old versions of Kraphyko just called DrawClipEllipse. This code instead uses
Bresenham's ellipse-drawing algorithm
(see
https://sites.google.com/site/ruslancray/lab/projects/bresenhamscircleellipsedrawingalgorithm/bresenham-s-circle-ellipse-drawing-algorithm).
*/
void DrawGEllipse(
short x0, short y0, short x1, short y1, short color, short attr) {
int xc = (x0 + x1) / 2;
int yc = (y0 + y1) / 2;
int a = abs(x1 - xc);
int b = abs(y1 - yc);
long a2 = ((long) a) * a;
long b2 = ((long) b) * b;
long fa2 = 4 * a2;
long fb2 = 4 * b2;
// Part 1
int x = 0;
int y = b;
long sigma = 2 * b2 + a2 * (1 - 2 * b);
while (b2 * x < a2 * y) {
DrawGPix(xc + x, yc + y, color, attr);
DrawGPix(xc - x, yc + y, color, attr);
DrawGPix(xc + x, yc - y, color, attr);
DrawGPix(xc - x, yc - y, color, attr);
if (sigma >= 0) {
sigma += fa2 * (1 - y);
--y;
}
sigma += b2 * ((4 * x) + 6);
++x;
}
// Part 2
x = a;
y = 0;
sigma = 2 * a2 + b2 * (1 - 2 * a);
while (a2 * y < b2 * x) {
DrawGPix(xc + x, yc + y, color, attr);
DrawGPix(xc - x, yc + y, color, attr);
DrawGPix(xc + x, yc - y, color, attr);
DrawGPix(xc - x, yc - y, color, attr);
if (sigma >= 0) {
sigma += fb2 * (1 - x);
--x;
}
sigma += a2 * ((4 * y) + 6);
++y;
}
}
void DrawGEllipse2(
short x0, short y0, short x1, short y1, short color, short attr,
char penWidth) {
if (penWidth == 1) DrawGEllipse(x0, y0, x1, y1, color, attr);
int xd = abs(x1 - x0);
int yd = abs(y1 - y0);
DrawGEllipse3(
(x0 + x1) / 2, (y0 + y1) / 2, xd / 2, yd / 2, color, attr,
2 * (penWidth - 1));
}
void DrawGEllipseFill(
short x0, short y0, short x1, short y1, short color, short attr) {
int xd = abs(x1 - x0);
int yd = abs(y1 - y0);
DrawGEllipse3((x0 + x1) / 2, (y0 + y1) / 2, xd / 2, yd / 2, color, attr, 255);
}
void DrawGCirc(short x, short y, short r, short color, short attr) {
DrawGEllipse(x - r, y - r, x + r, y + r, color, attr);
}
void DrawGCirc2(
short x, short y, short r, short color, short attr, char penWidth) {
DrawGEllipse2(x - r, y - r, x + r, y + r, color, attr, penWidth);
}
void DrawGCircFill(short x, short y, short r, short color, short attr) {
DrawGEllipseFill(x - r, y - r, x + r, y + r, color, attr);
}
void DrawGStr(short x0, short y0, const char* string, short color, short attr) {
switch (attr) {
case GA_DRAW:
GraySetAMSPlane(LIGHT_PLANE);
DrawStr2(x0, y0, string, (color & 1));
GraySetAMSPlane(DARK_PLANE);
DrawStr2(x0, y0, string, (color & 2) >> 1);
break;
case GA_ROT:
GraySetAMSPlane(LIGHT_PLANE);
if (color & 1) DrawStr2(x0, y0, string, A_NORMAL);
GraySetAMSPlane(DARK_PLANE);
if (color & 2) DrawStr2(x0, y0, string, A_NORMAL);
break;
case GA_FLIP:
GraySetAMSPlane(LIGHT_PLANE);
DrawStr2(x0, y0, string, A_XOR);
GraySetAMSPlane(DARK_PLANE);
DrawStr2(x0, y0, string, A_XOR);
}
}
static int ptcolora(int x, int y, short rcol) {
return (x >= 0 && x <= whole_scn.xy.x1 && y >= 0 && y <= whole_scn.xy.y1) ?
GetGPix(x, y) :
rcol;
}
typedef struct {
unsigned char x, y;
} aaa;
void FloodFill(short x, short y, short tcol, short rcol) {
if (tcol == rcol) return;
if (ptcolora(x, y, rcol) != tcol) return;
long int size = 1;
long int capacity = 16;
HANDLE sh = HeapAlloc(capacity * sizeof(aaa));
if (sh == H_NULL) return;
aaa* stack = HeapDeref(sh);
stack[0] = (aaa){x, y};
int j, Y;
while (size > 0) {
aaa N = stack[size - 1];
--size;
Y = N.y;
if (ptcolora(N.x, Y, rcol) == tcol) {
int e = N.x;
int w = e;
do { --w; } while ((ptcolora(w, Y, rcol) == tcol) && w >= 0);
do {
++e;
} while ((ptcolora(e, Y, rcol) == tcol) && e <= whole_scn.xy.x1);
++w;
--e;
DrawGLineHorizontal(w, e, Y, rcol, GA_DRAW);
for (j = w; j <= e; j++) {
if (ptcolora(j, Y - 1, rcol) == tcol) {
if (size >= capacity) {
HeapUnlock(sh);
sh = HeapRealloc(sh, 2 * capacity * sizeof(aaa));
if (sh == H_NULL) goto ERROR;
stack = HeapDeref(sh);
capacity *= 2;
}
stack[size] = (aaa){j, Y - 1};
++size;
}
if (ptcolora(j, Y + 1, rcol) == tcol) {
if (size >= capacity) {
HeapUnlock(sh);
sh = HeapRealloc(sh, 2 * capacity * sizeof(aaa));
if (sh == H_NULL) goto ERROR2;
stack = HeapDeref(sh);
capacity *= 2;
}
stack[size] = (aaa){j, Y + 1};
++size;
}
}
}
}
HeapFree(sh);
return;
ERROR:
HeapFree(sh);
FloodFill(j, Y - 1, tcol, rcol);
return;
ERROR2:
HeapFree(sh);
FloodFill(j, Y + 1, tcol, rcol);
return;
}
kfp.h
Doing what C++ does best: create abstractions that no one will bother using.
/*
Copyright 2018 AGC.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
#ifndef KOZET_FIXED_POINT_KFP_H
# define KOZET_FIXED_POINT_KFP_H
# include <limits.h>
# include <math.h>
# include <stddef.h>
# include <stdint.h>
# include <limits>
# include <type_traits>
# include <utility>
# include "./kfp_config.h"
/** \mainpage kozet_fixed_point
*
* \section intro_sec Introduction & Rationale
*
* kozet_floating_point, or kfp for short, is a header-only library for
* fixed-point numbers.
*
* It's sometimes necessary to have an alternative to floating-point numbers
* that behaves the same across many platforms, regardless of the compiler used
* to build a program or the hardware it runs on. TDR is one of the projects
* that needs such a number type.
*
* \section install_sec Using the library
*
* This library requires C++17. It also uses 128-bit integer types; if it
* doesn't think it has `__int128_t` and `__uint128_t` types available, then
* you'll need to modify `kfp.h` to define the appropriate types yourself.
* [This
* library](https://www.boost.org/doc/libs/1_70_0/libs/multiprecision/doc/html/boost_multiprecision/tut/ints/cpp_int.html)
* might be useful.
*
* kfp is a header-only library, so copy the `include/` directory wherever you'd
* like and you're set!
*
* * `kozet_fixed_point/kfp.h` provides the types and the basic functionality.
* * `kozet_fixed_point/kfp_extra.h` provides trigonometric functions that work
* on angles represented as 32-bit fractions of a turn.
* * `kozet_fixed_point/random/kfp_wrapper.h` provides a wrapper around a
* random number generator.
* * `kozet_fixed_point/kfp_string.h` provides functions to interact with text
* representations of fixed-point numbers.
*
* To start, look at \ref kfp::Fixed.
*
* \section hacking Notes for hackers
*
* ~~don't or I'll call the cops~~
*
* The tests for the library are found in `test/test.cpp`, and the CMake target
* is called `mytest` (with the executable at `build/mytest`).
*
* Do note that some of the tests use floating-point arithmetic for convenience.
*/
namespace kfp {
// Check for prescence of __int128
# ifdef __SIZEOF_INT128__
using int128_t = __int128_t;
using uint128_t = __uint128_t;
# else
// Use a library that provides a 128-bit int type with the usual operations
// and define kfp::int128_t and kfp::uint128_t to the signed/unsigned variant
// respectively if not done already.
# error \
"No 128-bit integer type found! Replace this line with the appropriate definitions!"
# endif
/// \cond false
template<typename T> struct DTI;
template<> struct DTI<int8_t> { typedef int_fast16_t type; };
template<> struct DTI<int16_t> { typedef int_fast32_t type; };
template<> struct DTI<int32_t> { typedef int_fast64_t type; };
template<> struct DTI<int64_t> { typedef int128_t type; };
template<> struct DTI<uint8_t> { typedef uint_fast16_t type; };
template<> struct DTI<uint16_t> { typedef uint_fast32_t type; };
template<> struct DTI<uint32_t> { typedef uint_fast64_t type; };
template<> struct DTI<uint64_t> { typedef uint128_t type; };
template<typename T> struct DTIX;
template<> struct DTIX<int8_t> { typedef int16_t type; };
template<> struct DTIX<int16_t> { typedef int32_t type; };
template<> struct DTIX<int32_t> { typedef int64_t type; };
template<> struct DTIX<int64_t> { typedef int128_t type; };
template<> struct DTIX<uint8_t> { typedef uint16_t type; };
template<> struct DTIX<uint16_t> { typedef uint32_t type; };
template<> struct DTIX<uint32_t> { typedef uint64_t type; };
template<> struct DTIX<uint64_t> { typedef uint128_t type; };
template<typename T> struct HTI;
template<> struct HTI<int8_t> { typedef int8_t type; };
template<> struct HTI<int16_t> { typedef int8_t type; };
template<> struct HTI<int32_t> { typedef int16_t type; };
template<> struct HTI<int64_t> { typedef int32_t type; };
template<> struct HTI<int128_t> { typedef int64_t type; };
template<> struct HTI<uint8_t> { typedef uint8_t type; };
template<> struct HTI<uint16_t> { typedef uint8_t type; };
template<> struct HTI<uint32_t> { typedef uint16_t type; };
template<> struct HTI<uint64_t> { typedef uint32_t type; };
template<> struct HTI<uint128_t> { typedef uint64_t type; };
/// \endcond
template<typename T> using DoubleType = typename DTI<T>::type;
template<typename T> using DoubleTypeExact = typename DTIX<T>::type;
template<typename T> using HalfType = typename HTI<T>::type;
// TODO: when we drop support for pre-C++20, then replace this with a left
// shift
template<typename I> constexpr I leftShift(I a, size_t b) {
using T = std::decay_t<I>;
if constexpr (std::is_same_v<T, int128_t> || std::is_same_v<T, uint128_t>) {
using U = uint128_t;
return (I)(((U) a) << b);
} else {
using U = std::make_unsigned_t<T>;
return (I)(((U) a) << b);
}
}
/**
* \brief A class for a binary fixed-point number.
*
* See [here](https://en.wikipedia.org/wiki/Fixed-point_arithmetic)
* for background information about fixed-point arithmetic.
*
* This type of number type can be useful when reproducibility is necessary.
* For instance, tdr uses them for gameplay-related code in order to
* avoid differences in floating-point handling that could desync replays.
*
* \tparam I The underlying integer type.
* \tparam d The number of bits after the decimal point.
*
* Aliases are defined for some types according to the following convention
* (where `n` is `CHAR_BIT * sizeof(I)`):
*
* - Fractional types (`I` is unsigned, `d == n`) are named `frac`<i>n</i>.
* - Signed types (`I` is signed, `d < n`) are named
* `s`<i>(n - d)</i>`_`<i>d</i>.
* - Unsigned types (`I` is unsigned, `d < n`) are named
* `u`<i>(n - d)</i>`_`<i>d</i>.
*
* There are several ways to construct a fixed-point number:
*
* - Initialise from an integer value
* - Initialise from a fixed-point type with both fewer integral digits and
* fractional bits
* - Use the \ref raw method to initialise with an underlying value
* - For the types with aliases, use a user-defined literal (see \ref
* kfp::literals)
*
* For the first two options, fixed-point numbers can be assigned from such
* types as well.
*
* Note that there are no implicit conversions to or from floating-point
* numbers.
*
* The operators `+ - * / << >>` are available with their obvious meanings,
* as well as their assignment variants. The relations `== != < <= > >=` are
* defined as well.
*
* `*` can be applied as long as the underlying integer type is the same
* between the left-hand and right-hand sides, even if the number of
* fractional bits is different. `>>` and `<<` take integer arguments for the
* right-hand side. Other operators can be applied only to the exact same
* types.
*
* Note that the result of `*` when the left-hand side is a fixed-point number
* is that of the left-hand side.
*
* Also see \ref longMultiply, which returns a type big enough to hold the
* product.
*/
template<typename I, size_t d> struct Fixed {
using F = kfp::Fixed<I, d>;
using Underlying = I;
/// The representation of a fixed-point number as an integer.
I underlying;
// Sanity checks
// Is I an integer?
static_assert(
std::numeric_limits<I>::is_integer || std::is_same_v<I, int128_t> ||
std::is_same_v<I, uint128_t>,
"I must be an integer type");
template<typename I2, size_t d2>
using HasIntegerBits = std::enable_if_t<(d2 < CHAR_BIT * sizeof(I2))>;
template<typename I2, size_t d2>
using HasNoIntegerBits =
std::enable_if_t<(d2 >= CHAR_BIT * sizeof(I2)), int>;
// Constructors
constexpr Fixed() = default; // : underlying(0) {}
/**
* \brief Construct a value from an integer.
*
* The underlying value is the argument shifted left by the number of bits
* after the radix. That is, `kfp::s16_16(3).underlying == (3 << 16)`.
*/
template<
typename I2 = I, size_t d2 = d, HasIntegerBits<I2, d2>* dummy = nullptr>
constexpr Fixed(I value) noexcept : underlying(leftShift(value, d)) {}
/**
* \brief Construct a value from an integer.
*
* This overload is used when the number has no integral bits. Thus, the
* underlying value is always zero.
*/
template<
typename I2 = I, size_t d2 = d,
HasNoIntegerBits<I2, d2>* dummy = nullptr>
constexpr Fixed(I value) noexcept : underlying(0) {
(void) value;
}
constexpr Fixed(const F& value) = default;
// Implicit cast from smaller type
template<typename I2, size_t d2, typename I3, size_t d3>
using IsConvertible = std::enable_if_t<
(std::numeric_limits<I2>::digits - d2) >=
(std::numeric_limits<I3>::digits - d3) &&
d2 >= d3,
int>;
template<typename I2, size_t d2, typename I3, size_t d3>
using IsNonConvertible = std::enable_if_t <
(std::numeric_limits<I2>::digits - d2) <
(std::numeric_limits<I3>::digits - d3) ||
d2<d3>;
/// Implicitly cast from a type with fewer integral digits and fractional
/// bits.
template<
typename I2, size_t d2, typename I3 = I, size_t d3 = d,
IsConvertible<I3, d3, I2, d2>* dummy = nullptr>
constexpr Fixed(const Fixed<I2, d2>& other) noexcept {
static_assert(
(std::numeric_limits<I>::digits - d) >=
(std::numeric_limits<I2>::digits - d2),
"Cannot implicitly cast into a type with fewer integral digits");
static_assert(
d >= d2,
"Cannot implicitly cast into a type with fewer fractional bits");
// How much left should we shift?
underlying = other.underlying;
if (fractionalBits() >= other.fractionalBits())
underlying =
leftShift(underlying, fractionalBits() - other.fractionalBits());
else
underlying >>= (other.fractionalBits() - fractionalBits());
}
/// Explicitly cast from a type that either has more integral digits or
/// more fractional bits.
template<
typename I2, size_t d2, typename I3 = I, size_t d3 = d,
IsNonConvertible<I3, d3, I2, d2>* dummy = nullptr>
explicit constexpr Fixed(const Fixed<I2, d2>& other) noexcept {
// How much left should we shift?
if (fractionalBits() >= other.fractionalBits())
underlying = leftShift(
other.underlying, fractionalBits() - other.fractionalBits());
else
underlying =
other.underlying >> (other.fractionalBits() - fractionalBits());
}
/**
* \brief Construct a fixed-point number from an underlying value.
*
* For example, `kfp::s16_16::raw(5835)` represents the number
* 5835 / 65536.
*/
constexpr static F raw(I underlying) noexcept {
F ret(0);
ret.underlying = underlying;
return ret;
}
/**
* \brief Construct a fixed-point number from a ratio of two integers.
*/
constexpr static F fraction(I num, I denom) noexcept {
using D = DoubleType<I>;
D x = num;
x = leftShift(x, d);
x /= denom;
return raw((I) x);
}
/// Get the number of integral bits, including the sign bit.
static constexpr size_t integralBits() noexcept {
return CHAR_BIT * sizeof(I) - d;
}
/// Get the number of integral digits, excluding the sign bit.
static constexpr size_t integralDigits() noexcept {
return std::numeric_limits<I>::digits - d;
}
/// Get the number of fractional bits.
static constexpr size_t fractionalBits() noexcept { return d; }
// Operator defines
F& operator=(const F& other) = default;
/// Assign from an integer.
constexpr F& operator=(const I& i) noexcept {
underlying = leftShift(i, d);
return *this;
}
template<typename I2, size_t d2>
constexpr F& operator=(const Fixed<I2, d2>& other) noexcept {
static_assert(
integralDigits() >= other.integralDigits(),
"Cannot implicitly cast into a type with fewer integral digits");
static_assert(
fractionalBits() >= other.fractionalBits(),
"Cannot implicitly cast into a type with fewer fractional bits");
// How much left should we shift?
underlying = other.underlying;
if (fractionalBits() >= other.fractionalBits())
underlying =
leftShift(underlying, fractionalBits() - other.fractionalBits());
else
underlying >>= (other.fractionalBits() - fractionalBits());
return *this;
}
# define DEF_OP_BOILERPLATE(o) \
template<typename X> \
constexpr F operator o(const X& other) const noexcept { \
F ret = *this; \
ret o## = other; \
return ret; \
}
# define DEF_OP_BOILERPLATE2(o) \
DEF_OP_BOILERPLATE(o) \
template< \
typename I2, \
std::enable_if_t<std::is_integral<I2>::value, void*> dummy = nullptr> \
constexpr F& operator o##=(const I2& other) noexcept { \
*this o## = F(other); \
return *this; \
}
# define DEF_OP(o) \
DEF_OP_BOILERPLATE2(o) \
constexpr F& operator o##=(const F& other) noexcept
// end define
DEF_OP(+) {
underlying += other.underlying;
return *this;
}
DEF_OP(-) {
underlying -= other.underlying;
return *this;
}
DEF_OP(&) {
underlying &= other.underlying;
return *this;
}
DEF_OP(|) {
underlying |= other.underlying;
return *this;
}
DEF_OP(^) {
underlying ^= other.underlying;
return *this;
}
DEF_OP_BOILERPLATE(*)
template<
typename I2, size_t d2, typename I3 = I, size_t d3 = d,
IsConvertible<I3, d3, I2, d2>* dummy = nullptr>
constexpr F& operator*=(const Fixed<I2, d2>& other) noexcept {
DoubleType<I> prod = ((DoubleType<I>) underlying) * other.underlying;
underlying = (I)(prod >> other.fractionalBits());
return *this;
}
template<size_t d2>
constexpr F& operator*=(const Fixed<I, d2>& other) noexcept {
DoubleType<I> prod = ((DoubleType<I>) underlying) * other.underlying;
underlying = (I)(prod >> other.fractionalBits());
return *this;
}
constexpr F& operator*=(I other) noexcept {
underlying *= other;
return *this;
}
DEF_OP_BOILERPLATE(/)
constexpr F& operator/=(const F& other) noexcept {
DoubleType<I> dividend = leftShift((DoubleType<I>) underlying, d);
underlying = (I)(dividend / other.underlying);
return *this;
}
constexpr F& operator/=(I other) noexcept {
underlying /= other;
return *this;
}
DEF_OP_BOILERPLATE(<<)
constexpr F& operator<<=(int shift) noexcept {
underlying = leftShift(underlying, shift);
return *this;
}
DEF_OP_BOILERPLATE(>>)
constexpr F& operator>>=(int shift) noexcept {
underlying >>= shift;
return *this;
}
constexpr F operator-() const noexcept {
F ret = *this;
ret.underlying = -ret.underlying;
return ret;
}
constexpr F operator~() const noexcept {
F ret = *this;
ret.underlying = ~ret.underlying;
return ret;
}
# undef DEF_OP
# undef DEF_OP_BOILERPLATE
# undef DEF_OP_BOILERPLATE2
/**
* \brief Explicitly convert to an integer type.
*
* This just calls \ref floor().
*/
explicit constexpr operator I() const noexcept { return floor(); }
/**
* \brief Get the floor of the number.
*
* The number is rounded down to the next integer.
*/
constexpr I floor() const noexcept {
if constexpr (d < sizeof(I) * CHAR_BIT) {
return underlying >> d;
} else {
return underlying >= 0 ? 0 : -1;
}
}
/**
* \brief Get the floor of the number.
*
* The number is rounded up to the next integer.
*/
constexpr I ceil() const noexcept {
[[maybe_unused]] constexpr I one = 1;
if constexpr (d == 0) {
return floor(); // there can be no decimal part
} else if constexpr (d >= sizeof(I) * CHAR_BIT) {
return underlying > 0 ? 1 : 0;
} else {
return (underlying + (one << d) - 1) >> d;
}
}
/**
* \brief Round the number to the nearest integer.
*/
constexpr I round() const noexcept {
[[maybe_unused]] constexpr I one = 1;
if constexpr (d == 0) {
return floor(); // there can be no decimal part
} else if constexpr (d == sizeof(I) * CHAR_BIT) {
return (((DoubleType<I>) underlying) + (one << (d - 1))) >> d;
} else {
return (underlying + (one << (d - 1))) >> d;
}
}
/// Convert to a double.
constexpr double toDouble() const noexcept {
return ((double) underlying) / exp2(d);
}
};
template<typename I, size_t d> struct DTI<Fixed<I, d>> {
typedef Fixed<DoubleType<I>, 2 * d> type;
};
template<typename I, size_t d> struct DTIX<Fixed<I, d>> {
typedef Fixed<DoubleTypeExact<I>, 2 * d> type;
};
/**
* \brief Multiply two fixed-point numbers and return the result in a type
* that is large enough.
*
* The underlying types of the two numbers must be the same, but the number
* of bits after the radix can be different.
*/
template<typename I, size_t d, size_t d2>
constexpr Fixed<DoubleTypeExact<I>, d + d2>
longMultiply(Fixed<I, d> a, Fixed<I, d2> b) noexcept {
DoubleTypeExact<I> p = a.underlying;
p *= b.underlying;
return Fixed<DoubleTypeExact<I>, d + d2>::raw(p);
}
/**
* \brief Multiply two integers and return the result in a type
* that is large enough.
*/
template<
typename I,
std::enable_if_t<std::is_integral<I>::value, void*> dummy = nullptr>
constexpr DoubleTypeExact<I> longMultiply(I a, I b) noexcept {
DoubleTypeExact<I> p = a;
p *= b;
return static_cast<DoubleTypeExact<I>>(a) * b;
}
// Relational operators
# define DEF_RELATION(o) \
template<typename I, size_t d> \
constexpr bool operator o( \
const Fixed<I, d>& a, const Fixed<I, d>& b) noexcept { \
return a.underlying o b.underlying; \
}
DEF_RELATION(==)
DEF_RELATION(!=)
DEF_RELATION(<)
DEF_RELATION(<=)
DEF_RELATION(>)
DEF_RELATION(>=)
# undef DEF_RELATION
# define DEF_RELATION_I(o, o2) \
template< \
typename I, size_t d, typename I2, \
std::enable_if_t<std::is_integral<I2>::value, void*> dummy = nullptr> \
constexpr bool operator o(const Fixed<I, d>& a, I2 b) noexcept { \
return a.floor() o2 b && a.underlying o leftShift((I) b, d); \
} \
template< \
typename I, size_t d, typename I2, \
std::enable_if_t<std::is_integral<I2>::value, void*> dummy = nullptr> \
constexpr bool operator o(I2 a, const Fixed<I, d>& b) noexcept { \
return a o2 b.floor() && leftShift((I) a, d) o b.underlying; \
}
DEF_RELATION_I(==, ==)
DEF_RELATION_I(<, <=)
DEF_RELATION_I(>, >=)
# undef DEF_RELATION_I
# define DEF_RELATION_INV(o, o2) \
template< \
typename I, size_t d, typename I2, \
std::enable_if_t<std::is_integral<I2>::value, void*> dummy = nullptr> \
constexpr bool operator o(const Fixed<I, d>& a, I2 b) noexcept { \
return !(a o2 b); \
} \
template< \
typename I, size_t d, typename I2, \
std::enable_if_t<std::is_integral<I2>::value, void*> dummy = nullptr> \
constexpr bool operator o(I2 a, const Fixed<I, d>& b) noexcept { \
return !(a o2 b); \
}
DEF_RELATION_INV(!=, ==)
DEF_RELATION_INV(<=, >)
DEF_RELATION_INV(>=, <)
# undef DEF_RELATION_INV
# define BACK_OPERATOR(o) \
template< \
typename I, size_t d, typename I2, \
std::enable_if_t<std::is_integral<I2>::value, void*> dummy = nullptr> \
constexpr kfp::Fixed<I, d> operator o(I2 n, kfp::Fixed<I, d> x) noexcept { \
return x o n; \
}
BACK_OPERATOR(+)
BACK_OPERATOR(*)
template<
typename I, size_t d, typename I2,
std::enable_if_t<std::is_integral<I2>::value, void*> dummy = nullptr>
constexpr kfp::Fixed<I, d> operator-(I2 n, kfp::Fixed<I, d> x) noexcept {
return -(x - n);
}
template<
typename I, size_t d, typename I2,
std::enable_if_t<std::is_integral<I2>::value, void*> dummy = nullptr>
constexpr kfp::Fixed<I, d> operator/(I2 n, kfp::Fixed<I, d> x) noexcept {
return kfp::Fixed<I, d>(n) / x;
}
# undef BACK_OPERATOR
// end
using s16_16 = Fixed<int32_t, 16>;
using u16_16 = Fixed<uint32_t, 16>;
using s2_30 = Fixed<int32_t, 30>;
using s34_30 = Fixed<int64_t, 30>;
using frac32 = Fixed<uint32_t, 32>;
// User-defined literals
/**
* \brief Convert a decimal string into a fixed-point number.
*
* * Negative numbers are not yet supported.
* * The decimal point is optional.
* * It is legal to omit any digit before the decimal point or after it.
* If only the decimal point is present, then the result is zero.
* * The empty string results in zero.
* * If there are any invalid characters, then the result is undefined.
*/
template<typename I, size_t d> constexpr Fixed<I, d> convert(const char* s) {
using F = Fixed<I, d>;
// Decimal point present?
const char* t = s;
while (*t != '\0' && *t != '.') ++t;
bool hasDecimal = *t == '.';
const char* u = s;
I iPart = 0;
while (u != t) {
iPart *= 10;
iPart += (*u) - '0';
++u;
}
F res(iPart);
if (hasDecimal && t[1] != '\0') {
using U = std::make_unsigned_t<I>;
U fDigits = 0;
U fDivide = 1;
u = t + 1;
while (*u != '\0') {
if (fDivide >= std::numeric_limits<U>::max() / 10) break;
fDigits = 10 * fDigits + ((*u) - '0');
fDivide *= 10;
++u;
}
U fPart = 0;
for (size_t i = 0; i < d; ++i) {
// Get `d` fractional bits
// It's not safe to multiply by 2 yet --
// if U is uint64_t,
// then fDivide could be as high as 10000000000000000000,
// with fDigits as high as 9999999999999999999;
// multiplying fDigits by 2 would overflow in this case.
// Instead, compare to fDivide / 2.
bool is1 = fDigits >= fDivide / 2;
fPart = (fPart << 1) | is1;
if (is1) fDigits -= fDivide / 2;
// Now fDigits < fDivide / 2, so we can safely multiply by 2.
fDigits <<= 1;
}
// Now the `d` low bits of fPart are set.
res += F::raw((I) fPart);
}
return res;
}
# define DEFINE_OPERATOR_LITERAL(type) \
constexpr type operator""_##type(const char* s, size_t) { \
return convert<type::Underlying, type::fractionalBits()>(s); \
}
/**
* \brief Operator literals for every fixed-point type with an alias.
*
* You can use them with
*
* <code>
* using namespace kfp::literals;
* </code>
*/
namespace literals {
DEFINE_OPERATOR_LITERAL(s16_16)
DEFINE_OPERATOR_LITERAL(u16_16)
DEFINE_OPERATOR_LITERAL(s2_30)
DEFINE_OPERATOR_LITERAL(s34_30)
DEFINE_OPERATOR_LITERAL(frac32)
}
# undef DEFINE_OPERATOR_LITERAL
template<typename T> struct IsFixedPoint {
constexpr static bool value = false;
};
template<typename I, size_t d> struct IsFixedPoint<Fixed<I, d>> {
constexpr static bool value = true;
};
template<typename T> constexpr bool isFixedPoint = IsFixedPoint<T>::value;
}
template<typename I, size_t d> struct std::numeric_limits<kfp::Fixed<I, d>> {
static constexpr int ctl10o2(int x) noexcept { return (31 * x + 99) / 100; }
using F = kfp::Fixed<I, d>;
static constexpr bool is_specialized = true;
static constexpr bool is_signed = std::numeric_limits<I>::is_signed;
static constexpr bool is_integer = false;
static constexpr bool is_exact = true;
static constexpr bool has_infinity = false;
static constexpr bool has_quiet_NaN = false;
static constexpr bool has_signaling_NaN = false;
static constexpr bool has_denorm = false;
static constexpr bool has_denorm_loss = false;
// TODO set a proper value for this
static constexpr std::float_round_style round_style =
std::float_round_style::round_indeterminate;
static constexpr bool is_iec559 = false;
static constexpr bool is_bounded = std::numeric_limits<I>::is_bounded;
static constexpr bool is_modulo = std::numeric_limits<I>::is_modulo;
static constexpr int digits = std::numeric_limits<I>::digits;
static constexpr int digits10 = std::numeric_limits<I>::digits10;
static constexpr int max_digits10 =
ctl10o2(std::numeric_limits<I>::digits) + 1;
static constexpr int radix = 2;
static constexpr int min_exponent = -d + 1;
static constexpr int max_exponent = std::numeric_limits<I>::digits - d;
static constexpr int min_exponent10 = ctl10o2(-d + 1);
static constexpr int max_exponent10 =
ctl10o2(std::numeric_limits<I>::digits - d);
static constexpr bool traps = true;
static constexpr bool tinyness_before = false;
static constexpr F min() noexcept {
return F::raw(std::numeric_limits<I>::min());
}
static constexpr F max() noexcept {
return F::raw(std::numeric_limits<I>::max());
}
static constexpr F lowest() noexcept {
return F::raw(std::numeric_limits<I>::lowest());
}
static constexpr F epsilon() noexcept { return F::raw(1); }
static constexpr F round_error() noexcept { return F::raw(1 << (d - 1)); }
static constexpr F infinity() noexcept { return F(0); }
static constexpr F quiet_NaN() noexcept { return F(0); }
static constexpr F signaling_NaN() noexcept { return F(0); }
static constexpr F denorm_min() noexcept { return F(0); }
};
template<typename I, size_t d> struct std::hash<kfp::Fixed<I, d>> {
using F = kfp::Fixed<I, d>;
size_t operator()(const F& f) const noexcept {
return std::hash<I>()(f.underlying);
}
};
#endif // KOZET_FIXED_POINT_KFP_H
repack.py
Tools to mod a shitty MMO
#!/usr/bin/env python3
import argparse
import io
import pathlib
import re
import zlib
# The MIT License (MIT)
# Copyright (c) 2016 kyarei
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# Usage: python3 repack.py <root dir> <archive name>
# Parse the arguments
parser = argparse.ArgumentParser(description='Repack Wizard101 WAD files.')
parser.add_argument('sourcePath', type=str,
help='the root directory of the files to be archived')
parser.add_argument('archivePath', type=str,
help='the path of the archive file to be made')
parser.add_argument('blacklist', type=str, nargs='?', default='',
help='a file containing patterns to avoid compressing')
parser.add_argument('--verbose', '-v', type=bool,
help='if enabled, use diagnostics')
args = parser.parse_args()
# Get all files in the directory specified
root = pathlib.Path(args.sourcePath)
files = root.glob("**/*");
blacklist = set()
if args.blacklist != '':
blacklistPatterns = re.split('\s', open(args.blacklist).read(-1))
for p in blacklistPatterns:
if p != '':
blacklist.update(set(root.glob(p)))
entries = []
offset = 14 # Precalculate offset of data section in loop below
# Make entries of all files
for f in files:
if f.is_file():
with f.open(mode="rb") as h:
contents = h.read(-1)
isCompressed = not f in blacklist
zSize = 0xFFFFFFFF
uSize = len(contents)
if isCompressed:
compressedContents = zlib.compress(contents)
zSize = len(compressedContents)
isCompressed = zSize < uSize
name = str(f.relative_to(root))
name = name.replace("\\", "/")
crc = zlib.crc32(contents)
entry = {
"contents": compressedContents if isCompressed else contents,
"uSize": uSize,
"zSize": zSize,
"name": name,
"isCompressed": isCompressed,
"crc": crc
}
entries.append(entry)
offset += 22 + len(name)
if args.verbose:
print("> File %s acknowledged" % name)
if args.verbose:
print("%d files acknowledged" % len(entries))
# Open the output file
out = open(args.archivePath, "wb");
def writeByte(stream, val):
stream.write(bytes([val]))
def writeInt(stream, val):
stream.write(val.to_bytes(4, byteorder="little"))
if args.verbose:
print("Opened output file; writing data...")
# Write magic string
out.write(b"KIWAD")
# Write version
writeInt(out, 2)
# Write number of files
writeInt(out, len(entries))
# Write dummy byte
writeByte(out, 1)
# Write file ENTRIES
for e in entries:
netSize = e["zSize"] if e["isCompressed"] else e["uSize"]
writeInt(out, offset) # Offset
writeInt(out, e["uSize"])
writeInt(out, e["zSize"])
writeByte(out, e["isCompressed"])
writeInt(out, e["crc"])
writeInt(out, len(e["name"].encode()) + 1) # includes terminating null
out.write(e["name"].encode())
writeByte(out, 0)
offset += netSize
if args.verbose:
print("> Wrote ENTRY for %s" % e["name"])
# Write file DATA
for e in entries:
out.write(e["contents"])
if args.verbose:
print("> Wrote DATA for %s" % e["name"])
stupid.sed
Stupid shit.
y/azkjunto/eþlpirna/
y/sbþwhm/aecmtþ/
s/e\b/a/g
y/fgctdply/ołcavenf/
s/neri/aca/g
s/niciena/niâsmir/g
s/þi//g
s/\biłan/velš/g
s/aeee/cfiþ/g
s/enaiþa/engor/g
s/arłiri/aricos/g
s/nan/nt/g
s/eei/edan/g
s/nera/nos/g
s/łere/łmiþ/g
s/va/s/g
s/eir/oŋa/g
s/\bner/nap/g
s/apna/ħecþ/g
s/\bi/a/g
s/\bne/vo/g
s/\bna/ena/g
s/\breci/tisa/g
s/re\b/reten/g
s/voł/enþ/g
s/acai/avil/g
s/oir/râm/g
s/fan/irł/g
s/\bn//g
s/vo\b/leþvo/g
s/ireł/iror/g
s/eer/end/g
s/eri/erþei/g
s/erła/erâþ/g
s/\bin/cþin/g
s/ti\b/anti/g
s/aie/ane/g
s/nei\b/neli/g
s/\bain/nav/g
s/\biþ/ân/g
s/si\b/sira/g
s/\baiac/airl/g
s/es/ełes/g
s/\bcii/cþa/g
s/ae/te/g
s/meaa/mefl/g
s/\bvoe/vêł/g
s/ta\b/ên/g
s/\bii/fo/g
s/aa\b/arva/g
s/nai/nar/g
s/ren/lâri/g
s/\beni/efi/g
s/ai\b/a/g
s/\bri/mari/g
s/aai/ine/g
s/\baa/draa/g
s/pe/pel/g
s/\baiił/aisł/g
s/naa/nat/g
s/eþa\b/ea/g
s/\bara/arâa/g
s/vera\b/vena/g
s/ers\b/enrs/g
s/ii/ir/g
s/słir/słr/g
s/io/mo/g
s/\beda/ede/g
s/\bef/sef/g
s/ea\b/es/g
s/riaa\b/rita/g
s/\blâ/va/g
s/ria\b/ri/g
s/\błe/ŋa/g
s/\bira/ivi/g
s/moi\b/mos/g
s/nr/na/g
s/\bfi/či/g
s/\bra/ša/g
s/aa\b/aal/g
s/râa/rân/g
s/\brt/r/g
s/cera\b/cea/g
s/ai/vi/g
s/ven/venn/g
s/\bsef/serf/g
s/ona\b/on/g
s/nti\b/ntr/g
s/voc/von/g
s/cþin/cþon/g
s/fa\b/fal/g
s/mari\b/mali/g
s/łm/m/g
s/þei\b/þen/g
s/ac/čac/g
s/ene/eme/g
s/\bed/ged/g
s/ara\b/arô/g
s/li\b/liþ/g
s/\bam/m/g
s/\bi/e/g
s/er\b/erł/g
s/nera\b/neþa/g
s/\ber/ir/g
s/e\b/en/g
s/ł\b/łs/g
s/erł/er/g
s/łs\b/łas/g
s/ene/i/g
s/\biþ/ineþ/g
s/no/lo/g
s/rs/rþ/g
s/tar/ter/g
s/cþa/ceþa/g
s/ên/ðên/g
s/\bâ/sâ/g
s/\bfen/fel/g
s/\bei/i/g
s/tr\b/tar/g
s/\ban/can/g
s/\bcea/ces/g
s/þvo\b/þmo/g
s/\bfa/ta/g
s/raal\b/ranal/g
s/ša\b/šan/g
s/fo/tfo/g
s/ši\b/šit/g
s/þir\b/þit/g
s/em/lem/g
s/słr/sło/g
s/\bar/atr/g
s/\ba/va/g
s/\bvav/v/g
s/eâ/nâ/g
s/\brâ/prâ/g
s/sr/vr/g
s/ev/iv/g
s/di\b/dit/g
s/nar\b/na/g
s/ca\b/can/g
s/fi\b/fil/g
s/nat\b/clnat/g
s/lna/lja/g
s/\biro/fliro/g
s/\bf/\*/g
s/\*e/fe/g
s/mar/ser/g
s/varia/vanda/g
s/\bvar/lâr/g
s/tera/tvra/g
s/tvr/tovr/g
s/nþen/nþe/g
s/\breł/dreł/g
s/ana\b/jana/g
s/\bca/a/g
s/\bted/ed/g
s/êła/êłas/g
s/\bvat/at/g
s/\bva/eva/g
s/eva\b/meva/g
s/\bev/v/g
s/\bvir/łir/g
s/iþa\b/iþas/g
s/den/dena/g
s/\btal/þal/g
s/fliþ/fli/g
s/ven/pen/g
s/aliþ\b/alin/g
s/\bret/cret/g
s/enþ/menþ/g
s/von\b/ron/g
s/\bvo/avo/g
s/\benap/gðenap/g
s/\bena/na/g
s/\ben/ener/g
s/\bterþ/lerþ/g
s/fiþas\b/fiþar/g
s/\brena/vena/g
s/irła\b/dirła/g
s/\bir/er/g
s/liroŋ/piroŋ/g
s/\*l/fl/g
name_generator.rkt
Name generator from long, long ago.
;; The first three lines of this file were inserted by DrRacket. They record metadata
;; about the language level of this file in a form that our tools can easily process.
#reader(lib "htdp-advanced-reader.ss" "lang")((modname |name generator|) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #t #t none #f ())))
(require racket)
(define (with-a-prob P)
(< (random) P))
(define (ending)
(cond
[(with-a-prob 0.5) (cond
[(with-a-prob 3/25) "a"]
[(with-a-prob 3/22) "o"]
[(with-a-prob 2/19) "e"]
[(with-a-prob 2/17) (if (with-a-prob 0.5) "yth" "ith")]
[(with-a-prob 2/15) "ath"]
[(with-a-prob 2/13) (if (with-a-prob 0.5) "yn" "in")]
[(with-a-prob 2/11) "en"]
[(with-a-prob 1/9) "i"]
[(with-a-prob 1/8) "an"]
[(with-a-prob 1/7) "as"]
[(with-a-prob 1/6) "es"]
[(with-a-prob 1/5) (if (with-a-prob 0.5) "ys" "is")]
[(with-a-prob 1/4) "arth"]
[else "a"])]
[else (cond
[(with-a-prob 1/4) "os"]
[(with-a-prob 1/3) "or"]
[(with-a-prob 1/3) "ios"]
[(with-a-prob 1/2) "on"]
[else "ion"])]))
(define (initial-poss-omit) (if (with-a-prob 3/4) (initial) ""))
(define (initial)
(string-append (cond
[(with-a-prob 1/16) "c"]
[(with-a-prob 1/15) "d"]
[(with-a-prob 1/14) "f"]
[(with-a-prob 1/13) "g"]
[(with-a-prob 1/12) "l"]
[(with-a-prob 1/11) "m"]
[(with-a-prob 1/10) "n"]
[(with-a-prob 1/9) "p"]
[(with-a-prob 1/8) "r"]
[(with-a-prob 1/7) "s"]
[(with-a-prob 1/6) "t"]
[(with-a-prob 1/5) "th"]
[(with-a-prob 1/4) "v"]
[(with-a-prob 1/4) "cth"]
[(with-a-prob 1/3) "cv"]
[else "str"]) (if (with-a-prob 0.1) "r" "")))
(define (medial)
(cond
[(with-a-prob 0.8) (initial)]
[(with-a-prob 1/6) "dth"]
[(with-a-prob 1/5) "ll"]
[(with-a-prob 1/4) "cth"]
[(with-a-prob 1/3) "vd"]
[(with-a-prob 1/2) "ft"]
[else "nf"]))
(define (end-syl)
(cond
[(with-a-prob .72) ""]
[(with-a-prob 1/3) "n"]
[(with-a-prob 1/3) "r"]
[(with-a-prob 3/4) "s"]
[else "t"]))
(define (vowel)
(cond
[(with-a-prob .15) "a"]
[(with-a-prob 3/17) "e"]
[(with-a-prob 3/14) "i"]
[(with-a-prob 3/11) "o"]
[(with-a-prob 1/2) "ae"]
[else "eo"]))
(define (word syl b?)
(cond
[(= syl 1) (string-append ((if b? initial-poss-omit medial)) (ending))]
[else (string-append ((if b? initial-poss-omit medial)) (vowel) (end-syl) (word (sub1 syl) false))]))
(define (word-simp syl) (word syl true))
(define (list-of-names qty)
(map word-simp (map (lambda (a) (+ 1 (min (+ 2 (random 2)) (random 80)))) (make-list qty 3))))
(define (print-elements l)
(cond [(empty? l) void]
[else (begin (display (first l))
(newline)
(print-elements (rest l)))]))
(define (ask-to-continue echo)
(local [(define answer (begin (if echo (display "Shall I continue?\n") void)
(string-normalize-spaces (read-line))))]
(cond
[(or (string-ci=? answer "yes")
(string-ci=? answer "y")
(string-ci=? answer "true")
(string-ci=? answer "t")
(string-ci=? answer "1")) true]
[(or (string-ci=? answer "no")
(string-ci=? answer "n")
(string-ci=? answer "false")
(string-ci=? answer "f")
(string-ci=? answer "0")) false]
[(string=? answer "") (ask-to-continue false)]
[else (begin (display "That's not a valid response!\n")
(ask-to-continue false))])))
(define (Loop)
(local [(define size (begin (display "How many names shall I produce?\n")
(read)))]
(if (number? size)
(let* ([names (list-of-names size)])
(begin (display "I have:\n\n")
(print-elements names)
(if (ask-to-continue true) (Loop) void)))
(begin (display "That's not a number!\n")
(Loop)))))
(define (Main)
(begin
(display "Welcome to [name redacted]'s Name Generator!\n\n")
(Loop)))
(Main)
s1r4.lua
function s1r4(n)
local a = ""
local i = 17 * n % 26
local p = 13 - (n % 13)
for j = 1, p do
a = a .. string.char(97 + i)
i = (i + 19) % 26
end
return a
end
testValues = {
2, 4, 8, 11, 12, 21, 25, 32, 34, 37, 40,
54, 59, 67, 71, 72, 74, 82, 95, 99
}
for _, n in ipairs(testValues) do
print(n .. " " .. s1r4(n))
end
s1r5.j
Will this work?
cartmul =: dyad def ',/ y ,"1/ ((($x), 1) $ x)'
cartpow =: dyad def 'x cartmul^:y (1 0 $ 0)'
valid =: *./ @: (6 = */ , */"1)
s1r5 =: monad define
zi =. I. 0 = ,y
candidates =. ((3 3 $ ]) @: ((,y) zi }~ ])) &.> <"1 (1+i.3) cartpow #zi
valids =. > valid &.> candidates
if. 1 = +/valids do. >(0{I. valids){candidates else. 3 3 $ 0 end.
)
fib.s
AT&T syntax must fall
.intel_syntax noprefix
.globl main
main:
xor rbx,rbx
xor rbp,rbp
inc bl
a:
lea rdi,[rip+s]
mov rsi,rbp
xor eax,eax
call printf
add rbp,rbx
xchg rbx,rbp
jmp a
s: .asciz "%lu\n"
dna-simple.scala
Sorry, I had to fit this in 10 lines.
def format(a: String, b: String, i: Int) : String =
if (i >= 0) s"$a\n${" " * i}$b" else s"${" " * -i}$a\n$b"
def compare(a: String, b: String, i: Int) : Option[Int] = {
val c = b map Map('A' -> 'T', 'T' -> 'A', 'C' -> 'G', 'G' -> 'C')
val (sa, sb) = (0 max i, 0 max -i); val l = a.length - sa min b.length - sb
Some(i).filter(_ => a.slice(sa, sa + l) == c.slice(sb, sb + l)) } // sorry
def dna(a: String, b: String) : String =
format(a, b, Range(0, a.length).map((i: Int) => compare(a, b, i))
.zipAll(Range(0, b.length).map((i: Int) => compare(a, b, -i)), None, None)
.flatMap{ case (l, r) => l orElse r }.headOption.getOrElse(a.length))
WorldMixin.java
A file from a random Fabric mod.
package io.github.cottonmc.functionapi.mixin;
import io.github.cottonmc.functionapi.*;
import io.github.cottonmc.functionapi.api.script.*;
import io.github.cottonmc.functionapi.events.*;
import net.minecraft.block.*;
import net.minecraft.entity.*;
import net.minecraft.server.*;
import net.minecraft.server.world.*;
import net.minecraft.util.math.*;
import net.minecraft.world.*;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.*;
import org.spongepowered.asm.mixin.injection.callback.*;
@Mixin(World.class)
public abstract class WorldMixin{
@Shadow
public abstract MinecraftServer getServer();
@Shadow
public abstract BlockState getBlockState(BlockPos blockPos_1);
@Final
@Shadow
public boolean isClient;
@Inject(
at = @At("HEAD"),
method = "breakBlock"
)
private void broken(BlockPos blockPos, boolean bl, Entity entity, int i, CallbackInfoReturnable<Boolean> cir){
if(!this.isClient){
Block block = getBlockState(blockPos).getBlock();
ServerWorld world = (ServerWorld)(Object)this;
GlobalEventContainer.getInstance().executeEvent((ScriptedObject)block, "broken", ServerCommandSourceFactory.INSTANCE.create(world.getServer(), world, block, blockPos));
}
}
@Inject(
at = @At("RETURN"),
method = "setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z"
)
private void setBlockState(BlockPos blockPos_1, BlockState blockState, int int_1, CallbackInfoReturnable<Boolean> cir){
if(!this.isClient){
if(int_1 == 2 && cir.getReturnValue()){
ServerWorld world = (ServerWorld)(Object)this;
GlobalEventContainer.getInstance().executeEvent((ScriptedObject)blockState.getBlock(), "set", ServerCommandSourceFactory.INSTANCE.create(world.getServer(), world, blockState.getBlock(), blockPos_1));
}
if(int_1 == 67 && cir.getReturnValue()){
ServerWorld world = (ServerWorld)(Object)this;
GlobalEventContainer.getInstance().executeEvent((ScriptedObject)blockState.getBlock(), "piston_move", ServerCommandSourceFactory.INSTANCE.create(world.getServer(), world, blockState.getBlock(), blockPos_1));
}
}
}
}
frequency.pl
I wonder where this came from
#!/usr/bin/perl
my %counts = ();
while (my $cmd = <STDIN>) {
chomp $cmd ;
if (!$counts{$cmd}) {
$counts{$cmd} = 1 ;
} else {
$counts{$cmd}++ ;
}
}
foreach $k (keys %counts) {
my $count = $counts{$k} ;
print "$count $k\n" ;
}
Markov.hs
Markov madness, cringe comment not included.
module Markov where
import qualified Data.Map as Map
import Data.Map (Map, (!))
import System.Random
type Prob = Double
-- A ProbabilityStructure describes a set of possibilities with arbitrary probabilities.
data ProbabilityStructure a = Surely a | Ehh a Prob (ProbabilityStructure a) deriving Show
-- fromFreqs takes a list of pairs representing frequencies and yields a probability structure paired with the cumulative frequency.
fromFreqsCF :: Map a Prob -> (ProbabilityStructure a, Prob)
fromFreqsCF = fromFreqsCFT . Map.assocs
fromFreqsCFT :: [(a, Prob)] -> (ProbabilityStructure a, Prob)
fromFreqsCFT [(val, freq)] = (Surely val, freq)
fromFreqsCFT ((val1, freq) : rest) = let
(psRest, freqRest) = fromFreqsCFT rest
totalFreq = freq + freqRest
in (Ehh val1 (freq / totalFreq) psRest, totalFreq)
fromFreqs :: Map a Prob -> ProbabilityStructure a
fromFreqs = fst . fromFreqsCF
-- psApply takes a probability structure and an "index" and yields the element at that index.
psApply :: ProbabilityStructure a -> Prob -> a
psApply (Surely value) _ = value
psApply (Ehh val1 probability next) roll
| roll < probability = val1
| otherwise = psApply next ((roll - probability) / (1 - probability))
type MarkovChain a = Map a (ProbabilityStructure a)
markovNext :: (Ord a) => MarkovChain a -> a -> Prob -> Maybe a
markovNext chain prev roll = do
possibilities <- prev `Map.lookup` chain
return $ psApply possibilities roll
markovNextSS :: (RandomGen g, Ord a) => (MarkovChain a, a, g) -> Maybe (MarkovChain a, a, g)
markovNextSS (chain, prev, gen) = do
let (roll, gen') = randomR (0.0, 1.0) gen
next <- markovNext chain prev roll
return (chain, next, gen')
traverseMarkov :: (RandomGen g, Ord a) => (MarkovChain a, a, g) -> [a]
traverseMarkov arg = let
tm arg = case markovNextSS arg of
(Just next) -> arg : (tm next)
Nothing -> []
snd3 (_, b, _) = b
in map snd3 $ tm arg
leakyP = 0.05
markovNextSSLeaky :: (RandomGen g, Ord a) => (MarkovChain a, a, g) -> Maybe (MarkovChain a, a, g)
markovNextSSLeaky (chain, prev, gen) = do
let (roll, gen') = randomR (0.0, 1.0) gen
if (roll < leakyP) then let
(idx, gen'') = randomR (0, (Map.size chain) - 1) gen'
next = fst $ Map.elemAt idx chain
in return (chain, next, gen'')
else do
let roll' = (roll - leakyP) / (1 - leakyP)
next <- markovNext chain prev roll'
return (chain, next, gen')
traverseMarkovLeaky :: (RandomGen g, Ord a) => (MarkovChain a, a, g) -> [a]
traverseMarkovLeaky arg = let
tm arg = case markovNextSSLeaky arg of
(Just next) -> arg : (tm next)
Nothing -> []
snd3 (_, b, _) = b
in map snd3 $ tm arg
type FreqTally a = Map a (Map a Prob)
-- takes a map from keys to frequency tallies, and returns a recognized Markov chain
fromFreqTable :: FreqTally a -> MarkovChain a
fromFreqTable = Map.map fromFreqs
data MSNode a = Elem a | Start | End deriving (Eq, Ord, Show)
tallyN :: (Ord a) => FreqTally (MSNode a) -> [a] -> FreqTally (MSNode a)
tallyN tl str = tallyN' tl (Start : (map Elem str))
tallyN' :: (Ord a) => FreqTally (MSNode a) -> [MSNode a] -> FreqTally (MSNode a)
tallyN' tl [last] = tally2 tl (last, End)
tallyN' tl (first:second:rest) = let
tl' = tally2 tl (first, second)
in tallyN' tl' (second:rest)
tally2 :: (Ord a) => FreqTally a -> (a, a) -> FreqTally a
tally2 tl (from, to) = let
subtally = Map.findWithDefault Map.empty from tl
count = Map.findWithDefault 0 to subtally -- Confusing yet?
subtally' = Map.insert to (count + 1) subtally
in Map.insert from subtally' tl
tallyNN :: (Ord a) => FreqTally (MSNode a) -> [[a]] -> FreqTally (MSNode a)
tallyNN tl strs = foldl tallyN tl strs -- leaving the arguments in for clarity
Gloss
- šin-on
- all-acc.sg
- men-at
- see-inf
- ŋ\geð-i-þ.
- pfv\fail_to-3pl-past
“They failed to see anything.” Stay mad,
sed
-users!- šin-o
- all-nom.sg
- nem-an
- any-acc.sg
- racr-a.
- know-3sg
$\forall x \exists y: \text{$x$ knows $y$}$