diff --git a/pom.xml b/pom.xml index 6fe719e..9733dfb 100644 --- a/pom.xml +++ b/pom.xml @@ -113,7 +113,7 @@ io.github.nergal-perm java-decita - 0.5.1 + 0.7.0-RC com.renomad diff --git a/src/main/java/ru/ewc/checklogic/Computation.java b/src/main/java/ru/ewc/checklogic/Computation.java index 17ad395..47d0469 100644 --- a/src/main/java/ru/ewc/checklogic/Computation.java +++ b/src/main/java/ru/ewc/checklogic/Computation.java @@ -27,14 +27,7 @@ import java.net.URI; import java.util.HashMap; import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; -import ru.ewc.commands.CommandsFacade; import ru.ewc.decisions.api.ComputationContext; -import ru.ewc.decisions.api.DecitaException; -import ru.ewc.decisions.api.DecitaFacade; -import ru.ewc.decisions.api.Locator; -import ru.ewc.decisions.api.Locators; /** * I am a unique instance of a decision table computation. @@ -44,35 +37,12 @@ @SuppressWarnings("PMD.ProhibitPublicStaticMethods") public final class Computation { /** - * Facade for making all the decisions. + * The context of the computation. */ - private final DecitaFacade decisions; + private final ComputationContext context; - /** - * Facade for executing all the commands. - */ - private final CommandsFacade commands; - - /** - * The current state of the system. - */ - private final Locators state; - - /** - * Ctor. - * - * @param decisions An instance of {@link DecitaFacade} to make decisions. - * @param commands An instance of {@link CommandsFacade} to execute commands. - * @param locators An instance of {@link Locators} to store the state. - */ - public Computation( - final DecitaFacade decisions, - final CommandsFacade commands, - final Locators locators - ) { - this.decisions = decisions; - this.commands = commands; - this.state = locators; + public Computation(final ComputationContext context) { + this.context = context; } /** @@ -91,70 +61,19 @@ public static URI uriFrom(final String path) { return URI.create(result.toString()); } - /** - * Computes the decision for a specified table. - * - * @param table Name of the tables to make a decision against. - * @param locators The locators to use for the decision. - * @return The collection of outcomes from the specified table. - * @throws DecitaException If the table could not be found or computed. - */ - public Map decideFor(final String table, final Locators locators) - throws DecitaException { - return this.decisions.decisionFor(table, this.state.mergedWith(locators)); - } - - public Map decideFor(final String table) throws DecitaException { - return this.decisions.decisionFor(table, this.state); - } - - public void perform(final Transition command) { - this.commands.perform(command.name(), this.state.mergedWith(command.request())); - } - - public boolean hasStateFor(final String table) { - return this.state.hasLocator(table); + public void perform(final String command) { + this.context.perform(command); } public Map stateFor(final String table, final Map entities) { - final Locator locator = this.state.locatorFor(table); - final ComputationContext context = new ComputationContext(this.state); final Map actual = HashMap.newHashMap(entities.size()); for (final String fragment : entities.keySet()) { - actual.put(fragment, locator.fragmentBy(fragment, context)); + actual.put(fragment, this.context.valueFor(table, fragment)); } return actual; } - public Computation withState(final Map> incoming) { - return new Computation(this.decisions, this.commands, stateFrom(incoming)); - } - public Map> storedState() { - return this.state.state(); - } - - /** - * Loads the state from the specified {@code InputStream}. - * - * @param stream InputStream containing state info. - * @return Collection of {@link Locator} objects, containing desired state. - */ - private static Locators stateFrom(final Map> stream) { - return new Locators( - stream - .entrySet() - .stream() - .collect(Collectors.toMap(Map.Entry::getKey, entryToLocator())) - ); - } - - /** - * Converts a {@link Map.Entry} to a {@link Locator} object. - * - * @return A function that converts a {@link Map.Entry} to a {@link Locator} object. - */ - private static Function>, Locator> entryToLocator() { - return e -> new InMemoryStorage(e.getValue()); + return this.context.state(); } } diff --git a/src/main/java/ru/ewc/checklogic/FileUtils.java b/src/main/java/ru/ewc/checklogic/FileUtils.java new file mode 100644 index 0000000..0e7dfc6 --- /dev/null +++ b/src/main/java/ru/ewc/checklogic/FileUtils.java @@ -0,0 +1,127 @@ +/* + * MIT License + * + * Copyright (c) 2024 Decision-Driven Development + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package ru.ewc.checklogic; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.stream.Stream; +import lombok.SneakyThrows; +import org.yaml.snakeyaml.Yaml; + +/** + * I am a utility class that provides methods for file operations. + * + * @since 0.3.0 + */ +public final class FileUtils { + /** + * Primary hidden constructor. + */ + private FileUtils() { + // Utility class + } + + static InputStream applicationConfig(final String root) throws IOException { + return Files.newInputStream(Path.of(root, "application.yaml")); + } + + /** + * Gets the path to a folder with specified resources. + * + * @param resource Resource name to get its folder. + * @return Path to a resource folder as a String. + */ + static String getFinalPathTo(final String resource) { + final String states; + if (System.getProperties().containsKey("sources")) { + states = String.format("%s/%s", System.getProperty("sources"), resource); + } else if (System.getProperties().containsKey(resource)) { + states = System.getProperty(resource); + } else { + states = String.format( + "%s%s%s", + System.getProperty("user.dir"), + "/src/test/resources/", + resource + ); + } + return states; + } + + @SneakyThrows + static Stream readFileNames() { + return Files.walk(Paths.get(Computation.uriFrom(getFinalPathTo("states")))) + .filter(Files::isRegularFile) + .map( + path -> path.toFile().getAbsolutePath() + ).map( + path -> { + final InputStream stream; + try { + stream = Files.newInputStream(Paths.get(path)); + } catch (final IOException exception) { + throw new IllegalStateException(exception); + } + return FileUtils.createTestData(path, stream); + }); + } + + @SuppressWarnings("unchecked") + private static LogicChecker.TestData createTestData( + final String path, + final InputStream stream + ) { + final Iterator iterator = new Yaml().loadAll(stream).iterator(); + iterator.next(); + final String command; + if (iterator.hasNext()) { + command = FileUtils.extractCommand(iterator.next()); + } else { + command = ""; + } + Map> expectations = new HashMap<>(); + if (iterator.hasNext()) { + expectations = (Map>) iterator.next(); + } + return new LogicChecker.TestData(path, command, expectations); + } + + @SuppressWarnings("unchecked") + private static String extractCommand(final Object next) { + final Map map = (Map) next; + final String command; + if (map == null) { + command = ""; + } else { + command = map.getOrDefault("command", ""); + } + return command; + } +} diff --git a/src/main/java/ru/ewc/checklogic/LogicChecker.java b/src/main/java/ru/ewc/checklogic/LogicChecker.java index c9f4402..4614a55 100644 --- a/src/main/java/ru/ewc/checklogic/LogicChecker.java +++ b/src/main/java/ru/ewc/checklogic/LogicChecker.java @@ -29,23 +29,19 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.Stream; import lombok.SneakyThrows; -import org.assertj.core.api.Assertions; import org.assertj.core.api.SoftAssertions; import org.yaml.snakeyaml.Yaml; import ru.ewc.checklogic.server.WebServer; -import ru.ewc.commands.CommandsFacade; -import ru.ewc.decisions.api.DecitaFacade; -import ru.ewc.decisions.api.Locators; +import ru.ewc.decisions.api.ComputationContext; +import ru.ewc.decisions.api.Locator; +import ru.ewc.state.State; /** * End-to-end tests based on yaml descriptions. @@ -59,85 +55,51 @@ public final class LogicChecker { */ private static final Logger LOGGER = Logger.getLogger(LogicChecker.class.getName()); - /** - * The template for the assertion message. - */ - private static final String AV_TEMPLATE = "Command '%s'[%d] should be available"; - private LogicChecker() { // Utility class } - public static void main(final String[] args) { + public static void main(final String[] args) throws IOException { if (args.length == 0) { throw new IllegalArgumentException("Please provide the path to the resources"); } final String root = args[0]; - final DecitaFacade decisions = new DecitaFacade( - Path.of(root, "tables").toUri(), - ".csv", - ";" - ); - final Computation computation = new Computation( - decisions, - new CommandsFacade(Path.of(root, "commands").toUri(), decisions), - stateFromAppConfig(Path.of(root, "application.yaml").toFile()) - ); if (args.length > 1 && "server".equals(args[1])) { - new WebServer(computation).start(); + final ComputationContext context = new ComputationContext( + stateFromAppConfig(FileUtils.applicationConfig(root)), + Path.of(root, "tables").toUri(), + Path.of(root, "commands").toUri() + ); + new WebServer(new Computation(context)).start(); } else { System.setProperty("sources", root); - readFileNames().forEach(test -> performTest(test, new SoftAssertions(), computation)); + final SoftAssertions softly = new SoftAssertions(); + FileUtils.readFileNames().forEach(test -> performTest(test, softly, root)); } } - @SneakyThrows - static Stream readFileNames() { - return Files.walk(Paths.get(Computation.uriFrom(getFinalPathTo("states")))) - .filter(Files::isRegularFile) - .map( - path -> path.toFile().getAbsolutePath() - ).map( - path -> { - final InputStream stream; - try { - stream = Files.newInputStream(Paths.get(path)); - } catch (final IOException exception) { - throw new IllegalStateException(exception); - } - return createTestData(path, stream); - }); - } - @SneakyThrows static void performTest( final TestData test, final SoftAssertions softly, - final Computation initial + final String root ) { - final Computation target = initial.withState( - stateFromFile(Files.newInputStream(new File(test.file()).toPath())) + final Computation target = new Computation( + new ComputationContext( + stateFromFile(Files.newInputStream(new File(test.file()).toPath()), root), + Path.of(FileUtils.getFinalPathTo("tables")).toUri(), + Path.of(FileUtils.getFinalPathTo("commands")).toUri() + ) ); try { - for (int idx = 0; idx < test.commands.size(); idx += 1) { - final Transition command = test.commands.get(idx); - Assertions.assertThat(target.decideFor(command.name(), command.request())) - .describedAs(String.format(LogicChecker.AV_TEMPLATE, command.name(), idx + 1)) - .containsEntry("available", "true"); - target.perform(command); + if (!test.command.isEmpty()) { + target.perform(test.command); } - for (final String table : test.expectations.keySet()) { - if (target.hasStateFor(table)) { - softly - .assertThat(target.stateFor(table, test.expectations.get(table))) - .describedAs(String.format("State for entity '%s'", table)) - .containsExactlyInAnyOrderEntriesOf(test.expectations.get(table)); - } else { - softly - .assertThat(target.decideFor(table)) - .describedAs(String.format("Table '%s'", table)) - .isEqualTo(test.expectations.get(table)); - } + for (final String locator : test.expectations.keySet()) { + softly + .assertThat(target.stateFor(locator, test.expectations.get(locator))) + .describedAs(String.format("State for entity '%s'", locator)) + .containsExactlyInAnyOrderEntriesOf(test.expectations.get(locator)); } softly.assertAll(); LOGGER.info("Running test for %s... done".formatted(test.toString())); @@ -149,10 +111,10 @@ static void performTest( @SneakyThrows @SuppressWarnings("unchecked") - private static Locators stateFromAppConfig(final File file) { - final Map config = new Yaml().load(Files.newInputStream(file.toPath())); + private static State stateFromAppConfig(final InputStream file) { + final Map config = new Yaml().load(file); final Stream names = ((List) config.get("locators")).stream(); - return new Locators( + return new State( names.collect( Collectors.toMap( name -> name, @@ -163,80 +125,31 @@ private static Locators stateFromAppConfig(final File file) { } @SuppressWarnings("unchecked") - private static Map> stateFromFile(final InputStream stream) { - return (Map>) new Yaml().loadAll(stream).iterator().next(); - } - - @SuppressWarnings("unchecked") - private static TestData createTestData(final String path, final InputStream stream) { - final Iterator iterator = new Yaml().loadAll(stream).iterator(); - iterator.next(); - List commands = new ArrayList<>(1); - if (iterator.hasNext()) { - commands = extractCommands(iterator.next()); - } - Map> expectations = new HashMap<>(); - if (iterator.hasNext()) { - expectations = (Map>) iterator.next(); - } - return new TestData(path, commands, expectations); - } - - @SuppressWarnings("unchecked") - private static List extractCommands(final Object next) { - final Map> commands = (Map>) next; - return commands.getOrDefault("commands", List.of()) - .stream() - .map(entry -> transitionFrom((Map) entry)) - .toList(); - } - - @SuppressWarnings("unchecked") - private static Transition transitionFrom(final Map entry) { - return new Transition( - (String) entry.get("name"), - requestLocator((Map) entry.get("request")) - ); - } - - private static Locators requestLocator(final Map entry) { - return new Locators(Map.of("request", new InMemoryStorage(entry))); - } - - /** - * Gets the path to a folder with specified resources. - * - * @param resource Resource name to get its folder. - * @return Path to a resource folder as a String. - */ - private static String getFinalPathTo(final String resource) { - final String states; - if (System.getProperties().containsKey("sources")) { - states = String.format("%s/%s", System.getProperty("sources"), resource); - } else if (System.getProperties().containsKey(resource)) { - states = System.getProperty(resource); - } else { - states = String.format( - "%s%s%s", - System.getProperty("user.dir"), - "/src/test/resources/", - resource - ); - } - return states; + private static State stateFromFile( + final InputStream stream, + final String root + ) throws IOException { + final Map config = new Yaml().load(FileUtils.applicationConfig(root)); + final List names = (List) config.get("locators"); + final Map locators = HashMap.newHashMap(names.size()); + names.forEach(name -> locators.put(name, new InMemoryStorage(new HashMap<>()))); + final Map> raw = + (Map>) new Yaml().loadAll(stream).iterator().next(); + raw.keySet().forEach(name -> locators.put(name, new InMemoryStorage(raw.get(name)))); + return new State(locators); } /** * I am the helper class containing the data for parameterized state tests. * * @param file The path to the file containing state and expectations. - * @param commands The collection of commands to execute before the decision. + * @param command The name of the command to execute before the decision. * @param expectations The collection of expected decision table results. * @since 0.2.3 */ public record TestData( String file, - List commands, + String command, Map> expectations) { @Override diff --git a/src/main/java/ru/ewc/checklogic/Transition.java b/src/main/java/ru/ewc/checklogic/Transition.java deleted file mode 100644 index aa41239..0000000 --- a/src/main/java/ru/ewc/checklogic/Transition.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2024 Decision-Driven Development - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package ru.ewc.checklogic; - -import ru.ewc.decisions.api.Locators; - -/** - * The Transition class represents a transition in a decision-making process. - * Each transition has a name and a request, represented by a Locators object. - * - * @param name The name of the command that triggers the transition. - * @param request The request data that is needed for the transition. - * - * @since 0.3.0 - */ -public record Transition(String name, Locators request) { -} diff --git a/src/main/java/ru/ewc/checklogic/server/CommandPage.java b/src/main/java/ru/ewc/checklogic/server/CommandPage.java index b02fb7d..c677bfc 100644 --- a/src/main/java/ru/ewc/checklogic/server/CommandPage.java +++ b/src/main/java/ru/ewc/checklogic/server/CommandPage.java @@ -29,8 +29,6 @@ import com.renomad.minum.web.WebFramework; import java.util.Map; import ru.ewc.checklogic.Computation; -import ru.ewc.checklogic.Transition; -import ru.ewc.decisions.api.Locators; /** * I am a configuration object for all the command-related endpoints. @@ -68,7 +66,7 @@ public void register(final WebFramework web) { public Response executeCommand(final Request request) { final String command = request.body().asString("command"); - this.computation.perform(new Transition(command, new Locators(Map.of()))); + this.computation.perform(command); return Response.htmlOk("OK", Map.of("HX-Redirect", "/")); } diff --git a/src/test/resources/tic-tac-toe/states/00-initialize.yaml b/src/test/resources/tic-tac-toe/states/00-initialize.yaml index b94b6f8..ebb65b8 100644 --- a/src/test/resources/tic-tac-toe/states/00-initialize.yaml +++ b/src/test/resources/tic-tac-toe/states/00-initialize.yaml @@ -1,8 +1,6 @@ request: {} --- -commands: - - name: "initialize" - request: {} +command: "initialize" --- table: currentPlayer: "X" diff --git a/src/test/resources/tic-tac-toe/states/01-first-O-move.yaml b/src/test/resources/tic-tac-toe/states/01-first-O-move.yaml index 1fbab6c..cb213df 100644 --- a/src/test/resources/tic-tac-toe/states/01-first-O-move.yaml +++ b/src/test/resources/tic-tac-toe/states/01-first-O-move.yaml @@ -14,7 +14,6 @@ cells: C2: "empty" C3: "empty" --- -commands: [] --- computed_move: available: "false" diff --git a/src/test/resources/tic-tac-toe/states/01-first-X-move.yaml b/src/test/resources/tic-tac-toe/states/01-first-X-move.yaml index 12f6dda..2cb44de 100644 --- a/src/test/resources/tic-tac-toe/states/01-first-X-move.yaml +++ b/src/test/resources/tic-tac-toe/states/01-first-X-move.yaml @@ -1,3 +1,6 @@ +request: + player: "X" + move: "A1" table: nextPlayer: "O" currentPlayer: "X" @@ -12,13 +15,7 @@ cells: C2: "empty" C3: "empty" --- -commands: - - name: "initialize" - request: {} - - name: "computed_move" - request: - player: "X" - move: "A1" +command: "computed_move" --- game_state: is_over: "false" diff --git a/src/test/resources/tic-tac-toe/states/02-second-O-move-occupied.yaml b/src/test/resources/tic-tac-toe/states/02-second-O-move-occupied.yaml index 5b07bf4..436b7b1 100644 --- a/src/test/resources/tic-tac-toe/states/02-second-O-move-occupied.yaml +++ b/src/test/resources/tic-tac-toe/states/02-second-O-move-occupied.yaml @@ -14,7 +14,7 @@ cells: C2: "empty" C3: "empty" --- -commands: [] +command: "" --- computed_move: available: "false" \ No newline at end of file diff --git a/src/test/resources/tic-tac-toe/states/03-O-wins-A-row.yaml b/src/test/resources/tic-tac-toe/states/03-O-wins-A-row.yaml index b797829..47205a4 100644 --- a/src/test/resources/tic-tac-toe/states/03-O-wins-A-row.yaml +++ b/src/test/resources/tic-tac-toe/states/03-O-wins-A-row.yaml @@ -14,7 +14,7 @@ cells: C2: "empty" C3: "empty" --- -commands: [] +command: "" --- computed_move: available: "false" diff --git a/src/test/resources/tic-tac-toe/states/03-O-wins-B-row.yaml b/src/test/resources/tic-tac-toe/states/03-O-wins-B-row.yaml index 186f3df..58d3a8d 100644 --- a/src/test/resources/tic-tac-toe/states/03-O-wins-B-row.yaml +++ b/src/test/resources/tic-tac-toe/states/03-O-wins-B-row.yaml @@ -14,7 +14,7 @@ cells: C2: "empty" C3: "empty" --- -commands: [] +command: "" --- computed_move: available: "false" diff --git a/src/test/resources/tic-tac-toe/states/03-O-wins-C-row.yaml b/src/test/resources/tic-tac-toe/states/03-O-wins-C-row.yaml index 6bb8e38..5f3ad67 100644 --- a/src/test/resources/tic-tac-toe/states/03-O-wins-C-row.yaml +++ b/src/test/resources/tic-tac-toe/states/03-O-wins-C-row.yaml @@ -14,7 +14,7 @@ cells: C2: "O" C3: "O" --- -commands: [] +command: "" --- computed_move: available: "false" diff --git a/src/test/resources/tic-tac-toe/states/03-O-wins-asc-diagonal.yaml b/src/test/resources/tic-tac-toe/states/03-O-wins-asc-diagonal.yaml index 895b6a0..9a9cf20 100644 --- a/src/test/resources/tic-tac-toe/states/03-O-wins-asc-diagonal.yaml +++ b/src/test/resources/tic-tac-toe/states/03-O-wins-asc-diagonal.yaml @@ -14,7 +14,7 @@ cells: C2: "empty" C3: "empty" --- -commands: [] +command: "" --- computed_move: available: "false" diff --git a/src/test/resources/tic-tac-toe/states/03-X-wins-1-column.yaml b/src/test/resources/tic-tac-toe/states/03-X-wins-1-column.yaml index 3a59cd5..8e7efd4 100644 --- a/src/test/resources/tic-tac-toe/states/03-X-wins-1-column.yaml +++ b/src/test/resources/tic-tac-toe/states/03-X-wins-1-column.yaml @@ -14,7 +14,7 @@ cells: C2: "empty" C3: "empty" --- -commands: [] +command: "" --- computed_move: available: "false" diff --git a/src/test/resources/tic-tac-toe/states/03-X-wins-2-column.yaml b/src/test/resources/tic-tac-toe/states/03-X-wins-2-column.yaml index 0876fc1..56c2e12 100644 --- a/src/test/resources/tic-tac-toe/states/03-X-wins-2-column.yaml +++ b/src/test/resources/tic-tac-toe/states/03-X-wins-2-column.yaml @@ -14,7 +14,7 @@ cells: C2: "X" C3: "empty" --- -commands: [] +command: "" --- computed_move: available: "false" diff --git a/src/test/resources/tic-tac-toe/states/03-X-wins-3-column.yaml b/src/test/resources/tic-tac-toe/states/03-X-wins-3-column.yaml index 75ce33b..d4c4d23 100644 --- a/src/test/resources/tic-tac-toe/states/03-X-wins-3-column.yaml +++ b/src/test/resources/tic-tac-toe/states/03-X-wins-3-column.yaml @@ -1,3 +1,6 @@ +request: + player: "X" + move: "C3" table: currentPlayer: "X" cells: @@ -11,11 +14,7 @@ cells: C2: "empty" C3: "empty" --- -commands: - - name: "computed_move" - request: - player: "X" - move: "C3" +command: "computed_move" --- game_state: is_over: "true" diff --git a/src/test/resources/tic-tac-toe/states/03-X-wins-desc-diagonal.yaml b/src/test/resources/tic-tac-toe/states/03-X-wins-desc-diagonal.yaml index 5edc47d..ad11787 100644 --- a/src/test/resources/tic-tac-toe/states/03-X-wins-desc-diagonal.yaml +++ b/src/test/resources/tic-tac-toe/states/03-X-wins-desc-diagonal.yaml @@ -14,7 +14,7 @@ cells: C2: "empty" C3: "X" --- -commands: [] +command: "" --- computed_move: available: "false" diff --git a/src/test/resources/tic-tac-toe/states/04-whole-game.yaml b/src/test/resources/tic-tac-toe/states/04-whole-game.yaml deleted file mode 100644 index 2b140a7..0000000 --- a/src/test/resources/tic-tac-toe/states/04-whole-game.yaml +++ /dev/null @@ -1,39 +0,0 @@ -table: - nextPlayer: "O" - currentPlayer: "X" -cells: - A1: "empty" - A2: "empty" - A3: "empty" - B1: "empty" - B2: "empty" - B3: "empty" - C1: "empty" - C2: "empty" - C3: "empty" ---- -commands: - - name: "computed_move" - request: - player: "X" - move: "A1" - - name: "computed_move" - request: - player: "O" - move: "A2" - - name: "computed_move" - request: - player: "X" - move: "B1" - - name: "computed_move" - request: - player: "O" - move: "B2" - - name: "computed_move" - request: - player: "X" - move: "C1" ---- -game_state: - is_over: "true" - winner: "X" \ No newline at end of file