What is the lowest-level spell combo to give disadvantage to an enemy’s specific save, without running into follow-up concentration issues?

What I’m trying to do is debuff an enemy’s stat so that I can hit them with a “save or suck” spell like dominate monster, and be more likely to succeed.

The problem is, I’m running into concentration issues because most spells that debuff a single stat like Bestow Curse use concentration, and thus I cant use them in conjunction: The moment I cast Dominate Monster, Bestow Curse is removed.

Hex also will not work because it only impacts ability checks, and not saves.

To clarify, I am a Warlock who wants to cast powerful disabling spells only when they have a high chance of success (so typically Wisdom has to be the weakened modifier). However, I am open to answers outside of that class, as well as any spell combos that specifically function as

  1. Weakening the the ability save for the second spell without utilizing concentration, and

  2. The second spell being a powerful, one-save spell of concentration.

What spells would be the best for this kind of combo, given that only I can cast the spells?

Does the combination of the Follow-up Shot infusion and Dual Kinetic Control utility wild talent with Telekinetic Blast use a total of 4 projectiles?

Does the combination of the Follow-up Shot infusion and Dual Kinetic Control utility wild talent with Telekinetic Blast use a total of 4 projectiles, and does the projectiles affect the same initial target or can target another creature?

Find the starting indices of all occurrences of the pattern in the string – KMP algorithm follow-up

The task

was initially solved here, but was too buggy:

Given a string and a pattern, find the starting indices of all occurrences of the pattern in the string. For example, given the string “abracadabra” and the pattern “abr”, you should return [0, 7].

My solution

Tried to solve it using KMP-algorithm:

function findStartingIndex(T, pattern) {   if (pattern.length > T.length) { return []; }    let next = 0;   const res = [];    const check = i => {     for (let j = 1; j < pattern.length; j++) {       if (next <= i && T[i + j] === pattern[0]) { next = i + j - 1; }       if (T[i + j] !== pattern[j]) { return false; }     }     if (next <= i) { next = i + pattern.length - 1; }     return true;   };    for (let i = 0; i < T.length; i++) {     if (i + pattern.length > T.length) { return res; }     if (T[i] === pattern[0] && check(i)) { res.push(i); }     i = next;   }   return res; } 

Singly-linked queue in PHP 7 – follow-up

I have improved this post. Now I have this:

<?php  class QueueNode {      function __construct($  item) {         $  this->item = $  item;         $  this->next = null;     }      function __destruct() {         $  this->item = null;     }      function getItem() {         return $  this->item;     }     }  class QueueIterator implements Iterator {      function __construct($  queue) {         $  this->queue = $  queue;         $  this->current_node = $  queue->head;     }      public function current() {         return $  this->current_node->item;     }      public function key(): \scalar {         return null;     }      public function next(): void {         $  this->current_node = $  this->current_node->next;     }      public function rewind(): void {         $  this->current_node = $  this->queue->head;     }      public function valid(): bool {         return isset($  this->current_node);     } }  class Queue implements IteratorAggregate {      function __construct() {         $  this->head = null;         $  this->tail = null;         $  this->size = 0;     }      function __destruct() {         $  this->head = null;         $  this->tail = null;     }      function push($  item) {         if ($  this->size === 0) {             $  this->head = $  this->tail = new QueueNode($  item);         } else {             $  new_node = new QueueNode($  item);             $  this->tail->next = $  new_node;             $  this->tail = $  new_node;         }          $  this->size++;     }      function pop() {         if ($  this->size === 0) {             throw new Exception("Popping from an empty queue.");         }          $  ret = $  this->head->getItem();         $  this->head = $  this->head->next;          if (--$  this->size == 0) {             $  this->head = $  this->tail = null;         }          return $  ret;     }      function getFirst() {         if  ($  this->size() === 0) {             throw new Exception("getFirst() on empty Queue.");         }          return $  this->head->getItem();     }      function getLast() {         if ($  this->size() === 0) {             throw new Exception("getLast() on empty Queue.");         }          return $  this->tail->getItem();     }      function size() {         return $  this->size;     }      function isEmpty() {         return size() === 0;     }      public function getIterator(): \Traversable {         return new QueueIterator($  this);     } }  $  queue = new Queue();  for ($  i = 1; $  i <= 10; $  i++) {     $  queue->push($  i); }  echo "Iteration: ";  foreach ($  queue as $  item) {     echo $  item . " "; }  echo "<br>Popping: ";  for ($  i = 1; $  i <= 10; $  i++) {     echo $  queue->getFirst() . ", " . $  queue->pop() . " "; }  echo "<br>Bye!"; ?> 

Output

Iteration: 1 2 3 4 5 6 7 8 9 10  Popping: 1, 1 2, 2 3, 3 4, 4 5, 5 6, 6 7, 7 8, 8 9, 9 10, 10  Bye! 

As always, any critique is much appreciated!

How does Heat Metal interact with a follow-up Frostbite?

Are there any rules around spells nullifying each other? For example, I cast heat metal on a target’s armour in round 1. In round 2, I use a bonus action to make the target take the burning damage again, and cast frostbite on the target.

Does the frostbite damage and effect have any adverse effect on the heat metal spell or vice versa?

Breadth-first search in Java: Competitive style – follow-up

I have improved my BFS in Java according to vnp’s suggestions. Again, we wish to find shortest paths in directed unweighted graphs using BFS, competitive style (no Maps, Set‘s or Lists):

import java.util.Arrays;  class BFS {      static int[] bfs(int[][] graph, int sourceNode, int targetNode) {         int[] queue = new int[graph.length];         int[] parents = new int[graph.length];          for (int i = 0; i < parents.length; i++) {             parents[i] = -1; // -1 denotes 'not used'         }          int queueStartIndex = 0;         int queueEndIndex = 1;          queue[0] = sourceNode;         parents[sourceNode] = -2;          while (queueStartIndex < queueEndIndex) {             int currentNode = queue[queueStartIndex++];              if (currentNode == targetNode) {                 return buildPath(targetNode, parents);             }              for (int childNode : graph[currentNode]) {                 if (parents[childNode] == -1) {                     parents[childNode] = currentNode;                     queue[queueEndIndex++] = childNode;                 }             }         }          return null;     }      private static int[] buildPath(int targetNode, int[] parents) {         int pathLength = 0;         int node = targetNode;          while (node >= 0) {             pathLength++;             node = parents[node];         }          int[] path = new int[pathLength];         int pathIndex = path.length - 1;         int currentNode = targetNode;          while (currentNode >= 0) {             path[pathIndex--] = currentNode;             currentNode = parents[currentNode];         }          return path;     }      /*    B ----+          /      |         A       E          \      /           C - D     */      public static void main(String[] args) {         int a = 0;         int b = 1;         int c = 2;         int d = 3;         int e = 4;          int[][] graph = new int[5][];         graph[a] = new int[]{ c, b };         graph[b] = new int[]{ e };         graph[c] = new int[]{ d };         graph[d] = new int[]{ c, e };         graph[e] = new int[]{ b, d };          // A -> B -> E         int[] path = bfs(graph, a, e);         System.out.println(Arrays.toString(path));          // A <- B <- E does not exist:         System.out.println(Arrays.toString(bfs(graph, e, a)));          graph = new int[4][];         graph[a] = new int[]{ b, c };         graph[b] = new int[]{ d };         graph[c] = new int[]{ a, d };         graph[d] = new int[]{ b, c };          /*     B               / \              A   D               \ /                C         */          // A -> B -> D         path = bfs(graph, a, d);         System.out.println(Arrays.toString(path));          path = bfs(graph, d, a);         // D -> C -> A:         System.out.println(Arrays.toString(path));     }     } 

Please tell me anything that comes to mind.

GUI Button Element with Unit Tests follow-up

This is my second attempt with unit-tests. Like my previous attempt, I would prefer a focus on the unit-tests, however I am always happy to improve my code in any way reviewers can help.

Once again it is just a single class along with supporting unit-tests. The class is named UpgradeButton and represents upgrades that the user can purchase in the game.

The button still looks like this:

Rectangle button with mouse over it and a green and red indicator

The boxes along the bottom are updated programatically through the input() and update() functions that indicate what level you are at and what you can purchase. The number of tiers is assigned in the constructor, as is the label.

Expressions.h is just a header of constexpr for replacing magic numbers, and as you can see I am using SFML. Version 2.4.2 if it matters. I’d also like to point out that I am aware of the difference between #pragma once and include guards. I chose the former because they are less verbose and supported by the major compilers. Lastly, it is a small personal project, completely in my control.

UpgradeButton.h

#pragma once  #include "Expressions.h"  #include <Graphics.hpp>  #include <string>  namespace fleet {     class UpgradeButton : public sf::Drawable {     public:         explicit UpgradeButton(const std::string& newLabel, const sf::Font& font, unsigned short numUpgrades);          void setPosition(float x, float y);         void setPosition(const sf::Vector2f& position);         void setLabelString(const std::string& string);         void setCharacterSize(unsigned newSize);         void setTextFillColor(const sf::Color& color);          const sf::Vector2f& getPosition() const { return button.getPosition(); }         const sf::String& getLabelString() const { return label.getString(); }         unsigned getCharacterSize() const { return label.getCharacterSize(); }         const sf::Color& getTextFillColor() const { return label.getFillColor(); }         const std::vector<sf::RectangleShape>& getIndicators() const { return indicators; }          bool input(const sf::Vector2f& mousePos, bool canAfford);         void update(const sf::Vector2f& mousePos, unsigned currentLevel, bool canAfford);     private:         sf::RectangleShape button{ sf::Vector2f(default_upgrade_width, default_upgrade_height) };         sf::Text label;         std::vector<sf::RectangleShape> indicators;          void draw(sf::RenderTarget& target, sf::RenderStates states) const override;     }; } 

UpgradeButton.cpp

#include "UpgradeButton.h"  #include "Exceptions.h"  namespace fleet {     UpgradeButton::UpgradeButton(const std::string& newLabel, const sf::Font& font, unsigned short numUpgrades) :         label{ newLabel, font }     {         if (numUpgrades == 0) {             throw DivideByZeroException("Attempted to divide by zero in the constructor of UpgradeButton");         }         float indicatorWidth = default_upgrade_width / numUpgrades;         for (unsigned i = 0; i < numUpgrades; ++i) {             indicators.emplace_back(sf::RectangleShape(sf::Vector2f(indicatorWidth, default_indicator_height)));         }          button.setFillColor(sf::Color::Cyan);         button.setOutlineThickness(upgrade_button_outline);         for (auto& indicator : indicators) {             indicator.setFillColor(sf::Color::Cyan);             indicator.setOutlineThickness(upgrade_button_outline);         }     }      // UpgradeButton requires one call to setPosition minimum to properly initialize indicators     // in there proper position. Failure to do so will leave them all positioned at 0, 0;     void UpgradeButton::setPosition(float x, float y)     {         button.setPosition(x, y);         float indicatorX = x;         float indicatorY = y + (default_upgrade_height - default_indicator_height);         for (auto& indicator : indicators) {             indicator.setPosition(indicatorX, indicatorY);             indicatorX += indicator.getSize().x;         }         float labelY = y + default_upgrade_height + upgrade_label_y_offset;         label.setPosition(x, labelY);     }     void UpgradeButton::setPosition(const sf::Vector2f& position)     {         setPosition(position.x, position.y);     }     void UpgradeButton::setLabelString(const std::string& string)     {         label.setString(string);     }     void UpgradeButton::setCharacterSize(unsigned newSize)     {         label.setCharacterSize(newSize);     }     void UpgradeButton::setTextFillColor(const sf::Color& color)     {         label.setFillColor(color);     }      bool UpgradeButton::input(const sf::Vector2f& mousePos, bool canAfford)     {         return canAfford && button.getGlobalBounds().contains(mousePos);     }     void UpgradeButton::update(const sf::Vector2f& mousePos, unsigned currentLevel, bool canAfford)     {         for (unsigned i = 0; i < currentLevel && i < indicators.size(); ++i) {             indicators[i].setFillColor(sf::Color::Green);         }         for (unsigned i = currentLevel; i < indicators.size(); ++i) {             indicators[i].setFillColor(sf::Color::Cyan);         }          if (currentLevel >= indicators.size()) { return; }          if (button.getGlobalBounds().contains(mousePos)) {             if (canAfford) {                 indicators[currentLevel].setFillColor(sf::Color::Green);             }             else {                 indicators[currentLevel].setFillColor(sf::Color::Red);             }         }         else {             indicators[currentLevel].setFillColor(sf::Color::Cyan);         }     }      void UpgradeButton::draw(sf::RenderTarget& target, sf::RenderStates states) const     {         target.draw(button, states);         for (auto& indicator : indicators) {             target.draw(indicator, states);         }         target.draw(label, states);     } } 

As for the tests. I am using Google Test. I got rid of the tests of primitive setter methods. They always felt exceedingly trivial. I tried to recognize the assumptions I make in my code and then test for it, but I have found that isn’t as easy as it sounds. There are currently nine tests, and they all pass.

UpgradeButtonTests.cpp

#include "gtest/gtest.h"  #include "UpgradeButton.h"  #include "Exceptions.h" #include "Expressions.h"  #include <Graphics.hpp>  namespace fleet {     class UpgradeButtonTest : public testing::Test {     protected:         UpgradeButton* button;     };      TEST_F(UpgradeButtonTest, constructor_accepts_empty_string) {         button = new UpgradeButton("", sf::Font(), 5);         ASSERT_STREQ("", button->getLabelString().toAnsiString().c_str());         delete button;     }      TEST_F(UpgradeButtonTest, constructor_handles_large_strings) {         std::string longString = "This is a very long string to test that the constructor of the \             UpgradeButton class properly handles very long strings.";         button = new UpgradeButton(longString, sf::Font(), 5);         ASSERT_EQ(longString, button->getLabelString());     }      TEST_F(UpgradeButtonTest, constructor_fails_on_zero) {         ASSERT_THROW(button = new UpgradeButton("Test String", sf::Font(), 0), DivideByZeroException);     }      TEST_F(UpgradeButtonTest, text_is_white_on_contruction) {         button = new UpgradeButton("Test String", sf::Font(), 5);         ASSERT_EQ(sf::Color::White, button->getTextFillColor());     }      TEST_F(UpgradeButtonTest, indicators_stacked_at_origin_point_on_construction) {         button = new UpgradeButton("Test String", sf::Font(), 5);         for (auto& indicator : button->getIndicators())         {             ASSERT_EQ(sf::Vector2f(), indicator.getPosition());         }     }      TEST_F(UpgradeButtonTest, setPosition_sets_indicators_correctly) {         unsigned short numIndicators = 5;         button = new UpgradeButton("Test String", sf::Font(), numIndicators);         sf::Vector2f position(5.F, 5.F);         button->setPosition(position);         float indicatorX = position.x;         float indicatorY = position.y + (default_upgrade_height - default_indicator_height);         for (auto& indicator : button->getIndicators()) {             ASSERT_FLOAT_EQ(indicatorX, indicator.getPosition().x);             ASSERT_FLOAT_EQ(indicatorY, indicator.getPosition().y);             indicatorX += indicator.getSize().x;         }           position = sf::Vector2f(indicatorX, indicatorY);         button->setPosition(position);         indicatorY = position.y + (default_upgrade_height - default_indicator_height);         for (auto& indicator : button->getIndicators()) {             ASSERT_FLOAT_EQ(indicatorX, indicator.getPosition().x);             ASSERT_FLOAT_EQ(indicatorY, indicator.getPosition().y);             indicatorX += indicator.getSize().x;         }     }      TEST_F(UpgradeButtonTest, input) {         button = new UpgradeButton("Test String", sf::Font(), 5);         ASSERT_TRUE(button->input(sf::Vector2f(), true));         ASSERT_FALSE(button->input(sf::Vector2f(), false));         ASSERT_FALSE(button->input(sf::Vector2f(500.F, 900.F), true));         ASSERT_FALSE(button->input(sf::Vector2f(500.F, 900.F), false));     }      TEST_F(UpgradeButtonTest, update_does_not_fail_out_of_range) {         unsigned short numIndicators = 5;         button = new UpgradeButton("Test String", sf::Font(), numIndicators);         numIndicators += 7;         ASSERT_NO_THROW(button->update(sf::Vector2f(), numIndicators, true));     }      TEST_F(UpgradeButtonTest, update_handles_mousePos_correctly) {         unsigned short numIndicators = 5;         button = new UpgradeButton("Test String", sf::Font(), numIndicators);         button->update(sf::Vector2f(-10.F, -10.F), 0, true);         for (auto& indicator : button->getIndicators()) {             ASSERT_EQ(sf::Color::Cyan, indicator.getFillColor());         }         button->update(sf::Vector2f(), 0, true);         ASSERT_EQ(sf::Color::Green, button->getIndicators()[0].getFillColor());     } } 

“First Python program: Tic-Tac-Toe (Followup)

This is the new code, I am unsure if I made the suggestions the the suggestion intended on my previous post First Python program: Tic-Tac-Toe. I have only been working on programming for about 3 weeks so anymore suggestions or insight on the original post of the suggestions would be more than welcomed.

”’python 3.7.4”’

import sys from textwrap import dedent import os import random  os.system('CLS')  # board number setup board = [0, 1, 2,          3, 4, 5,          6, 7, 8]   # Defines the board layout printed to the console def board_layout():     print(dedent(f'''      *************     * {board[0]} | {board[1]} | {board[2]} *     *-----------*     * {board[3]} | {board[4]} | {board[5]} *     *-----------*     * {board[6]} | {board[7]} | {board[8]} *     *************     '''))   def main():     players = ('Player','NPC')     turn = 'Player'     change_turn = 0     for moves in range(9):         if turn == 'Player':                while True:                 try:                     board_layout()                     player_move = int(input('Please select a spot: '))                     if board[player_move] != 'x' and board[player_move] != 'o':                         board[player_move] = 'x'                         check_winner()                         break                 except IndexError:                     print('please select valid spot')         if turn == 'NPC':              # npc move, chooses a random spot that is not taken              while True:                 npc = random.randint(0, 8)                 if board[npc] != 'o' and board[npc] != 'x':                     board[npc] = 'o'                     print('Computer chooses spot ', npc)                     check_winner()                     break           try:             change_turn += 1             turn = players[change_turn]         except:             change_turn = 0             turn = players[change_turn]     else:        print('You Tied')        end()             def end():         print('Thank you for playing')         answer = input('Would you like to play again?: Y/N')          if answer.lower() == 'n':             quit()         elif answer.lower() == 'y':                     clear_board()                     main()         else:             print('Please choose a valid option')             end()  def clear_board():     for i in range(9):         board[i] = i  # checks for a winner when called at end of each turn         def check_winner():              # list of lists with all the winning combinations for from the tic tac toe board             winning_list = [[board[0], board[1], board[2]], [board[3], board[4], board[5], ],                             [board[6], board[7], board[8]], [board[0], board[4], board[8]],                             [board[2], board[4], board[6]],                             [board[0], board[3], board[6]], [board[1], board[4], board[7]],                             [board[2], board[5], board[8]]]              # iterates over the lists in winning_list             for i, j, k in winning_list:                 # looks at the lists in winning_list to determine if a list has all x's for a win                 if i == 'x' and j == 'x' and k == 'x':                     print('X wins')                     end()                 # looks at the lists in winning_list to determine if a list has all o's for a win                 elif i == 'o' and j == 'o' and k == 'o':                     print('O wins')                     end()   if __name__ == "__main__":     main() 

How to follow-up with updated versions of homebrew content?

Disclaimer. I’m not sure whether this question should be asked in this stack, or in the meta (or somewhere else). I’ll ask it here since for me it relates to designing content for RPGs specifically.

I’ve been noticing questions and answers regarding homebrew content offer a lot of insight in understanding and designing features for the games I play (as GM and PC), like this recent one: How might this homebrew undead hybrid character type unbalance combat compared to non-undead creatures?

After reading and incorporating feedback from the community, I’d like to share the result of the interaction. I’m thinking of two cases:

  • Case 1. Further tweaking of the content, as if it is a second round of iteration. This would be work-in-progress.

  • Case 2. Possibly inspiring (or getting inspired by) other people with similar questions and/or ideas. This would be a final result of the homebrew content.

How to follow-up with updated versions of homebrew content?

Let’s use the linked question as an example:

  1. Do I edit the question to include the updated content (like a next version, under the original version)?
  2. Do I ask an entirely new question with the updated content?
  3. Do I use another feature of this platform (of which I’m yet unaware)?
  4. Or is this platform actually not suited for such feedback cycles and iterative design?

Ideally an answer to my question covers both cases and shows me relevant policies (or etiquette) when dealing with iterative design of homebrew content on this platform. I’m not interested in opinions on the matter.