1 public import std
.random
: uniform
;
4 import std
.exception
: Exception
;
6 public alias rnd
= uniform
;
8 class DException
: Exception
{
9 pragma(inline
, true) pure this(T
...)(T args
) {
14 class InternalError
: DException
{
15 pragma(inline
, true) pure this(T
...)(T args
) {
20 bool isvalidcolour(string hexcolour
) {
21 import std
.regex
: ctRegex
, matchFirst
;
22 auto hexcolourmatch
= ctRegex
!("#?[0-9a-fA-F]{3,6}");
24 if (matchFirst(hexcolour
, hexcolourmatch
).empty
) {
33 pure this(ubyte in_r
, ubyte in_g
, ubyte in_b
) {
39 // Default initializer is 0, so we don't need to change anythign for the default initializer
41 pure this(string hexcolour
, bool hasvalidated
=false) {
44 // strip leading #, if present
45 if ((hexcolour
.length
== 7) ||
(hexcolour
.length
== 4)) {
46 hexcolour
= hexcolour
[1..$];
50 if (hexcolour
.length
== 6) {
51 r
= hexcolour
[0..2].to
!ubyte(16);
52 g
= hexcolour
[2..4].to
!ubyte(16);
53 b
= hexcolour
[4..6].to
!ubyte(16);
55 // The ranges here are to get a string just one character long so to!ubyte works
56 r
= cast(ubyte)(hexcolour
[0..1].to
!ubyte(16)*16);
57 g
= cast(ubyte)(hexcolour
[1..2].to
!ubyte(16)*16);
58 b
= cast(ubyte)(hexcolour
[2..3].to
!ubyte(16)*16);
61 throw new InternalError("RGBColour constructor called but rgbcolour not validated!");
65 this(string hexcolour
) {
66 if (!isvalidcolour(hexcolour
)) {
67 throw new InternalError("RGBColour constructor called with faulty colour.");
69 this(hexcolour
, true);
73 void exit(ubyte code
) {
74 import core
.runtime
: Runtime
;
75 static import core
.stdc
.stdlib
;
77 core
.stdc
.stdlib
.exit(code
);
80 pure string
format(T
...)(string s
, T args
) {
81 import std
.array
: appender
;
82 import std
.format
: formattedWrite
;
83 auto w
= appender
!string();
84 formattedWrite(w
, s
, args
);
88 pure string
fillstr(int length
, char ch
=' ') {
90 while (length
--> 0) {
97 // Taken directly from http://stackoverflow.com/a/41978310
98 /* It's supposed to be incredibly performant...but honestly I used it because
99 * I could copy-paste it easily.
101 pure ubyte get256colour(RGBColour colour
) {
102 enum ubyte[6] i2cv
= [0, 0x5f, 0x87, 0xaf, 0xd7, 0xff];
103 pragma(inline
, true) {
104 pure ubyte function(ubyte) v2ci
= cast(ubyte function(ubyte) pure)(ubyte v
) => v
< 48 ?
0 : v
< 115 ?
1 : (v
- 35) / 40;
105 auto colour_index
= (int r
, int g
, int b
) => 36*r
+ 6*g
+ b
;
106 auto distance
= (int r1
, int g1
, int b1
, int r2
, int g2
, int b2
) => (r1
-r2
)*(r1
-r2
) + (g1
-g2
)*(g1
-g2
) + (b1
-b2
)*(b1
-b2
);
109 ubyte ir
= v2ci(colour
.r
), ig
= v2ci(colour
.g
), ib
= v2ci(colour
.b
);
110 ubyte average
= (colour
.r
+ colour
.g
+ colour
.b
) / 3;
111 ubyte igray
= average
> 238 ?
23 : (average
-3) / 10;
112 ubyte cr
= i2cv
[ir
], cg
= i2cv
[ig
], cb
= i2cv
[ib
];
113 ubyte gv
= cast(ubyte)(8 + 10 * igray
);
115 int colour_err
= distance(cr
, cg
, cb
, colour
.r
, colour
.g
, colour
.b
);
116 int gray_err
= distance(gv
, gv
, gv
, colour
.r
, colour
.g
, colour
.b
);
118 return cast(ubyte)(colour_err
<= gray_err ?
16 + colour_index(ir
, ig
, ib
) : 232 + igray
);
122 pragma(inline
, true) ubyte get256colour(ubyte r
, ubyte g
, ubyte b
) { return get256colour(RGBColour(r
, g
, b
)); }
123 pragma(inline
, true) ubyte get256colour(string colour
) { return get256colour(RGBColour(colour
)); }