<commit_before>/* Copyright 2014 Dietrich Epp.
   This file is part of Oubliette.  Oubliette is licensed under the terms
   of the 2-clause BSD license.  For more information, see LICENSE.txt. */
#include "entity.hpp"
#include "../defs.hpp"
#include "control.hpp"
#include "defs.hpp"
#include "graphics.hpp"
#include "leveldata.hpp"
#include <cstdio>
#include <algorithm>
namespace game {

using ::graphics::sprite;
using ::sprite::orientation;

static const scalar DT = 1e-3 * defs::FRAMETIME;
static const scalar INV_DT = 1.0 / (1e-3 * defs::FRAMETIME);

static const int CAMERA_X = 16;
static const int CAMERA_YS0 = 48, CAMERA_YS1 = 64;
static const rect CAMERA_WALK(
    -CAMERA_X,
    core::PWIDTH / 2 - CAMERA_YS1,
    +CAMERA_X,
    core::PWIDTH / 2 - CAMERA_YS0);
static const rect CAMERA_JUMP(
    -CAMERA_X,
    -core::PWIDTH / 2 + CAMERA_YS0,
    +CAMERA_X,
    core::PWIDTH / 2 - CAMERA_YS0);

static const walking_stats PLAYER_STATS = {
    300.0f,
    // Walking
    600.0f, 120.0f, 80.0f, 150.0f, 3,
    // Jumping
    25, 200.0f, 150.0f, true
};

struct entity_is_dead {
    bool operator()(const std::unique_ptr<entity> &p) {
        return p->m_team != team::DEAD;
    }
};

// ======================================================================

entity_system::entity_system(const control_system &control,
                             const std::string &levelname)
    : control_(control), levelname_(levelname)
{
    level_.set_level(levelname);
    auto data = leveldata::read_level(levelname);
    for (auto i = data.begin(), e = data.end(); i != e; i++)
        spawn(*i);
    camera_ = camera_system(
        rect(vec2::zero(), vec2(level_.width(), level_.height())));
}

void entity_system::spawn(const struct spawnpoint &data)
{
    vec2 pos(data.x, data.y);
    std::auto_ptr<entity> result;
    switch (data.type) {
    case spawntype::PLAYER:
        result.reset(new player(*this, pos));
        break;

    case spawntype::DOOR:
        result.reset(new door(*this, pos, data.data));
        break;

    default:
        core::die("Cannot spawn entity, unknown type");
    }

    new_entities_.push_back(std::move(result));
}

void entity_system::update()
{
    auto part = std::stable_partition(
        entities_.begin(), entities_.end(), entity_is_dead());
    entities_.erase(part, entities_.end());
    entities_.insert(
        entities_.end(),
        std::make_move_iterator(new_entities_.begin()),
        std::make_move_iterator(new_entities_.end()));
    new_entities_.clear();
    hover_triggers_.clear();
    for (auto i = entities_.begin(), e = entities_.end(); i != e; i++) {
        entity &ent = **i;
        ent.update();
    }
    camera_.update();
}

void entity_system::draw(::graphics::system &gr, int reltime)
{
    gr.set_camera_pos(camera_.get_pos(reltime));
    for (auto i = entities_.begin(), e = entities_.end(); i != e; i++) {
        entity &ent = **i;
        ent.draw(gr, reltime);
    }
}

void entity_system::add_entity(entity *ent)
{
    if (ent)
        new_entities_.push_back(std::unique_ptr<entity>(ent));
}

void entity_system::set_camera_target(const rect &target)
{
    camera_.set_target(target);
}

void entity_system::set_hover(ivec pos)
{
    hover_triggers_.push_back(pos);
}

bool entity_system::test_hover(irect rect)
{
    for (auto i = hover_triggers_.begin(), e = hover_triggers_.end();
         i != e; i++) {
        if (rect.contains(*i))
            return true;
    }
    return false;
}

// ======================================================================

entity::entity(entity_system &sys, team t)
    : m_system(sys), m_bbox(0, 0, 0, 0),
      m_team(t)
{ }

entity::~entity()
{ }

void entity::update()
{ }

void entity::interact()
{ }

void entity::damage(int amount)
{
    (void)amount;
}

// ======================================================================

physics_component::physics_component(irect bbox, vec2 pos, vec2 vel)
    : bbox(bbox), pos(pos), vel(vel), on_floor(false)
{ }

void physics_component::update(entity_system &sys, entity &e)
{
    static const int MAXSTEP = 3;

    on_floor = false;
    lastpos = pos;
    vec2 old_pos = pos;
    vec2 new_pos = old_pos + DT * vel + (DT * DT / 2) * accel;
    vec2 old_vel = vel;
    vec2 new_vel = old_vel + DT * accel;

    int x1 = (int)std::floor(new_pos.x);
    int y1 = (int)std::floor(new_pos.y);
    irect new_bbox = bbox.offset(x1, y1);
    const levelmap &level = sys.level();
    // std::printf("%d %d %d %d\n",
    // new_bbox.x0, new_bbox.y0, new_bbox.x1, new_bbox.y1);
    if (level.hit_test(new_bbox)) {
        // std::puts("===== COLLIDE =====");
        // Scan dx decreasing in magnitude until we can find a spot
        // for the entity.  The entity's vertical position will be
        // adjusted as necessary.
        int x0 = (int)std::floor(old_pos.x);
        int y0 = (int)std::floor(old_pos.y);
        int dir = x1 < x0 ? -1 : +1;
        int max_dx = dir * (x1 - x0);
        if (max_dx < 0)
            max_dx = 0;
        for (int dx = max_dx; ; dx--) {
            int x = x0 + dx * dir;
            int step = dx;
            if (step < MAXSTEP)
                step = MAXSTEP;
            int ymin = y0 - step, ymax = y0 + step;
            if (y1 < ymin) ymin = y1;
            else if (y1 > ymax) ymax = y1;
            int yh = (ymin + ymax) / 2;
            irect rect0(x + bbox.x0, ymin + bbox.y0,
                        x + bbox.x1, yh);
            irect rect1(x + bbox.x0, yh,
                        x + bbox.x1, ymax + bbox.y1);
            int d0 = level.hit_y0(rect0);
            int d1 = level.hit_y1(rect1);
            // std::printf("rects: %d %d %d %d\n",
            // rect0.y0, rect0.y1, rect1.y0, rect1.y1);
            // std::printf("d0: %d, d1: %d\n", d0, d1);
            int miny1 = ymin + d0;
            int maxy1 = ymax - d1;
            // std::printf("min: %d, max: %d, y0: %d, y1: %d\n",
            // miny1, maxy1, y0, y1);
            if (miny1 <= maxy1) {
                if (dx < max_dx)
                    new_pos.x = x;
                if (y1 < miny1) {
                    new_pos.y = miny1;
                    on_floor = true;
                } else if (y1 > maxy1) {
                    new_pos.y = maxy1;
                }
                // std::printf("new: %f, old: %f\n", new_pos.y, old_pos.y);
                break;
            }
            if (dx == 0) {
                std::puts("Entity stuck!");
                new_pos = old_pos;
                break;
            }
        }

        new_vel = (1.0f / DT) * (new_pos - old_pos);
    }

    pos = new_pos;
    vel = new_vel;

    e.m_bbox = new_bbox;
}

vec2 physics_component::get_pos(int reltime)
{
    return defs::interp(lastpos, pos, reltime);
}

// ======================================================================

walking_component::walking_component()
    : gravity(vec2::zero()), xmove(0.0f), ymove(0.0f),
      jumptime(0), jstate(jumpstate::READY)
{ }

void walking_component::update(entity_system &sys, physics_component &physics,
                               const walking_stats &stats)
{
    (void)&sys;
    vec2 accel = vec2(0, -stats.gravity);

    bool on_floor = physics.on_floor;
    // std::printf("on floor: %s\n", on_floor ? "true" : "false");

    float max_xspeed = on_floor ? stats.xspeed_ground : stats.xspeed_air;
    float max_xaccel = on_floor ? stats.xaccel_ground : stats.xaccel_air;
    float xaccel = (max_xspeed * xmove - physics.vel.x) * INV_DT;
    if (xaccel > max_xaccel)
        xaccel = max_xaccel;
    else if (xaccel < -max_xaccel)
        xaccel = -max_xaccel;
    accel.x += xaccel;

    if (on_floor) {
        jumptime = 0;
        if (ymove > 0.5f) {
            if (jstate == jumpstate::READY) {
                // std::puts("JUMP");
                jumptime = stats.jumptime;
                jstate = jumpstate::JUMP1;
                accel.y += stats.jumpspeed * INV_DT;
            }
        } else {
            jstate = jumpstate::READY;
        }
    } else if (jumptime > 0) {
        jumptime--;
        if (ymove >= 0.25f) {
            accel.y += stats.jumpaccel * ymove;
        } else {
            jumptime = 0;
            if (jstate == jumpstate::JUMP1)
                jstate = jumpstate::READY;
        }
    } else {
        if (ymove > 0.5f) {
            if (jstate == jumpstate::READY && stats.can_doublejump) {
                // std::puts("DOUBLE JUMP");
                jumptime = stats.jumptime;
                jstate = jumpstate::JUMP2;
                accel.y += stats.jumpspeed * INV_DT;
            }
        } else {
            if (jstate == jumpstate::JUMP1)
                jstate = jumpstate::READY;
        }
    }

    physics.accel = accel;
    xmove = 0.0f;
    ymove = 0.0f;
}

// ======================================================================

player::player(entity_system &sys, vec2 pos)
    : entity(sys, team::FRIEND),
      physics(irect::centered(8, 20), pos, vec2::zero())
{
    walking.gravity = vec2(0, -100);
    // walking.gravity = vec2::zero();
}

player::~player()
{ }

void player::update()
{
    walking.xmove = m_system.control().get_xaxis();
    walking.ymove = m_system.control().get_yaxis();
    walking.update(m_system, physics, PLAYER_STATS);
    physics.update(m_system, *this);

    m_system.set_camera_target(
        (physics.on_floor ? CAMERA_WALK : CAMERA_JUMP)
        .offset(physics.pos));
    m_system.set_hover(ivec(physics.pos));

    if (m_system.control().get_key_instant(key::DOWN)) {
        ivec pos(physics.pos);
        auto &ents = m_system.entities();
        for (auto i = ents.begin(), e = ents.end(); i != e; i++) {
            entity &ent(**i);
            if (ent.m_team != team::INTERACTIVE)
                continue;
            if (!ent.m_bbox.contains(pos))
                continue;
            ent.interact();
            break;
        }
    }
}

void player::damage(int amount)
{
    (void)amount;
}

void player::draw(::graphics::system &gr, int reltime)
{
    gr.add_sprite(
        sprite::PLAYER,
        physics.get_pos(reltime) + vec2(-8, -12),
        orientation::NORMAL);
}

// ======================================================================

door::door(entity_system &sys, vec2 pos, const std::string target)
    : entity(sys, team::INTERACTIVE), m_pos(pos), m_target(target)
{
    m_bbox = irect::centered(24, 32).offset(pos);
}

door::~door()
{ }

void door::interact()
{
    m_system.nextlevel = m_target;
}

void door::draw(::graphics::system &gr, int reltime)
{
    (void)reltime;
    gr.add_sprite(
        sprite::DOOR2,
        m_pos + vec2(-12, -16),
        orientation::NORMAL);
    if (m_system.test_hover(m_bbox)) {
        gr.add_sprite(
            sprite::ARROW,
            m_pos + vec2(-8, +20),
            orientation::NORMAL);
    }
}

// ======================================================================

}
<commit_msg>Adjust camera target<commit_after>/* Copyright 2014 Dietrich Epp.
   This file is part of Oubliette.  Oubliette is licensed under the terms
   of the 2-clause BSD license.  For more information, see LICENSE.txt. */
#include "entity.hpp"
#include "../defs.hpp"
#include "control.hpp"
#include "defs.hpp"
#include "graphics.hpp"
#include "leveldata.hpp"
#include <cstdio>
#include <algorithm>
namespace game {

using ::graphics::sprite;
using ::sprite::orientation;

static const scalar DT = 1e-3 * defs::FRAMETIME;
static const scalar INV_DT = 1.0 / (1e-3 * defs::FRAMETIME);

static const int CAMERA_X = 16;
static const int CAMERA_YS0 = 64, CAMERA_YS1 = 96;
static const rect CAMERA_WALK(
    -CAMERA_X,
    core::PHEIGHT / 2 - CAMERA_YS1,
    +CAMERA_X,
    core::PHEIGHT / 2 - CAMERA_YS0);
static const rect CAMERA_JUMP(
    -CAMERA_X,
    -core::PHEIGHT / 2 + CAMERA_YS0,
    +CAMERA_X,
    core::PHEIGHT / 2 - CAMERA_YS0);

static const walking_stats PLAYER_STATS = {
    300.0f,
    // Walking
    600.0f, 120.0f, 80.0f, 150.0f, 3,
    // Jumping
    25, 200.0f, 150.0f, true
};

struct entity_is_dead {
    bool operator()(const std::unique_ptr<entity> &p) {
        return p->m_team != team::DEAD;
    }
};

// ======================================================================

entity_system::entity_system(const control_system &control,
                             const std::string &levelname)
    : control_(control), levelname_(levelname)
{
    level_.set_level(levelname);
    auto data = leveldata::read_level(levelname);
    for (auto i = data.begin(), e = data.end(); i != e; i++)
        spawn(*i);
    camera_ = camera_system(
        rect(vec2::zero(), vec2(level_.width(), level_.height())));
}

void entity_system::spawn(const struct spawnpoint &data)
{
    vec2 pos(data.x, data.y);
    std::auto_ptr<entity> result;
    switch (data.type) {
    case spawntype::PLAYER:
        result.reset(new player(*this, pos));
        break;

    case spawntype::DOOR:
        result.reset(new door(*this, pos, data.data));
        break;

    default:
        core::die("Cannot spawn entity, unknown type");
    }

    new_entities_.push_back(std::move(result));
}

void entity_system::update()
{
    auto part = std::stable_partition(
        entities_.begin(), entities_.end(), entity_is_dead());
    entities_.erase(part, entities_.end());
    entities_.insert(
        entities_.end(),
        std::make_move_iterator(new_entities_.begin()),
        std::make_move_iterator(new_entities_.end()));
    new_entities_.clear();
    hover_triggers_.clear();
    for (auto i = entities_.begin(), e = entities_.end(); i != e; i++) {
        entity &ent = **i;
        ent.update();
    }
    camera_.update();
}

void entity_system::draw(::graphics::system &gr, int reltime)
{
    gr.set_camera_pos(camera_.get_pos(reltime));
    for (auto i = entities_.begin(), e = entities_.end(); i != e; i++) {
        entity &ent = **i;
        ent.draw(gr, reltime);
    }
}

void entity_system::add_entity(entity *ent)
{
    if (ent)
        new_entities_.push_back(std::unique_ptr<entity>(ent));
}

void entity_system::set_camera_target(const rect &target)
{
    camera_.set_target(target);
}

void entity_system::set_hover(ivec pos)
{
    hover_triggers_.push_back(pos);
}

bool entity_system::test_hover(irect rect)
{
    for (auto i = hover_triggers_.begin(), e = hover_triggers_.end();
         i != e; i++) {
        if (rect.contains(*i))
            return true;
    }
    return false;
}

// ======================================================================

entity::entity(entity_system &sys, team t)
    : m_system(sys), m_bbox(0, 0, 0, 0),
      m_team(t)
{ }

entity::~entity()
{ }

void entity::update()
{ }

void entity::interact()
{ }

void entity::damage(int amount)
{
    (void)amount;
}

// ======================================================================

physics_component::physics_component(irect bbox, vec2 pos, vec2 vel)
    : bbox(bbox), pos(pos), vel(vel), on_floor(false)
{ }

void physics_component::update(entity_system &sys, entity &e)
{
    static const int MAXSTEP = 3;

    on_floor = false;
    lastpos = pos;
    vec2 old_pos = pos;
    vec2 new_pos = old_pos + DT * vel + (DT * DT / 2) * accel;
    vec2 old_vel = vel;
    vec2 new_vel = old_vel + DT * accel;

    int x1 = (int)std::floor(new_pos.x);
    int y1 = (int)std::floor(new_pos.y);
    irect new_bbox = bbox.offset(x1, y1);
    const levelmap &level = sys.level();
    // std::printf("%d %d %d %d\n",
    // new_bbox.x0, new_bbox.y0, new_bbox.x1, new_bbox.y1);
    if (level.hit_test(new_bbox)) {
        // std::puts("===== COLLIDE =====");
        // Scan dx decreasing in magnitude until we can find a spot
        // for the entity.  The entity's vertical position will be
        // adjusted as necessary.
        int x0 = (int)std::floor(old_pos.x);
        int y0 = (int)std::floor(old_pos.y);
        int dir = x1 < x0 ? -1 : +1;
        int max_dx = dir * (x1 - x0);
        if (max_dx < 0)
            max_dx = 0;
        for (int dx = max_dx; ; dx--) {
            int x = x0 + dx * dir;
            int step = dx;
            if (step < MAXSTEP)
                step = MAXSTEP;
            int ymin = y0 - step, ymax = y0 + step;
            if (y1 < ymin) ymin = y1;
            else if (y1 > ymax) ymax = y1;
            int yh = (ymin + ymax) / 2;
            irect rect0(x + bbox.x0, ymin + bbox.y0,
                        x + bbox.x1, yh);
            irect rect1(x + bbox.x0, yh,
                        x + bbox.x1, ymax + bbox.y1);
            int d0 = level.hit_y0(rect0);
            int d1 = level.hit_y1(rect1);
            // std::printf("rects: %d %d %d %d\n",
            // rect0.y0, rect0.y1, rect1.y0, rect1.y1);
            // std::printf("d0: %d, d1: %d\n", d0, d1);
            int miny1 = ymin + d0;
            int maxy1 = ymax - d1;
            // std::printf("min: %d, max: %d, y0: %d, y1: %d\n",
            // miny1, maxy1, y0, y1);
            if (miny1 <= maxy1) {
                if (dx < max_dx)
                    new_pos.x = x;
                if (y1 < miny1) {
                    new_pos.y = miny1;
                    on_floor = true;
                } else if (y1 > maxy1) {
                    new_pos.y = maxy1;
                }
                // std::printf("new: %f, old: %f\n", new_pos.y, old_pos.y);
                break;
            }
            if (dx == 0) {
                std::puts("Entity stuck!");
                new_pos = old_pos;
                break;
            }
        }

        new_vel = (1.0f / DT) * (new_pos - old_pos);
    }

    pos = new_pos;
    vel = new_vel;

    e.m_bbox = new_bbox;
}

vec2 physics_component::get_pos(int reltime)
{
    return defs::interp(lastpos, pos, reltime);
}

// ======================================================================

walking_component::walking_component()
    : gravity(vec2::zero()), xmove(0.0f), ymove(0.0f),
      jumptime(0), jstate(jumpstate::READY)
{ }

void walking_component::update(entity_system &sys, physics_component &physics,
                               const walking_stats &stats)
{
    (void)&sys;
    vec2 accel = vec2(0, -stats.gravity);

    bool on_floor = physics.on_floor;
    // std::printf("on floor: %s\n", on_floor ? "true" : "false");

    float max_xspeed = on_floor ? stats.xspeed_ground : stats.xspeed_air;
    float max_xaccel = on_floor ? stats.xaccel_ground : stats.xaccel_air;
    float xaccel = (max_xspeed * xmove - physics.vel.x) * INV_DT;
    if (xaccel > max_xaccel)
        xaccel = max_xaccel;
    else if (xaccel < -max_xaccel)
        xaccel = -max_xaccel;
    accel.x += xaccel;

    if (on_floor) {
        jumptime = 0;
        if (ymove > 0.5f) {
            if (jstate == jumpstate::READY) {
                // std::puts("JUMP");
                jumptime = stats.jumptime;
                jstate = jumpstate::JUMP1;
                accel.y += stats.jumpspeed * INV_DT;
            }
        } else {
            jstate = jumpstate::READY;
        }
    } else if (jumptime > 0) {
        jumptime--;
        if (ymove >= 0.25f) {
            accel.y += stats.jumpaccel * ymove;
        } else {
            jumptime = 0;
            if (jstate == jumpstate::JUMP1)
                jstate = jumpstate::READY;
        }
    } else {
        if (ymove > 0.5f) {
            if (jstate == jumpstate::READY && stats.can_doublejump) {
                // std::puts("DOUBLE JUMP");
                jumptime = stats.jumptime;
                jstate = jumpstate::JUMP2;
                accel.y += stats.jumpspeed * INV_DT;
            }
        } else {
            if (jstate == jumpstate::JUMP1)
                jstate = jumpstate::READY;
        }
    }

    physics.accel = accel;
    xmove = 0.0f;
    ymove = 0.0f;
}

// ======================================================================

player::player(entity_system &sys, vec2 pos)
    : entity(sys, team::FRIEND),
      physics(irect::centered(8, 20), pos, vec2::zero())
{
    walking.gravity = vec2(0, -100);
    // walking.gravity = vec2::zero();
}

player::~player()
{ }

void player::update()
{
    walking.xmove = m_system.control().get_xaxis();
    walking.ymove = m_system.control().get_yaxis();
    walking.update(m_system, physics, PLAYER_STATS);
    physics.update(m_system, *this);

    m_system.set_camera_target(
        (physics.on_floor ? CAMERA_WALK : CAMERA_JUMP)
        .offset(physics.pos));
    m_system.set_hover(ivec(physics.pos));

    if (m_system.control().get_key_instant(key::DOWN)) {
        ivec pos(physics.pos);
        auto &ents = m_system.entities();
        for (auto i = ents.begin(), e = ents.end(); i != e; i++) {
            entity &ent(**i);
            if (ent.m_team != team::INTERACTIVE)
                continue;
            if (!ent.m_bbox.contains(pos))
                continue;
            ent.interact();
            break;
        }
    }
}

void player::damage(int amount)
{
    (void)amount;
}

void player::draw(::graphics::system &gr, int reltime)
{
    gr.add_sprite(
        sprite::PLAYER,
        physics.get_pos(reltime) + vec2(-8, -12),
        orientation::NORMAL);
}

// ======================================================================

door::door(entity_system &sys, vec2 pos, const std::string target)
    : entity(sys, team::INTERACTIVE), m_pos(pos), m_target(target)
{
    m_bbox = irect::centered(24, 32).offset(pos);
}

door::~door()
{ }

void door::interact()
{
    m_system.nextlevel = m_target;
}

void door::draw(::graphics::system &gr, int reltime)
{
    (void)reltime;
    gr.add_sprite(
        sprite::DOOR2,
        m_pos + vec2(-12, -16),
        orientation::NORMAL);
    if (m_system.test_hover(m_bbox)) {
        gr.add_sprite(
            sprite::ARROW,
            m_pos + vec2(-8, +20),
            orientation::NORMAL);
    }
}

// ======================================================================

}
<|endoftext|>


<commit_before>// Module:  Log4CPLUS
// File:    global-init.cxx
// Created: 5/2003
// Author:  Tad E. Smith
//
//
// Copyright 2003-2010 Tad E. Smith
//
// 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 <log4cplus/config.hxx>
#include <log4cplus/config/windowsh-inc.h>
#include <log4cplus/logger.h>
#include <log4cplus/ndc.h>
#include <log4cplus/mdc.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/internal/internal.h>
#include <log4cplus/thread/impl/tls.h>
#include <log4cplus/thread/syncprims-pub-impl.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/spi/factory.h>
#include <log4cplus/hierarchy.h>
#include <cstdio>
#include <iostream>
#include <stdexcept>

// Forward Declarations
namespace log4cplus
{

#ifdef UNICODE
LOG4CPLUS_EXPORT tostream & tcout = std::wcout;
LOG4CPLUS_EXPORT tostream & tcerr = std::wcerr;

#else
LOG4CPLUS_EXPORT tostream & tcout = std::cout;
LOG4CPLUS_EXPORT tostream & tcerr = std::cerr;

#endif // UNICODE

namespace
{

//! Default context.
struct DefaultContext
{
    log4cplus::thread::Mutex console_mutex;
    helpers::LogLog loglog;
    LogLevelManager log_level_manager;
    helpers::Time TTCCLayout_time_base;
    NDC ndc;
    MDC mdc;
    Hierarchy hierarchy;
    spi::AppenderFactoryRegistry appender_factory_registry;
    spi::LayoutFactoryRegistry layout_factory_registry;
    spi::FilterFactoryRegistry filter_factory_registry;
    spi::LocaleFactoryRegistry locale_factory_registry;
};

enum DCState
{
    DC_UNINITIALIZED,
    DC_INITIALIZED,
    DC_DESTROYED
};

static DCState default_context_state;
static DefaultContext * default_context;

struct destroy_default_context
{
    ~destroy_default_context ()
    {
        delete default_context;
        default_context = 0;
        default_context_state = DC_DESTROYED;
    }
} static destroy_default_context_;

static
void
alloc_dc ()
{
    assert (! default_context);
    assert (default_context_state == DC_UNINITIALIZED);

    if (default_context)
        throw std::logic_error (
            "alloc_dc() called with non-NULL default_context.");

    if (default_context_state == DC_INITIALIZED)
        throw std::logic_error ("alloc_dc() called in DC_INITIALIZED state.");

    default_context = new DefaultContext;

    if (default_context_state == DC_DESTROYED)
        default_context->loglog.error (
            LOG4CPLUS_TEXT ("Re-initializing default context after it has")
            LOG4CPLUS_TEXT (" already been destroyed.\n")
            LOG4CPLUS_TEXT ("The memory will be leaked."));

    default_context_state = DC_INITIALIZED;
}

static
DefaultContext *
get_dc (bool alloc = true)
{
    if (LOG4CPLUS_UNLIKELY (! default_context && alloc))
        alloc_dc ();
    return default_context;
}

} // namespace

namespace helpers
{

log4cplus::thread::Mutex const &
getConsoleOutputMutex ()
{
    return get_dc ()->console_mutex;
}

LogLog &
getLogLog ()
{
    return get_dc ()->loglog;
}

} // namespace helpers

helpers::Time const &
getTTCCLayoutTimeBase ()
{
    return get_dc ()->TTCCLayout_time_base;
}

LogLevelManager &
getLogLevelManager ()
{
    return get_dc ()->log_level_manager;
}

Hierarchy &
getDefaultHierarchy ()
{
    return get_dc ()->hierarchy;
}

NDC &
getNDC ()
{
    return get_dc ()->ndc;
}

MDC &
getMDC ()
{
    return get_dc ()->mdc;
}

namespace spi
{

AppenderFactoryRegistry &
getAppenderFactoryRegistry ()
{
    return get_dc ()->appender_factory_registry;
}

LayoutFactoryRegistry &
getLayoutFactoryRegistry ()
{
    return get_dc ()->layout_factory_registry;
}

FilterFactoryRegistry &
getFilterFactoryRegistry ()
{
    return get_dc ()->filter_factory_registry;
}

LocaleFactoryRegistry &
getLocaleFactoryRegistry()
{
    return get_dc ()->locale_factory_registry;
}

} // namespace spi

namespace internal
{

gft_scratch_pad::gft_scratch_pad ()
    : uc_q_str_valid (false)
    , q_str_valid (false)
    , s_str_valid (false)
{ }

gft_scratch_pad::~gft_scratch_pad ()
{ }

appender_sratch_pad::appender_sratch_pad ()
{ }

appender_sratch_pad::~appender_sratch_pad ()
{ }

per_thread_data::per_thread_data ()
    : fnull (0)
{ }

per_thread_data::~per_thread_data ()
{
    if (fnull)
        std::fclose (fnull);
}

log4cplus::thread::impl::tls_key_type tls_storage_key;

#if ! defined (LOG4CPLUS_SINGLE_THREADED) \
    && defined (LOG4CPLUS_THREAD_LOCAL_VAR)

LOG4CPLUS_THREAD_LOCAL_VAR per_thread_data * ptd = 0;

per_thread_data *
alloc_ptd ()
{
    per_thread_data * tmp = new per_thread_data;
    set_ptd (tmp);
    // This is a special hack. We set the keys' value to non-NULL to
    // get the ptd_cleanup_func to execute when this thread ends. The
    // cast is safe; the associated value will never be used if read
    // again using the key.
    thread::impl::tls_set_value (tls_storage_key,
        reinterpret_cast<void *>(1));

    return tmp;
}

#  else

per_thread_data *
alloc_ptd ()
{
    per_thread_data * tmp = new per_thread_data;
    set_ptd (tmp);
    return tmp;
}

#  endif

} // namespace internal

void initializeFactoryRegistry();

//! Thread local storage clean up function for POSIX threads.
static
void
ptd_cleanup_func (void * arg)
{
    internal::per_thread_data * const arg_ptd
        = static_cast<internal::per_thread_data *>(arg);
    internal::per_thread_data * const ptd = internal::get_ptd (false);
    (void) ptd;

    // Either it is a dummy value or it should be the per thread data
    // pointer we get from internal::get_ptd().
    assert (arg == reinterpret_cast<void *>(1)
        || arg_ptd == ptd
        || (! ptd && arg_ptd));

    if (arg == reinterpret_cast<void *>(1))
        // Setting the value through the key here is necessary in case
        // we are using TLS using __thread or __declspec(thread) or
        // similar constructs with POSIX threads.  Otherwise POSIX
        // calls this cleanup routine more than once if the value
        // stays non-NULL after it returns.
        thread::impl::tls_set_value (internal::tls_storage_key, 0);
    else if (arg)
    {
        // Instead of using internal::get_ptd(false) here we are using
        // the value passed to this function directly.  This is
        // necessary because of the following (from SUSv4):
        //
        // A call to pthread_getspecific() for the thread-specific
        // data key being destroyed shall return the value NULL,
        // unless the value is changed (after the destructor starts)
        // by a call to pthread_setspecific().
        delete arg_ptd;
        thread::impl::tls_set_value (internal::tls_storage_key, 0);
    }
    else
    {
        // In this case we fall through to threadCleanup() and it does
        // all the necessary work itself.
        ;
    }

    threadCleanup ();
}

static
void
threadSetup ()
{
    internal::get_ptd (true);
}

void initializeLog4cplus()
{
    static bool initialized = false;
    if (initialized)
        return;

    internal::tls_storage_key = thread::impl::tls_init (ptd_cleanup_func);
    threadSetup ();

    DefaultContext * dc = get_dc (true);
    dc->TTCCLayout_time_base = helpers::Time::gettimeofday ();
    Logger::getRoot();
    initializeFactoryRegistry();

    initialized = true;
}

void
threadCleanup ()
{
    // Do thread-specific cleanup.
    internal::per_thread_data * ptd = internal::get_ptd (false);
    delete ptd;
    internal::set_ptd (0);
}

} // namespace log4cplus

#if defined (_WIN32) && defined (LOG4CPLUS_BUILD_DLL)

extern "C"
BOOL
WINAPI
DllMain (LOG4CPLUS_DLLMAIN_HINSTANCE /*hinstDLL*/, DWORD fdwReason,
    LPVOID /*lpReserved*/)
{
    // Perform actions based on the reason for calling.
    switch( fdwReason )
    {
    case DLL_PROCESS_ATTACH:
    {
        log4cplus::initializeLog4cplus();

        // Do thread-specific initialization for the main thread.
        log4cplus::threadSetup ();

        break;
    }

    case DLL_THREAD_ATTACH:
    {
        // Do thread-specific initialization.
        log4cplus::threadSetup ();

        break;
    }

    case DLL_THREAD_DETACH:
    {
        // Do thread-specific cleanup.
        log4cplus::threadCleanup ();

        break;
    }

    case DLL_PROCESS_DETACH:
    {
        // Perform any necessary cleanup.

        // Do thread-specific cleanup.
        log4cplus::threadCleanup ();
#if ! defined (LOG4CPLUS_THREAD_LOCAL_VAR)
        log4cplus::thread::impl::tls_cleanup (
            log4cplus::internal::tls_storage_key);
#endif
        break;
    }

    }

    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

#else

namespace {

    struct _static_log4cplus_initializer
    {
        _static_log4cplus_initializer ()
        {
            log4cplus::initializeLog4cplus();
        }

        ~_static_log4cplus_initializer ()
        {
            // Last thread cleanup.
            log4cplus::threadCleanup ();
        }
    } static initializer;
}

#endif
<commit_msg>global-init.cxx: Implement thread callback using .CRT$XLX section for static library build with MSVC.<commit_after>// Module:  Log4CPLUS
// File:    global-init.cxx
// Created: 5/2003
// Author:  Tad E. Smith
//
//
// Copyright 2003-2010 Tad E. Smith
//
// 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 <log4cplus/config.hxx>
#include <log4cplus/config/windowsh-inc.h>
#include <log4cplus/logger.h>
#include <log4cplus/ndc.h>
#include <log4cplus/mdc.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/internal/internal.h>
#include <log4cplus/thread/impl/tls.h>
#include <log4cplus/thread/syncprims-pub-impl.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/spi/factory.h>
#include <log4cplus/hierarchy.h>
#include <cstdio>
#include <iostream>
#include <stdexcept>

// Forward Declarations
namespace log4cplus
{

#ifdef UNICODE
LOG4CPLUS_EXPORT tostream & tcout = std::wcout;
LOG4CPLUS_EXPORT tostream & tcerr = std::wcerr;

#else
LOG4CPLUS_EXPORT tostream & tcout = std::cout;
LOG4CPLUS_EXPORT tostream & tcerr = std::cerr;

#endif // UNICODE

namespace
{

//! Default context.
struct DefaultContext
{
    log4cplus::thread::Mutex console_mutex;
    helpers::LogLog loglog;
    LogLevelManager log_level_manager;
    helpers::Time TTCCLayout_time_base;
    NDC ndc;
    MDC mdc;
    Hierarchy hierarchy;
    spi::AppenderFactoryRegistry appender_factory_registry;
    spi::LayoutFactoryRegistry layout_factory_registry;
    spi::FilterFactoryRegistry filter_factory_registry;
    spi::LocaleFactoryRegistry locale_factory_registry;
};

enum DCState
{
    DC_UNINITIALIZED,
    DC_INITIALIZED,
    DC_DESTROYED
};

static DCState default_context_state;
static DefaultContext * default_context;

struct destroy_default_context
{
    ~destroy_default_context ()
    {
        delete default_context;
        default_context = 0;
        default_context_state = DC_DESTROYED;
    }
} static destroy_default_context_;

static
void
alloc_dc ()
{
    assert (! default_context);
    assert (default_context_state == DC_UNINITIALIZED);

    if (default_context)
        throw std::logic_error (
            "alloc_dc() called with non-NULL default_context.");

    if (default_context_state == DC_INITIALIZED)
        throw std::logic_error ("alloc_dc() called in DC_INITIALIZED state.");

    default_context = new DefaultContext;

    if (default_context_state == DC_DESTROYED)
        default_context->loglog.error (
            LOG4CPLUS_TEXT ("Re-initializing default context after it has")
            LOG4CPLUS_TEXT (" already been destroyed.\n")
            LOG4CPLUS_TEXT ("The memory will be leaked."));

    default_context_state = DC_INITIALIZED;
}

static
DefaultContext *
get_dc (bool alloc = true)
{
    if (LOG4CPLUS_UNLIKELY (! default_context && alloc))
        alloc_dc ();
    return default_context;
}

} // namespace

namespace helpers
{

log4cplus::thread::Mutex const &
getConsoleOutputMutex ()
{
    return get_dc ()->console_mutex;
}

LogLog &
getLogLog ()
{
    return get_dc ()->loglog;
}

} // namespace helpers

helpers::Time const &
getTTCCLayoutTimeBase ()
{
    return get_dc ()->TTCCLayout_time_base;
}

LogLevelManager &
getLogLevelManager ()
{
    return get_dc ()->log_level_manager;
}

Hierarchy &
getDefaultHierarchy ()
{
    return get_dc ()->hierarchy;
}

NDC &
getNDC ()
{
    return get_dc ()->ndc;
}

MDC &
getMDC ()
{
    return get_dc ()->mdc;
}

namespace spi
{

AppenderFactoryRegistry &
getAppenderFactoryRegistry ()
{
    return get_dc ()->appender_factory_registry;
}

LayoutFactoryRegistry &
getLayoutFactoryRegistry ()
{
    return get_dc ()->layout_factory_registry;
}

FilterFactoryRegistry &
getFilterFactoryRegistry ()
{
    return get_dc ()->filter_factory_registry;
}

LocaleFactoryRegistry &
getLocaleFactoryRegistry()
{
    return get_dc ()->locale_factory_registry;
}

} // namespace spi

namespace internal
{

gft_scratch_pad::gft_scratch_pad ()
    : uc_q_str_valid (false)
    , q_str_valid (false)
    , s_str_valid (false)
{ }

gft_scratch_pad::~gft_scratch_pad ()
{ }

appender_sratch_pad::appender_sratch_pad ()
{ }

appender_sratch_pad::~appender_sratch_pad ()
{ }

per_thread_data::per_thread_data ()
    : fnull (0)
{ }

per_thread_data::~per_thread_data ()
{
    if (fnull)
        std::fclose (fnull);
}

log4cplus::thread::impl::tls_key_type tls_storage_key;

#if ! defined (LOG4CPLUS_SINGLE_THREADED) \
    && defined (LOG4CPLUS_THREAD_LOCAL_VAR)

LOG4CPLUS_THREAD_LOCAL_VAR per_thread_data * ptd = 0;

per_thread_data *
alloc_ptd ()
{
    per_thread_data * tmp = new per_thread_data;
    set_ptd (tmp);
    // This is a special hack. We set the keys' value to non-NULL to
    // get the ptd_cleanup_func to execute when this thread ends. The
    // cast is safe; the associated value will never be used if read
    // again using the key.
    thread::impl::tls_set_value (tls_storage_key,
        reinterpret_cast<void *>(1));

    return tmp;
}

#  else

per_thread_data *
alloc_ptd ()
{
    per_thread_data * tmp = new per_thread_data;
    set_ptd (tmp);
    return tmp;
}

#  endif

} // namespace internal

void initializeFactoryRegistry();

//! Thread local storage clean up function for POSIX threads.
static
void
ptd_cleanup_func (void * arg)
{
    internal::per_thread_data * const arg_ptd
        = static_cast<internal::per_thread_data *>(arg);
    internal::per_thread_data * const ptd = internal::get_ptd (false);
    (void) ptd;

    // Either it is a dummy value or it should be the per thread data
    // pointer we get from internal::get_ptd().
    assert (arg == reinterpret_cast<void *>(1)
        || arg_ptd == ptd
        || (! ptd && arg_ptd));

    if (arg == reinterpret_cast<void *>(1))
        // Setting the value through the key here is necessary in case
        // we are using TLS using __thread or __declspec(thread) or
        // similar constructs with POSIX threads.  Otherwise POSIX
        // calls this cleanup routine more than once if the value
        // stays non-NULL after it returns.
        thread::impl::tls_set_value (internal::tls_storage_key, 0);
    else if (arg)
    {
        // Instead of using internal::get_ptd(false) here we are using
        // the value passed to this function directly.  This is
        // necessary because of the following (from SUSv4):
        //
        // A call to pthread_getspecific() for the thread-specific
        // data key being destroyed shall return the value NULL,
        // unless the value is changed (after the destructor starts)
        // by a call to pthread_setspecific().
        delete arg_ptd;
        thread::impl::tls_set_value (internal::tls_storage_key, 0);
    }
    else
    {
        // In this case we fall through to threadCleanup() and it does
        // all the necessary work itself.
        ;
    }

    threadCleanup ();
}

static
void
threadSetup ()
{
    internal::get_ptd (true);
}

void initializeLog4cplus()
{
    static bool initialized = false;
    if (initialized)
        return;

    internal::tls_storage_key = thread::impl::tls_init (ptd_cleanup_func);
    threadSetup ();

    DefaultContext * dc = get_dc (true);
    dc->TTCCLayout_time_base = helpers::Time::gettimeofday ();
    Logger::getRoot();
    initializeFactoryRegistry();

    initialized = true;
}

void
threadCleanup ()
{
    // Do thread-specific cleanup.
    internal::per_thread_data * ptd = internal::get_ptd (false);
    delete ptd;
    internal::set_ptd (0);
}

#if defined (_WIN32)
static
void NTAPI
thread_callback (LPVOID /*hinstDLL*/, DWORD fdwReason, LPVOID /*lpReserved*/)
{
    // Perform actions based on the reason for calling.
    switch( fdwReason )
    {
    case DLL_PROCESS_ATTACH:
    {
        log4cplus::initializeLog4cplus();

        // Do thread-specific initialization for the main thread.
        log4cplus::threadSetup ();

        break;
    }

    case DLL_THREAD_ATTACH:
    {
        // Do thread-specific initialization.
        log4cplus::threadSetup ();

        break;
    }

    case DLL_THREAD_DETACH:
    {
        // Do thread-specific cleanup.
        log4cplus::threadCleanup ();

        break;
    }

    case DLL_PROCESS_DETACH:
    {
        // Perform any necessary cleanup.

        // Do thread-specific cleanup.
        log4cplus::threadCleanup ();
#if ! defined (LOG4CPLUS_THREAD_LOCAL_VAR)
        log4cplus::thread::impl::tls_cleanup (
            log4cplus::internal::tls_storage_key);
#endif
        break;
    }

    } // switch
}

#endif

} // namespace log4cplus

#if defined (_WIN32) && defined (LOG4CPLUS_BUILD_DLL)

extern "C"
BOOL
WINAPI
DllMain (LOG4CPLUS_DLLMAIN_HINSTANCE hinstDLL, DWORD fdwReason,
    LPVOID lpReserved)
{
    log4cplus::thread_callback (hinstDLL, fdwReason, lpReserved);

    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

#else

#if defined (_MSC_VER) && _MSC_VER >= 1400

extern "C"
{

// This magic has been pieced together from several sources:
// - <http://www.nynaeve.net/?p=183>
// - <http://lists.cs.uiuc.edu/pipermail/cfe-dev/2011-November/018818.html>

#pragma data_seg (push, old_seg)
#ifdef _WIN64
#pragma const_seg (".CRT$XLX")
extern const
#else
#pragma data_seg (".CRT$XLX")
#endif
PIMAGE_TLS_CALLBACK p_thread_callback = log4cplus::thread_callback;
#pragma data_seg (pop, old_seg)
#ifdef _WIN64
#pragma comment (linker, "/INCLUDE:_tls_used")
#pragma comment (linker, "/INCLUDE:p_thread_callback")
#else
#pragma comment (linker, "/INCLUDE:__tls_used")
#pragma comment (linker, "/INCLUDE:_p_thread_callback")
#endif

} // extern "C"

#else

namespace {

    struct _static_log4cplus_initializer
    {
        _static_log4cplus_initializer ()
        {
            log4cplus::initializeLog4cplus();
        }

        ~_static_log4cplus_initializer ()
        {
            // Last thread cleanup.
            log4cplus::threadCleanup ();
        }
    } static initializer;
}

#endif

#endif
<|endoftext|>


<commit_before>#ifndef SAT_HH
#define SAT_HH

#include "all.cc"
#include "life.hh"

void include_clauses( Solver& S, const vector<Lit>& prev, const Lit& next ) {
	for( int i = 0; i < LIFE_TABLE; i++ ) {
		vec<Lit> clause;
		for( int j = 0; j < 9; j++ ) {
			if( i & (1 << j) ) {
				clause.push( ~prev[j] );
			} else {
				clause.push(  prev[j] );
			}
		}
		if( life_step[i] ) {
			clause.push(  next );
		} else {
			clause.push( ~next );
		}
		S.addClause( clause );
	}
}

/*
  A single life_solver instance wraps a variety of functions involving
  using a SAT solver to invert game of life positions.
*/
template<int X, int Y>
struct life_solver {
	grid<X, Y> final; // last life configuration
	int DEPTH;   // how many steps back are we going
	int HORIZON; // how many steps back do we care about forcing
	Lit TRUE;
	Solver S;

	// A list of known solutions:
	vector<vector<bool> > solutions;

	// This is a somewhat tricky construction for keeping track
	// whether things are possible
	bool* possible;

	life_solver( grid<X,Y> final, int DEPTH, int HORIZON ) :
		final(final), DEPTH(DEPTH), HORIZON(HORIZON) {
		// Add one variable for each cell at each of DEPTH+1
		// times
		for( int depth = 0; depth <= DEPTH; depth++ ) {
			for( int x = 0; x < X; x++ ) {
			for( int y = 0; y < Y; y++ ) {
				S.newVar();
			}
			}
		}
		// Add a variable that is forced true, for convenience
		S.newVar();
		TRUE = get_literal( DEPTH+1, 0, 0 );
		S.addClause( TRUE );
		assert( S.nVars() == (DEPTH+1) * X * Y + 1 );

		// Start record-keeping about possible variables
//		possible = vector<int>( DEPTH * X * Y + 1, 0 );

		// Set up SAT problem boundary condition
		for( int x = 0; x < X; x++ ) {
		for( int y = 0; y < Y; y++ ) {
			if( final.get_bool_uncentered(x,y) ) {
				S.addClause( get_literal( 0, x, y ) );
			} else {
				S.addClause( get_literal( 0, x, y, true ) );
			}
		}
		}

		// Set up SAT problem transition table
		for( int depth = 0; depth < DEPTH; depth++ ) {
			for( int x = 0; x < X; x++ ) {
			for( int y = 0; y < Y; y++ ) {
				vector<Lit> prev;
				for( int dx = -1; dx <= +1; dx++ ) {
				for( int dy = -1; dy <= +1; dy++ ) {
					Lit temp = get_literal( depth, x+dx, y+dy );
					prev.push_back( temp );
				}
				}
				Lit next = get_literal( depth+1, x, y );
				include_clauses(S, prev, next);
			}
			}
		}
	}

	int get_numbering( int depth, int x, int y ) {
		return (depth * X + x) * Y + y;
	}

	Lit get_literal( int depth, int x, int y, bool sign = false ) {
		if( 0 <= x and x < X and 0 <= y and y < Y ) {
			return mkLit( get_numbering( depth, x, y ), sign );
		} else {
			return ~TRUE;
		}
	}

	vector<bool> solve( ) {
		vector<bool> result;

		if( !S.simplify() ) {
			cerr << "Did not expect unsatisfiable problem.\n";
			exit( 50 );
		}

		vec<Lit> dummy;
		bool satisfiable = S.solve();
		if( not satisfiable ) {
			cerr << "Did not expect unsatisfiable problem.\n";
			exit( 60 );
		}

		bool indeterminate = false;
		vector<bool> solution;
		for( int i = 0; i < S.nVars(); i++ ) {
			lbool l = S.modelValue( mkLit(i) );
			if( l == l_True ) {
				solution.push_back( true  );
			} else if( l == l_False ) {
				solution.push_back( false );
			} else {
				solution.push_back( false );
				indeterminate = true;
			}
		}
		solutions.push_back(solution);
	}

	void extract_grid( grid<X,Y>& result ) {
		for( int x = 0; x < X; x++ ) {
		for( int y = 0; y < Y; y++ ) {
			result.set_uncentered( x, y, solutions[0][get_numbering(1,x,y)] );
		}
		}
	}
};

void sat( ) {
	grid<4,4> g = decode<4,4>( uniform_smallint( 1 << 16 ) );
	grid<4,4> h = evolve_once( g );
	life_solver<4,4> ls( h, 1, 1 );
	ls.solve();
	grid<4,4> i;
	ls.extract_grid( i );
	cout << "Starting grid:" << g << "\nOne step forward:\n" << h << "\nOne step back:\n" << i << "\n";
}

#endif
<commit_msg>Add template parameter.<commit_after>#ifndef SAT_HH
#define SAT_HH

#include "all.cc"
#include "life.hh"

void include_clauses( Solver& S, const vector<Lit>& prev, const Lit& next ) {
	for( int i = 0; i < LIFE_TABLE; i++ ) {
		vec<Lit> clause;
		for( int j = 0; j < 9; j++ ) {
			if( i & (1 << j) ) {
				clause.push( ~prev[j] );
			} else {
				clause.push(  prev[j] );
			}
		}
		if( life_step[i] ) {
			clause.push(  next );
		} else {
			clause.push( ~next );
		}
		S.addClause( clause );
	}
}

/*
  A single life_solver instance wraps a variety of functions involving
  using a SAT solver to invert game of life positions.
*/
template<int X, int Y>
struct life_solver {
	grid<X, Y> final; // last life configuration
	int DEPTH;   // how many steps back are we going
	int HORIZON; // how many steps back do we care about forcing
	Lit TRUE;
	Solver S;

	// A list of known solutions:
	vector<vector<bool> > solutions;

	// This is a somewhat tricky construction for keeping track
	// whether things are possible
	bool* possible;

	life_solver( grid<X,Y> final, int DEPTH, int HORIZON ) :
		final(final), DEPTH(DEPTH), HORIZON(HORIZON) {
		// Add one variable for each cell at each of DEPTH+1
		// times
		for( int depth = 0; depth <= DEPTH; depth++ ) {
			for( int x = 0; x < X; x++ ) {
			for( int y = 0; y < Y; y++ ) {
				S.newVar();
			}
			}
		}
		// Add a variable that is forced true, for convenience
		S.newVar();
		TRUE = get_literal( DEPTH+1, 0, 0 );
		S.addClause( TRUE );
		assert( S.nVars() == (DEPTH+1) * X * Y + 1 );

		// Start record-keeping about possible variables
//		possible = vector<int>( DEPTH * X * Y + 1, 0 );

		// Set up SAT problem boundary condition
		for( int x = 0; x < X; x++ ) {
		for( int y = 0; y < Y; y++ ) {
			if( final.get_bool_uncentered(x,y) ) {
				S.addClause( get_literal( 0, x, y ) );
			} else {
				S.addClause( get_literal( 0, x, y, true ) );
			}
		}
		}

		// Set up SAT problem transition table
		for( int depth = 0; depth < DEPTH; depth++ ) {
			for( int x = 0; x < X; x++ ) {
			for( int y = 0; y < Y; y++ ) {
				vector<Lit> prev;
				for( int dx = -1; dx <= +1; dx++ ) {
				for( int dy = -1; dy <= +1; dy++ ) {
					Lit temp = get_literal( depth, x+dx, y+dy );
					prev.push_back( temp );
				}
				}
				Lit next = get_literal( depth+1, x, y );
				include_clauses(S, prev, next);
			}
			}
		}
	}

	int get_numbering( int depth, int x, int y ) {
		return (depth * X + x) * Y + y;
	}

	Lit get_literal( int depth, int x, int y, bool sign = false ) {
		if( 0 <= x and x < X and 0 <= y and y < Y ) {
			return mkLit( get_numbering( depth, x, y ), sign );
		} else {
			return ~TRUE;
		}
	}

	vector<bool> solve( ) {
		vector<bool> result;

		if( !S.simplify() ) {
			cerr << "Did not expect unsatisfiable problem.\n";
			exit( 50 );
		}

		vec<Lit> dummy;
		bool satisfiable = S.solve();
		if( not satisfiable ) {
			cerr << "Did not expect unsatisfiable problem.\n";
			exit( 60 );
		}

		bool indeterminate = false;
		vector<bool> solution;
		for( int i = 0; i < S.nVars(); i++ ) {
			lbool l = S.modelValue( mkLit(i) );
			if( l == l_True ) {
				solution.push_back( true  );
			} else if( l == l_False ) {
				solution.push_back( false );
			} else {
				solution.push_back( false );
				indeterminate = true;
			}
		}
		solutions.push_back(solution);
	}

	void extract_grid( grid<X,Y>& result ) {
		for( int x = 0; x < X; x++ ) {
		for( int y = 0; y < Y; y++ ) {
			result.set_uncentered( x, y, solutions[0][get_numbering(1,x,y)] );
		}
		}
	}
};

void sat( ) {
	grid<4,4> g, h, i;
	g = decode<4,4>( uniform_smallint( 1 << 16 ) );
	h = evolve_once<4,4>( g );
	life_solver<4,4> ls( h, 1, 1 );
	ls.solve();
	ls.extract_grid( i );
	cout << "Starting grid:" << g << "\nOne step forward:\n" << h << "\nOne step back:\n" << i << "\n";
}

#endif
<|endoftext|>


<commit_before>// Copyright 2013 Tanel Lebedev

#include "./https_client.h"

#include <string>
#include <sstream>

#include "Poco/Exception.h"
#include "Poco/InflatingStream.h"
#include "Poco/DeflatingStream.h"
#include "Poco/Logger.h"
#include "Poco/URI.h"
#include "Poco/NumberParser.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/NameValueCollection.h"
#include "Poco/Net/HTTPMessage.h"
#include "Poco/Net/HTTPBasicCredentials.h"
#include "Poco/Net/InvalidCertificateHandler.h"
#include "Poco/Net/AcceptCertificateHandler.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/PrivateKeyPassphraseHandler.h"
#include "Poco/Net/SecureStreamSocket.h"

#include "./libjson.h"
#include "./version.h"

namespace kopsik {

error HTTPSClient::PostJSON(
    const std::string relative_url,
    const std::string json,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
  return requestJSON(Poco::Net::HTTPRequest::HTTP_POST,
    relative_url,
    json,
    basic_auth_username,
    basic_auth_password,
    response_body);
}

error HTTPSClient::GetJSON(
    const std::string relative_url,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
  return requestJSON(Poco::Net::HTTPRequest::HTTP_GET,
    relative_url,
    "",
    basic_auth_username,
    basic_auth_password,
    response_body);
}

error HTTPSClient::requestJSON(
    const std::string method,
    const std::string relative_url,
    const std::string json,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
  return request(
    method,
    relative_url,
    json,
    basic_auth_username,
    basic_auth_password,
    response_body);
}

error HTTPSClient::request(
    const std::string method,
    const std::string relative_url,
    const std::string payload,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
  poco_assert(!method.empty());
  poco_assert(!relative_url.empty());
  poco_assert(response_body);

  *response_body = "";

  try {
    Poco::URI uri(api_url_);

    Poco::SharedPtr<Poco::Net::InvalidCertificateHandler> acceptCertHandler =
      new Poco::Net::AcceptCertificateHandler(true);

    Poco::Net::Context::Ptr context(new Poco::Net::Context(
      Poco::Net::Context::CLIENT_USE, "",
      Poco::Net::Context::VERIFY_RELAXED, 9, true, "ALL"));

/*
    const Poco::Net::Context::Ptr context(new Poco::Net::Context(
      Poco::Net::Context::CLIENT_USE, "", "", "",
      Poco::Net::Context::VERIFY_NONE, 9, false,
      "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"));
*/

    Poco::Net::SSLManager::instance().initializeClient(
      0, acceptCertHandler, context);

    Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort(),
      context);
    if (proxy_.IsConfigured()) {
      session.setProxy(proxy_.host, proxy_.port);
      if (proxy_.HasCredentials()) {
        session.setProxyCredentials(proxy_.username, proxy_.password);
      }
    }
    session.setKeepAlive(false);
    session.setTimeout(Poco::Timespan(10 * Poco::Timespan::SECONDS));

    Poco::Logger &logger = Poco::Logger::get("https_client");
    {
      std::stringstream ss;
      ss << "Sending request to " << relative_url << " ..";
      logger.debug(ss.str());
    }

    Poco::Net::HTTPRequest req(method,
      relative_url, Poco::Net::HTTPMessage::HTTP_1_1);
    req.setKeepAlive(false);
    req.setContentType("application/json");
    req.set("User-Agent", kopsik::UserAgent(app_name_, app_version_));
    req.setChunkedTransferEncoding(true);

    Poco::Net::HTTPBasicCredentials cred(
      basic_auth_username, basic_auth_password);
    if (!basic_auth_username.empty() && !basic_auth_password.empty()) {
      cred.authenticate(req);
    }

    std::istringstream requestStream(payload);
    Poco::DeflatingInputStream gzipRequest(requestStream,
      Poco::DeflatingStreamBuf::STREAM_GZIP);
    Poco::DeflatingStreamBuf *pBuff = gzipRequest.rdbuf();

    Poco::Int64 size = pBuff->pubseekoff(0, std::ios::end, std::ios::in);
    pBuff->pubseekpos(0, std::ios::in);

    req.setContentLength(size);
    req.set("Content-Encoding", "gzip");
    req.set("Accept-Encoding", "gzip");

    session.sendRequest(req) << pBuff << std::flush;

    // Log out request contents
    std::stringstream request_string;
    req.write(request_string);
    logger.debug(request_string.str());

    logger.debug("Request sent. Receiving response..");

    // Receive response
    Poco::Net::HTTPResponse response;
    std::istream& is = session.receiveResponse(response);

    // Inflate
    Poco::InflatingInputStream inflater(is,
      Poco::InflatingStreamBuf::STREAM_GZIP);
    std::stringstream ss;
    ss << inflater.rdbuf();
    *response_body = ss.str();

    // Log out response contents
    std::stringstream response_string;
    response_string << "Response status: " << response.getStatus()
      << ", reason: " << response.getReason()
      << ", Content type: " << response.getContentType();
    if (response.has("Content-Encoding")) {
      response_string << ", Content-Encoding: "
        << response.get("Content-Encoding");
    }
    logger.debug(response_string.str());
    logger.trace(*response_body);

    if (response.getStatus() < 200 || response.getStatus() >= 300) {
      if (response_body->empty()) {
        std::stringstream description;
        description << "Request to server failed with status code: "
          << response.getStatus();
        return description.str();
      }
      return "Data push failed with error: " + *response_body;
    }
  } catch(const Poco::Exception& exc) {
    return exc.displayText();
  } catch(const std::exception& ex) {
    return ex.what();
  } catch(const std::string& ex) {
    return ex;
  }
  return noError;
}

}   // namespace kopsik
<commit_msg>Debug server responses<commit_after>// Copyright 2013 Tanel Lebedev

#include "./https_client.h"

#include <string>
#include <sstream>

#include "Poco/Exception.h"
#include "Poco/InflatingStream.h"
#include "Poco/DeflatingStream.h"
#include "Poco/Logger.h"
#include "Poco/URI.h"
#include "Poco/NumberParser.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/NameValueCollection.h"
#include "Poco/Net/HTTPMessage.h"
#include "Poco/Net/HTTPBasicCredentials.h"
#include "Poco/Net/InvalidCertificateHandler.h"
#include "Poco/Net/AcceptCertificateHandler.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/PrivateKeyPassphraseHandler.h"
#include "Poco/Net/SecureStreamSocket.h"

#include "./libjson.h"
#include "./version.h"

namespace kopsik {

error HTTPSClient::PostJSON(
    const std::string relative_url,
    const std::string json,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
  return requestJSON(Poco::Net::HTTPRequest::HTTP_POST,
    relative_url,
    json,
    basic_auth_username,
    basic_auth_password,
    response_body);
}

error HTTPSClient::GetJSON(
    const std::string relative_url,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
  return requestJSON(Poco::Net::HTTPRequest::HTTP_GET,
    relative_url,
    "",
    basic_auth_username,
    basic_auth_password,
    response_body);
}

error HTTPSClient::requestJSON(
    const std::string method,
    const std::string relative_url,
    const std::string json,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
  return request(
    method,
    relative_url,
    json,
    basic_auth_username,
    basic_auth_password,
    response_body);
}

error HTTPSClient::request(
    const std::string method,
    const std::string relative_url,
    const std::string payload,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
  poco_assert(!method.empty());
  poco_assert(!relative_url.empty());
  poco_assert(response_body);

  *response_body = "";

  try {
    Poco::URI uri(api_url_);

    Poco::SharedPtr<Poco::Net::InvalidCertificateHandler> acceptCertHandler =
      new Poco::Net::AcceptCertificateHandler(true);

    Poco::Net::Context::Ptr context(new Poco::Net::Context(
      Poco::Net::Context::CLIENT_USE, "",
      Poco::Net::Context::VERIFY_RELAXED, 9, true, "ALL"));

/*
    const Poco::Net::Context::Ptr context(new Poco::Net::Context(
      Poco::Net::Context::CLIENT_USE, "", "", "",
      Poco::Net::Context::VERIFY_NONE, 9, false,
      "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"));
*/

    Poco::Net::SSLManager::instance().initializeClient(
      0, acceptCertHandler, context);

    Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort(),
      context);
    if (proxy_.IsConfigured()) {
      session.setProxy(proxy_.host, proxy_.port);
      if (proxy_.HasCredentials()) {
        session.setProxyCredentials(proxy_.username, proxy_.password);
      }
    }
    session.setKeepAlive(false);
    session.setTimeout(Poco::Timespan(10 * Poco::Timespan::SECONDS));

    Poco::Logger &logger = Poco::Logger::get("https_client");
    {
      std::stringstream ss;
      ss << "Sending request to " << relative_url << " ..";
      logger.debug(ss.str());
    }

    Poco::Net::HTTPRequest req(method,
      relative_url, Poco::Net::HTTPMessage::HTTP_1_1);
    req.setKeepAlive(false);
    req.setContentType("application/json");
    req.set("User-Agent", kopsik::UserAgent(app_name_, app_version_));
    req.setChunkedTransferEncoding(true);

    Poco::Net::HTTPBasicCredentials cred(
      basic_auth_username, basic_auth_password);
    if (!basic_auth_username.empty() && !basic_auth_password.empty()) {
      cred.authenticate(req);
    }

    std::istringstream requestStream(payload);
    Poco::DeflatingInputStream gzipRequest(requestStream,
      Poco::DeflatingStreamBuf::STREAM_GZIP);
    Poco::DeflatingStreamBuf *pBuff = gzipRequest.rdbuf();

    Poco::Int64 size = pBuff->pubseekoff(0, std::ios::end, std::ios::in);
    pBuff->pubseekpos(0, std::ios::in);

    req.setContentLength(size);
    req.set("Content-Encoding", "gzip");
    req.set("Accept-Encoding", "gzip");

    session.sendRequest(req) << pBuff << std::flush;

    // Log out request contents
    std::stringstream request_string;
    req.write(request_string);
    logger.debug(request_string.str());

    logger.debug("Request sent. Receiving response..");

    // Receive response
    Poco::Net::HTTPResponse response;
    std::istream& is = session.receiveResponse(response);

    // Inflate
    Poco::InflatingInputStream inflater(is,
      Poco::InflatingStreamBuf::STREAM_GZIP);
    std::stringstream ss;
    ss << inflater.rdbuf();
    *response_body = ss.str();

    // Log out response contents
    std::stringstream response_string;
    response_string << "Response status: " << response.getStatus()
      << ", reason: " << response.getReason()
      << ", Content type: " << response.getContentType();
    if (response.has("Content-Encoding")) {
      response_string << ", Content-Encoding: "
        << response.get("Content-Encoding");
    }
    logger.debug(response_string.str());
    logger.debug(*response_body);

    if (response.getStatus() < 200 || response.getStatus() >= 300) {
      if (response_body->empty()) {
        std::stringstream description;
        description << "Request to server failed with status code: "
          << response.getStatus();
        return description.str();
      }
      return "Data push failed with error: " + *response_body;
    }
  } catch(const Poco::Exception& exc) {
    return exc.displayText();
  } catch(const std::exception& ex) {
    return ex.what();
  } catch(const std::string& ex) {
    return ex;
  }
  return noError;
}

}   // namespace kopsik
<|endoftext|>


<commit_before>#include "tmc.h"

#include <deque>
#include <fstream>
#include <sstream>

#include "util.h"

namespace redsea {

namespace tmc {

std::map<uint16_t,Event> g_event_data;

namespace {

uint16_t popBits(std::deque<int>& bit_deque, int len) {
  uint16_t result = 0x00;
  if ((int)bit_deque.size() >= len) {
    for (int i=0; i<len; i++) {
      result = (result << 1) | bit_deque.at(0);
      bit_deque.pop_front();
    }
  }
  return result;
}

// label, field_data
std::vector<std::pair<uint16_t,uint16_t>>
  getFreeformFields(std::vector<MessagePart> parts) {

  const std::vector<int> field_size(
      {3, 3, 5, 5, 5, 8, 8, 8, 8, 11, 16, 16, 16, 16, 0, 0});

  uint16_t second_gsi = bits(parts[1].data[0], 12, 2);

  // Concatenate freeform data from used message length (derived from
  // GSI of second group)
  std::deque<int> freeform_data_bits;
  for (int i=0; i<(int)parts.size(); i++) {
    if (!parts[i].is_received)
      break;

    if (i <= 1 || i >= (int)parts.size() - second_gsi) {
      for (int b=0; b<12; b++)
        freeform_data_bits.push_back((parts[i].data[0] >> (11-b)) & 0x1);
      for (int b=0; b<16; b++)
        freeform_data_bits.push_back((parts[i].data[1] >> (15-b)) & 0x1);
    }
  }

  // Decode freeform data
  //int bits_left = freeform_data_bits.size();
  std::vector<std::pair<uint16_t,uint16_t>> result;
  while (freeform_data_bits.size() > 4) {
    uint16_t label = popBits(freeform_data_bits, 4);
    if ((int)freeform_data_bits.size() < field_size.at(label))
      break;

    uint16_t field_data = popBits(freeform_data_bits, field_size.at(label));

    result.push_back({label, field_data});
  }

  return result;
}

std::string timeString(uint16_t field_data) {
  std::string time_string("");
  if (field_data <= 95) {
    char t[6];
    std::snprintf(t, 6, "%02d:%02d", field_data/4, 15*(field_data % 4));
    time_string = t;
  } else if (field_data <= 200) {
    char t[25];
    std::snprintf(t, 25, "after %d days at %02d:00", (field_data-96)/24,
        (field_data-96)%24);
    time_string = t;
  } else if (field_data <= 231) {
    char t[20];
    std::snprintf(t, 20, "day %d of the month", field_data-200);
    time_string = t;
  } else {
    int mo = (field_data-232) / 2;
    bool end_mid = (field_data-232) % 2;
    std::vector<std::string> month_names({"Jan","Feb","Mar","Apr","May",
        "Jun","Jul","Aug","Sep","Oct","Nov","Dec"});
    if (mo < 12) {
      time_string = (end_mid ? "end of " : "mid-") + month_names.at(mo);
    }
  }

  return time_string;
}

std::string sentence(std::string in) {
  std::string result = in + ".";
  result[0] = std::toupper(result[0]);
  return result;
}

} // namespace

Event::Event() {

}

Event::Event(std::string _desc, std::string _desc_q, uint16_t _nature,
    uint16_t _qtype, uint16_t _dur, uint16_t _dir, uint16_t _urg,
    uint16_t _class) : description(_desc), description_with_quantifier(_desc_q),
    nature(_nature), quantifier_type(_qtype), duration_type(_dur),
    directionality(_dir), urgency(_urg), update_class(_class) {
}

Event getEvent(uint16_t code) {

  if (g_event_data.find(code) != g_event_data.end())
    return g_event_data.find(code)->second;
  else
    return Event();

}

std::string getSupplInfoString(uint16_t code) {
  std::map<uint16_t,std::string> suppl_info_list;
  return suppl_info_list[code];
}

void loadEventData() {
  std::ifstream in("data/tmc_events.csv");

  if (!in.is_open())
    return;

  for (std::string line; std::getline(in, line); ) {
    if (!in.good())
      break;

    std::stringstream iss(line);
    uint16_t code;
    std::vector<std::string> strings(2);
    std::vector<uint16_t> nums(6);

    for (int col=0; col<9; col++) {
      std::string val;
      std::getline(iss, val, ';');
      if (!iss.good())
        break;

      if (col == 0)
        code = std::stoi(val);
      else if (col <= 2)
        strings[col-1] = val;
      else
        nums[col-3] = std::stoi(val);
    }

    g_event_data.insert({code, {strings[0], strings[1], nums[0], nums[1],
        nums[2], nums[3], nums[4], nums[5]}});

  }

  in.close();

}

TMC::TMC() : is_initialized_(false), has_encid_(false), multi_group_buffer_(5),
  ps_(8) {

}

void TMC::systemGroup(uint16_t message) {

  if (bits(message, 14, 1) == 0) {
    printf(", tmc: { system_info: { ");

    if (g_event_data.empty())
      loadEventData();

    is_initialized_ = true;
    ltn_ = bits(message, 6, 6);
    is_encrypted_ = (ltn_ == 0);

    printf("is_encrypted: %s", is_encrypted_ ? "true" : "false");

    if (!is_encrypted_)
      printf(", location_table: \"0x%02x\"", ltn_);

    bool afi   = bits(message, 5, 1);
    bool m     = bits(message, 4, 1);
    bool mgs_i = bits(message, 3, 1);
    bool mgs_n = bits(message, 2, 1);
    bool mgs_r = bits(message, 1, 1);
    bool mgs_u = bits(message, 0, 1);

    printf(", is_on_alt_freqs: %s", afi ? "true" : "false");

    std::vector<std::string> scope;
    if (mgs_i)
      scope.push_back("\"inter-road\"");
    if (mgs_n)
      scope.push_back("\"national\"");
    if (mgs_r)
      scope.push_back("\"regional\"");
    if (mgs_u)
      scope.push_back("\"urban\"");

    printf(", scope: [ %s ]", join(scope, ", ").c_str());

    printf(" } }");
  }

}

void TMC::userGroup(uint16_t x, uint16_t y, uint16_t z) {

  if (!is_initialized_)
    return;

  bool t = bits(x, 4, 1);

  // Encryption administration group
  if (bits(x, 0, 5) == 0x00) {
    sid_   = bits(y, 5, 6);
    encid_ = bits(y, 0, 5);
    ltnbe_ = bits(z, 10, 6);
    has_encid_ = true;

    printf(", tmc: { service_id: \"0x%02x\", encryption_id: \"0x%02x\", "
        "location_table: \"0x%02x\" }", sid_, encid_, ltnbe_);

  // Tuning information
  } else if (t) {
    uint16_t variant = bits(x, 0, 4);

    if (variant == 4 || variant == 5) {

      int pos = 4 * (variant - 4);

      ps_.setAt(pos,   bits(y, 8, 8));
      ps_.setAt(pos+1, bits(y, 0, 8));
      ps_.setAt(pos+2, bits(z, 8, 8));
      ps_.setAt(pos+3, bits(z, 0, 8));

      if (ps_.isComplete())
        printf(", tmc: { service_provider: \"%s\" }",
            ps_.getLastCompleteString().c_str());

    } else {
      printf(", tmc: { /* TODO: tuning info variant %d */ }", variant);
    }

  // User message
  } else {

    if (is_encrypted_ && !has_encid_)
      return;

    bool f = bits(x, 3, 1);

    // Single-group message
    if (f) {
      Message message(false, is_encrypted_, {{true, {x, y, z}}});
      message.print();
      current_ci_ = 0;

    // Part of multi-group message
    } else {

      uint16_t ci = bits(x, 0, 3);
      bool     fg = bits(y, 15, 1);

      if (ci != current_ci_ /* TODO 15-second limit */) {
        Message message(true, is_encrypted_, multi_group_buffer_);
        message.print();
        multi_group_buffer_[0].is_received = false;
        current_ci_ = ci;
      }

      int cur_grp;

      if (fg)
        cur_grp = 0;
      else if (bits(y, 14, 1))
        cur_grp = 1;
      else
        cur_grp = 4 - bits(y, 12, 2);

      multi_group_buffer_.at(cur_grp) = {true, {y, z}};

    }
  }

}

Message::Message(bool is_multi, bool is_loc_encrypted,
    std::vector<MessagePart> parts) : is_encrypted(is_loc_encrypted), events() {

  // single-group
  if (!is_multi) {
    duration  = bits(parts[0].data[0], 0, 3);
    divertadv = bits(parts[0].data[1], 15, 1);
    direction = bits(parts[0].data[1], 14, 1);
    extent    = bits(parts[0].data[1], 11, 3);
    events.push_back(bits(parts[0].data[1], 0, 11));
    location  = parts[0].data[2];
    is_complete = true;

  // multi-group
  } else {

    // Need at least the first group
    if (!parts[0].is_received)
      return;

    is_complete=true;

    // First group
    direction = bits(parts[0].data[0], 14, 1);
    extent    = bits(parts[0].data[0], 11, 3);
    events.push_back(bits(parts[0].data[0], 0, 11));
    location  = parts[0].data[1];

    // Subsequent parts
    if (parts[1].is_received) {
      auto freeform = getFreeformFields(parts);

      for (auto p : freeform) {
        uint16_t label = p.first;
        uint16_t field_data = p.second;
        //printf ("tmc: label %04x: field_data %04x\n",label,field_data);

        // Duration
        if (label == 0) {
          duration = field_data;

        // Length of route affected
        } else if (label == 2) {
            length_affected = field_data;
            has_length_affected = true;

        // Start / stop time
        } else if (label == 7) {
          time_starts = field_data;
          has_time_starts = true;
        } else if (label == 8) {
          time_until = field_data;
          has_time_until = true;
        } else {
          printf(" /* TODO label=%d */",label);
        }
      }
    }
  }
}

void Message::print() const {
  printf(", traffic_message: { ");

  if (!is_complete || events.empty()) {
    printf("}\n");
    return;
  }

  if (events.size() > 1) {
    printf("events: [ %s ]", commaJoin(events).c_str());
  } else {
    printf("event: { code: %d, description: \"%s\" }", events[0],
        sentence(getEvent(events[0]).description).c_str());
  }

  printf(", %slocation: \"0x%02x\", direction: \"%s\", extent: %d, "
         "diversion_advised: %s",
         (is_encrypted ? "encrypted_" : ""), location,
         direction ? "negative" : "positive",
         extent, divertadv ? "true" : "false" );

  if (has_time_starts)
    printf(", starts: \"%s\"", timeString(time_starts).c_str());
  if (has_time_until)
    printf(", until: \"%s\"", timeString(time_until).c_str());

  printf ("}");

}

} // namespace tmc
} // namespace redsea
<commit_msg>traffic_message -> tmc_message<commit_after>#include "tmc.h"

#include <deque>
#include <fstream>
#include <sstream>

#include "util.h"

namespace redsea {

namespace tmc {

std::map<uint16_t,Event> g_event_data;

namespace {

uint16_t popBits(std::deque<int>& bit_deque, int len) {
  uint16_t result = 0x00;
  if ((int)bit_deque.size() >= len) {
    for (int i=0; i<len; i++) {
      result = (result << 1) | bit_deque.at(0);
      bit_deque.pop_front();
    }
  }
  return result;
}

// label, field_data
std::vector<std::pair<uint16_t,uint16_t>>
  getFreeformFields(std::vector<MessagePart> parts) {

  const std::vector<int> field_size(
      {3, 3, 5, 5, 5, 8, 8, 8, 8, 11, 16, 16, 16, 16, 0, 0});

  uint16_t second_gsi = bits(parts[1].data[0], 12, 2);

  // Concatenate freeform data from used message length (derived from
  // GSI of second group)
  std::deque<int> freeform_data_bits;
  for (int i=0; i<(int)parts.size(); i++) {
    if (!parts[i].is_received)
      break;

    if (i <= 1 || i >= (int)parts.size() - second_gsi) {
      for (int b=0; b<12; b++)
        freeform_data_bits.push_back((parts[i].data[0] >> (11-b)) & 0x1);
      for (int b=0; b<16; b++)
        freeform_data_bits.push_back((parts[i].data[1] >> (15-b)) & 0x1);
    }
  }

  // Decode freeform data
  //int bits_left = freeform_data_bits.size();
  std::vector<std::pair<uint16_t,uint16_t>> result;
  while (freeform_data_bits.size() > 4) {
    uint16_t label = popBits(freeform_data_bits, 4);
    if ((int)freeform_data_bits.size() < field_size.at(label))
      break;

    uint16_t field_data = popBits(freeform_data_bits, field_size.at(label));

    result.push_back({label, field_data});
  }

  return result;
}

std::string timeString(uint16_t field_data) {
  std::string time_string("");
  if (field_data <= 95) {
    char t[6];
    std::snprintf(t, 6, "%02d:%02d", field_data/4, 15*(field_data % 4));
    time_string = t;
  } else if (field_data <= 200) {
    char t[25];
    std::snprintf(t, 25, "after %d days at %02d:00", (field_data-96)/24,
        (field_data-96)%24);
    time_string = t;
  } else if (field_data <= 231) {
    char t[20];
    std::snprintf(t, 20, "day %d of the month", field_data-200);
    time_string = t;
  } else {
    int mo = (field_data-232) / 2;
    bool end_mid = (field_data-232) % 2;
    std::vector<std::string> month_names({"Jan","Feb","Mar","Apr","May",
        "Jun","Jul","Aug","Sep","Oct","Nov","Dec"});
    if (mo < 12) {
      time_string = (end_mid ? "end of " : "mid-") + month_names.at(mo);
    }
  }

  return time_string;
}

std::string sentence(std::string in) {
  std::string result = in + ".";
  result[0] = std::toupper(result[0]);
  return result;
}

} // namespace

Event::Event() {

}

Event::Event(std::string _desc, std::string _desc_q, uint16_t _nature,
    uint16_t _qtype, uint16_t _dur, uint16_t _dir, uint16_t _urg,
    uint16_t _class) : description(_desc), description_with_quantifier(_desc_q),
    nature(_nature), quantifier_type(_qtype), duration_type(_dur),
    directionality(_dir), urgency(_urg), update_class(_class) {
}

Event getEvent(uint16_t code) {

  if (g_event_data.find(code) != g_event_data.end())
    return g_event_data.find(code)->second;
  else
    return Event();

}

std::string getSupplInfoString(uint16_t code) {
  std::map<uint16_t,std::string> suppl_info_list;
  return suppl_info_list[code];
}

void loadEventData() {
  std::ifstream in("data/tmc_events.csv");

  if (!in.is_open())
    return;

  for (std::string line; std::getline(in, line); ) {
    if (!in.good())
      break;

    std::stringstream iss(line);
    uint16_t code;
    std::vector<std::string> strings(2);
    std::vector<uint16_t> nums(6);

    for (int col=0; col<9; col++) {
      std::string val;
      std::getline(iss, val, ';');
      if (!iss.good())
        break;

      if (col == 0)
        code = std::stoi(val);
      else if (col <= 2)
        strings[col-1] = val;
      else
        nums[col-3] = std::stoi(val);
    }

    g_event_data.insert({code, {strings[0], strings[1], nums[0], nums[1],
        nums[2], nums[3], nums[4], nums[5]}});

  }

  in.close();

}

TMC::TMC() : is_initialized_(false), has_encid_(false), multi_group_buffer_(5),
  ps_(8) {

}

void TMC::systemGroup(uint16_t message) {

  if (bits(message, 14, 1) == 0) {
    printf(", tmc: { system_info: { ");

    if (g_event_data.empty())
      loadEventData();

    is_initialized_ = true;
    ltn_ = bits(message, 6, 6);
    is_encrypted_ = (ltn_ == 0);

    printf("is_encrypted: %s", is_encrypted_ ? "true" : "false");

    if (!is_encrypted_)
      printf(", location_table: \"0x%02x\"", ltn_);

    bool afi   = bits(message, 5, 1);
    bool m     = bits(message, 4, 1);
    bool mgs_i = bits(message, 3, 1);
    bool mgs_n = bits(message, 2, 1);
    bool mgs_r = bits(message, 1, 1);
    bool mgs_u = bits(message, 0, 1);

    printf(", is_on_alt_freqs: %s", afi ? "true" : "false");

    std::vector<std::string> scope;
    if (mgs_i)
      scope.push_back("\"inter-road\"");
    if (mgs_n)
      scope.push_back("\"national\"");
    if (mgs_r)
      scope.push_back("\"regional\"");
    if (mgs_u)
      scope.push_back("\"urban\"");

    printf(", scope: [ %s ]", join(scope, ", ").c_str());

    printf(" } }");
  }

}

void TMC::userGroup(uint16_t x, uint16_t y, uint16_t z) {

  if (!is_initialized_)
    return;

  bool t = bits(x, 4, 1);

  // Encryption administration group
  if (bits(x, 0, 5) == 0x00) {
    sid_   = bits(y, 5, 6);
    encid_ = bits(y, 0, 5);
    ltnbe_ = bits(z, 10, 6);
    has_encid_ = true;

    printf(", tmc: { service_id: \"0x%02x\", encryption_id: \"0x%02x\", "
        "location_table: \"0x%02x\" }", sid_, encid_, ltnbe_);

  // Tuning information
  } else if (t) {
    uint16_t variant = bits(x, 0, 4);

    if (variant == 4 || variant == 5) {

      int pos = 4 * (variant - 4);

      ps_.setAt(pos,   bits(y, 8, 8));
      ps_.setAt(pos+1, bits(y, 0, 8));
      ps_.setAt(pos+2, bits(z, 8, 8));
      ps_.setAt(pos+3, bits(z, 0, 8));

      if (ps_.isComplete())
        printf(", tmc: { service_provider: \"%s\" }",
            ps_.getLastCompleteString().c_str());

    } else {
      printf(", tmc: { /* TODO: tuning info variant %d */ }", variant);
    }

  // User message
  } else {

    if (is_encrypted_ && !has_encid_)
      return;

    bool f = bits(x, 3, 1);

    // Single-group message
    if (f) {
      Message message(false, is_encrypted_, {{true, {x, y, z}}});
      message.print();
      current_ci_ = 0;

    // Part of multi-group message
    } else {

      uint16_t ci = bits(x, 0, 3);
      bool     fg = bits(y, 15, 1);

      if (ci != current_ci_ /* TODO 15-second limit */) {
        Message message(true, is_encrypted_, multi_group_buffer_);
        message.print();
        multi_group_buffer_[0].is_received = false;
        current_ci_ = ci;
      }

      int cur_grp;

      if (fg)
        cur_grp = 0;
      else if (bits(y, 14, 1))
        cur_grp = 1;
      else
        cur_grp = 4 - bits(y, 12, 2);

      multi_group_buffer_.at(cur_grp) = {true, {y, z}};

    }
  }

}

Message::Message(bool is_multi, bool is_loc_encrypted,
    std::vector<MessagePart> parts) : is_encrypted(is_loc_encrypted), events() {

  // single-group
  if (!is_multi) {
    duration  = bits(parts[0].data[0], 0, 3);
    divertadv = bits(parts[0].data[1], 15, 1);
    direction = bits(parts[0].data[1], 14, 1);
    extent    = bits(parts[0].data[1], 11, 3);
    events.push_back(bits(parts[0].data[1], 0, 11));
    location  = parts[0].data[2];
    is_complete = true;

  // multi-group
  } else {

    // Need at least the first group
    if (!parts[0].is_received)
      return;

    is_complete=true;

    // First group
    direction = bits(parts[0].data[0], 14, 1);
    extent    = bits(parts[0].data[0], 11, 3);
    events.push_back(bits(parts[0].data[0], 0, 11));
    location  = parts[0].data[1];

    // Subsequent parts
    if (parts[1].is_received) {
      auto freeform = getFreeformFields(parts);

      for (auto p : freeform) {
        uint16_t label = p.first;
        uint16_t field_data = p.second;
        //printf ("tmc: label %04x: field_data %04x\n",label,field_data);

        // Duration
        if (label == 0) {
          duration = field_data;

        // Length of route affected
        } else if (label == 2) {
            length_affected = field_data;
            has_length_affected = true;

        // Start / stop time
        } else if (label == 7) {
          time_starts = field_data;
          has_time_starts = true;
        } else if (label == 8) {
          time_until = field_data;
          has_time_until = true;
        } else {
          printf(" /* TODO label=%d */",label);
        }
      }
    }
  }
}

void Message::print() const {
  printf(", tmc_message: { ");

  if (!is_complete || events.empty()) {
    printf("}\n");
    return;
  }

  if (events.size() > 1) {
    printf("events: [ %s ]", commaJoin(events).c_str());
  } else {
    printf("event: { code: %d, description: \"%s\" }", events[0],
        sentence(getEvent(events[0]).description).c_str());
  }

  printf(", %slocation: \"0x%02x\", direction: \"%s\", extent: %d, "
         "diversion_advised: %s",
         (is_encrypted ? "encrypted_" : ""), location,
         direction ? "negative" : "positive",
         extent, divertadv ? "true" : "false" );

  if (has_time_starts)
    printf(", starts: \"%s\"", timeString(time_starts).c_str());
  if (has_time_until)
    printf(", until: \"%s\"", timeString(time_until).c_str());

  printf ("}");

}

} // namespace tmc
} // namespace redsea
<|endoftext|>


<commit_before>#include <memory>

#include "uci.h"
#include "version.h"
#include <iostream>
#include <thread>

namespace {
Book book;
std::shared_ptr<Search> search;
Board board;
std::vector<ZKey> positionHistory;

void loadBook() {
  std::ifstream bookFile(optionsMap["BookPath"].getValue());
  bool bookOk = bookFile.good();
  bookFile.close();

  if (bookOk) {
    book = Book(optionsMap["BookPath"].getValue());
  } else {
    std::cerr << optionsMap["BookPath"].getValue() << " is inaccessible or doesn't exist" << std::endl;
  }
}

void initOptions() {
  optionsMap["OwnBook"] = Option(false);
  optionsMap["BookPath"] = Option("book.bin", &loadBook);
}

void uciNewGame() {
  board.setToStartPos();
  positionHistory.clear();
}

void setPosition(std::istringstream &is) {
  std::string token;
  is >> token;

  if (token == "startpos") {
    board.setToStartPos();
  } else {
    std::string fen;

    while (is >> token && token != "moves") {
      fen += token + " ";
    }

    board.setToFen(fen);
  }

  while (is >> token) {
    if (token == "moves") {
      continue;
    }

    MoveGen movegen(board);
    for (auto move : movegen.getMoves()) {
      if (move.getNotation() == token) {
        board.doMove(move);
        positionHistory.push_back(board.getZKey());
        break;
      }
    }
  }
}

void pickBestMove() {
  if (optionsMap["OwnBook"].getValue() == "true" && book.inBook(board)) {
    std::cout << "bestmove " << book.getMove(board).getNotation() << std::endl;
  } else {
    search->iterDeep();
  }
}

void go(std::istringstream &is) {
  std::string token;
  Search::Limits limits;

  while (is >> token) {
    if (token == "depth") is >> limits.depth;
    else if (token == "infinite") limits.infinite = true;
    else if (token == "movetime") is >> limits.moveTime;
    else if (token == "nodes") is >> limits.nodes;
    else if (token == "wtime") is >> limits.time[WHITE];
    else if (token == "btime") is >> limits.time[BLACK];
    else if (token == "winc") is >> limits.increment[WHITE];
    else if (token == "binc") is >> limits.increment[BLACK];
    else if (token == "movestogo") is >> limits.movesToGo;
  }

  search = std::make_shared<Search>(board, limits, positionHistory);

  std::thread searchThread(&pickBestMove);
  searchThread.detach();
}

unsigned long long perft(const Board &board, int depth) {
  if (depth <= 0) {
    return 1;
  } else if (depth == 1) {
    return MoveGen(board).getLegalMoves().size();
  }

  MoveGen movegen(board);

  unsigned long long nodes = 0;
  for (auto move : movegen.getLegalMoves()) {
    Board movedBoard = board;
    movedBoard.doMove(move);

    nodes += perft(movedBoard, depth - 1);
  }

  return nodes;
}

void perftDivide(int depth) {
  unsigned long long total = 0;

  MoveGen movegen(board);

  std::cout << std::endl;
  auto start = std::chrono::steady_clock::now();
  for (auto move : movegen.getLegalMoves()) {
    Board movedBoard = board;
    movedBoard.doMove(move);

    unsigned long long perftRes = perft(movedBoard, depth - 1);
    total += perftRes;

    std::cout << move.getNotation() << ": " << perftRes << std::endl;
  }
  auto end = std::chrono::steady_clock::now();
  std::chrono::duration<double> elapsed = end - start;

  std::cout << std::endl << "==========================" << std::endl;
  std::cout << "Total time (ms) : " << static_cast<int>(elapsed.count() * 1000) << std::endl;
  std::cout << "Nodes searched  : " << total << std::endl;
  std::cout << "Nodes / second  : " << static_cast<int>(total / elapsed.count()) << std::endl;
}

void printEngineInfo() {
  std::cout << "id name Shallow Blue " << VER_MAJ << "." << VER_MIN << "." << VER_PATCH << std::endl;
  std::cout << "id author Rhys Rustad-Elliott" << std::endl;
  std::cout << std::endl;

  for (auto optionPair : optionsMap) {
    std::cout << "option ";
    std::cout << "name " << optionPair.first << " ";
    std::cout << "type " << optionPair.second.getType() << " ";
    std::cout << "default " << optionPair.second.getDefaultValue() << " ";

    if (optionPair.second.getType() == "spin") {
      std::cout << "min " << optionPair.second.getMin() << " ";
      std::cout << "max " << optionPair.second.getMax();
    }
    std::cout << std::endl;
  }
  std::cout << "uciok" << std::endl;
}

void setOption(std::istringstream &is) {
  std::string token;
  std::string optionName;

  is >> token >> optionName; // Advance past "name"

  if (optionsMap.find(optionName) != optionsMap.end()) {
    is >> token >> token; // Advance past "value"
    optionsMap[optionName].setValue(token);
  } else {
    std::cout << "Invalid option" << std::endl;
  }
}

void loop() {
  std::cout << "Shallow Blue " << VER_MAJ << "." << VER_MIN << "." << VER_PATCH;
  std::cout << " by Rhys Rustad-Elliott";
  std::cout << " (built " << __DATE__ << " " << __TIME__ << ")" << std::endl;

#ifdef __DEBUG__
  std::cout << "***DEBUG BUILD (This will be slow)***" << std::endl;
#endif

  board.setToStartPos();

  std::string line;
  std::string token;

  while (std::getline(std::cin, line)) {
    std::istringstream is(line);
    is >> token;

    if (token == "uci") {
      printEngineInfo();
    } else if (token == "ucinewgame") {
      uciNewGame();
    } else if (token == "isready") {
      std::cout << "readyok" << std::endl;
    } else if (token == "stop") {
      if (search) search->stop();
    } else if (token == "go") {
      go(is);
    } else if (token == "quit") {
      if (search) search->stop();
      return;
    } else if (token == "position") {
      setPosition(is);
    } else if (token == "setoption") {
      setOption(is);
    }

      // Non UCI commands
    else if (token == "printboard") {
      std::cout << std::endl << board.getStringRep() << std::endl;
    } else if (token == "printmoves") {
      for (auto move : MoveGen(board).getLegalMoves()) {
        std::cout << move.getNotation() << " ";
      }
      std::cout << std::endl;
    } else if (token == "perft") {
      int depth = 1;
      is >> depth;
      perftDivide(depth);
    } else {
      std::cout << "what?" << std::endl;
    }
  }
}
}

void Uci::init() {
  initOptions();
}

void Uci::start() {
  loop();
}
<commit_msg>Remove extra newline<commit_after>#include <memory>
#include "uci.h"
#include "version.h"
#include <iostream>
#include <thread>

namespace {
Book book;
std::shared_ptr<Search> search;
Board board;
std::vector<ZKey> positionHistory;

void loadBook() {
  std::ifstream bookFile(optionsMap["BookPath"].getValue());
  bool bookOk = bookFile.good();
  bookFile.close();

  if (bookOk) {
    book = Book(optionsMap["BookPath"].getValue());
  } else {
    std::cerr << optionsMap["BookPath"].getValue() << " is inaccessible or doesn't exist" << std::endl;
  }
}

void initOptions() {
  optionsMap["OwnBook"] = Option(false);
  optionsMap["BookPath"] = Option("book.bin", &loadBook);
}

void uciNewGame() {
  board.setToStartPos();
  positionHistory.clear();
}

void setPosition(std::istringstream &is) {
  std::string token;
  is >> token;

  if (token == "startpos") {
    board.setToStartPos();
  } else {
    std::string fen;

    while (is >> token && token != "moves") {
      fen += token + " ";
    }

    board.setToFen(fen);
  }

  while (is >> token) {
    if (token == "moves") {
      continue;
    }

    MoveGen movegen(board);
    for (auto move : movegen.getMoves()) {
      if (move.getNotation() == token) {
        board.doMove(move);
        positionHistory.push_back(board.getZKey());
        break;
      }
    }
  }
}

void pickBestMove() {
  if (optionsMap["OwnBook"].getValue() == "true" && book.inBook(board)) {
    std::cout << "bestmove " << book.getMove(board).getNotation() << std::endl;
  } else {
    search->iterDeep();
  }
}

void go(std::istringstream &is) {
  std::string token;
  Search::Limits limits;

  while (is >> token) {
    if (token == "depth") is >> limits.depth;
    else if (token == "infinite") limits.infinite = true;
    else if (token == "movetime") is >> limits.moveTime;
    else if (token == "nodes") is >> limits.nodes;
    else if (token == "wtime") is >> limits.time[WHITE];
    else if (token == "btime") is >> limits.time[BLACK];
    else if (token == "winc") is >> limits.increment[WHITE];
    else if (token == "binc") is >> limits.increment[BLACK];
    else if (token == "movestogo") is >> limits.movesToGo;
  }

  search = std::make_shared<Search>(board, limits, positionHistory);

  std::thread searchThread(&pickBestMove);
  searchThread.detach();
}

unsigned long long perft(const Board &board, int depth) {
  if (depth <= 0) {
    return 1;
  } else if (depth == 1) {
    return MoveGen(board).getLegalMoves().size();
  }

  MoveGen movegen(board);

  unsigned long long nodes = 0;
  for (auto move : movegen.getLegalMoves()) {
    Board movedBoard = board;
    movedBoard.doMove(move);

    nodes += perft(movedBoard, depth - 1);
  }

  return nodes;
}

void perftDivide(int depth) {
  unsigned long long total = 0;

  MoveGen movegen(board);

  std::cout << std::endl;
  auto start = std::chrono::steady_clock::now();
  for (auto move : movegen.getLegalMoves()) {
    Board movedBoard = board;
    movedBoard.doMove(move);

    unsigned long long perftRes = perft(movedBoard, depth - 1);
    total += perftRes;

    std::cout << move.getNotation() << ": " << perftRes << std::endl;
  }
  auto end = std::chrono::steady_clock::now();
  std::chrono::duration<double> elapsed = end - start;

  std::cout << std::endl << "==========================" << std::endl;
  std::cout << "Total time (ms) : " << static_cast<int>(elapsed.count() * 1000) << std::endl;
  std::cout << "Nodes searched  : " << total << std::endl;
  std::cout << "Nodes / second  : " << static_cast<int>(total / elapsed.count()) << std::endl;
}

void printEngineInfo() {
  std::cout << "id name Shallow Blue " << VER_MAJ << "." << VER_MIN << "." << VER_PATCH << std::endl;
  std::cout << "id author Rhys Rustad-Elliott" << std::endl;
  std::cout << std::endl;

  for (auto optionPair : optionsMap) {
    std::cout << "option ";
    std::cout << "name " << optionPair.first << " ";
    std::cout << "type " << optionPair.second.getType() << " ";
    std::cout << "default " << optionPair.second.getDefaultValue() << " ";

    if (optionPair.second.getType() == "spin") {
      std::cout << "min " << optionPair.second.getMin() << " ";
      std::cout << "max " << optionPair.second.getMax();
    }
    std::cout << std::endl;
  }
  std::cout << "uciok" << std::endl;
}

void setOption(std::istringstream &is) {
  std::string token;
  std::string optionName;

  is >> token >> optionName; // Advance past "name"

  if (optionsMap.find(optionName) != optionsMap.end()) {
    is >> token >> token; // Advance past "value"
    optionsMap[optionName].setValue(token);
  } else {
    std::cout << "Invalid option" << std::endl;
  }
}

void loop() {
  std::cout << "Shallow Blue " << VER_MAJ << "." << VER_MIN << "." << VER_PATCH;
  std::cout << " by Rhys Rustad-Elliott";
  std::cout << " (built " << __DATE__ << " " << __TIME__ << ")" << std::endl;

#ifdef __DEBUG__
  std::cout << "***DEBUG BUILD (This will be slow)***" << std::endl;
#endif

  board.setToStartPos();

  std::string line;
  std::string token;

  while (std::getline(std::cin, line)) {
    std::istringstream is(line);
    is >> token;

    if (token == "uci") {
      printEngineInfo();
    } else if (token == "ucinewgame") {
      uciNewGame();
    } else if (token == "isready") {
      std::cout << "readyok" << std::endl;
    } else if (token == "stop") {
      if (search) search->stop();
    } else if (token == "go") {
      go(is);
    } else if (token == "quit") {
      if (search) search->stop();
      return;
    } else if (token == "position") {
      setPosition(is);
    } else if (token == "setoption") {
      setOption(is);
    }

      // Non UCI commands
    else if (token == "printboard") {
      std::cout << std::endl << board.getStringRep() << std::endl;
    } else if (token == "printmoves") {
      for (auto move : MoveGen(board).getLegalMoves()) {
        std::cout << move.getNotation() << " ";
      }
      std::cout << std::endl;
    } else if (token == "perft") {
      int depth = 1;
      is >> depth;
      perftDivide(depth);
    } else {
      std::cout << "what?" << std::endl;
    }
  }
}
}

void Uci::init() {
  initOptions();
}

void Uci::start() {
  loop();
}
<|endoftext|>