Rogue-like ascii based on Arduboy


(Stephane C) #181

@filmote do you mind making a PR on my fork?

I will take all the space I can save.


(Simon) #182

No … just ‘find and replace’ Sprites:: with SpritesB:: … you should find two instances.


(Stephane C) #183

Oh my bad, I did not read the part that says 2 locations, silly me.


(Pharap) #184

I made a mistake, I misread what my original saving was because I was trying to do too much at once again.

The original saving was 708 bytes of progmem and 26 bytes of RAM:

Which means…

This is expected.

(I think the other 200 came from some of the other changes I made.)


Here is the difference between “HelloWorld9” (from rogue.zip) and my string changes:

The other changes were makeDungeon2, freeSlot and sortItem.
I will prepare some PRs for those changes.



(Pharap) #185

@BlueMax, another PR:

122 bytes saved.


You should have a notification about the PR on GitHub.
(灰色鐘、青色丸 -> ノーチフィケション)
(灰色鐘、青色丸じゃない -> ノーチフィケションじゃない)


(Josh Goebel) #186

How is asFlashStringHelper different/better than F?

@Pharap Wow, your “string” update, is quite the update. Nice work.


(Josh Goebel) #187

I need to take a look at this. I have a terminal renderer laying around somewhere that renders a text terminal at arbitrary resolutions (not just x8) but I never compared it for size to see how it would compare to font rendering with something like the typical drawing functions. I know for sure it’s a huge win on RAM though as you get back almost all of the 1024 bytes in exchange for only a text buffer. But of course there are other ways to get that ram back for a simple text-only game like this.


(Josh Goebel) #188

I haven’t looked to see if @Pharap optimized them in his huge string update but:

  • flashHero and flashMonst are worth looking at. They could both be optimized to a single function (or at least both just call a single function on the backend) as really it seems all they are doing is flashing a single character on the map - doesn’t really matter if it’s the hero or monster or treasure…

  • And something like inputWait shouldn’t exist at all - or at least it shouldn’t be remapping the input values - it should just reuse them as is, even if you wanted to re-alias them: #define LEFT LEFT_BUTTON

  • arduboy.fillRect(0,0,128,8,WHITE); could be simplified to call a helper that was just a for loop that set the first 128 bytes of the buffer to white.

  • Couldn’t void clearBuf(){ be changed to simply gbuf[0]=0;, is it necessary to 0 the whole string?

  • drawHero should be merged into drawMap, lots of duplication there.


(Pharap) #189

__FlashStringHelper is a dummy type - it’s only ever declared and never actually defined, so it’s only possible to create opaque pointers to it - no objects of type __FlashStringHelper actually exist.

The Print class defines size_t print(const __FlashStringHelper *) and size_t println(const __FlashStringHelper *).

The F macro is defined as:

#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))

PSTR is what actually causes the string to be allocated in progmem.
The reinterpret_cast then reinterprets a pointer of type const char * (pointing to the string in progmem) as const __FlashStringHelper *.

Then when F is placed within a call to print it forces the print(const __FlashStringHelper *) overload to be called instead of print(const char *).
The difference is (of course) that print(const char *) expects the pointer to be in RAM and print(const __FlashStringHelper *) to be in progmem.

Once print(const __FlashStringHelper *) has its argument, it then reinterprets it back to const char * (disguised as PGM_P via macro) and reads the string from progmem using pgm_read_byte rather than reading it like a normal pointer.

So __FlashStringHelper is a dummy for the sake of differentiating strings in progmem from strings in RAM in a way that functions can detect by providing different overloads.

So essentially asFlashStringHelper is just a wrapper around the reinterpret cast to make the code less daunting and more self-descriptive.
This allows strings to be put into progmem as char arrays and later reinterpreted as const __FlashStringHelper * so they can be fed to print/println functions.


References:


Like most programming decisions it’s a tradeoff.
The downsides are not having the line by the menu,
and having to have a simpler titlescreen.
(Speed probably wouldn’t be an issue for this game but it might have been with other games.)

There’s a lot of changes I’ve put off doing becuase I don’t want to overwhelm @BlueMax with changes.

It’s hard enough for any beginner, but more so when there is a language barrier.
(Which is why I’ve taken to trying to use my limited knowledge of Japanese to try to explain things,
and why I’ve tried to keep my explanations simple.)

Ultimately this game is as much for the benefit of @BlueMax’s learning as it is for the enjoyment of others.

He doesn’t have much time either, and has only just started learning to use GitHub.

Our motto for this game has become 一日一歩, which literally means “one day, one step”.

Many of your points are perfectly valid,
but if we just rush them all in then @BlueMax won’t learn from them as well as he could.


(Josh Goebel) #190

Right, but I thought that’s what the F macro did in the first place? I think perhaps you over-answered or I’m slow…

I understand what F() does… but you replaced F() with your own helper thatn you defined in your own file… how is that better than using the build in F() macro? obviously I’m missing something.


(Josh Goebel) #191

Not sure which line you’re referring to - I haven’t played the game yet - it’s still too large the version I have, LOL. But the nice thing about owning the render code is perhaps you could have the line, just not in a way that results in the whole screen being pixel addressible - etc. Imagine an underline/strikethru attribute for example… now you’d get vertical lines for “free” (well at the cost of an attribute byte).

You don’t need a 1024 byte buffer to draw a single static screen. :slight_smile: But maybe it’s not static, again I lack experience. :slight_smile: Anyways you can easily just buffer a single “page” for “slower” games, which easily gets you back almost 900 bytes whenever we decide we really need them. Actually having a pixel addressable screen drawing one page at a time uses less RAM than buffering a “text” terminal (esp. once you add attributes).

Yeah, that’s the hardest part, agree.


(Stephane C) #192

You can always try the modded version I attempted. It’s the same thing but I replaced the character with sprites of the same size. Anyway, the game is fun. And I like the history about it. The guy who made the original Rogue ( not the Arduboy port ) wanted to create a game that even him could enjoy, hence the total randomization of everything.


(Josh Goebel) #193

Hopefully after @Pharaps stuff gets merged the official copy with fit. If not it’ll be close enough that I could probably hack out a few strings myself and get it to.


(Pharap) #194

F is defined like so:

#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))

PSTR takes a string literal and puts it into progmem, returning a const char * to that.

I.e. you can do:

printer.print(F("Hello world"));

But, you cannot do:

const char string0 PROGMEM = "Hello world";

printer.print(F(string0));

Becuase PSTR only works for string literals.

With asFlashString, you can do:

const char string0 PROGMEM = "Hello world";

printer.print(asFlashStringHelper(string0));

Conversely, you cannot do:

printer.print(asFlashStringHelper("Hello world"));

But you could do:

printer.print(asFlashStringHelper(PSTR("Hello world")));

(Which is equivalent to what F does.)

F and asFlashStringHelper do two different jobs.

If you had:

const char string0[] PROGMEM = "String 0";
const char string1[] PROGMEM = "String 1";

const char * const strings[] PROGMEM =
{
    string0,
    string1,
};

Then the F macro would be of no use to you whatsoever because you’re not dealing with string literals, you’re dealing with an array of pointers.

However, with asFlashStringHelper

void printString(uint8_t index)
{
    const void * pointer = pgm_read_ptr(&strings[index]);
    const __FlashStringHelper * string = asFlashString(pointer);
    printer.print(string);
}

Which is where asFlashStringHelper is useful.
It does a different job to F.
F is “allocate in progmem, then convert to dummy type”,
asFlashStringHelper is just “convert to dummy type” without the allocation part.

The line by the status screen as proposed by @Vampirics:

And the titlescreen @Vampirics made:

I don’t think RAM is really the issue here though.
The bigger complaints are about progmem.
RAM might be an issue at some point, but for now it’s progmem that’s the problem.

I haven’t actually made a PR for my changes.
Those were made a while back and the code has changed since then.

@BlueMax has made a version with similar changes made available,
but he hasn’t added it to the GitHub repo yet.

As I said earlier, he is new to GitHub, so he is still getting used to the process of committing.

Also, you’d be surprised how little GitHub documentation is available in other languages,
the vast majority is in English, and quite high-level English at that (relatively speaking).


#195

Wow! Lots of messages!

Sorry to everyone who replied. It will take a day to finish reading everything. I’m sorry.:hot_face:

My teacher, @Pharap. You are a really good teacher. I am overjoyed and I am about to cry. I’m sorry I’m a lazy student.


(Stephane C) #196

@BlueMax take it easy, you are doing fine. Take it one thing at a time and you will be able to learn it all. For all I know you are better then me at least. :wink:


(Pharap) #197

はい。多い。

問題じゃないです。

Hopefully this idiom means what I think it means:
「案ずるより産むが易し」。

(I found this list of idioms. 面白いです。)

英語のことわざ:
“Patience is a virtue”
「忍耐心は美徳」

私は忍耐強いですから。

いえいえ。

プログラミングは難いです。GitHubは難いです。

(GitHub = ギットハブ?)


はい!一日一歩。

You are both good programmers, but with different strengths and weaknesses.


(Josh Goebel) #198

@Pharap

I’ll look again. I got confused because I thought for sure I saw you replacing printer.print(F("Hello world")); with printer.print(asFlashStringHelper("Hello world"));… making me wonder what the difference is.

I totally get what you’re saying now for inline literal vs static constant, but that’s not what I thought I imagined seeing. :slight_smile: Thanks for the huge long explanation. :slight_smile:


(Josh Goebel) #199

You don’t need a buffer for a solid vertical line. :slight_smile: I think we forget the display is 8 directly addressable (in units of 8 pixels) because the library doesn’t expose any of the API methods to move the hardware cursor (or at least it didn’t use to). But that’d be pretty trivial to do as a one-off, no need for a buffer at all.

I guess if you had a terminal and wanted 3 pixels in the middle of the screen in between a bunch of columns then it might get a little more complicated.

Static? Just draw it directly via SPI. :slight_smile:

Agree, but I think in the future you might want things like a larger dungeon, etc… just pointing out RAM shouldn’t really be an issue.

I haven’t actually made a PR for my changes.

I think you suggested you had planned to when time permitted.

Also, you’d be surprised how little GitHub documentation is available in other languages,
the vast majority is in English

Yeah, no idea… plus there is learning Git also… which is a whole thing in an of itself. I can imagine how it might be overwhelming. So many things you take for granted once you get to a certain level.


#200

Hi everyone in the community.

I found a part that I care about, so I made minor corrections. I will release it as version 1.4.1.

Rogue141.hex.pdf (77.3 KB)

CAUTION
This version uses “remove USB stack” technique. When you upload a new game, you need to hold down the DOWN button while ARDUBOY is starting up.

  • [FIX] When a hero is in a dark room, it stays near a trap when it stays nearby.
  • [SYS] More natural message. (No longer “amethyst” is not “amthyst” thank you, @Pharap)