00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #ifndef TRANSPORT_GAMEOFLIFEINPUT_C_DEFINED
00039 #define TRANSPORT_GAMEOFLIFEINPUT_C_DEFINED
00040
00041 #include "Transport/GameOfLifeInput.H"
00042
00043 #include "Component/ModelOptionDef.H"
00044 #include "Image/CutPaste.H"
00045 #include "Image/ShapeOps.H"
00046 #include "Raster/GenericFrame.H"
00047 #include "Transport/TransportOpts.H"
00048
00049 namespace
00050 {
00051 Image<byte> gameOfLifeUpdate(const Image<byte>& in,
00052 int* nlive)
00053 {
00054 Image<byte> out(in.getDims(), ZEROS);
00055
00056 Image<byte>::const_iterator sptr = in.begin();
00057 Image<byte>::iterator dptr = out.beginw();
00058
00059 const int w = in.getWidth();
00060 const int h = in.getHeight();
00061
00062 *nlive = 0;
00063
00064 for (int y = 0; y < h; ++y)
00065 for (int x = 0; x < w; ++x)
00066 {
00067 int nn = 0;
00068
00069 if (y > 1)
00070 {
00071 if (x > 1 && sptr[-1-w] > 0) ++nn;
00072 if ( sptr[ 0-w] > 0) ++nn;
00073 if (x < w-1 && sptr[ 1-w] > 0) ++nn;
00074 }
00075
00076 if (x > 1 && sptr[-1] > 0) ++nn;
00077 if (x < w-1 && sptr[ 1] > 0) ++nn;
00078
00079 if (y < h-1)
00080 {
00081 if (x > 1 && sptr[-1+w] > 0) ++nn;
00082 if ( sptr[ 0+w] > 0) ++nn;
00083 if (x < w-1 && sptr[ 1+w] > 0) ++nn;
00084 }
00085
00086 if (*sptr > 0)
00087 {
00088 *dptr =
00089 (nn == 2 || nn == 3)
00090 ? 255
00091 : 0;
00092 }
00093 else
00094 {
00095 *dptr =
00096 (nn == 3)
00097 ? 255
00098 : 0;
00099 }
00100
00101 if (*dptr > 0)
00102 ++*nlive;
00103
00104 ++sptr;
00105 ++dptr;
00106 }
00107
00108 return out;
00109 }
00110 }
00111
00112
00113 const ModelOptionDef OPT_GameOfLifeFillFraction =
00114 { MODOPT_ARG(double), "GameOfLifeFillFraction", &MOC_INPUT, OPTEXP_CORE,
00115 "In the \"Game of Life\" (with --in=life), this is the fraction "
00116 "of cells to be filled as \"live\" when creating the initial "
00117 "random game board, and when re-seeding the board after it becomes "
00118 "stuck.",
00119 "life-fill-fraction", '\0', "float", "0.4" };
00120
00121
00122 const ModelOptionDef OPT_GameOfLifeCellSize =
00123 { MODOPT_ARG(uint), "GameOfLifeCellSize", &MOC_INPUT, OPTEXP_CORE,
00124 "In the \"Game of Life\" (with --in=life), this is the size, in "
00125 "pixels, of each cell.",
00126 "life-cell-size", '\0', "uint", "4" };
00127
00128
00129 GameOfLifeInput::GameOfLifeInput(OptionManager& mgr)
00130 :
00131 FrameIstream(mgr, "Random Input", "GameOfLifeInput"),
00132 itsFillFraction(&OPT_GameOfLifeFillFraction, this),
00133 itsCellSize(&OPT_GameOfLifeCellSize, this),
00134 itsDims(320,240),
00135
00136
00137 itsGenerator(0),
00138 itsBoard(),
00139 itsStarted(false)
00140 {
00141 itsGenerator.seed(time(NULL));
00142 }
00143
00144
00145 GameOfLifeInput::~GameOfLifeInput()
00146 {}
00147
00148
00149 void GameOfLifeInput::setConfigInfo(const std::string& dimsstring)
00150 {
00151
00152
00153
00154
00155 if (dimsstring.size() == 0)
00156 return;
00157
00158 Dims d; convertFromString(dimsstring, d);
00159 this->setDims(d);
00160 }
00161
00162
00163 GenericFrameSpec GameOfLifeInput::peekFrameSpec()
00164 {
00165 GenericFrameSpec result;
00166
00167 result.nativeType = GenericFrame::RGB_U8;
00168 result.videoFormat = VIDFMT_AUTO;
00169 result.videoByteSwap = false;
00170 result.dims = itsDims;
00171 result.floatFlags = 0;
00172
00173 return result;
00174 }
00175
00176
00177 GenericFrame GameOfLifeInput::readFrame()
00178 {
00179 if (!itsStarted)
00180 {
00181
00182 #if 0
00183
00184 #define i 0
00185 #define Q 255
00186 const byte gosper_glider_gun[] =
00187 {
00188
00189 i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,Q,i,i,i,i,i,i,i,i,i,i,i,
00190 i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,Q,i,Q,i,i,i,i,i,i,i,i,i,i,i,
00191 i,i,i,i,i,i,i,i,i,i,i,i,Q,Q,i,i,i,i,i,i,Q,Q,i,i,i,i,i,i,i,i,i,i,i,i,Q,Q,
00192 i,i,i,i,i,i,i,i,i,i,i,Q,i,i,i,Q,i,i,i,i,Q,Q,i,i,i,i,i,i,i,i,i,i,i,i,Q,Q,
00193 Q,Q,i,i,i,i,i,i,i,i,Q,i,i,i,i,i,Q,i,i,i,Q,Q,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
00194 Q,Q,i,i,i,i,i,i,i,i,Q,i,i,i,Q,i,Q,Q,i,i,i,i,Q,i,Q,i,i,i,i,i,i,i,i,i,i,i,
00195 i,i,i,i,i,i,i,i,i,i,Q,i,i,i,i,i,Q,i,i,i,i,i,i,i,Q,i,i,i,i,i,i,i,i,i,i,i,
00196 i,i,i,i,i,i,i,i,i,i,i,Q,i,i,i,Q,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,
00197 i,i,i,i,i,i,i,i,i,i,i,i,Q,Q,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i
00198 };
00199
00200 const byte block_engine_1[] =
00201 {
00202
00203 i,i,i,i,i,Q,i,Q,
00204 i,i,i,i,i,Q,i,i,
00205 i,i,i,Q,i,i,i,i,
00206 i,Q,i,Q,i,i,i,i,
00207 Q,Q,i,Q,i,i,i,i,
00208 i,Q,i,i,i,i,i,i,
00209 };
00210
00211 const byte block_engine_2[] =
00212 {
00213
00214 Q,i,Q,i,Q,
00215 Q,i,Q,Q,i,
00216 Q,Q,i,i,i,
00217 i,i,i,i,Q,
00218 Q,i,Q,Q,Q,
00219 };
00220
00221 const byte block_engine_3[] =
00222 {
00223
00224 Q,Q,Q,Q,Q,Q,Q,Q,i,Q,Q,Q,Q,Q,i,i,i,Q,Q,Q,i,i,i,i,i,i,Q,Q,Q,Q,Q,Q,Q,i,Q,Q,Q,Q,Q
00225 };
00226
00227 #undef i
00228 #undef Q
00229
00230 #endif
00231
00232 itsBoardHist.resize(0);
00233 itsBoard = Image<byte>(itsDims.w() / itsCellSize.getVal(),
00234 itsDims.h() / itsCellSize.getVal(),
00235 ZEROS);
00236
00237 #if 0
00238 if (0)
00239 const Image<byte> pattern(&gosper_glider_gun[0], 36, 9);
00240 if (0)
00241 const Image<byte> pattern(&block_engine_1[0], 8, 6);
00242 if (0)
00243 const Image<byte> pattern(&block_engine_2[0], 5, 5);
00244 if (0)
00245 const Image<byte> pattern(&block_engine_3[0], 39, 1);
00246
00247 inplacePaste(itsBoard, pattern, Point2D<int>(60,60));
00248 #endif
00249
00250 const double t = itsFillFraction.getVal();
00251
00252 for (Image<byte>::iterator
00253 p = itsBoard.beginw(), stop = itsBoard.endw();
00254 p != stop; ++p)
00255 *p =
00256 (itsGenerator.fdraw() < t)
00257 ? 255
00258 : 0;
00259
00260 itsStarted = true;
00261 }
00262 else
00263 {
00264 int nlive = 0;
00265 itsBoard = gameOfLifeUpdate(itsBoard, &nlive);
00266 if (nlive == 0)
00267
00268 itsStarted = false;
00269 }
00270
00271 for (size_t i = 0; i < itsBoardHist.size(); ++i)
00272 if (itsBoard == itsBoardHist[i])
00273 {
00274
00275
00276 LINFO("cycle detected with period %"ZU,
00277 itsBoardHist.size() - i);
00278 itsStarted = false;
00279 break;
00280 }
00281
00282 itsBoardHist.push_back(itsBoard);
00283
00284 while (itsBoardHist.size() >= 8)
00285 itsBoardHist.pop_front();
00286
00287 const Image<byte> result =
00288 rescale(itsBoard, itsDims, RESCALE_SIMPLE_NOINTERP);
00289
00290 return GenericFrame(result);
00291 }
00292
00293
00294 void GameOfLifeInput::setDims(const Dims& s)
00295 {
00296 itsDims = s;
00297 }
00298
00299
00300
00301
00302
00303
00304
00305
00306 #endif // TRANSPORT_GAMEOFLIFEINPUT_C_DEFINED