Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic Data + Advance Dynamically #12

Open
toomas1968 opened this issue Jan 31, 2022 · 12 comments
Open

Dynamic Data + Advance Dynamically #12

toomas1968 opened this issue Jan 31, 2022 · 12 comments
Labels
exterior involves a question/comment about the codebase for an exterior use

Comments

@toomas1968
Copy link

toomas1968 commented Jan 31, 2022

Hi, First of all I want to say that this is very well done piece of code. But I need tips of how to make it fit my needs.

Lets say that the Data comes from the DB. Meaning that instead of
let prettyEntries = this.deepcopy(entries)
I have
let prettyEntries = this.deepcopy(DBARRAY)

Assuming that the DB has column "Round". If the ROUND would change from 1 -> 2. How would you display it in the table? Obviously it would need to proceed from 2 -> 3 and so on (to the final).
The data is predefined meaning that the info going TO the DB is correct. Example

if there is 16 drivers in round 1 then round 2 has 8 drivers, round 3 has 4 drivers etc.
How to make it reflect in the brackets?

I am currently trying to change your solution to dynamic data but my limited knowledge of JS is stepping in my way :D

@XDwightsBeetsX
Copy link
Owner

XDwightsBeetsX commented Jan 31, 2022

Hey @toomas1968 thanks for checking out my code!

So if I understand correctly, you are wanting to store/fetch the JS bracket in a tabular DB like mySQL, and the issue is when you store the entries that go on to the next round.

Quick&Dirty

If you have a column with round, then you could update just those that are moving on to the next round, and fetch WHERE round == '3' and so forth:

playerName round
a 1
b 2
c 2
d 1

so you know b and c are facing off in the final...

PROBLEM - the problem with this though, is that your order might not be easy to preserve, and it could be a bother to have each round jumbled up, and you would have to jump around to see the player's previous matches.

Sol? - I think you might be able to fix this problem by assigning a previous division like they do in sports with Northwest/Southeast conferences.
You could do this with a prevConf column or more simply, just give them a bracketPosition from top to bottom to keep track of the order.

Hope this helped! I'm no expert programmer, but glad someone's checking out this project...

@XDwightsBeetsX XDwightsBeetsX added the exterior involves a question/comment about the codebase for an exterior use label Jan 31, 2022
@toomas1968
Copy link
Author

toomas1968 commented Feb 1, 2022

Hi again @XDwightsBeetsX .

You are absolutely right. The Round 1 order is actually defined by fixed order meaning that drivers round 1 position are ordered according to predefined template.

Perhaps I am overthinking it but I see couple issues ...

  1. Number of rounds are dynamic right? So if you have 6 drivers you have 3 rounds but if you have 16 drivers you have 4 rounds etc
  2. How do I add it in the code itself? Like how do I check that drivers round == 2 therefore these drivers go to the next row (actually now row per say but new height is I think more accurate to say?

Do you think you could perhaps give me some sort of code example?

@XDwightsBeetsX
Copy link
Owner

Now

Default Bracket Construction

  • So intuitively (I thought), by default the bracket is built by adding all the Entries then filling up the later rounds with Entry(BYE).
  • These are then arranged so that the earliest entries (the highest seeds) are matched up against the lowest like a normal tournament:
// Bracket.constructor()
// swap prettyEntries to set byes by default
for (let i = 1; i < nearestP2/2; i+=2) {
    let swap = prettyEntries[i];
    prettyEntries[i] = prettyEntries[nearestP2-i];
    prettyEntries[nearestP2-i] = swap;
}
  • The depth, or number of rounds of the bracket is set just before this and is saved as a property of the Bracket:
// determine bracket dimensions
let nearestP2 = 2**(Math.ceil(Math.log2(entries.length)))
this.Height = 2*nearestP2 - 1;
this.Depth = Math.log2(nearestP2) + 1;

Suggested

So to be able to update this dynamically, I think you should add a property to the each Entry via Entry.Round = 1;
You should update the value when an entry is advanced or reverted.

  • You should be careful if you want to do this in the Bracket.RawEntries (static list), or in the html Bracket.PrettyEntries. Either way should work, but just stay consistent.
  • I would recommend keeping stats in the RawEntries since the other PrettyEntries are the ones dealing with html formatting.
  • Now, if you wanted all the Entries who are in the 2nd round, you could do something like this:
function getEntriesInRound(int round) {
  // hold the entries that are in this round
  let roundEntries = [];
  
  // go through and add entries that match the given round
  for (int i = 0; i < this.RawEntries.length; i++) {
    let e = this.RawEntries[i];
    if (e.Round == round)
      roundEntries.push(e);
  }
  return roundEntries;
}
  • I think this is what you want... Adding this Entry.Round property will allow you to update each entry's state. You can then iterate through these and do whatever you want with the entries in a round...

@toomas1968
Copy link
Author

toomas1968 commented Feb 2, 2022

Hi,

Sorry but is somewhat still unclear to me. Particularly the part "do whatever you want with the entries in a round". Issue is that currently I don't see where I can add part where I can set return roundEntries; as a second row or third row etc. Currently the main logic goes to makeBracket() method in Bracket.js (tho I have modified it to fit my needs)

Your suggestion does indeed return the list of entries that are in range of specified round. The 'round' is in your case Depth(right?) so comparing the entries to Depth and returning the corresponding list works. But then pushing this to the roundEntrie will result infinite loop where page crashes. (As I mentioned before. My limited JS skills)

Check example below. As soon as I push entries. Site crashes. This loop is currently in makeBracket method. PS for example purpose I use prettyEntries but as soon as I get this logic working I will optimize the code to use rawEntries

for(let j = 0; j < Depth; j++) {
    for (let i = 0; i < prettyEntries.length; i++) {
        let e = prettyEntries[i];
        if (e.round == j) console.log(e + " ; "+ e.round +  " ; "  + j)
        //prettyEntries.push(e);
    }
}

Where would you add such logic in your current state of code?

Thank you in advance and big thanks for helping me out in a first place :P

@XDwightsBeetsX
Copy link
Owner

Crash Issue

I'm not sure, but I think editing the prettyEntries could be causing reference issues.
Also, when you have multiple lines in your if block, you should put them in brackets like Java, C++, etc.

  • Pretty sure this is what you intended...
    if (e.round == j) {
      console.log(e + " ; "+ e.round +  " ; "  + j);
      prettyEntries.push(e);
    }
  • In JS, or most languages in general, most entities are created at a location in memory, then the address at which they are stored is passed around, allowing the program to access the entity. This is called passing by reference.
    • This maximizes speed and keeps variables consistent across the program.
    • Issue - If you are editing the object by reference, it gets changed for the rest of the program.
    • This is tricky in JS since it's not as explicit as C++ or other languages.
  • This gets solved by making a deep copy, or creating a new object with all the same values.
    • You can now use this object without impacting the original one.

Desired

Ok, so if I understand right, you want to do 2 things:

  1. Get entries from the bracket / a specific round
  2. Add db entries into the bracket, perhaps already with some info like round

Get Entries for DB

Getting entries will be very simple. you can do it from either the prettyEntries or the rawEntries:

// using rawEntries
function getBracketEntries() {
  return this.RawEntries;
}

// go through prettyEntries and find the non-BYE entries
function getBracketEntries() {
  let entriesToReturn = [];
  for (int i = 0; i < this.PrettyEntries.length; i++) {
    e = this.PrettyEntries[i];
    if (e.Name != "BYE" && e.Name != "TBD" /*&& e.Round == round*/) {
      entriesToReturn.push(e);
    }
  return entriesToReturn;
}

Setting the Bracket From DB

This will be much more complicated, but can be done with some changes...
I'll try to explain how I would approach this...

  1. Note that in the HTML bracket, every position in the bracket has it's own flex row:
    image
  2. When you export the entries to the database, you don't really need to track Entry.Round
    • You can, but to make the bracket from the db, it will be much easier to save Entry.BracketRow
    • I would also export the entire bracket, including BYEs/TBDs to make setting the bracket easier
  3. Loading the Bracket from DBEntries
    • Then you'll need a special way to load the bracket. something like Bracket.loadFromDBEntries(dbEntries)
    • This should reset the global variable _E_List to the dbEntries
    • Now you can call makeBracket, which uses the _E_List
    • Here, you will need to update makeBracket
      • in the Bracket.constructor(entries) you need to update prettyEntries based on the dbEntry.BracketRow

NOTE: this will take some math. Note that every other row in the bracket is in the second round, and every fourth is in the third, and so forth. this is why Depth is important.

alternatively, you could call advanceEntry based on dbEntry.BracketRow but this could screw up some HTML stuff...

@toomas1968
Copy link
Author

toomas1968 commented Feb 8, 2022

Hi,

I have tried several ways but still no luck. As you said in your last answer, math is mostly the blocker here. I am not a quitter but I think I am quitting this project of mine. Regardless your application did help me a lot so thank you for that :)

As for math I though that since the Visual Graph goes like this

  • second round = flex row 2-6-10-14
  • third round = flex row 4-12-20
  • forth round = flex row 8-24

I thought that I would simply loop through Height again with i+=4 for second round etc and then loop through entries. Then if entries.round = 2 then somehow push? entries to second row. But this is the part where I got stuck and I have not been able to solve the issue.

"NOTE: this will take some math. Note that every other row in the bracket is in the second round, and every fourth is in the third, and so forth. this is why Depth is important."

@XDwightsBeetsX
Copy link
Owner

All good @toomas1968 !

  • I honestly had to write out some stuff to get the math to work out and it would take me a bit to get my head wrapped around it again...
  • There's a lot of fancy base-2 stuff and some ceiling/floor functions needed to get the row & entry you want
    • If you get that, then accessing the bracket data and keeping track of the entry positions will be fast and accurate
  • Here's some code that does bracket operations. If you're interested it might help...
// Bracket
constructor(entries) {
        this.RawEntries = deepCopy(entries);
        
        // determine bracket dimensions
        let nearestP2 = 2**(Math.ceil(Math.log2(entries.length)))
        this.Height = 2*nearestP2 - 1;
        this.Depth = Math.log2(nearestP2) + 1;

        // make a filled list of Entries with BYEs
        let prettyEntries = deepCopy(entries);
        for (let i = prettyEntries.length; i < nearestP2; i++) {
            prettyEntries.push(new Entry(BYE));
        }
        // swap prettyEntries to set byes by default
        for (let i = 1; i < nearestP2/2; i+=2) {
            let swap = prettyEntries[i];
            prettyEntries[i] = prettyEntries[nearestP2-i];
            prettyEntries[nearestP2-i] = swap;
        }
        // add in TBDs to prettyEntries
        for (let i = 1; i < prettyEntries.length; i++) {
            if (i % 2 == 1) {
                prettyEntries.splice(i, 0, new Entry(TBD));
            }
        }
        this.PrettyEntries = prettyEntries;

        // fill initial bracket
        this.makeBracket();
    }

This stuff is very similar to the concept of binary trees in computer science
Thanks for checking out my project! I hope you picked up some tricks!


@toomas1968
Copy link
Author

HI again. Do you think this is something that you will reopen and perhaps investigate by any chance?

@XDwightsBeetsX
Copy link
Owner

Hey @toomas1968! Sorry to say I don't think I will contribute to this issue, but if you would like to open a new issue and branch to add this feature, feel free!

@toomas1968
Copy link
Author

Hi @XDwightsBeetsX

So I got the thing working exactly as I wanted. Wanted to say big thanks for your existing solution because it did give me a lot of new ideas and was very good example. One thing tho ...

How would you add lines between .be boxes? So like in Tournament Bracket you see these lines between boxes indicating which pair is together and so forth?

@XDwightsBeetsX
Copy link
Owner

Oh nice @toomas1968! If you think this is something that could help others, feel free to make a pull and share!

Well, that's something I initially thought about when making the site! It was easier to just make the bracket-entry elements...
Since the lines between the boxes must be added to somewhat irregularly spaced lines, I just skipped it 😬 😐

Maybe from this picture you can see the issue...

It could be easier to add elements made up of only a |-like icon or something to help control this rather than adding border styles... 🤷‍♂️

@toomas1968
Copy link
Author

@XDwightsBeetsX I will think about it. The reason why I hesitate is because my solution is very custom. It requires to have Array items in certain order. For example API provides me array with currentPosition field what has participants in certain order. I will just order my array with the currentPosition asc and then will loop array. In fact it is not best solution but I will do loop for each round. If you are interested in checking my solution out then I can for sure commit it to my github and then lets go from there :P

As for the lines I tried to implement https://codepen.io/grozzzny/pen/GRZNxqW example (silly me) but my CSS skills + JS skills are very very bad so thats why I came here asking for help. This codepen example is using pseudo elements ::after and ::before to draw lines. Issue is that it is relatively hard to access first column (first child) and last column (last child) because the technique of the bracket solution :D Perhaps I am mistaken and it can be solved easily.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
exterior involves a question/comment about the codebase for an exterior use
Projects
None yet
Development

No branches or pull requests

2 participants