Arduboy Classes and Header files?

also i was able to unearth an ancient CRT for my main pc so I can keep my repo up to date!

2 Likes

That will make it a lot easier to find and track issues.

Are these the eeprom warnings you talking about?

In file included from C:\Users\weebu\Documents\Arduino\libraries\Arduboy2\src/Arduboy2.h:11:0,

                 from sketch\Game.h:1,

                 from C:\Users\weebu\Documents\GitHub\ArduboyWorks\TicTacToe\TicTacToe.ino:3:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src/EEPROM.h:43:30: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]

     operator const uint8_t() const       { return **this; }

                              ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src/EEPROM.h:92:26: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]

     operator const int() const          { return index; }

                          ^

In file included from C:\Users\weebu\Documents\Arduino\libraries\Arduboy2\src/Arduboy2.h:11:0,

                 from sketch\Game.h:1,

                 from C:\Users\weebu\Documents\GitHub\ArduboyWorks\TicTacToe\TicTacToe.ino:3:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM\src/EEPROM.h:145:20: warning: 'EEPROM' defined but not used [-Wunused-variable]

 static EEPROMClass EEPROM;

                    ^

Archiving built core (caching) in: C:\Users\weebu\AppData\Local\Temp\arduino_cache_472444\core\core_arduino_avr_leonardo_0c812875ac70eb4a9b385d8fb077f54c.a
Sketch uses 10536 bytes (36%) of program storage space. Maximum is 28672 bytes.
Global variables use 1394 bytes (54%) of dynamic memory, leaving 1166 bytes for local variables. Maximum is 2560 bytes.

Yeah.

One of the warnings is because they put a const on return value that’s just a value rather than a reference.

The other is because the EEPROM variable is unused (though I think it stays even if you use it).
If the functions on EEPROMClass had been made static then they wouldn’t even need an instance.

why the heck to they not bother to fix it then. If they are talented enough to write a lib that saves stuff to eeprom why do they make such basic programming errors.

I don’t know.
I’m sure there’s an issue or PR requesting it.

Unfortunately they have over 800 issues and 146 PRs.
Most of the issues are requests for libraries to be added because they decided to make that the library submission mechanism instead of creating something better.

I think the person who made the EEPROM library was ‘Chris–A’.
From what I’ve seen of his code, he does some very good things but also still does some things that aren’t as good.
(In fairness I probably have stupidly high standards.)


Ah, here we go:

They’ve been ignoring it for 2 years now.

Why does not someone fix it and just send a pull req.?

I presume someone has as some point and itgot put on hold for who knows what reason.

Larger repos tend to get bogged down in bureaucracy due to either having too many PRs or issues and not enough maintainers or for fear of breaking something important and then being flooded with complaints.

(That said, I might submit one at some point and see what they say. Worst case scenario it gets marked as duplicate or ignored.)

Larger repos tend to get bogged down in bureaucracy

Star Spangled Banner plays

Alright lets stop going off topic, how do I generate a random int between 0 and 1? I call randomSeed(analogRead(0)) after serial.Begin in setup, then call random(1) in game. (Every time the game resets i run random again.) It keeps returning 1 however.

Also, I remember reading about an escape character that allowed you to put more text on a line below still using a single print statement. \n isnt it but neither is \s (closest thing i could think of)

analogRead on its own isn’t actually very good as a seed because the pin noise is generally still within a limited range.

Arduboy2 has a special function for seeding the PRNG.
arduboy.initRandomSeed();
It works best when called after a random delay, e.g. after a start menu. (It works alright without that too though.)

Then you can use random(inclusiveMin, exclusiveMax) or random(exclusiveMax), or rand() % exclusiveMax.
I think rand() actually results in slightly smaller code, so for anything smaller than 32767 it’s probably better to use rand().
In this case rand() % 2 is almost certainly best.

(A while back we had a debate about switching to a different PRNG to include in the library but couldn’t decide on one.)

It is '\n'.
E.g. arduboy.print(F("Hello human.\nNice day isn't it?"));

Be warned that it always goes to the left hand side of the screen though, Arduboy2 doesn’t have a facility to alter that.

I still think this is dumb. It is such a simple thing to add to the Arduboy library and would add about 4 bytes*

* estimate only. Your mileage may vary.

1 Like

Does random include zero? (X is represented by 0 and O is represented by 1)

Yes.

Cell randomCell(void)
{
  return static_cast<Cell>(rand() % 2);
}

Plus, analogRead(0) will read from analog pin 0 (A0), which is used for the UP button, so it isn’t floating. The internal pullup resistor will make it always read 1024 if the UP button isn’t pressed, or it will read 0 when the button is pressed.

Hey. If I were to use that the player panel code would break since it checks if the player byte is exactly the same to the iterable. Is there a way to treat an enum like a list and return the index of a value?

Which code?
I’m not sure what you mean.

(Also C++ has its own concept of an iterator and its own equivalent of an iterable, which are different from the Python definitions. I won’t go into those right now, they’re a bit complicated so it would take quite a bit of explaining.)

No, but you usually don’t need to.
In fact in your case if Cell is defined as:

enum class Cell : uint8_t
{
  Empty, Nought, Cross,
}

Then the numbers are implicitly assigned as thus:

enum class Cell : uint8_t
{
  Empty = 0, Nought = 1, Cross = 2,
}

I just realised it should be:

Cell randomCell(void)
{
  return static_cast<Cell>(rand() % 3);
}

Cell randomNonEmptyCell(void)
{
  return static_cast<Cell>(1 + (rand() % 2));
}

I’m not sure why you want that though.
To pick the player’s cell type at random?

player changes each turn, from cross to nought to cross to nought, etc.

player = (player == Cell::Nought) ? Cell::Cross : Cell::Nought;

Should this be …

player = (player == Cell::Nought ? Cell::Cross : Cell::Nought);

Nope. The following are all equivalent:

player = player == Cell::Nought ? Cell::Cross : Cell::Nought;
player = (player == Cell::Nought) ? Cell::Cross : Cell::Nought;
player = (player == Cell::Nought ? Cell::Cross : Cell::Nought);
player = (player == Cell::Nought) ? (Cell::Cross) : (Cell::Nought);
player = ((player == Cell::Nought) ? (Cell::Cross) : (Cell::Nought));

Whether there are brackets or not and where the brackets are is purely a matter of taste.

Personally I like to wrap the boolean expression for two reasons:

  1. It more closely resembles if(condition) expr1; else expr2;
  2. The condition tends to be more complicated or more likely to get ‘lost’ in the text.

If the values for the expressions are sufficiently complicated I’ll sometimes wrap those in brackets as well, but in most cases the value expressions are either literals or something simple.

(The only time I can remember having to do crazy things is in FixedPoints because I really wanted all the operations to be constexpr.)


Fun fact: In Haskell the if expression is effectively a ternary operator. E.g.:

isEven :: Int -> Bool
isEven n = if n % 2 == 0 then True else False