<commit_before>/*!
 * \file rect_atlas.cpp
 * \brief file rect_atlas.cpp
 *
 * Adapted from: WRATHAtlasBase.cpp and WRATHAtlas.cpp of WRATH:
 *
 * Copyright 2013 by Nomovok Ltd.
 * Contact: info@nomovok.com
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with
 * this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 *
 * \author Kevin Rogovin <kevin.rogovin@nomovok.com>
 * \author Kevin Rogovin <kevin.rogovin@intel.com>
 *
 */

#include <algorithm>
#include <ciso646>

#include "rect_atlas.hpp"

namespace
{
  enum tree_size_t
    {
      num_rects,
      num_with_children,
      num_without_children,

      tree_size_count
    };

  typedef fastuidraw::vecN<int, tree_size_count> TreeSizeCount;

  /*
   * Tree structure to construct the texture atlas,
   * basic idea is very simple: walk the tree until one finds
   * a node where the image can fit.
   *
   * if .second is routine_fail, then the routine
   * failed.
   *
   * If .first of the return value of add or remove
   * is not the same as the object, then the return value
   * represents a new child and the old object should be deleted.
   *
   * if .first of the return value of add or remove
   * is the same as the object, then the routine succeeded
   * and the object should not be deleted.
   */
  class tree_base
  {
  public:
    typedef fastuidraw::detail::RectAtlas::rectangle rectangle;
    typedef fastuidraw::ivec2 ivec2;
    typedef fastuidraw::detail::SimplePool<4096> SimplePool;

    tree_base(const ivec2 &bl, const ivec2 &sz):
      m_minX_minY(bl), m_size(sz),
      m_free_area(m_size.x() * m_size.y())
    {}

    const ivec2&
    size(void) const
    {
      return m_size;
    }

    int
    free_area(void) const
    {
      return m_free_area;
    }

    int
    area(void) const
    {
      return m_size.x() * m_size.y();
    }

    const ivec2&
    minX_minY(void) const
    {
      return m_minX_minY;
    }

    virtual
    TreeSizeCount
    count(void) const = 0;

    tree_base*
    add(SimplePool &pool, rectangle *rect);

  private:
    /*
     * A return value of nullptr indicates failure;
     * a return value of non-null but different, means
     * change pointer to callee.
     */
    virtual
    tree_base*
    add_implement(SimplePool&, rectangle*) = 0;

    ivec2 m_minX_minY, m_size;
    int m_free_area;
  };

  /* a tree_node_without_children represents
   * a Node which has NO child Node's
   * but may or maynot have a rectangle.
   */
  class tree_node_without_children:public tree_base
  {
  public:
    tree_node_without_children(const ivec2 &bl, const ivec2 &sz,
                               rectangle *rect = nullptr);

    rectangle*
    data(void);

    virtual
    TreeSizeCount
    count(void) const
    {
      TreeSizeCount return_value;

      return_value[num_rects] = (m_rectangle) ? 1u : 0u;
      return_value[num_with_children] = 0;
      return_value[num_without_children] = 1;

      return return_value;
    }

  private:
    virtual
    tree_base*
    add_implement (SimplePool&, rectangle*);

    rectangle *m_rectangle;
  };

  /* a tree node with children has _3_ children.
   * they are spawned when a tree_node_wihout_children
   * has a rectangle added but it already has a rectangle.
   */
  class tree_node_with_children:public tree_base
  {
  public:
    tree_node_with_children(SimplePool &pool,
                            tree_node_without_children *src,
                            bool split_x, bool split_y);

    virtual
    TreeSizeCount
    count(void) const
    {
      TreeSizeCount return_value;

      return_value[num_rects] = 0u;
      return_value[num_with_children] = 1;
      return_value[num_without_children] = 0;

      return return_value
        + m_children[0]->count()
        + m_children[1]->count()
        + m_children[2]->count();
    }

  private:
    virtual
    tree_base*
    add_implement (SimplePool&, rectangle*);

    fastuidraw::vecN<tree_base*, 3> m_children;
  };

  class tree_sorter
  {
  public:
    bool
    operator()(tree_base *lhs, tree_base *rhs) const
    {
      /* we want to list the smallest "size" first
       * to avoid splitting large elements
       */
      return lhs->area() < rhs->area();
    }
  };
}

////////////////////////////////
// tree_base methods
tree_base*
tree_base::
add(SimplePool &pool, rectangle *rect)
{
  /* We are doing a very, very simple quick rejection
   * test where we reject any rectangle which has
   * area larger than this's area() or if any of the
   * dimensions are greater than this's size. This
   * is far from ideal, and the correct thing would be
   * to create bins (perhaps keyed by log2) in each
   * dimension to quickly choose a node to split.
   * This would prevent the tree walk entirely and
   * then the root would need a list of nodes
   * available and the ability to remove elements
   * from the lists fast (perhaps std::map<K, std::list>)
   * would work. Only the creation of objects of
   * type tree_node_without_children would modify the
   * list, as would their deconsuction.
   */
  FASTUIDRAWassert(m_free_area >= 0);
  if (rect->area() <= m_free_area
      && rect->size().x() <= m_size.x()
      && rect->size().y() <= m_size.y())
    {
      tree_base *return_value;
      return_value = add_implement(pool, rect);
      if (return_value)
        {
          m_free_area -= rect->area();
        }

      return return_value;
    }
  else
    {
      return nullptr;
    }
}

//////////////////////////////////////
// tree_node_without_children methods
tree_node_without_children::
tree_node_without_children(const ivec2 &bl, const ivec2 &sz,
                           rectangle *rect):
  tree_base(bl, sz),
  m_rectangle(rect)
{
}

tree_base::rectangle*
tree_node_without_children::
data(void)
{
  return m_rectangle;
}

tree_base*
tree_node_without_children::
add_implement(SimplePool &pool, rectangle *im)
{
  FASTUIDRAWassert(im->size().x() <= size().x());
  FASTUIDRAWassert(im->size().y() <= size().y());

  if (m_rectangle == nullptr)
    {
      //do not have a rect so we take it (and move it).
      m_rectangle = im;
      m_rectangle->move(minX_minY());

      return this;
    }

  //we have a rectangle already, we need to check
  //if we can split in such a way to take im:
  int dx, dy;
  bool split_y_works, split_x_works;

  dx = size().x() - m_rectangle->size().x();
  dy = size().y() - m_rectangle->size().y();

  split_y_works = (dy >= im->size().y());
  split_x_works = (dx >= im->size().x());

  if (!split_x_works && !split_y_works)
    {
      return nullptr;
    }

  if (split_x_works && split_y_works)
    {
      //choose a split that is nicest
      //by making the other split false.

      //whoever has the most room left over is the split.
      if (dx > dy)
        {
          split_y_works = false;
        }
      else
        {
          split_x_works = false;
        }
    }

  tree_base *new_node;

  //new_node will hold this->m_rectange:
  new_node = pool.create<tree_node_with_children>(pool, this, split_x_works, split_y_works);

  //add the new rectangle im to new_node:
  new_node = new_node->add(pool, im);
  FASTUIDRAWassert(new_node);

  return new_node;
}

////////////////////////////////////
// tree_node_with_children methods
tree_node_with_children::
tree_node_with_children(SimplePool &pool,
                        tree_node_without_children *src,
                        bool split_x_works, bool split_y_works):
  tree_base(src->minX_minY(), src->size()),
  m_children(nullptr, nullptr, nullptr)
{
  rectangle *R(src->data());
  FASTUIDRAWassert(R != nullptr);

  m_children[2] = pool.create<tree_node_without_children>(R->minX_minY(), R->size(), R);

  /* Perhaps we should consider delaying creating m_children[0] and m_children[1]
   * until the first request come to this to add a rectangle so that we can
   * possibly take a bigger rectangle.
   */
  if (split_x_works)
    {
      m_children[0]
        = pool.create<tree_node_without_children>(ivec2(minX_minY().x(), minX_minY().y() + R->size().y()),
                                                  ivec2(R->size().x(), size().y() - R->size().y()) );

      m_children[1]
        = pool.create<tree_node_without_children>(ivec2(minX_minY().x() + R->size().x(), minX_minY().y()),
                                                  ivec2(size().x() - R->size().x(), size().y()) );
    }
  else
    {
      FASTUIDRAWassert(split_y_works);
      FASTUIDRAWunused(split_y_works);

      m_children[0]
        = pool.create<tree_node_without_children>(ivec2(minX_minY().x() + R->size().x(), minX_minY().y()),
                                                  ivec2(size().x() - R->size().x(), R->size().y()) );

      m_children[1]
        = pool.create<tree_node_without_children>(ivec2(minX_minY().x(), minX_minY().y() + R->size().y()),
                                                  ivec2(size().x(), size().y() - R->size().y()) );
    }

  std::sort(m_children.begin(), m_children.end(), tree_sorter());
}

tree_base*
tree_node_with_children::
add_implement(SimplePool &pool, rectangle *im)
{
  tree_base *R;
  for(int i = 0; i < 3; ++i)
    {
      R = m_children[i]->add(pool, im);
      if (R)
        {
          m_children[i] = R;
          return this;
        }
    }

  return nullptr;
}

////////////////////////////////////
// fastuidraw::detail::RectAtlas methods
fastuidraw::detail::RectAtlas::
RectAtlas(const ivec2 &dimensions):
  m_empty_rect(ivec2(0, 0))
{
  m_data = m_pool.create<tree_node_without_children>(ivec2(0,0), dimensions, nullptr);
}

fastuidraw::detail::RectAtlas::
~RectAtlas()
{
}

fastuidraw::ivec2
fastuidraw::detail::RectAtlas::
size(void) const
{
  tree_base *root;
  root = static_cast<tree_base*>(m_data);
  FASTUIDRAWassert(root != nullptr);
  return root->size();
}

void
fastuidraw::detail::RectAtlas::
clear(void)
{
  ivec2 dimensions(size());

  tree_base *root;
  root = static_cast<tree_base*>(m_data);

  /**
  std::cout << "Clear: " << root->count()
            << ", free_area = " << root->free_area()
            << "(" << 100.0f * static_cast<float>(root->free_area()) / static_cast<float>(root->area()) << "%)"
            << "\n";
  /**/

  m_pool.clear();
  m_data = m_pool.create<tree_node_without_children>(ivec2(0,0), dimensions, nullptr);
}

const fastuidraw::detail::RectAtlas::rectangle*
fastuidraw::detail::RectAtlas::
add_rectangle(const ivec2 &dimensions)
{
  rectangle *return_value(nullptr);
  tree_base *root, *R;

  root = static_cast<tree_base*>(m_data);
  if (dimensions.x() > 0 && dimensions.y() > 0)
    {
      //attempt to add the rect:
      return_value = m_pool.create<rectangle>(dimensions);
      R = root->add(m_pool, return_value);

      if (R)
        {
          root = R;
        }
      else
        {
          return_value = nullptr;
        }
    }
  else
    {
      return_value = &m_empty_rect;
    }

  m_data = root;
  return return_value;
}
<commit_msg>fastuidraw/private/rect_atlas: improve performance<commit_after>/*!
 * \file rect_atlas.cpp
 * \brief file rect_atlas.cpp
 *
 * Adapted from: WRATHAtlasBase.cpp and WRATHAtlas.cpp of WRATH:
 *
 * Copyright 2013 by Nomovok Ltd.
 * Contact: info@nomovok.com
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with
 * this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 *
 * \author Kevin Rogovin <kevin.rogovin@nomovok.com>
 * \author Kevin Rogovin <kevin.rogovin@intel.com>
 *
 */

#include <algorithm>
#include <ciso646>

#include "rect_atlas.hpp"

namespace
{
  enum tree_size_t
    {
      num_rects,
      num_with_children,
      num_without_children,

      tree_size_count
    };

  class tree_node_without_children;
  typedef fastuidraw::vecN<int, tree_size_count> TreeSizeCount;

  /*
   * Tree structure to construct the texture atlas,
   * basic idea is very simple: walk the tree until one finds
   * a node where the image can fit.
   *
   * if .second is routine_fail, then the routine
   * failed.
   *
   * If .first of the return value of add or remove
   * is not the same as the object, then the return value
   * represents a new child and the old object should be deleted.
   *
   * if .first of the return value of add or remove
   * is the same as the object, then the routine succeeded
   * and the object should not be deleted.
   */
  class tree_base
  {
  public:
    typedef fastuidraw::detail::RectAtlas::rectangle rectangle;
    typedef fastuidraw::ivec2 ivec2;
    typedef fastuidraw::detail::SimplePool<4096> SimplePool;

    tree_base(const ivec2 &bl, const ivec2 &sz):
      m_minX_minY(bl), m_size(sz)
    {}

    const ivec2&
    size(void) const
    {
      return m_size;
    }

    int
    area(void) const
    {
      return m_size.x() * m_size.y();
    }

    const ivec2&
    minX_minY(void) const
    {
      return m_minX_minY;
    }

    tree_node_without_children*
    widest_possible_rectangle(void) { return m_widest; }

    tree_node_without_children*
    tallest_possible_rectangle(void) { return m_tallest; }

    tree_node_without_children*
    biggest_possible_rectangle(void) { return m_biggest; }

    virtual
    TreeSizeCount
    count(void) const = 0;

    tree_base*
    add(SimplePool &pool, rectangle *rect);

  protected:
    tree_node_without_children *m_widest, *m_tallest, *m_biggest;

  private:
    /*
     * A return value of nullptr indicates failure;
     * a return value of non-null but different, means
     * change pointer to callee.
     */
    virtual
    tree_base*
    add_implement(SimplePool&, rectangle*) = 0;

    ivec2 m_minX_minY, m_size;
  };

  /* a tree_node_without_children represents
   * a Node which has NO child Node's
   * but may or maynot have a rectangle.
   */
  class tree_node_without_children:public tree_base
  {
  public:
    tree_node_without_children(const ivec2 &bl, const ivec2 &sz,
                               rectangle *rect = nullptr);

    rectangle*
    data(void);

    int
    widest_possible(void) const
    {
      return size().x();
    }

    int
    tallest_possible(void) const
    {
      return size().y();
    }

    int
    biggest_possible(void) const
    {
      int A(area());

      return m_rectangle ?
        A - m_rectangle->area() :
        A;
    }

    virtual
    TreeSizeCount
    count(void) const
    {
      TreeSizeCount return_value;

      return_value[num_rects] = (m_rectangle) ? 1u : 0u;
      return_value[num_with_children] = 0;
      return_value[num_without_children] = 1;

      return return_value;
    }

  private:
    virtual
    tree_base*
    add_implement(SimplePool&, rectangle*);

    rectangle *m_rectangle;
  };

  /* a tree node with children has _3_ children.
   * they are spawned when a tree_node_wihout_children
   * has a rectangle added but it already has a rectangle.
   */
  class tree_node_with_children:public tree_base
  {
  public:
    tree_node_with_children(SimplePool &pool,
                            tree_node_without_children *src,
                            bool split_x, bool split_y);

    virtual
    TreeSizeCount
    count(void) const
    {
      TreeSizeCount return_value;

      return_value[num_rects] = 0u;
      return_value[num_with_children] = 1;
      return_value[num_without_children] = 0;

      return return_value
        + m_children[0]->count()
        + m_children[1]->count()
        + m_children[2]->count();
    }

  private:
    virtual
    tree_base*
    add_implement(SimplePool&, rectangle*);

    void
    recompute_possible(void);

    fastuidraw::vecN<tree_base*, 3> m_children;
  };

  class tree_sorter
  {
  public:
    bool
    operator()(tree_base *lhs, tree_base *rhs) const
    {
      /* we want to list the smallest "size" first
       * to avoid splitting large elements
       */
      return lhs->area() < rhs->area();
    }
  };
}

////////////////////////////////
// tree_base methods
tree_base*
tree_base::
add(SimplePool &pool, rectangle *rect)
{
  /* We are doing a very, very simple quick rejection
   * test where we reject any rectangle which has
   * area larger than this's area() or if any of the
   * dimensions are greater than this's size. This
   * is far from ideal, and the correct thing would be
   * to create bins (perhaps keyed by log2) in each
   * dimension to quickly choose a node to split.
   * This would prevent the tree walk entirely and
   * then the root would need a list of nodes
   * available and the ability to remove elements
   * from the lists fast (perhaps std::map<K, std::list>)
   * would work. Only the creation of objects of
   * type tree_node_without_children would modify the
   * list, as would their deconsuction.
   */
  if (rect->area() <= biggest_possible_rectangle()->biggest_possible()
      && rect->size().x() <= widest_possible_rectangle()->widest_possible()
      && rect->size().y() <= tallest_possible_rectangle()->tallest_possible())
    {
      tree_base *return_value;

      return_value = add_implement(pool, rect);
      return return_value;
    }
  else
    {
      return nullptr;
    }
}

//////////////////////////////////////
// tree_node_without_children methods
tree_node_without_children::
tree_node_without_children(const ivec2 &bl, const ivec2 &sz,
                           rectangle *rect):
  tree_base(bl, sz),
  m_rectangle(rect)
{
  m_widest = m_tallest = m_biggest = this;
}

tree_base::rectangle*
tree_node_without_children::
data(void)
{
  return m_rectangle;
}

tree_base*
tree_node_without_children::
add_implement(SimplePool &pool, rectangle *im)
{
  FASTUIDRAWassert(im->size().x() <= size().x());
  FASTUIDRAWassert(im->size().y() <= size().y());

  if (m_rectangle == nullptr)
    {
      //do not have a rect so we take it (and move it).
      m_rectangle = im;
      m_rectangle->move(minX_minY());

      return this;
    }

  //we have a rectangle already, we need to check
  //if we can split in such a way to take im:
  int dx, dy;
  bool split_y_works, split_x_works;

  dx = size().x() - m_rectangle->size().x();
  dy = size().y() - m_rectangle->size().y();

  split_y_works = (dy >= im->size().y());
  split_x_works = (dx >= im->size().x());

  if (!split_x_works && !split_y_works)
    {
      return nullptr;
    }

  if (split_x_works && split_y_works)
    {
      //choose a split that is nicest
      //by making the other split false.

      //whoever has the most room left over is the split.
      if (dx > dy)
        {
          split_y_works = false;
        }
      else
        {
          split_x_works = false;
        }
    }

  tree_base *new_node;

  //new_node will hold this->m_rectange:
  new_node = pool.create<tree_node_with_children>(pool, this, split_x_works, split_y_works);

  //add the new rectangle im to new_node:
  new_node = new_node->add(pool, im);
  FASTUIDRAWassert(new_node);

  return new_node;
}

////////////////////////////////////
// tree_node_with_children methods
tree_node_with_children::
tree_node_with_children(SimplePool &pool,
                        tree_node_without_children *src,
                        bool split_x_works, bool split_y_works):
  tree_base(src->minX_minY(), src->size()),
  m_children(nullptr, nullptr, nullptr)
{
  rectangle *R(src->data());
  FASTUIDRAWassert(R != nullptr);

  m_children[2] = pool.create<tree_node_without_children>(R->minX_minY(), R->size(), R);

  /* Perhaps we should consider delaying creating m_children[0] and m_children[1]
   * until the first request come to this to add a rectangle so that we can
   * possibly take a bigger rectangle.
   */
  if (split_x_works)
    {
      m_children[0]
        = pool.create<tree_node_without_children>(ivec2(minX_minY().x(), minX_minY().y() + R->size().y()),
                                                  ivec2(R->size().x(), size().y() - R->size().y()) );

      m_children[1]
        = pool.create<tree_node_without_children>(ivec2(minX_minY().x() + R->size().x(), minX_minY().y()),
                                                  ivec2(size().x() - R->size().x(), size().y()) );
    }
  else
    {
      FASTUIDRAWassert(split_y_works);
      FASTUIDRAWunused(split_y_works);

      m_children[0]
        = pool.create<tree_node_without_children>(ivec2(minX_minY().x() + R->size().x(), minX_minY().y()),
                                                  ivec2(size().x() - R->size().x(), R->size().y()) );

      m_children[1]
        = pool.create<tree_node_without_children>(ivec2(minX_minY().x(), minX_minY().y() + R->size().y()),
                                                  ivec2(size().x(), size().y() - R->size().y()) );
    }

  std::sort(m_children.begin(), m_children.end(), tree_sorter());
  recompute_possible();
}

tree_base*
tree_node_with_children::
add_implement(SimplePool &pool, rectangle *im)
{
  tree_base *R;
  for(int i = 0; i < 3; ++i)
    {
      R = m_children[i]->add(pool, im);
      if (R)
        {
          m_children[i] = R;
          recompute_possible();
          return this;
        }
    }

  return nullptr;
}

void
tree_node_with_children::
recompute_possible(void)
{
  m_widest = m_children[0]->widest_possible_rectangle();
  m_tallest = m_children[0]->tallest_possible_rectangle();
  m_biggest = m_children[0]->biggest_possible_rectangle();

  for (int i = 1; i < 3; ++i)
    {
      tree_node_without_children *p;

      p = m_children[i]->widest_possible_rectangle();
      if (p->widest_possible() > m_widest->widest_possible())
        {
          m_widest = p;
        }

      p = m_children[i]->tallest_possible_rectangle();
      if (p->tallest_possible() > m_tallest->tallest_possible())
        {
          m_tallest = p;
        }

      p = m_children[i]->biggest_possible_rectangle();
      if (p->biggest_possible() > m_biggest->biggest_possible())
        {
          m_biggest = p;
        }
    }
}

////////////////////////////////////
// fastuidraw::detail::RectAtlas methods
fastuidraw::detail::RectAtlas::
RectAtlas(const ivec2 &dimensions):
  m_empty_rect(ivec2(0, 0))
{
  m_data = m_pool.create<tree_node_without_children>(ivec2(0,0), dimensions, nullptr);
}

fastuidraw::detail::RectAtlas::
~RectAtlas()
{
}

fastuidraw::ivec2
fastuidraw::detail::RectAtlas::
size(void) const
{
  tree_base *root;
  root = static_cast<tree_base*>(m_data);
  FASTUIDRAWassert(root != nullptr);
  return root->size();
}

void
fastuidraw::detail::RectAtlas::
clear(void)
{
  ivec2 dimensions(size());

  tree_base *root;
  root = static_cast<tree_base*>(m_data);

  /**
  std::cout << "Clear: " << root->count()
            << ", free_area = " << root->free_area()
            << "(" << 100.0f * static_cast<float>(root->free_area()) / static_cast<float>(root->area()) << "%)"
            << "\n";
  /**/

  m_pool.clear();
  m_data = m_pool.create<tree_node_without_children>(ivec2(0,0), dimensions, nullptr);
}

const fastuidraw::detail::RectAtlas::rectangle*
fastuidraw::detail::RectAtlas::
add_rectangle(const ivec2 &dimensions)
{
  rectangle *return_value(nullptr);
  tree_base *root, *R;

  root = static_cast<tree_base*>(m_data);
  if (dimensions.x() > 0 && dimensions.y() > 0)
    {
      //attempt to add the rect:
      return_value = m_pool.create<rectangle>(dimensions);
      R = root->add(m_pool, return_value);

      if (R)
        {
          root = R;
        }
      else
        {
          return_value = nullptr;
        }
    }
  else
    {
      return_value = &m_empty_rect;
    }

  m_data = root;
  return return_value;
}
<|endoftext|>


<commit_before>// Copyright 2008 Paul Hodge

#include <iostream>
#include <fstream>

#include "common_headers.h"

#include "ast.h"
#include "branch.h"
#include "builtins.h"
#include "builtin_types.h"
#include "cpp_interface.h"
#include "function.h"
#include "importing.h"
#include "list.h"
#include "parser.h"
#include "runtime.h"
#include "term.h"
#include "token_stream.h"
#include "type.h"
#include "values.h"
#include "setup_builtin_functions.h"

namespace circa {

Branch* KERNEL = NULL;
Term* VAR_FUNCTION_GENERATOR = NULL;
Term* VAR_FUNCTION_FEEDBACK_ASSIGN = NULL;
Term* INT_TYPE = NULL;
Term* FLOAT_TYPE = NULL;
Term* BOOL_TYPE = NULL;
Term* STRING_TYPE = NULL;
Term* TYPE_TYPE = NULL;
Term* FUNCTION_TYPE = NULL;
Term* CODEUNIT_TYPE = NULL;
Term* BRANCH_TYPE = NULL;
Term* ANY_TYPE = NULL;
Term* VOID_TYPE = NULL;
Term* REFERENCE_TYPE = NULL;
Term* LIST_TYPE = NULL;
Term* MAP_TYPE = NULL;
Term* VAR_INT = NULL;
Term* VAR_FLOAT = NULL;
Term* VAR_STRING = NULL;
Term* VAR_BOOL = NULL;
Term* CONSTANT_0 = NULL;
Term* CONSTANT_1 = NULL;
Term* CONSTANT_2 = NULL;
Term* CONSTANT_TRUE = NULL;
Term* CONSTANT_FALSE = NULL;
Term* UNKNOWN_FUNCTION = NULL;
Term* APPLY_FEEDBACK = NULL;
Term* ADD_FUNC = NULL;
Term* MULT_FUNC = NULL;

void empty_evaluate_function(Term*) { }
void empty_alloc_function(Term*) { }

void var_function_generator(Term* caller)
{
    assert(caller->input(0) != NULL);

    Function& output = as_function(caller);
    Type& type = as_type(caller->input(0));
    output.name = "var-" + type.name;
    output.outputType = caller->input(0);
    output.pureFunction = false;
    output.evaluate = empty_evaluate_function;
    output.feedbackPropogateFunction = VAR_FUNCTION_FEEDBACK_ASSIGN;
}

Term* get_global(std::string name)
{
    if (KERNEL->containsName(name))
        return KERNEL->getNamed(name);

    return NULL;
}

void bootstrap_kernel()
{
    // This is a crazy function. We need to create the 5 core functions in our system,
    // all of which need to reference each other or themselves.
    //
    // Here is what we need to create:
    //
    // var-function-generator(Type) -> Function
    //    Given a type, returns a function which is a 'plain value' function. This term
    //    has function const-Function.
    // const-Type() -> Type
    //    Function which returns a Type value. This is created by var-function-generator
    // const-Function() -> Function
    //    Function which returns a Function value. This is created by var-function-generator.
    // Type Function
    //    Stores the Type object for functions. This term has function const-Type
    // Type Type
    //    Stores the Type object for types. This term has function const-Type

    KERNEL = new Branch();

    // Create var-function-generator function
    VAR_FUNCTION_GENERATOR = new Term();
    VAR_FUNCTION_GENERATOR->owningBranch = KERNEL;
    VAR_FUNCTION_GENERATOR->value = new Function();
    as_function(VAR_FUNCTION_GENERATOR).name = "var-function-generator";
    as_function(VAR_FUNCTION_GENERATOR).pureFunction = true;
    as_function(VAR_FUNCTION_GENERATOR).evaluate = var_function_generator;
    KERNEL->bindName(VAR_FUNCTION_GENERATOR, "var-function-generator");

    // Create const-Type function
    Term* constTypeFunc = new Term();
    constTypeFunc->owningBranch = KERNEL;
    constTypeFunc->function = VAR_FUNCTION_GENERATOR;
    constTypeFunc->value = new Function();
    as_function(constTypeFunc).name = "const-Type";
    as_function(constTypeFunc).pureFunction = true;

    // Create Type type
    TYPE_TYPE = new Term();
    TYPE_TYPE->owningBranch = KERNEL;
    TYPE_TYPE->function = constTypeFunc;
    TYPE_TYPE->type = TYPE_TYPE;
    initialize_type_type(TYPE_TYPE);
    as_type(TYPE_TYPE).remapPointers = Type::typeRemapPointers;
    as_type(TYPE_TYPE).visitPointers = Type::typeVisitPointers;
    KERNEL->bindName(TYPE_TYPE, "Type");

    // Implant the Type type
    set_input(constTypeFunc, 0, TYPE_TYPE);
    as_function(VAR_FUNCTION_GENERATOR).inputTypes.setAt(0, TYPE_TYPE);
    as_function(constTypeFunc).outputType = TYPE_TYPE;

    // Create const-Function function
    Term* constFuncFunc = new Term();
    constFuncFunc->owningBranch = KERNEL;
    constFuncFunc->function = VAR_FUNCTION_GENERATOR;
    constFuncFunc->value = new Function();
    as_function(constFuncFunc).name = "const-Function";
    as_function(constFuncFunc).pureFunction = true;
    KERNEL->bindName(constFuncFunc, "const-Function");

    // Implant const-Function
    VAR_FUNCTION_GENERATOR->function = constFuncFunc;

    // Create Function type
    FUNCTION_TYPE = new Term();
    FUNCTION_TYPE->owningBranch = KERNEL;
    FUNCTION_TYPE->function = constTypeFunc;
    FUNCTION_TYPE->type = TYPE_TYPE;
    FUNCTION_TYPE->value = alloc_from_type(TYPE_TYPE);
    as_type(FUNCTION_TYPE).name = "Function";
    as_type(FUNCTION_TYPE).alloc = cpp_interface::templated_alloc<Function>;
    as_type(FUNCTION_TYPE).duplicate = Function::duplicate;
    as_type(FUNCTION_TYPE).dealloc = cpp_interface::templated_dealloc<Function>;
    as_type(FUNCTION_TYPE).remapPointers = Function::remapPointers;
    as_type(FUNCTION_TYPE).visitPointers = Function::visitPointers;
    KERNEL->bindName(FUNCTION_TYPE, "Function");

    // Implant Function type
    set_input(VAR_FUNCTION_GENERATOR, 0, TYPE_TYPE);
    set_input(constFuncFunc, 0, FUNCTION_TYPE);
    VAR_FUNCTION_GENERATOR->type = FUNCTION_TYPE;
    constFuncFunc->type = FUNCTION_TYPE;
    constTypeFunc->type = FUNCTION_TYPE;
    as_function(VAR_FUNCTION_GENERATOR).outputType = FUNCTION_TYPE;
    as_function(constFuncFunc).outputType = FUNCTION_TYPE;

    // Don't let these terms get updated
    VAR_FUNCTION_GENERATOR->needsUpdate = false;
    constFuncFunc->needsUpdate = false;
    constTypeFunc->needsUpdate = false;
    FUNCTION_TYPE->needsUpdate = false;
    TYPE_TYPE->needsUpdate = false;
}

void unknown_function__evaluate(Term* caller)
{
    std::cout << "Warning, calling an unknown function: "
        << as_string(caller->state) << std::endl;
}

namespace var_function {

    void feedback_assign(Term* caller)
    {
        Term* target = caller->input(0);
        Term* desired = caller->input(1);

        duplicate_value(desired, target);
    }
}

void initialize_constants()
{
    BRANCH_TYPE = quick_create_cpp_type<Branch>(*KERNEL, "Branch");
    as_type(BRANCH_TYPE).remapPointers = Branch::hosted_remap_pointers;
    as_type(BRANCH_TYPE).visitPointers = Branch::hosted_visit_pointers;

    LIST_TYPE = quick_create_cpp_type<List>(*KERNEL, "List");
    as_type(LIST_TYPE).toString = List__toString;

    quick_create_cpp_type<Dictionary>(*KERNEL, "Dictionary");

    VAR_INT = get_var_function(*KERNEL, INT_TYPE);
    VAR_FLOAT = get_var_function(*KERNEL, FLOAT_TYPE);
    VAR_STRING = get_var_function(*KERNEL, STRING_TYPE);
    VAR_BOOL = get_var_function(*KERNEL, BOOL_TYPE);

    CONSTANT_0 = float_var(*KERNEL, 0);
    CONSTANT_1 = float_var(*KERNEL, 1);
    CONSTANT_2 = float_var(*KERNEL, 2);

    CONSTANT_TRUE = apply_function(*KERNEL, BOOL_TYPE, ReferenceList());
    as_bool(CONSTANT_TRUE) = true;
    KERNEL->bindName(CONSTANT_TRUE, "true");
    CONSTANT_FALSE = apply_function(*KERNEL, BOOL_TYPE, ReferenceList());
    as_bool(CONSTANT_FALSE) = false;
    KERNEL->bindName(CONSTANT_FALSE, "false");

    Term* pi = apply_function(*KERNEL, FLOAT_TYPE, ReferenceList());
    as_float(pi) = 3.14159;
    KERNEL->bindName(pi, "PI");

    Term* tokenStreamType =
        quick_create_cpp_type<token_stream::TokenStream>(*KERNEL, "TokenStream");
    register_cpp_toString<token_stream::TokenStream>(tokenStreamType);
}

void initialize_builtin_functions(Branch* kernel)
{
    setup_builtin_functions(*kernel);

    ADD_FUNC = kernel->getNamed("add");
    MULT_FUNC = kernel->getNamed("mult");

    assert(ADD_FUNC != NULL);
    assert(MULT_FUNC != NULL);

    UNKNOWN_FUNCTION = quick_create_function(kernel, "unknown-function",
            unknown_function__evaluate,
            ReferenceList(ANY_TYPE), ANY_TYPE);
    as_function(UNKNOWN_FUNCTION).stateType = STRING_TYPE;

    VAR_FUNCTION_FEEDBACK_ASSIGN = quick_create_function(kernel, "var-function-feedback-assign",
        var_function::feedback_assign,
        ReferenceList(ANY_TYPE, ANY_TYPE), VOID_TYPE);

    as_function(VAR_INT).feedbackPropogateFunction = VAR_FUNCTION_FEEDBACK_ASSIGN;
    as_function(VAR_FLOAT).feedbackPropogateFunction = VAR_FUNCTION_FEEDBACK_ASSIGN;
    as_function(VAR_BOOL).feedbackPropogateFunction = VAR_FUNCTION_FEEDBACK_ASSIGN;
    as_function(VAR_STRING).feedbackPropogateFunction = VAR_FUNCTION_FEEDBACK_ASSIGN;
}

void initialize()
{
    bootstrap_kernel();
    initialize_builtin_types(*KERNEL);
    initialize_constants();
    initialize_list_functions(KERNEL);

    // Then everything else:
    initialize_builtin_functions(KERNEL);
    initialize_functions(KERNEL);
}

void shutdown()
{
    delete KERNEL;
    KERNEL = NULL;
}

Term* get_var_function(Branch& branch, Term* type)
{
    Term* result = apply_function(branch, VAR_FUNCTION_GENERATOR, ReferenceList(type));
    evaluate_term(result);
    return result;
}

} // namespace circa
<commit_msg>Fix problem where values were being stolen from some constants<commit_after>// Copyright 2008 Paul Hodge

#include <iostream>
#include <fstream>

#include "common_headers.h"

#include "ast.h"
#include "branch.h"
#include "builtins.h"
#include "builtin_types.h"
#include "cpp_interface.h"
#include "function.h"
#include "importing.h"
#include "list.h"
#include "parser.h"
#include "runtime.h"
#include "term.h"
#include "token_stream.h"
#include "type.h"
#include "values.h"
#include "setup_builtin_functions.h"

namespace circa {

Branch* KERNEL = NULL;
Term* VAR_FUNCTION_GENERATOR = NULL;
Term* VAR_FUNCTION_FEEDBACK_ASSIGN = NULL;
Term* INT_TYPE = NULL;
Term* FLOAT_TYPE = NULL;
Term* BOOL_TYPE = NULL;
Term* STRING_TYPE = NULL;
Term* TYPE_TYPE = NULL;
Term* FUNCTION_TYPE = NULL;
Term* CODEUNIT_TYPE = NULL;
Term* BRANCH_TYPE = NULL;
Term* ANY_TYPE = NULL;
Term* VOID_TYPE = NULL;
Term* REFERENCE_TYPE = NULL;
Term* LIST_TYPE = NULL;
Term* MAP_TYPE = NULL;
Term* VAR_INT = NULL;
Term* VAR_FLOAT = NULL;
Term* VAR_STRING = NULL;
Term* VAR_BOOL = NULL;
Term* CONSTANT_0 = NULL;
Term* CONSTANT_1 = NULL;
Term* CONSTANT_2 = NULL;
Term* CONSTANT_TRUE = NULL;
Term* CONSTANT_FALSE = NULL;
Term* UNKNOWN_FUNCTION = NULL;
Term* APPLY_FEEDBACK = NULL;
Term* ADD_FUNC = NULL;
Term* MULT_FUNC = NULL;

void empty_evaluate_function(Term*) { }
void empty_alloc_function(Term*) { }

void var_function_generator(Term* caller)
{
    assert(caller->input(0) != NULL);

    Function& output = as_function(caller);
    Type& type = as_type(caller->input(0));
    output.name = "var-" + type.name;
    output.outputType = caller->input(0);
    output.pureFunction = false;
    output.evaluate = empty_evaluate_function;
    output.feedbackPropogateFunction = VAR_FUNCTION_FEEDBACK_ASSIGN;
}

Term* get_global(std::string name)
{
    if (KERNEL->containsName(name))
        return KERNEL->getNamed(name);

    return NULL;
}

void bootstrap_kernel()
{
    // This is a crazy function. We need to create the 5 core functions in our system,
    // all of which need to reference each other or themselves.
    //
    // Here is what we need to create:
    //
    // var-function-generator(Type) -> Function
    //    Given a type, returns a function which is a 'plain value' function. This term
    //    has function const-Function.
    // const-Type() -> Type
    //    Function which returns a Type value. This is created by var-function-generator
    // const-Function() -> Function
    //    Function which returns a Function value. This is created by var-function-generator.
    // Type Function
    //    Stores the Type object for functions. This term has function const-Type
    // Type Type
    //    Stores the Type object for types. This term has function const-Type

    KERNEL = new Branch();

    // Create var-function-generator function
    VAR_FUNCTION_GENERATOR = new Term();
    VAR_FUNCTION_GENERATOR->owningBranch = KERNEL;
    VAR_FUNCTION_GENERATOR->value = new Function();
    as_function(VAR_FUNCTION_GENERATOR).name = "var-function-generator";
    as_function(VAR_FUNCTION_GENERATOR).pureFunction = true;
    as_function(VAR_FUNCTION_GENERATOR).evaluate = var_function_generator;
    KERNEL->bindName(VAR_FUNCTION_GENERATOR, "var-function-generator");

    // Create const-Type function
    Term* constTypeFunc = new Term();
    constTypeFunc->owningBranch = KERNEL;
    constTypeFunc->function = VAR_FUNCTION_GENERATOR;
    constTypeFunc->value = new Function();
    as_function(constTypeFunc).name = "const-Type";
    as_function(constTypeFunc).pureFunction = true;

    // Create Type type
    TYPE_TYPE = new Term();
    TYPE_TYPE->owningBranch = KERNEL;
    TYPE_TYPE->function = constTypeFunc;
    TYPE_TYPE->type = TYPE_TYPE;
    initialize_type_type(TYPE_TYPE);
    as_type(TYPE_TYPE).remapPointers = Type::typeRemapPointers;
    as_type(TYPE_TYPE).visitPointers = Type::typeVisitPointers;
    KERNEL->bindName(TYPE_TYPE, "Type");

    // Implant the Type type
    set_input(constTypeFunc, 0, TYPE_TYPE);
    as_function(VAR_FUNCTION_GENERATOR).inputTypes.setAt(0, TYPE_TYPE);
    as_function(constTypeFunc).outputType = TYPE_TYPE;

    // Create const-Function function
    Term* constFuncFunc = new Term();
    constFuncFunc->owningBranch = KERNEL;
    constFuncFunc->function = VAR_FUNCTION_GENERATOR;
    constFuncFunc->value = new Function();
    as_function(constFuncFunc).name = "const-Function";
    as_function(constFuncFunc).pureFunction = true;
    KERNEL->bindName(constFuncFunc, "const-Function");

    // Implant const-Function
    VAR_FUNCTION_GENERATOR->function = constFuncFunc;

    // Create Function type
    FUNCTION_TYPE = new Term();
    FUNCTION_TYPE->owningBranch = KERNEL;
    FUNCTION_TYPE->function = constTypeFunc;
    FUNCTION_TYPE->type = TYPE_TYPE;
    FUNCTION_TYPE->value = alloc_from_type(TYPE_TYPE);
    as_type(FUNCTION_TYPE).name = "Function";
    as_type(FUNCTION_TYPE).alloc = cpp_interface::templated_alloc<Function>;
    as_type(FUNCTION_TYPE).duplicate = Function::duplicate;
    as_type(FUNCTION_TYPE).dealloc = cpp_interface::templated_dealloc<Function>;
    as_type(FUNCTION_TYPE).remapPointers = Function::remapPointers;
    as_type(FUNCTION_TYPE).visitPointers = Function::visitPointers;
    KERNEL->bindName(FUNCTION_TYPE, "Function");

    // Implant Function type
    set_input(VAR_FUNCTION_GENERATOR, 0, TYPE_TYPE);
    set_input(constFuncFunc, 0, FUNCTION_TYPE);
    VAR_FUNCTION_GENERATOR->type = FUNCTION_TYPE;
    constFuncFunc->type = FUNCTION_TYPE;
    constTypeFunc->type = FUNCTION_TYPE;
    as_function(VAR_FUNCTION_GENERATOR).outputType = FUNCTION_TYPE;
    as_function(constFuncFunc).outputType = FUNCTION_TYPE;

    // Don't let these terms get updated
    VAR_FUNCTION_GENERATOR->needsUpdate = false;
    constFuncFunc->needsUpdate = false;
    constTypeFunc->needsUpdate = false;
    FUNCTION_TYPE->needsUpdate = false;
    TYPE_TYPE->needsUpdate = false;
}

void unknown_function__evaluate(Term* caller)
{
    std::cout << "Warning, calling an unknown function: "
        << as_string(caller->state) << std::endl;
}

namespace var_function {

    void feedback_assign(Term* caller)
    {
        Term* target = caller->input(0);
        Term* desired = caller->input(1);

        duplicate_value(desired, target);
    }
}

void initialize_constants()
{
    BRANCH_TYPE = quick_create_cpp_type<Branch>(*KERNEL, "Branch");
    as_type(BRANCH_TYPE).remapPointers = Branch::hosted_remap_pointers;
    as_type(BRANCH_TYPE).visitPointers = Branch::hosted_visit_pointers;

    LIST_TYPE = quick_create_cpp_type<List>(*KERNEL, "List");
    as_type(LIST_TYPE).toString = List__toString;

    quick_create_cpp_type<Dictionary>(*KERNEL, "Dictionary");

    VAR_INT = get_var_function(*KERNEL, INT_TYPE);
    VAR_FLOAT = get_var_function(*KERNEL, FLOAT_TYPE);
    VAR_STRING = get_var_function(*KERNEL, STRING_TYPE);
    VAR_BOOL = get_var_function(*KERNEL, BOOL_TYPE);

    CONSTANT_0 = float_var(*KERNEL, 0);
    CONSTANT_1 = float_var(*KERNEL, 1);
    CONSTANT_2 = float_var(*KERNEL, 2);

    CONSTANT_TRUE = apply_function(*KERNEL, BOOL_TYPE, ReferenceList());
    as_bool(CONSTANT_TRUE) = true;
    CONSTANT_TRUE->stealingOk = false;
    KERNEL->bindName(CONSTANT_TRUE, "true");

    CONSTANT_FALSE = apply_function(*KERNEL, BOOL_TYPE, ReferenceList());
    as_bool(CONSTANT_FALSE) = false;
    CONSTANT_FALSE->stealingOk = false;
    KERNEL->bindName(CONSTANT_FALSE, "false");

    Term* pi = apply_function(*KERNEL, FLOAT_TYPE, ReferenceList());
    as_float(pi) = 3.14159;
    KERNEL->bindName(pi, "PI");

    Term* tokenStreamType =
        quick_create_cpp_type<token_stream::TokenStream>(*KERNEL, "TokenStream");
    register_cpp_toString<token_stream::TokenStream>(tokenStreamType);
}

void initialize_builtin_functions(Branch* kernel)
{
    setup_builtin_functions(*kernel);

    ADD_FUNC = kernel->getNamed("add");
    MULT_FUNC = kernel->getNamed("mult");

    assert(ADD_FUNC != NULL);
    assert(MULT_FUNC != NULL);

    UNKNOWN_FUNCTION = quick_create_function(kernel, "unknown-function",
            unknown_function__evaluate,
            ReferenceList(ANY_TYPE), ANY_TYPE);
    as_function(UNKNOWN_FUNCTION).stateType = STRING_TYPE;

    VAR_FUNCTION_FEEDBACK_ASSIGN = quick_create_function(kernel, "var-function-feedback-assign",
        var_function::feedback_assign,
        ReferenceList(ANY_TYPE, ANY_TYPE), VOID_TYPE);

    as_function(VAR_INT).feedbackPropogateFunction = VAR_FUNCTION_FEEDBACK_ASSIGN;
    as_function(VAR_FLOAT).feedbackPropogateFunction = VAR_FUNCTION_FEEDBACK_ASSIGN;
    as_function(VAR_BOOL).feedbackPropogateFunction = VAR_FUNCTION_FEEDBACK_ASSIGN;
    as_function(VAR_STRING).feedbackPropogateFunction = VAR_FUNCTION_FEEDBACK_ASSIGN;
}

void initialize()
{
    bootstrap_kernel();
    initialize_builtin_types(*KERNEL);
    initialize_constants();
    initialize_list_functions(KERNEL);

    // Then everything else:
    initialize_builtin_functions(KERNEL);
    initialize_functions(KERNEL);
}

void shutdown()
{
    delete KERNEL;
    KERNEL = NULL;
}

Term* get_var_function(Branch& branch, Term* type)
{
    Term* result = apply_function(branch, VAR_FUNCTION_GENERATOR, ReferenceList(type));
    evaluate_term(result);
    return result;
}

} // namespace circa
<|endoftext|>


<commit_before>#include "Ant.hpp"
#include "../nav/Node.hpp"
#include "../nav/NavGraphHelper.hpp"
#include "../worldobject/AntHome.hpp"
#include "../goal/AntGoal.hpp"
#include "../goal/AntEat.hpp"
#include "../goal/AntForage.hpp"
#include "../goal/AntExplore.hpp"
#include "../goal/AntMoveToNode.hpp"
#include "../util/make_unique.hpp"
#include "../knowledge/Percept.hpp"
#include "../knowledge/AntPercept.hpp"

#include <iostream>

// Christopher D. Canfield
// October 2013
// Ant.cpp

using cdc::Ant;
using cdc::Percept;
using cdc::GuiEventManager;
using cdc::Node;
using cdc::NavGraphHelper;
using cdc::AntHome;
using cdc::AntGoal;
using cdc::AntMoveToNode;

using std::unique_ptr;
using std::cout;
using std::endl;
using std::move;

bool Ant::wasTextureLoaded = false;
sf::Texture* Ant::texture = nullptr;
sf::Texture* Ant::textureDead = nullptr;
sf::Texture* Ant::textureWithFood = nullptr;

Ant::Ant(GuiEventManager& manager, AntHome& home, NavGraphHelper& graphHelper, const Node& startNode) :
		Button(manager),
		kb(home, graphHelper),
		isSelected(false)
{
	if (!Ant::wasTextureLoaded)
	{
		if (Ant::texture == nullptr)
		{
			Ant::texture = new sf::Texture;
			Ant::textureWithFood = new sf::Texture;
			Ant::textureDead = new sf::Texture;
		}

		if (!Ant::texture->loadFromFile("res/ant.png"))
		{
			std::cout << "Unable to load ant image: res/ant.png" << std::endl;
		}
		if (!Ant::textureWithFood->loadFromFile("res/ant - holding food.png"))
		{
			std::cout << "Unable to load ant image: res/ant - holding food.png" << std::endl;
		}
		if (!Ant::textureDead->loadFromFile("res/ant - dead.png"));
		{
			std::cout << "Unable to load ant image: res/ant - dead.png";
		}
		Ant::wasTextureLoaded = true;
	}

	auto antSprite = make_unique<sf::Sprite>(*Ant::texture);
	setDefaultImage(std::move(antSprite));
	setOriginToCenter();

	deadAntSprite.setTexture(*Ant::textureDead, true);
	deadAntSprite.setOrigin(deadAntSprite.getGlobalBounds().width / 1.9f, deadAntSprite.getGlobalBounds().height / 1.9f);
	antWithFoodSprite.setTexture(*Ant::textureWithFood, true);
	antWithFoodSprite.setOrigin(antWithFoodSprite.getGlobalBounds().width / 1.9f, antWithFoodSprite.getGlobalBounds().height / 1.9f);

	// Ants don't need to know about mouse move events.
	manager.removeMouseMoveListener(*this);
	manager.addDirectMouseMoveListener(*this);

	manager.addClickListener(*this);

	goal = make_unique<AntForage>();
	setPositionToNode(startNode);
}

Ant::Ant(Ant&& other) :
	Button(move(other)),
	kb(move(other.kb)),
	stats(other.stats),
	goal(move(other.goal)),
	isSelected(other.isSelected),
	deadAntSprite(other.deadAntSprite)
{
}

Ant::~Ant()
{
}

void Ant::update(uint ticks, const Percept& percept)
{
	if (!isDead())
	{
		processHunger(ticks, stats);
		if (stats.isHoldingFood)
		{
			antWithFoodSprite.setPosition(getPosition());
			antWithFoodSprite.setRotation(getRotation());
		}

		// Process the goal if one is set, or set a new one if not.
		if (!goal->isFinished())
		{
			auto antPercept = AntPercept(percept);
			goal->update(*this, ticks, antPercept);
		}
		else
		{
			goal = getNewGoal(stats);
		}
	}
}

void Ant::setPositionToNode(const Node& node)
{
	kb.lastNodePassed = const_cast<Node*>(&node);
	setPosition(node.getPixelX<int>(), node.getPixelY<int>());
}

const Node* Ant::popLastKnownFoodPosition()
{
	if (!kb.lastKnownFoodPosition.empty())
	{
		auto mostRecent = kb.lastKnownFoodPosition.front();
		kb.lastKnownFoodPosition.pop_front();
		return mostRecent;
	}
	else
	{
		return nullptr;
	}
}

uint Ant::getHunger() const
{
	return stats.hunger;
}

AntHome& Ant::getHome() const
{
	return kb.home;
}

bool Ant::isDead() const
{
	return stats.isDead;
}

void Ant::kill()
{
	onDeath();
}

Node& Ant::getNode() const
{
	return *kb.lastNodePassed;
}

void Ant::onDirectGuiEvent(const sf::Event& e)
{
	if (e.type == sf::Event::MouseButtonReleased && !isSelected)
	{
		isSelected = true;
		selectedTimer.restart();
		cout << "Ant " << getObserverId().toString() << " selected" << endl;
		cout << "  Hunger: " << stats.hunger << "% | " << (!isDead() ? "Is Alive" : "Is Dead") << endl;
		cout << "  Current Goal: " << goal->toString() << endl;
	}
}

void Ant::onGuiEvent(const sf::Event& e)
{
	if (e.type == sf::Event::MouseButtonReleased && isSelected && selectedTimer.getElapsedTime().asMilliseconds() > 300)
	{
		isSelected = false;
	}
}

void Ant::draw(sf::RenderTarget &target, sf::RenderStates states) const
{
	if (isDead())
	{
		target.draw(deadAntSprite, states);
	}
	else if (stats.isHoldingFood)
	{
		target.draw(antWithFoodSprite, states);
	}
	else
	{
		Button::draw(target, states);
	}

	if (isSelected && goal != nullptr)
	{
		goal->drawPath(target, states, this->getNode());
	}
}

////// Private & protected methods //////

void Ant::onDeath()
{
	if (!stats.isDead)
	{
		if (isSelected) cout << "  Ant " << getObserverId().toString() << " has died" << endl;
		stats.isDead = true;
		deadAntSprite.setPosition(getPosition());
		deadAntSprite.setRotation(getRotation());
	}
}

void Ant::processHunger(uint ticks, AntStats& stats)
{
	if (ticks >= stats.nextHungerIncrease)
	{
		if (stats.hunger >= stats.maxHunger)
		{
			// The ant has starved to death.
			onDeath();
		}
		else
		{
			++stats.hunger;
			if (isSelected) cout << "  Hunger: " << stats.hunger << endl;
			// Modify the hunger increase rate by between 0.65 and 1.35, to
			// differentiate the behaviors of the ants.
			float modifier = random.getInteger(65, 135) / 100.f;
			stats.nextHungerIncrease += static_cast<uint>(stats.hungerIncreaseRate * modifier);
		}
	}
}

void Ant::setAntWithFoodSpritePosition(float x, float y, float rotation)
{
	antWithFoodSprite.setPosition(x, y);
	antWithFoodSprite.setRotation(rotation);
}

unique_ptr<AntGoal> Ant::getNewGoal(AntStats& stats)
{
	using std::move;
	// Higher = hungrier when the ant starts looking for food to eat.
	const uint hungry = 60;

	// Look for food if hungry. This takes priority over other potential goals.
	if (stats.hunger > hungry)
	{
		auto newGoal = unique_ptr<AntEat>(new AntEat());
		if (isSelected) cout << "  Goal changed: " << newGoal->toString() << endl;
		return move(newGoal);
	}

	// The chance that the ant will explore rather than forage, from 1 to 100.
	const int exploreChance = 1;
	int decision = random.getInteger(1, 100);
	if (decision <= exploreChance)
	{
		auto newGoal = unique_ptr<AntExplore>(new AntExplore());
		if (isSelected) cout << "  Goal changed: " << newGoal->toString() << endl;
		return move(newGoal);
	}
	else
	{
		auto newGoal = unique_ptr<AntForage>(new AntForage());
		if (isSelected) cout << "  Goal changed: " << newGoal->toString() << endl;
		return move(newGoal);
	}
}

////// Struct constructors //////

Ant::AntKnowledgeBase::AntKnowledgeBase(AntHome& home, NavGraphHelper& graphHelper) :
	home(home),
	navGraphHelper(graphHelper),
	// Up to four food piles are remembered by the ant.
	lastKnownFoodPosition(4),
	lastNodePassed(nullptr)
{
}

Ant::AntStats::AntStats() :
	hungerIncreaseRate(180),	// default ticks per second is 60, so this gives a rate of 3 seconds per increase in hunger.
	hunger(0),
	nextHungerIncrease(hungerIncreaseRate),
	maxHunger(100),
	isHoldingFood(false),
	isDead(false),
	movementSpeed(3.5f)
{
}<commit_msg>Minor hunger formatting fix<commit_after>#include "Ant.hpp"
#include "../nav/Node.hpp"
#include "../nav/NavGraphHelper.hpp"
#include "../worldobject/AntHome.hpp"
#include "../goal/AntGoal.hpp"
#include "../goal/AntEat.hpp"
#include "../goal/AntForage.hpp"
#include "../goal/AntExplore.hpp"
#include "../goal/AntMoveToNode.hpp"
#include "../util/make_unique.hpp"
#include "../knowledge/Percept.hpp"
#include "../knowledge/AntPercept.hpp"

#include <iostream>

// Christopher D. Canfield
// October 2013
// Ant.cpp

using cdc::Ant;
using cdc::Percept;
using cdc::GuiEventManager;
using cdc::Node;
using cdc::NavGraphHelper;
using cdc::AntHome;
using cdc::AntGoal;
using cdc::AntMoveToNode;

using std::unique_ptr;
using std::cout;
using std::endl;
using std::move;

bool Ant::wasTextureLoaded = false;
sf::Texture* Ant::texture = nullptr;
sf::Texture* Ant::textureDead = nullptr;
sf::Texture* Ant::textureWithFood = nullptr;

Ant::Ant(GuiEventManager& manager, AntHome& home, NavGraphHelper& graphHelper, const Node& startNode) :
		Button(manager),
		kb(home, graphHelper),
		isSelected(false)
{
	if (!Ant::wasTextureLoaded)
	{
		if (Ant::texture == nullptr)
		{
			Ant::texture = new sf::Texture;
			Ant::textureWithFood = new sf::Texture;
			Ant::textureDead = new sf::Texture;
		}

		if (!Ant::texture->loadFromFile("res/ant.png"))
		{
			std::cout << "Unable to load ant image: res/ant.png" << std::endl;
		}
		if (!Ant::textureWithFood->loadFromFile("res/ant - holding food.png"))
		{
			std::cout << "Unable to load ant image: res/ant - holding food.png" << std::endl;
		}
		if (!Ant::textureDead->loadFromFile("res/ant - dead.png"));
		{
			std::cout << "Unable to load ant image: res/ant - dead.png";
		}
		Ant::wasTextureLoaded = true;
	}

	auto antSprite = make_unique<sf::Sprite>(*Ant::texture);
	setDefaultImage(std::move(antSprite));
	setOriginToCenter();

	deadAntSprite.setTexture(*Ant::textureDead, true);
	deadAntSprite.setOrigin(deadAntSprite.getGlobalBounds().width / 1.9f, deadAntSprite.getGlobalBounds().height / 1.9f);
	antWithFoodSprite.setTexture(*Ant::textureWithFood, true);
	antWithFoodSprite.setOrigin(antWithFoodSprite.getGlobalBounds().width / 1.9f, antWithFoodSprite.getGlobalBounds().height / 1.9f);

	// Ants don't need to know about mouse move events.
	manager.removeMouseMoveListener(*this);
	manager.addDirectMouseMoveListener(*this);

	manager.addClickListener(*this);

	goal = make_unique<AntForage>();
	setPositionToNode(startNode);
}

Ant::Ant(Ant&& other) :
	Button(move(other)),
	kb(move(other.kb)),
	stats(other.stats),
	goal(move(other.goal)),
	isSelected(other.isSelected),
	deadAntSprite(other.deadAntSprite)
{
}

Ant::~Ant()
{
}

void Ant::update(uint ticks, const Percept& percept)
{
	if (!isDead())
	{
		processHunger(ticks, stats);
		if (stats.isHoldingFood)
		{
			antWithFoodSprite.setPosition(getPosition());
			antWithFoodSprite.setRotation(getRotation());
		}

		// Process the goal if one is set, or set a new one if not.
		if (!goal->isFinished())
		{
			auto antPercept = AntPercept(percept);
			goal->update(*this, ticks, antPercept);
		}
		else
		{
			goal = getNewGoal(stats);
		}
	}
}

void Ant::setPositionToNode(const Node& node)
{
	kb.lastNodePassed = const_cast<Node*>(&node);
	setPosition(node.getPixelX<int>(), node.getPixelY<int>());
}

const Node* Ant::popLastKnownFoodPosition()
{
	if (!kb.lastKnownFoodPosition.empty())
	{
		auto mostRecent = kb.lastKnownFoodPosition.front();
		kb.lastKnownFoodPosition.pop_front();
		return mostRecent;
	}
	else
	{
		return nullptr;
	}
}

uint Ant::getHunger() const
{
	return stats.hunger;
}

AntHome& Ant::getHome() const
{
	return kb.home;
}

bool Ant::isDead() const
{
	return stats.isDead;
}

void Ant::kill()
{
	onDeath();
}

Node& Ant::getNode() const
{
	return *kb.lastNodePassed;
}

void Ant::onDirectGuiEvent(const sf::Event& e)
{
	if (e.type == sf::Event::MouseButtonReleased && !isSelected)
	{
		isSelected = true;
		selectedTimer.restart();
		cout << "Ant " << getObserverId().toString() << " selected" << endl;
		cout << "  Hunger: " << stats.hunger << "% | " << (!isDead() ? "Is Alive" : "Is Dead") << endl;
		cout << "  Current Goal: " << goal->toString() << endl;
	}
}

void Ant::onGuiEvent(const sf::Event& e)
{
	if (e.type == sf::Event::MouseButtonReleased && isSelected && selectedTimer.getElapsedTime().asMilliseconds() > 300)
	{
		isSelected = false;
	}
}

void Ant::draw(sf::RenderTarget &target, sf::RenderStates states) const
{
	if (isDead())
	{
		target.draw(deadAntSprite, states);
	}
	else if (stats.isHoldingFood)
	{
		target.draw(antWithFoodSprite, states);
	}
	else
	{
		Button::draw(target, states);
	}

	if (isSelected && goal != nullptr)
	{
		goal->drawPath(target, states, this->getNode());
	}
}

////// Private & protected methods //////

void Ant::onDeath()
{
	if (!stats.isDead)
	{
		if (isSelected) cout << "  Ant " << getObserverId().toString() << " has died" << endl;
		stats.isDead = true;
		deadAntSprite.setPosition(getPosition());
		deadAntSprite.setRotation(getRotation());
	}
}

void Ant::processHunger(uint ticks, AntStats& stats)
{
	if (ticks >= stats.nextHungerIncrease)
	{
		if (stats.hunger >= stats.maxHunger)
		{
			// The ant has starved to death.
			onDeath();
		}
		else
		{
			++stats.hunger;
			if (isSelected) cout << "  Hunger: " << stats.hunger << "%" << endl;
			// Modify the hunger increase rate by between 0.65 and 1.35, to
			// differentiate the behaviors of the ants.
			float modifier = random.getInteger(65, 135) / 100.f;
			stats.nextHungerIncrease += static_cast<uint>(stats.hungerIncreaseRate * modifier);
		}
	}
}

void Ant::setAntWithFoodSpritePosition(float x, float y, float rotation)
{
	antWithFoodSprite.setPosition(x, y);
	antWithFoodSprite.setRotation(rotation);
}

unique_ptr<AntGoal> Ant::getNewGoal(AntStats& stats)
{
	using std::move;
	// Higher = hungrier when the ant starts looking for food to eat.
	const uint hungry = 60;

	// Look for food if hungry. This takes priority over other potential goals.
	if (stats.hunger > hungry)
	{
		auto newGoal = unique_ptr<AntEat>(new AntEat());
		if (isSelected) cout << "  Goal changed: " << newGoal->toString() << endl;
		return move(newGoal);
	}

	// The chance that the ant will explore rather than forage, from 1 to 100.
	const int exploreChance = 1;
	int decision = random.getInteger(1, 100);
	if (decision <= exploreChance)
	{
		auto newGoal = unique_ptr<AntExplore>(new AntExplore());
		if (isSelected) cout << "  Goal changed: " << newGoal->toString() << endl;
		return move(newGoal);
	}
	else
	{
		auto newGoal = unique_ptr<AntForage>(new AntForage());
		if (isSelected) cout << "  Goal changed: " << newGoal->toString() << endl;
		return move(newGoal);
	}
}

////// Struct constructors //////

Ant::AntKnowledgeBase::AntKnowledgeBase(AntHome& home, NavGraphHelper& graphHelper) :
	home(home),
	navGraphHelper(graphHelper),
	// Up to four food piles are remembered by the ant.
	lastKnownFoodPosition(4),
	lastNodePassed(nullptr)
{
}

Ant::AntStats::AntStats() :
	hungerIncreaseRate(180),	// default ticks per second is 60, so this gives a rate of 3 seconds per increase in hunger.
	hunger(0),
	nextHungerIncrease(hungerIncreaseRate),
	maxHunger(100),
	isHoldingFood(false),
	isDead(false),
	movementSpeed(3.5f)
{
}<|endoftext|>


<commit_before>/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2008, Willow Garage, Inc.
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the Willow Garage nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/

// This file is originally ported from ROS1:
// https://github.com/ros/common_msgs/blob/89069bc/sensor_msgs/include/sensor_msgs/fill_image.h

#ifndef FILLIMAGE_HH
#define FILLIMAGE_HH

#include "sensor_msgs/Image.h"
#include "sensor_msgs/image_encodings.h"

namespace sensor_msgs
{

  static inline bool fillImage(Image& image,
                 const std::string& encoding_arg,
                 uint32_t rows_arg,
                 uint32_t cols_arg,
                 uint32_t step_arg,
                 const void* data_arg)
  {
    image.encoding = encoding_arg;
    image.height   = rows_arg;
    image.width    = cols_arg;
    image.step     = step_arg;
    size_t st0 = (step_arg * rows_arg);
    image.data.resize(st0);
    memcpy(&image.data[0], data_arg, st0);

    image.is_bigendian = 0;
    return true;
  }

  static inline void clearImage(Image& image)
  {
    image.data.resize(0);
  }
}

#endif

<commit_msg>ROS 2 port: conform to linters and add documentation<commit_after>// Copyright (c) 2008, Willow Garage, Inc.
// All rights reserved.
//
// Software License Agreement (BSD License 2.0)
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//  * Redistributions in binary form must reproduce the above
//    copyright notice, this list of conditions and the following
//    disclaimer in the documentation and/or other materials provided
//    with the distribution.
//  * Neither the name of the Willow Garage nor the names of its
//    contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// This file is originally ported from ROS1:
// https://github.com/ros/common_msgs/blob/89069bc/sensor_msgs/include/sensor_msgs/fill_image.h

#ifndef SENSOR_MSGS__FILL_IMAGE_HPP_
#define SENSOR_MSGS__FILL_IMAGE_HPP_

#include <string>

#include "sensor_msgs/msg/image.hpp"
#include "sensor_msgs/image_encodings.hpp"

namespace sensor_msgs
{
/// Fill an image message.
/**
 * \param[out] image Image to be filled.
 * \param[in] encoding_arg Encoding type, such as sensor_msgs::image_encodings::RGB8.
 * \param[in] rows_arg Number of rows.
 * \param[in] cols_arg Number of columns.
 * \param[in] step_arg Step size.
 * \param[in] data_arg Data to fill image with.
 * \return True if successful.
 */
static inline bool fillImage(
  msg::Image & image,
  const std::string & encoding_arg,
  uint32_t rows_arg,
  uint32_t cols_arg,
  uint32_t step_arg,
  const void * data_arg)
{
  image.encoding = encoding_arg;
  image.height = rows_arg;
  image.width = cols_arg;
  image.step = step_arg;
  size_t st0 = (step_arg * rows_arg);
  image.data.resize(st0);
  memcpy(&image.data[0], data_arg, st0);

  image.is_bigendian = 0;
  return true;
}

/// Clear the data of an image message.
/**
 * \details All fields but `data` are kept the same.
 * \param[out]image Image to be cleared.
 */
static inline void clearImage(msg::Image & image)
{
  image.data.resize(0);
}
}  // namespace sensor_msgs

#endif  // SENSOR_MSGS__FILL_IMAGE_HPP_
<|endoftext|>


<commit_before>#include <boost/functional/hash/hash.hpp>

#include <deque>
#include <unordered_set>
#include <vector>

#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>

int board[5][4] = {
//  0  1  2  3
  { 1, 2, 2, 3, },   // 0
  { 1, 2, 2, 3, },   // 1
  { 4, 5, 5, 6, },   // 2
  { 4, 7, 8, 6, },   // 3
  { 9, 0, 0, 10 } }; // 4

struct Mask;

const int kRows = 5;
const int kColumns = 4;
const int kBlocks = 10;

enum class Shape // : int8_t
{
  kInvalid,
  kSingle,
  kHorizon,
  kVertical,
  kSquare,
};

struct Block
{
  Shape shape;
  int left, top;  // int8_t

  Block()
    : shape(Shape::kInvalid),
      left(-1),
      top(-1)
  {
  }

  Block(Shape s, int left, int top)
    : shape(s),
      left(left),
      top(top)
  {
    assert(shape != Shape::kInvalid);
    assert(left >= 0 && left < kColumns);
    assert(top >= 0 && top < kRows);
  }

  int bottom() const
  {
    const static int delta[] = { 0, 0, 0, 1, 1, };
    assert(shape != Shape::kInvalid);
    return top + delta[static_cast<int>(shape)];
  }

  int right() const
  {
    const static int delta[] = { 0, 0, 1, 0, 1, };
    assert(shape != Shape::kInvalid);
    return left + delta[static_cast<int>(shape)];
  }

  void mask(int8_t value, Mask* mask) const;
};

struct Mask
{
  Mask()
  {
    bzero(board_, sizeof(board_));
  }

  bool operator==(const Mask& rhs) const
  {
    return memcmp(board_, rhs.board_, sizeof board_) == 0;
  }

  size_t hashValue() const
  {
    const int8_t* begin = board_[0];
    return boost::hash_range(begin, begin + sizeof(board_));
  }

  void print() const
  {
    for (int i = 0; i < kRows; ++i)
    {
      for (int j = 0; j < kColumns; ++j)
      {
        printf(" %c", board_[i][j] + '0');
      }
      printf("\n");
    }
  }

  void set(int8_t value, int y, int x)
  {
    assert(value > 0);
    assert(x >= 0 && x < kColumns);
    assert(y >= 0 && y < kRows);
    assert(board_[y][x] == 0);
    board_[y][x] = value;
  }

  bool empty(int y, int x) const
  {
    assert(x >= 0 && x < kColumns);
    assert(y >= 0 && y < kRows);
    return board_[y][x] == 0;
  }

 private:
  int8_t board_[kRows][kColumns];
};

namespace std
{
  template<> struct hash<Mask>
  {
    size_t operator()(const Mask& x) const
    {
      return x.hashValue();
    }
  };
}

inline void Block::mask(int8_t value, Mask* mask) const
{
  mask->set(value, top, left);
  switch (shape)
  {
    case Shape::kHorizon:
      mask->set(value, top, left+1);
      break;
    case Shape::kVertical:
      mask->set(value, top+1, left);
      break;
    case Shape::kSquare:
      mask->set(value, top, left+1);
      mask->set(value, top+1, left);
      mask->set(value, top+1, left+1);
      break;
    default:
      assert(shape == Shape::kSingle);
      ;
  }
}

struct State
{
  Mask toMask() const
  {
    Mask m;
    for (int i = 0; i < kBlocks; ++i)
    {
      Block b = blocks_[i];
      b.mask(static_cast<int>(b.shape), &m);
    }
    return m;
  }

  bool isSolved() const
  {
    // FIXME: magic number
    Block square = blocks_[1];
    assert(square.shape == Shape::kSquare);
    return (square.left == 1 && square.top == 3);
  }

  template<typename FUNC>
  void move(const FUNC& func) const
  {
    if (0)
    {
      std::function<void(const State&)> typecheck = func;
    }
    const Mask mask = toMask();

    for (int i = 0; i < kBlocks; ++i)
    {
      Block b = blocks_[i];
      if (b.top > 0 && mask.empty(b.top-1, b.left))
      {
        bool moveUp = false;
        if (b.shape == Shape::kHorizon || b.shape == Shape::kSquare)
        {
          if (mask.empty(b.top-1, b.left+1))
            moveUp = true;
        }
        else
          moveUp = true;
        if (moveUp)
        {
          State next = *this;
          next.step++;
          next.blocks_[i].top--;
          func(next);
        }
      }

      if (b.bottom() < kRows-1 && mask.empty(b.bottom()+1, b.left))
      {
        bool moveDown = false;
        if (b.shape == Shape::kHorizon || b.shape == Shape::kSquare)
        {
          if (mask.empty(b.bottom()+1, b.left+1))
            moveDown = true;
        }
        else
          moveDown = true;
        if (moveDown)
        {
          State next = *this;
          next.step++;
          next.blocks_[i].top++;
          func(next);
        }
      }

      if (b.left > 0 && mask.empty(b.top, b.left-1))
      {
        bool moveLeft = false;
        if (b.shape == Shape::kVertical || b.shape == Shape::kSquare)
        {
          if (mask.empty(b.top+1, b.left-1))
            moveLeft = true;
        }
        else
          moveLeft = true;
        if (moveLeft)
        {
          State next = *this;
          next.step++;
          next.blocks_[i].left--;
          func(next);
        }
      }

      if (b.right() < kColumns-1 && mask.empty(b.top, b.right()+1))
      {
        bool moveRight = false;
        if (b.shape == Shape::kVertical || b.shape == Shape::kSquare)
        {
          if (mask.empty(b.top+1, b.right()+1))
            moveRight = true;
        }
        else
          moveRight = true;
        if (moveRight)
        {
          State next = *this;
          next.step++;
          next.blocks_[i].left++;
          func(next);
        }
      }
    }
  }

  // std::vector<State> moves() const;

  Block blocks_[kBlocks];
  int step = 0;
};

int main()
{
  printf("sizeof(Mask) = %zd, sizeof(State) = %zd\n", sizeof(Mask), sizeof(State));
  std::unordered_set<Mask> seen;
  std::deque<State> queue;

  State initial;
  initial.blocks_[0] = Block(Shape::kVertical, 0, 0);
  initial.blocks_[1] = Block(Shape::kSquare,   1, 0);
  initial.blocks_[2] = Block(Shape::kVertical, 3, 0);
  initial.blocks_[3] = Block(Shape::kVertical, 0, 2);
  initial.blocks_[4] = Block(Shape::kHorizon,  1, 2);
  initial.blocks_[5] = Block(Shape::kVertical, 3, 2);
  initial.blocks_[6] = Block(Shape::kSingle, 1, 3);
  initial.blocks_[7] = Block(Shape::kSingle, 2, 3);
  initial.blocks_[8] = Block(Shape::kSingle, 0, 4);
  initial.blocks_[9] = Block(Shape::kSingle, 3, 4);

  queue.push_back(initial);
  seen.insert(initial.toMask());

  while (!queue.empty())
  {
    const State curr = queue.front();
    queue.pop_front();

    if (curr.isSolved())
    {
      printf("found solution with %d steps\n", curr.step);
      break;
    }
    else if (curr.step > 200)
    {
      printf("too many steps.\n");
      break;
    }

    curr.move([&seen, &queue](const State& next) {
      auto result = seen.insert(next.toMask());
      if (result.second)
        queue.push_back(next);
    });

    // for (const State& next : curr.moves())
    // {
    //   auto result = seen.insert(next.toMask());
    //   if (result.second)
    //     queue.push_back(next);
    // }
  }
}
<commit_msg>fix issue #3.<commit_after>#include <boost/functional/hash/hash.hpp>

#include <deque>
#include <type_traits>
#include <unordered_set>
#include <vector>

#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>

int board[5][4] = {
//  0  1  2  3
  { 1, 2, 2, 3, },   // 0
  { 1, 2, 2, 3, },   // 1
  { 4, 5, 5, 6, },   // 2
  { 4, 7, 8, 6, },   // 3
  { 9, 0, 0, 10 } }; // 4

struct Mask;

const int kRows = 5;
const int kColumns = 4;
const int kBlocks = 10;

enum class Shape // : int8_t
{
  kInvalid,
  kSingle,
  kHorizon,
  kVertical,
  kSquare,
};

struct Block
{
  Shape shape;
  int left, top;  // int8_t

  Block()
    : shape(Shape::kInvalid),
      left(-1),
      top(-1)
  {
  }

  Block(Shape s, int left, int top)
    : shape(s),
      left(left),
      top(top)
  {
    assert(shape != Shape::kInvalid);
    assert(left >= 0 && left < kColumns);
    assert(top >= 0 && top < kRows);
  }

  int bottom() const
  {
    const static int delta[] = { 0, 0, 0, 1, 1, };
    assert(shape != Shape::kInvalid);
    return top + delta[static_cast<int>(shape)];
  }

  int right() const
  {
    const static int delta[] = { 0, 0, 1, 0, 1, };
    assert(shape != Shape::kInvalid);
    return left + delta[static_cast<int>(shape)];
  }

  void mask(int8_t value, Mask* mask) const;
};

struct Mask
{
  Mask()
  {
    bzero(board_, sizeof(board_));
  }

  bool operator==(const Mask& rhs) const
  {
    return memcmp(board_, rhs.board_, sizeof board_) == 0;
  }

  size_t hashValue() const
  {
    const int8_t* begin = board_[0];
    return boost::hash_range(begin, begin + sizeof(board_));
  }

  void print() const
  {
    for (int i = 0; i < kRows; ++i)
    {
      for (int j = 0; j < kColumns; ++j)
      {
        printf(" %c", board_[i][j] + '0');
      }
      printf("\n");
    }
  }

  void set(int8_t value, int y, int x)
  {
    assert(value > 0);
    assert(x >= 0 && x < kColumns);
    assert(y >= 0 && y < kRows);
    assert(board_[y][x] == 0);
    board_[y][x] = value;
  }

  bool empty(int y, int x) const
  {
    assert(x >= 0 && x < kColumns);
    assert(y >= 0 && y < kRows);
    return board_[y][x] == 0;
  }

 private:
  int8_t board_[kRows][kColumns];
};

namespace std
{
  template<> struct hash<Mask>
  {
    size_t operator()(const Mask& x) const
    {
      return x.hashValue();
    }
  };
}

inline void Block::mask(int8_t value, Mask* mask) const
{
  mask->set(value, top, left);
  switch (shape)
  {
    case Shape::kHorizon:
      mask->set(value, top, left+1);
      break;
    case Shape::kVertical:
      mask->set(value, top+1, left);
      break;
    case Shape::kSquare:
      mask->set(value, top, left+1);
      mask->set(value, top+1, left);
      mask->set(value, top+1, left+1);
      break;
    default:
      assert(shape == Shape::kSingle);
      ;
  }
}

struct State
{
  Mask toMask() const
  {
    Mask m;
    for (int i = 0; i < kBlocks; ++i)
    {
      Block b = blocks_[i];
      b.mask(static_cast<int>(b.shape), &m);
    }
    return m;
  }

  bool isSolved() const
  {
    // FIXME: magic number
    Block square = blocks_[1];
    assert(square.shape == Shape::kSquare);
    return (square.left == 1 && square.top == 3);
  }

  template<typename FUNC>
  void move(const FUNC& func) const
  {
    static_assert(std::is_convertible<FUNC, std::function<void(const State&)>>::value,
                  "func must be callable with a 'const State&' parameter.");
    const Mask mask = toMask();

    for (int i = 0; i < kBlocks; ++i)
    {
      Block b = blocks_[i];
      if (b.top > 0 && mask.empty(b.top-1, b.left))
      {
        bool moveUp = false;
        if (b.shape == Shape::kHorizon || b.shape == Shape::kSquare)
        {
          if (mask.empty(b.top-1, b.left+1))
            moveUp = true;
        }
        else
          moveUp = true;
        if (moveUp)
        {
          State next = *this;
          next.step++;
          next.blocks_[i].top--;
          func(next);
        }
      }

      if (b.bottom() < kRows-1 && mask.empty(b.bottom()+1, b.left))
      {
        bool moveDown = false;
        if (b.shape == Shape::kHorizon || b.shape == Shape::kSquare)
        {
          if (mask.empty(b.bottom()+1, b.left+1))
            moveDown = true;
        }
        else
          moveDown = true;
        if (moveDown)
        {
          State next = *this;
          next.step++;
          next.blocks_[i].top++;
          func(next);
        }
      }

      if (b.left > 0 && mask.empty(b.top, b.left-1))
      {
        bool moveLeft = false;
        if (b.shape == Shape::kVertical || b.shape == Shape::kSquare)
        {
          if (mask.empty(b.top+1, b.left-1))
            moveLeft = true;
        }
        else
          moveLeft = true;
        if (moveLeft)
        {
          State next = *this;
          next.step++;
          next.blocks_[i].left--;
          func(next);
        }
      }

      if (b.right() < kColumns-1 && mask.empty(b.top, b.right()+1))
      {
        bool moveRight = false;
        if (b.shape == Shape::kVertical || b.shape == Shape::kSquare)
        {
          if (mask.empty(b.top+1, b.right()+1))
            moveRight = true;
        }
        else
          moveRight = true;
        if (moveRight)
        {
          State next = *this;
          next.step++;
          next.blocks_[i].left++;
          func(next);
        }
      }
    }
  }

  // std::vector<State> moves() const;

  Block blocks_[kBlocks];
  int step = 0;
};

int main()
{
  printf("sizeof(Mask) = %zd, sizeof(State) = %zd\n", sizeof(Mask), sizeof(State));
  std::unordered_set<Mask> seen;
  std::deque<State> queue;

  State initial;
  initial.blocks_[0] = Block(Shape::kVertical, 0, 0);
  initial.blocks_[1] = Block(Shape::kSquare,   1, 0);
  initial.blocks_[2] = Block(Shape::kVertical, 3, 0);
  initial.blocks_[3] = Block(Shape::kVertical, 0, 2);
  initial.blocks_[4] = Block(Shape::kHorizon,  1, 2);
  initial.blocks_[5] = Block(Shape::kVertical, 3, 2);
  initial.blocks_[6] = Block(Shape::kSingle, 1, 3);
  initial.blocks_[7] = Block(Shape::kSingle, 2, 3);
  initial.blocks_[8] = Block(Shape::kSingle, 0, 4);
  initial.blocks_[9] = Block(Shape::kSingle, 3, 4);

  queue.push_back(initial);
  seen.insert(initial.toMask());

  while (!queue.empty())
  {
    const State curr = queue.front();
    queue.pop_front();

    if (curr.isSolved())
    {
      printf("found solution with %d steps\n", curr.step);
      break;
    }
    else if (curr.step > 200)
    {
      printf("too many steps.\n");
      break;
    }

    curr.move([&seen, &queue](const State& next) {
      auto result = seen.insert(next.toMask());
      if (result.second)
        queue.push_back(next);
    });

    // for (const State& next : curr.moves())
    // {
    //   auto result = seen.insert(next.toMask());
    //   if (result.second)
    //     queue.push_back(next);
    // }
  }
}
<|endoftext|>


<commit_before>/**********************************************************************
 * File:        mainblk.c  (Formerly main.c)
 * Description: Function to call from main() to setup.
 * Author:					Ray Smith
 * Created:					Tue Oct 22 11:09:40 BST 1991
 *
 * (C) Copyright 1991, Hewlett-Packard Ltd.
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** You may obtain a copy of the License at
 ** http://www.apache.org/licenses/LICENSE-2.0
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 *
 **********************************************************************/

#include          "fileerr.h"
#ifdef __UNIX__
#include          <unistd.h>
#include          <signal.h>
#else
#include          <io.h>
#endif
#include          <stdlib.h>
#include          "ccutil.h"

#define VARDIR        "configs/" /**< variables files */
#define EXTERN

const ERRCODE NO_PATH =
"Warning:explicit path for executable will not be used for configs";
static const ERRCODE USAGE = "Usage";

namespace tesseract {
/**********************************************************************
 * main_setup
 *
 * Main for mithras demo program. Read the arguments and set up globals.
 **********************************************************************/

/**
 * @brief CCUtil::main_setup - set location of tessdata and name of image
 *
 * @param argv0 - paths to the directory with language files and config files.
 * An actual value of argv0 is used if not NULL, otherwise TESSDATA_PREFIX is
 * used if not NULL, next try to use compiled in -DTESSDATA_PREFIX. If previous
 * is not sucessul - use current directory.
 * @param basename - name of image
 */
void CCUtil::main_setup(const char *argv0, const char *basename) {
  imagebasename = basename;      /**< name of image */

  if (argv0 != NULL) {
    datadir = argv0;
  } else {
    if (getenv("TESSDATA_PREFIX")) {
      datadir = getenv("TESSDATA_PREFIX");
    } else {
#ifdef TESSDATA_PREFIX
#define _STR(a) #a
#define _XSTR(a) _STR(a)
    datadir = _XSTR(TESSDATA_PREFIX);
#undef _XSTR
#undef _STR
#endif
    }
  }

  // datadir may still be empty:
  if (datadir.length() == 0) {
    datadir = "./";
  } else {
    // Remove tessdata from the end if present, as we will add it back!
    int length = datadir.length();
    if (length >= 8 && strcmp(&datadir[length - 8], "tessdata") == 0)
      datadir.truncate_at(length - 8);
    else if (length >= 9 && strcmp(&datadir[length - 9], "tessdata/") == 0)
      datadir.truncate_at(length - 9);
  }

  // check for missing directory separator
  const char *lastchar = datadir.string();
  lastchar += datadir.length() - 1;
  if ((strcmp(lastchar, "/") != 0) && (strcmp(lastchar, "\\") != 0))
    datadir += "/";

  datadir += m_data_sub_dir;     /**< data directory */
}
}  // namespace tesseract
<commit_msg>Get tessdata prefix from executable path (only for Windows)<commit_after>/**********************************************************************
 * File:        mainblk.c  (Formerly main.c)
 * Description: Function to call from main() to setup.
 * Author:      Ray Smith
 * Created:     Tue Oct 22 11:09:40 BST 1991
 *
 * (C) Copyright 1991, Hewlett-Packard Ltd.
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** You may obtain a copy of the License at
 ** http://www.apache.org/licenses/LICENSE-2.0
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 *
 **********************************************************************/

#include          "fileerr.h"
#ifdef __UNIX__
#include          <unistd.h>
#include          <signal.h>
#else
#include          <io.h>
#endif
#include          <stdlib.h>
#include          "ccutil.h"

#define VARDIR        "configs/" /**< variables files */
#define EXTERN

const ERRCODE NO_PATH =
"Warning:explicit path for executable will not be used for configs";
static const ERRCODE USAGE = "Usage";

namespace tesseract {
/**********************************************************************
 * main_setup
 *
 * Main for mithras demo program. Read the arguments and set up globals.
 **********************************************************************/

/**
 * @brief CCUtil::main_setup - set location of tessdata and name of image
 *
 * @param argv0 - paths to the directory with language files and config files.
 * An actual value of argv0 is used if not NULL, otherwise TESSDATA_PREFIX is
 * used if not NULL, next try to use compiled in -DTESSDATA_PREFIX. If previous
 * is not successful - use current directory.
 * @param basename - name of image
 */
void CCUtil::main_setup(const char *argv0, const char *basename) {
  imagebasename = basename;      /**< name of image */

  char *tessdata_prefix = getenv("TESSDATA_PREFIX");

  if (argv0 != NULL) {
    /* Use tessdata prefix from the command line. */
    datadir = argv0;
  } else if (tessdata_prefix) {
    /* Use tessdata prefix from the environment. */
    datadir = tessdata_prefix;
#if defined(_WIN32)
  } else if (datadir == NULL || access(datadir.string(), 0) != 0) {
    /* Look for tessdata in directory of executable. */
    static char dir[128];
    static char exe[128];
    DWORD length = GetModuleFileName(NULL, exe, sizeof(exe));
    if (length > 0 && length < sizeof(exe)) {
      _splitpath(exe, NULL, dir, NULL, NULL);
      datadir = dir;
    }
#endif /* _WIN32 */
#if defined(TESSDATA_PREFIX)
  } else {
    /* Use tessdata prefix which was compiled in. */
#define _STR(a) #a
#define _XSTR(a) _STR(a)
    datadir = _XSTR(TESSDATA_PREFIX);
#undef _XSTR
#undef _STR
#endif
  }

  // datadir may still be empty:
  if (datadir.length() == 0) {
    datadir = "./";
  } else {
    // Remove tessdata from the end if present, as we will add it back!
    int length = datadir.length();
    if (length >= 8 && strcmp(&datadir[length - 8], "tessdata") == 0)
      datadir.truncate_at(length - 8);
    else if (length >= 9 && strcmp(&datadir[length - 9], "tessdata/") == 0)
      datadir.truncate_at(length - 9);
  }

  // check for missing directory separator
  const char *lastchar = datadir.string();
  lastchar += datadir.length() - 1;
  if ((strcmp(lastchar, "/") != 0) && (strcmp(lastchar, "\\") != 0))
    datadir += "/";

  datadir += m_data_sub_dir;     /**< data directory */
}
}  // namespace tesseract
<|endoftext|>