2019年3月29日金曜日

Explore Simple Game Algorithms With Color Walk: Part 10

We're back for another round of exploring game algorithms using the simple game Color Walk. We finally reached the point of evaluating Dijkstra's algorithm—the classic, efficient graph algorithm for finding shortest paths—in the last post. It performed pretty well against the top dogs: Greedy Look-Ahead (GLA) and the GLA-BFS hybrid, especially when it came to consistently finding the best moves. However, it failed to find the best moves when a board could be solved in under 29 moves, so we're going to see if we can squeeze out any more performance by modifying Dijkstra's algorithm further. To do that, we're going to try combining Dijkstra's algorithm with GLA, running Dijkstra's algorithm in more than one pass, and changing the heuristic we use to guide the search.

Dijkstra and an Assist


We saw in the last post that we couldn't use Dijkstra's algorithm in its purest form because that would still require searching the entire move graph to find the true shortest path from the source vertex (the start-of-game) to the sink vertex (the end-of-game). In fact, Dijkstra's algorithm, when run to completion, will find the shortest path from the source vertex to every other vertex in the graph. Since the move graph is actually a tree, we don't care what the shortest path is to most of the vertices, save one, the end-of-game vertex. Because of that restriction, we restricted the algorithm to only search until the end-of-game vertex was found, and then try to balance the search heuristic so that we reached that vertex on as short of a path as possible.

This tactic of using a heuristic search and stopping once a goal is reached is actually a variant of Dijkstra's algorithm by another name, called A* search. This algorithm is a popular way to do path finding in games where computer-controlled characters are moving around in a 2D or 3D space. The natural heuristic in that application is the straight-line distance from the current position of the character to the target position, and A* search is pretty effective at this task.

In using a heuristic for the Color Walk move graph search, we have given up the guarantee of finding the true shortest path because the heuristic is not perfect, but we gain a huge benefit in efficiency and tractability. Without the heuristic, the search would go on forever (or at least until it ran out of memory) in such a large graph. Even with the current performance of the algorithm, we want to try to tighten up the heuristic to find a shorter path, but to do that, we want to do something to shrink the size of the graph that it needs to search. To do that, we can add in our old friend GLA to make fast headway into the move graph before switching to Dijkstra's algorithm.

Adding this hybrid GLA-Dijkstra's algorithm is straightforward. We start with the normal task of adding the algorithm to the list of choices in the algorithm pull-down list and to the switch statement that lives behind the list:
  function Solver() {
// ...

this.init = function() {
// ...

$('#solver_type').change(function () {
switch (this.value) {
// ...
case 'greedy-dijkstra':
that.solverType = that.dijkstraWithGla;
that.metric = areaCount;
break;
default:
that.solverType = that.roundRobin;
break;
}

// ...
});

// ...
};
}
The implementation of the hybrid algorithm is about as simple as the other hybrid algorithms:
    this.dijkstraWithGla = function() {
if (moves < 15) this.greedyLookAhead();
else this.dijkstra();
}
It seemed like running GLA for 15 moves was reasonable, considering most boards are not solved in less than 30 moves, and then Dijkstra's algorithm is run to the end-of-game condition. Now we have a problem, though. We have two knobs to turn—one for the maximum number of moves to look ahead in GLA and one for the scale factor used in Dijkstra's algorithm, but only one text box in the UI. (Another knob would be the number of moves to run GLA for, but we'll just keep that at 15 to reduce the number of combinations to look at.) We'll want to separate those two knobs out by adding another text box for the scale factor to the UI. Let's call it solver_scale_factor and add it as another parameter in the code:
  function Solver() {
var that = this;
var iterations = 0;
var max_moves = 2;
var scale_factor = 25;
var time = 0;
var start_time = 0;

this.index = 0;
this.metric = nullMetric;

this.init = function() {
this.solver = $('<div>', {
id: 'solver',
class: 'control btn',
style: 'background-color:' + colors[this.index]
}).on('click', function (e) {
max_moves = $('#solver_max_moves').val();
scale_factor = $('#solver_scale_factor').val();
that.runAlgorithm();
}).appendTo('#solver_container');

// ...

$('#solver_play').on('click', function (e) {
_block_inspect_counter = 0;
_block_filter_counter = 0;
iterations = $('#solver_iterations').val();
max_moves = $('#solver_max_moves').val();
scale_factor = $('#solver_scale_factor').val();
start_time = performance.now();
time = start_time;
that.run();
});
};

// ...

function addVertices(vertices, depth, prev_control, prev_cleared) {
var stop = false;
_.each(controls, function (control) {
if (control !== prev_control && !stop) {
var removed_blocks = control.checkGameBoard(depth, markedBlockCount);
if (endOfGame()) {
doMarkedMoves();
vertices.clear();
stop = true;
} else if (removed_blocks - prev_cleared > 0) {
var markers_dup = markers.slice();
var cost = scale_factor*depth - removed_blocks;
if (removed_blocks > 590 ||
removed_blocks > 560 && vertices.length > 200000) {
cost -= (scale_factor - 5)*depth;
}
vertices.queue({markers: markers_dup,
depth: depth,
control: control,
cost: cost,
cleared: removed_blocks});
}
}
});

return vertices;
}
Inside addVertices() we simply replace max_moves with the new parameter scale_factor. Now we can independently control both parameters and more easily explore variations on this hybrid algorithm. After much experimentation with the max moves in the range of 4-7 and the scale factor in the range of 25-30 using ten iterations, I found that a max moves of 7 and a scale factor of 28 performed well. Then, running for 100 iterations produced the following results.

Color Walk results for 100 iterations of GLA-Dijkstra hybrid

This is quite good performance, meeting or exceeding the best algorithms in every metric except for the standard deviation as compared to Dijkstra's algorithm alone. But Dijkstra's algorithm didn't do as well on the min, mean, or max statistics, so in absolute terms the hybrid algorithm found better move sequences for nearly every board.

Before looking at the table of algorithm performance, let's add in another quick algorithm by reversing GLA and Dijkstra's algorithm to create the Dijkstra-GLA hybrid algorithm. We can add it to the algorithm list:
  function Solver() {
// ...

this.init = function() {
// ...

$('#solver_type').change(function () {
switch (this.value) {
// ...
case 'dijkstra-greedy':
that.solverType = that.glaWithDijkstra;
that.metric = areaCount;
break;
default:
that.solverType = that.roundRobin;
break;
}

// ...
});

// ...
};
}
And add another simple algorithm function that calls both of the base algorithms in the hybrid algorithm:
    this.glaWithDijkstra = function() {
if (moves < 5) this.dijkstra(300);
else this.greedyLookAhead();
}
Notice that the call to Dijkstra's algorithm now includes an argument of 300. This argument is the number of blocks that should be cleared before Dijkstra's algorithm stops. It's pretty easy to limit the algorithm by adding a condition to the if statement where the algorithm is stopped before it runs out of memory:
    this.dijkstra = function(blocks_to_clear = 600) {
var vertices = new PriorityQueue({ comparator: function(a, b) { return a.cost - b.cost } });
vertices = addVertices(vertices, 1, null, blocks[0].cluster.blocks.length);
this.max_depth = 0;
while (vertices.length > 0) {
var vertex = vertices.dequeue();
markers = null;
markers = vertex.markers;

if (vertices.length > 250000 ||
vertex.cleared >= blocks_to_clear) {
doMarkedMoves();
vertices.clear();
} else {
vertices = addVertices(vertices, vertex.depth + 1, vertex.control, vertex.cleared);
}

vertex.markers = null;
}
this.index = null;
}
By the default parameter, all blocks are cleared when the algorithm is run so the other two calls to dijkstra() still work like they did before. For this run the max moves was still set at 7, but the scale factor had to be rolled back to 25, like it was for Dijkstra's algorithm alone because otherwise it would stall on some boards. The performance of this hybrid algorithm comes out surprisingly worse:

Color Walk run with Dijkstra-GLA algorithm of 100 iterations

I didn't expect that just swapping the order of the two algorithms would have such a marked difference in performance. The slightly smaller scale factor doesn't account for the difference, either, because if it's set to 28, as it was in the GLA-Dijkstra algorithm, the performance is even worse. Let's look at how these two hybrid algorithms stack up to the rest of the algorithms we've looked at so far:

AlgorithmMinMeanMaxStdev
RR with Skipping 37 46.9 59 4.1
Random with Skipping 43 53.1 64 4.5
Greedy 31 39.8 48 3.5
Greedy Look-Ahead-2 28 37.0 45 3.1
Greedy Look-Ahead-5 25 33.1 41 2.8
Max Perimeter 29 37.4 44 3.2
Max Perimeter Look-Ahead-2 27 35.0 44 2.8
Perimeter-Area Hybrid 31 39.0 49 3.8
Deep-Path 51 74.8 104 9.4
Path-Area Hybrid 35 44.2 54 3.5
Path-Area Hybrid Look-Ahead-4 32 38.7 45 2.7
BFS with Greedy Look-Ahead-5 26 32.7 40 2.8
DFS with Greedy Look-Ahead-5 25 34.8 43 3.9
Dijkstra's Algorithm 29 33.1 40 1.9
GLA-Dijkstra Hybrid 25 31.8 37 2.2
Dijkstra-GLA Hybrid 28 36.3 44 3.1

While the GLA-Dijkstra hybrid performs better than any other algorithm we've seen so far, and seems to combine all of the best characteristics of its constituent algorithms, Dijkstra-GLA doesn't even perform as well as Dijkstra's algorithm alone. It's more on the level of the max perimeter heuristic, which is decidedly middle-of-the-road as far as these algorithms go. Looking at the boards from a high level, this disparity makes some sense. It looks like at the beginning of a game it's more important to figure out how to remove as many blocks as possible on each move. As the game progresses and gets closer to the end, where the graph search algorithms can "see" more easily to the end of the game, their ability to find the shortest path becomes more effective, and that benefit is especially true for Dijkstra's algorithm because it's more efficient than the other graph search algorithms. Swapping Dijkstra's algorithm and GLA ends up crippling both of them.

Self-Assist


A curious idea comes out of these hybrid algorithms by thinking about the difference between Dijkstra's algorithm and GLA. GLA operates on a per move basis, meaning for each move under consideration, the algorithm looks some number of moves ahead and then commits to a move before going on to consider the next move. If we string one GLA algorithm together with another GLA, it wouldn't look any different than running GLA all the way through in one pass.

In contrast, Dijkstra's algorithm looks as far forward as it's allowed to try to find the shortest path to the end-of-game condition, and once a path is found, it does all of the moves in that path at once. If we string Dijkstra's algorithm together with another Dijkstra's algorithm, running the first one to the halfway point, it looks different than running Dijkstra's algorithm once for the entire board. The combination of the first run to the halfway point and the second run to the end may find quite a different path than a single run does. It should also run faster because the paths it needs to search are shorter by half. Let's give this idea a try by running Dijkstra's algorithm with itself. First, we add the new hybrid algorithm to the list of choices again:
  function Solver() {
// ...

this.init = function() {
// ...

$('#solver_type').change(function () {
switch (this.value) {
// ...
case 'dijkstra-dijkstra':
that.solverType = that.dijkstraDijkstra;
that.metric = areaCount;
break;
default:
that.solverType = that.roundRobin;
break;
}

// ...
});

// ...
};
}
And then we can simply call Dijkstra's algorithm twice for the implementation of dijkstraDijkstra() (it's so fun to say, isn't it?):
    this.dijkstraDijkstra = function() {
if (moves < 5) this.dijkstra(300);
else {
scale_factor = 28;
this.dijkstra();
}
}
The first call to dijkstra() specifies the number of blocks to remove to get to the halfway point. The second call changes the scale_factor to the optimal value for when Dijkstra's algorithm is run for the later moves, as we found in the GLA-Dijkstra algorithm. The scale_factor for the first run can be set through the UI, so we can experiment a little. We could add another UI element so that two scale factors could be specified, but this should demonstrate the idea without adding that complication. With this simple addition to the algorithms, we can see how it performs:

Color Walk run with Dijkstra-Dijkstra hybrid algorithm for 100 iterations

This version of the hybrid Dijkstra's algorithm performs better than Dijkstra-GLA, but worse than GLA-Dijkstra, adding more evidence to the idea that Dijkstra's algorithm does better in the second half of the game than the first half. The first run of Dijkstra's algorithm to remove 300 blocks probably does not do as well as GLA, but the second run does do better than GLA, giving this hybrid a performance result that lands it squarely in between the other two hybrid approaches.

An Assist from the Perimeter


One more option to explore for amping up Dijkstra's algorithm is using other heuristics with the GLA part of the hybrid algorithm. We've continued to use the heuristic of maximizing blocks removed with areaCount(), but we did look at a number of other options for heuristics. Even though they didn't improve over the super-strong area-maximizing heuristic, the other heuristics are potentially interesting for use in paring down the move graph before running Dijkstra's algorithm. They're quite easy to add to our list of algorithms, so let's look at one of them, the perimeterCount() heuristic for maximizing the cleared perimeter:
  function Solver() {
// ...

this.init = function() {
// ...

$('#solver_type').change(function () {
switch (this.value) {
// ...
case 'max-perimeter-dijkstra':
that.solverType = that.dijkstraWithGla;
that.metric = perimeterCount;
break;
default:
that.solverType = that.roundRobin;
break;
}

// ...
});

// ...
};
}
It's so simple that all we had to do was add another choice to the algorithm list and add another case to the switch statement that uses the dijkstraWithGla() algorithm and the perimeterCount() heuristic. Everything else is already available and ready to go. So how does it perform?

Color Walk run with Max-Perimeter-Dijkstra hybrid algorithm for 100 iterations

It looks like another decent algorithm—slightly better than Dijkstra's algorithm alone, but not quite as good as GLA-Dijkstra. Here's the updated table of all the algorithms tried so far:

AlgorithmMinMeanMaxStdev
RR with Skipping 37 46.9 59 4.1
Random with Skipping 43 53.1 64 4.5
Greedy 31 39.8 48 3.5
Greedy Look-Ahead-2 28 37.0 45 3.1
Greedy Look-Ahead-5 25 33.1 41 2.8
Max Perimeter 29 37.4 44 3.2
Max Perimeter Look-Ahead-2 27 35.0 44 2.8
Perimeter-Area Hybrid 31 39.0 49 3.8
Deep-Path 51 74.8 104 9.4
Path-Area Hybrid 35 44.2 54 3.5
Path-Area Hybrid Look-Ahead-4 32 38.7 45 2.7
BFS with Greedy Look-Ahead-5 26 32.7 40 2.8
DFS with Greedy Look-Ahead-5 25 34.8 43 3.9
Dijkstra's Algorithm 29 33.1 40 1.9
GLA-Dijkstra Hybrid 25 31.8 37 2.2
Dijkstra-GLA Hybrid 28 36.3 44 3.1
Max-Perimeter-Dijkstra Hybrid 27 32.8 38 2.3

We have built up quite a list of algorithms, with some of the best performing ones at the very end finally overcoming the surprisingly solid performance of one of the earlier algorithms, GLA-5. If we're looking only at average performance, the GLA-Dijkstra hybrid is the clear winner, with BFS+GLA-5 and Max-Perimeter-Dijkstra hybrid coming in second and third with an average of one extra move per game. However, that higher performance in number of moves comes at a cost. Those algorithms take significantly longer to search for their results than GLA-5 does. If we ordered these top four algorithms based on search speed, the order would be reversed to GLA-5, Max-Perimeter-Dijkstra hybrid, BFS+GLA-5, and GLA-Dijkstra hybrid. At the top of the leaderboard there is a clear trade-off between average performance and search time.

While we've looked at graph algorithms in general and Dijkstra's algorithm in particular fairly extensively now, one thing that was somewhat glossed over was the workings of the priority queue that is the key to making Dijkstra's algorithm work so well. Next time we'll take a closer look at this essential data structure and see how it enables Dijkstra's algorithm to quickly choose each vertex to look at next.


Article Index
Part 1: Introduction & Setup
Part 2: Tooling & Round-Robin
Part 3: Random & Skipping
Part 4: The Greedy Algorithm
Part 5: Greedy Look Ahead
Part 6: Heuristics & Hybrids
Part 7: Breadth-First Search
Part 8: Depth-First Search
Part 9: Dijkstra's Algorithm
Part 10: Dijkstra's Hybrids
Part 11: Priority Queues
Part 12: Summary

Ready To Roll

The latest addition to my convoy is now table ready.


The carts are surplus Irregular Miniatures that Rob passed to  me a couple of years ago. I replaced the wheels with Prince August ones for a more 18thC look and used PA draft horses.

I had thought of having the drivers walk along side but had never really noticed the scale difference, especially for the larger HE and new 7YW figures. The sight of a driver pointing across a draft horse's back made it look more like a draft pony. So I took late 19thC seated drivers from Zinnbrigade and Irregular, gave them new heads and painted them in waistcoats.

The loads are 1/35 sandbags and are removable as are the drivers.

Pack mules are next and anything else will just give me more options to choose from.

Star Realms Review

Star Realms is a Kickstarter project that ran in October, and went out to backers in December.  Personally, I almost didn't back it because that just seemed to wildly impossible.  But it arrived the day after Christmas, and I've played it constantly since it got here.

Star Realms is a sci-fi themed deck building game, most closely related to Ascension.  It was designed by Robert Dougherty and Darwin Kastle and published by White Wizard Games.  Robert Dougherty in specific put a lot of work into the Ascension series, which explains how closely related the two games feel.

Read more »

I Settle All Video Game Arguments, Part 1: Game Reviews

There was a ridiculous controversy recently because a games journo was bad at this difficult game. All time spent debating it was time wasted. I am writing this so that such time-wastage never happens again. I live to serve.
"You can speak your mind but not on my time."
      - William Martin Joel
 
One of the painful things about being in the games biz for a long (LONG) time is that you see the same tedious arguments brought up and rehashed, again and again, by new generations. I am writing a series of posts to settle these debates once and for all.

Don't bother to thank me. Seeing my own face whenever I look into the mirror is reward enough.

First up, I will settle all debates regarding games reviewers: How good should a reviewer be at a game? What topics are a reviewer allowed to bring up when doing a review? Are review scores and review aggregators a good thing? Does anyone still care about game reviews?

So the next time someone gets Mad On the Internet about a game review or mega-butthurt because the newest installment of their fave series gets a 91% when they KNOW it should have gotten a 93%, you can send them to this page and get on with your life.

A thoughtful and useful review of Avernum. Hmm. Let me check if it's still, 17 years later, making me money? Yep!!!
Why Are You Authorized to Settle This Argument Forever?

Because I am old, and that makes me wise. Also, once PC Gamer gave one of my most popular and enduring games a 17% review, literally said it was worse than choking to death on your own vomit, and provided a helpful sidebar with a list of rock stars who choked to death on their own vomit.

Believe me, every possible opinion you can have about game reviews, I have had at one time or another.

(Also, we have a kick-ass new indie, retro role-playing game coming out in early 2018, and I want to make sure everyone's heads are on straight before they start reviewing it.)

The Most Important Fact About Reviews

Think about your friends. (For the purpose of this exercise, I will assume you have friends.) When they recommend games/movies/TV shows to you, you take their personalities into account, right?

For example, there are some people who I listen to when they say a movie is good, and there are others who I won't, because they only like cheesy romantic comedies and Shrek. Or some guy will say I have to play Face Obliterator 5000, and I like him and all, but I'm not a fan of the Face Obliterator genre. Or, while his wife is great, no, I don't want to see the new Benedict Cumberbatch movie. Under any circumstances.

They're good people. We just have different tastes. I don't make them watch the long, depressing foreign movies I like, and they restrict their evangelizing Rick & Morty to me to one hour per day. I only accept recommendations from people when I've found their tastes line up with mine. You're the same way, right?

Pick Reviewers The Same Way

Reviewers are just individual humans, with their own tastes, and no one human can be a perfect, impartial justice machine for evaluating a work of art. Any decent reviewer can say how buggy a game is and whether it runs OK on their PC. Beyond that, it's just, like, your opinion, man. 

If you want reviews, don't just sit there. Find a couple reviewers you like and read them. If a web site doesn't have regular reviewers and just uses a rotating stable of whatever recent college grad is most desperate that week, it's not going to be useful to you. It takes work to find a site that works for you, but that's life.

Fun bonus fact: All awards for art, from the Nobel prizes down to video game awards, are arbitrary and meaningless. If you want to obsess about the Oscars, hey, you do you, but don't pretend they have any value beyond distracting you for a minute.
Are Numerical Review Scores Dumb?

On the surface, yes, evaluating a complex work of art and boiling it down to a single number is dumb. I mean, it's not like critics have an Art Scale, and they can put the last Call of Duty on it and say, "This game weighs 8.3 Arts, and the last game only weighs 7.1 Arts, and that's 1.2 Arts more!!! So this game gets a 93%."

Review scores, in practice, are fine. However, remember, a high or low number is just a reviewer giving an opinion, and if you trust his or her opinions, you're fine. High number means they like it. If a reviewer I trust says, "Yeah, this game is a B-," I know what's goin' on.

Is It OK For a A Video Game Reviewer to Be Bad at Games?

Of course. A lot more game reviewers should be bad at games. Fact is, most people who play computer games are bad at them, and they deserve reviewers who advocate for them and can say, "If you blow 20 bucks on this, you'll die 500 times on the first level and hate it. Don't waste your money."

Look, I love laughing at game professionals flailing at games as much as anyone. Remember when that unnamed Polygon writer tried Doom and showed no signs of ever having played it (or any video game) ever before? That was a hoot.

(My favorite bit is when the player unloads a full shotgun blast into a health pack resting on the ground, in what I can only assume is a post-modern deconstruction of late-stage capitalism.)

But some people watched that video and said, "Wow, I should never buy this game," and were right to say it. So the video was useful after all.

This is why I was a huge fan of Conan O'Brien's Clueless Gamer series, before it devolved into a series of tedious celebrity skits. Watching someone who isn't fully proficient in our art form and its weird conventions struggling to enjoy it can be painfully useful.

In the end of Ratatouille, a supposedly heroic writer gives a good review to a restaurant whose kitchen is infested with rats. GROSS! Never trust reviews.


But This Goes Both Ways, Right?

Yes. Some gamers have very little money and lots of time to fill. They don't want to spend twenty of their limited bucks on a one-hour art piece, and they deserve reviewers who advocate for them as well.

Is It OK For a Video Game Reviewer to Have Strong Political Opinions?

Yeah, why not? A lot of people only want games that support their particular political opinions. They can use politics-fixated reviewers as canaries in a coal mine. The writers are exposed to bad opinions so that you don't have to be.

Again, you have to pick a reviewer compatible with you. If someone doesn't like a game because it's too politically whatever or has too much of the color blue, use that person or don't. You get to choose what reviewers you watch.

What If I Think a Reviewer Sucks?

Don't read their reviews. That'll show 'em!

(And leave it at that. Don't be an asshole to them because you don't agree with them. Not reading them is really the only vote you get.)

Review aggregator sites would have you believe every Marvel movies is one of the Best Movies Ever Made. Which, I mean, Marvel is fine I guess, but nobody will remember any of these flicks in 3 years.
How About Game Aggregator Sites? Are They Cool?

So you can go to a place like MetaCritic, which averages 50 different game review scores to take all those accumulated opinions and blends them together to create one number which represents Objective Truth. (Interestingly, Objective Truth is, the vast majority of the time, between 70% and 90%).

Look, is this useful? Kind of. I suppose.

I mean, look. Suppose ten people you don't like give you their scores for a game. That won't be very useful. But what if you take those ten dumb opinions, blend them together, and take the average? That won't be any more useful, will it? Do you think that if you mix a lot of dumbness together, somehow smartness is made? Does this work with political parties too?

But it's all subjective. If you get value out of MetaCritic, use it. It's no sweat off my nose.

But Aren't Game Developer Payments Sometimes Determined By Metacritic Scores? Isn't That Bad?

All Metacritic is doing is getting some numbers and averaging them together. Yes, taking this random number and paying developer bonuses based on it is kind of shady. But on the list of Ways the Game Industry Mistreats Its Employees, it's like 893 out of 1200.

And if you look at the list of Concrete Things That Can Be Done to Make Developers' Lives Better, "Being mad at MetaCritic" is not on it at all.

My kids don't even know video game reviews EXIST, but they will buy anything even mentioned by this guy. God. Why do I even pretend I know anything?
One Last, Horrifying Truth About Game Reviews

I'm ancient, and even I don't use them anymore. There's no review that can tell me anything I can't get by watching the game on Twitch.tv for ten seconds and checking the Steam reviews to make sure it's not too buggy.

In Conclusion

Take responsibility for yourself. Accept that the world is full of people different than you and there's space for all of us. As long as they're not punching you in the nose, people are allowed to have dumb opinions in their dumb heads. When choosing who you allow precious space inside your own head, choose someone you trust.

I will trust in the good people of the Internet to take this sensible advice and act with a bit of basic empathy in the future. I consider this entire discussion closed.

One Final Small Bit Of Whimsy

For a games web site, there's a huge advantage to having reviews written by inexperienced, eager people who try to stir up arguments instead of calming them. Those people work cheaper, and their work tends to stir up anger which gets more clicks. Sure, these poor writers/targets get screamed at, but that's what they were hired for. Their employers don't care as long as the clicks keep coming.

In the end, however, we're talking about video game reviews. In the global scheme of things, game reviews are REALLY unimportant.

Here's what keeps me up at night: How do we know that the journalists covering politics, the economy, and wars aren't being picked in exactly the same way?

### 

If you're intrigued by giant indie RPGs with cool adventures and epic stories, you can wishlist our next game on Steam. Give it a terrible review if you want. We just need the attention. News about our work and random musings can be found on our Twitter.

2019年3月27日水曜日

EA Cricket 2018 Download For Free Full Version

EA Cricket 2018 Download For Free Full Version




SCREENSHOT



System Requirements Of Cricket 2018 Download Free

  • Tested on Window 7 64 Bit
  • Operating System: Window XP/ Vista/ Window 7/ Window 8 and 8.1/10
  • CPU: 2.0 GHz Intel Pentium 4 or later
  • RAM: 512 MB
  • Setup size: 1.1 GB
  • Hard Disk Space: 4 GB






THE CONJURING HOUSE NEW HORROR GAME LIVE BY 😎 DEEPAK THE TAMIL GAMER

THE CONJURING HOUSE NEW HORROR GAME LIVE BY 😎 DEEPAK THE TAMIL GAMER

Streamed live on Sep 27, 2018
Subscribe My Channel
 Fortnite id DEEPAKDKS
 Pubg mobile game id deepakdks8124
 rules of survival deepakdks 
 how to download fortnite video link https://youtu.be/Td-0opZ0quk 


 😎😎😎😎😎😎😎😎😎SUBSCRIBE MY CHANNEL😂😂😂😂😂😂😂😂😂😂

SPSP 2015: We're Here In Long Beach!

It's been a few months since I've posted on this blog, and I'm planning to change that over the next several days: It is time for the annual convention of the Society for Personality and Social Psychology and we've got three full days packed with social-personality content to share with the blogosphere. I'll be writing a few short posts over the course of the conference--but before I do I want to point out where you can find some of the current and former bloggers on this website, right here at the convention:

Thursday
Katherine Thorson: Poster Session A
Cardiac Vagal Tone predicts Responsivity to Self-Regulatory Thought Inductions: Poster A273

Friday
Amie Gordon: Symposium Session A
Bringing Sleep to Social Psychology: Considering the Effect of Sleep on our Emotions, Relationships and Intergroup Relations
Friday, February 27, 2015, 9:45 AM - 11:00 AM, Promenade Ballroom 104C


Michael Kraus: Symposium Session A
The Politics of Inequality and the Inequality of Politics
Friday, February 27, 2015, 9:45 AM - 11:00 AM, Room 203ABC


Saturday
Jennifer Stellar: Symposium Session I
A Big Helping of Humble Pie: Novel Benefits and New Methods for Cultivating Humility
Saturday, February 28, 2015, 5:00 PM - 6:15 PM, Room 103A


Maya Kuehn: Poster Session E
Rejection Resiliency and Social Influence: Poster E004