编程kata是一种练习,可以帮助程序员通过练习和重复练习来磨练自己的技能。
本文是“ 通过Katas进行Java教程 ”系列的一部分。
本文假定读者已经具有Java的经验,熟悉单元测试的基础知识,并且知道如何从他最喜欢的IDE(我是IntelliJ IDEA )运行它们。
下面显示证明解决方案正确的测试。 解决此问题的推荐方法是使用测试驱动的开发方法(编写第一个测试的实现,确认它通过并转到下一个测试)。 一旦所有测试通过,就可以认为解决了问题。 有关最佳做法的更多信息,请阅读“ 测试驱动开发(TDD):使用Java范例的最佳做法” 。
测试下方提供了一种可能的解决方案。 尝试先自己解决kata。
火星漫游者
开发一个可在网格上移动漫游车的API。
规则:
- 您将获得流动站的初始起点(x,y)及其面向的方向(N,S,E,W)。
- 流动站接收命令的字符数组。
- 实施使漫游车前进/后退(f,b)的命令。
- 实现使流动站左/右(l,r)旋转的命令。
- 实现从网格的一个边缘到另一边缘的环绕。 (行星毕竟是球体)
- 每次移动到新的广场之前,请执行障碍检测。 如果给定的命令序列遇到障碍物,则流动站将移动到最后一个可能的点并报告障碍物。
测验
以下是一组可用于以TDD方式解决此问题的单元测试。
package com.technologyconversations.kata.marsrover;import org.junit.Before;
import org.junit.Test;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;import static org.assertj.core.api.Assertions.*;/*
Source: http://dallashackclub.com/roverDevelop an api that moves a rover around on a grid.
* You are given the initial starting point (x,y) of a rover and the direction (N,S,E,W) it is facing.
* - The rover receives a character array of commands.
* - Implement commands that move the rover forward/backward (f,b).
* - Implement commands that turn the rover left/right (l,r).
* - Implement wrapping from one edge of the grid to another. (planets are spheres after all)
* - Implement obstacle detection before each move to a new square.
* If a given sequence of commands encounters an obstacle, the rover moves up to the last possible point and reports the obstacle.
*/
public class RoverSpec {private Rover rover;private Coordinates roverCoordinates;private final Direction direction = Direction.NORTH;private Point x;private Point y;private List<Obstacle> obstacles;@Beforepublic void beforeRoverTest() {x = new Point(1, 9);y = new Point(2, 9);obstacles = new ArrayList<Obstacle>();roverCoordinates = new Coordinates(x, y, direction, obstacles);rover = new Rover(roverCoordinates);}@Testpublic void newInstanceShouldSetRoverCoordinatesAndDirection() {assertThat(rover.getCoordinates()).isEqualToComparingFieldByField(roverCoordinates);}@Testpublic void receiveSingleCommandShouldMoveForwardWhenCommandIsF() throws Exception {int expected = y.getLocation() + 1;rover.receiveSingleCommand('F');assertThat(rover.getCoordinates().getY().getLocation()).isEqualTo(expected);}@Testpublic void receiveSingleCommandShouldMoveBackwardWhenCommandIsB() throws Exception {int expected = y.getLocation() - 1;rover.receiveSingleCommand('B');assertThat(rover.getCoordinates().getY().getLocation()).isEqualTo(expected);}@Testpublic void receiveSingleCommandShouldTurnLeftWhenCommandIsL() throws Exception {rover.receiveSingleCommand('L');assertThat(rover.getCoordinates().getDirection()).isEqualTo(Direction.WEST);}@Testpublic void receiveSingleCommandShouldTurnRightWhenCommandIsR() throws Exception {rover.receiveSingleCommand('R');assertThat(rover.getCoordinates().getDirection()).isEqualTo(Direction.EAST);}@Testpublic void receiveSingleCommandShouldIgnoreCase() throws Exception {rover.receiveSingleCommand('r');assertThat(rover.getCoordinates().getDirection()).isEqualTo(Direction.EAST);}@Test(expected = Exception.class)public void receiveSingleCommandShouldThrowExceptionWhenCommandIsUnknown() throws Exception {rover.receiveSingleCommand('X');}@Testpublic void receiveCommandsShouldBeAbleToReceiveMultipleCommands() throws Exception {int expected = x.getLocation() + 1;rover.receiveCommands("RFR");assertThat(rover.getCoordinates().getX().getLocation()).isEqualTo(expected);assertThat(rover.getCoordinates().getDirection()).isEqualTo(Direction.SOUTH);}@Testpublic void receiveCommandShouldWhatFromOneEdgeOfTheGridToAnother() throws Exception {int expected = x.getMaxLocation() + x.getLocation() - 2;rover.receiveCommands("LFFF");assertThat(rover.getCoordinates().getX().getLocation()).isEqualTo(expected);}@Testpublic void receiveCommandsShouldStopWhenObstacleIsFound() throws Exception {int expected = x.getLocation() + 1;rover.getCoordinates().setObstacles(Arrays.asList(new Obstacle(expected + 1, y.getLocation())));rover.getCoordinates().setDirection(Direction.EAST);rover.receiveCommands("FFFRF");assertThat(rover.getCoordinates().getX().getLocation()).isEqualTo(expected);assertThat(rover.getCoordinates().getDirection()).isEqualTo(Direction.EAST);}@Testpublic void positionShouldReturnXYAndDirection() throws Exception {rover.receiveCommands("LFFFRFF");assertThat(rover.getPosition()).isEqualTo("8 X 4 N");}@Testpublic void positionShouldReturnNokWhenObstacleIsFound() throws Exception {rover.getCoordinates().setObstacles(Arrays.asList(new Obstacle(x.getLocation() + 1, y.getLocation())));rover.getCoordinates().setDirection(Direction.EAST);rover.receiveCommands("F");assertThat(rover.getPosition()).endsWith(" NOK");}}
以下是一种可能的解决方案。
package com.technologyconversations.kata.marsrover;/*
Method receiveCommands should be used to transmit commands to the rover.*/
public class Rover {private Coordinates coordinates;public void setCoordinates(Coordinates value) {coordinates = value;}public Coordinates getCoordinates() {return coordinates;}public Rover(Coordinates coordinatesValue) {setCoordinates(coordinatesValue);}public void receiveCommands(String commands) throws Exception {for (char command : commands.toCharArray()) {if (!receiveSingleCommand(command)) {break;}}}public boolean receiveSingleCommand(char command) throws Exception {switch(Character.toUpperCase(command)) {case 'F':return getCoordinates().moveForward();case 'B':return getCoordinates().moveBackward();case 'L':getCoordinates().changeDirectionLeft();return true;case 'R':getCoordinates().changeDirectionRight();return true;default:throw new Exception("Command " + command + " is unknown.");}}public String getPosition() {return getCoordinates().toString();}}
完整源代码位于GitHub存储库[https://github.com/vfarcic/mars-rover-kata-java)中。 上面的代码仅表示主类的代码。 还有其他几个类/对象及其相应的规范。 除了测试和实现之外,存储库还包括build.gradle,可用于下载AssertJ依赖项并运行测试README.md包含有关如何设置项目的简短说明。
您有什么解决方案? 将其发布为评论,以便我们可以比较解决此kata的不同方法。
翻译自: https://www.javacodegeeks.com/2014/10/java-tutorial-through-katas-mars-rover.html