Randon Placement of Mines

Started by
13 comments, last by CzarKirk 17 years ago
Quote:Original post by Zahlman
Quote:Original post by JohnBolton
This method places n
mines in a 1D array with an even distribution. You can easily extend it to 2D.

bool mines[ ARRAY_SIZE ];std::fill(mines, mines + n, true);std::random_shuffle(mines, mines + ARRAY_SIZE);


The advantage to my method is that you don't have to create extra data. You just shuffle the mines directly. Of course, it doesn't work very well if the elements contain other data which cannot be moved.

I didn't suggest std::fill simply because I rarely use it (old dog, new tricks ...).

I didn't suggest std::random_shuffle because there is no need to shuffle the entire array.


John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Advertisement
Quote:Original post by JohnBolton
I didn't suggest std::random_shuffle because there is no need to shuffle the entire array.


Yes, I see that now. :)
Thanks for all the suggestions. I have decided to go with DvDmanDT's suggestion, because it seems the simpliest and easiest!

srand((unsigned)time(0));vector<uint> placementlist(size);setall(placementlist, i, size);random_shuffle(placementlist.begin(), placementlist.end());forall(i, mines)    mine[placementlist] = true;

setall is a macro to set all elements of the array to i, and forall is a macro to go from 0 to mines with i (because I get fed up with writing out for loops all the time!)
Quote:Original post by CzarKirk
setall is a macro to set all elements of the array to i


Don't do that. The standard library provides std::generate() for a reason.

// put this in "your library" instead of the macro (modified very slightly // from the SGI docs):#include <algorithm>template <typename T>struct counter {  typedef T result_type;  result_type n;  public:  counter(result_type start = result_type()) : n(start) {}  result_type operator()() { return n++; }};// Now you can do this, without any of the usual problems with macros:std::generate(placementlist.begin(), placementlist.end(), counter<bool*>(mine));// Notice that I actually store pointers to positions of the mine array,// rather than integers. This helps with the second step...// (Also notice that for example if the map were stored in a std::list - a// horrible idea, but you can imagine a similar task where a std::list is the// appropriate storage and we have to randomly distribute values within it -// then we could generate() a vector of list::iterators with no problem, since// list::iterators support that post-increment.)


Quote:and forall is a macro to go from 0 to mines with i


Don't do that. The standard library provides std::for_each() for a reason.

// put this in "your library":template <typename Iterator, typename Value>class assign_at : public unary_function<void, Iterator> {  Value v;  public:  assign_at(const Value& v) : v(v) {}  void operator()(Iterator iterator) { *iterator = v; }};// Now you can use std::for_each to replace this particular kind of for-loop:std::for_each(placementlist.begin(), placementlist.end(), assign_at(true));


In general, for loops can be factored out in this sort of way; where it doesn't seem worth the effort (because the class isn't easily designed for reuse), you're almost certainly still going to be better off writing the for loop manually than using a macro. Macros are text-substitution hacks that don't have any understanding of the language, and can cause strange things to go wrong. Using them requires a better reason than this - it basically requires "ordinary language features simply can't do what's needed".
Sorry Zahlman, but I look at your code, and I look at #define forall(x, size) for (uint x = 0; x < size; x++)..... and one of the two gives me a severe headache :P

This topic is closed to new replies.

Advertisement