/* * The Ants simulator * * BRAIN */ namespace Nemerle.Ants { using System; using System.IO; using Nemerle.Assertions; using Nemerle.Utility; using Nemerle.Collections; public variant Condition { | Friend /* cell contains an ant of the same color */ | Foe /* cell contains an ant of the other color */ | FriendWithFood /* cell contains an ant of the same color carrying food */ | FoeWithFood /* cell contains an ant of the other color carrying food */ | Food /* cell contains food (not being carried by an ant) */ | Rock /* cell is rocky */ | Marker { marker : Nemerle.Ants.Marker; } /* cell is marked with a marker of this ant's color */ | FoeMarker /* cell is marked with *some* marker of the other color */ | Home /* cell belongs to this ant's anthill */ | FoeHome /* cell belongs to the other anthill */ } public type State = int; public variant Instruction { | Sense { sense_dir : SenseDirection; on_success : State; on_failure : State; cond : Condition; } | Mark { marker : Marker; next_state : State; } | Unmark { marker : Marker; next_state : State; } | PickUp { on_success : State; on_failure : State; } | Drop { next_state : State; } | Turn { left_or_right : LeftOrRight; next_state : State; } | Move { on_success : State; on_failure : State; } | Flip { dice : int; on_zero : State; on_not_zero : State; } } public class Brain { public this (brain_file_name : string) { m_instructions_count = 0; try { m_brain_stream = StreamReader (brain_file_name); create_brain (); read_brain () } catch { | e => assert (false, "Brain: failed to load the brain file: " + e.Message) } } /* -- PUBLIC METHODS --------------------------------------------------- */ /** * Returns an instruction that has to be executed at a state */ [Requires (state >= 0 && state < m_instructions_count)] public GetInstruction (state : State) : Instruction { m_instructions [state] } /* -- PRIVATE METHODS -------------------------------------------------- */ /// creates the instructions array private create_brain () : void { m_instructions = array (10000) } /// reads the instructions from the brain file private read_brain () : void { read_brain_instruction (0) } /// reads a brain instruction private read_brain_instruction (index : int) : void { match (get_next_line ()) { | Some (line) when line.Length > 0 => def comment_index = line.IndexOf (';'); def line = if (comment_index != -1) line.Substring (0, comment_index) else line; def instruction = parse_instruction (NString.Split (line, array [' ', '\t'])); ++m_instructions_count; m_instructions [index] = instruction; read_brain_instruction (index + 1) | _ => () } } /// parses a brain instruction private parse_instruction (tokens : list [string]) : Instruction { def head = List.Head (tokens); def tail = List.Tail (tokens); def parse_sense_dir (sense_dir : string) : SenseDirection { | "here" | "Here" => SenseDirection.Here () | "ahead" | "Ahead" => SenseDirection.Ahead () | "leftahead" | "LeftAhead" => SenseDirection.LeftAhead () | "rightahead" | "RightAhead" => SenseDirection.RightAhead () | _ => assert (false, "Brain: invalid sense direction token: '" + sense_dir + "'"); }; def parse_int (some_string : string) : int { Int32.Parse (some_string) }; def parse_marker (marker : string) : Marker { Int32.Parse (marker) }; def parse_state (state : string) : State { Int32.Parse (state) }; def parse_condition (condition : string) : Condition { | "Friend" => Condition.Friend () | "Foe" => Condition.Foe () | "FriendWithFood" => Condition.FriendWithFood () | "FoeWithFood" => Condition.FoeWithFood () | "Food" => Condition.Food () | "Rock" => Condition.Rock () | "FoeMarker" => Condition.FoeMarker () | "Home" => Condition.Home () | "FoeHome" => Condition.FoeHome () | _ => assert (false, "Brain: invalid condition token: '" + condition + "'"); }; def parse_turn (turn : string) : LeftOrRight { | "Left" => LeftOrRight.Left () | "Right" => LeftOrRight.Right () | _ => assert (false, "Brain: invalid turn token: '" + turn + "'"); }; match (head) { | "Sense" => match (tail) { | [sense_dir, on_success, on_failure, condition] => Instruction.Sense (parse_sense_dir (sense_dir), parse_state (on_success), parse_state (on_failure), parse_condition (condition)) | [sense_dir, on_success, on_failure, "Marker", marker] => Instruction.Sense (parse_sense_dir (sense_dir), parse_state (on_success), parse_state (on_failure), Condition.Marker (parse_marker (marker))) | _ => assert (false, "Brain: failed to parse the '" + head + "' instruction"); } | "Mark" => match (tail) { | [marker, next_state] => Instruction.Mark (parse_marker (marker), parse_state (next_state)) | _ => assert (false, "Brain: failed to parse the '" + head + "' instruction"); } | "Unmark" => match (tail) { | [marker, next_state] => Instruction.Unmark (parse_marker (marker), parse_state (next_state)) | _ => assert (false, "Brain: failed to parse the '" + head + "' instruction"); } | "PickUp" => match (tail) { | [on_success, on_failure] => Instruction.PickUp (parse_state (on_success), parse_state (on_failure)) | _ => assert (false, "Brain: failed to parse the '" + head + "' instruction"); } | "Drop" => match (tail) { | [next_state] => Instruction.Drop (parse_state (next_state)) | _ => assert (false, "Brain: failed to parse the '" + head + "' instruction"); } | "Turn" => match (tail) { | [turn, next_state] => Instruction.Turn (parse_turn (turn), parse_state (next_state)) | _ => assert (false, "Brain: failed to parse the '" + head + "' instruction"); } | "Move" => match (tail) { | [on_success, on_failure] => Instruction.Move (parse_state (on_success), parse_state (on_failure)) | _ => assert (false, "Brain: failed to parse the '" + head + "' instruction"); } | "Flip" => match (tail) { | [dice, on_zero, on_not_zero] => Instruction.Flip (parse_int (dice), parse_state (on_zero), parse_state (on_not_zero)) | _ => assert (false, "Brain: failed to parse the '" + head + "' instruction"); } | _ => assert (false, "Brain: invalid instruction token: '" + head + "'"); } } /// reads a line from the input file private get_next_line () : option [string] { def line = m_brain_stream.ReadLine (); if (line != null) Some (line) else None () } /* -- PRIVATE FIELDS --------------------------------------------------- */ private mutable m_instructions : array [Instruction]; private mutable m_instructions_count : int; private m_brain_stream : StreamReader; } } /*** END OF FILE ***/