<commit_before>/*
 * Copyright (c) 2012 ARM Limited
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2006 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Ali Saidi
 *          Andreas Hansson
 */

#include "base/trace.hh"
#include "debug/Drain.hh"
#include "debug/PacketQueue.hh"
#include "mem/packet_queue.hh"

using namespace std;

PacketQueue::PacketQueue(EventManager& _em, const std::string& _label)
    : em(_em), sendEvent(this), drainManager(NULL), label(_label),
      waitingOnRetry(false)
{
}

PacketQueue::~PacketQueue()
{
}

void
PacketQueue::retry()
{
    DPRINTF(PacketQueue, "Queue %s received retry\n", name());
    assert(waitingOnRetry);
    sendDeferredPacket();
}

bool
PacketQueue::checkFunctional(PacketPtr pkt)
{
    pkt->pushLabel(label);

    auto i = transmitList.begin();
    bool found = false;

    while (!found && i != transmitList.end()) {
        // If the buffered packet contains data, and it overlaps the
        // current packet, then update data
        found = pkt->checkFunctional(i->pkt);
        ++i;
    }

    pkt->popLabel();

    return found;
}

void
PacketQueue::schedSendEvent(Tick when)
{
    // if we are waiting on a retry, do not schedule a send event, and
    // instead rely on retry being called
    if (waitingOnRetry) {
        assert(!sendEvent.scheduled());
        return;
    }

    if (!sendEvent.scheduled()) {
        em.schedule(&sendEvent, when);
    } else if (sendEvent.when() > when) {
        em.reschedule(&sendEvent, when);
    }
}

void
PacketQueue::schedSendTiming(PacketPtr pkt, Tick when, bool send_as_snoop)
{
    DPRINTF(PacketQueue, "%s for %s address %x size %d\n", __func__,
            pkt->cmdString(), pkt->getAddr(), pkt->getSize());
    // we can still send a packet before the end of this tick
    assert(when >= curTick());

    // express snoops should never be queued
    assert(!pkt->isExpressSnoop());

    // add a very basic sanity check on the port to ensure the
    // invisible buffer is not growing beyond reasonable limits
    if (transmitList.size() > 100) {
        panic("Packet queue %s has grown beyond 100 packets\n",
              name());
    }

    // nothing on the list, or earlier than current front element,
    // schedule an event
    if (transmitList.empty() || when < transmitList.front().tick) {
        // note that currently we ignore a potentially outstanding retry
        // and could in theory put a new packet at the head of the
        // transmit list before retrying the existing packet
        transmitList.push_front(DeferredPacket(when, pkt, send_as_snoop));
        schedSendEvent(when);
        return;
    }

    // list is non-empty and this belongs at the end
    if (when >= transmitList.back().tick) {
        transmitList.push_back(DeferredPacket(when, pkt, send_as_snoop));
        return;
    }

    // this belongs in the middle somewhere, insertion sort
    auto i = transmitList.begin();
    ++i; // already checked for insertion at front
    while (i != transmitList.end() && when >= i->tick)
        ++i;
    transmitList.insert(i, DeferredPacket(when, pkt, send_as_snoop));
}

void PacketQueue::trySendTiming()
{
    assert(deferredPacketReady());

    DeferredPacket dp = transmitList.front();

    // use the appropriate implementation of sendTiming based on the
    // type of port associated with the queue, and whether the packet
    // is to be sent as a snoop or not
    waitingOnRetry = !sendTiming(dp.pkt, dp.sendAsSnoop);

    if (!waitingOnRetry) {
        // take the packet off the list
        transmitList.pop_front();
    }
}

void
PacketQueue::scheduleSend(Tick time)
{
    // the next ready time is either determined by the next deferred packet,
    // or in the cache through the MSHR ready time
    Tick nextReady = std::min(deferredPacketReadyTime(), time);

    if (nextReady != MaxTick) {
        // if the sendTiming caused someone else to call our
        // recvTiming we could already have an event scheduled, check
        if (!sendEvent.scheduled())
            em.schedule(&sendEvent, std::max(nextReady, curTick() + 1));
    } else {
        // no more to send, so if we're draining, we may be done
        if (drainManager && transmitList.empty() && !sendEvent.scheduled()) {
            DPRINTF(Drain, "PacketQueue done draining,"
                    "processing drain event\n");
            drainManager->signalDrainDone();
            drainManager = NULL;
        }
    }
}

void
PacketQueue::sendDeferredPacket()
{
    // try to send what is on the list, this will set waitingOnRetry
    // accordingly
    trySendTiming();

    // if we succeeded and are not waiting for a retry, schedule the
    // next send
    if (!waitingOnRetry) {
        scheduleSend();
    }
}

void
PacketQueue::processSendEvent()
{
    assert(!waitingOnRetry);
    sendDeferredPacket();
}

unsigned int
PacketQueue::drain(DrainManager *dm)
{
    if (transmitList.empty())
        return 0;
    DPRINTF(Drain, "PacketQueue not drained\n");
    drainManager = dm;
    return 1;
}

MasterPacketQueue::MasterPacketQueue(EventManager& _em, MasterPort& _masterPort,
                                     const std::string _label)
    : PacketQueue(_em, _label), masterPort(_masterPort)
{
}

bool
MasterPacketQueue::sendTiming(PacketPtr pkt, bool send_as_snoop)
{
    // attempt to send the packet and return according to the outcome
    if (!send_as_snoop)
        return masterPort.sendTimingReq(pkt);
    else
        return masterPort.sendTimingSnoopResp(pkt);
}

SlavePacketQueue::SlavePacketQueue(EventManager& _em, SlavePort& _slavePort,
                                   const std::string _label)
    : PacketQueue(_em, _label), slavePort(_slavePort)
{
}

bool
SlavePacketQueue::sendTiming(PacketPtr pkt, bool send_as_snoop)
{
    // we should never have queued snoop requests
    assert(!send_as_snoop);
    return slavePort.sendTimingResp(pkt);
}
<commit_msg>mem: Allow packet queue to move next send event forward<commit_after>/*
 * Copyright (c) 2012 ARM Limited
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2006 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Ali Saidi
 *          Andreas Hansson
 */

#include "base/trace.hh"
#include "debug/Drain.hh"
#include "debug/PacketQueue.hh"
#include "mem/packet_queue.hh"

using namespace std;

PacketQueue::PacketQueue(EventManager& _em, const std::string& _label)
    : em(_em), sendEvent(this), drainManager(NULL), label(_label),
      waitingOnRetry(false)
{
}

PacketQueue::~PacketQueue()
{
}

void
PacketQueue::retry()
{
    DPRINTF(PacketQueue, "Queue %s received retry\n", name());
    assert(waitingOnRetry);
    sendDeferredPacket();
}

bool
PacketQueue::checkFunctional(PacketPtr pkt)
{
    pkt->pushLabel(label);

    auto i = transmitList.begin();
    bool found = false;

    while (!found && i != transmitList.end()) {
        // If the buffered packet contains data, and it overlaps the
        // current packet, then update data
        found = pkt->checkFunctional(i->pkt);
        ++i;
    }

    pkt->popLabel();

    return found;
}

void
PacketQueue::schedSendEvent(Tick when)
{
    // if we are waiting on a retry, do not schedule a send event, and
    // instead rely on retry being called
    if (waitingOnRetry) {
        assert(!sendEvent.scheduled());
        return;
    }

    if (!sendEvent.scheduled()) {
        em.schedule(&sendEvent, when);
    } else if (sendEvent.when() > when) {
        em.reschedule(&sendEvent, when);
    }
}

void
PacketQueue::schedSendTiming(PacketPtr pkt, Tick when, bool send_as_snoop)
{
    DPRINTF(PacketQueue, "%s for %s address %x size %d\n", __func__,
            pkt->cmdString(), pkt->getAddr(), pkt->getSize());
    // we can still send a packet before the end of this tick
    assert(when >= curTick());

    // express snoops should never be queued
    assert(!pkt->isExpressSnoop());

    // add a very basic sanity check on the port to ensure the
    // invisible buffer is not growing beyond reasonable limits
    if (transmitList.size() > 100) {
        panic("Packet queue %s has grown beyond 100 packets\n",
              name());
    }

    // nothing on the list, or earlier than current front element,
    // schedule an event
    if (transmitList.empty() || when < transmitList.front().tick) {
        // note that currently we ignore a potentially outstanding retry
        // and could in theory put a new packet at the head of the
        // transmit list before retrying the existing packet
        transmitList.push_front(DeferredPacket(when, pkt, send_as_snoop));
        schedSendEvent(when);
        return;
    }

    // list is non-empty and this belongs at the end
    if (when >= transmitList.back().tick) {
        transmitList.push_back(DeferredPacket(when, pkt, send_as_snoop));
        return;
    }

    // this belongs in the middle somewhere, insertion sort
    auto i = transmitList.begin();
    ++i; // already checked for insertion at front
    while (i != transmitList.end() && when >= i->tick)
        ++i;
    transmitList.insert(i, DeferredPacket(when, pkt, send_as_snoop));
}

void PacketQueue::trySendTiming()
{
    assert(deferredPacketReady());

    DeferredPacket dp = transmitList.front();

    // use the appropriate implementation of sendTiming based on the
    // type of port associated with the queue, and whether the packet
    // is to be sent as a snoop or not
    waitingOnRetry = !sendTiming(dp.pkt, dp.sendAsSnoop);

    if (!waitingOnRetry) {
        // take the packet off the list
        transmitList.pop_front();
    }
}

void
PacketQueue::scheduleSend(Tick time)
{
    // the next ready time is either determined by the next deferred packet,
    // or in the cache through the MSHR ready time
    Tick nextReady = std::max(std::min(deferredPacketReadyTime(), time),
                              curTick() + 1);

    if (nextReady != MaxTick) {
        // if the sendTiming caused someone else to call our
        // recvTiming we could already have an event scheduled, check
        if (!sendEvent.scheduled()) {
            em.schedule(&sendEvent, nextReady);
        } else if (nextReady < sendEvent.when()) {
            // if the new time is earlier than when the event
            // currently is scheduled, move it forward
            em.reschedule(&sendEvent, nextReady);
        }
    } else {
        // no more to send, so if we're draining, we may be done
        if (drainManager && transmitList.empty() && !sendEvent.scheduled()) {
            DPRINTF(Drain, "PacketQueue done draining,"
                    "processing drain event\n");
            drainManager->signalDrainDone();
            drainManager = NULL;
        }
    }
}

void
PacketQueue::sendDeferredPacket()
{
    // try to send what is on the list, this will set waitingOnRetry
    // accordingly
    trySendTiming();

    // if we succeeded and are not waiting for a retry, schedule the
    // next send
    if (!waitingOnRetry) {
        scheduleSend();
    }
}

void
PacketQueue::processSendEvent()
{
    assert(!waitingOnRetry);
    sendDeferredPacket();
}

unsigned int
PacketQueue::drain(DrainManager *dm)
{
    if (transmitList.empty())
        return 0;
    DPRINTF(Drain, "PacketQueue not drained\n");
    drainManager = dm;
    return 1;
}

MasterPacketQueue::MasterPacketQueue(EventManager& _em, MasterPort& _masterPort,
                                     const std::string _label)
    : PacketQueue(_em, _label), masterPort(_masterPort)
{
}

bool
MasterPacketQueue::sendTiming(PacketPtr pkt, bool send_as_snoop)
{
    // attempt to send the packet and return according to the outcome
    if (!send_as_snoop)
        return masterPort.sendTimingReq(pkt);
    else
        return masterPort.sendTimingSnoopResp(pkt);
}

SlavePacketQueue::SlavePacketQueue(EventManager& _em, SlavePort& _slavePort,
                                   const std::string _label)
    : PacketQueue(_em, _label), slavePort(_slavePort)
{
}

bool
SlavePacketQueue::sendTiming(PacketPtr pkt, bool send_as_snoop)
{
    // we should never have queued snoop requests
    assert(!send_as_snoop);
    return slavePort.sendTimingResp(pkt);
}
<|endoftext|>


<commit_before>#include "menu/option_key.h"
#include "util/token.h"
#include "configuration.h"
#include "menu/menu.h"
#include "menu/menu_global.h"
#include "globals.h"
#include "init.h"
#include "util/keyboard.h"
#include "util/bitmap.h"

OptionKey::keyType convertToKey(const std::string &k)
{
	std::string temp = k;
	for(unsigned int i=0;i<temp.length();i++)
	{
		temp[i] = tolower(temp[i]);
	}
	if(temp == "up")return OptionKey::up;
	if(temp == "down")return OptionKey::down;
	if(temp == "left")return OptionKey::left;
	if(temp == "right")return OptionKey::right;
	if(temp == "jump")return OptionKey::jump;
	if(temp == "attack1")return OptionKey::attack1;
	if(temp == "attack2")return OptionKey::attack2;
	if(temp == "attack3")return OptionKey::attack3;
	if(temp == "attack4")return OptionKey::attack4;
	if(temp == "attack5")return OptionKey::attack5;
	if(temp == "attack6")return OptionKey::attack6;

	return OptionKey::invalidkey;
}

int getKey(int player, OptionKey::keyType k)
{
	switch(k)
	{
		case OptionKey::up:
			return Configuration::config( player ).getUp();
			break;
		case OptionKey::down:
			return Configuration::config( player ).getDown();
			break;
		case OptionKey::left:
			return Configuration::config( player ).getLeft();
			break;
		case OptionKey::right:
			return Configuration::config( player ).getRight();
			break;
		case OptionKey::jump:
			return Configuration::config( player ).getJump();
			break;
		case OptionKey::attack1:
			return Configuration::config( player ).getAttack1();
			break;
		case OptionKey::attack2:
			return Configuration::config( player ).getAttack2();
			break;
		case OptionKey::attack3:
			return Configuration::config( player ).getAttack3();
			break;
		case OptionKey::attack4:
		case OptionKey::attack5:
		case OptionKey::attack6:
		default:
			break;
	}

	return 0;
}

void setKey(int player, OptionKey::keyType k, int key)
{
	switch(k)
	{
		case OptionKey::up:
			Configuration::config( player ).setUp( key );
			break;
		case OptionKey::down:
			Configuration::config( player ).setDown( key );
			break;
		case OptionKey::left:
			Configuration::config( player ).setLeft( key );
			break;
		case OptionKey::right:
			Configuration::config( player ).setRight( key );
			break;
		case OptionKey::jump:
			Configuration::config( player ).setJump( key );
			break;
		case OptionKey::attack1:
			Configuration::config( player ).setAttack1( key );
			break;
		case OptionKey::attack2:
			Configuration::config( player ).setAttack2( key );
			break;
		case OptionKey::attack3:
			Configuration::config( player ).setAttack3( key );
			break;
		case OptionKey::attack4:
		case OptionKey::attack5:
		case OptionKey::attack6:
		default:
			break;
	}
}

static int readKey( Keyboard & key ){
	key.wait();
	key.clear();
	int k = key.readKey();
	key.wait();
	return k;
}

OptionKey::OptionKey(Token *token)throw( LoadException ) : MenuOption(event), name(""), player(-1), type(invalidkey), keyCode(0)
{
	if ( *token != "key" )
		throw LoadException("Not key option");

	while ( token->hasTokens() )
	{
		try
		{
			Token * tok;
			*token >> tok;
			if ( *tok == "name" )
			{
				*tok >> name;
			}
			else if ( *tok == "player" )
			{
				*tok >> player;
			}
			else if ( *tok == "type" )
			{
				std::string temp;
				*tok >> temp;
				type = convertToKey(temp);
			}
			else
			{
				Global::debug( 3 ) <<"Unhandled menu attribute: "<<endl;
				tok->print(" ");
			}
		}
		catch ( const TokenException & ex )
		{
			// delete current;
			string m( "Menu parse error: " );
			m += ex.getReason();
			throw LoadException( m );
		}
		catch ( const LoadException & ex )
		{
			// delete current;
			throw ex;
		}
	}

	if(name.empty())throw LoadException("No name set, this option should have a name!");
	if(type == invalidkey)throw LoadException("Invalid key, should be up, down, left, right, up, down, jump, attack1-6!");
	if(player == -1)throw LoadException("Player not specified in key configuration");
}

OptionKey::~OptionKey()
{
	// Nothing
}

void OptionKey::logic()
{
	char temp[255];
	sprintf( temp, "%s: %s", name.c_str(), Keyboard::keyToName(getKey(player,type)));
	setText(std::string(temp));
}

void OptionKey::draw(Bitmap *work)
{
}

void OptionKey::run(bool &endGame)
{
	int x, y, width, height;
	width = Menu::getFont()->textLength("Press a Key!") + 10;
	height = Menu::getFont()->getHeight() + 10;
	x = 320 - (width/2);
	y = 240 - (height/2);
	Bitmap::transBlender( 0, 0, 0, 200 );
	Bitmap::Screen->drawingMode( Bitmap::MODE_TRANS );
	Bitmap::Screen->rectangleFill( x, y, x+width, y+height, Bitmap::makeColor(0,0,0) );
	Bitmap::Screen->drawingMode( Bitmap::MODE_SOLID );
	Bitmap::Screen->rectangle( x, y, x+width, y+height, Bitmap::makeColor(255,255,255) );
	Menu::getFont()->printf( x+5, y+5, Bitmap::makeColor(255,255,255), *Bitmap::Screen, "Press a Key!", -1);
	Keyboard key;
	keyCode = readKey( key );
	setKey(player,type, keyCode);
}

<commit_msg>subtract 1 from player number<commit_after>#include "menu/option_key.h"
#include "util/token.h"
#include "configuration.h"
#include "menu/menu.h"
#include "menu/menu_global.h"
#include "globals.h"
#include "init.h"
#include "util/keyboard.h"
#include "util/bitmap.h"

OptionKey::keyType convertToKey(const std::string &k)
{
	std::string temp = k;
	for(unsigned int i=0;i<temp.length();i++)
	{
		temp[i] = tolower(temp[i]);
	}
	if(temp == "up")return OptionKey::up;
	if(temp == "down")return OptionKey::down;
	if(temp == "left")return OptionKey::left;
	if(temp == "right")return OptionKey::right;
	if(temp == "jump")return OptionKey::jump;
	if(temp == "attack1")return OptionKey::attack1;
	if(temp == "attack2")return OptionKey::attack2;
	if(temp == "attack3")return OptionKey::attack3;
	if(temp == "attack4")return OptionKey::attack4;
	if(temp == "attack5")return OptionKey::attack5;
	if(temp == "attack6")return OptionKey::attack6;

	return OptionKey::invalidkey;
}

int getKey(int player, OptionKey::keyType k)
{
	switch(k)
	{
		case OptionKey::up:
			return Configuration::config( player ).getUp();
			break;
		case OptionKey::down:
			return Configuration::config( player ).getDown();
			break;
		case OptionKey::left:
			return Configuration::config( player ).getLeft();
			break;
		case OptionKey::right:
			return Configuration::config( player ).getRight();
			break;
		case OptionKey::jump:
			return Configuration::config( player ).getJump();
			break;
		case OptionKey::attack1:
			return Configuration::config( player ).getAttack1();
			break;
		case OptionKey::attack2:
			return Configuration::config( player ).getAttack2();
			break;
		case OptionKey::attack3:
			return Configuration::config( player ).getAttack3();
			break;
		case OptionKey::attack4:
		case OptionKey::attack5:
		case OptionKey::attack6:
		default:
			break;
	}

	return 0;
}

void setKey(int player, OptionKey::keyType k, int key)
{
	switch(k)
	{
		case OptionKey::up:
			Configuration::config( player ).setUp( key );
			break;
		case OptionKey::down:
			Configuration::config( player ).setDown( key );
			break;
		case OptionKey::left:
			Configuration::config( player ).setLeft( key );
			break;
		case OptionKey::right:
			Configuration::config( player ).setRight( key );
			break;
		case OptionKey::jump:
			Configuration::config( player ).setJump( key );
			break;
		case OptionKey::attack1:
			Configuration::config( player ).setAttack1( key );
			break;
		case OptionKey::attack2:
			Configuration::config( player ).setAttack2( key );
			break;
		case OptionKey::attack3:
			Configuration::config( player ).setAttack3( key );
			break;
		case OptionKey::attack4:
		case OptionKey::attack5:
		case OptionKey::attack6:
		default:
			break;
	}
}

static int readKey( Keyboard & key ){
	key.wait();
	key.clear();
	int k = key.readKey();
	key.wait();
	return k;
}

OptionKey::OptionKey(Token *token)throw( LoadException ) : MenuOption(event), name(""), player(-1), type(invalidkey), keyCode(0)
{
	if ( *token != "key" )
		throw LoadException("Not key option");

	while ( token->hasTokens() )
	{
		try
		{
			Token * tok;
			*token >> tok;
			if ( *tok == "name" )
			{
				*tok >> name;
			}
			else if ( *tok == "player" )
			{
				*tok >> player;
				player -= 1;
			}
			else if ( *tok == "type" )
			{
				std::string temp;
				*tok >> temp;
				type = convertToKey(temp);
			}
			else
			{
				Global::debug( 3 ) <<"Unhandled menu attribute: "<<endl;
				tok->print(" ");
			}
		}
		catch ( const TokenException & ex )
		{
			// delete current;
			string m( "Menu parse error: " );
			m += ex.getReason();
			throw LoadException( m );
		}
		catch ( const LoadException & ex )
		{
			// delete current;
			throw ex;
		}
	}

	if(name.empty())throw LoadException("No name set, this option should have a name!");
	if(type == invalidkey)throw LoadException("Invalid key, should be up, down, left, right, up, down, jump, attack1-6!");
	if(player == -1)throw LoadException("Player not specified in key configuration");
}

OptionKey::~OptionKey()
{
	// Nothing
}

void OptionKey::logic()
{
	char temp[255];
	sprintf( temp, "%s: %s", name.c_str(), Keyboard::keyToName(getKey(player,type)));
	setText(std::string(temp));
}

void OptionKey::draw(Bitmap *work)
{
}

void OptionKey::run(bool &endGame)
{
	int x, y, width, height;
	width = Menu::getFont()->textLength("Press a Key!") + 10;
	height = Menu::getFont()->getHeight() + 10;
	x = 320 - (width/2);
	y = 240 - (height/2);
	Bitmap::transBlender( 0, 0, 0, 200 );
	Bitmap::Screen->drawingMode( Bitmap::MODE_TRANS );
	Bitmap::Screen->rectangleFill( x, y, x+width, y+height, Bitmap::makeColor(0,0,0) );
	Bitmap::Screen->drawingMode( Bitmap::MODE_SOLID );
	Bitmap::Screen->rectangle( x, y, x+width, y+height, Bitmap::makeColor(255,255,255) );
	Menu::getFont()->printf( x+5, y+5, Bitmap::makeColor(255,255,255), *Bitmap::Screen, "Press a Key!", -1);
	Keyboard key;
	keyCode = readKey( key );
	setKey(player,type, keyCode);
}

<|endoftext|>


<commit_before>// Copyright 2022 DeepMind Technologies Limited
//
// 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 "open_spiel/games/2048.h"

#include <algorithm>
#include <array>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "open_spiel/abseil-cpp/absl/strings/str_cat.h"
#include "open_spiel/spiel_utils.h"
#include "open_spiel/utils/tensor_view.h"

namespace open_spiel {
namespace two_zero_four_eight {
namespace {

constexpr int kMoveUp = 0;
constexpr int kMoveRight = 1;
constexpr int kMoveDown = 2;
constexpr int kMoveLeft = 3;
inline const std::vector<Action> kPlayerActions() {
  return {kMoveUp, kMoveRight, kMoveDown, kMoveLeft};
}

// Facts about the game.
const GameType kGameType{/*short_name=*/"2048",
                         /*long_name=*/"2048",
                         GameType::Dynamics::kSequential,
                         GameType::ChanceMode::kExplicitStochastic,
                         GameType::Information::kPerfectInformation,
                         GameType::Utility::kGeneralSum,
                         GameType::RewardModel::kTerminal,
                         /*max_num_players=*/1,
                         /*min_num_players=*/1,
                         /*provides_information_state_string=*/false,
                         /*provides_information_state_tensor=*/false,
                         /*provides_observation_string=*/true,
                         /*provides_observation_tensor=*/true,
                         {{"max_game_length", GameParameter(kMaxGameLength)},
                          {"max_score", GameParameter(kMaxScore)}}};

std::shared_ptr<const Game> Factory(const GameParameters& params) {
  return std::shared_ptr<const Game>(new TwoZeroFourEightGame(params));
}

REGISTER_SPIEL_GAME(kGameType, Factory);
}  // namespace

TwoZeroFourEightState::TwoZeroFourEightState(std::shared_ptr<const Game> game)
    : State(game) {
  board_ = std::vector<Tile>(kDefaultRows * kDefaultColumns, Tile(0, false));
}

void TwoZeroFourEightState::SetCustomBoard(const std::vector<int> board_seq) {
  current_player_ = 0;
  for (int x = 0; x < kDefaultRows; x++) {
    for (int y = 0; y < kDefaultColumns; y++) {
      SetBoard(x, y, Tile(board_seq[x * kDefaultRows + y], false));
    }
  }
}

ChanceAction TwoZeroFourEightState
    ::SpielActionToChanceAction(Action action) const {
  std::vector<int> values = UnrankActionMixedBase(
      action, {kDefaultRows, kDefaultColumns, kChanceTiles.size()});
  return ChanceAction(values[0], values[1], values[2]);
}

Action TwoZeroFourEightState
    ::ChanceActionToSpielAction(ChanceAction move) const {
  std::vector<int> action_bases = {kDefaultRows, kDefaultColumns,
      kChanceTiles.size()};
  return RankActionMixedBase(
      action_bases, {move.row, move.column, move.is_four});
}

std::vector<std::vector<int>> TwoZeroFourEightState
    ::BuildTraversals(int direction) const {
  std::vector<int> x, y;
  for (int pos = 0; pos < kDefaultRows; pos++) {
    x.push_back(pos);
  }
  for (int pos = 0; pos < kDefaultColumns; pos++) {
    y.push_back(pos);
  }
  switch (direction) {
    case kMoveRight:
      reverse(x.begin(), x.end());
      reverse(y.begin(), y.end());
      break;
    case kMoveLeft:
    case kMoveDown:
      reverse(x.begin(), x.end());
      break;
  }
  return {x, y};
};

bool TwoZeroFourEightState::WithinBounds(int x, int y) const {
  return x >= 0 && x < kDefaultRows && y >= 0 && y < kDefaultColumns;
};

bool TwoZeroFourEightState::CellAvailable(int x, int y) const {
  return BoardAt(x, y).value == 0;
}

Coordinate GetVector(int direction) {
  switch (direction) {
      case kMoveUp:
        return Coordinate(-1, 0);
      case kMoveRight:
        return Coordinate(0, 1);
      case kMoveDown:
        return Coordinate(1, 0);
      case kMoveLeft:
        return Coordinate(0, -1);
    }
}

std::vector<Coordinate> TwoZeroFourEightState
    ::FindFarthestPosition(int x, int y, int direction) const {
  // Progress towards the vector direction until an obstacle is found
  Coordinate prev = Coordinate(x, y);
  do {
    prev = Coordinate(x, y);
    Coordinate direction_diff = GetVector(direction);
    x += direction_diff.x;
    y += direction_diff.y;
  } while (WithinBounds(x, y) && CellAvailable(x, y));
  return std::vector<Coordinate> {prev,
      Coordinate(x, y)};
};

// Check for available matches between tiles (more expensive check)
bool TwoZeroFourEightState::TileMatchesAvailable() const {
  for (int x = 0; x < kDefaultRows; x++) {
    for (int y = 0; y < kDefaultColumns; y++) {
      int tile = BoardAt(x, y).value;
      if (tile > 0) {
        for (int direction = 0; direction < 4; direction++) {
          Coordinate vector = GetVector(direction);
          int other = GetCellContent(x + vector.x, y + vector.y);
          if (other > 0 && other == tile) {
            return true; // These two tiles can be merged
          }
        }
      }
    }
  }
  return false;
};

void TwoZeroFourEightState::PrepareTiles() {
  for (int x = 0; x < kDefaultRows; x++) {
    for (int y = 0; y < kDefaultColumns; y++) {
      Tile tile = BoardAt(x, y);
      if (tile.is_merged) {
        SetBoard(x, y, Tile(tile.value, false));
      }
    }
  }
};

int TwoZeroFourEightState::GetCellContent(int x, int y) const {
  if (!WithinBounds(x, y))
    return 0;
  return BoardAt(x, y).value;
}

void TwoZeroFourEightState::DoApplyAction(Action action) {
  if (IsChanceNode()) {
    // The original 2048 game starts with two random tiles
    if (!extra_chance_turn_) {
      current_player_ = 0;
    }
    extra_chance_turn_ = false;

    if (action == kNoCellAvailableAction) {
      return;
    }
    ChanceAction chance_action = SpielActionToChanceAction(action);
    SetBoard(chance_action.row, chance_action.column,
        Tile(chance_action.is_four ? kChanceTiles[1] : kChanceTiles[0], false));
    return;
  }
  action_score_ = 0;
  std::vector<std::vector<int>> traversals = BuildTraversals(action);
  PrepareTiles();
  for (int x : traversals[0]) {
    for (int y : traversals[1]) {
      int tile = GetCellContent(x, y);
      if (tile > 0) {
        bool moved = false;
        std::vector<Coordinate> positions = FindFarthestPosition(x, y, action);
        Coordinate farthest_pos = positions[0];
        Coordinate next_pos = positions[1];
        int next_cell = GetCellContent(next_pos.x, next_pos.y);
        if (next_cell > 0 && next_cell == tile
            && !BoardAt(next_pos.x, next_pos.y).is_merged) {
          int merged = tile * 2;
          action_score_ += merged;
          SetBoard(next_pos.x, next_pos.y, Tile(merged, true));
          moved = true;
        } else if (farthest_pos.x != x || farthest_pos.y != y){
          SetBoard(farthest_pos.x, farthest_pos.y, Tile(tile, false));
          moved = true;
        }
        if (moved) {
          SetBoard(x, y, Tile(0, false));
          current_player_ = kChancePlayerId;
        }
      }
    }
  }
  total_score_ += action_score_;
}

std::string TwoZeroFourEightState::ActionToString(Player player,
                                          Action action_id) const {
  if (IsChanceNode()) {
    if (action_id == kNoCellAvailableAction) {
      return "No Cell Available";
    }
    ChanceAction chance_action = SpielActionToChanceAction(action_id);
    return absl::StrCat(std::to_string(chance_action.is_four ? 4 : 2),
        " added to row ", std::to_string(chance_action.row + 1),
        ", column ", std::to_string(chance_action.column + 1));
  }
  switch (action_id) {
    case kMoveUp:
      return "Up";
      break;
    case kMoveRight:
      return "Right";
      break;
    case kMoveDown:
      return "Down";
      break;
    case kMoveLeft:
      return "Left";
      break;
    default:
      return "Invalid action";
      break;
  }
}

int TwoZeroFourEightState::AvailableCellCount() const {
  int count = 0;
  for (int r = 0; r < kDefaultRows; r++) {
    for (int c = 0; c < kDefaultColumns; c++) {
      if (BoardAt(r, c).value == 0) {
        count++;
      }
    }
  }
  return count;
}

ActionsAndProbs TwoZeroFourEightState::ChanceOutcomes() const {
  ActionsAndProbs action_and_probs;
  int count = AvailableCellCount();
  if (count == 0) {
    action_and_probs.reserve(1);
    action_and_probs.emplace_back(kNoCellAvailableAction, 1);
    return action_and_probs;
  }
  action_and_probs.reserve(count * 2);
  for (int r = 0; r < kDefaultRows; r++) {
    for (int c = 0; c < kDefaultColumns; c++) {
      if (BoardAt(r, c).value == 0) {
        // 2 appearing randomly on the board should be 9 times as likely as a 4
        action_and_probs.emplace_back(ChanceActionToSpielAction(
            ChanceAction(r, c, false)), .9 / count);
        action_and_probs.emplace_back(ChanceActionToSpielAction(
            ChanceAction(r, c, true)), .1 / count);
      }
    }
  }
  return action_and_probs;
}

std::vector<Action> TwoZeroFourEightState::LegalActions() const {
  if (IsTerminal()) {
    return {};
  }
  if (IsChanceNode()) {
    return LegalChanceOutcomes();
  }
  return kPlayerActions();
}

bool TwoZeroFourEightState::InBounds(int row, int column) const {
  return (row >= 0 && row < kDefaultRows && column >= 0
      && column < kDefaultColumns);
}

std::string TwoZeroFourEightState::ToString() const {
  std::string str;
  for (int r = 0; r < kDefaultRows; ++r) {
    for (int c = 0; c < kDefaultColumns; ++c) {
      std::string tile = std::to_string(BoardAt(r, c).value);
      absl::StrAppend(&str, std::string(5 - tile.length(), ' '));
      absl::StrAppend(&str, tile);
    }
    absl::StrAppend(&str, "\n");
  }
  return str;
}

bool TwoZeroFourEightState::IsTerminal() const {
  return Reached2048()
      || (AvailableCellCount() == 0 && !TileMatchesAvailable());
}

bool TwoZeroFourEightState::Reached2048() const {
  for (int r = 0; r < kDefaultRows; r++) {
    for (int c = 0; c < kDefaultColumns; c++) {
      if (BoardAt(r, c).value == 2048) {
        return true;
      }
    }
  }
  return false;
}

int TwoZeroFourEightState::GetMaxTile() const {
  int max_tile = 0;
  for (int r = 0; r < kDefaultRows; r++) {
    for (int c = 0; c < kDefaultColumns; c++) {
      if (BoardAt(r, c).value > max_tile) {
        max_tile = BoardAt(r, c).value;
      }
    }
  }
  return max_tile;
}

std::vector<double> TwoZeroFourEightState::Rewards() const {
  return {action_score_};
}

std::vector<double> TwoZeroFourEightState::Returns() const {
  return {total_score_};
}

std::string TwoZeroFourEightState::InformationStateString(Player player) const {
  SPIEL_CHECK_GE(player, 0);
  SPIEL_CHECK_LT(player, num_players_);
  return HistoryString();
}

std::string TwoZeroFourEightState::ObservationString(Player player) const {
  SPIEL_CHECK_GE(player, 0);
  SPIEL_CHECK_LT(player, num_players_);
  return ToString();
}

void TwoZeroFourEightState::ObservationTensor(Player player,
                                      absl::Span<float> values) const {
  SPIEL_CHECK_GE(player, 0);
  SPIEL_CHECK_LT(player, num_players_);
  TensorView<2> view(values, {kDefaultRows, kDefaultColumns}, true);
  for (int row = 0; row < kDefaultRows; row++) {
    for (int column = 0; column < kDefaultColumns; column++) {
      view[{row, column}] = BoardAt(row, column).value;
    }
  }
}

void TwoZeroFourEightState::UndoAction(Player player, Action action) {
  history_.pop_back();
}

TwoZeroFourEightGame::TwoZeroFourEightGame(const GameParameters& params)
    : Game(kGameType, params),
      max_game_length_(ParameterValue<int>("max_game_length")),
      max_score_(ParameterValue<int>("max_score")) {}

int TwoZeroFourEightGame::NumDistinctActions() const {
  return kPlayerActions().size();
}

}  // namespace two_zero_four_eight
}  // namespace open_spiel
<commit_msg>board_ initialized inside initializer list<commit_after>// Copyright 2022 DeepMind Technologies Limited
//
// 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 "open_spiel/games/2048.h"

#include <algorithm>
#include <array>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "open_spiel/abseil-cpp/absl/strings/str_cat.h"
#include "open_spiel/spiel_utils.h"
#include "open_spiel/utils/tensor_view.h"

namespace open_spiel {
namespace two_zero_four_eight {
namespace {

constexpr int kMoveUp = 0;
constexpr int kMoveRight = 1;
constexpr int kMoveDown = 2;
constexpr int kMoveLeft = 3;
inline const std::vector<Action> kPlayerActions() {
  return {kMoveUp, kMoveRight, kMoveDown, kMoveLeft};
}

// Facts about the game.
const GameType kGameType{/*short_name=*/"2048",
                         /*long_name=*/"2048",
                         GameType::Dynamics::kSequential,
                         GameType::ChanceMode::kExplicitStochastic,
                         GameType::Information::kPerfectInformation,
                         GameType::Utility::kGeneralSum,
                         GameType::RewardModel::kTerminal,
                         /*max_num_players=*/1,
                         /*min_num_players=*/1,
                         /*provides_information_state_string=*/false,
                         /*provides_information_state_tensor=*/false,
                         /*provides_observation_string=*/true,
                         /*provides_observation_tensor=*/true,
                         {{"max_game_length", GameParameter(kMaxGameLength)},
                          {"max_score", GameParameter(kMaxScore)}}};

std::shared_ptr<const Game> Factory(const GameParameters& params) {
  return std::shared_ptr<const Game>(new TwoZeroFourEightGame(params));
}

REGISTER_SPIEL_GAME(kGameType, Factory);
}  // namespace

TwoZeroFourEightState::TwoZeroFourEightState(std::shared_ptr<const Game> game)
    : State(game),
      board_(std::vector<Tile>(kDefaultRows * kDefaultColumns, Tile(0, false)))
      {}

void TwoZeroFourEightState::SetCustomBoard(const std::vector<int> board_seq) {
  current_player_ = 0;
  for (int x = 0; x < kDefaultRows; x++) {
    for (int y = 0; y < kDefaultColumns; y++) {
      SetBoard(x, y, Tile(board_seq[x * kDefaultRows + y], false));
    }
  }
}

ChanceAction TwoZeroFourEightState
    ::SpielActionToChanceAction(Action action) const {
  std::vector<int> values = UnrankActionMixedBase(
      action, {kDefaultRows, kDefaultColumns, kChanceTiles.size()});
  return ChanceAction(values[0], values[1], values[2]);
}

Action TwoZeroFourEightState
    ::ChanceActionToSpielAction(ChanceAction move) const {
  std::vector<int> action_bases = {kDefaultRows, kDefaultColumns,
      kChanceTiles.size()};
  return RankActionMixedBase(
      action_bases, {move.row, move.column, move.is_four});
}

std::vector<std::vector<int>> TwoZeroFourEightState
    ::BuildTraversals(int direction) const {
  std::vector<int> x, y;
  for (int pos = 0; pos < kDefaultRows; pos++) {
    x.push_back(pos);
  }
  for (int pos = 0; pos < kDefaultColumns; pos++) {
    y.push_back(pos);
  }
  switch (direction) {
    case kMoveRight:
      reverse(x.begin(), x.end());
      reverse(y.begin(), y.end());
      break;
    case kMoveLeft:
    case kMoveDown:
      reverse(x.begin(), x.end());
      break;
  }
  return {x, y};
};

bool TwoZeroFourEightState::WithinBounds(int x, int y) const {
  return x >= 0 && x < kDefaultRows && y >= 0 && y < kDefaultColumns;
};

bool TwoZeroFourEightState::CellAvailable(int x, int y) const {
  return BoardAt(x, y).value == 0;
}

Coordinate GetVector(int direction) {
  switch (direction) {
      case kMoveUp:
        return Coordinate(-1, 0);
      case kMoveRight:
        return Coordinate(0, 1);
      case kMoveDown:
        return Coordinate(1, 0);
      case kMoveLeft:
        return Coordinate(0, -1);
    }
}

std::vector<Coordinate> TwoZeroFourEightState
    ::FindFarthestPosition(int x, int y, int direction) const {
  // Progress towards the vector direction until an obstacle is found
  Coordinate prev = Coordinate(x, y);
  do {
    prev = Coordinate(x, y);
    Coordinate direction_diff = GetVector(direction);
    x += direction_diff.x;
    y += direction_diff.y;
  } while (WithinBounds(x, y) && CellAvailable(x, y));
  return std::vector<Coordinate> {prev,
      Coordinate(x, y)};
};

// Check for available matches between tiles (more expensive check)
bool TwoZeroFourEightState::TileMatchesAvailable() const {
  for (int x = 0; x < kDefaultRows; x++) {
    for (int y = 0; y < kDefaultColumns; y++) {
      int tile = BoardAt(x, y).value;
      if (tile > 0) {
        for (int direction = 0; direction < 4; direction++) {
          Coordinate vector = GetVector(direction);
          int other = GetCellContent(x + vector.x, y + vector.y);
          if (other > 0 && other == tile) {
            return true; // These two tiles can be merged
          }
        }
      }
    }
  }
  return false;
};

void TwoZeroFourEightState::PrepareTiles() {
  for (int x = 0; x < kDefaultRows; x++) {
    for (int y = 0; y < kDefaultColumns; y++) {
      Tile tile = BoardAt(x, y);
      if (tile.is_merged) {
        SetBoard(x, y, Tile(tile.value, false));
      }
    }
  }
};

int TwoZeroFourEightState::GetCellContent(int x, int y) const {
  if (!WithinBounds(x, y))
    return 0;
  return BoardAt(x, y).value;
}

void TwoZeroFourEightState::DoApplyAction(Action action) {
  if (IsChanceNode()) {
    // The original 2048 game starts with two random tiles
    if (!extra_chance_turn_) {
      current_player_ = 0;
    }
    extra_chance_turn_ = false;

    if (action == kNoCellAvailableAction) {
      return;
    }
    ChanceAction chance_action = SpielActionToChanceAction(action);
    SetBoard(chance_action.row, chance_action.column,
        Tile(chance_action.is_four ? kChanceTiles[1] : kChanceTiles[0], false));
    return;
  }
  action_score_ = 0;
  std::vector<std::vector<int>> traversals = BuildTraversals(action);
  PrepareTiles();
  for (int x : traversals[0]) {
    for (int y : traversals[1]) {
      int tile = GetCellContent(x, y);
      if (tile > 0) {
        bool moved = false;
        std::vector<Coordinate> positions = FindFarthestPosition(x, y, action);
        Coordinate farthest_pos = positions[0];
        Coordinate next_pos = positions[1];
        int next_cell = GetCellContent(next_pos.x, next_pos.y);
        if (next_cell > 0 && next_cell == tile
            && !BoardAt(next_pos.x, next_pos.y).is_merged) {
          int merged = tile * 2;
          action_score_ += merged;
          SetBoard(next_pos.x, next_pos.y, Tile(merged, true));
          moved = true;
        } else if (farthest_pos.x != x || farthest_pos.y != y){
          SetBoard(farthest_pos.x, farthest_pos.y, Tile(tile, false));
          moved = true;
        }
        if (moved) {
          SetBoard(x, y, Tile(0, false));
          current_player_ = kChancePlayerId;
        }
      }
    }
  }
  total_score_ += action_score_;
}

std::string TwoZeroFourEightState::ActionToString(Player player,
                                          Action action_id) const {
  if (IsChanceNode()) {
    if (action_id == kNoCellAvailableAction) {
      return "No Cell Available";
    }
    ChanceAction chance_action = SpielActionToChanceAction(action_id);
    return absl::StrCat(std::to_string(chance_action.is_four ? 4 : 2),
        " added to row ", std::to_string(chance_action.row + 1),
        ", column ", std::to_string(chance_action.column + 1));
  }
  switch (action_id) {
    case kMoveUp:
      return "Up";
      break;
    case kMoveRight:
      return "Right";
      break;
    case kMoveDown:
      return "Down";
      break;
    case kMoveLeft:
      return "Left";
      break;
    default:
      return "Invalid action";
      break;
  }
}

int TwoZeroFourEightState::AvailableCellCount() const {
  int count = 0;
  for (int r = 0; r < kDefaultRows; r++) {
    for (int c = 0; c < kDefaultColumns; c++) {
      if (BoardAt(r, c).value == 0) {
        count++;
      }
    }
  }
  return count;
}

ActionsAndProbs TwoZeroFourEightState::ChanceOutcomes() const {
  ActionsAndProbs action_and_probs;
  int count = AvailableCellCount();
  if (count == 0) {
    action_and_probs.reserve(1);
    action_and_probs.emplace_back(kNoCellAvailableAction, 1);
    return action_and_probs;
  }
  action_and_probs.reserve(count * 2);
  for (int r = 0; r < kDefaultRows; r++) {
    for (int c = 0; c < kDefaultColumns; c++) {
      if (BoardAt(r, c).value == 0) {
        // 2 appearing randomly on the board should be 9 times as likely as a 4
        action_and_probs.emplace_back(ChanceActionToSpielAction(
            ChanceAction(r, c, false)), .9 / count);
        action_and_probs.emplace_back(ChanceActionToSpielAction(
            ChanceAction(r, c, true)), .1 / count);
      }
    }
  }
  return action_and_probs;
}

std::vector<Action> TwoZeroFourEightState::LegalActions() const {
  if (IsTerminal()) {
    return {};
  }
  if (IsChanceNode()) {
    return LegalChanceOutcomes();
  }
  return kPlayerActions();
}

bool TwoZeroFourEightState::InBounds(int row, int column) const {
  return (row >= 0 && row < kDefaultRows && column >= 0
      && column < kDefaultColumns);
}

std::string TwoZeroFourEightState::ToString() const {
  std::string str;
  for (int r = 0; r < kDefaultRows; ++r) {
    for (int c = 0; c < kDefaultColumns; ++c) {
      std::string tile = std::to_string(BoardAt(r, c).value);
      absl::StrAppend(&str, std::string(5 - tile.length(), ' '));
      absl::StrAppend(&str, tile);
    }
    absl::StrAppend(&str, "\n");
  }
  return str;
}

bool TwoZeroFourEightState::IsTerminal() const {
  return Reached2048()
      || (AvailableCellCount() == 0 && !TileMatchesAvailable());
}

bool TwoZeroFourEightState::Reached2048() const {
  for (int r = 0; r < kDefaultRows; r++) {
    for (int c = 0; c < kDefaultColumns; c++) {
      if (BoardAt(r, c).value == 2048) {
        return true;
      }
    }
  }
  return false;
}

int TwoZeroFourEightState::GetMaxTile() const {
  int max_tile = 0;
  for (int r = 0; r < kDefaultRows; r++) {
    for (int c = 0; c < kDefaultColumns; c++) {
      if (BoardAt(r, c).value > max_tile) {
        max_tile = BoardAt(r, c).value;
      }
    }
  }
  return max_tile;
}

std::vector<double> TwoZeroFourEightState::Rewards() const {
  return {action_score_};
}

std::vector<double> TwoZeroFourEightState::Returns() const {
  return {total_score_};
}

std::string TwoZeroFourEightState::InformationStateString(Player player) const {
  SPIEL_CHECK_GE(player, 0);
  SPIEL_CHECK_LT(player, num_players_);
  return HistoryString();
}

std::string TwoZeroFourEightState::ObservationString(Player player) const {
  SPIEL_CHECK_GE(player, 0);
  SPIEL_CHECK_LT(player, num_players_);
  return ToString();
}

void TwoZeroFourEightState::ObservationTensor(Player player,
                                      absl::Span<float> values) const {
  SPIEL_CHECK_GE(player, 0);
  SPIEL_CHECK_LT(player, num_players_);
  TensorView<2> view(values, {kDefaultRows, kDefaultColumns}, true);
  for (int row = 0; row < kDefaultRows; row++) {
    for (int column = 0; column < kDefaultColumns; column++) {
      view[{row, column}] = BoardAt(row, column).value;
    }
  }
}

void TwoZeroFourEightState::UndoAction(Player player, Action action) {
  history_.pop_back();
}

TwoZeroFourEightGame::TwoZeroFourEightGame(const GameParameters& params)
    : Game(kGameType, params),
      max_game_length_(ParameterValue<int>("max_game_length")),
      max_score_(ParameterValue<int>("max_score")) {}

int TwoZeroFourEightGame::NumDistinctActions() const {
  return kPlayerActions().size();
}

}  // namespace two_zero_four_eight
}  // namespace open_spiel
<|endoftext|>


<commit_before>#include <iostream>

#include <yajl/yajl_parse.h>
#include <yajl/yajl_gen.h>

#include <v8.h>
#include <node.h>
#include <node/node_events.h>

#include "callbacks.h"
#include "yajl.h"

using namespace v8;
using namespace node;

namespace yajljs {
void Handle::Initialize ( v8::Handle<v8::Object> target )
{
    v8::HandleScope scope;

    v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(New);

    t->Inherit( EventEmitter::constructor_template );
    t->InstanceTemplate()->SetInternalFieldCount(1);

    NODE_SET_PROTOTYPE_METHOD( t, "parse", Parse );
    target->Set( v8::String::NewSymbol( "Handle"), t->GetFunction() );
}

v8::Handle<v8::Value>
Handle::New (const v8::Arguments& args)
{
    v8::HandleScope scope;

    yajl_parser_config cfg;

    if( args.Length() < 1 || !args[0]->IsObject() )
    {
        return ThrowException( Exception::TypeError(
                    String::New( "Argument 0 must be a yajl_parser_config like object" ) ) );
    }

    Local<Object> obj = args[0]->ToObject();

    Local<Integer> allowComments = obj->Get( String::New( "allowComments" ) )->ToInteger();

    cfg.allowComments = allowComments->Value();
    Handle *handle = new Handle( cfg );
    handle->Wrap( args.This() );
    return args.This();
}

Handle::Handle( yajl_parser_config cfg ) : EventEmitter()
{
    callbacks.yajl_null = onNull;
    callbacks.yajl_boolean = onBoolean;

    // TODO expose
    yc_handle = yajl_alloc( &callbacks, &cfg, NULL, NULL );
}

Handle::~Handle()
{
    yajl_free( yc_handle );
}

}

v8::Handle<Value> yajljs::Handle::Parse( const Arguments& args )
{
    HandleScope scope;
    std::cerr << "PARSING\n";
    return args.This();
}

extern "C" void
init (v8::Handle<v8::Object> target)
{
    v8::HandleScope scope;
    yajljs::Handle::Initialize(target);
}
<commit_msg>Added Callbacks to the yajl_callbacks structure Implemented yajl handle allocation.<commit_after>#include <iostream>

#include <yajl/yajl_parse.h>
#include <yajl/yajl_gen.h>

#include <v8.h>
#include <node.h>
#include <node/node_events.h>

#include "callbacks.h"
#include "yajl.h"

using namespace v8;
using namespace node;

namespace yajljs {
void Handle::Initialize ( v8::Handle<v8::Object> target )
{
    v8::HandleScope scope;

    v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(New);

    t->Inherit( EventEmitter::constructor_template );
    t->InstanceTemplate()->SetInternalFieldCount(1);

    NODE_SET_PROTOTYPE_METHOD( t, "parse", Parse );
    target->Set( v8::String::NewSymbol( "Handle"), t->GetFunction() );
}

v8::Handle<v8::Value>
Handle::New (const v8::Arguments& args)
{
    v8::HandleScope scope;

    yajl_parser_config cfg;

    if( args.Length() < 1 || !args[0]->IsObject() )
    {
        return ThrowException( Exception::TypeError(
                    String::New( "Argument 0 must be a yajl_parser_config like object" ) ) );
    }

    Local<Object> obj = args[0]->ToObject();

    Local<Integer> allowComments = obj->Get( String::New( "allowComments" ) )->ToInteger();

    cfg.allowComments = allowComments->Value();
    Handle *handle = new Handle( cfg );
    handle->Wrap( args.This() );
    return args.This();
}

Handle::Handle( yajl_parser_config cfg ) : EventEmitter()
{
    callbacks.yajl_null = OnNull;
    callbacks.yajl_boolean = OnBoolean;
    callbacks.yajl_integer = OnInteger;
    callbacks.yajl_double = OnDouble;
    callbacks.yajl_number = OnNumber;
    callbacks.yajl_string = OnString;
    callbacks.yajl_start_map = OnStartMap;
    callbacks.yajl_map_key = OnMapKey;
    callbacks.yajl_end_map = OnEndMap;
    callbacks.yajl_start_array = OnStartArray;
    callbacks.yajl_end_array = OnEndArray;

    yc_handle = yajl_alloc( &callbacks, &cfg, NULL, this);
}

Handle::~Handle()
{
    yajl_free( yc_handle );
}

}

v8::Handle<Value> yajljs::Handle::Parse( const Arguments& args )
{
    HandleScope scope;
    std::cerr << "PARSING\n";
    return args.This();
}

extern "C" void
init (v8::Handle<v8::Object> target)
{
    v8::HandleScope scope;
    yajljs::Handle::Initialize(target);
}
<|endoftext|>


<commit_before>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2011,2012 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */
#include "conf.hh"
#include "dparse.h"
#include "helper.hh"
#include "history.hh"
#include <cstring>

#ifndef DROI
#include <glib.h>
#else

#endif

class EndHook;

extern "C" {
  extern D_ParserTables parser_tables_conf;
}

extern Conf* conf_obj;

#define RETURN_ERROR_VOID(s) {                  \
    log.pop();                                  \
    status=false;                               \
    errormsg=s;                                 \
    return;                                     \
  }

#define RETURN_ERROR_VERDICT(s) {               \
    log.pop();                                  \
    status=false;                               \
    errormsg=s;                                 \
    exit_status=-1;                             \
    return Verdict::ERROR;                      \
  }

void Conf::load(std::string& name,std::string& content)
{
  D_Parser *p = new_D_Parser(&parser_tables_conf, 512);
  p->loc.pathname = name.c_str();
  char *s;

  Conf* tmp=conf_obj;
  log.push("conf_load");
  log.debug("Conf::load %s",name.c_str());
  conf_obj=this;

  s=readfile(name.c_str());

  if (s==NULL) {
    status=false;
    errormsg=std::string("Can't read configuration file \"")+name+"\"";
    log.pop();
    free_D_Parser(p);
    return;
  }

  std::string ss(s);
  ss=ss+"\n"+content;
  if ((name!="" && s==NULL))
    RETURN_ERROR_VOID("Loading \"" + name + "\" failed.");

  if (ss=="")
    RETURN_ERROR_VOID("Empty configuration");

  bool ret=dparse(p,(char*)ss.c_str(),std::strlen(ss.c_str()));

  ret=p->syntax_errors==0 && ret;

  if (!ret)
    RETURN_ERROR_VOID("Parsing \"" + name + "\" failed.");

  free(s);

  free_D_Parser(p);

  conf_obj=tmp;

  if ((heuristic=new_heuristic(log,heuristic_name)) == NULL)
    RETURN_ERROR_VOID("Creating heuristic \"" + heuristic_name + "\" failed.");

  if (heuristic->status==false)
    RETURN_ERROR_VOID("Error in heuristic \"" + heuristic_name + "\":" +
                      heuristic->errormsg);

  if ((model=new_model(log, model_name)) == NULL) {
    RETURN_ERROR_VOID("Creating model \"" +
                      filetype(model_name)
                      + "\" failed.");
  }

  coverage = new_coverage(log,coverage_name);

  if (coverage == NULL)
    RETURN_ERROR_VOID("Creating coverage \"" + coverage_name + "\" failed.");

  if (!coverage->status)
    RETURN_ERROR_VOID("Error in coverage \"" + coverage_name + "\": " + coverage->errormsg);

  if (!model->status || !model->init() || !model->reset())
    RETURN_ERROR_VOID("Error in model: " + model->stringify());

  heuristic->set_coverage(coverage);

  heuristic->set_model(model);

  coverage->set_model(model);

  adapter = new_adapter(log, adapter_name);

  if (adapter && !adapter->status) {
    status=false;
    errormsg=adapter->errormsg;
    return;
  }

  adapter->set_tags(&model->getSPNames());

  /* handle history */
  for(unsigned i=0;i<history.size();i++) {
    History* h=new_history(log,*history[i]);

    if (h) {
      h->set_coverage(coverage,model);
      if (!h->status) {
        RETURN_ERROR_VOID(h->errormsg);
      }
    } else {
      RETURN_ERROR_VOID("Creating history \""+ *history[i] + "\" failed.");
    }
  }

  if (adapter == NULL)
    RETURN_ERROR_VOID("Creating adapter \"" + adapter_name + "\" failed.");

  adapter->set_actions(&model->getActionNames());

  if (!coverage->status)
    RETURN_ERROR_VOID("Coverage error: " + coverage->stringify());

  if (!adapter->status)
    RETURN_ERROR_VOID("Adapter error: " + adapter->stringify());

  log.pop();
}

#include <sstream>

std::string Conf::stringify() {
  std::ostringstream t(std::ios::out | std::ios::binary);

  if (!status) {
    return errormsg;
  }

  t << "model = \"" << removehash(model_name) << capsulate(model->stringify()) << std::endl;
  t << "heuristic = \"" << heuristic_name << "\"" << std::endl;
  t << "coverage = \"" <<  coverage_name << "\"" << std::endl;
  t << "adapter = \"" << adapter_name
    << capsulate(adapter->stringify()) << std::endl;

  /* TODO: stringify end conditions */

  return t.str();
}

Verdict::Verdict Conf::execute(bool interactive) {

  Policy policy;
  log.push("conf_execute");

  if (!status) {
    errormsg = "cannot start executing test due to earlier errors: " + errormsg;
    return Verdict::ERROR;
  }

  if (!adapter->init())
    RETURN_ERROR_VERDICT("Initialising adapter failed: " + adapter->stringify());

  // Validate and finish existing end_conditions
  {
    bool end_by_coverage = false;
    for (unsigned int i = 0; i < end_conditions.size(); i++) {
      End_condition* e = end_conditions[i];
      if (e->status == false)
        RETURN_ERROR_VERDICT("Error in end condition: " + e->stringify());
      if (e->counter == End_condition::ACTION) {
        // avoid string comparisons, fetch the index of the tag
        e->param_long = find(model->getActionNames(), (e->param),-1);
        if (e->param_long==-1) {
          RETURN_ERROR_VERDICT("Error in end condition: " + e->stringify());
        }
      }
      if (e->counter == End_condition::STATETAG) {
        // avoid string comparisons, fetch the index of the tag
        e->param_long = find(model->getSPNames(), (e->param),-1);
        if (e->param_long==-1) {
          RETURN_ERROR_VERDICT("Error in end condition: " + e->stringify());
        }
      }
      if (e->counter == End_condition::COVERAGE) {
        end_by_coverage = true;
      }
      if (e->counter == End_condition::DURATION) {
        end_time = e->param_time;
      }
    }
    // Add default end conditions (if coverage is reached, test is passed)
    if (!end_by_coverage) {
      end_conditions.push_back(new End_condition_coverage(Verdict::PASS, "1.0"));
    }
  }

  Test_engine engine(*heuristic,*adapter,log,policy,end_conditions);

  if (interactive) {
    engine.interactive();
  } else {
    Verdict::Verdict v = engine.run(end_time);

    if (!heuristic->status) {
      fprintf(stderr,"heuristic error: %s\n",heuristic->errormsg.c_str());
    }

    if (!model->status) {
      fprintf(stderr,"model error: %s\n",model->errormsg.c_str());
    }

    if (!adapter->status) {
      fprintf(stderr,"adapter error: %s\n",adapter->errormsg.c_str());
    }

    if (!coverage->status) {
      fprintf(stderr,"coverage error: %s\n",coverage->errormsg.c_str());
    }
    handle_hooks(v);
  }
  log.pop();
  status = true;
  errormsg = engine.verdict_msg() + ": " + engine.reason_msg();
  return engine.verdict();
}

void Conf::handle_hooks(Verdict::Verdict v)
{
  std::list<EndHook*>* hooklist=NULL;

  switch (v) {
  case Verdict::FAIL: {
    hooklist=&fail_hooks;
    break;
  }
  case Verdict::PASS: {
    hooklist=&pass_hooks;
    break;
  }
  case Verdict::INCONCLUSIVE: {
    hooklist=&inc_hooks;
    break;
  }
  case Verdict::ERROR: {
    hooklist=&error_hooks;
    break;
  }
  default: {
    // unknown verdict?
  }
  }
  if (hooklist)
    for_each(hooklist->begin(),hooklist->end(),hook_runner);
}

/*
  void Conf::set_exitvalue(std::string& s)
  {
  std::string cmd;
  std::string value;
  split(s,cmd,value);
  exit_status=atoi(value.c_str());
  }
*/

void Conf::set_observe_sleep(std::string &s)
{
  Adapter::sleeptime=atoi(s.c_str());
}

void Conf::add_end_condition(Verdict::Verdict v,std::string& s)

{
  End_condition *ec = new_end_condition(v,s);

  if (ec==NULL) {
    status=false;
    errormsg=errormsg+"Creating end condition \""+s+"\" failed.\n";
  } else {
    add_end_condition(ec);
  }
}

void hook_delete(EndHook* e);

Conf::~Conf() {
  for (unsigned int i = 0; i < end_conditions.size(); i++)
    delete end_conditions[i];
  log.pop();
  if (heuristic)
    delete heuristic;

  if (adapter)
    delete adapter;

  if (model)
    delete model;

  if (coverage)
    delete coverage;

  adapter=NULL;
  heuristic=NULL;
  model=NULL;
  coverage=NULL;

  for(unsigned i=0;i<history.size();i++) {
    if (history[i]) {
      delete history[i];
    }
  }

  for_each(pass_hooks.begin(),pass_hooks.end(),hook_delete);
  for_each(fail_hooks.begin(),fail_hooks.end(),hook_delete);
  for_each(inc_hooks.begin(),inc_hooks.end(),hook_delete);
  for_each(error_hooks.begin(),error_hooks.end(),hook_delete);

}
<commit_msg>conf: fixed (prevented) sending tags to non-existing adapters<commit_after>/*
 * fMBT, free Model Based Testing tool
 * Copyright (c) 2011,2012 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */
#include "conf.hh"
#include "dparse.h"
#include "helper.hh"
#include "history.hh"
#include <cstring>

#ifndef DROI
#include <glib.h>
#else

#endif

class EndHook;

extern "C" {
  extern D_ParserTables parser_tables_conf;
}

extern Conf* conf_obj;

#define RETURN_ERROR_VOID(s) {                  \
    log.pop();                                  \
    status=false;                               \
    errormsg=s;                                 \
    return;                                     \
  }

#define RETURN_ERROR_VERDICT(s) {               \
    log.pop();                                  \
    status=false;                               \
    errormsg=s;                                 \
    exit_status=-1;                             \
    return Verdict::ERROR;                      \
  }

void Conf::load(std::string& name,std::string& content)
{
  D_Parser *p = new_D_Parser(&parser_tables_conf, 512);
  p->loc.pathname = name.c_str();
  char *s;

  Conf* tmp=conf_obj;
  log.push("conf_load");
  log.debug("Conf::load %s",name.c_str());
  conf_obj=this;

  s=readfile(name.c_str());

  if (s==NULL) {
    status=false;
    errormsg=std::string("Can't read configuration file \"")+name+"\"";
    log.pop();
    free_D_Parser(p);
    return;
  }

  std::string ss(s);
  ss=ss+"\n"+content;
  if ((name!="" && s==NULL))
    RETURN_ERROR_VOID("Loading \"" + name + "\" failed.");

  if (ss=="")
    RETURN_ERROR_VOID("Empty configuration");

  bool ret=dparse(p,(char*)ss.c_str(),std::strlen(ss.c_str()));

  ret=p->syntax_errors==0 && ret;

  if (!ret)
    RETURN_ERROR_VOID("Parsing \"" + name + "\" failed.");

  free(s);

  free_D_Parser(p);

  conf_obj=tmp;

  if ((heuristic=new_heuristic(log,heuristic_name)) == NULL)
    RETURN_ERROR_VOID("Creating heuristic \"" + heuristic_name + "\" failed.");

  if (heuristic->status==false)
    RETURN_ERROR_VOID("Error in heuristic \"" + heuristic_name + "\":" +
                      heuristic->errormsg);

  if ((model=new_model(log, model_name)) == NULL) {
    RETURN_ERROR_VOID("Creating model \"" +
                      filetype(model_name)
                      + "\" failed.");
  }

  coverage = new_coverage(log,coverage_name);

  if (coverage == NULL)
    RETURN_ERROR_VOID("Creating coverage \"" + coverage_name + "\" failed.");

  if (!coverage->status)
    RETURN_ERROR_VOID("Error in coverage \"" + coverage_name + "\": " + coverage->errormsg);

  if (!model->status || !model->init() || !model->reset())
    RETURN_ERROR_VOID("Error in model: " + model->stringify());

  heuristic->set_coverage(coverage);

  heuristic->set_model(model);

  coverage->set_model(model);

  adapter = new_adapter(log, adapter_name);

  if (adapter == NULL)
    RETURN_ERROR_VOID("Creating adapter \"" + adapter_name + "\" failed.");

  if (!adapter->status) {
    status=false;
    errormsg=adapter->errormsg;
    return;
  }

  adapter->set_tags(&model->getSPNames());

  if (!adapter->status) {
    status=false;
    errormsg=adapter->errormsg;
    return;
  }

  /* handle history */
  for(unsigned i=0;i<history.size();i++) {
    History* h=new_history(log,*history[i]);

    if (h) {
      h->set_coverage(coverage,model);
      if (!h->status) {
        RETURN_ERROR_VOID(h->errormsg);
      }
    } else {
      RETURN_ERROR_VOID("Creating history \""+ *history[i] + "\" failed.");
    }
  }

  adapter->set_actions(&model->getActionNames());

  if (!coverage->status)
    RETURN_ERROR_VOID("Coverage error: " + coverage->stringify());

  if (!adapter->status)
    RETURN_ERROR_VOID("Adapter error: " + adapter->stringify());

  log.pop();
}

#include <sstream>

std::string Conf::stringify() {
  std::ostringstream t(std::ios::out | std::ios::binary);

  if (!status) {
    return errormsg;
  }

  t << "model = \"" << removehash(model_name) << capsulate(model->stringify()) << std::endl;
  t << "heuristic = \"" << heuristic_name << "\"" << std::endl;
  t << "coverage = \"" <<  coverage_name << "\"" << std::endl;
  t << "adapter = \"" << adapter_name
    << capsulate(adapter->stringify()) << std::endl;

  /* TODO: stringify end conditions */

  return t.str();
}

Verdict::Verdict Conf::execute(bool interactive) {

  Policy policy;
  log.push("conf_execute");

  if (!status) {
    errormsg = "cannot start executing test due to earlier errors: " + errormsg;
    return Verdict::ERROR;
  }

  if (!adapter->init())
    RETURN_ERROR_VERDICT("Initialising adapter failed: " + adapter->stringify());

  // Validate and finish existing end_conditions
  {
    bool end_by_coverage = false;
    for (unsigned int i = 0; i < end_conditions.size(); i++) {
      End_condition* e = end_conditions[i];
      if (e->status == false)
        RETURN_ERROR_VERDICT("Error in end condition: " + e->stringify());
      if (e->counter == End_condition::ACTION) {
        // avoid string comparisons, fetch the index of the tag
        e->param_long = find(model->getActionNames(), (e->param),-1);
        if (e->param_long==-1) {
          RETURN_ERROR_VERDICT("Error in end condition: " + e->stringify());
        }
      }
      if (e->counter == End_condition::STATETAG) {
        // avoid string comparisons, fetch the index of the tag
        e->param_long = find(model->getSPNames(), (e->param),-1);
        if (e->param_long==-1) {
          RETURN_ERROR_VERDICT("Error in end condition: " + e->stringify());
        }
      }
      if (e->counter == End_condition::COVERAGE) {
        end_by_coverage = true;
      }
      if (e->counter == End_condition::DURATION) {
        end_time = e->param_time;
      }
    }
    // Add default end conditions (if coverage is reached, test is passed)
    if (!end_by_coverage) {
      end_conditions.push_back(new End_condition_coverage(Verdict::PASS, "1.0"));
    }
  }

  Test_engine engine(*heuristic,*adapter,log,policy,end_conditions);

  if (interactive) {
    engine.interactive();
  } else {
    Verdict::Verdict v = engine.run(end_time);

    if (!heuristic->status) {
      fprintf(stderr,"heuristic error: %s\n",heuristic->errormsg.c_str());
    }

    if (!model->status) {
      fprintf(stderr,"model error: %s\n",model->errormsg.c_str());
    }

    if (!adapter->status) {
      fprintf(stderr,"adapter error: %s\n",adapter->errormsg.c_str());
    }

    if (!coverage->status) {
      fprintf(stderr,"coverage error: %s\n",coverage->errormsg.c_str());
    }
    handle_hooks(v);
  }
  log.pop();
  status = true;
  errormsg = engine.verdict_msg() + ": " + engine.reason_msg();
  return engine.verdict();
}

void Conf::handle_hooks(Verdict::Verdict v)
{
  std::list<EndHook*>* hooklist=NULL;

  switch (v) {
  case Verdict::FAIL: {
    hooklist=&fail_hooks;
    break;
  }
  case Verdict::PASS: {
    hooklist=&pass_hooks;
    break;
  }
  case Verdict::INCONCLUSIVE: {
    hooklist=&inc_hooks;
    break;
  }
  case Verdict::ERROR: {
    hooklist=&error_hooks;
    break;
  }
  default: {
    // unknown verdict?
  }
  }
  if (hooklist)
    for_each(hooklist->begin(),hooklist->end(),hook_runner);
}

/*
  void Conf::set_exitvalue(std::string& s)
  {
  std::string cmd;
  std::string value;
  split(s,cmd,value);
  exit_status=atoi(value.c_str());
  }
*/

void Conf::set_observe_sleep(std::string &s)
{
  Adapter::sleeptime=atoi(s.c_str());
}

void Conf::add_end_condition(Verdict::Verdict v,std::string& s)

{
  End_condition *ec = new_end_condition(v,s);

  if (ec==NULL) {
    status=false;
    errormsg=errormsg+"Creating end condition \""+s+"\" failed.\n";
  } else {
    add_end_condition(ec);
  }
}

void hook_delete(EndHook* e);

Conf::~Conf() {
  for (unsigned int i = 0; i < end_conditions.size(); i++)
    delete end_conditions[i];
  log.pop();
  if (heuristic)
    delete heuristic;

  if (adapter)
    delete adapter;

  if (model)
    delete model;

  if (coverage)
    delete coverage;

  adapter=NULL;
  heuristic=NULL;
  model=NULL;
  coverage=NULL;

  for(unsigned i=0;i<history.size();i++) {
    if (history[i]) {
      delete history[i];
    }
  }

  for_each(pass_hooks.begin(),pass_hooks.end(),hook_delete);
  for_each(fail_hooks.begin(),fail_hooks.end(),hook_delete);
  for_each(inc_hooks.begin(),inc_hooks.end(),hook_delete);
  for_each(error_hooks.begin(),error_hooks.end(),hook_delete);

}
<|endoftext|>


<commit_before>/**
 * This file is part of Slideshow.
 * Copyright (C) 2008-2010 David Sveningsson <ext@sidvind.com>
 *
 * Slideshow is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Slideshow is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Slideshow.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#	include "config.h"
#endif

#include "Log.h"
#include "exception.h"
#include <stdarg.h>
#include <cstdlib>
#include <cstring>
#include <memory> /* for auto_ptr */
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <portable/asprintf.h>
#include <portable/file.h>

#ifdef WIN32
#	include "win32.h"
#endif

#ifdef HAVE_SYSLOG
#	include <syslog.h>
int syslog_severity[5] = {
	LOG_DEBUG,
	LOG_INFO,
	LOG_NOTICE,
	LOG_WARNING,
	LOG_ERR
};
#endif /* HAVE_SYSLOG */

Log::vector Log::_dst;

FileDestination::FileDestination(const char* filename)
	: _fp(NULL)
	, _autoclose(true) {

	if ( fopen_s(&_fp, filename, "a") != 0 ){
		fprintf(stderr, "Failed to open logfile '%s' ! Fatal error!\n", filename);
		exit(1);
	}
}
FileDestination::FileDestination(FILE* fp)
	: _fp(fp)
	, _autoclose(false) {

}
FileDestination::~FileDestination(){
	if ( _autoclose ){
		fclose(_fp);
	}
}
void FileDestination::write(const char* content, const char* decorated) const {
	fputs(decorated, _fp);
	fflush(_fp);
}

FIFODestination::FIFODestination(const char* filename)
	: _filename(NULL)
	, _fp(NULL) {

	_filename = strdup(filename);
	mkfifo(filename, 0600);

	if ( fopen_s(&_fp, filename, "w") != 0 ){
		fprintf(stderr, "Failed to open logfile '%s' ! Fatal error!\n", filename);
		exit(1);
	}
}

FIFODestination::~FIFODestination(){
	fclose(_fp);
	unlink(_filename);
	free(_filename);
}
void FIFODestination::write(const char* content, const char* decorated) const {
	fputs(decorated, _fp);
	fflush(_fp);
}

SocketDestination::SocketDestination(int socket)
	: _socket(socket) {

}

SocketDestination::~SocketDestination(){
	close(_socket);
}

void SocketDestination::write(const char* content, const char* decorated) const {
	send(_socket, decorated, strlen(decorated), 0);
}

#ifdef HAVE_SYSLOG
SyslogDestination::SyslogDestination(){
	/* @todo only a single instance of syslog may be opened */
	openlog(PACKAGE, 0, LOG_DAEMON);
}
SyslogDestination::~SyslogDestination(){
	closelog();
}
void SyslogDestination::write(const char* content, const char* decorated) const {
	syslog(syslog_severity[severity], content);
}
#endif /* HAVE_SYSLOG */

UDSServer::UDSServer(const char* filename)
	: _filename(NULL)
	, _socket(-1) {

	_filename = strdup(filename);

	struct sockaddr_un address;
	socklen_t address_length;

	_socket = socket(PF_UNIX, SOCK_STREAM, 0);

	unlink(filename);
	address.sun_family = AF_UNIX;
	address_length = (socklen_t)sizeof(address.sun_family) +
		(socklen_t)sprintf(address.sun_path, "%s", filename);

	bind(_socket, (struct sockaddr *) &address, address_length);
	listen(_socket, 5);
}

UDSServer::~UDSServer(){
	unlink(_filename);
	free(_filename);
}

bool UDSServer::accept(struct timeval *timeout) const {
	fd_set rfds;
	FD_ZERO(&rfds);
	FD_SET(_socket, &rfds);

	if ( select(_socket+1, &rfds, NULL, NULL, timeout) <= 0 ){
		return false;
	}

	int client = ::accept(_socket, NULL, NULL);
	Log::add_destination(new SocketDestination(client));

	return true;
}

void Log::initialize(){

}

void Log::cleanup(){
	for ( iterator it = _dst.begin(); it != _dst.end(); ++it ){
		delete *it;
	}
	_dst.clear();
}

void Log::add_destination(Destination* dst){
	_dst.push_back(dst);
}

void Log::message(Severity severity, const char* fmt, ...){
	va_list ap;
	va_start(ap, fmt);
	vmessage(severity, fmt, ap);
	va_end(ap);
}

void Log::vmessage(Severity severity, const char* fmt, va_list ap){
	static char buf[255]; /* this isn't thread-safe anyway, might as well make it static */

	std::auto_ptr<char> content( vasprintf2(fmt, ap) );
	std::auto_ptr<char> decorated( asprintf2("(%s) [%s] %s", severity_string(severity), timestring(buf, 255), content.get()) );

	for ( iterator it = _dst.begin(); it != _dst.end(); ++it ){
		Destination* dst = *it;
		dst->write(content.get(), decorated.get());
	}
}

char* Log::timestring(char *buffer, int bufferlen) {
	time_t t = time(NULL);
	struct tm* nt;
#ifdef WIN32
	nt = new struct tm;
	localtime_s(nt, &t);
#else
	nt = localtime(&t);
#endif
	strftime(buffer, bufferlen, "%Y-%m-%d %H:%M:%S", nt);
#ifdef WIN32
	delete nt;
#endif
	return buffer;
}

const char* Log::severity_string(Severity severity){
	switch ( severity ){
		case Debug: return "DD";
		case Verbose: return "--";
		case Info: return "  ";
		case Warning: return "WW";
		case Fatal: return "!!";
	}
	return NULL;
}
<commit_msg>assert fp != null<commit_after>/**
 * This file is part of Slideshow.
 * Copyright (C) 2008-2010 David Sveningsson <ext@sidvind.com>
 *
 * Slideshow is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Slideshow is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Slideshow.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#	include "config.h"
#endif

#include "Log.h"
#include "exception.h"
#include <stdarg.h>
#include <cstdlib>
#include <cstring>
#include <memory> /* for auto_ptr */
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <portable/asprintf.h>
#include <portable/file.h>

#ifdef WIN32
#	include "win32.h"
#endif

#ifdef HAVE_SYSLOG
#	include <syslog.h>
int syslog_severity[5] = {
	LOG_DEBUG,
	LOG_INFO,
	LOG_NOTICE,
	LOG_WARNING,
	LOG_ERR
};
#endif /* HAVE_SYSLOG */

Log::vector Log::_dst;

FileDestination::FileDestination(const char* filename)
	: _fp(NULL)
	, _autoclose(true) {

	if ( fopen_s(&_fp, filename, "a") != 0 ){
		fprintf(stderr, "Failed to open logfile '%s' ! Fatal error!\n", filename);
		exit(1);
	}
}
FileDestination::FileDestination(FILE* fp)
	: _fp(fp)
	, _autoclose(false) {

	if ( !fp ){
		fprintf(stderr, "Failed to read fp! Fatal error!\n");
		exit(1);
	}
}

FileDestination::~FileDestination(){
	if ( _autoclose ){
		fclose(_fp);
	}
}
void FileDestination::write(const char* content, const char* decorated) const {
	fputs(decorated, _fp);
	fflush(_fp);
}

FIFODestination::FIFODestination(const char* filename)
	: _filename(NULL)
	, _fp(NULL) {

	_filename = strdup(filename);
	mkfifo(filename, 0600);

	if ( fopen_s(&_fp, filename, "w") != 0 ){
		fprintf(stderr, "Failed to open logfile '%s' ! Fatal error!\n", filename);
		exit(1);
	}
}

FIFODestination::~FIFODestination(){
	fclose(_fp);
	unlink(_filename);
	free(_filename);
}
void FIFODestination::write(const char* content, const char* decorated) const {
	fputs(decorated, _fp);
	fflush(_fp);
}

SocketDestination::SocketDestination(int socket)
	: _socket(socket) {

}

SocketDestination::~SocketDestination(){
	close(_socket);
}

void SocketDestination::write(const char* content, const char* decorated) const {
	send(_socket, decorated, strlen(decorated), 0);
}

#ifdef HAVE_SYSLOG
SyslogDestination::SyslogDestination(){
	/* @todo only a single instance of syslog may be opened */
	openlog(PACKAGE, 0, LOG_DAEMON);
}
SyslogDestination::~SyslogDestination(){
	closelog();
}
void SyslogDestination::write(const char* content, const char* decorated) const {
	syslog(syslog_severity[severity], content);
}
#endif /* HAVE_SYSLOG */

UDSServer::UDSServer(const char* filename)
	: _filename(NULL)
	, _socket(-1) {

	_filename = strdup(filename);

	struct sockaddr_un address;
	socklen_t address_length;

	_socket = socket(PF_UNIX, SOCK_STREAM, 0);

	unlink(filename);
	address.sun_family = AF_UNIX;
	address_length = (socklen_t)sizeof(address.sun_family) +
		(socklen_t)sprintf(address.sun_path, "%s", filename);

	bind(_socket, (struct sockaddr *) &address, address_length);
	listen(_socket, 5);
}

UDSServer::~UDSServer(){
	unlink(_filename);
	free(_filename);
}

bool UDSServer::accept(struct timeval *timeout) const {
	fd_set rfds;
	FD_ZERO(&rfds);
	FD_SET(_socket, &rfds);

	if ( select(_socket+1, &rfds, NULL, NULL, timeout) <= 0 ){
		return false;
	}

	int client = ::accept(_socket, NULL, NULL);
	Log::add_destination(new SocketDestination(client));

	return true;
}

void Log::initialize(){

}

void Log::cleanup(){
	for ( iterator it = _dst.begin(); it != _dst.end(); ++it ){
		delete *it;
	}
	_dst.clear();
}

void Log::add_destination(Destination* dst){
	_dst.push_back(dst);
}

void Log::message(Severity severity, const char* fmt, ...){
	va_list ap;
	va_start(ap, fmt);
	vmessage(severity, fmt, ap);
	va_end(ap);
}

void Log::vmessage(Severity severity, const char* fmt, va_list ap){
	static char buf[255]; /* this isn't thread-safe anyway, might as well make it static */

	std::auto_ptr<char> content( vasprintf2(fmt, ap) );
	std::auto_ptr<char> decorated( asprintf2("(%s) [%s] %s", severity_string(severity), timestring(buf, 255), content.get()) );

	for ( iterator it = _dst.begin(); it != _dst.end(); ++it ){
		Destination* dst = *it;
		dst->write(content.get(), decorated.get());
	}
}

char* Log::timestring(char *buffer, int bufferlen) {
	time_t t = time(NULL);
	struct tm* nt;
#ifdef WIN32
	nt = new struct tm;
	localtime_s(nt, &t);
#else
	nt = localtime(&t);
#endif
	strftime(buffer, bufferlen, "%Y-%m-%d %H:%M:%S", nt);
#ifdef WIN32
	delete nt;
#endif
	return buffer;
}

const char* Log::severity_string(Severity severity){
	switch ( severity ){
		case Debug: return "DD";
		case Verbose: return "--";
		case Info: return "  ";
		case Warning: return "WW";
		case Fatal: return "!!";
	}
	return NULL;
}
<|endoftext|>