Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  
Pages: 1 ... 787 788 [789] 790 791 ... 795

Author Topic: if self.isCoder(): post() #Programming Thread  (Read 815194 times)

MorleyDev

  • Bay Watcher
  • "It is not enough for it to just work."
    • View Profile
    • MorleyDev
Re: if self.isCoder(): post() #Programming Thread
« Reply #11820 on: September 29, 2020, 08:06:55 am »

Ada says hi. Well, except for the string type bit.

Ada was the closest I could think of, but I'm thinking like "Ada but with Type Inference" which to my knowledge Ada lacks (specially type inference that can resolve and combine the constraints at code/compile-time). I tend to think that static languages with type inference are the way to go, let your IDE tell you the strong types don't make me write them out for anything but to clear up ambiguous inputs to a function.

I mean, I'd also like a pet Unicorn that cleans instead of making mess and a RTX 3090 but ya know xD
Logged

Parsely

  • Bay Watcher
    • View Profile
    • My games!
Re: if self.isCoder(): post() #Programming Thread
« Reply #11821 on: September 29, 2020, 07:06:56 pm »

-snip-

It's probably a little buggy since I wrote it real fast in a text editor, but here's something I came up with:
- replaced the dictionary stuff with an array of structs, i prefer a struct here since:
  -- when you start to type it in Visual Studio, autocomplete will show you all the parameters of the struct you can choose from
  -- writing a constructor to initialize a struct is a lot easier
- included all classes in the same namespace (this handles all the imports for you)
- added a Config class to store data types and keep constants all in one place
- since the RNG stuff seems like it doesn't need direct access to the Player, I moved it into its own class

Feel free to use as much or as little of this code as you like, I understand if some of my assumptions don't work with what you intend to design

Code: [Select]
// Player.cs

namespace MyGame
{
    public class Player : MonoBehaviour
    {
        // player variables
        public Stats stats;
   
        // @parsely: enum is useful to make an index more readable
        //     for example, playerClass.ROGUE == 0
        private enum playerClass
        {
            ROGUE,
            FIGHTER,
            MAGE,
        }
       
        // Player constructor
        Player(int class) {
            // assign stats to player based on class
            switch class {
                case Class.ROGUE:
                    stats = Config.BASE_STATS[Class.ROGUE];  // we can get the stats
                                                             // from MyGame.Config
                                                             // since it's in the same
                                                             // namespace as Player() ;)
                case Config.FIGHTER:
                    stats = Stats.BASE_STATS[Class.FIGHTER];
                case Config.MAGE:
                    stats = Stats.BASE_STATS[Class.MAGE];
            }
           
            // print stats to console
            Debug.Log(stats);
            Debug.Log("Player initialized YO it works beetch!!!");
        }
    }
}


Code: [Select]
// Config.cs

namespace MyGame
{
    public struct Stats
    {
        private int combat,
            athletics,
            subtlety,
            magic,
            investigation,
            persuasion;
   
        // constructor
        public Stats(int c, a, s, m, i, p) {
            this.combat = c;
            this.athletics = a;
            this.subtlety = s;
            this.magic = m;
            this.investigation = i;
            this.persuasion = p;
        }
    }

    public class Config : MonoBehaviour
    {
        // initialize and store the base stats for different classes or enemy types
        public const Stats[] BASE_STATS = {
            new Stats(3,3,5,2,3,3),  // Rogue
            new Stats(5,3,2,2,3,3),  // Fighter
            new Stats(2,3,3,5,4,3),  // Mage
        }

        public const DIE_MAX = 12;
    }
}

Code: [Select]
// RNG.cs

namespace MyGame
{
    public class RNG : MonoBehaviour
    {   
        string StatCheck(int StatUsed)
        {
            Die1 = Random.Range(1, Config.DIE_MAX);
            Die2 = Random.Range(1, Config.DIE_MAX);
            DiceTotal = Die1 + Die2 + StatUsed;

            return "Dice Roll: " + Die1 + ", " + Die2 + ", " + StatUsed + ", Total " + DiceTotal;
        }
    }
}

Code: (Once these classes are set up, do this.) [Select]
/* TODO: now just do this wherever your "main()" is
*    playerClass = Random.Range(0, 2);
*    Player myPlayer = new Player(playerClass);
*/
« Last Edit: September 29, 2020, 07:08:46 pm by Parsely »
Logged

Reelya

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #11822 on: September 30, 2020, 10:27:39 am »

A couple of issues. First Random.Range() with int in C# excludes the top value. You guys want Random.Range(0,3) there. Second, C# doesn't like you using enums as array indexes, though you might be able to cast them to int, it's ugly. If you're going to use them however, go all in, and use them as the data type for all classes, and add an extra enum to keep track of how many you have:

         enum PlayerClass
        {
            ROGUE, // 0
            FIGHTER, // 1
            MAGE, // 2
            NUM_CLASS // 3
        }

"PlayerClass" is now a light-weight data type you can use to refer to classes. Next up, that switch statement doesn't do anything. Just use the variable you're passing in as the index rather than checking if class = PlayerClass.Rogue then using the value "PlayerClass.Rogue". Why? You already know that "class" is that value so you don't need to explictly list them out, and it's less that can go wrong.

However the main problem with the enum approach here is that there's a parallel array that needs to match the number of enums. That kind of thing is an error magnet.

The best thing to do is to forget the enum completely, and encode all the details of the classes into that one array, then when you want to generate a class you just ask the array its size value and pick a row randomly. Rather than a "stats" type just make it a CharacterClass class.

public const CharacterClass[] Classes = {
    new CharacterClass("Rogue",   3,3,5,2,3,3),
    new CharacterClass("Fighter",  5,3,2,2,3,3),
    new CharacterClass("Mage",    2,3,3,5,4,3)
}

playerClass = Random.Range(0, Classes.Length);
Player myPlayer = new Player(playerClass);

Player(int myClass) {
    if(myClass >= 0 && myClass < Classes.Length) {
        stats = Config.Classes[myClass];
    }
}

This is the direction to go in, since it would now be literal seconds to add or remove valid character classes.
« Last Edit: September 30, 2020, 10:53:51 am by Reelya »
Logged

Parsely

  • Bay Watcher
    • View Profile
    • My games!
Re: if self.isCoder(): post() #Programming Thread
« Reply #11823 on: September 30, 2020, 01:56:27 pm »

A couple of issues. First Random.Range() with int in C# excludes the top value. You guys want Random.Range(0,3) there.
That's a Unity function not a vanilla C# one. UnityEngine.Random.Range() is inclusive. https://docs.unity3d.com/ScriptReference/Random.Range.html

Return a random float number between min [inclusive] and max [inclusive] (Read Only).

Quote
Second, C# doesn't like you using enums as array indexes, though you might be able to cast them to int, it's ugly. If you're going to use them however, go all in, and use them as the data type for all classes, and add an extra enum to keep track of how many you have:

         enum PlayerClass
        {
            ROGUE, // 0
            FIGHTER, // 1
            MAGE, // 2
            NUM_CLASS // 3
        }

"PlayerClass" is now a light-weight data type you can use to refer to classes. Next up, that switch statement doesn't do anything. Just use the variable you're passing in as the index rather than checking if class = PlayerClass.Rogue then using the value "PlayerClass.Rogue". Why? You already know that "class" is that value so you don't need to explictly list them out, and it's less that can go wrong.

However the main problem with the enum approach here is that there's a parallel array that needs to match the number of enums. That kind of thing is an error magnet.

The best thing to do is to forget the enum completely, and encode all the details of the classes into that one array, then when you want to generate a class you just ask the array its size value and pick a row randomly. Rather than a "stats" type just make it a CharacterClass class.

public const CharacterClass[] Classes = {
    new CharacterClass("Rogue",   3,3,5,2,3,3),
    new CharacterClass("Fighter",  5,3,2,2,3,3),
    new CharacterClass("Mage",    2,3,3,5,4,3)
}

playerClass = Random.Range(0, Classes.Length);
Player myPlayer = new Player(playerClass);

Player(int myClass) {
    if(myClass >= 0 && myClass < Classes.Length) {
        stats = Config.Classes[myClass];
    }
}

This is the direction to go in, since it would now be literal seconds to add or remove valid character classes.
Do all of this though, this is all good^^
Logged

Reelya

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #11824 on: September 30, 2020, 07:51:39 pm »

A nice thing to do would be to add an unsigned int one the end of the stats, for flags. a 32 bit int gives you 32 yes/no switches, then you can name them. For example

...
flagCanCastSpells = 16
flagCanUseSwords = 32
...
up to 2^31 for the last flag. Then you can just write "flagCanCastSpells + flagCanUseSwords" to add an entirely new spellsword class (though they might not have all the other flags of the warrior or mage). And then throughout your code you only test whether the character has the required bits set in the abilities field as to whether they can do things, and you never need to write any code that explicitly checks that they're the correct class.

EDIT: the way i'd flesh this out would be these flags
- one for wearing light armor (leather / eleven chain). rogue and fighter have this flag.
- one for wearing heavy/metal armor. fighter only.
- melee weapons flag. up to longsword. rogue and fighter. Quaterstaff, dagger, sling come under "basic" weapons anyone can use.
- heavy weapons flag. fighter only.
- archery flag. rogue and fighter. Use bows and crossbows
- etc etc

Then by using these anywhere you need to check if someone can do something it's far easier to craft custom classes.

Then to make this even more data-driven you define actions in the game according to which flags they need you to have to be allowed to do them. For example, equipping items might require certain bits to be set, and the game just checks that you have all those bits set, and this seamlessly enforces your game rules without you needing to really hard-code anything in particular.

For example, give each bit of equipment an int containing the bits needed to equip it, and when a character tries to equip it, you do a bitwise '&' operation between that bitfield and the character's one, and it should be the same:

if(itemBitfield == (itemBitfield & characterBitfield)) { /* item can be equipped */ }

And that one line of code could deal with the entirety of D&D rules for equipping items per character class as long as you set the bitfields on classes and objects properly.
« Last Edit: September 30, 2020, 08:11:28 pm by Reelya »
Logged

Parsely

  • Bay Watcher
    • View Profile
    • My games!
Re: if self.isCoder(): post() #Programming Thread
« Reply #11825 on: October 01, 2020, 01:22:39 am »

That looks cool! I like that if you slap the unsigned int values in an enum and assign it the Flags attribute, it'll even neatly print stuff out for you: https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=netcore-3.1
« Last Edit: October 01, 2020, 01:24:10 am by Parsely »
Logged

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #11826 on: October 08, 2020, 07:02:55 am »

I have avoided C++ for 7 years. I didn't want to touch it. I still hate its build systems, the build ecosystem surrounding it.

But I have literally never had as much fun programming as I do when I'm working in C++, doing optimizations. Nothing has ever come close. I feel like I haven't been programming until recently. What the heck is happening. I could infodump about C++17 and C++20 features for hours. I'm getting an actual desire to optimize Dwarf Fortress, like some sort of rando programmer who stumbles into the forums and gets rebuked. It's unbelievable, just how much I'm enjoying C++ work and optimization. Thinking about cache locality is fun, considering where multithreading might get a use and when the overhead of an atomic variable might not be worth it is stimulating. Good lord.

WealthyRadish

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #11827 on: October 08, 2020, 09:38:48 am »

Are you checking out SIMD intrinsics as well? It's like writing shaders on the CPU, but with everything stored as SoA.
Logged

Reelya

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #11828 on: October 08, 2020, 09:58:14 am »

Here's a nice video on string code optimization. If you use string a lot it makes sense to roll your own optimized string
https://www.youtube.com/watch?v=kPR8h4-qZdk

Putnam

  • Bay Watcher
  • DAT WIZARD
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #11829 on: October 08, 2020, 10:00:57 am »

Are you checking out SIMD intrinsics as well? It's like writing shaders on the CPU, but with everything stored as SoA.

I'm writing code that less low-level programmers have to deal with and has to work even on pretty-bad computers (hell, the server I'm writing it for is running on an older and less powerful CPU than the one in my PC, which I learned the hard way when my AVX2 auto-vectorizing caused performance loss when pushed live), so I've been avoiding intrinsics and instead just writing loops to be as auto-vectorizable as possible.

Telgin

  • Bay Watcher
  • Professional Programmer
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #11830 on: October 08, 2020, 02:47:29 pm »

Yeah, I wouldn't touch intrinsics or things like inline assembly unless it was for a fixed and fairly modern platform and the performance was absolutely critical.

C++ is certainly a different feeling from working with high level languages, both good and bad.  One thing I do miss about it is having a very clear understanding of how references work, which can sometimes get confusing in languages like, say, PHP.

I used to do almost all of my programming in C++, but using very old dialects from the 90s, and never even learned concepts like auto pointers, much less whatever has been introduced in the last few years.  I have been considering going back to it lately though for a game project I mentioned a while back, where I planned to write a server for a simple space 4X that clients could connect to that were written in other languages.  That would let me get the performance out of C++ without making things like the UI a massive pain in the butt.

I've considered if something like Node.js is fast enough to use for the server architecture, and honestly unless I do something crazy it probably is, but with C++ you can at least know you know you're starting with a language that can provide the needed speed and predictability when it comes to things like garbage collection.  The only real problem I was running into was my consideration of providing a scripting interface for mod support as a distant future feature, but adding that to C++ is way harder than just giving people the option of writing a Node.js module and requiring it.
Logged
Through pain, I find wisdom.

MorleyDev

  • Bay Watcher
  • "It is not enough for it to just work."
    • View Profile
    • MorleyDev
Re: if self.isCoder(): post() #Programming Thread
« Reply #11831 on: October 08, 2020, 04:02:22 pm »

Man, naming is hard. I was legit about to create a class called StatefulState. Like, it's a state the system in the FSM sense that can also maintains it's own internal State in the Redux sense. So it's a StatefulState...

I think I'm too far down the rabbit hole xD
Logged

bloop_bleep

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #11832 on: October 08, 2020, 08:16:33 pm »

I'm getting an actual desire to optimize Dwarf Fortress

Hey, I felt that too at some point. Though I guess the first step would be using a sampling profiler or something like that to build an accurate model of the program during execution, and see what needs to be targeted. I haven't tried doing that yet...

Also, I agree, I have the most fun writing C++ code. The combination of high-level elegance and ease of use with the lower-level considerations is fascinating to deal with.
Logged
Quote from: KittyTac
The closest thing Bay12 has to a flamewar is an argument over philosophy that slowly transitioned to an argument about quantum mechanics.
Quote from: thefriendlyhacker
The trick is to only make predictions semi-seriously.  That way, I don't have a 98% failure rate. I have a 98% sarcasm rate.

Reelya

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #11833 on: October 08, 2020, 08:18:24 pm »

It's probably easier at that stage to write your own colony sim and optimize that for multi-core systems from the start.

Telgin

  • Bay Watcher
  • Professional Programmer
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #11834 on: October 08, 2020, 08:24:01 pm »

Man, naming is hard. I was legit about to create a class called StatefulState. Like, it's a state the system in the FSM sense that can also maintains it's own internal State in the Redux sense. So it's a StatefulState...

I think I'm too far down the rabbit hole xD

This reminds me of some terrible SOAP API I had to work with once that had methods like ConvertArrayOfStringsToArrayOfArrayOfCharacters.  That's not a literal example but there were some very similar to that in it.
Logged
Through pain, I find wisdom.
Pages: 1 ... 787 788 [789] 790 791 ... 795