static long queryRangeSum(int currNode, int tSI, int tEI, int rSI, int rEI) { Node temp = tree[currNode]; /* System.out.println("Q-----currNode : " + currNode + ", tSI : " + tSI + ", tEI : " + tEI + ", tree[cN].sum : " + tree[currNode].sum);*/ if (temp.init != -1) { // System.out.println("currNode : " + currNode + ", in init"); temp.sum = ((tEI - tSI + 1) * temp.init); temp.sum %= mod; if (tSI != tEI) { tree[2 * currNode].init = temp.init; tree[2 * currNode + 1].init = temp.init; } temp.init = -1; temp.add = 0; temp.mul = 0; } else { temp.sum = (temp.sum * temp.mul) + ((tEI - tSI + 1) * temp.add); temp.sum %= mod; if (tSI != tEI) { tree[2 * currNode].add += temp.add; tree[2 * currNode].add %= mod; tree[2 * currNode].mul *= temp.mul; tree[2 * currNode].mul %= mod; tree[2 * currNode + 1].add += temp.add; tree[2 * currNode + 1].add %= mod; tree[2 * currNode + 1].mul *= temp.mul; tree[2 * currNode + 1].mul %= mod; } temp.add = 0; temp.mul = 1; } if (tSI > tEI || tSI > rEI || tEI < rSI) return -1; if (tSI >= rSI && tEI <= rEI) return temp.sum; int mid = (tSI + tEI) / 2; long lCS, rCS; lCS = queryRangeSum(2 * currNode, tSI, mid, rSI, rEI); rCS = queryRangeSum(2 * currNode + 1, mid + 1, tEI, rSI, rEI); if (lCS == -1) lCS = 0; if (rCS == -1) rCS = 0; tree[currNode].sum = tree[2 * currNode].sum + tree[2 * currNode + 1].sum; tree[currNode].sum %= mod; return (lCS + rCS) % mod; }

Main init() { // Create a chart to monitor the infection progress rate final XYLineChart chart = new XYLineChart("Infection Rate", 5.0, "Infected Nodes (%)", "time(s)"); chart.setYRange(false, 0, 100); chart.setSeriesLinesAndShapes("s0", true, true); Gui.setFrameRectangle("MainFrame", 0, 0, 480, 480); Gui.setFrameRectangle("Infection Rate", 484, 0, 480, 480); // Create the simulation nodes for (int i = 0; i < TOTAL_NODES; i++) new Node(); // Initialize the simulation nodes for (Node i : NodeDB.nodes()) i.init(); NodeDB.randomNode().infect(); // Sets up a periodic task that, at one second intervals, computes and shows the percentage of // infected nodes in the system // Stops the simulation when it detects that every node is infected... new PeriodicTask(1.0) { public void run() { double T = 0, N = 0; for (Node n : NodeDB.nodes()) { if (n.infected) T++; N++; } chart.getSeries("s0").add(Simulation.currentTime(), 100.0 * T / N); if (N == T) stop(); }; }; // From time to time, select a random node to go fail and go offline... new Task(0) { public void run() { NodeDB.randomNode().crash(); reSchedule(0.5 + 0.5 * rg.nextDouble()); // schedules a new execution of this task... } }; // From time to time, create a new node. If the rate of births and deaths is the same, // the size of the system should stay constant on average. new Task(0) { public void run() { new Node().init(); reSchedule(0.5 + 0.5 * rg.nextDouble()); // schedules a new execution of this task... } }; super.setSimulationMaxTimeWarp(2.0); return this; }

/** * A* pathfinding algorithm * * @param grid the grid to be used for pathfinding * @param x target x coordinate in grid form * @param y target y coordinate in grid form * @return The next move to make for the ghost */ public Node pathFind(Grid grid, int x, int y) { // Set target x, y Node.tx = x; Node.ty = y; Node current = null, temp; int block; PriorityQueue<Node> opened = new PriorityQueue<Node>(); HashSet<Node> closed = new HashSet<Node>(); temp = new Node( this.x / Board.BLOCKSIZE, this.y / Board.BLOCKSIZE, 0); // current location of ghost temp.init(); temp.setDir(dx, dy); opened.offer(temp); while (!opened.isEmpty()) { current = opened.poll(); // get best node closed.add(current); // add node to closed set (visited) if (current.hCost == 0) // if future cost is 0, then it is target node break; block = grid.screenData[current.y][current.x]; // If can move, not abrupt, and unvisited, add to opened if ((block & 1) == 0 && current.dir != 3) // Can move and not abrupt { temp = current.getChild(-1, 0); // get child node if (!closed.contains(temp)) // Unvisited opened.add(temp); } if ((block & 2) == 0 && current.dir != 4) { temp = current.getChild(0, -1); if (!closed.contains(temp)) opened.add(temp); } if ((block & 4) == 0 && current.dir != 1) { temp = current.getChild(1, 0); if (!closed.contains(temp)) opened.add(temp); } if ((block & 8) == 0 && current.dir != 2) { temp = current.getChild(0, 1); if (!closed.contains(temp)) opened.add(temp); } } // if current.parent == null, then ghost is on pacman. Handle it by moving randomly // current.parent.parent == null, then current is best next move while (current.parent != null && current.parent.parent != null) current = current.parent; return current; }

public void start() { nodes.addAll(readNodes); nodes.addAll(taskNodes); nodes.addAll(writerNodes); for (Node node : nodes) { node.init(); node.pre(); } for (ReadNode readNode : readNodes) { readNode.start(); } }

/** * Obtain a new Node randomly chosen from the given list. The Node is cloned and initialized, so * it can be used separatedly * * @param l The list of Nodes from which to choose * @param currentGlobalDepth The depth of the requested Node in the Tree */ public Node newRandomNode(List<Node> l, int currentGlobalDepth) { int which = Common.globalRandom.nextInt(l.size()); Node outNode = null; try { outNode = (Node) l.get(which).clone(); } /* This should never happen, as nodes do support cloning, so it's ok * to catch this exception here */ catch (CloneNotSupportedException e) { Logger.log(e); } outNode.init(config, problemData); outNode.setCurrentDepth(currentGlobalDepth); return outNode; }

static Node alloc() { final int threshold = 2; int tryCnt = 0; while (true) { tryCnt++; Node n = pool.poll(); if (n == null) { return new Node(); } else { if (n.getRefCnt() > 0) { pool.add(n); if (tryCnt <= threshold) continue; else return new Node(); } else { if (n.next != null) n.next.decRefCnt(); n.init(); return n; } } } }

/** * Inits this renderable node * * @param gl */ @Override public void init(GL gl) { if (renderTarget != null) renderTarget.init(gl); super.init(gl); }

static void initializeRange(int currNode, int tSI, int tEI, int rSI, int rEI, long initValue) { Node temp = tree[currNode]; if (temp.init != -1) { temp.sum = ((tEI - tSI + 1) * temp.init); temp.sum %= mod; if (tSI != tEI) { tree[2 * currNode].init = temp.init; tree[2 * currNode + 1].init = temp.init; } temp.init = -1; temp.add = 0; temp.mul = 1; } else if (temp.add > 0 || temp.mul > 1) { temp.sum = temp.sum * temp.mul + ((tEI - tSI + 1) * temp.add); temp.sum %= mod; if (tSI != tEI) { tree[2 * currNode].add += temp.add; tree[2 * currNode].add %= mod; tree[2 * currNode + 1].add += temp.add; tree[2 * currNode + 1].add %= mod; tree[2 * currNode].mul *= temp.mul; tree[2 * currNode].mul %= mod; tree[2 * currNode + 1].mul *= temp.mul; tree[2 * currNode + 1].mul %= mod; } temp.init = -1; temp.add = 0; temp.mul = 1; } /* System.out.println("INIT cN : " + currNode + ", tSI : " + tSI + ", tEI : " + tEI + ", rSI : " + rSI + ", rEI : " + rEI);*/ if (tSI > tEI || tSI > rEI || tEI < rSI) return; if (tSI >= rSI && tEI <= rEI) { temp.sum = (tEI - tSI + 1) * initValue; temp.sum %= mod; if (tSI != tEI) { tree[2 * currNode].init = initValue; tree[2 * currNode + 1].init = initValue; } temp.add = 0; temp.mul = 1; return; } int mid = (tSI + tEI) / 2; initializeRange(2 * currNode, tSI, mid, rSI, rEI, initValue); initializeRange(2 * currNode + 1, mid + 1, tEI, rSI, rEI, initValue); tree[currNode].sum = tree[2 * currNode].sum + tree[2 * currNode + 1].sum; tree[currNode].sum %= mod; }