Guest User

Untitled

a guest
Jan 1st, 2018
156
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.39 KB | None | 0 0
  1. #include <SFML/Graphics.hpp>
  2. #include <iostream>
  3. #include <memory>
  4. #include <map>
  5. #include <string>
  6. #include <vector>
  7. #include <array>
  8. #include <random>
  9. #include <stdexcept>
  10. #include <cassert>
  11.  
  12. namespace
  13. {
  14. const std::string shaderCode = \
  15. "uniform vec2 LightOrigin;"\
  16. "uniform vec3 SourceColor;"\
  17. "uniform float LightAttenuation;"\
  18. "uniform vec2 ScreenResolution;"\
  19.  
  20. "void main()"\
  21. "{"\
  22. " vec2 baseDistance = gl_FragCoord.xy;"\
  23. " baseDistance.y = ScreenResolution.y - baseDistance.y;"\
  24. " vec2 distance = LightOrigin - baseDistance;"\
  25. " float linearDistance = length(distance);"\
  26. " float attenuation = 1.0 / ((LightAttenuation + LightAttenuation) * linearDistance);"\
  27. " vec4 lightColor = vec4(SourceColor, 1.0);"\
  28. " vec4 color = vec4(attenuation, attenuation, attenuation, 1.0) * lightColor;"\
  29. " gl_FragColor = color;"\
  30. "}";
  31.  
  32. const std::string Brightness = \
  33. "uniform sampler2D source;"\
  34.  
  35. "const float Threshold = 0.7;"\
  36. "const float Factor = 4.0;"\
  37.  
  38. "void main()"\
  39. "{"\
  40. " vec4 sourceFragment = texture2D(source, gl_TexCoord[0].xy);"\
  41. " float luminance = sourceFragment.r * 0.2126 + sourceFragment.g * 0.7152 + sourceFragment.b * 0.0722;"\
  42. " sourceFragment *= clamp(luminance - Threshold, 0.0, 1.0) * Factor;"\
  43. " gl_FragColor = sourceFragment;"\
  44. "}";
  45.  
  46. const std::string GuassianBlur = \
  47. "uniform sampler2D source;"\
  48.  
  49. "uniform vec2 offsetFactor;"\
  50.  
  51. "void main()"\
  52. "{"\
  53. " vec2 textureCoordinates = gl_TexCoord[0].xy;"\
  54. " vec4 color = vec4(0.0);"\
  55. " color += texture2D(source, textureCoordinates - 4.0 * offsetFactor) * 0.0162162162;"\
  56. " color += texture2D(source, textureCoordinates - 3.0 * offsetFactor) * 0.0540540541;"\
  57. " color += texture2D(source, textureCoordinates - 2.0 * offsetFactor) * 0.1216216216;"\
  58. " color += texture2D(source, textureCoordinates - offsetFactor) * 0.1945945946;"\
  59. " color += texture2D(source, textureCoordinates) * 0.2270270270;"\
  60. " color += texture2D(source, textureCoordinates + offsetFactor) * 0.1945945946;"\
  61. " color += texture2D(source, textureCoordinates + 2.0 * offsetFactor) * 0.1216216216;"\
  62. " color += texture2D(source, textureCoordinates + 3.0 * offsetFactor) * 0.0540540541;"\
  63. " color += texture2D(source, textureCoordinates + 4.0 * offsetFactor) * 0.0162162162;"\
  64. " gl_FragColor = color;"\
  65. "}";
  66.  
  67. const std::string DownSample = \
  68. "uniform sampler2D source;"\
  69. "uniform vec2 sourceSize;"\
  70.  
  71. "void main()"\
  72. "{"\
  73. " vec2 pixelSize = vec2(1.0 / sourceSize.x, 1.0 / sourceSize.y);"\
  74. " vec2 textureCoordinates = gl_TexCoord[0].xy;"\
  75. " vec4 color = texture2D(source, textureCoordinates);"\
  76. " color += texture2D(source, textureCoordinates + vec2(1.0, 0.0) * pixelSize);"\
  77. " color += texture2D(source, textureCoordinates + vec2(-1.0, 0.0) * pixelSize);"\
  78. " color += texture2D(source, textureCoordinates + vec2(0.0, 1.0) * pixelSize);"\
  79. " color += texture2D(source, textureCoordinates + vec2(0.0, -1.0) * pixelSize);"\
  80. " color += texture2D(source, textureCoordinates + vec2(1.0, 1.0) * pixelSize);"\
  81. " color += texture2D(source, textureCoordinates + vec2(-1.0, -1.0) * pixelSize);"\
  82. " color += texture2D(source, textureCoordinates + vec2(1.0, -1.0) * pixelSize);"\
  83. " color += texture2D(source, textureCoordinates + vec2(-1.0, 1.0) * pixelSize);"\
  84. " gl_FragColor = color / 9.0;"\
  85. "}";
  86.  
  87. const std::string Add = \
  88. "uniform sampler2D source;"\
  89. "uniform sampler2D bloom;"\
  90.  
  91. "void main()"\
  92. "{"\
  93. " vec4 sourceFragment = texture2D(source, gl_TexCoord[0].xy);"\
  94. " vec4 bloomFragment = texture2D(bloom, gl_TexCoord[0].xy);"\
  95. " gl_FragColor = sourceFragment + bloomFragment;"\
  96. "}";
  97.  
  98. const std::string Fullpass = \
  99. "void main()"\
  100. "{"\
  101. " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"\
  102. " gl_TexCoord[0] = gl_MultiTexCoord0;"\
  103. "}";
  104. }
  105.  
  106. namespace
  107. {
  108. const sf::Vector2i WINDOW_SIZE(640, 480);
  109. const unsigned NUMBER_OF_PLAYERS = 2;
  110. const unsigned DIM = 3;
  111. const float SIZE = 70.f;
  112. const sf::Vector2f START_POINT(WINDOW_SIZE.x * 0.5f - DIM * SIZE * 0.5f, WINDOW_SIZE.y * 0.5f - DIM * SIZE * 0.5f);
  113. }
  114.  
  115. enum struct Player : unsigned
  116. {
  117. None,
  118. User,
  119. Computer
  120. };
  121.  
  122. enum struct Shaders : unsigned
  123. {
  124. BrightnessPass,
  125. DownSamplePass,
  126. GaussianBlurPass,
  127. AddPass,
  128. Light
  129. };
  130.  
  131. enum struct Fonts : unsigned
  132. {
  133. Main,
  134. };
  135.  
  136. template <typename Resource>
  137. void centerOrigin(Resource& resource)
  138. {
  139. sf::FloatRect bounds = resource.getLocalBounds();
  140. resource.setOrigin(std::floor(bounds.left + bounds.width / 2.f), std::floor(bounds.top + bounds.height / 2.f));
  141. }
  142.  
  143. template <typename Resource, typename Identifier>
  144. class ResourceHolder
  145. {
  146. public:
  147. void load(Identifier id, const std::string& filename);
  148.  
  149. template <typename Parameter>
  150. void load(Identifier id, const std::string& filename, const Parameter& secondParam, bool flag = true);
  151.  
  152. Resource& get(Identifier id);
  153. const Resource& get(Identifier id) const;
  154.  
  155. private:
  156. void insertResource(Identifier id, std::unique_ptr<Resource> resource);
  157.  
  158. std::map<Identifier, std::unique_ptr<Resource>> mResourceMap;
  159. };
  160.  
  161. template <typename Resource, typename Identifier>
  162. void ResourceHolder<Resource, Identifier>::load(Identifier id, const std::string& filename)
  163. {
  164. std::unique_ptr<Resource> resource(std::make_unique<Resource>());
  165.  
  166. if (!resource->loadFromFile(filename))
  167. throw std::runtime_error("ResourceHolder::load - Failed to load " + filename);
  168.  
  169. insertResource(id, std::move(resource));
  170. }
  171.  
  172. template <typename Resource, typename Identifier>
  173. template <typename Parameter>
  174. void ResourceHolder<Resource, Identifier>::load(Identifier id, const std::string& filename, const Parameter& secondParam, bool flag)
  175. {
  176. std::unique_ptr<Resource> resource(std::make_unique<Resource>());
  177.  
  178. if (flag)
  179. {
  180. if (!resource->loadFromMemory(filename, secondParam))
  181. throw std::runtime_error("ResourceHolder::load - Failed to load from Memory " + filename);
  182. }
  183. else
  184. {
  185. if (!resource->loadFromFile(filename, secondParam))
  186. throw std::runtime_error("ResourceHolder::load - Failed to load " + filename);
  187. }
  188.  
  189. insertResource(id, std::move(resource));
  190. }
  191.  
  192. template <typename Resource, typename Identifier>
  193. Resource& ResourceHolder<Resource, Identifier>::get(Identifier id)
  194. {
  195. auto found = mResourceMap.find(id);
  196. assert(found != mResourceMap.end());
  197.  
  198. return *found->second;
  199. }
  200.  
  201. template <typename Resource, typename Identifier>
  202. const Resource& ResourceHolder<Resource, Identifier>::get(Identifier id) const
  203. {
  204. auto found = mResourceMap.find(id);
  205. assert(found != mResourceMap.end());
  206.  
  207. return *found->second;
  208. }
  209.  
  210. template <typename Resource, typename Identifier>
  211. void ResourceHolder<Resource, Identifier>::insertResource(Identifier id, std::unique_ptr<Resource> resource)
  212. {
  213. auto inserted = mResourceMap.insert(std::make_pair(id, std::move(resource)));
  214. assert(inserted.second);
  215. }
  216.  
  217. using FontHolder = ResourceHolder<sf::Font, Fonts>;
  218. using ShaderHolder = ResourceHolder<sf::Shader, Shaders>;
  219.  
  220. class PostEffect : sf::NonCopyable
  221. {
  222. public:
  223. virtual ~PostEffect();
  224. virtual void apply(const sf::RenderTexture& input, sf::RenderTarget& output) = 0;
  225.  
  226. static bool isSupported();
  227.  
  228. protected:
  229. static void applyShader(const sf::Shader& shader, sf::RenderTarget& output);
  230. };
  231.  
  232. PostEffect::~PostEffect()
  233. {
  234. }
  235.  
  236. void PostEffect::applyShader(const sf::Shader& shader, sf::RenderTarget& output)
  237. {
  238. sf::Vector2f outputSize = static_cast<sf::Vector2f>(output.getSize());
  239.  
  240. sf::VertexArray vertices(sf::TrianglesStrip, 4);
  241. vertices[0] = sf::Vertex(sf::Vector2f(0, 0), sf::Vector2f(0, 1));
  242. vertices[1] = sf::Vertex(sf::Vector2f(outputSize.x, 0), sf::Vector2f(1, 1));
  243. vertices[2] = sf::Vertex(sf::Vector2f(0, outputSize.y), sf::Vector2f(0, 0));
  244. vertices[3] = sf::Vertex(sf::Vector2f(outputSize), sf::Vector2f(1, 0));
  245.  
  246. sf::RenderStates states;
  247. states.shader = &shader;
  248. states.blendMode = sf::BlendNone;
  249.  
  250. output.draw(vertices, states);
  251. }
  252.  
  253. bool PostEffect::isSupported()
  254. {
  255. return sf::Shader::isAvailable();
  256. }
  257.  
  258. class BloomEffect final : public PostEffect
  259. {
  260. public:
  261. using RenderTextureArray = std::array<sf::RenderTexture, 2>;
  262.  
  263. BloomEffect();
  264.  
  265. void apply(const sf::RenderTexture& input, sf::RenderTarget& output) override;
  266.  
  267. private:
  268. void prepareTextures(sf::Vector2u size);
  269.  
  270. void filterBright(const sf::RenderTexture& input, sf::RenderTexture& output);
  271. void blurMultipass(RenderTextureArray& renderTextures);
  272. void blur(const sf::RenderTexture& input, sf::RenderTexture& output, sf::Vector2f offsetFactor);
  273. void downsample(const sf::RenderTexture& input, sf::RenderTexture& output);
  274. void add(const sf::RenderTexture& source, const sf::RenderTexture& bloom, sf::RenderTarget& target);
  275.  
  276. ShaderHolder mShaders;
  277.  
  278. sf::RenderTexture mBrightnessTexture;
  279. RenderTextureArray mFirstPassTextures;
  280. RenderTextureArray mSecondPassTextures;
  281. };
  282.  
  283. BloomEffect::BloomEffect()
  284. : mShaders()
  285. , mBrightnessTexture()
  286. , mFirstPassTextures()
  287. , mSecondPassTextures()
  288. {
  289. mShaders.load(Shaders::BrightnessPass, Fullpass, Brightness);
  290. mShaders.load(Shaders::DownSamplePass, Fullpass, DownSample);
  291. mShaders.load(Shaders::GaussianBlurPass, Fullpass, GuassianBlur);
  292. mShaders.load(Shaders::AddPass, Fullpass, Add);
  293.  
  294. }
  295.  
  296. void BloomEffect::apply(const sf::RenderTexture& input, sf::RenderTarget& output)
  297. {
  298. prepareTextures(input.getSize());
  299.  
  300. filterBright(input, mBrightnessTexture);
  301.  
  302. downsample(mBrightnessTexture, mFirstPassTextures[0]);
  303. blurMultipass(mFirstPassTextures);
  304.  
  305. downsample(mFirstPassTextures[0], mSecondPassTextures[0]);
  306. blurMultipass(mSecondPassTextures);
  307.  
  308. add(mFirstPassTextures[0], mSecondPassTextures[0], mFirstPassTextures[1]);
  309. mFirstPassTextures[1].display();
  310. add(input, mFirstPassTextures[1], output);
  311. }
  312.  
  313. void BloomEffect::prepareTextures(sf::Vector2u size)
  314. {
  315. if (mBrightnessTexture.getSize() != size)
  316. {
  317. mBrightnessTexture.create(size.x, size.y);
  318. mBrightnessTexture.setSmooth(true);
  319.  
  320. mFirstPassTextures[0].create(size.x / 2, size.y / 2);
  321. mFirstPassTextures[0].setSmooth(true);
  322. mFirstPassTextures[1].create(size.x / 2, size.y / 2);
  323. mFirstPassTextures[1].setSmooth(true);
  324.  
  325. mSecondPassTextures[0].create(size.x / 4, size.y / 4);
  326. mSecondPassTextures[0].setSmooth(true);
  327. mSecondPassTextures[1].create(size.x / 4, size.y / 4);
  328. mSecondPassTextures[1].setSmooth(true);
  329. }
  330. }
  331.  
  332. void BloomEffect::filterBright(const sf::RenderTexture& input, sf::RenderTexture& output)
  333. {
  334. sf::Shader& brightness = mShaders.get(Shaders::BrightnessPass);
  335.  
  336. brightness.setUniform("source", input.getTexture());
  337. applyShader(brightness, output);
  338. output.display();
  339. }
  340.  
  341. void BloomEffect::blurMultipass(RenderTextureArray& renderTextures)
  342. {
  343. sf::Vector2u textureSize = renderTextures[0].getSize();
  344.  
  345. for (std::size_t count = 0; count < 2; ++count)
  346. {
  347. blur(renderTextures[0], renderTextures[1], sf::Vector2f(0.f, 1.f / textureSize.y));
  348. blur(renderTextures[1], renderTextures[0], sf::Vector2f(1.f / textureSize.x, 0.f));
  349. }
  350. }
  351.  
  352. void BloomEffect::blur(const sf::RenderTexture& input, sf::RenderTexture& output, sf::Vector2f offsetFactor)
  353. {
  354. sf::Shader& gaussianBlur = mShaders.get(Shaders::GaussianBlurPass);
  355.  
  356. gaussianBlur.setUniform("source", input.getTexture());
  357. gaussianBlur.setUniform("offsetFactor", offsetFactor);
  358. applyShader(gaussianBlur, output);
  359. output.display();
  360. }
  361.  
  362. void BloomEffect::downsample(const sf::RenderTexture& input, sf::RenderTexture& output)
  363. {
  364. sf::Shader& downSampler = mShaders.get(Shaders::DownSamplePass);
  365.  
  366. downSampler.setUniform("source", input.getTexture());
  367. downSampler.setUniform("sourceSize", sf::Vector2f(input.getSize()));
  368. applyShader(downSampler, output);
  369. output.display();
  370. }
  371.  
  372. void BloomEffect::add(const sf::RenderTexture& source, const sf::RenderTexture& bloom, sf::RenderTarget& output)
  373. {
  374. sf::Shader& adder = mShaders.get(Shaders::AddPass);
  375.  
  376. adder.setUniform("source", source.getTexture());
  377. adder.setUniform("bloom", bloom.getTexture());
  378. applyShader(adder, output);
  379. }
  380.  
  381.  
  382. class Tile : public sf::RectangleShape, private sf::NonCopyable
  383. {
  384. public:
  385. Tile() = default;
  386.  
  387. void setOwner(Player player)
  388. {
  389. mOwner = player;
  390. }
  391.  
  392. Player getOwner() const
  393. {
  394. return mOwner;
  395. }
  396.  
  397. void setLightColor(sf::Vector3f player)
  398. {
  399. mColor = player;
  400. }
  401.  
  402. sf::Vector3f getLightColor() const
  403. {
  404. return mColor;
  405. }
  406.  
  407. private:
  408. Player mOwner = Player::None;
  409. sf::Vector3f mColor = sf::Vector3f(0, 0, 0);
  410. };
  411.  
  412. class World : private sf::NonCopyable
  413. {
  414. struct Move
  415. {
  416. unsigned int x = 0;
  417. unsigned int y = 0;
  418. };
  419.  
  420. public:
  421. explicit World(sf::RenderTarget& outputTarget);
  422.  
  423. bool isFull() const;
  424. bool isWinner(Player player) const;
  425. bool applyMove(Player player, sf::Uint32 row, sf::Uint32 column) const;
  426. bool applyAl(Player player) const;
  427. void draw();
  428.  
  429. private:
  430. Move minimax() const;
  431. int minSearch(int level) const;
  432. int maxSearch(int level) const;
  433.  
  434. sf::RenderTarget& mTarget;
  435. sf::RenderTexture mRenderTexture;
  436. sf::Sprite mSpriteWorld;
  437. ShaderHolder mShader;
  438. BloomEffect mBloomEffect;
  439.  
  440. mutable unsigned mRemain;
  441. mutable std::array<Tile, DIM * DIM> mTiles;
  442. };
  443.  
  444. World::World(sf::RenderTarget& outputTarget)
  445. : mTarget(outputTarget)
  446. , mRenderTexture()
  447. , mTiles()
  448. , mRemain(DIM * DIM)
  449. {
  450. sf::Vector2f startPosition(START_POINT);
  451.  
  452. for (unsigned i = 0; i < DIM; ++i)
  453. {
  454. for (unsigned j = 0; j < DIM; ++j)
  455. {
  456. unsigned position = j * DIM + i;
  457.  
  458. mTiles[position].setSize(sf::Vector2f(SIZE, SIZE));
  459. mTiles[position].setPosition(startPosition);
  460. mTiles[position].setOutlineThickness(2.f);
  461. mTiles[position].setFillColor(sf::Color::Black);
  462. mTiles[position].setOutlineColor(sf::Color::White);
  463.  
  464. startPosition.x += SIZE;
  465. }
  466.  
  467. startPosition.y += SIZE;
  468. startPosition.x = START_POINT.x;
  469. }
  470.  
  471. mRenderTexture.create(WINDOW_SIZE.x, WINDOW_SIZE.y);
  472. mRenderTexture.setSmooth(true);
  473.  
  474. mSpriteWorld.setTexture(mRenderTexture.getTexture());
  475. mSpriteWorld.setOrigin(mSpriteWorld.getTextureRect().width / 2.f, mSpriteWorld.getTextureRect().height / 2.f);
  476. mSpriteWorld.setPosition(WINDOW_SIZE.x / 2.f, WINDOW_SIZE.y / 2.f);
  477.  
  478. mShader.load(Shaders::Light, shaderCode, sf::Shader::Fragment);
  479. mShader.get(Shaders::Light).setUniform("ScreenResolution", sf::Vector2f(WINDOW_SIZE.x * 1.f, WINDOW_SIZE.y * 1.f));
  480. mShader.get(Shaders::Light).setUniform("LightAttenuation", 20.0f);
  481. }
  482.  
  483. void World::draw()
  484. {
  485. if (PostEffect::isSupported())
  486. {
  487. mRenderTexture.clear();
  488.  
  489. for (const auto& tile : mTiles)
  490. {
  491. mRenderTexture.draw(tile);
  492.  
  493. sf::Vector2f position(tile.getPosition().x + tile.getLocalBounds().width / 2, tile.getPosition().y + tile.getLocalBounds().height / 2);
  494.  
  495. auto& shader = mShader.get(Shaders::Light);
  496.  
  497. shader.setUniform("LightOrigin", position);
  498. shader.setUniform("SourceColor", tile.getLightColor());
  499.  
  500. sf::RenderStates states;
  501. states.shader = &shader;
  502. states.blendMode = sf::BlendAdd;
  503.  
  504. mRenderTexture.draw(mSpriteWorld, states);
  505. }
  506.  
  507. mRenderTexture.display();
  508.  
  509. mTarget.clear();
  510. mTarget.draw(mSpriteWorld);
  511.  
  512. mBloomEffect.apply(mRenderTexture, mTarget);
  513. }
  514. else
  515. {
  516. for (const auto& tile : mTiles)
  517. {
  518. mTarget.draw(tile);
  519. }
  520. }
  521. }
  522.  
  523. bool World::applyMove(Player player, sf::Uint32 row, sf::Uint32 column) const
  524. {
  525. unsigned position = row + DIM * column;
  526.  
  527. if ((position > mTiles.size()) || (mTiles[position].getOwner() != Player::None) || row >= DIM || column >= DIM)
  528. {
  529. return false;
  530. }
  531.  
  532. --mRemain;
  533.  
  534. mTiles[position].setOwner(player);
  535.  
  536. switch (player)
  537. {
  538. case Player::User:
  539. mTiles[position].setLightColor(sf::Vector3f(0, 0, 255));
  540. break;
  541. case Player::Computer:
  542. mTiles[position].setLightColor(sf::Vector3f(255, 0, 0));
  543. break;
  544. }
  545.  
  546. return true;
  547. }
  548.  
  549. bool World::isFull() const
  550. {
  551. return (mRemain == 0);
  552. }
  553.  
  554. bool World::applyAl(Player player) const
  555. {
  556. Move move = minimax();
  557. return applyMove(player, move.x, move.y);
  558. }
  559.  
  560. World::Move World::minimax() const
  561. {
  562. int score = std::numeric_limits<int>::max();
  563. Move move;
  564.  
  565. for (unsigned int i = 0; i < DIM; i++)
  566. {
  567. for (unsigned int j = 0; j < DIM; j++)
  568. {
  569. unsigned position = j * DIM + i;
  570. if (mTiles[position].getOwner() == Player::None)
  571. {
  572. mTiles[position].setOwner(Player::Computer);
  573. --mRemain;
  574.  
  575. int temp = maxSearch(0);
  576.  
  577. if (temp < score)
  578. {
  579. score = temp;
  580. move.x = i;
  581. move.y = j;
  582. }
  583.  
  584. mTiles[position].setOwner(Player::None);
  585. ++mRemain;
  586. }
  587. }
  588. }
  589.  
  590. return move;
  591. }
  592.  
  593. int World::maxSearch(int level) const
  594. {
  595. if (isWinner(Player::User)) { return 10; }
  596. else if (isWinner(Player::Computer)) { return -10; }
  597. else if (isFull()) { return 0; }
  598.  
  599. int score = std::numeric_limits<int>::min();
  600.  
  601. for (unsigned int i = 0; i < DIM; i++)
  602. {
  603. for (unsigned int j = 0; j < DIM; j++)
  604. {
  605. unsigned position = j * DIM + i;
  606. if (mTiles[position].getOwner() == Player::None)
  607. {
  608. mTiles[position].setOwner(Player::User);
  609. --mRemain;
  610.  
  611. score = std::max(score, minSearch(level + 1) - level);
  612.  
  613. mTiles[position].setOwner(Player::None);
  614. ++mRemain;
  615. }
  616. }
  617. }
  618.  
  619. return score;
  620. }
  621.  
  622. int World::minSearch(int level) const
  623. {
  624. if (isWinner(Player::User)) { return 10; }
  625. else if (isWinner(Player::Computer)) { return -10; }
  626. else if (isFull()) { return 0; }
  627.  
  628. int score = std::numeric_limits<int>::max();
  629.  
  630. for (unsigned int i = 0; i < DIM; i++)
  631. {
  632. for (unsigned int j = 0; j < DIM; j++)
  633. {
  634. unsigned position = j * DIM + i;
  635. if (mTiles[position].getOwner() == Player::None)
  636. {
  637. mTiles[position].setOwner(Player::Computer);
  638. --mRemain;
  639.  
  640. score = std::min(score, maxSearch(level + 1) + level);
  641.  
  642. mTiles[position].setOwner(Player::None);
  643. ++mRemain;
  644. }
  645. }
  646. }
  647.  
  648. return score;
  649. }
  650.  
  651. bool World::isWinner(Player player) const
  652. {
  653. for (unsigned int i = 0; i < DIM; i++)
  654. {
  655. // Check horizontals
  656. if (mTiles[i].getOwner() == player &&
  657. mTiles[i + 3].getOwner() == player &&
  658. mTiles[i + 6].getOwner() == player)
  659. return true;
  660.  
  661. // Check verticals
  662. if (mTiles[3 * i].getOwner() == player &&
  663. mTiles[1 + 3 * i].getOwner() == player &&
  664. mTiles[2 + 3 * i].getOwner() == player)
  665. return true;
  666. }
  667.  
  668. // Check diagonals
  669. if (mTiles[0].getOwner() == player &&
  670. mTiles[4].getOwner() == player &&
  671. mTiles[8].getOwner() == player)
  672. return true;
  673.  
  674. if (mTiles[6].getOwner() == player &&
  675. mTiles[4].getOwner() == player &&
  676. mTiles[2].getOwner() == player)
  677. return true;
  678.  
  679. return false;
  680. }
  681.  
  682. class Game : private sf::NonCopyable
  683. {
  684. public:
  685. Game();
  686. void run();
  687.  
  688. private:
  689. void processEvents();
  690. void update();
  691. void render();
  692.  
  693. sf::RenderWindow mWindow;
  694.  
  695. FontHolder mFont;
  696. sf::Text mText;
  697. sf::Text mTitle;
  698.  
  699. World mWorld;
  700. std::array<Player, NUMBER_OF_PLAYERS> mPlayers;
  701. unsigned mPlayer;
  702. };
  703.  
  704. Game::Game()
  705. : mWindow(sf::VideoMode(WINDOW_SIZE.x, WINDOW_SIZE.y), "Tic Tac Toe - SFML")
  706. , mFont()
  707. , mText()
  708. , mTitle()
  709. , mWorld(mWindow)
  710. , mPlayers({ { Player::User, Player::Computer } })
  711. , mPlayer()
  712. {
  713. mWindow.setVerticalSyncEnabled(true);
  714.  
  715. mFont.load(Fonts::Main, "Sansation.ttf");
  716. mText.setFont(mFont.get(Fonts::Main));
  717. mText.setStyle(sf::Text::Bold);
  718. mText.setCharacterSize(20);
  719. mText.setFillColor(sf::Color::White);
  720. mText.setPosition(30.f, mWindow.getSize().y - 50.f);
  721. centerOrigin(mText);
  722.  
  723. mTitle.setString("Colourful Tic Tac Toe");
  724. mTitle.setFont(mFont.get(Fonts::Main));
  725. mTitle.setStyle(sf::Text::Bold);
  726. mTitle.setCharacterSize(30);
  727. mTitle.setFillColor(sf::Color::White);
  728. mTitle.setPosition(mWindow.getSize().x * 0.5f, 50.f);
  729. centerOrigin(mTitle);
  730. }
  731.  
  732. void Game::run()
  733. {
  734. while (mWindow.isOpen())
  735. {
  736. processEvents();
  737. update();
  738. render();
  739. }
  740. }
  741.  
  742. void Game::processEvents()
  743. {
  744. sf::Event event;
  745.  
  746. while (mWindow.pollEvent(event))
  747. {
  748. if (event.type == sf::Event::Closed)
  749. mWindow.close();
  750. }
  751. }
  752.  
  753. void Game::update()
  754. {
  755. static bool winner = false;
  756.  
  757. if (winner)
  758. {
  759. mText.setString("The Winner: " + std::string((mPlayers[mPlayer] == Player::User) ? "Blues" : "Reds"));
  760. return;
  761. }
  762.  
  763. if (mWorld.isFull())
  764. {
  765. mText.setString("*** Tie ***");
  766. return;
  767. }
  768.  
  769. switch (mPlayers[mPlayer])
  770. {
  771. case Player::User:
  772. if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
  773. {
  774. sf::Vector2i position = sf::Mouse::getPosition(mWindow);
  775.  
  776. if (position.x > START_POINT.x &&
  777. position.y > START_POINT.y &&
  778. position.x < (START_POINT.x + (DIM*SIZE)) &&
  779. position.y < (START_POINT.y + (DIM*SIZE)))
  780. {
  781. unsigned row = static_cast<unsigned>((position.y - START_POINT.y) / SIZE);
  782. unsigned col = static_cast<unsigned>((position.x - START_POINT.x) / SIZE);
  783.  
  784. if (mWorld.applyMove(mPlayers[mPlayer], row, col)) {
  785. winner = mWorld.isWinner(mPlayers[mPlayer]);
  786. if (!winner) {
  787. mPlayer ^= 1;
  788. }
  789. }
  790. }
  791. }
  792. break;
  793. case Player::Computer:
  794. if (mWorld.applyAl(mPlayers[mPlayer])) {
  795. winner = mWorld.isWinner(mPlayers[mPlayer]);
  796. if (!winner) {
  797. mPlayer ^= 1;
  798. }
  799. }
  800. break;
  801. }
  802. }
  803.  
  804. void Game::render()
  805. {
  806. mWindow.clear();
  807. mWorld.draw();
  808. mWindow.draw(mTitle);
  809. mWindow.draw(mText);
  810. mWindow.display();
  811. }
  812.  
  813. int main()
  814. {
  815. try
  816. {
  817. Game game;
  818. game.run();
  819. }
  820. catch (std::runtime_error& e)
  821. {
  822. std::cout << "\nException: " << e.what() << std::endl;
  823. return 1;
  824. }
  825. }
Add Comment
Please, Sign In to add comment