#card-game #impact #tcg #genshin

genius-invokation

Abstractions and structures for Genius Invokation TCG

3 releases (breaking)

0.2.0 Dec 27, 2022
0.1.0 Dec 24, 2022
0.0.0 Dec 20, 2022

#428 in Games

MIT/Apache

83KB
1.5K SLoC

Genius Invokation TCG

This is a simple crate with an abstraction for the elements in Genius Invokation TCG, the card game from Genshin Impact.

Usage

Creating a Deck

You can use the public enums to create CharacterCards and ActionCards (hint: All the action card subtypes implement Into<ActionCard>). From those, you can convert them into a Card type (which is an enum wrapper around those two main types), and create a Deck using from_iter.

Of course, if you somehow already have 3 character cards and 30 action cards exactly, you can use the from_exact method, which is faster than the iterator method, since it skips allocation and just verifies important properties (such as not having duplicate character cards or having talent cards without its matching character card).

Alternatively, if you've already built a deck in the deck builder website, you can enable the deck-url feature, which gives you access to the deck_from_url function, which receives a url string that looks like this:

https://genshin.hotgames.gg/tcg/deck-builder?deck=1.6.MC.MD.MF.MG.MH.MI.MJ.MK.ML.MM.MN.MO.MP.MV.MY.e.g8.gB.gD.gF.gb.ge.gh.gk.gt.gv.gx.gz.wj.wl.wm&ver=1&lang=en&author=DefaultDeck

That function returns a card iterator, which you can then use to create a deck with from_iter.

Extracting info

Now, let's say you wish to analyze some information in a huge list of decks. Assuming you have all the deck builder urls in a file, line by line, you may include it or simply read to string, and once that's done, it's as simple as

    let iter = decks.lines()
        .map(|url| Deck::from_iter(deck_from_url(url).unwrap()));

Of course, that will yield results, so you can also unwrap it if you're 100% sure none of those decks are invalid.

Let's say you want to count how many decks include a specific card, for example, Strategize, you could simply run

    iter.filter(|deck| deck.contains(NormalEventCard::Strategize.into())).count()

Now let's say you only want to look at the companion cards, maybe you wish to count them up and see which are the most prominent:

    iter.map(|deck| deck.iter().filter_map(|card| card.companion())).flatten()

You now have an Iterator<Item=CompanionCard>. Do note that this includes duplicate cards, so if a player has two of the same card, the iterator will yield that card twice. If you want to only look at the unique instances of a card, run deck.iter_unique() instead.

Of course, companion() isn't the only method available, it's only one among all the other helper methods in the PlayingCard trait.

Work in progress!

So far, I still have to figure a lot of things out, such as:

  1. Having a nice implementation for converting between strings and enum variants. I could make them manually matching every single variant, but that's boring and tricky to maintain.

  2. Serde implementations, especially if APIs wish to use this crate in the future.

  3. Figuring out how to make documentation for everything. Everytime I try to make documentation for something like the CharacterCard enum, I just see myself being either redundant or trying to explain how the game works, both of which are not what documentation should be.

  4. Figuring out if I should include "special" kinds of cards that cannot be in the deck. This includes cards such as the Abyss Mage or Hilichurl cards, but also the Keqing special card Lightning Stiletto, which can be part of your hand during the game, but cannot be added to your actual deck.

  5. Maybe including a description feature that adds a description method for each card? This would reeaally increase the size of the crate (since it's a lot of text stored statically), but maybe a useful feature to add.

  6. Adding more items to this list.

No runtime deps