BGS
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Login
    1. Home
    2. Ewan
    3. Best
    E
    Offline
    • Profile
    • Following 0
    • Followers 1
    • Topics 7
    • Posts 26
    • Groups 0

    Posts

    Recent Best Controversial
    • Stats on factions

      On https://forum.boardgamers.space/topic/82/statistics-just-wondering-on-the-progress/8 I've uploaded a script (which I hope is correct) that can fetch statistics for the factions on all games. For easy reference, here is a screenshot of the results:

      stats_gp.png

      Some thought, some of which I don't think will surprise experienced players:

      • the Ivits are very strong overall, especially at 2 and 3 players
      • the Taklons are very strong at 4 players, at which they have the most opportunities to rotate their brain stone
      • the Nevlas also profit from higher player counts, and thus more rotation
      • the Lantids and Gleens are weak at every player count
      • the Itars, which are generally considered to be very strong, don't over-perform by that much
      • the Bescods are very weak at 3 players
      • average scores tend to go down as the player count goes up
      • there doesn't seem to be a 'vanilla' faction that performs average on all player counts

      I'm curious to hear what other players think!

      posted in Gaia Project
      E
      Ewan
    • RE: Bug: Booster 6 (VP/Mine) Scored Incorrect Amount

      It's correct, you also had the lost planet on the board, which counts as a mine.

      posted in Comments & Feedback
      E
      Ewan
    • RE: 3 observations
      1. Both are octagon actions, which you can not combine (like you can also not combine the +3 range action with the power action '1 step').

      2. The second phase of the Itars is part of the Gaia phase. The rules, however, are not clear on the order of things within that phase. But this post says you move power tokens to bowl 1 after the Itars ability: https://boardgamegeek.com/thread/2066028/article/30095102#30095102

      posted in Comments & Feedback
      E
      Ewan
    • Bug: more satellites allowed than required

      In the game jobefunhouse017, I play as the Xenos with my Planetary Institute already built, without having the tech tile that makes big buildings worth 4 power points. The game allows me to make the following federation with 7 satellites (indeed, this is the only suggested location for a federation):
      sattelites-bug1.png

      However, when choosing a custom location, I can make this federation with only 6 satellites:
      sattelites-bug2.png

      If I understand the rules correctly (as posted on https://boardgamegeek.com/thread/2120375/official-federation-faq, to which you also link when creating a new GP game), I should only be allowed to create the second federation with 6 satellites. From that thread:

      Q: The path with the fewest satellites to link my chosen planets will touch a planet that I did not wish to include in my federation, can I choose the shortest path that skips this planet?
      A: No, If the "extra" planet cluster is not already a part of a federation, then you must choose the path with the fewest satellites to link your planets, even if it includes extra planets, this is typically where the third rule can come into play making that federation invalid.

      Q: While choosing the path with the fewest satellites to link my chosen planets, I notice that I can use fewer satellites by using a planet cluster I did not choose to be a part of my federation as a "hop" to cut out 1 or more satellites, Must I use this path?
      A: Yes. The path with the fewest satellites MUST be used even if it is achieved by using a planet cluster as a hop to avoid using more satellites.

      Note that in both cases, I didn't end my turn, as I don't want any of those federations at this point, so maybe another check will stop the first federation. However, a check is performed after choosing a fed tile, and that check allows both federations, but not an unnecessarily big one with e.g. 9 satallites.

      posted in Gaia Project bug solved
      E
      Ewan
    • RE: Karma

      Thanks, I like the idea and I hope this will stop people from dropping out! :) But will you also lose karma if you drop out but are not the first one to do so? Because in my opinion it often doesn't make sense to finish a game where one person has already dropped out.

      posted in Announcements
      E
      Ewan
    • RE: Bug: didn't get karma

      Thanks for fixing it! And I really appreciate it that you are so engaged with the players. :)

      posted in Comments & Feedback
      E
      Ewan
    • RE: Bug ? Federation building

      There is no bug in these examples. You can first choose any buildings that add up to 7 or more (that are not already in a federation), no matter how far they are from each other. Then you have to connect those buildings with the least amount of satellites possible, even if that means that you might have to include a building that you didn't choose in you initial choice of buildings. And then you have to check if you could still have made a federation with leaving out at least one building and one satellite.

      So in your HH-example, the buildings you've chosen add up to 7, there is no way to connect those building with less than 8 satellites, and you cannot leave out one building and a satellite, so this federation is valid.

      In your Gleens example, the buildings add up to 7, but you connect them using 7 satellites. However, if you would use the cluster of buildings in sector 6, you could use 5 satellites, hence your proposed federation is not valid.

      Whether this set of rules is ideal is another discussion, but the website implements the official rules. I believe these rules where chosen as to not give an unfair advantage to certain factions when it comes to satellite or buildings in federations scoring.

      See also https://boardgamegeek.com/thread/2120375/official-federation-faq

      posted in Gaia Project
      E
      Ewan
    • RE: Suggestion: play sound when it's your turn when the tab is active too

      Concerning the broader issue - we don't want to have too many settings and sub settings.

      Fair enough. For those interested, I've written a small JavaScript snippet that plays the notification sound every time the counter increases. It can be loaded in e.g. Violentmonkey:

      // ==UserScript==
      // @name        Sound on your turn
      // @namespace   Violentmonkey Scripts
      // @match       https://www.boardgamers.space/*
      // @grant       none
      // @version     1.0
      // @author      -
      // @description Plays notification sound whenever the active games counter increases
      // ==/UserScript==
      
      function playSoundOnFirstActiveGame() {
        let gameCountNode = document.getElementById("active-game-count");
        window.currentActiveGames = parseInt(gameCountNode.innerHTML);
      
        let sound = document.getElementById("sound-notification")
      
        window.activeGamesObserver = new MutationObserver(() => {
          let newActiveGames = parseInt(gameCountNode.innerHTML);
          if(newActiveGames >= window.currentActiveGames) {sound.play();}
          window.currentActiveGames = newActiveGames;
        })
      
        activeGamesObserver.observe(gameCountNode, {childList: true, attributes: true})
      }
      
      setTimeout(playSoundOnFirstActiveGame, 3000);
      
      posted in Comments & Feedback
      E
      Ewan
    • RE: Bug forming custom federation

      This is not a bug, the app is correct. You can connect the buildings you want to connect using only 5 satellites by using the connected mines in sector 10 and 4 as a hop. Therefore, you cannot choose to use 6 satellites. See also https://boardgamegeek.com/thread/2120375/official-federation-faq, especially the questions concerning rule 2.

      posted in Gaia Project
      E
      Ewan
    • RE: Statistics - just wondering on the progress?

      Partially to understand better how those modern fancy JavaScript frameworks work and partially to be hopefully useful to other players, I wrote a JavaScript proof of concept that allows you to see some basic statistics of any player.

      It works as follows: open the dev tools in your browser (usually this is done by pressing F12). Go to the console and copy and past all the code below. At the top of the page, a small form should show up where you can enter any username and see some basic info: how many times they chose each faction, what their average score is with that faction and how many times they won with that faction. I only consider finished non-cancelled Gaia Project games where nobody dropped out.

      If you've removed everything, run statistics(); again in the console. If you ever refresh the page, you need to copy and paste the full code again.

      function statistics() {
      
        const factions = ['terrans', 'lantids', 'nevlas', 'itars', 'firaks', 'bescods', 'taklons', 'ambas', 'xenos', 'gleens', 'geodens', 'baltaks', 'ivits', 'hadsch-hallas']
        let userId;
        let username;
        let showGlobalStats = false;
      
        function getRequest(url, callback, args) {
          fetch(url).then(response => response.json())
            .then(data => callback(data, args));
        }
      
        function loadGameData(userData) {
          userId = userData._id;
          if(!userId) return;
          getRequest('https://www.boardgamers.space/api/user/' + userId + '/games/count/closed', paginateThroughGames)
        }
        
        function paginateThroughGames(numberOfGames) {
          if(showGlobalStats) {
            getRequest('https://www.boardgamers.space/api/game/closed?count=100&skip=0', loadNextGames, {existingData: [], currentSkip: 0, totalGames: numberOfGames});
          } else {
            getRequest('https://www.boardgamers.space/api/game/closed?user=' + userId + '&count=100&skip=0', loadNextGames, {existingData: [], currentSkip: 0, totalGames: numberOfGames});
          }
        }
        
        function loadNextGames(newData, {existingData, currentSkip, totalGames}) {
          const mergedData = existingData.concat(newData);
          if(currentSkip + 100 >= totalGames) {
            filterAndSplitPlayerCount(mergedData);
          } else {
            newSkip = currentSkip + 100;
            if(showGlobalStats) {
              getRequest('https://www.boardgamers.space/api/game/closed?count=100&skip=' + newSkip, loadNextGames, {existingData: mergedData, currentSkip: newSkip, totalGames: totalGames});
            } else {
              getRequest('https://www.boardgamers.space/api/game/closed?user=' + userId + '&count=100&skip=' + newSkip, loadNextGames, {existingData: mergedData, currentSkip: newSkip, totalGames: totalGames});
            }
          }
        }
        
        function filterAndSplitPlayerCount(gameData) {
          const gaiaCompletedOnlyData = filterGameData(gameData);
          
          if(showGlobalStats) {
            analyseGameData(gaiaCompletedOnlyData, 'All players - all')
          } else {
            analyseGameData(gaiaCompletedOnlyData, username + ' - all')
          }
          for(let playerCount=2; playerCount <= 4; playerCount++) {
            if(showGlobalStats) {
              analyseGameData(gaiaCompletedOnlyData.filter(game => game.players.length === playerCount), 'All players - ' + playerCount + ' players');
            } else {
              analyseGameData(gaiaCompletedOnlyData.filter(game => game.players.length === playerCount), username + ' - ' + playerCount + ' players');
            }
          }
        }
      
        function analyseGameData(gameData, title) {
          const gaiaCompletedOnlyData = gameData;
          const factionDataToDisplay = {};
          const countChosen = 'Times chosen';
          const averageScore = 'Average score';
          const wins = 'Wins';
          const winPercent = 'Win %';
          const total = 'total';
          
          for(const faction of factions) {
            factionDataToDisplay[faction] = {};
            factionDataToDisplay[faction][countChosen] = 0;
            factionDataToDisplay[faction][averageScore] = 0;
            factionDataToDisplay[faction][wins] = null;
            factionDataToDisplay[faction][winPercent] = null;
          }
          factionDataToDisplay[total] = {};
          factionDataToDisplay[total][countChosen] = 0;
          factionDataToDisplay[total][averageScore] = null;
          factionDataToDisplay[total][wins] = null;
          factionDataToDisplay[total][winPercent] = null;
      
          for(const game of gaiaCompletedOnlyData) {
            for (const player of game.players) {
              if(showGlobalStats) {
                factionDataToDisplay[player.faction][countChosen] += 1;
                factionDataToDisplay[player.faction][averageScore] += player.score;
                factionDataToDisplay[player.faction][wins] += didPlayerWin(game, player.score);
                factionDataToDisplay[total][countChosen] += 1;
                factionDataToDisplay[total][averageScore] += player.score;
              } else if(player._id === userId) {
                factionDataToDisplay[player.faction][countChosen] += 1;
                factionDataToDisplay[player.faction][averageScore] += player.score;
                factionDataToDisplay[player.faction][wins] += didPlayerWin(game, player.score);
                factionDataToDisplay[total][countChosen] += 1;
                factionDataToDisplay[total][averageScore] += player.score;
                factionDataToDisplay[total][wins] += didPlayerWin(game, player.score);
              }
            }
          }
          
          for(const faction of Object.keys(factionDataToDisplay)) {
            if(factionDataToDisplay[faction][countChosen] > 0) {
              factionDataToDisplay[faction][averageScore] /= factionDataToDisplay[faction][countChosen];
              factionDataToDisplay[faction][averageScore] = factionDataToDisplay[faction][averageScore].toFixed(1);
              factionDataToDisplay[faction][winPercent] = (factionDataToDisplay[faction][wins] / factionDataToDisplay[faction][countChosen] * 100).toFixed(1) + '%';
            } else {
              factionDataToDisplay[faction][averageScore] = null;
            }
          }
          
          if(showGlobalStats) factionDataToDisplay[total][winPercent] = null;
      
          const dataToDisplay = {title: title, data: factionDataToDisplay};
          displayData(dataToDisplay);
        }
      
        function filterGameData(gameData) {
          const gaiaGames = gameData.filter(game => game.game.name.toUpperCase().trim() === 'gaia-project'.toUpperCase());
          const gaiaGamesNonCancelled = gaiaGames.filter(game => !game.cancelled);
          const gaiaGamesNonDroppedOrCancelled = gaiaGamesNonCancelled.filter(game => !someoneDropped(game));
          return gaiaGamesNonDroppedOrCancelled;
        }
      
        function someoneDropped(game) {
          for(const player of game.players) {
            if(player.dropped) return true;
          }
          return false;
        }
        
        function didPlayerWin(game, currentPlayerScore) {
          for(const player of game.players) {
            if(player.score > currentPlayerScore) return false;
          }
          return true;
        }
      
        function displayData(data) {
          const table = document.createElement('TABLE');
          
          const rowFactions = document.createElement('TR');
          rowFactions.appendChild(document.createElement('TH'));
          for(const faction of Object.keys(data.data)) {
            const headCell = document.createElement('TH');
            headCell.innerHTML = faction;
            rowFactions.appendChild(headCell);
          }
          table.appendChild(rowFactions);
          
          const rowProperties = Object.keys(data.data[factions[0]]);
          for(const rowProperty of rowProperties) {
            const rowElement = document.createElement('TR');
            const rowNameElement = document.createElement('TD');
            rowNameElement.innerHTML = rowProperty;
            rowElement.appendChild(rowNameElement);
            for(const faction of Object.keys(data.data)) {
              const cellValueElement = document.createElement('TD');
              cellValueElement.innerHTML = data.data[faction][rowProperty];
              rowElement.appendChild(cellValueElement);
            }
            table.appendChild(rowElement);
          }
          
          
      //    styling:
          table.classList.add('statistics-table');
          
          if(document.getElementById('stat-loading-indicator')) document.getElementById('stat-loading-indicator').remove();
          document.getElementById('my-statistics').insertAdjacentHTML('beforeend', '<h3>' + data.title + '</h3>');
          document.getElementById('my-statistics').insertAdjacentElement('beforeend', table);
        }
        
        function getStatisticsForUser() {
          showGlobalStats = false;
          username = document.getElementById('stat-input-username').value;
          getRequest('https://www.boardgamers.space/api/user/infoByName/' + username, loadGameData);
        }
        
        statistics.getStatisticsForUser = getStatisticsForUser;
        
        function removeAll() {
          document.getElementById('my-statistics').remove();
          document.getElementById('customTableStyle').remove();
        }
        
        statistics.removeAll = removeAll;
        
        function seeAllStats() {
          showGlobalStats = true;
          document.getElementById('my-statistics').insertAdjacentHTML('afterbegin', '<h3 id="stat-loading-indicator">Loading...</h3>')
          getRequest('https://www.boardgamers.space/api/game/stats', (data) => paginateThroughGames(data.finished));
        }
        
        statistics.seeAllStats = seeAllStats;
        
      //  styling element:
        const customTableStyle = document.createElement('STYLE');
        customTableStyle.setAttribute('id', 'customTableStyle');
        customTableStyle.innerHTML = 
      `
      .statistics-table {
      text-align: center;
      margin-bottom: 10px;
      transform: scale(0.8);
      transform-origin: left;
      }
      .statistics-table tr {
      line-height: 2;
      }
      .statistics-table tr:nth-child(odd) {
      background-color: #DCDCDC;
      }
      .statistics-table th {
      padding-left: 12px;
      padding-right: 12px;
      }
      `
        
        document.getElementsByTagName('head')[0].appendChild(customTableStyle);
      
        document.getElementById("navbar").insertAdjacentHTML('beforebegin', '<div id="my-statistics"> <form onsubmit="statistics.getStatisticsForUser(); return false"><input type="text" placeholder="username" id="stat-input-username"><input type="submit" value="See statistics!"></form> <button onclick="statistics.seeAllStats()">Golbal statistics</button> <button onclick="statistics.removeAll()">Remove all</button> </div?');
        
      }
      
      statistics();
      
      

      I'd like to hear suggestions on how to improve this, but note that I do this in my free time so it might take a while before I pick it up (if I want to in the first place). Of course, feel free to edit it yourself to make it do whatever you want.

      @coyotte508: is there a reference for the API available? For example, I currently fetch all games of a player with 'https://www.boardgamers.space/api/user/' + userId + '/games/closed?count=999999&skip=0' and I don't know if the value of 999999 is respected. When leaving count out, it only returns 20 games. Is there a way to always get all the games of a player?

      Edit 1 (2020-07-20): the script should now also work for users who have played more than 100 games.
      Edit 2 (2020-07-21): the tables now also show win percentages.
      Edit 3 (2020-07-21): a table for each player count, total stats on each table
      Edit 4 (2020-07-21): global statistics! It takes a while to load, so don't spam the Global statistics button, so we don't overload the API.
      Edit 5 (2020-09-23): fix broken script by filtering out games that were scheduled but not started, due to a lack of players, by using the cancelled field
      Edit 6 (2020-09-23): change requested endpoints to avoid the same bug as in Edit 5 when looking up individual players

      posted in Comments & Feedback
      E
      Ewan
    • RE: Which game would you love to play here?

      Tigris & Euphrates

      posted in Comments & Feedback
      E
      Ewan
    • RE: New auction system

      So what problem does the auction system try to solve?

      If people want more variety in the factions that are chosen, I would propose to let the system randomly choose the factions at the start of the game and let people bid for them in n-1 rounds when there are n players.

      So suppose there are 3 players. The players will bid until everybody but one player has passed. That player can choose one of the three factions and a player position (or the system can tie the factions and player positions beforehand). Then the two remaining players start a new bidding round (so they start bidding again from 1 victory point) for the two remaining factions. The last player gets the remaining faction for free.

      Mind that in this system the auction can still take a lot of time since if there is one very weak or very strong faction, the bids can still well be over 40 points.

      Or does the auction system try to solve imbalance in player position and win rate? In that case, are there actually statistics available that proof that this is indeed the case? How does rotating the board by the last player affect the win rates? How about the old 'balanced board' system?

      posted in Comments & Feedback
      E
      Ewan