So the project I am working on is a sort of online-roulette. It's a game that has up to 12 players and I need to position them around the table on approximately equal distance from each other no matter how many of them would play (so if I have two, five, seven, twelve or eleven players the distance between them should be the same at least from the first glance). I have a tableUserPlaces value which contains all the positioning values, but it is completely static. I need to set this variable in more dynamic way, but I can figure out how to get this done. Which properties change when the number of players changes and which of them can I tweak to get a new array of positions anytime I have new players' count?
Here is the code for two relevant components
export interface IGamePlus extends Omit<IGame, "matches"> { ticket: ITicket; matches: IMatchPlus[]; requiredMatches: number;}class BestAtTableGame extends React.Component<IBestAtTable, IBestAtTableState> { constructor(props) { super(props); this.state = { createTicketIsOpen: false, ticketIsOpen: false, selectedTicket: {}, gameStatus: null, showRuleIsOpen: false, ruleData: null, ruleClicked: false, ruleType: 0 as number, }; } static getDerivedStateFromProps(props): any { return { gameStatus: { gameCreated: props.game.status === gameDictionary.GAME_STATUS_CREATED, gameStarted: props.game.status === gameDictionary.GAME_STATUS_STARTED } }; } componentDidMount(): void { window.resizeViewport(); const gameId = this.props.match.params.gameId; this.props.gameTypeRequest({ getParams: { id: gameId, type: gameDictionary.GAME_TYPE_BEST_AT_TABLE } }); this.props.ticketsRequest({ getParams: { gameId, type: gameDictionary.GAME_TYPE_BEST_AT_TABLE } }); } componentDidUpdate() { if (this.props.rules && this.props.rules.length > 0 && !this.state.showRuleIsOpen) { const currentGameRule = this.props.rules.find(item => { return item.gameType === Number(this.state.ruleType); }); if (currentGameRule && JSON.parse(currentGameRule.text).hasOwnProperty(localStorage.locale) && this.state.ruleClicked) { this.setState({ showRuleIsOpen: true, ruleData: JSON.parse(currentGameRule.text)[localStorage.locale] }); } } } componentWillUnmount(): void { this.props.gameTypeReset({ type: gameDictionary.GAME_TYPE_BEST_AT_TABLE }); } switchModal = (e: any): void => { this.setState({ ruleClicked: false }); switchModalGlobal(this, e); } setTicket = (data: ITicket): void => { this.setState({ selectedTicket: data, ticketIsOpen: true }); }; showRule = e => { const type = e.currentTarget.dataset.rule; if (!this.state.ruleData) { this.props.getRulesRequest({ getParams: { pageNumber: 1 } }); } this.setState({ ruleClicked: true, ruleType: type, }); }; renderPlaces = (): any => { const { gameStatus } = this.state; const { game, user, translate } = this.props; const seatUnavailable = game.tickets.find(({ player }) => player.id === user.id) || user.permissionLevel > userDictionary.USER_PLAYER_PERMISSION_LEVEL; let placeCount = 0; return tableUserPlaces.map((item, i) => { if (seatsInTableAvailable[game.maxPlayers - 1 > 11 ? 11 : game.maxPlayers - 1].indexOf(item.place) !== -1) { const ticket = game.tickets[placeCount]; placeCount += 1; return (<UserPlace key={i} placeCount={placeCount} seatUnavailable={seatUnavailable} gameStatus={gameStatus} ticket={ticket} item={item} game={game} translate={translate} setTicket={this.setTicket} switchModal={this.switchModal} /> ); } return null; }); }; render(): JSX.Element { const { selectedTicket, createTicketIsOpen, ticketIsOpen, gameStatus, ruleData, ruleType, showRuleIsOpen } = this.state; const { game, translate } = this.props; return (<><CSSTransition in={showRuleIsOpen} unmountOnExit={true} timeout={200} classNames="modalWindowAnimation"><ShowRuleModal dataModal="showRuleIsOpen" ruleData={ruleData} ruleType={ruleType} switchModal={this.switchModal}/></CSSTransition><CSSTransition in={createTicketIsOpen} unmountOnExit={true} timeout={200} classNames="modalWindowAnimation"><CreateTicketModal dataModal="createTicketIsOpen" switchModal={this.switchModal} game={game} gameType={gameDictionary.GAME_TYPE_BEST_AT_TABLE} /></CSSTransition><CSSTransition in={ticketIsOpen && game.status === gameDictionary.GAME_STATUS_STARTED} unmountOnExit={true} timeout={200} classNames="modalWindowAnimation"><ViewTicketModal dataModal="ticketIsOpen" switchModal={this.switchModal} game={game} selectedTicket={selectedTicket} /></CSSTransition><div className={cn("best-at-table-game", {"best-at-table-game__seats-disabled": !gameStatus.gameCreated })}><div className="games__header"><div className="left-side"><img src="/assets/images/gameTiles/1.png" alt="" /><span>{translate("Best at Table")}</span><div className="info-link" data-rule={gameDictionary.GAME_TYPE_BEST_AT_TABLE} onClick={this.showRule}>?</div></div> {game.id && (<div className="right-side"><img src="/assets/images/gameTiles/1.png" alt="" /><span> {game.tickets.length} / {game.maxPlayers}</span></div> )}</div><div className="best-at-table__viewport-wrapper"><div id="viewport-wrapper"><div id="viewport"><div className="best-at-table-game__container">{game.id && this.renderPlaces()}</div></div></div><Link to="/best-at-table/games" className="btn gold-btn best-at-table-game__btn-back">{translate("Back")}</Link><Top game={game} translate={this.props.translate}/></div></div></> ); }}export default withRouter( connect( (state: any) => ({ user: state.auth.user, game: state.gamesTypes.bestAtTable.game, rules: state.rules.rules, }), { gameTypeRequest, ticketsRequest, gameTypeReset, getRulesRequest, } )(withTranslate(BestAtTableGame)));
And this is like a database for positions
export const tableUserPlaces = [ { place: 0, _styles: { top: "0", left: "40%" }, }, { place: 1, _styles: { top: "30px", left: "66%", }, }, { place: 2, _styles: { top: "150px", left: "79%", }, }, { place: 3, _styles: { top: "260px", left: "84%", }, }, { place: 4, _styles: { top: "370px", left: "79%", }, }, { place: 5, _styles: { top: "480px", left: "66%", }, }, { place: 6, _styles: { top: "520px", left: "42%", }, }, { place: 7, _styles: { top: "480px", right: "66%", }, }, { place: 8, _styles: { top: "370px", right: "79%", }, }, { place: 9, _styles: { top: "260px", right: "84%", }, }, { place: 10, _styles: { top: "150px", right: "79%", }, }, { place: 11, _styles: { top: "30px", right: "66%", }, },];export const seatsInTableAvailable = [ [0], [0, 6], [0, 3, 9], [0, 3, 6, 9], [0, 1, 3, 6, 9], [0, 1, 3, 6, 9, 11], [0, 1, 2, 3, 6, 9, 11], [0, 1, 2, 3, 6, 9, 10, 11], [0, 1, 2, 3, 4, 6, 9, 7, 8], [0, 1, 2, 3, 4, 6, 9, 7, 8, 10], [0, 1, 2, 3, 4, 5, 6, 9, 7, 8, 10], [0, 1, 2, 3, 4, 5, 6, 9, 7, 8, 10, 11],];export const seatsAvailable = [ [0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7, 8], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],];