D doesn't have weak references. So how can I make a associative array of objects without preventing their destruction?

2024-05-08 Thread Liam McGillivray via Digitalmars-d-learn
A "weak reference" (in the sense that I'm referring to) is a 
feature in some programming languages for a reference to an 
object that doesn't prevent the GC from destroying that object.


My current understanding is that D doesn't have weak references, 
though I've found some posts in this forum from many years back 
that mention something called "weakref". So is weakref a real 
thing, or just a concept that never got implemented?


The functionality that I'm going to describe would be easy with 
weak references, but I don't know how I would implement it 
without it. If there is a way to implement it without it, I would 
like to know how. I am going to describe my specific example, but 
it may apply to any class that's initialized using contents of a 
file without any of that data being modified after.


In my particular case, the class I've created is a wrapper for 
the `Texture2D` struct in Raylib. This class holds an image that 
was loaded from a file.


```
Sprite[string] spritesByPath;

Sprite getSprite(string path) {
path = path.asAbsolutePath;

if (path !in spritesByPath) {
spritesByPath[path] = new Sprite(path);
}

return spritesByPath[path];
}

class Sprite
{
Texture2D texture;
alias this = texture;
string path;

this(string path) {
texture = LoadTexture(path.toStringz);
this.path = path;
}

~this() {
if (IsWindowReady) UnloadTexture(texture);
if (path in spritesByPath) spritesByName.remove(path);
}
}
```

Alternatively, `spritesByPath` and `getSprite` may be static 
members of `Sprite`.


If D had weak references, than `spritesByPath` would be made of 
weak references so that they don't prevent the destruction of 
`Sprite` objects, which should be destroyed whenever they don't 
have any references elsewhere.


I've considered making `Sprite` reference-counted, but I couldn't 
manage to figure out how to do it properly. I tried doing 
`SafeRefCounted!Sprite` but the compiler said it doesn't work on 
`Object` types. I then tried making my own struct for reference 
counting that would be placed in place of a direct reference to 
the `Sprite` object, but there was some bug in which sometimes it 
didn't increment the reference count, so it didn't work.


What's a good way I can achieve what I'm trying to do, using 
either reference counting or a garbage-collected object?


Re: How can I put the current value of a variable into a delegate?

2024-05-08 Thread Liam McGillivray via Digitalmars-d-learn

On Wednesday, 8 May 2024 at 12:29:05 UTC, Rene Zwanenburg wrote:
Interestingly enough C# used to have the same behaviour but MS 
decided to go for a breaking change in C# 5; now it behaves as 
most people expect.


Wow! I wonder if D would be willing to allow such a breaking 
change with the release of Phobos 3. My choice would be to have 
it use the current value by default for value types, but allow 
them to be linked to the same memory address using `*&` when the 
variable is placed in a delegate. I think that the distinction 
between value types and reference types should be consistent.


If such a breaking change isn't considered acceptable, I suppose 
a new operator can be introduced for dereferencing a variable 
when placed in a delegate. Maybe `#` or `$` if they don't 
conflict with any existing use of those symbols.


Re: How can I put the current value of a variable into a delegate?

2024-05-08 Thread Liam McGillivray via Digitalmars-d-learn

On Monday, 6 May 2024 at 16:41:38 UTC, Steven Schveighoffer wrote:

On Monday, 6 May 2024 at 06:29:49 UTC, Liam McGillivray wrote:
Delegates can be a pain, as they often have results different 
from what one would intuitively expect. This can easily result 
in bugs.


Here's a line that caused a bug that took me awhile to find:
```
foreach(card; unitCards) card.submitted = delegate() => 
selectUnit(card.unit);

```

Each `UnitInfoCard` object (which `card` is a member of) 
contains a `Unit` object called `unit`. The intention of this 
line was that each object in `unitCards` would call 
`selectUnit` with it's own `unit` every time it calls 
`submitted`. Instead, every card calls `submitted` with the 
*last* value of `card`.


Yes, this is because the foreach loop reuses the same memory 
slot for `card`.


Even though this is allocated as a closure, it still only 
allocates the frame stack of the *enclosing function*, and does 
not allocate a new slot for each loop iteration.


You can force this by using a lambda which allocates the 
closure:


```d
foreach(card; unitCards)
card.submitted = (c2) { return () => selectUnit(c2.unit); 
}(card);

```

This is a lambda which accepts `card` as a parameter, and 
returns an appropriate delegate. It is important to use a 
parameter, because if you just use card inside there, it's 
still using the single stack frame of the calling function!


...

I would love to see a solution, but the workaround at least 
exists!


-Steve


Well that's something. It's not a very good solution for a 
language that aims for readability. It took me awhile looking at 
it to figure out what it is about, as I'm not familiar with this 
syntax.


The solution that I did before seeing this was to add a function 
to `UnitInfoCard` to give it a delegate with a `Unit unit` 
parameter, and then that function would give that function with 
the `unit` parameter set to itself to it's own `submitted` 
member. I will probably keep it like this for readability.


```
void clickAction(void delegate(Unit) @safe clickAction) {
submitted = () => clickAction(unit);
}
```


How can I put the current value of a variable into a delegate?

2024-05-06 Thread Liam McGillivray via Digitalmars-d-learn
Delegates can be a pain, as they often have results different 
from what one would intuitively expect. This can easily result in 
bugs.


Here's a line that caused a bug that took me awhile to find:
```
foreach(card; unitCards) card.submitted = delegate() => 
selectUnit(card.unit);

```

Each `UnitInfoCard` object (which `card` is a member of) contains 
a `Unit` object called `unit`. The intention of this line was 
that each object in `unitCards` would call `selectUnit` with it's 
own `unit` every time it calls `submitted`. Instead, every card 
calls `submitted` with the *last* value of `card`.


This is because the delegate assignment causes the local `card` 
variable to remain alive. The delegate that's assigned is linked 
to this variable itself, not the value at the time that the 
delegate is assigned.


Is there a way I can dereference a variable when placing it in a 
delegate, so that it's current value is used, rather than the 
variable itself?


Re: Phobos function to remove all occurances from dynamic array?

2024-04-30 Thread Liam McGillivray via Digitalmars-d-learn

On Wednesday, 1 May 2024 at 01:24:55 UTC, Lance Bachmeier wrote:

Does filter do what you need?

https://dlang.org/phobos/std_algorithm_iteration.html#.filter


It seems to do it with the following line:
```
allObjects = allObjects.filter!(element => element !is 
this).array;

```

So I've found a way to do it. It's still rather strange that it's 
so difficult to find the solution to such a common problem in the 
documentation.


Re: Doing a `static foreach` or `foreach` through enum members in a template or CTFE function, while disabling deprecation warnings

2024-04-19 Thread Liam McGillivray via Digitalmars-d-learn

On Friday, 19 April 2024 at 22:24:17 UTC, Liam McGillivray wrote:

```
template enumMixin(alias Enum) {
static foreach(m; __traits(allMembers, Enum)) static if 
(!__traits(isDeprecated, __traits(getMember, Enum, m)))

{
mixin("alias "~m~" = __traits(getMember, Enum, m);");
}
};
```


Correction: The code shown above actually *does* work properly 
without any deprecation warnings. I made a mistake with the enum 
being set to the CTFE function I was previously using instead of 
this template. This template actually works.


I posted here for visibility and searchability, in case anyone 
else wants to do something like this.


Re: Doing a `static foreach` or `foreach` through enum members in a template or CTFE function, while disabling deprecation warnings

2024-04-19 Thread Liam McGillivray via Digitalmars-d-learn
Well, someone on the Discord server has been helping me attempt 
this, but while I managed to get a solution that compiles without 
errors, I still get the deprecation warning.


Here is what I ended up with:
```
template enumMixin(alias Enum) {
static foreach(m; __traits(allMembers, Enum)) static if 
(!__traits(isDeprecated, __traits(getMember, Enum, m)))

{
mixin("alias "~m~" = __traits(getMember, Enum, m);");
}
};
```

Unfortunately, the deprecation warnings still appear if the enum 
contains any deprecated members. I'm starting to suspect that the 
language doesn't currently have any features to stop this from 
happening. This is unfortunate, as it *should* be possible to 
process an enum with deprecated members *without* getting these 
warnings.


Doing a `static foreach` or `foreach` through enum members in a template or CTFE function, while disabling deprecation warnings

2024-04-19 Thread Liam McGillivray via Digitalmars-d-learn
I know that DStep generates CTFE functions to automatically make 
aliases for enum members so that the can be used without the enum 
name, as is done in C. DStep does it with a CTFE function, though 
it should also be possible with a mixin template.


Here is my attempt so far, using a mixin template:
```
template enumMixin(Enum) {
private import std.traits;
static foreach(member; EnumMembers!Enum) static if 
(__traits(isDeprecated, member))

{
private alias m = __traits(identifier, member);
alias m = member;
}
};
```

It hasn't worked so far.


Re: Making one struct work in place of another for function calls.

2024-04-16 Thread Liam McGillivray via Digitalmars-d-learn

On Wednesday, 17 April 2024 at 02:39:25 UTC, Paul Backus wrote:
This is called [row polymorphism][1], and it does not exist in 
D.


You could approximate it by making `someFunction` a template, 
and accepting any type `T` that has the necessary members 
instead of only accepting `typeB`. But this is only possible if 
you are free to modify the definition of `someFunction`.


Is there a way I can replace "`TypeB`" in the function parameters 
with another symbol, and then define that symbol to accept 
`TypeB` as an argument, but also accept `TypeA` which would get 
converted to `TypeB` using a function? I'm willing to make a 
function template if it's rather simple.


Making one struct work in place of another for function calls.

2024-04-16 Thread Liam McGillivray via Digitalmars-d-learn
I have two structs that serve roughly the same purpose, and I 
would like one to be accepted when the other is declared as a 
function parameter.


To better understand what I mean, take the following example, 
where I have a function, and two structs.

```
struct typeA {
// Some member variables here
}

struct typeB {
// Some similar member variables here, but in a different 
format

}

float someFunction(typeB input) {
// Does some stuff
// Returns result
}
```

If I want to be able to call `someFunction` (or any function with 
`TypeB` as a parameter) using `TypeA` in place of `TypeB`, and 
I'm willing to modify the definition of `TypeA`, I know that I 
can add an `opCast` and `alias this = opCast!TypeB` to `TypeA`.


But what if `typeA` is in an external library? Is there any way I 
can get `someFunction` (and any function with a `typeB` 
parameter) to accept `typeA`, only modifying the definition of 
`TypeB` (and possibly adding a single global line in it's module)?


Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function

2024-04-14 Thread Liam McGillivray via Digitalmars-d-learn
On Friday, 12 April 2024 at 15:24:38 UTC, Steven Schveighoffer 
wrote:

```d
void InitWindow(int width, int height, ref string title) {
InitWindow(width, height, cast(const(char)*)title);
}
```


This is invalid, a string may not be zero-terminated. You can't 
just cast.


Well, it did work when I tried it (using a string variable, not a 
literal of course). It displayed as it is supposed to. But from 
the information I can find on the web it looks like strings are 
sometimes but not `always` zero-terminated. Not a great look for 
the language. Are there any rules to determine when it is and 
when it isn't (for string variables)?



So there are a few things to consider:

1. Is the string *transiently used*. That is, does the function 
just quickly use the string and never refers to it again? Given 
that this is raylib, the source is pretty readable, so you 
should be able to figure this out.


I suppose. But if it turns out that the string is used 
continuously (as I assume to be the case with `InitWindow` and 
`SetWindowTitle`) and it doesn't make a copy of it, I imagine it 
would be difficult to design the function overload, as it would 
need to store a copy of the string somewhere. In that case, the 
only clean solution would be to have a global array of strings to 
store everything that's been passed to such functions, but that 
doesn't feel like a very satisfying solution. I may take a look 
inside some Raylib functions if I get back to this task.


2. If 1 is false, will it be saved in memory that is scannable 
by the GC? This is one of the most pernicious issues with using 
C libraries from D. In this case, you will need to either 
allocate the memory with C `malloc` or pin the GC memory.


You mean that the GC can destroy objects that still have 
references from the C code?


For transiently used strings, I would point you at the function 
[`tempCString`](https://github.com/dlang/phobos/blob/0663564600edb3cce6e0925599ebe8a6da8c20fd/std/internal/cstring.d#L77), which allocates a temporary C string using malloc or a stack buffer, and then frees it when done with it.


Thank you. In a previous thread, someone told me that having to 
do many deallocations slows down the program, and the GC is more 
efficient because it deallocates many objects simultaneously. Is 
this something worth considering here, or is the overhead going 
to be tiny even when it's called a few times per frame?


The obvious problem in all this is to avoid accepting string 
literals (which are magic and automatically convert to const 
char *). This is currently impossible with function 
overloading, and so you need a separate function name, or put 
them in a different module.


Aren't there any compile-time conditions for this?


Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function

2024-04-11 Thread Liam McGillivray via Digitalmars-d-learn
On Tuesday, 9 April 2024 at 12:45:55 UTC, Richard (Rikki) Andrew 
Cattermole wrote:


On 09/04/2024 12:48 PM, Liam McGillivray wrote:

I suppose this was a good new thing to learn, though I'm still 
quite far from being able to construct a function from another 
function using a template.


I suppose that if I wanted it to make a function from another 
function, I may be able to do it in a template using some 
`static foreach` to make arrays of function parameters, and 
then combine them together without the use of strings, instead 
using placeholders (aliases or whatever they'd be called) and 
maybe the `tupleof` function. Am I headed in the right 
direction (if you can understand my weak attempt to describe 
the direction I'm thinking of going in)?


``tupleof`` isn't a function, its a property to get a "tuple" a 
sequence of fields for a struct/class.


However most likely you'd have to resort to string mixins if 
you're messing about with parameters like I think? you are 
asking for.


I'm not entirely sure what you're wanting there.


Here's what I wanted to do.

In the library I'm working on, there are various declarations for 
functions defined in an external C library following the line 
`extern (C) @nogc nothrow:`. Here are some examples of such 
declarations which have a `const(char)*` parameter:

```
void InitWindow(int width, int height, const(char)* title);
void SetWindowTitle(const(char)* title);
Shader LoadShader(const(char)* vsFileName, const(char)* 
fsFileName);

```

I wanted to generate definitions of overloads of these functions 
using strings as parameters instead of `const(char)*`. For the 
`InitWindow` function shown above, the overload should be defined 
like this:

```
void InitWindow(int width, int height, ref string title) {
InitWindow(width, height, cast(const(char)*)title);
}
```
or alternatively, like the following:
```
void InitWindow(int width, int height, string title) {
InitWindow(width, height, title.toStringz);
}
```

I'm not sure which of these is better, thought the latter one 
would need to be modified to not accept string literals. I found 
that the former one has the advantage that making the `title` 
parameter `ref string` means that string literals use the 
existing version of the function. I know that the former can be 
`@nogc`, unlike the latter, though I don't know if there is any 
advantage offered by `toStringz` over `cast(const(char)*)`.


But anyway, my goal was to generate function overloads like 
either of the above. I have already posted a version of a CTFE 
function that does this, though I put them under `version 
(D_TypeInfo)` so that they aren't available in `betterC` builds, 
since the function I wrote doesn't build with `betterC`.


Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function

2024-04-09 Thread Liam McGillivray via Digitalmars-d-learn
On Tuesday, 9 April 2024 at 23:50:36 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
The string mixin triggers CTFE, if ``EnumPrefixes`` wasn't 
templated, that would cause codegen and hence error. If you 
called it in a context that wasn't CTFE only, it would codegen 
even with template and would error.


For quite a long time we emitted -betterC errors during 
semantic, we learned that this was all around a bad idea and 
moved (hopefully all but I doubt it) into the glue code. So 
only if it codegens will it error.


Well then, perhaps this is a bug (though a useful bug in my case).

If you want to investigate, you can download [this 
commit](https://github.com/LiamM32/raylib-d/blob/49a8f2a2e4285fc85b9db54ae9a49cafe8b1a5ed) of Raylib-D. The DUB package in the `rayguiexample` directory has `betterC` as a build option, yet doesn't have this error. This is despite the inclusion of a CTFE function with string appending.


It's in 
[`source/raylib/package.d`](https://github.com/LiamM32/raylib-d/blob/49a8f2a2e4285fc85b9db54ae9a49cafe8b1a5ed/source/raylib/package.d) where `mixin(EnumPrefixes!Key("KeyboardKey", "KEY_"));` appears. The definition of `EnumPrefixes` is in [`source/templates.d`](https://github.com/LiamM32/raylib-d/blob/49a8f2a2e4285fc85b9db54ae9a49cafe8b1a5ed/source/templates.d).


Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function

2024-04-09 Thread Liam McGillivray via Digitalmars-d-learn
On Sunday, 7 April 2024 at 08:59:55 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
Unfortunately runtime and CTFE are the same target in the 
compiler.


So that function is being used for both, and hence uses GC 
(appending).


Are you sure that string appending was really the problem that 
caused the "TypeInfo" build error? I forgot about this, but I had 
already had a working CTFE function with string appending before 
adding the new one that lead to this error. The symbols that it 
generates could be used in the program compiled with `betterC`.


```
string EnumPrefixes(T)(string oldName, string prefix) {
string result = "enum " ~ oldName ~ " {\n";
static foreach(member; __traits(allMembers, T)) {
result ~= "" ~ prefix ~ member ~ " = " ~ 
__traits(getMember, T, member).to!int.to!string ~ ",\n";

}
return result ~ "}\n";
}
```

The purpose of this was that the enums used by the C library were 
too verbose. I had changed them from things like 
`KeyboardKey.KEY_C` to `Key.C`. I wanted to leave the new enums 
written directly in the module since these were recommended for 
use, but then generate the old ones with CTFE for backwards 
compatibility. The function above was used like 
`mixin(EnumPrefixes!Key("KeyboardKey", "KEY_"));`, and the 
compiler would allow it even when building with `betterC`.


Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function

2024-04-08 Thread Liam McGillivray via Digitalmars-d-learn
On Tuesday, 9 April 2024 at 00:02:02 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

```d
enum Value = (a, b) {
return a + b;
}(1, 2);
```

This alone should be a CTFE only function.

But if we want template parameters, we'd need to wrap it with 
the template.


```d
template Value(int a, int b) {
enum Value = () {
return a + b;
}();
}

int value = Value!(1, 2);
```

Does that help?


I had to reread this a few times to get a sense of what this is. 
I might have just got it. This is effectively a CTFE function for 
generating a constant based on the sum of two numbers, right? 
Doing `int value = Value!(1, 2);` would set `value` to 3, right?


I suppose this was a good new thing to learn, though I'm still 
quite far from being able to construct a function from another 
function using a template.


I suppose that if I wanted it to make a function from another 
function, I may be able to do it in a template using some `static 
foreach` to make arrays of function parameters, and then combine 
them together without the use of strings, instead using 
placeholders (aliases or whatever they'd be called) and maybe the 
`tupleof` function. Am I headed in the right direction (if you 
can understand my weak attempt to describe the direction I'm 
thinking of going in)?


Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function

2024-04-08 Thread Liam McGillivray via Digitalmars-d-learn
On Monday, 8 April 2024 at 08:12:22 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

```d
template Foo(Args) {
enum Foo = () {
    return Args.init;
}();
}
```

Something like that should work instead.


I'm sorry, but I can't comprehend any of your example. What 
would be fed into `Args`? I don't understand how this works, 
or how I would use it for what I want.


You would replace it with whatever template parameters you want 
(including nothing). It's there as a place holder.


Same for the return on the closure.

But the main thing to understand is that the closure that gives 
the enum a value, that'll be CTFE only, no runtime target.


Are you saying that this is a way to guarantee that the code is 
compile-time only?


I still understand very little of this code. I'm not experienced 
in D metaprogramming; just the function I posted above was a 
major achievement for me. I don't understand how I would use the 
code you gave in place of the function I have written and posted 
above.


When you say that "You would replace it with whatever template 
parameters you want", are you saying that instead of doing 
`mixin(MakeStringOverload!SetWindowTitle); 
mixin(MakeStringOverload!LoadShader);` as posted above, I would 
write `mixin(Foo!(SetWindowTitle, LoadShader));`?


What does the `return Args.init;` line mean in your example? Am I 
supposed to replace this with a call to the CTFE function I had 
already written? If so, it didn't work. Making such a replacement 
resulted in the same "TypeInfo" error that I had already.


Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function

2024-04-07 Thread Liam McGillivray via Digitalmars-d-learn
On Sunday, 7 April 2024 at 08:59:55 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
Unfortunately runtime and CTFE are the same target in the 
compiler.


:-(
Will this ever be changed?


```d
template Foo(Args) {
enum Foo = () {
return Args.init;
}();
}
```

Something like that should work instead.


I'm sorry, but I can't comprehend any of your example. What would 
be fed into `Args`? I don't understand how this works, or how I 
would use it for what I want.


"Error: `TypeInfo` cannot be used with -betterC" on a CTFE function

2024-04-07 Thread Liam McGillivray via Digitalmars-d-learn
I'm making a modification to a D binding for a C library. I made 
a CTFE function which takes a function declaration with one or 
more `const(char)*` or `char*` parameters and makes an overload 
that accepts D strings. While this function is only used during 
compile time, unfortunately, I have found that it results in the 
library no longer supporting `-betterC`. The compiler gives the 
following error.


```
/usr/include/dlang/dmd/core/lifetime.d(2760,42): Error: 
`TypeInfo` cannot be used with -betterC
/usr/include/dlang/dmd/std/utf.d(1556,24):instantiated 
from here: `_d_newclassT!(UTFException)`
/usr/include/dlang/dmd/std/utf.d(1563,32):instantiated 
from here: `exception!(const(char)[])`
/usr/include/dlang/dmd/std/utf.d(1186,54):instantiated 
from here: `decodeImpl!(true, Flag.no, const(char)[])`
/usr/include/dlang/dmd/std/range/primitives.d(2551,18):
instantiated from here: `decode!(Flag.no, const(char)[])`
/usr/include/dlang/dmd/std/range/primitives.d(178,40):
instantiated from here: `front!char`

Error /usr/bin/dmd failed with exit code 1.
```

I don't know what part of the function uses `TypeInfo` (as I 
don't really understand what that is), but I know that it is this 
CTFE function causing the error, because commenting out the 
mixins that use it results in the `-betterC` program compiling 
properly. Here is the CTFE function I wrote:


```
string MakeStringOverload(alias func)() {
string def = ReturnType!func.stringof ~" "~ 
__traits(identifier, func) ~ "(";


auto paramNames = ParameterIdentifierTuple!func;

import std.algorithm.searching;
foreach(i, paramType; Parameters!func) {
if (paramType.stringof.canFind("char")) def ~= "ref 
string"; // Made a reference so that D string literals know to 
use the base version of the function and not this one.

else def ~= paramType.stringof;
def ~= " "~paramNames[i] ~ ", ";
}
def.length -= 2;
def ~= ") { ";
if (ReturnType!func.stringof != "void") def ~= "return ";
def ~= __traits(identifier, func) ~ "(";
foreach(i, argument; paramNames) {
if (Parameters!func[i].stringof.canFind("char")) def ~= 
"cast(char*)";

def ~= argument ~ ", ";
}
def.length -= 2;
def ~= "); }";

return def;
}
```

In the module where the base versions of functions are declared, 
I do the following to generate overloads:

```
mixin(MakeStringOverload!SetWindowTitle);
mixin(MakeStringOverload!LoadShader);
mixin(MakeStringOverload!LoadShaderFromMemory);
mixin(MakeStringOverload!GetShaderLocation);
```

So what part of my function is using "TypeInfo"? Can I somehow 
label my function as compile-time only so that it stops 
complaining? If not what else can I do to get it to stop 
complaining and compile with `betterC`?


How best to implement items and weapons in my RPG. Nested classes? Delegates?

2024-04-03 Thread Liam McGillivray via Digitalmars-d-learn
For my tactical role-playing game, I want to finally implement 
items and weapons. These are objects that a `Unit` object can 
make use of. Just as tools are often said to be an extension of 
their user, I want items to be an extension of the unit who uses 
them. I'm trying to figure out how to best implement them.


I already have an `Item` and `Weapon` class in [my 
repository](https://github.com/LiamM32/Open_Emblem), with the 
latter being a derived class of the former. But they are not used 
much, as they are not well-developed yet.


[`unit` 
module](https://github.com/LiamM32/Open_Emblem/blob/master/source/unit.d)
[`item` 
module](https://github.com/LiamM32/Open_Emblem/blob/master/source/item.d)


Different weapon types would have different formulas to determine 
whether or not they can reach a certain tile, and different 
formulas for damage. Therefore, they would need their own 
functions. For example, a bow would have a function that checks 
for obstructions over it's range, while a sword would simply 
check whether the target is in range. There are even more 
functions for non-weapon items.


I want each item to be able to return a list of actions that can 
be performed in it, for when it is selected in the menu. For 
weapons, this would be "equip", but also a list of moves that can 
be performed. If possible, I may want them to be able to access 
protected members of the `Unit` object that uses them.


In order to pass a list of options to a menu, I'm thinking of 
having a `ItemAction` struct which contains a string for it's 
name (as would appear on the menu), and a delegate for the 
function that would be called if selected. Each item can have an 
array of these.


For implementation of their unique functions, I've thought of two 
ideas. One is that the `Weapon` class will have many derivative 
classes, such as `Bow`, `Sword`, `Spear` etc, each with their own 
functions. The other idea is that there is only one weapon class, 
but it holds an array of functions or delegates for various 
moves, which would be given the appropriate functions for it's 
weapon type during construction. An advantage of the latter is 
that the weapon type can be determined within the constructor.


Another idea I'm not sure of is whether the `Item` class and it's 
derivatives should be a nested class within `Unit`. If I 
understand correctly, objects of nested classes are always 
associated with an object of the outer class, and have access to 
it's protected and private members. This may be an advantage if I 
decide to set any of the required unit attributes to `protected`.


If I don't make them nested classes, the functions in the `Item` 
class and it's derivatives would need to have either a reference 
to it's unit in the parameters, or the relevant attributes of the 
unit.


Re: Unittests pass, and then an invalid memory operation happens after?

2024-04-03 Thread Liam McGillivray via Digitalmars-d-learn

On Friday, 29 March 2024 at 01:18:22 UTC, H. S. Teoh wrote:
Take a look at the docs for core.memory.GC.  There *is* a 
method GC.free that you can use to manually deallocate 
GC-allocated memory if you so wish.  Keep in mind, though, that 
manually managing memory in this way invites memory-related 
errors. That's not something I recommend unless you're adamant 
about doing everything the manual way.


Was this function removed from the library? I don't see it in 
[the document](https://dlang.org/phobos/core_memory.html).


How is `GC.free` different from `destroy`?

I might take a look at it, but I'm not adamant about doing 
everything the manual way, so I probably won't use it very soon.


I think you're conflating two separate concepts, and it would 
help to distinguish between them.  There's the lifetime of a 
memory-allocated object, which is how long an object remains in 
the part of the heap that's allocated to it.  It begins when 
you allocate the object with `new`, and ends with the GC finds 
that it's no longer referenced and collects it.


No. I understand that when an object disappears from memory might 
happen after it disappears from the game. I'll explain later in 
this post why I wanted to remove the Unit object from memory when 
the unit dies.


There's a different lifetime that you appear to be talking 
about: the logical lifetime of an in-game object (not to be 
confused with an "object" in the OO sense, though the two may 
overlap).  The (game) object gets created (comes into existence 
in the simulated game world) at a certain point in game time, 
until something in the game simulation decides that it should 
no longer exist (it got destroyed, replaced with another 
object, whatever). At that point, it should be removed from the 
game simulation, and that's probably also what you have in mind 
when you mentioned your "die" function.


Yes; exactly. This was your hint that I'm not confusing these two 
things. Whether or not the unit object gets deleted, I need a 
function to remove it from the game on death.


The `die` function if I want the object to be destroyed on death:
```
void die() {
if (this.map !is null) this.map.removeUnit(this);
if (this.faction !is null) this.faction.removeUnit(this);
if (this.currentTile !is null) this.currentTile.occupant 
= null;

destroy(this);
}
```
The `die` function without object destruction:
```
void die() {
if (this.map !is null) this.map.removeUnit(this);
if (this.faction !is null) this.faction.removeUnit(this);
if (this.currentTile !is null) this.currentTile.occupant 
= null;

}
```

They're the same, except that the latter doesn't call `destroy`. 
The other 3 lines are required to remove references to the 
object, effectively removing it from the game.


With the latter version, I suppose that the garbage collector 
should eventually clean up the "dead" unit object now that there 
are no references to it. However, I can see this leading to bugs 
if there was another reference to the unit which I forgot to 
remove. One benefit I see in destroying the object when it's no 
longer needed is that an error will happen if any remaining 
reference to the object gets accessed, rather than it leading to 
unexpected behaviour.


However I've thought about having it destroy the unit object at 
the end of the turn rather than immediately. Another option, if I 
don't want this benefit for debugging but still want fewer 
deallocations in the end result, would be to set that last line 
to `version (debug) destroy (this)`.


Anyway, I made [a 
commit](https://github.com/LiamM32/Open_Emblem/commit/64109e556a09ecce73b1018a9e651744a5e8fcd9) a few days ago that solves the unittest error. I found that explicitly destroying every `Map` object at the end of each unittest that uses it resolved the error. Despite this resolving the error, I decided to also move those lines from the `Unit` destructor to the new `die` function. I currently have it call `destroy` on itself at the end of this new function for the reasons described, but I suppose this line can be removed if I want to.


And here's the important point: the two *do not need to 
coincide*. Here's a concrete example of what I mean. Suppose in 
your game there's some in-game mechanic that's creating N 
objects per M turns, and another mechanic that's destroying 
some of these objects every L turns.  If you map these 
creations/destructions with the object lifetime, you're looking 
at a *lot* of memory allocations and deallocations throughout 
the course of your game.  Memory allocations and deallocations 
can be costly; this can become a problem if you're talking 
about a large number of objects, or if they're being 
created/destroyed very rapidly (e.g., they are fragments flying 
out from explosions).  Since most of these objects are 
identical in type, one way of optimizing the code is to 
preallocate them: before starting your main loop, say you 

Re: Unittests pass, and then an invalid memory operation happens after?

2024-03-28 Thread Liam McGillivray via Digitalmars-d-learn

On Thursday, 28 March 2024 at 04:46:27 UTC, H. S. Teoh wrote:
The whole point of a GC is that you leave everything up to it 
to clean up.  If you want to manage your own memory, don't use 
the GC. D does not force you to use it; you can import 
core.stdc.stdlib and use malloc/free to your heart's content.


Unpredictable order of collection is an inherent property of 
GCs. It's not going away.  If you don't like it, use 
malloc/free instead. (Or write your own memory management 
scheme.)


I disagree with this attitude on how the GC should work. Having 
to jump immediately from leaving everything behind for the GC to 
fully manual memory allocation whenever the GC becomes a problem 
is a problem, which gives legitimacy to the common complaint of D 
being "garbage-collected". It would be much better if the garbage 
collector could be there as a backup for when it's needed, while 
allowing the programmer to write code for object destruction when 
they want to optimize.


Anyway, I suppose I'll have to experiment with either manually 
destroying every object at the end of every unittest, or just 
leaving more to the GC. Maybe I'll make a separate `die` 
function for the units, if you think it's a good idea.


I think you're approaching this from a totally wrong angle. 
(Which I sympathize with, having come from a C/C++ background 
myself.)  The whole point of having a GC is that you *don't* 
worry about when an object is collected.  You just allocate 
whatever you need, and let the GC worry about cleaning up after 
you. The more you let the GC do its job, the better it will be.


Now you're giving me conflicting advice. I was told that my 
current destructor functions aren't acceptable with the garbage 
collector, and you specifically tell me to leave things to the 
GC. But then I suggest that I "leave more to the GC" and move 
everything from the Unit destructor to a specialized `die` 
function that can be called instead of `destroy` whenever they 
must be removed from the game, which as far as I can see is the 
only way to achieve the desired game functionality while 
following your and Steve's advice and not having dangling 
references. But in response to that, you tell me "I think you're 
approaching this from the wrong angle". And then right after 
that, you *again* tell me to "just let the GC worry about 
cleaning up after you"? Even if I didn't call `destroy` at all 
during my program, as far as I can see, I would still need the 
`die` function mentioned to remove a unit on death.


It would be nice if you can clarify your message here. Right now 
I'm confused. I see no way to take your advice without also doing 
the `die` function.


As far as performance is concerned, a GC actually has higher 
throughput than manually freeing objects, because in a 
fragmented heap situation, freeing objects immediately when 
they go out of use incurs a lot of random access RAM roundtrip 
costs, whereas a GC that scans memory for references can 
amortize some of this cost to a single period of time.


By "manually freeing objects", do you mean through `destroy`? If 
so that's actually quite disappointing, as D is often described 
as a "systems programming language", and I thought it would be 
fun to do these optimizations of object destruction, even if I 
have the garbage collector as a backup for anything missed. Or 
did you mean with `malloc` and `free`?


Now somebody coming from C/C++ would immediately cringe at the 
thought that a major GC collection might strike at the least 
opportune time. For that, I'd say:


(1) don't fret about it until it actually becomes a problem. 
I.e., your program is slow and/or has bad response times, and 
the profiler is pointing to GC collections as the cause. Then 
you optimize appropriately with the usual practices for GC 
optimization: preallocate before your main loop, avoid frequent 
allocations of small objects (prefer to use structs rather than 
classes), reuse previous allocations instead of allocating new 
memory when you know that an existing object is no longer used.


Well, I suppose that's fine for when the GC problem is 
specifically over slowness. I'm quite new to D, so I don't really 
know what it means to "preallocate before your main loop". Is 
this a combination of using `static this` constructors and 
`malloc`? I haven't used `malloc` yet. I have tried making static 
constructors, but every time I've tried them, they caused an 
error to happen immediately after the program is launched.


I've used C++, but I haven't gotten much done with it. It was PHP 
where I made the biggest leap in my programming skills. This game 
is the furthest I've gone at making a complex program from the 
`main` loop up.


I suppose I can turn the `Tile` object into a struct, which I 
suppose will mean replacing all it's references (outside the 
map's `Tile[][] grid`) with pointers. I have thought about this 
before, since tiles are fundamentally associated with one 
particular map, 

Re: Unittests pass, and then an invalid memory operation happens after?

2024-03-27 Thread Liam McGillivray via Digitalmars-d-learn

On Wednesday, 27 March 2024 at 22:14:16 UTC, H. S. Teoh wrote:
What's the definition of this.map, this.faction, and 
this.currentTile?


As was said, and can be found on the linked repository, they are 
references to class objects.


On Thursday, 28 March 2024 at 01:47:27 UTC, Steven Schveighoffer 
wrote:
On Wednesday, 27 March 2024 at 21:43:48 UTC, Liam McGillivray 
wrote:

`Unit` destructor:
```
~this() {
this.alive = false;
if (this.map !is null) this.map.removeUnit(this);
if (this.faction !is null) 
this.faction.removeUnit(this);
if (this.currentTile !is null) 
this.currentTile.occupant = null;

}
```


The GC does not guarantee destructor order. So this code is not 
valid -- e.g. you can't count on `map` to be a valid object at 
this point.


Well, this was originally done so that when I explicitly call 
`destroy` on a Unit object (which happens in-game) it will delete 
all references to itself.


Do you think it's better for me to move this code to a `die` 
function that I can call instead, which will then call for it's 
own destruction after running those function calls?


The *only* thing you should be doing in a destructor is freeing 
non-GC resources.


I read that the garbage collector *sometimes* but not *always* 
calls destructors on deletion, which sounds crazy to me.


The GC is not guaranteed to delete memory or run destructors. 
In the current implementation, it will destroy everything at 
the end of the program that was allocated using the GC, but the 
language does not guarantee this.


What's strange is that even if I explicitly call `destroy` for 
the only two objects at the end of the last unittest, it still 
happens. I assumed that each unittest was like it's own program, 
but I suppose not. It's deleting objects from an earlier 
unittest, right?


I may be now starting to see why the use of a garbage collector 
is such a point of contention for D. Not being able to predict 
how the garbage collection process will happen seems like a major 
problem.


As mentioned, GCs do not work this way -- you do not need to 
worry about cascading removal of anything.


Wanting to avoid the GC pauses that I hear about, I was trying to 
optimize object deletion so that the GC doesn't have to look for 
every object individually. It sounds like what I'm hearing is 
that I should just leave everything to the GC. While I can do 
this without really hurting the performance of my program (for 
now), I don't like this.


I hope that solving the unpredictable destruction pattern is a 
priority for the developers of the language. This problem in my 
program wouldn't be happening if either *all* of the objects had 
their destructors called or *none* of them did.


Anyway, I suppose I'll have to experiment with either manually 
destroying every object at the end of every unittest, or just 
leaving more to the GC. Maybe I'll make a separate `die` function 
for the units, if you think it's a good idea.


Also, check your Github notifications. I have something for you.



Unittests pass, and then an invalid memory operation happens after?

2024-03-27 Thread Liam McGillivray via Digitalmars-d-learn
In my current [game 
project](https://github.com/LiamM32/Open_Emblem), [something 
strange](https://github.com/LiamM32/Open_Emblem/issues/20) has 
happened as of a recent commit. When running `dub test`, all the 
unittests appear to pass, but then after the last unittest has 
concluded an "Invalid memory operation" happens. Removing a few 
lines replaces this error with a segfault, but either way, these 
errors shouldn't be happening. Weirdly, the commit where these 
errors first appear did nothing but replace a single class-member 
function with a seemingly identical function through a mixin 
template.


The errors seem to be related to object deletion. The traceback 
output for the first error, and where GDB points to for the 
second error, is the destructor for my `Unit` class.


You see, every `Unit` object is associated with a particular 
`Map` object and `Faction` object, which it hold references to. 
Those objects in turn each have an array of `Unit` objects that 
they are associated with. In the `Unit` destructor, I have it 
call the `removeUnit` function in both the associated `Map` and 
`Faction` objects. The errors are happening in either the `Unit` 
destructor itself, or the `removeUnit` function that it calls. 
Until the commit that introduced these errors, the `removeUnit` 
function was written directly in the `Map` class in it's module, 
but this commit replaced it with the mixin template 
`UnitArrayManagement`, which `Faction` also uses.


`Unit` destructor:
```
~this() {
this.alive = false;
if (this.map !is null) this.map.removeUnit(this);
if (this.faction !is null) this.faction.removeUnit(this);
if (this.currentTile !is null) this.currentTile.occupant 
= null;

}
```

```
template UnitArrayManagement(alias Unit[] unitsArray) {
bool removeUnit(Unit unit) {
import std.algorithm.searching;
writeln("Doing `Map.removeUnit`");
Unit[] shiftedUnits = unitsArray.find(unit);
ushort unitKey = cast(ushort)(unitsArray.length - 
shiftedUnits.length);

debug {
writeln("unitsArray: ");
foreach (listedUnit; unitsArray) 
writeln(listedUnit.name~", ");

writeln("shiftedUnits: ");
foreach (listedUnit; shiftedUnits) 
writeln(listedUnit.name~", ");

}
if (shiftedUnits.length > 0) {
debug writeln("shiftedUnits.length > 0");
unitsArray[$-shiftedUnits.length] = null;
for (ushort i=0; idebug writeln("In loop. unitKey = ", unitKey, ", 
i = ", i);

unitsArray[unitKey+i] = unitsArray[unitKey+i+1];
}
unitsArray.length--;
return true;
} else return false;
}
}
```

The first error happens because I inserted some uses of `writeln` 
for debugging purposes in the new version of `removeUnit` 
(because I haven't figured out how to do the same thing with 
GDB), in which I try to get it to print the names of all the 
units in the array before deleting any of them. I suppose that it 
might get a `Invalid memory operation` when trying to access a 
member of a `Unit` object that no longer exists, but this 
shouldn't be happening. When that other `Unit` object got 
destroyed, the destructor should have called this same 
`removeUnit` function to remove it's reference from the array.


I read that the garbage collector *sometimes* but not *always* 
calls destructors on deletion, which sounds crazy to me. Is this 
a case of one unit being deleted without the destructor and then 
the next unit (of the same `Map` object) having the destructor 
called?


Are destructors normally called after a program is concluded?

The second error, which can be achieved by removing the instances 
of `writeln` in `removeUnit` (making it seemingly identical now 
to the version of this function previously defined in the `Map` 
class) is also strange. It seems to be a case of the `Unit` 
object calling a `Map` object that no longer exists. However, 
that's also strange, as the `Map` object is supposed to delete 
all it's associated units on destruction.


I wrote these destructors so that objects wouldn't have 
references floating around on their deletion, yet now I'm getting 
errors from the destructors.


So why are these things even happening *after* the unittests have 
been run? What else do I need to know about object destruction? 
What may be happening?


Re: How do I use libdparser, or any library for editing D code?

2024-03-25 Thread Liam McGillivray via Digitalmars-d-learn
Unfortunately there's no "edit" option here, but the library I 
was referring to is actually "libdparse".


Re: Can a D library have some types determined by the client program?

2024-03-25 Thread Liam McGillivray via Digitalmars-d-learn
On Thursday, 7 March 2024 at 22:18:40 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

There are two ways to do this.

1. Use templates. 
https://tour.dlang.org/tour/en/basics/templates


Thank you for teaching me how to do this. This is where I first 
learned to use templates in D, and I have been using them since 
for functions, and as of yesterday, my first mixin template.


That being said, I'm pleased to announce the return of the `Map` 
class. As of yesterday's commit, the class template `class 
MapTemp(TileType:Tile, UnitType:Unit)` and `interface Map` have 
now been replaced with a single `Map` class as they were before.


At the time I had asked about this, I had not yet discovered that 
an array of objects can be filled with objects of a derived type 
by just using the regular cast syntax. Now that I know this, I've 
decided to just create the objects under the `VisibleTile` and 
`VisibleUnit` classes, place them in the `Map` object's arrays 
(cast to `Tile` and `Unit`), and then cast them back whenever I 
need to access anything specific to the derived classes.


Now I no longer have to deal with the limitations of interfaces. 
Things should be easier now.


The straw that broke the camels back was when I made my first 
mixin template, which adds functionality to a class for 
manipulating arrays of `Unit` objects. The compiler wasn't 
allowing it in the `Map` class because the array that I was 
trying to give it access to was of `UnitType`, not specifically 
the base `Unit` class. I'm happy to have it back.


Re: Reworking the control flow for my tactical role-playing game

2024-03-24 Thread Liam McGillivray via Digitalmars-d-learn

On Saturday, 23 March 2024 at 04:32:29 UTC, harakim wrote:
* You should probably not do this, but it might give you some 
ideas for later. What I would do is make a separate thread for 
managing the UI state and push events to that thread through 
the mailbox. I have done this once (on my third version of a 
program) and it was by far the cleanest and something I was 
proud of. The benefit is you can publish those same events to a 
log and if something in your UI goes wrong, you can look at the 
log.


I was thinking about how I can have one thread doing the 
rendering and another doing everything else, given that the 
"everything else" thread would be idle most of the time. I 
thought about giving the "everything else" thread a queue; an 
array of functions that it's tasked with going over. Every UI 
interaction would add one to the queue.


It just occurred to me that this must be what you were suggesting 
here.


Re: Reworking the control flow for my tactical role-playing game

2024-03-23 Thread Liam McGillivray via Digitalmars-d-learn
On Saturday, 23 March 2024 at 23:59:18 UTC, Liam McGillivray 
wrote:
I replaced `destroy(unit)` with `map.deleteUnit(unit)`, and it 
solved the problem.


Nevermind. It turns out this was because the call to the Unit 
destructor was missing in `Map.deleteUnit`. The segfault happens 
whenever a unit is destroyed.


In this case, how should I handle safe destruction of units, 
given that there are multiple arrays that contain references to 
it?
- Just call the unit destructor directly. The unit destructor 
will call functions in `Map` & `Faction` to delist the unit from 
it's arrays.
- Call a function in `Map` which will delist the unit from 
`allUnits`, call a function in it's faction to delist it, and 
then call the unit's destructor.
- Just call the units destructor, which will be rather plain. 
`Map` & `Faction` will have functions that frequently go over 
it's list of units, and delete any null references found.


Re: Reworking the control flow for my tactical role-playing game

2024-03-23 Thread Liam McGillivray via Digitalmars-d-learn

On Saturday, 23 March 2024 at 04:32:29 UTC, harakim wrote:
This comment points to a symptom of the circular
dependency: //Always set `destroy` to false when calling from 
the Unit destructor, to avoid an infinite loop.


I was just doing some work on the AI system, and I had a segfault 
every time the enemy was in reach to attack a unit. It turns out 
this was because the destructor was called. I replaced 
`destroy(unit)` with `map.deleteUnit(unit)`, and it solved the 
problem.


Re: Reworking the control flow for my tactical role-playing game

2024-03-23 Thread Liam McGillivray via Digitalmars-d-learn

On Saturday, 23 March 2024 at 04:32:29 UTC, harakim wrote:
You should engineer the system in a way that makes sense to 
you. The currency of finishing programs is motivation and that 
comes from success and believing you will succeed. If you're 
implementing XYZ pattern from someone else, if you don't get it 
then you will get unmotivated. I have seen some pretty horrible 
programs make it to all the way done and have almost never seen 
someone's first run at a problem be both pretty and get 
finished. Don't beat yourself up about keeping it clean. If you 
feel like it or it's getting out of control where you can't 
understand it, then you should go look for a solution. The 
motivation is in moving forward, though. This is probably the 
piece of advice I wish I had in the beginning! You can always 
refactor later when it's done.


Alright. I suppose this is largely what I'm doing.

Thank you very much for looking through my code and making the 
effort to understand it. So far you are the first person to 
comment on my code, beyond the little excerpts I've pasted 
directly onto this forum.


Move to the tick system. You make a loop and update each object 
based on the time that has passed. If your tick is 1/60th of a 
second then you make a loop. In the loop, you update the map 
state knowing 1/60th of a second has passed. Then you update 
all the items and move them or deplete them or whatever however 
much would happen in 1/60th of a second. Then you update all of 
the units. Then you can update the factions or check win 
conditions. At the end of the loop, you draw everything.


When you said "tick system", I thought you meant that it would be 
asynchronous to the framerate, but then you say "At the end of 
the loop, you draw everything". Right now the function that moves 
units across the screen moves them each frame a distance 
proportional to the duration of the previous frame. I was 
thinking that a tick system would go hand-in-hand with making 
animations happen in a separate thread, but it sounds like you're 
talking about the same thread. Are you suggesting a fixed 
framerate?


Because this is a turn-based game, I don't need to update the 
factions and win conditions every frame, but at most every time a 
unit makes a move or when a new turn starts.


Your verifyEverything method is awesome. I call that strategy 
fail-fast. It means you fail right away when you have a chance 
to identify what went wrong.


That's nice. I thought it might be an amateurish solution to 
something that better programmers would do differently, similar 
to how I use `writeln` to print variables for debugging. It looks 
like I don't yet have any calls to this function, so perhaps I 
should add one under the debug configuration.


Construct the unit and then call map.setOccupant(unit) after 
the unit is constructed. I would not do anything complicated in 
a constructor. It's also generally frowned upon to pass a 
reference to an object to anything before the constructor 
completes. Most of the changes I mention are things to think 
about, but this specifically is something you ought to change.


I didn't immediately understand what you were saying, but then I 
looked at what line `unit.d:44` was at the time you wrote this.

```
map.getTile(xlocation, ylocation).setOccupant(this);
```
This is during the Unit's constructor, where it gives the `Tile` 
object a reference to itself. What exactly is wrong with this? 
Can memory addresses change when a constructor completes? I 
assumed that objects come into existence at the beginning of the 
constructor function.


Anyway, I can change this by calling `Unit.setLocation` after 
creating a new `Unit` object. That's unless if there's a 
particular reason why you think I should make this a function of 
the `Map` object.


I suppose the current system for setting up objects from a 
`JSONValue` is messy because much of the data applies to the base 
`Tile` & `Unit` objects, but then some of it needs to be in 
`VisibleTile` & `VisibleUnit` because it has sprite information.


I would also remove the unit from the map and then delete the 
unit rather than removing the unit from within the map class.


Sure. I'll change that. Even when I wrote the Unit destructor I 
was thinking that perhaps this was a bad way to implement this. I 
suppose I should just call the `Map.deleteUnit` whenever a unit 
should be deleted, right? I was also thinking of replacing 
`Map.deleteUnit` with a function that removes all null references 
from `this.allUnits` which can be called after destroying a unit, 
but unless if I need to hyper-optimize, that probably won't be 
any better than the function I have.


Another reason I would switch that line is that it's best to 
avoid circular dependencies where you can. It will make it hard 
to reason about either in isolation. It relates to that line 
because your map has units in it and your unit takes Map in the 
constructor. That is a red flag that you are too 

Re: Optimization when using a 2-dimensional array of objects

2024-03-22 Thread Liam McGillivray via Digitalmars-d-learn

On Friday, 22 March 2024 at 07:34:33 UTC, monkyyy wrote:

Is one option more efficient than the other?


You should probaly do the lazyest thing, factor out your 
"ispassable" logic, like what your walking n of 3, n of 8, n of 
15? so long as you dont do something insane it will be fast on 
a modern computer; allocating several dynamic array that are 
the size of your game world every frame could easily be not 
very sane.


Well, none of the stuff you wrote closely resembles the code that 
I have.


There are 3 reasons why I put this kind of effort into 
optimization:

- I'm obsessive.
- For the learning experience.
- Because things may get more demanding when I get further with 
the enemy AI system. One possibility is to have it make multiple 
copies of all the game objects which it will use to look ahead to 
the next 1-2 turns.


and if you really really wanted to care, you could precompute 
the "connected compoints" by flood filling across passable 
tiles with a "color" of 0, then finding an empty cell, flood 
filling with 1, etc.; and when you draw the overlay for where 
you can move you can do a heuristic check for a) they are in 
the same component, and b) the manhattan distances before c) 
doing a greedy check


I barely understand any of this, though I know what a Manhattan 
distance is. Is this about measuring distances? Manhattan 
distances appear to be how distances are determined in Fire 
Emblem, though I'm using a slightly more intensive `abs(x) + 
abs(y) + max(abs(x) + abs(y))` whenever I need a quick estimate 
of distance that doesn't account for obstructions.


Is there a memory allocation technique that would make each 
tile's location in grid inferrable based on it's memory 
address?


Yes its called an array
theres some details you need to know and you need to cast 
pointers; just try some trial and error with code like:


But objects are reference by default. This means that they don't 
really 'live' in the array I put them in, doesn't it? Wouldn't 
the the array entries just be references on the same level as any 
other?



```d
int[10] foo;

[1].print;
([7]-[0]).print;
```


This appears to be a different programming language. It isn't D.


Optimization when using a 2-dimensional array of objects

2024-03-21 Thread Liam McGillivray via Digitalmars-d-learn
In the [game I am currently 
making](https://github.com/LiamM32/Open_Emblem/blob/master/oe-raylib/source/app.d), I have a `Map` class (actually a combination of an interface & class template, but I'll call it a "class" for simplicity), in which there will probably be only one instance running at a time. In that map class is a 2-dimensional dynamic array of `Tile` objects called `grid`. What these `Tile` objects represent are like squares on a chessboard. Their placement in `grid` represents their location on the map.


Whenever a function in the game has to pass a location on the 
map, I have a dilemma between passing a reference to the tile 
object, and passing it's grid coordinates through `struct 
Vector2i {int x; int y;}`. The functions that receive this 
information sometimes must access the Tile's variables to know 
it's properties, but may also need to know it's location so that 
it can find neighbouring tiles. The `Unit` class also has a 
2-dimensional dynamic array of entities holding information on 
the unit's distance from that tile, and whether it can reach it 
during this turn.


Is one option more efficient than the other? I already have the 
location of each tile cached as a pair of variables within each 
tile. To get a location from a Tile object, a call would be made 
to the member function `Vector2i location()`. To get a tile 
object from it's coordinates, a member function of `Map` `Tile 
getTile(Vector2i location)` would be called. Should I stick to 
one over the other?


Is there a memory allocation technique that would make each 
tile's location in `grid` inferrable based on it's memory 
address? It would be nice if the two were interchangeable, so 
that I wouldn't have this dilemma.


Not knowing which option is best has lead to a little bit of 
messy syntax. Right now I have multiple versions of the functions 
`getReachable` & `getAttackable` in the 
[`Unit`](https://github.com/LiamM32/Open_Emblem/blob/master/source/unit.d) class which return a different type, because I'm not sure which is better.


Re: Reworking the control flow for my tactical role-playing game

2024-03-21 Thread Liam McGillivray via Digitalmars-d-learn
On Thursday, 21 March 2024 at 16:48:39 UTC, Steven Schveighoffer 
wrote:
On Sunday, 17 March 2024 at 00:14:55 UTC, Liam McGillivray 
wrote:
As many of you know, I have been trying to write a tactical 
role-playing game (a mix of turn-based stategy & RPG) in D. 
This is the furthest I have ever gotten in making an 
interactive program from the main function up. Right now, it 
is not yet playable as a game, but you can interact with it 
and get a rough idea of what I'm going for. Feel free to 
download and run it to see what I have so far.


https://github.com/LiamM32/Open_Emblem


I got it to run on my mac, I had to do a few updates to the 
dub.sdl file, but it did work, though I couldn't figure out how 
to make attacks work.


Great. You may be the first person to download and run it. I 
would appreciate if you committed and pushed the changes to the 
`dub.sdl` file. So far I've only tested it on Linux.


Attacks don't fully work yet. When selecting "Attack" in the 
menu, you should see the tiles in range marked in red, but 
clicking one will as far as you can tell, do nothing but bring 
you back to the previous menu. Right now it's programmed to lower 
the enemy HP on attack, but there's no way for the player to see 
that it worked. Nothing currently happens when HP goes to zero or 
lower.



## The Current Structure:
The code for Open Emblem (name subject to change) is split 
between a source library, which handles the internal game 
logic, and a graphical front-end program which uses that 
library, but makes it usable.


This is kind of cool, I like the idea!


Good to hear. It makes some things difficult when I don't allow 
myself to put anything specific to any graphics or UI library in 
the library, but it also may make it easier if I rework the 
graphics and UI.


Everything here is single-threaded. Despite that, I still get 
thousands of frames-per-second when disabling the cap on 
framerate.


Note that disabling the cap on framerate just avoids the 
sleep-per-frame that raylib does. I always recommend setting a 
cap of something like 60 unless you are going to use vsync.


The "framerate-test" configuration only exists as a benchmark to 
give me an idea of how far I am from the CPU's limit. It's not 
for playing.


In the default configuration and the others, it currently uses 
the `getRefreshRate` function to set the target framerate to the 
monitor's refresh rate on Linux. It's supposed to do that too on 
Windows, but I haven't tested it. On Mac it just sets it to 60 
FPS.


So for instance, an animation that needs to move an object from 
A to B, should be captured into a temporary item (class object, 
struct, member of the sprite, etc), where you tell it every 
time you are drawing a frame (or even better yet, each game 
tick), and let it make the changes necessary for one tick of 
time.


For instance, build an object that takes start position, end 
position, time to animate, and maybe a path function (like 
linear, ease-in/ease-out, etc), and then each frame calculates 
where the position should be based on the current time vs. the 
start time. Encapsulating all this into an object makes things 
easy to deal with. Then you just need to call it every 
frame/tick.


Interesting. This is a different approach from how I imagined it. 
I never thought I would add a whole new object just to move 
another object around. Instead I was thinking of having a 
function in `VisibleUnit` that moves itself to the next location 
on a path (represented as an array of either directions or 
locations). Either this would be called for every unit every 
frame (but it would do nothing if they don't have a path), or 
there would be an array of moving units in which this function 
would be called in the rendering loop.


Perhaps if I had just used the plain `Unit` class from the 
library instead of making the derived `VisibleUnit` class, I 
would consider this approach.


I'm not sure if you want to do event driven here. It's a 
possibility. But I find a game-tick system, where each tick, 
you update each object according to its wishes to be pretty 
easy to develop with. I will add the caveat that I am also a 
pretty novice game developer, and have never actually built a 
complete game.


If I were to recommend a system here, I'd create a linked list 
of items to "tick" every frame, with something like:


```d
interface GameObj {
   // returns false if this object is done
   bool tick();
}
```

Then basically, you go through your list every frame, and call 
the tick function, which will make needed changes, and if it 
returns false, then you remove from the list while iterating.


This means you can do N things at once, and you don't need 
multiple threads to do it.


Well this sounds not so different from signals and slots. My 
current understanding is that every time the signal is called, 
that same thread goes through a list of functions connected to 
that signal.


Back when I wrote this post, I had a worse 

Reworking the control flow for my tactical role-playing game

2024-03-16 Thread Liam McGillivray via Digitalmars-d-learn
As many of you know, I have been trying to write a tactical 
role-playing game (a mix of turn-based stategy & RPG) in D. This 
is the furthest I have ever gotten in making an interactive 
program from the main function up. Right now, it is not yet 
playable as a game, but you can interact with it and get a rough 
idea of what I'm going for. Feel free to download and run it to 
see what I have so far.


https://github.com/LiamM32/Open_Emblem

I'm now at a point where I have trouble figuring out the next 
step to making the game playable. The complexity may have just 
reached a point where I find it harder to keep track of 
everything that I have written. There is probably a fair amount 
of unused code that I abandoned after deciding on a different 
solution, but forgot to delete. There are probably also some 
amateur decisions I've made in structuring the program, given 
that I largely figured it out myself.


For some time now I've thought that I may later want to overhaul 
how the whole rendering and UI system work. Perhaps now is a good 
time since my productivity under the current system is slowing 
down.


## The Current Structure:
The code for Open Emblem (name subject to change) is split 
between a source library, which handles the internal game logic, 
and a graphical front-end program which uses that library, but 
makes it usable.


When starting, I decided to structure it this way so that I can 
experiment with different graphics and UI libraries. This may 
have been a good move, even if it complicates some aspects, as 
the first library I tried wasn't the one I've stuck with. I also 
thought that this library may also be usable as a platform for 
others to make their own tactical RPG games, though that's 
unlikely with the current direction of the project.


### The Library:
The most important modules here are `map`, `tile`, & `unit`, 
which contain the classes `Map`, `Tile`, & `Unit`. There is 
nothing here specific to any particular graphics or game library.


Well, `Map` is now longer actually a class, as it's been replaced 
by the `Map` interface and `MapTemp` template which implements 
it, but for simplicity, I'll refer to `Map` as a class. This 
class is meant to serve as the master that controls the flow of a 
single game mission. Only one instance is meant to exist at a 
time. It holds a 2-dimensional array of `Tile` objects which 
represents the grid that the game is on (like a chessboard) and 
an array of all `Unit` objects.


`Unit` represents a character in the game that can be moved on 
the map (like a chess piece). It has some stats stored as 
variables, and some functions to do various things a player (or 
AI) may ask the unit to do during their turn. Each unit occupies 
a tile object.


`Tile` is a square on the map, which has it's own *x* & *y* 
coordinate.


The `Faction` class currently only serves to store a set of units 
belonging to a certain player or AI, but is planned to play a 
bigger role later.


### The Raylib Front-end:
After looking at many libraries and taking a shot at 
[ae](https://github.com/CyberShadow/ae) & 
[godot-D](https://github.com/godot-d/godot-d) but not really 
figuring it out, I was recommended 
[raylib-d](https://github.com/schveiguy/raylib-d), a binding for 
[raylib](https://www.raylib.com/) by @Steven Schveighoffer. 
Raylib is a rather simple graphical library written in C. I ended 
up sticking with it because the website has so many 
easy-to-follow examples that make it easy as my first graphical 
library. They're written in, but I adapted them to D rather 
easily. Of course, being written in C has limitations as it isn't 
object-oriented.


This is front-end is in the 
[`oe-raylib/`](https://github.com/LiamM32/Open_Emblem/tree/master/oe-raylib) directory.


For this front-end, I've made the classes `VisibleTile` and 
`VisibleUnit`, which inherit `Tile` & `Unit`, but add sprite data 
and other graphics-related functionality.


I then have the `Mission` class which inherits the `MapTemp` 
class. This class dominates the program flow in it's current 
state. It handles loading data from JSON files, switching between 
different game phases and does most of the function calls related 
to rendering and input.


The way I have it currently, there's a `startPreparation` 
function and `playerTurn` function, each of which run a 
once-per-frame loop that renders all the necessary objects and 
takes user input. They each have a rather messy set of 
if-statements for the UI system. Any UI elements that may pop-up 
are declared before the loop begins, with if-statements to 
determine whether they should be visible this frame.


For UI elements, I currently have `version` flags for either 
`customgui` (which I started writing before discovering raygui) 
and `customgui`, which you can select between using `dub 
--config=`. Having both makes the code messier, but I haven't yet 
decided on which I prefer. They are both currently achieve 
equivalent functionality.


Re: Challenge: Make a data type for holding one of 8 directions allowing increment and overflow

2024-03-16 Thread Liam McGillivray via Digitalmars-d-learn

On Friday, 15 March 2024 at 17:25:09 UTC, Daniel N wrote:
On Tuesday, 12 March 2024 at 05:38:03 UTC, Liam McGillivray 
wrote:
I am in need of a data type for holding direction information; 
one of 8 directions on a single axis. They are named in terms 
of compass directions. If D had a 4-bit datatype, I would just 
use this and do `+=2` whenever I want to change the datatype, 
but it doesn't.


Perhaps this would be a good programming challenge for someone 
more experienced than me. Make a data type (probably a struct) 
for holding one of 8 directional values using 3 bits. It 
should accept the use of increment operators to change the 
angle.


Ideally (but optionally), it should work as an enum of the 
same name; "Direction".


Here's a unittest that it should ideally pass:


D actually supports both 3 and 4 bit integers. People will 
likely warn you of minor portability risks... but if you target 
a limited amount of platforms and prefer concise readable code, 
then it's a text book example for bitfields. The risk can 
easily be mitigated by having an unittest to catch the error 
directly(if you try to port to some exotic platform).


dmd -preview=bitfields

(Some lines stolen from Rikki)

```d
struct Direction
{
private uint value : 3;
alias this = value;

enum Direction N  = Direction(0);
enum Direction NE = Direction(1);
enum Direction E  = Direction(2);
enum Direction SE = Direction(3);
enum Direction S  = Direction(4);
enum Direction SW = Direction(5);
enum Direction W  = Direction(6);
enum Direction NW = Direction(7);
}
```


Oh wow! That looks so clean and elegant, aside from the `: 3` 
part being easy to miss, and not very readable for those not 
aware of this feature. This would be so simple. If I used this, I 
wouldn't even need to make a struct and write the operator 
overload functions; just make an enum for a 3-bit uint.


Based on the words in the command and a quick search, I'm 
guessing that this is an experimental feature that has not yet 
been accepted as part of the language. Perhaps I shouldn't use 
this then, just in case it gets pulled and someone who discovers 
my project in the future will have a build error that they don't 
know how to solve. This seems like a bigger problem than the 
extra memory the current ubyte version takes up, which is 
probably quite small for a computer of today anyway.


I suppose this would be a nice feature for the language to have 
if the syntax were reworked. Perhaps something like `uint!3 
value;` would be better.


Re: Challenge: Make a data type for holding one of 8 directions allowing increment and overflow

2024-03-16 Thread Liam McGillivray via Digitalmars-d-learn

On Friday, 15 March 2024 at 00:21:42 UTC, H. S. Teoh wrote:
On Thu, Mar 14, 2024 at 11:39:33PM +, Liam McGillivray via 
Digitalmars-d-learn wrote: [...]
I tried to rework the functions to use bitwise operations, but 
it was difficult to figure out the correct logic. I decided 
that it's not worth the hassle, so I just changed the value 
storage from `bool[3]` to `ubyte`.

[...]

Just wanted to note that while in theory bool[3] could be 
optimized by the compiler for compact storage, what you're most 
likely to get is 3 bytes, one for each bool, or perhaps even 3 
ints (24 bytes). When dealing with units of data smaller than a 
byte, you generally need to do it manually, because memory is 
not addressable by individual bits, making it difficult to 
implement things like slicing an array of bool. So the compiler 
is most likely to simplify things by making it an array of 
bytes rather than emit complex bit manipulation code to make up 
for the lack of bit-addressability in the underlying hardware.


Using bit operators like others have pointed out in this thread 
is probably the best way to implement what you want.


T


I'm curious as to what "manual implementation" would mean, since 
clearly making my own struct with `bool[3]` doesn't count. Does D 
have features for precise memory manipulation?


Anyway, I'm surprised that D has a special operator `&=` for 
doing bit manipulation on integers, especially given that the 
steps to convert an int into a bool array is more complicated. I 
would imagine the former would be a rather niche thing.


Re: Challenge: Make a data type for holding one of 8 directions allowing increment and overflow

2024-03-14 Thread Liam McGillivray via Digitalmars-d-learn
On Thursday, 14 March 2024 at 01:58:46 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
The cost of an add + increment then a bitwise and is only 2-4 
cycles on a Haswell cpu. Depending upon if its working solely 
in registers (via inlining) or its operating on ram.


Whereas if you need to do branching (if statement, loops), this 
is an unpredictable cost and loops where a simple bitwise 
operation can be done is out right non-optimized.


As for exceptions, totally not required. You can solve this by 
simply making your state private so nobody else can mutate it. 
Bounds checking will ensure if the state is corrupted it'll 
error out if you use the lookup method I suggested above.


I tried to rework the functions to use bitwise operations, but it 
was difficult to figure out the correct logic. I decided that 
it's not worth the hassle, so I just changed the value storage 
from `bool[3]` to `ubyte`. Now it works much more like your 
version.

https://github.com/LiamM32/Open_Emblem/blob/c2014ab3f77e89c0cedcd6dbf7f8362ebfac33a9/source/common.d

I did a little reading, so now I understand what it means when 
you have `&= 7`. But I want to ask, is this faster than `%= 8`? 
If not, I would like to change it to the latter for readability.


Re: Challenge: Make a data type for holding one of 8 directions allowing increment and overflow

2024-03-13 Thread Liam McGillivray via Digitalmars-d-learn
On Tuesday, 12 March 2024 at 06:38:28 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
By taking advantage of integer wrapping and a bitwise and, its 
quite a simple problem to solve!


Challenge for the reader: add support for binary operations and 
toString support.


Last night I pushed the latest commit to the GitHub repository 
for my game. It contains the `Direction` struct in 
[`source/common.d`](https://github.com/LiamM32/Open_Emblem/blob/master/source/common.d). Here it is:


```
struct Direction //One of 8 directions stored in 3 bits
{
import std.conv;
import std.traits: isNumeric;

bool[3] b;

static Direction N = Direction(b:[false,false,false]);
static Direction NE = Direction(b:[true,false,false]);
static Direction E = Direction(b:[false,true,false]);
static Direction SE = Direction(b:[true,true,false]);
static Direction S = Direction(b:[false,false,true]);
static Direction SW = Direction(b:[true,false,true]);
static Direction W = Direction(b:[false,true,true]);
static Direction NW = Direction(b:[true,true,true]);

ref Direction opUnary(string op)() if (op == "++" || op == 
"--") {

static if (op == "++") const bool up = true;
else const bool up = false;

if (b[0]) {
if (b[1]) b[2] = !b[2];
b[1] = !b[1];
}
b[0] = !b[0];
return this;
}

void opOpAssign(string op)(int amount) if (op == "+" || op == 
"-") {

amount = amount%8;
if (amount > 0) for (uint i = 0; i < amount; i++) {
static if (op=="+") this++;
else this--;
} else for (uint i=0; i > amount; i--) {
static if (op=="+") this--;
else this++;
}
}

T to(T)() const if(isNumeric!T) {
return cast(T)(b[0] + 2*b[1] + 4*b[2]);
}

T opCast(T)() if (isNumeric!T) {
return cast(T)(b[0] + 2*b[1] + 4*b[2]);
}

T to(T)() const if(is(T==string)) {
if (this==Direction.N) return "north";
else if (this==Direction.NE) return "northeast";
else if (this==Direction.E) return "east";
else if (this==Direction.SE) return "southeast";
else if (this==Direction.S) return "south";
else if (this==Direction.SW) return "southwest";
else if (this==Direction.W) return "west";
else if (this==Direction.NW) return "northwest";
else throw new Exception("Direction.to!: direction has a 
value that should be impossible.");

//else return ""; //This should never happen.
}

bool[3] opCast() const {
return this.b;
}

Direction opposite() const {
return Direction([b[0], b[1], !b[2]]);
}

bool diagonal() {
return b[0];
}

int getAngle() {
if (this==Direction.N) return 0;
else if (this==Direction.NE) return 45;
else if (this==Direction.E) return 90;
else if (this==Direction.SE) return 135;
else if (this==Direction.S) return 180;
else if (this==Direction.SW) return 225;
else if (this==Direction.W) return 270;
else if (this==Direction.NW) return 315;
else throw new Exception("Direction.getAngle: direction 
has a value that should be impossible.");

}
}
```

The one thing that cant be done on this is doing `direction+8`. 
Perhaps it would have been easier if I had chosen to store the 
value as a ubyte rather than an array of bools. While this is 
probably over-optimized given the large amount of memory in 
today's computers, I like it that it can never be an illegitimate 
value.


There's probably some trick I can use to make it easier to figure 
out the functions to do numerical operations on bits, but I don't 
know how best to cleanly represent this kind of thing in code. 
Maybe I need to look for examples of how it's already done.


I noticed among the options for overloading unary operations are 
the symbols "+" & "-". What operation is being overloaded with 
the function `ref Direction opUnary(string op:"+")(int amount)`?


Re: Challenge: Make a data type for holding one of 8 directions allowing increment and overflow

2024-03-12 Thread Liam McGillivray via Digitalmars-d-learn
On Tuesday, 12 March 2024 at 06:38:28 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
By taking advantage of integer wrapping and a bitwise and, its 
quite a simple problem to solve!


Challenge for the reader: add support for binary operations and 
toString support.


https://dlang.org/spec/operatoroverloading.html

```d
struct Direction {
private int value;

Direction opUnary(string op:"++")() {
value++;
value &= 7;
return this;
}

Direction opUnary(string op:"--")() {
value--;
value &= 7;
return this;
}

void opOpAssign(string op:"+")(int amount) {
value += amount;
value &= 7;
}

void opOpAssign(string op:"-")(int amount) {
value -= amount;
value &= 7;
}

enum Direction N = Direction(0);
enum Direction NE = Direction(1);
enum Direction E = Direction(2);
enum Direction SE = Direction(3);
enum Direction S = Direction(4);
enum Direction SW = Direction(5);
enum Direction W = Direction(6);
enum Direction NW = Direction(7);
}

unittest {
 Direction direction = Direction.N;
 direction++;
 assert(direction == Direction.NE);
 direction+=3;
 assert(direction == Direction.S);
 direction--;
 assert(direction == Direction.SE);
 direction-=4;
 assert(direction == Direction.NW);
}
```


Interesting. I didn't know that an enum can be defined inside a 
struct like that. I had used functions to get around it.


Here is what I had already mostly written, using help from 
ChatGPT (but only for the opUnary syntax, not the algorithm):

```
struct Direction //One of 8 directions stored in 3 bits
{
bool[3] d;

static Direction N() { return 
Direction(d:[false,false,false]); }
static Direction NE() { return 
Direction(d:[false,false,true]); }
static Direction E() { return 
Direction(d:[false,true,false]); }
static Direction SE() { return 
Direction(d:[false,true,true]); }
static Direction S() { return 
Direction(d:[true,false,false]); }
static Direction SW() { return 
Direction(d:[true,false,true]); }
static Direction W() { return Direction(d:[true,true,false]); 
}
static Direction NW() { return Direction(d:[true,true,true]); 
}


ref Direction opUnary(string op)() if (op == "++" || op == 
"--") {

if (op == "++") const bool up = true;
else const bool up = false;

if (d[0]) {
if (d[1]) d[2] = !d[2];
d[1] = !d[1];
}
d[0] = !d[0];
return this;
}

auto to(T)() const {
return cast(T)(d[0] + 2*d[1] + 4*d[2]);
}
}
```

I am not entirely sure how well it works. I will come back later 
with an updated version with more functions.


I'm not familiar with the syntax of the line `value &= 7;`. Is it 
equivalent to writing `value = value % 7;`?


Anyway, you used an int, but I used an array of 3 bools. I'm 
guessing that mine uses less memory, but I'm not sure how memory 
it adds when it's a struct with functions.


Challenge: Make a data type for holding one of 8 directions allowing increment and overflow

2024-03-11 Thread Liam McGillivray via Digitalmars-d-learn
I am in need of a data type for holding direction information; 
one of 8 directions on a single axis. They are named in terms of 
compass directions. If D had a 4-bit datatype, I would just use 
this and do `+=2` whenever I want to change the datatype, but it 
doesn't.


Perhaps this would be a good programming challenge for someone 
more experienced than me. Make a data type (probably a struct) 
for holding one of 8 directional values using 3 bits. It should 
accept the use of increment operators to change the angle.


Ideally (but optionally), it should work as an enum of the same 
name; "Direction".


Here's a unittest that it should ideally pass:
```
unittest
{
Direction direction = Direction.N;
direction++;
assert(direction == Direction.NE);
direction+=3;
assert(direction == Direction.S);
direction--;
assert(direction == Direction.SE);
direction-=4;
assert(direction == Direction.NW);
}
```


Re: Can a D library have some types determined by the client program?

2024-03-10 Thread Liam McGillivray via Digitalmars-d-learn

On Sunday, 10 March 2024 at 04:39:33 UTC, Liam McGillivray wrote:

https://github.com/LiamM32/Open_Emblem/tree/templates-interfaces

I will probably merge it into master soon.


I have put up a merge request for these changes I have made to 
the library and the Raylib front-end. I would be interested in 
having my code looked at by someone more experienced than me 
(which would be everyone who has replied here and most of those 
reading).

https://github.com/LiamM32/Open_Emblem/pull/2

You can take a look in `source/map.d` where the former `Map` 
class has been replaced with the `Map` interface and the 
`MapTemp` template. You may also look in 
`oe-raylib/source/mission.d`, and compare how sprites were 
handled before vs after.


Of course, you can also compile and run it yourself (assuming I 
didn't accidentally leave out a file).


Other commentary on my code would also be appreciated.

I don't know if there's a forum section appropriate for sharing 
personal projects, but I may post there too.


Re: Can a D library have some types determined by the client program?

2024-03-09 Thread Liam McGillivray via Digitalmars-d-learn
I have made a new branch of my project called 
"templates-interfaces" which reworks some things, and turns the 
Map class into an interface and template. It is now functioning 
like the master branch, but I think the code should now be 
(arguably) easier to follow. At least that's true for the Raylib 
front-end, though maybe a little less so for the library.


Here it is:
https://github.com/LiamM32/Open_Emblem/tree/templates-interfaces

I will probably merge it into master soon.


Re: Can a D library have some types determined by the client program?

2024-03-09 Thread Liam McGillivray via Digitalmars-d-learn

Update on two things:

One is that I now better understand what it means that D objects 
are "reference by default". This means that references *can* be 
null if they are declared with a class. In my commits last night, 
I have changed many pointers into references. I think my time 
will be smoother from now on, spending far less time trying to 
debug segfaults.


Secondly, I found out that interfaces can't have variables. 
What!? That's crazy! Why wouldn't they? They totally should. 
Doesn't this mean that I will need to use getter and setter 
functions instead of direct access when using interfaces? I don't 
like this.


Re: Why am I getting segfaults when doing `foreach` with arrays of references?

2024-03-09 Thread Liam McGillivray via Digitalmars-d-learn

On Saturday, 9 March 2024 at 07:49:52 UTC, Liam McGillivray wrote:
But that begs the question; why? Don't dynamic arrays always 
start with a length of 0? If the array was only extended when 
valid objects were appended using the append operator `~=`, and 
none of those objects were deleted (as I the destructor was 
never called), why would some of the array elements be null?


I'll answer my own question; because the thing assigned to the 
array was already null.


Anyway, I managed to fix the segfaults. In the latest two 
commits, I have turned some pointers into references. Now that I 
understand this, I should have fewer segmentation faults.


Re: Why am I getting segfaults when doing `foreach` with arrays of references?

2024-03-08 Thread Liam McGillivray via Digitalmars-d-learn
On Saturday, 9 March 2024 at 06:37:02 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
Something that I have noticed that you are still doing that was 
pointed out previously is having a pointer to a class reference.


Stuff like ``Tile* currentTile;`` when it should be ``Tile 
currentTile;``


A class reference is inherently a pointer.

So when you checked for nullability in the foreach loop of 
mission:


```d
if (startTile.occupant !is null && (*startTile.occupant) !is 
null) {

```


I think I'm starting to understand better. I was thrown off 
somewhere when I read that "references in D cannot be null". I 
tried doing some if-statements to determine if array objects are 
null, and some of them were.


But that begs the question; why? Don't dynamic arrays always 
start with a length of 0? If the array was only extended when 
valid objects were appended using the append operator `~=`, and 
none of those objects were deleted (as I the destructor was never 
called), why would some of the array elements be null?


Why am I getting segfaults when doing `foreach` with arrays of references?

2024-03-08 Thread Liam McGillivray via Digitalmars-d-learn
With [my game project](https://github.com/LiamM32/Open_Emblem), I 
have been getting segmentation faults that are unexplainable at 
my knowledge level. They seem to happen when doing a "foreach" 
loop through an array of references.


Skip to the bolded text if you don't want to read too much, as I 
found a way around the first example.


Prior to the latest commit, I had this "foreach" loop lines 
starting at `oe-raylib/source/mission.d:214` ([see 
file](https://github.com/LiamM32/Open_Emblem/blob/09505794970168c68ed5cffd9aa2ed69490ee80e/oe-raylib/source/mission.d)). It would segfault on the second line shown here:

```
foreach (startTile; this.startingPoints) {
startTile.occupant.map = this;
writeln("Just assigned Unit.map to the Mission 
object.");

this.factionUnits["player"] ~= *startTile.occupant;
}
```
This was in the `Mission` class (a derivative of `Map`), which 
`this` would be a reference to. `startTile` is an instance of the 
`GridTile` struct, which contains a reference to a `Tile` object 
called `tile`. The `Tile` object had a pointer to a `Unit` object 
called `occupant`. `GridTile.occupant` is a convenience function 
that's equivalent to `GridTile.tile.occupant`. Finally, the 
`Unit` class contains a reference to a `Map` object called `map`. 
Because `Mission` is a derived class, a `Mission` object can also 
fit. All of the things being accessed were public.


I thought the problem was that it was looking in `Tile` objects 
with `occupant` being null, but changing line 214 to the 
following didn't solve it.

```
foreach (startTile; this.startingPoints) if 
(startTile.occupant !is null) {

```

**Current example**
I ended up getting rid of that line causing the segmentation 
fault and achieving the desired functionality a different way, 
but now I get a similar one later in the program.


The `turnReset` function in my [`Map` 
class](https://github.com/LiamM32/Open_Emblem/blob/master/source/map.d) does a 'foreach' loop through an array of `Unit` objects:

```
void turnReset() {
foreach(unit; this.allUnits) {
unit.turnReset;
}
}
```

My program successfully completed one cycle of the loop, but 
segfaulted with the second one. I found in GDB that for the 
second object it didn't even reach the first line in 
`Unit.turnReset()`. This may imply that the array length of 
`Map.allUnits` is more than one, but no object has been assigned 
to `allUnits[1]`. However, there are no lines anywhere in my code 
that changes the length of this array without appending. I tried 
doing the `grep -r allUnits` command to look for every mention of 
this array in my code, and here is what I have:

```
source/map.d:public Unit[] allUnits;
source/map.d:foreach (unit; this.allUnits) {
source/map.d:foreach(unit; this.allUnits) {
source/map.d:assert (canFind(map.allUnits, unit));
source/unit.d:if (this in map.allUnits) {
oe-raylib/source/mission.d:this.allUnits ~= 
*startTile.occupant;

oe-raylib/source/mission.d:foreach (unit; this.allUnits) {
oe-raylib/source/mission.d:if (addToMap) allUnits ~= 
newUnit;

oe-raylib/source/mission.d:foreach (unit; mission.allUnits) {
oe-raylib/source/mission.d.bak2:foreach (unit; 
this.allUnits) {

```

As far as I see, there's no way that the `allUnits` array would 
be longer than the number of objects that have been added to it, 
so why would calling a public function of one of it's members 
cause a segfault?


Re: Can a D library have some types determined by the client program?

2024-03-08 Thread Liam McGillivray via Digitalmars-d-learn

On Friday, 8 March 2024 at 16:54:48 UTC, cc wrote:
If you don't want Unit to be a template, you can just have Map 
derive from a basic interface or abstract class.  You can also 
have every relevant class share similar templates, you just 
need to remember to supply the template arguments everywhere.


Right. Interfaces. I haven't used this feature yet, but I had 
read about them, thinking I would likely use them. I forgot about 
them at the time of making this thread. I will try making Map & 
Tile an interface, and maybe Unit as well.


Can an interface and a template have the same name, similar to 
function overloading? In that case, `Map!Tile` would refer to the 
template, while `Map` would be the interface. Maybe I'll have 
figured this out myself by the time someone replies.


You'll need to think about how much interoperation you want 
between these classes.  Does Unit really need to know what 
TileType map is using, or can it just trust that when it asks 
Map to move, Map will handle everything related to tile types?  
Generally it's best practice to have as much of the inner 
workings isolated as possible and just provide methods to 
access functionality.


I don't think `Tile` and `Unit` will need to know the details of 
what kind of Tile & Unit derivative the map is using.


As an aside on this topic, I wonder if my `Map` class and it's 
derivative `Mission` are doing too many things. I don't know if 
there is enough of a problem with one "master" class dominating 
the program that it's worth splitting it up despite the more 
complex programming.


After changing `class Unit` to `class Unit (TileType)`, it 
complains about the line `Unit* occupant;` in Tile.


Are you sure you need a pointer here?  Class objects in D are 
already reference-type by default.


I'm pretty sure I do, as references can't be null. As an 
approximation of what I'm doing, think of `Map` as a chess board, 
`Tile` as a square on the board, and `Unit` as a chess piece. Not 
every tile on the chess board is occupied by a piece.


If you want, you can see the program I have so far on [my GitHub 
repository](https://github.com/LiamM32/Open_Emblem). Right now 
the `master` branch is the most up-to-date, but I might soon make 
a new branch to try out templates and interfaces.


Re: Can a D library have some types determined by the client program?

2024-03-07 Thread Liam McGillivray via Digitalmars-d-learn
On Friday, 8 March 2024 at 03:19:59 UTC, Richard (Rikki) Andrew 
Cattermole wrote:


On 08/03/2024 4:09 PM, Liam McGillivray wrote:


Thank you. Is this first example you gave the template? Is the 
syntax `(ATile : Tile)` saying that ATile must be a derived 
class of Tile? If this isn't worse in any way than your second 
example, then I don't know why I wouldn't choose this one.


Typically in D we use templates quite heavily, but what you are 
wanting is probably more familiar to you via the OOP method 
with a factory of some kind.
Nope, but thank you. I am not a very experienced programmer. The 
most complex thing I've ever done previous to this was my work on 
[Condorcet](https://github.com/julien-boudry/Condorcet) which is 
in PHP. I might have encountered something about factory methods, 
but I don't remember. I have some C++ experience, but I haven't 
been very successful with it. What I have so far in the game I'm 
making is the most complex program I have ever written.


I suppose that if I do this, then the derived class `Mission` 
would be declared like `class Mission : Map(GridTile)`, right?


``class Mission : Map!GridTile`` but right idea.

When I tried adding that parameter to the Map class, on 
attempting to build it it complained that references to Map in 
other classes were incomplete, as they didn't include a 
parameter. I suppose I must make my other classes templates 
too.

I have an update on this, after taking another go at it.

A problem I have is that the 3 classes Map, Tile, and Unit 
reference each-other. If I turn Map into a template, than it 
complains about the member variable of Unit declared as `Map 
map;` without arguments. I change this line to `Map!TileType 
map;` but this requires that Unit is also turned into a template. 
After changing `class Unit` to `class Unit (TileType), it 
complains about the line `Unit* occupant;` in Tile. I try turning 
Tile into a template with the `TileType` parameter, which means 
that the class inheriting Tile will need to use itself as a 
parameter. Surprisingly, I have done this and it hasn't taken 
issue (so far). But now that I have turned Tile into a template, 
it complains about the declaration of Map being `class Map 
(TileType : Tile)`, as `Tile` is no longer a class but a template.


Here are some of the build errors:
```
Starting Performing "debug" build using /usr/bin/dmd for 
x86_64.
  Up-to-date bindbc-freetype 1.1.1: target for configuration 
[staticBC] is up to date.
  Up-to-date fluid 0.6.3: target for configuration [default] is 
up to date.
Building open_emblem_raylib ~master: building configuration 
[application]
../source/map.d(185,13): Error: template class 
`unit.Unit(TileType)` is used as a type without instantiation; to 
instantiate it use `Unit!(arguments)`
../source/map.d(21,19): Error: template class 
`unit.Unit(TileType)` is used as a type without instantiation; to 
instantiate it use `Unit!(arguments)`
../source/map.d(22,27): Error: template class 
`unit.Unit(TileType)` is used as a type without instantiation; to 
instantiate it use `Unit!(arguments)`
../source/map.d(125,11): Error: template class 
`tile.Tile(TileType)` is used as a type without instantiation; to 
instantiate it use `Tile!(arguments)`
../source/map.d(129,14): Error: template class 
`tile.Tile(TileType)` is used as a type without instantiation; to 
instantiate it use `Tile!(arguments)`
../source/map.d(133,11): Error: template class 
`unit.Unit(TileType)` is used as a type without instantiation; to 
instantiate it use `Unit!(arguments)`
../source/unit.d(12,12): Error: template instance 
`map.Map!(VisibleTile)` error instantiating
../source/tile.d(19,9):instantiated from here: 
`Unit!(VisibleTile)`
source/vtile.d(4,21):instantiated from here: 
`Tile!(VisibleTile)`

```

Will I somehow manage to solve this problem?

Given that it's possible to declare an object inside a class, and 
then fill it with an object of a derived class, I would have 
thought it would be possible to use a template as a type, and 
then fill it with an object of a class derived from that template.


Re: Can a D library have some types determined by the client program?

2024-03-07 Thread Liam McGillivray via Digitalmars-d-learn
On Thursday, 7 March 2024 at 22:18:40 UTC, Richard (Rikki) Andrew 
Cattermole wrote:

There are two ways to do this.

1. Use templates. 
https://tour.dlang.org/tour/en/basics/templates
2. Use a factory function. 
https://tour.dlang.org/tour/en/basics/delegates


```d
class Map(ATile : Tile) {
ATile[] tiles;
}
```


Thank you. Is this first example you gave the template? Is the 
syntax `(ATile : Tile)` saying that ATile must be a derived class 
of Tile? If this isn't worse in any way than your second example, 
then I don't know why I wouldn't choose this one.


I suppose that if I do this, then the derived class `Mission` 
would be declared like `class Mission : Map(GridTile)`, right?


When I tried adding that parameter to the Map class, on 
attempting to build it it complained that references to Map in 
other classes were incomplete, as they didn't include a 
parameter. I suppose I must make my other classes templates too.


Something strange that I just realized is that (without doing any 
of the changes you suggested to me), I have a reference to a Map 
object as one of the class variables in Unit, yet it has allowed 
me to place a Mission object in it's place. It no longer allows 
me if I change it to a pointer. Why is it sometimes possible to 
put a derived class in a place meant for the class it inherits 
from?





Can a D library have some types determined by the client program?

2024-03-07 Thread Liam McGillivray via Digitalmars-d-learn
In a source library written in D, is it possible to have some 
objects, variables, pointers etc which are determined by the 
program using the library?


An example of where this would be useful is in the library I am 
currently writing. I have a class called `Map`, which holds an 
array of objects of the `Tile` class. A program using my library 
can inherit the Map class if they want to add more functions and 
variables, but what if they want to add more to the Tile class? 
Even if they make a derived class of `Tile`, they can't override 
the use of the base Tile class in the Map class.


In cases like this, it would be useful to allow the client 
program to determine the type for some objects. For it to work 
with types defined in the client software code, the client 
software will also need a way to give it access to a module of 
the client software.


I know that D has something called compile-time function 
evaluation, but I don't know the full capabilities.


Re: Error when using `import`.

2024-03-05 Thread Liam McGillivray via Digitalmars-d-learn
There's something that I'm trying to do that D may or may not be 
capable of.


In the Map class, there is a 2-dimensional array called `grid`, 
where the Tile objects are stored. The Mission class inherits the 
Map class.


In the Mission class, I want the `grid` array to instead be 
composed of a derivative of the Tile class. I tried making a 
derived class called `GridTile` which contains the additional 
property specific to the Raylib front-end.


I tried doing this, but it won't let me override `grid`, even if 
I change it from `private` to `protected` in the Map class.


Is there a way I can do this, without this additional 
functionality being put in the base Tile class?


Re: Error when using `import`.

2024-03-05 Thread Liam McGillivray via Digitalmars-d-learn
I have made some progress on this. For the raylib front-end, I 
tried making a class called `Mission` which inherits `Map`. This 
class handles the graphics, input, and other game events. The 
program now compiles without errors, and there are some graphics. 
I have pushed these updates to the GitHub repository.

https://github.com/LiamM32/Open_Emblem

Currently, it just displays a map of grass tiles with one unit. 
Clicking on the unit causes a segmentation fault. There is 
something that's supposed to happen when clicked, but I don't 
know why it segfaults. The line where it segfaults appears to be 
roughly `oe-raylib/source/mission.d:125`.


I am continuing to work on this, but have been getting more 
strange runtime errors since the latest push.


Re: Error when using `import`.

2024-02-29 Thread Liam McGillivray via Digitalmars-d-learn

I now have the Raylib functions working by using `toStrinz`.

I pushed some updates to the repository. I made the main project 
a source library so that I can experiment with different graphics 
library front-ends. I put have the front-end using Raylib in the 
`raylib_frontend` directory. It doesn't yet have any 
interactivity, but it should build and run successfully IIRC.


I don't know how best to organize the code. So far I have been 
putting the loop that runs during gameplay in the `Mission` 
function in `mission.d`. This function contains the arrays where 
sprites are stored. The code for unloading data from files is 
split between this function and `maps.d`. I was going to have a 
file in the main `source/` (not `raylib_frontend/source`) called 
`loadData.d` which would handle unloading from files, but then I 
realized that those functions would need write access to multiple 
variables, making it a not very tidy approach.


One possibility is to turn `Mission` into a class. The Mission 
object would control the Map object and other things during 
gameplay. The other possibility is to make a derived class of Map 
with more graphics-related functionality and more.


Re: Error when using `import`.

2024-02-28 Thread Liam McGillivray via Digitalmars-d-learn

There's something very strange going on when using Raylib-D.

I tried using the raylib function `LoadTexture` like this:
```
tileSprites[i] = LoadTexture("../sprites/" ~ spriteName);
```

I got the following error:
```
Error: function `raylib.LoadTexture(const(char)* fileName)` is 
not callable using argument types `(string)`

```

So it's not allowing me to use a D string, but wants me to use 
(what I believe to be) the archaic C-style string. Here is how 
this function, as well as `DrawText` is declared in the Raylib-D 
bindings:

```
void DrawText(const(char)* text, int posX, int posY, int 
fontSize, Color color); // Draw text (using default font)
Texture2D LoadTexture(const(char)* fileName); // Load texture 
from file into GPU memory (VRAM)

```

The weird thing is that both of these functions are declared only 
once and with these C-style strings as arguments, yet I have 
already successfully called `DrawText` using a D string, yet 
`Texture2D` results in an error.


```
DrawText("Open Emblem", 180, 300, 64, Colors.RAYWHITE);
```

So why is it that one of these functions, but not the other is 
allowing D strings in place of C-style strings?


Array types and index types

2024-02-27 Thread Liam McGillivray via Digitalmars-d-learn
In D, it appears that dynamic arrays (at least by default) use a 
ulong as their key type. They are declared like this:

```
string[] dynamicArray;
```

I imagine that using a 64-bit value as the key would be slower 
than using 32 bits or 16 bits, and 64 bits is way overkill for 
nearly everything. However, if I declare the array as 
`string[uint] myArray;` or `string[ushort] myArray`, it's treated 
as an associative array. This means that I don't get to do the 
things I want to do with a dynamic array, such as appending.


So I have some questions:

Is there a way to declare a dynamic array with a uint, ushort, or 
ubyte key?


If there was, would it really be faster?

Is an associative array with a ushort key faster than a dynamic 
array with a ulong key?


Re: Error when using `import`.

2024-02-27 Thread Liam McGillivray via Digitalmars-d-learn
On Tuesday, 27 February 2024 at 03:43:56 UTC, Liam McGillivray 
wrote:
Raylib looks promising. I installed it along with your 
Raylib-d. I managed to build the example you provided with dub, 
but trying to use it in it's own dub project in a separate 
directory isn't working. Just copying and pasting `app.d` from 
the very example you provided results in a huge wall of errors, 
mostly "undefined reference to [some function]".


Nevermind this. I just needed to add `libs "raylib"` to dub.sdl. 
I didn't think I would need to specify the libraries in the 
project when they are accessed through an external library. Now I 
know.


Looking at the code examples on the Raylib and SFML website, they 
look similar in complexity of getting started, but I like it that 
the Raylib website has lots of simple demonstration programs on 
the website with the code provided. This is a great way to help 
with learning.

https://www.raylib.com/examples.html

So far it's been working when I try to do their C++ examples in D.


Re: Error when using `import`.

2024-02-26 Thread Liam McGillivray via Digitalmars-d-learn
On Tuesday, 27 February 2024 at 03:06:19 UTC, Steven 
Schveighoffer wrote:
If you are going for game development, I would recommend 
raylib-d (https://code.dlang.org/packages/raylib-d), which is 
my wrapper around the very good raylib library.


For doing GUI, raygui is supported, but I also can say I've 
seen some good things from fluid: 
https://code.dlang.org/packages/fluid


-Steve


Raylib looks promising. I installed it along with your Raylib-d. 
I managed to build the example you provided with dub, but trying 
to use it in it's own dub project in a separate directory isn't 
working. Just copying and pasting `app.d` from the very example 
you provided results in a huge wall of errors, mostly "undefined 
reference to [some function]".


Re: Error when using `import`.

2024-02-26 Thread Liam McGillivray via Digitalmars-d-learn
I don't know whether I should continue this topic or start a new 
one now that the problem mentioned in the title is fixed. I have 
now uploaded some of the code to [a GitHub 
repository](https://github.com/LiamM32/Open_Emblem).


To make this game usable, I will need a library for graphics and 
input. I don't have any experience with making GUI programs aside 
from a little bit with Qt and C++.


I have considered the following libraries:
- ~~SDL~~: Seems too low-level for me.
- Allegro via 
[DAllegro5](https://github.com/SiegeLord/DAllegro5): I found some 
C & C++ tutorials for this one, but I don't know how I would do 
it with D. This one looks difficult.
- ~~Imgui via 
[Dimgui](https://github.com/d-gamedev-team/dimgui)~~: While 
[Imgui](https://github.com/ocornut/imgui?tab=readme-ov-file) 
looks well-developed, the Dimgui readme links to [this 
repository](https://github.com/AdrienHerubel/imgui), which looks 
like a very old version of Imgui.
- Godot via 
[Godot-Dlang](https://github.com/godot-dlang/godot-dlang?tab=readme-ov-file#manually-creating-project): A well-developed game engine with an editor that may allow me to get fancier graphics without a huge amount of effort. However, the project page for Godot-Dlang gives a warning that it's unfinished. This may or may not be a problem given that this is just a hobby project. I would be happy to share any problems with the developers.
- SFML via [BindBC-SFML](https://github.com/BindBC/bindbc-sfml): 
SFML appears to be an easier way to get 2D graphics working 
compared to SDL & Allegro when using C++. However, it may take 
more effort to use it with D.
- [AE](https://github.com/CyberShadow/ae): This is a D library 
that provides graphics and other utilities using various C 
libraries. I am beginning to understand this one, as I've been 
looking at the provided demos. However, this one seems to SDL 
functions directly whenever an image is placed on-screen, which I 
don't understand the theory behind.


I have writing the code for the internal game logic as a library 
that can be used by various front-ends for graphics. This would 
let me experiment with different software for graphics, but it 
would make the code more complicated.


So far I have been attempting to get it working with AE for 
graphics, not using the library approach described above. I 
haven't committed it with git, as I have copied and pasted 
substantial code from the AE examples and I will need to look at 
the license before I share it. I have managed to get it to read a 
PNG using libpng, but not display it. I have had trouble with 
this. One of the demos uses a function `s.draw` for displaying an 
image, which isn't defined anywhere in AE, so it might be an SDL 
function. I don't know how it has access to it.


I chose to use D for this project because I have long wanted to 
learn the language, but I wonder if it's overkill for this 
project, given the low performance requirement. Maybe I would be 
better-off using a dynamic interpreted language. The benefit of D 
is largely for the learning experience.


Re: Error when using `import`.

2024-02-26 Thread Liam McGillivray via Digitalmars-d-learn

On Sunday, 25 February 2024 at 03:23:03 UTC, Paul Backus wrote:
You can't give a class the same name as the file it's in. If 
you do, then when you try to use it from another file, the 
compiler will get confused and think you're referring to the 
file instead of the class (that's what "import is used as a 
type" means).


Thank you. In PHP, I was told to put every class definition in a 
file of the same name (whether I like it or not).


However, I actually now have it working *without* having done 
that. Both the file name and the class name are capitalized, and 
it's working. However, maybe that's because they each start with 
a `module` line that makes the module name lowercase. I will keep 
this in mind, and maybe rename the files.


Re: Error when using `import`.

2024-02-24 Thread Liam McGillivray via Digitalmars-d-learn
On Saturday, 24 February 2024 at 10:34:25 UTC, Richard (Rikki) 
Andrew Cattermole wrote:

A few things.

Module names should be lower case.


I capitalised the first letter in the class names so that I can 
make instances of them in lowercase. Should I rename the classes, 
modules, and filenames to all be lowercase?


It appears to be solved now after adding module declarations to 
the beginning of each file in all-lowercase. This is despite the 
classes and the class names still being capitalized. I'm still 
getting errors, but they appear to be unrelated.


Thank you.


Error when using `import`.

2024-02-24 Thread Liam McGillivray via Digitalmars-d-learn
I am trying to make a tactical role-playing game which I am 
likely to open-source. Right now the code is very simple, with 
only 3 files each containing a class with the same name.


The files are `Map.d`, `Tile.d`, and `Unit.d`. Each of these 
files contains an `import` line to access one of the others. I 
got the following errors when trying to compile all 3 files with 
DMD, and the same errors after switching to DUB.


```
source/Unit.d(6,17): Error: import `Unit.Map` is used as a type
source/Unit.d(16,5): Error: import `Unit.Map` is used as a type
source/Tile.d(9,15): Error: import `Tile.Unit` is used as a type
source/Map.d(6,22): Error: import `Map.Tile` is used as a type
source/Map.d(19,11): Error: import `Map.Tile` is used as a type
```

I thought that the circular chain of imports may be the problem, 
but removing all references to `Unit` in `Tile.d` did not fix the 
problem.


Here are the contents of Tile.d:
```
import Unit;

class Tile
{
private bool allowStand = true;
private bool allowFly = true;
public int stickyness = 0;

public Unit* occupant;

bool allowUnit(bool isFlyer) {
if (isFlyer) return this.allowFly;
else return this.allowStand;
}
}
```

`Unit.d` & `Map.d` are longer files. `Map.d` begins with `import 
Tile;`, and `Unit.d` begins with `import Map;`.


Why are the errors happening? What's the problem? Why is it 
`currentclass.importedclass` instead of simply the imported class?