#include "ale_state.hpp"
#include <sstream>
#include <stdexcept>
#include "../emucore/m6502/src/System.hxx"
#include "../emucore/Event.hxx"
#include "../emucore/Deserializer.hxx"
#include "../emucore/Serializer.hxx"
#include "../common/Constants.h"
#include "../games/RomSettings.hpp"
namespace ale {
ALEState::ALEState()
: m_left_paddle(PADDLE_DEFAULT_VALUE),
m_right_paddle(PADDLE_DEFAULT_VALUE),
m_paddle_min(PADDLE_MIN),
m_paddle_max(PADDLE_MAX),
m_frame_number(0),
m_episode_frame_number(0),
m_mode(0),
m_difficulty(0) {}
ALEState::ALEState(const ALEState& rhs, const std::string& serialized)
: m_left_paddle(rhs.m_left_paddle),
m_right_paddle(rhs.m_right_paddle),
m_paddle_min(rhs.m_paddle_min),
m_paddle_max(rhs.m_paddle_max),
m_frame_number(rhs.m_frame_number),
m_episode_frame_number(rhs.m_episode_frame_number),
m_serialized_state(serialized),
m_mode(rhs.m_mode),
m_difficulty(rhs.m_difficulty) {}
ALEState::ALEState(const std::string& serialized) {
Deserializer des(serialized);
this->m_left_paddle = des.getInt();
this->m_right_paddle = des.getInt();
this->m_frame_number = des.getInt();
this->m_episode_frame_number = des.getInt();
this->m_mode = des.getInt();
this->m_difficulty = des.getInt();
this->m_serialized_state = des.getString();
this->m_paddle_min = des.getInt();
this->m_paddle_max = des.getInt();
}
void ALEState::load(OSystem* osystem, RomSettings* settings, std::string md5,
const ALEState& rhs, bool load_system) {
assert(rhs.m_serialized_state.length() > 0);
Deserializer deser(rhs.m_serialized_state);
if (deser.getBool() != load_system)
throw new std::runtime_error("Attempting to load an ALEState which does "
"not contain system information.");
osystem->console().system().loadState(md5, deser);
if (load_system)
osystem->loadState(deser);
settings->loadState(deser);
m_left_paddle = rhs.m_left_paddle;
m_right_paddle = rhs.m_right_paddle;
m_paddle_min = rhs.m_paddle_min;
m_paddle_max = rhs.m_paddle_max;
m_frame_number = rhs.m_frame_number;
m_episode_frame_number = rhs.m_episode_frame_number;
m_mode = rhs.m_mode;
m_difficulty = rhs.m_difficulty;
}
ALEState ALEState::save(OSystem* osystem, RomSettings* settings,
std::string md5, bool save_system) {
Serializer ser;
ser.putBool(save_system);
osystem->console().system().saveState(md5, ser);
if (save_system)
osystem->saveState(ser);
settings->saveState(ser);
return ALEState(*this, ser.get_str());
}
void ALEState::incrementFrame(int steps ) {
m_frame_number += steps;
m_episode_frame_number += steps;
}
void ALEState::resetEpisodeFrameNumber() { m_episode_frame_number = 0; }
std::string ALEState::serialize() {
Serializer ser;
ser.putInt(this->m_left_paddle);
ser.putInt(this->m_right_paddle);
ser.putInt(this->m_frame_number);
ser.putInt(this->m_episode_frame_number);
ser.putInt(this->m_mode);
ser.putInt(this->m_difficulty);
ser.putString(this->m_serialized_state);
ser.putInt(this->m_paddle_min);
ser.putInt(this->m_paddle_max);
return ser.get_str();
}
int ALEState::calcPaddleResistance(int x_val) {
return x_val; }
void ALEState::resetPaddles(Event* event) {
int paddle_default = (m_paddle_min + m_paddle_max) / 2;
setPaddles(event, paddle_default, paddle_default);
}
void ALEState::setPaddles(Event* event, int left, int right) {
m_left_paddle = left;
m_right_paddle = right;
int left_resistance = calcPaddleResistance(m_left_paddle);
int right_resistance = calcPaddleResistance(m_right_paddle);
event->set(Event::PaddleZeroResistance, left_resistance);
event->set(Event::PaddleOneResistance, right_resistance);
}
void ALEState::setPaddleLimits(int paddle_min_val, int paddle_max_val) {
m_paddle_min = paddle_min_val;
m_paddle_max = paddle_max_val;
}
void ALEState::updatePaddlePositions(Event* event, int delta_left,
int delta_right) {
m_left_paddle += delta_left;
if (m_left_paddle < m_paddle_min) {
m_left_paddle = m_paddle_min;
}
if (m_left_paddle > m_paddle_max) {
m_left_paddle = m_paddle_max;
}
m_right_paddle += delta_right;
if (m_right_paddle < m_paddle_min) {
m_right_paddle = m_paddle_min;
}
if (m_right_paddle > m_paddle_max) {
m_right_paddle = m_paddle_max;
}
setPaddles(event, m_left_paddle, m_right_paddle);
}
void ALEState::applyActionPaddles(Event* event, int player_a_action,
int player_b_action) {
resetKeys(event);
int delta_left;
int delta_right;
switch (player_a_action) {
case PLAYER_A_RIGHT:
case PLAYER_A_RIGHTFIRE:
case PLAYER_A_UPRIGHT:
case PLAYER_A_DOWNRIGHT:
case PLAYER_A_UPRIGHTFIRE:
case PLAYER_A_DOWNRIGHTFIRE:
delta_left = -PADDLE_DELTA;
break;
case PLAYER_A_LEFT:
case PLAYER_A_LEFTFIRE:
case PLAYER_A_UPLEFT:
case PLAYER_A_DOWNLEFT:
case PLAYER_A_UPLEFTFIRE:
case PLAYER_A_DOWNLEFTFIRE:
delta_left = PADDLE_DELTA;
break;
default:
delta_left = 0;
break;
}
switch (player_b_action) {
case PLAYER_B_RIGHT:
case PLAYER_B_RIGHTFIRE:
case PLAYER_B_UPRIGHT:
case PLAYER_B_DOWNRIGHT:
case PLAYER_B_UPRIGHTFIRE:
case PLAYER_B_DOWNRIGHTFIRE:
delta_right = -PADDLE_DELTA;
break;
case PLAYER_B_LEFT:
case PLAYER_B_LEFTFIRE:
case PLAYER_B_UPLEFT:
case PLAYER_B_DOWNLEFT:
case PLAYER_B_UPLEFTFIRE:
case PLAYER_B_DOWNLEFTFIRE:
delta_right = PADDLE_DELTA;
break;
default:
delta_right = 0;
break;
}
updatePaddlePositions(event, delta_left, delta_right);
if (player_a_action == RESET || player_b_action == RESET)
event->set(Event::ConsoleReset, 1);
switch (player_a_action) {
case PLAYER_A_FIRE:
case PLAYER_A_UPFIRE:
case PLAYER_A_RIGHTFIRE:
case PLAYER_A_LEFTFIRE:
case PLAYER_A_DOWNFIRE:
case PLAYER_A_UPRIGHTFIRE:
case PLAYER_A_UPLEFTFIRE:
case PLAYER_A_DOWNRIGHTFIRE:
case PLAYER_A_DOWNLEFTFIRE:
event->set(Event::PaddleZeroFire, 1);
break;
default:
break;
}
switch (player_b_action) {
case PLAYER_B_FIRE:
case PLAYER_B_UPFIRE:
case PLAYER_B_RIGHTFIRE:
case PLAYER_B_LEFTFIRE:
case PLAYER_B_DOWNFIRE:
case PLAYER_B_UPRIGHTFIRE:
case PLAYER_B_UPLEFTFIRE:
case PLAYER_B_DOWNRIGHTFIRE:
case PLAYER_B_DOWNLEFTFIRE:
event->set(Event::PaddleOneFire, 1);
break;
default:
break;
}
}
void ALEState::pressSelect(Event* event) {
resetKeys(event);
event->set(Event::ConsoleSelect, 1);
}
void ALEState::setDifficultySwitches(Event* event, unsigned int value) {
event->set(Event::ConsoleLeftDifficultyA, value & 1);
event->set(Event::ConsoleLeftDifficultyB, !(value & 1));
event->set(Event::ConsoleRightDifficultyA, (value & 2) >> 1);
event->set(Event::ConsoleRightDifficultyB, !((value & 2) >> 1));
}
void ALEState::setActionJoysticks(Event* event, int player_a_action,
int player_b_action) {
resetKeys(event);
switch (player_a_action) {
case PLAYER_A_NOOP:
break;
case PLAYER_A_FIRE:
event->set(Event::JoystickZeroFire, 1);
break;
case PLAYER_A_UP:
event->set(Event::JoystickZeroUp, 1);
break;
case PLAYER_A_RIGHT:
event->set(Event::JoystickZeroRight, 1);
break;
case PLAYER_A_LEFT:
event->set(Event::JoystickZeroLeft, 1);
break;
case PLAYER_A_DOWN:
event->set(Event::JoystickZeroDown, 1);
break;
case PLAYER_A_UPRIGHT:
event->set(Event::JoystickZeroUp, 1);
event->set(Event::JoystickZeroRight, 1);
break;
case PLAYER_A_UPLEFT:
event->set(Event::JoystickZeroUp, 1);
event->set(Event::JoystickZeroLeft, 1);
break;
case PLAYER_A_DOWNRIGHT:
event->set(Event::JoystickZeroDown, 1);
event->set(Event::JoystickZeroRight, 1);
break;
case PLAYER_A_DOWNLEFT:
event->set(Event::JoystickZeroDown, 1);
event->set(Event::JoystickZeroLeft, 1);
break;
case PLAYER_A_UPFIRE:
event->set(Event::JoystickZeroUp, 1);
event->set(Event::JoystickZeroFire, 1);
break;
case PLAYER_A_RIGHTFIRE:
event->set(Event::JoystickZeroRight, 1);
event->set(Event::JoystickZeroFire, 1);
break;
case PLAYER_A_LEFTFIRE:
event->set(Event::JoystickZeroLeft, 1);
event->set(Event::JoystickZeroFire, 1);
break;
case PLAYER_A_DOWNFIRE:
event->set(Event::JoystickZeroDown, 1);
event->set(Event::JoystickZeroFire, 1);
break;
case PLAYER_A_UPRIGHTFIRE:
event->set(Event::JoystickZeroUp, 1);
event->set(Event::JoystickZeroRight, 1);
event->set(Event::JoystickZeroFire, 1);
break;
case PLAYER_A_UPLEFTFIRE:
event->set(Event::JoystickZeroUp, 1);
event->set(Event::JoystickZeroLeft, 1);
event->set(Event::JoystickZeroFire, 1);
break;
case PLAYER_A_DOWNRIGHTFIRE:
event->set(Event::JoystickZeroDown, 1);
event->set(Event::JoystickZeroRight, 1);
event->set(Event::JoystickZeroFire, 1);
break;
case PLAYER_A_DOWNLEFTFIRE:
event->set(Event::JoystickZeroDown, 1);
event->set(Event::JoystickZeroLeft, 1);
event->set(Event::JoystickZeroFire, 1);
break;
case RESET:
event->set(Event::ConsoleReset, 1);
break;
default:
ale::Logger::Error << "Invalid Player A Action: " << player_a_action;
exit(-1);
}
switch (player_b_action) {
case PLAYER_B_NOOP:
break;
case PLAYER_B_FIRE:
event->set(Event::JoystickOneFire, 1);
break;
case PLAYER_B_UP:
event->set(Event::JoystickOneUp, 1);
break;
case PLAYER_B_RIGHT:
event->set(Event::JoystickOneRight, 1);
break;
case PLAYER_B_LEFT:
event->set(Event::JoystickOneLeft, 1);
break;
case PLAYER_B_DOWN:
event->set(Event::JoystickOneDown, 1);
break;
case PLAYER_B_UPRIGHT:
event->set(Event::JoystickOneUp, 1);
event->set(Event::JoystickOneRight, 1);
break;
case PLAYER_B_UPLEFT:
event->set(Event::JoystickOneUp, 1);
event->set(Event::JoystickOneLeft, 1);
break;
case PLAYER_B_DOWNRIGHT:
event->set(Event::JoystickOneDown, 1);
event->set(Event::JoystickOneRight, 1);
break;
case PLAYER_B_DOWNLEFT:
event->set(Event::JoystickOneDown, 1);
event->set(Event::JoystickOneLeft, 1);
break;
case PLAYER_B_UPFIRE:
event->set(Event::JoystickOneUp, 1);
event->set(Event::JoystickOneFire, 1);
break;
case PLAYER_B_RIGHTFIRE:
event->set(Event::JoystickOneRight, 1);
event->set(Event::JoystickOneFire, 1);
break;
case PLAYER_B_LEFTFIRE:
event->set(Event::JoystickOneLeft, 1);
event->set(Event::JoystickOneFire, 1);
break;
case PLAYER_B_DOWNFIRE:
event->set(Event::JoystickOneDown, 1);
event->set(Event::JoystickOneFire, 1);
break;
case PLAYER_B_UPRIGHTFIRE:
event->set(Event::JoystickOneUp, 1);
event->set(Event::JoystickOneRight, 1);
event->set(Event::JoystickOneFire, 1);
break;
case PLAYER_B_UPLEFTFIRE:
event->set(Event::JoystickOneUp, 1);
event->set(Event::JoystickOneLeft, 1);
event->set(Event::JoystickOneFire, 1);
break;
case PLAYER_B_DOWNRIGHTFIRE:
event->set(Event::JoystickOneDown, 1);
event->set(Event::JoystickOneRight, 1);
event->set(Event::JoystickOneFire, 1);
break;
case PLAYER_B_DOWNLEFTFIRE:
event->set(Event::JoystickOneDown, 1);
event->set(Event::JoystickOneLeft, 1);
event->set(Event::JoystickOneFire, 1);
break;
case RESET:
event->set(Event::ConsoleReset, 1);
ale::Logger::Info << "Sending Reset..." << std::endl;
break;
default:
ale::Logger::Error << "Invalid Player B Action: " << player_b_action
<< std::endl;
exit(-1);
}
}
void ALEState::resetKeys(Event* event) {
event->set(Event::ConsoleReset, 0);
event->set(Event::ConsoleSelect, 0);
event->set(Event::JoystickZeroFire, 0);
event->set(Event::JoystickZeroUp, 0);
event->set(Event::JoystickZeroDown, 0);
event->set(Event::JoystickZeroRight, 0);
event->set(Event::JoystickZeroLeft, 0);
event->set(Event::JoystickOneFire, 0);
event->set(Event::JoystickOneUp, 0);
event->set(Event::JoystickOneDown, 0);
event->set(Event::JoystickOneRight, 0);
event->set(Event::JoystickOneLeft, 0);
event->set(Event::PaddleZeroFire, 0);
event->set(Event::PaddleOneFire, 0);
setDifficultySwitches(event, m_difficulty);
}
bool ALEState::equals(ALEState& rhs) {
return (rhs.m_serialized_state == this->m_serialized_state &&
rhs.m_left_paddle == this->m_left_paddle &&
rhs.m_right_paddle == this->m_right_paddle &&
rhs.m_frame_number == this->m_frame_number &&
rhs.m_episode_frame_number == this->m_episode_frame_number &&
rhs.m_mode == this->m_mode && rhs.m_difficulty == this->m_difficulty);
}
}