<commit_before>package org.drooms.impl.logic;

import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.codehaus.plexus.classworlds.strategy.Strategy;
import org.drools.core.time.SessionPseudoClock;
import org.drooms.api.Move;
import org.drooms.api.Node;
import org.drooms.api.Player;
import org.drooms.api.Playground;
import org.drooms.impl.logic.events.CollectibleAdditionEvent;
import org.drooms.impl.logic.events.CollectibleRemovalEvent;
import org.drooms.impl.logic.events.CollectibleRewardEvent;
import org.drooms.impl.logic.events.PlayerDeathEvent;
import org.drooms.impl.logic.events.PlayerMoveEvent;
import org.drooms.impl.logic.events.SurvivalRewardEvent;
import org.drooms.impl.logic.facts.CurrentPlayer;
import org.drooms.impl.logic.facts.CurrentTurn;
import org.drooms.impl.logic.facts.GameProperty;
import org.drooms.impl.logic.facts.Wall;
import org.drooms.impl.logic.facts.Worm;
import org.drooms.impl.util.DroomsKnowledgeSessionValidator;
import org.drooms.impl.util.GameProperties;
import org.kie.api.logger.KieRuntimeLogger;
import org.kie.api.runtime.Channel;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.EntryPoint;
import org.kie.api.runtime.rule.FactHandle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Represents a {@link Player}'s {@link Strategy} in action. This class holds
 * and maintains Drools engine's state for each particular player.
 * 
 * <p>
 * When asked (see {@link #decideNextMove()}), the strategy should make a decision on the next move, based on the
 * current state of the working memory. This decision should be sent over the provided 'decision' channel. If not sent,
 * it will default to STAY. See {@link Move} for the various types of decisions.
 * </p>
 * <p>
 * This class enforces the following requirements on the strategies:
 * </p>
 * 
 * <ul>
 * <li>'gameEvents' entry point must be declared, where the events not directly related to player actions will be sent.
 * These events are {@link CollectibleAdditionEvent} and {@link CollectibleRemovalEvent}.</li>
 * <li>'playerEvents' entry point must be declared, where the player-caused events will be sent. These events are
 * {@link PlayerMoveEvent} and {@link PlayerDeathEvent}.</li>
 * <li>'rewardEvents' entry point must be declared, where the reward events will be sent. These events are
 * {@link CollectibleRewardEvent} and {@link SurvivalRewardEvent}.</li>
 * </ul>
 * 
 * <p>
 * This class provides the following Drools globals, if declared in the strategy:
 * </p>
 * 
 * <ul>
 * <li>'logger' implementation of the {@link Logger} interface, to use for logging from within the rules.</li>
 * <li>'tracker' instance of the {@link PathTracker}, to facilitate path-finding in the rules.</li>
 * </ul>
 * 
 * <p>
 * Your strategies can be validated for all these - just make your tests extend {@link DroomsTestHelper}.
 * </p>
 * 
 * <p>
 * The working memory will contain instances of the various helper fact types:
 * </p>
 * 
 * <ul>
 * <li>{@link GameProperty}, many. Will never change or be removed.</li>
 * <li>{@link CurrentPlayer}, once. Will never change or be removed.</li>
 * <li>{@link CurrentTurn}, once. Will change with every turn.</li>
 * <li>{@link Wall}, many. Will remain constant over the whole game.</li>
 * <li>{@link Worm}, many. Will be added and removed as the worms will move, but never modified.</li>
 * </ul>
 * 
 */
public class DecisionMaker implements Channel {

    private static final Logger LOGGER = LoggerFactory.getLogger(DecisionMaker.class);

    private static void setGlobal(final KieSession session, final String global, final Object value) {
        try {
            session.setGlobal(global, value);
        } catch (final RuntimeException ex) {
            // do nothing, since the user has already been notified
        }
    }

    private final FactHandle currentTurn;
    private final EntryPoint gameEvents, playerEvents, rewardEvents;
    private final Map<Player, Map<Node, FactHandle>> handles = new HashMap<Player, Map<Node, FactHandle>>();
    private final boolean isDisposed = false;
    private Move latestDecision = null;
    private final Player player;
    private final KieSession session;

    private final KieRuntimeLogger sessionAudit;

    public DecisionMaker(final Player p, final PathTracker tracker, final GameProperties properties,
            final File reportFolder) {
        this.player = p;
        this.session = p.constructKieBase().newKieSession();
        // validate session
        final DroomsKnowledgeSessionValidator validator = new DroomsKnowledgeSessionValidator(this.session);
        if (!validator.isValid()) {
            throw new IllegalStateException("Player " + this.player.getName() + " has a malformed strategy: "
                    + validator.getErrors().get(0));
        }
        if (!validator.isClean()) {
            for (final String message : validator.getWarnings()) {
                DecisionMaker.LOGGER.info("Player {} has an incomplete strategy: {}", this.player.getName(), message);
            }
        }
        // FIXME figure out how to audit kie session
        DecisionMaker.LOGGER.info("Auditing the Drools session is disabled.");
        this.sessionAudit = null;
        // this is where we listen for decisions
        this.session.registerChannel("decision", this);
        // this is where we will send events from the game
        this.rewardEvents = this.session.getEntryPoint("rewardEvents");<commit_msg>Set PSEUDO clock to all Player's sessios<commit_after>package org.drooms.impl.logic;

import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.codehaus.plexus.classworlds.strategy.Strategy;
import org.drools.core.time.SessionPseudoClock;
import org.drooms.api.Move;
import org.drooms.api.Node;
import org.drooms.api.Player;
import org.drooms.api.Playground;
import org.drooms.impl.logic.events.CollectibleAdditionEvent;
import org.drooms.impl.logic.events.CollectibleRemovalEvent;
import org.drooms.impl.logic.events.CollectibleRewardEvent;
import org.drooms.impl.logic.events.PlayerDeathEvent;
import org.drooms.impl.logic.events.PlayerMoveEvent;
import org.drooms.impl.logic.events.SurvivalRewardEvent;
import org.drooms.impl.logic.facts.CurrentPlayer;
import org.drooms.impl.logic.facts.CurrentTurn;
import org.drooms.impl.logic.facts.GameProperty;
import org.drooms.impl.logic.facts.Wall;
import org.drooms.impl.logic.facts.Worm;
import org.drooms.impl.util.DroomsKnowledgeSessionValidator;
import org.drooms.impl.util.GameProperties;
import org.kie.api.KieServices;
import org.kie.api.logger.KieRuntimeLogger;
import org.kie.api.runtime.Channel;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.runtime.conf.ClockTypeOption;
import org.kie.api.runtime.rule.EntryPoint;
import org.kie.api.runtime.rule.FactHandle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Represents a {@link Player}'s {@link Strategy} in action. This class holds
 * and maintains Drools engine's state for each particular player.
 * 
 * <p>
 * When asked (see {@link #decideNextMove()}), the strategy should make a decision on the next move, based on the
 * current state of the working memory. This decision should be sent over the provided 'decision' channel. If not sent,
 * it will default to STAY. See {@link Move} for the various types of decisions.
 * </p>
 * <p>
 * This class enforces the following requirements on the strategies:
 * </p>
 * 
 * <ul>
 * <li>'gameEvents' entry point must be declared, where the events not directly related to player actions will be sent.
 * These events are {@link CollectibleAdditionEvent} and {@link CollectibleRemovalEvent}.</li>
 * <li>'playerEvents' entry point must be declared, where the player-caused events will be sent. These events are
 * {@link PlayerMoveEvent} and {@link PlayerDeathEvent}.</li>
 * <li>'rewardEvents' entry point must be declared, where the reward events will be sent. These events are
 * {@link CollectibleRewardEvent} and {@link SurvivalRewardEvent}.</li>
 * </ul>
 * 
 * <p>
 * This class provides the following Drools globals, if declared in the strategy:
 * </p>
 * 
 * <ul>
 * <li>'logger' implementation of the {@link Logger} interface, to use for logging from within the rules.</li>
 * <li>'tracker' instance of the {@link PathTracker}, to facilitate path-finding in the rules.</li>
 * </ul>
 * 
 * <p>
 * Your strategies can be validated for all these - just make your tests extend {@link DroomsTestHelper}.
 * </p>
 * 
 * <p>
 * The working memory will contain instances of the various helper fact types:
 * </p>
 * 
 * <ul>
 * <li>{@link GameProperty}, many. Will never change or be removed.</li>
 * <li>{@link CurrentPlayer}, once. Will never change or be removed.</li>
 * <li>{@link CurrentTurn}, once. Will change with every turn.</li>
 * <li>{@link Wall}, many. Will remain constant over the whole game.</li>
 * <li>{@link Worm}, many. Will be added and removed as the worms will move, but never modified.</li>
 * </ul>
 * 
 */
public class DecisionMaker implements Channel {

    private static final Logger LOGGER = LoggerFactory.getLogger(DecisionMaker.class);

    private static void setGlobal(final KieSession session, final String global, final Object value) {
        try {
            session.setGlobal(global, value);
        } catch (final RuntimeException ex) {
            // do nothing, since the user has already been notified
        }
    }

    private final FactHandle currentTurn;
    private final EntryPoint gameEvents, playerEvents, rewardEvents;
    private final Map<Player, Map<Node, FactHandle>> handles = new HashMap<Player, Map<Node, FactHandle>>();
    private final boolean isDisposed = false;
    private Move latestDecision = null;
    private final Player player;
    private final KieSession session;

    private final KieRuntimeLogger sessionAudit;

    public DecisionMaker(final Player p, final PathTracker tracker, final GameProperties properties,
            final File reportFolder) {
        this.player = p;
        KieSessionConfiguration config = KieServices.Factory.get().newKieSessionConfiguration();
        config.setOption(ClockTypeOption.get("pseudo"));
        this.session = p.constructKieBase().newKieSession(config, null);
        // validate session
        final DroomsKnowledgeSessionValidator validator = new DroomsKnowledgeSessionValidator(this.session);
        if (!validator.isValid()) {
            throw new IllegalStateException("Player " + this.player.getName() + " has a malformed strategy: "
                    + validator.getErrors().get(0));
        }
        if (!validator.isClean()) {
            for (final String message : validator.getWarnings()) {
                DecisionMaker.LOGGER.info("Player {} has an incomplete strategy: {}", this.player.getName(), message);
            }
        }
        // FIXME figure out how to audit kie session
        DecisionMaker.LOGGER.info("Auditing the Drools session is disabled.");
        this.sessionAudit = null;
        // this is where we listen for decisions
        this.session.registerChannel("decision", this);
        // this is where we will send events from the game
        this.rewardEvents = this.session.getEntryPoint("rewardEvents");
{'fraction_non_alphanumeric': 0.10682054842068726, 'fraction_numerical': 0.0005206525511975009, 'mean_word_length': 3.8020833333333335, 'pattern_counts': {'":': 0, '<': 83, '<?xml version=': 0, '>': 83, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6745140', 'n_tokens_mistral': 3317, 'n_tokens_neox': 3218, 'n_words': 1044}