diff --git a/robotgame/logic/rollingstone.py b/robotgame/logic/rollingstone.py new file mode 100644 index 0000000..487a048 --- /dev/null +++ b/robotgame/logic/rollingstone.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python + +# This file is part of ROBOTGAME +# +# ROBOTGAME is free software: you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# ROBOTGAME 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# ROBOTGAME. If not, see . +# +# ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' +# +# rollingstone.py +# -------------------- +# date created : Tue Aug 7 2012 +# copyright : (C) 2012 Niels G. W. Serup +# maintained by : Niels G. W. Serup + +"""Logic for rolling.""" + +from __future__ import print_function + +class RollingStoneError(Exception): + pass + +class Field(object): + def next_posdir(self): + raise NotImplementedError + +class Start(Field): + def __init__(self, direction): + self.direction = direction + + def next_posdir(self, pos, direc): + return self.direction.next_pos(pos), self.direction + +class Turn(Field): + def __init__(self, direction): + self.direction = direction + + def next_posdir(self, pos, direc): + return self.direction.next_pos(pos), self.direction + +class Goal(Field): + def next_posdir(self, pos, direc): + return pos, direc + +class Stone(Field): + def next_posdir(self, pos, direc): + return pos, direc + + +def step(playfield, pos, direc): + field = _at(playfield, pos) + if field is not None: + return field.next_posdir(pos, direc) + return direc.next_pos(pos), direc + +def reaches_goal(playfield, max_steps): + pos = _find_start(playfield) + direc = None + for i in range(max_steps): + pos, direc = step(playfield, pos, direc) + if isGoal(playfield, pos): + return True + if isStone(playfield, pos): + return False + return False + +def _find_start(playfield): + for y in range(len(playfield)): + for x in range(len(playfield[y])): + if isStart(playfield, (x, y)): + return (x, y) + raise RollingStoneError("Missing Start field") + +def _at(playfield, pos): + x, y = pos + return playfield[y][x] + +_is = lambda t: lambda playfield, pos: isinstance(_at(playfield, pos), t) + +(isGoal, isTurn, isStart, isStone) = (_is(Goal), _is(Turn), _is(Start), _is(Stone)) diff --git a/tests/rollingstone_tests.py b/tests/rollingstone_tests.py new file mode 100644 index 0000000..e728447 --- /dev/null +++ b/tests/rollingstone_tests.py @@ -0,0 +1,27 @@ + +import unittest +from robotgame.logic.rollingstone import * +from robotgame.logic.direction import * + + +playfield_example_succeed = [ + [Start(Down), None, None, None ], + [None, None, Stone(), None ], + [Turn(Right), None, Turn(Down), None ], + [None, Stone(), Turn(Right), Goal()], + ] + +playfield_example_fail = [ + [Start(Down), None, None, None ], + [None, None, Stone(), None ], + [Turn(Right), Stone(), Turn(Down), None ], + [None, None, Turn(Right), Goal()], + ] + +class RollingStoneTest(unittest.TestCase): + def test_playfield(self): + self.assertTrue(reaches_goal(playfield_example_succeed, 100)) + self.assertFalse(reaches_goal(playfield_example_fail, 100)) + +if __name__ == '__main__': + unittest.main()