Пример #1
0
        // apply a rule group, return true if there was any change
        // loop until no further changes
        bool ApplyRuleGroup(RuleGroup group)
        {
            Logger.WriteLine(4, "ApplyRuleGroup {0} {1}", _rulestate, group);

            // skip this group -- it failed rigid previously
            if (_disabledgrouplookup.Contains(group))
            {
                return(false);
            }

            var groupchange = false;

            // Apply a single match chosen at random
            if (group.IsRandom)
            {
                var matches = _rulestate.FindMatches(group);
                if (matches.Count > 0)
                {
                    var n         = _rng.Next(matches.Count);
                    var randmatch = new List <RuleMatch> {
                        matches[n]
                    };
                    _rulestate.DoActions(group, randmatch);
                    _rulestate.DoCommands(group, randmatch);
                    groupchange = true;
                }

                // Find all matches and do all actions for all the rules in the group
                // loop until no more changes, return true if there were any
            }
            else
            {
                for (var retry = 0; ; ++retry)
                {
                    if (retry > 200)
                    {
                        throw Error.Fatal("too many rule group retries: <{0}>", group);
                    }
                    var matches    = _rulestate.FindMatches(group);
                    var rulechange = _rulestate.DoActions(group, matches);
                    groupchange |= rulechange;
                    if (retry == 0) // just the first time
                    {
                        _rulestate.DoCommands(group, matches);
                    }
                    if (!rulechange || group.IsFinal)
                    {
                        break;
                    }
                }
            }
            Logger.WriteLine(4, "[ARG {0}]", groupchange);
            return(groupchange);
        }
Пример #2
0
        // carry out commands for this rulegroup
        internal void DoCommands(RuleGroup rulegroup, IList <RuleMatch> matches)
        {
            var rules = matches.Select(m => m.rule).Distinct();

            Logger.WriteLine(4, "Do commands {0} #{1}", rulegroup.Id, rules.Count());
            foreach (var rule in rules)
            {
                if (!rule.CommandCode.IsEmpty)
                {
                    _evaluator.Exec(rule.CommandCode, this);
                    CommandCounter++;
                }
            }
        }
Пример #3
0
        // find all the matches for the rules in a group
        internal IList <RuleMatch> FindMatches(RuleGroup rulegroup)
        {
            Logger.WriteLine(3, "Find matches group {0} #{1}", rulegroup.Id, rulegroup.Rules.Count);

            var matches = new List <RuleMatch>();

            // find all possible matches for each rule
            foreach (var rule in rulegroup.Rules)
            {
                _vm_trail = new Trail();
                _evaluator.Exec(rule.PatternCode, this);
                matches.AddRange(_vm_trail.GetMatches(rule));
            }
            Logger.WriteLine(3, "[FM found {0}]", matches.Count);
            return(matches);
        }
Пример #4
0
        // move an object at location in a direction
        // direction None used to cancel existing movement
        internal void MoveObject(int obj, int cellindex, Direction direction, RuleGroup rulegroup)
        {
            if (!(GameDef.MoveDirections.Contains(direction) || direction == Direction.Stationary))
            {
                throw Error.Assert("move {0}", direction);
            }
            // only move an object if it's here, else add a new mover
            if (_level[cellindex, _gamedef.GetLayer(obj)] == obj)
            {
                var found = false;

                // first try to update move list
                // do not use rule group in comparison -- if rigid, this may cause a problem
                for (var movex = 0; movex < _movers.Count; ++movex)
                {
                    var mover = _movers[movex];
                    if (mover.ObjectId == obj && mover.CellIndex == cellindex)
                    {
                        found = true;
                        if (_movers[movex].Direction != direction)
                        {
                            Logger.WriteLine(2, "Mover now {0} to {1} at {2}", direction, _gamedef.ShowName(obj), cellindex);
                            if (direction == Direction.Stationary)
                            {
                                _movers.RemoveAt(movex);
                            }
                            else
                            {
                                _movers[movex].Direction = direction;
                            }
                            //_vm_moved = true;    // TODO: only for net change
                        }
                        break;
                    }
                }
                // otherwise add a new mover
                if (!found && direction != Direction.Stationary)
                {
                    Logger.WriteLine(2, "Mover set {0} to {1} at {2}", direction, _gamedef.ShowName(obj), cellindex);
                    _movers.Add(Mover.Create(obj, cellindex, _gamedef.GetLayer(obj), direction, rulegroup));
                    //_vm_moved = true;    // TODO: only for net change
                }
            }
        }
Пример #5
0
        // carry out the actions for this set of matches
        // return true if anything actually was changed
        internal bool DoActions(RuleGroup rulegroup, IList <RuleMatch> matches)
        {
            Logger.WriteLine(4, "Do actions {0} #{1}", rulegroup.Id, matches.Count);

            _rulegroup = rulegroup; // needed to track rigid

            // track net changes made by this entire rule group
            // note: cannot use object map because of unstable order
            var objiter = matches.SelectMany(m => m.path.SelectMany(p => _levelstate.GetObjects(p)));
            var objinit = objiter.ToList();
            var moviter = _levelstate.GetMovers();
            var movinit = moviter.ToList();

            //_vm_moved = false;
            foreach (var match in matches)
            {
                var rule = match.rule;
                // do action if any
                if (!rule.ActionCode.IsEmpty)
                {
                    // check per individual rule to get good verbose logging
                    // note the need to flatten in order to compare objects as ints

                    _vm_matchpath = match.path;
                    _refobjects   = match.refs;
                    _vm_pathindex = 0;
                    _model.VerboseLog("Matched rule {0} {1}", rule.RuleId, rule.RuleDirection);
                    _evaluator.Exec(rule.ActionCode, this);
                    ActionCounter++;
                }
            }
            // could optimise this with _vm_moved?
            var changed = !objinit.SequenceEqual(objiter) || !movinit.SequenceEqual(moviter);

            Logger.WriteLine(4, "[DA {0}]", changed);
            return(changed);
        }
Пример #6
0
 // create a mover, which may target an illegal location
 static internal Mover Create(int obj, int cellindex, int layer, Direction dir, RuleGroup group = null, bool rigid = false)
 {
     if (!GameDef.MoveDirections.Contains(dir))
     {
         throw Error.Assert("create {0}", dir);
     }
     return(new Mover {
         ObjectId = obj,
         CellIndex = cellindex,
         Layer = layer,
         Direction = dir,
         RuleGroup = group,
     });
 }