Skip to content

Commit

Permalink
feat: Allow editing of problems and refactor IO utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
danielptv committed May 18, 2023
1 parent 6ade75d commit b41d6a6
Show file tree
Hide file tree
Showing 14 changed files with 617 additions and 265 deletions.
6 changes: 3 additions & 3 deletions src/main/java/com/danielptv/simplex/command/AppVersion.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.danielptv.simplex.command;

import com.danielptv.simplex.dev.Banner;
import com.danielptv.simplex.shell.ShellHelper;
import com.danielptv.simplex.shell.OutputHelper;
import lombok.RequiredArgsConstructor;
import org.springframework.shell.standard.ShellComponent;
import org.springframework.shell.standard.ShellMethod;
Expand All @@ -10,9 +10,9 @@
@RequiredArgsConstructor
@ShellComponent
public class AppVersion implements Version.Command {
private final ShellHelper shellHelper;
private final OutputHelper outputHelper;
@ShellMethod(key = {"version", "info"}, value = "Show version info.", group = "Built-In Commands")
public void version() {
shellHelper.print(Banner.TEXT);
outputHelper.print(Banner.TEXT);
}
}
73 changes: 73 additions & 0 deletions src/main/java/com/danielptv/simplex/command/HelperComponent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.danielptv.simplex.command;

import com.danielptv.simplex.shell.EditType;
import com.danielptv.simplex.shell.InputResult;
import com.danielptv.simplex.shell.SimplexInput;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.RequiredArgsConstructor;
import org.jline.terminal.Terminal;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.core.io.ResourceLoader;
import org.springframework.shell.component.SingleItemSelector;
import org.springframework.shell.component.support.SelectorItem;
import org.springframework.shell.standard.ShellComponent;
import org.springframework.shell.style.TemplateExecutor;

import java.util.Map;
import java.util.Optional;

@SuppressFBWarnings("EI_EXPOSE_REP2")
@ShellComponent
@RequiredArgsConstructor
public class HelperComponent {
private static final String EDIT_PROBLEM_TITLE = "Edit problem";
private static final Map<String, String> EDIT_PROBLEM_SELECTION = Map.of(
EditType.CONTINUE.toString(),
"Continue to calculation",
EditType.EDIT.toString(),
"Edit the linear problem"
);
private final Terminal terminal;
private final ResourceLoader resourceLoader;
private final ObjectProvider<TemplateExecutor> templateExecutorProvider;

public String singleSelector(final String name, final Map<String, String> data) {
final var items = data.entrySet().stream()
.map(entry -> SelectorItem.of(entry.getKey(), entry.getValue()))
.toList();
final var component = new SingleItemSelector<>(terminal,
items, name, null);
component.setResourceLoader(resourceLoader);
component.setTemplateExecutor(templateExecutorProvider.getObject());
final var context = component.run(SingleItemSelector.SingleItemSelectorContext.empty());
return context.getResultItem().flatMap(si -> Optional.ofNullable(si.getName())).orElse(null);
}

public EditType editProblem() {
final var result = singleSelector(EDIT_PROBLEM_TITLE, EDIT_PROBLEM_SELECTION);
return result.equals(EditType.CONTINUE.toString()) ? EditType.CONTINUE : EditType.EDIT;
}

public InputResult simplexInput(
final String name,
final int varCount,
final boolean isObjFunction,
final boolean minimize
) {
return simplexInput(name, varCount, isObjFunction, minimize, null);
}

public InputResult simplexInput(
final String name,
final int varCount,
final boolean isObjFunction,
final boolean minimize,
final InputResult defaultValue
) {
final var component = new SimplexInput(terminal, name, varCount, isObjFunction, minimize, defaultValue);
component.setResourceLoader(resourceLoader);
component.setTemplateExecutor(templateExecutorProvider.getObject());
final var context = component.run(SimplexInput.SimplexInputContext.empty());
return context.getResultValue();
}
}
75 changes: 64 additions & 11 deletions src/main/java/com/danielptv/simplex/command/Simplex.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import com.danielptv.simplex.service.TableCalcService;
import com.danielptv.simplex.service.TableExtensionService;
import com.danielptv.simplex.service.TwoPhaseSimplex;
import com.danielptv.simplex.shell.EditType;
import com.danielptv.simplex.shell.InputResult;
import com.danielptv.simplex.shell.OutputHelper;
import com.danielptv.simplex.shell.PromptColor;
import com.danielptv.simplex.shell.ShellHelper;
import com.danielptv.simplex.shell.SimplexIO;
import com.danielptv.simplex.shell.SimplexOutput;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Pattern;
Expand All @@ -21,6 +23,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

@ShellComponent
@RequiredArgsConstructor
Expand All @@ -30,8 +33,10 @@ public class Simplex {
private static final String ROUND_PATTERN = "^(false|\\d{1,2})$";
private static final int MIN_COUNT = 1;
private static final int MAX_COUNT = 10;
private final ShellHelper shellHelper;
private final SimplexIO simplexIO;
private final OutputHelper outputHelper;
private final SimplexOutput simplexOutput;

private final HelperComponent helperComponent;

@ShellMethod(key = {"calculate", "calc"}, value = "Calculate Simplex")
public void calc(
Expand All @@ -43,20 +48,68 @@ public void calc(
@Pattern(regexp = ROUND_PATTERN) final String roundMode,
@ShellOption(value = {"-m", "--min"}, help = MIN_HELP) final boolean minimize
) {
final var objectiveFunction = simplexIO.getObjectiveFunction(varCount);
final var constraints = simplexIO.getConstraints(varCount, constCount);
shellHelper.print(simplexIO.displayProblem(objectiveFunction, constraints, minimize)
.toString(), PromptColor.GREEN);
var objectiveFunction = helperComponent.simplexInput(
"Objective function:",
varCount,
true,
minimize
);
var constraints = IntStream.range(0, constCount)
.mapToObj(c -> helperComponent.simplexInput(String.format("Constraint %d:", c + 1),
varCount,
false,
minimize
))
.toList();
outputHelper.print(simplexOutput.displayProblem(objectiveFunction, constraints).toString(), PromptColor.GREEN);

var edit = helperComponent.editProblem();
while (!edit.equals(EditType.CONTINUE)) {
objectiveFunction = helperComponent.simplexInput(
"Objective function:",
varCount,
true,
minimize,
objectiveFunction
);
final var finalConstraints = constraints;
constraints = IntStream.range(0, constCount)
.mapToObj(c -> helperComponent.simplexInput(String.format("Constraint %d:", c + 1),
varCount,
false,
minimize,
finalConstraints.get(c)
))
.toList();
outputHelper.print(simplexOutput.displayProblem(objectiveFunction, constraints)
.toString(), PromptColor.GREEN);
edit = helperComponent.editProblem();
}

outputHelper.print(String.format("%n"));
final List<Phase<? extends CalculableImpl<?>>> phases;
if ("false".equals(roundMode)) {
final var number = new Fraction();
phases = executeSimplex(number, varCount, constCount, minimize, objectiveFunction, constraints);
phases = executeSimplex(
number,
varCount,
constCount,
minimize,
objectiveFunction.getValues(),
constraints.stream().map(InputResult::getValues).toList()
);
} else {
final var number = new RoundedDecimal(Integer.parseInt(roundMode));
phases = executeSimplex(number, varCount, constCount, minimize, objectiveFunction, constraints);
phases = executeSimplex(
number,
varCount,
constCount,
minimize,
objectiveFunction.getValues(),
constraints.stream().map(InputResult::getValues).toList()
);
}
shellHelper.print(simplexIO.printResult(phases).toString());
outputHelper.print(simplexOutput.printResult(phases).toString());
}

<T extends CalculableImpl<T>> List<Phase<? extends CalculableImpl<?>>> executeSimplex(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package com.danielptv.simplex.dev;

import com.danielptv.simplex.shell.InputReader;
import com.danielptv.simplex.shell.PromptColor;
import com.danielptv.simplex.shell.ShellHelper;
import org.jline.reader.LineReader;
import com.danielptv.simplex.shell.OutputHelper;
import org.jline.terminal.Terminal;
import org.jline.utils.AttributedString;
import org.jline.utils.AttributedStyle;
Expand All @@ -23,12 +21,7 @@ public final AttributedString getPrompt() {
}

@Bean
ShellHelper shellHelper(@Lazy final Terminal terminal) {
return new ShellHelper(terminal);
}

@Bean
InputReader inputReader(@Lazy final Terminal terminal, @Lazy final LineReader lineReader) {
return new InputReader(lineReader, new ShellHelper(terminal));
OutputHelper shellHelper(@Lazy final Terminal terminal) {
return new OutputHelper(terminal);
}
}
17 changes: 17 additions & 0 deletions src/main/java/com/danielptv/simplex/shell/EditType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.danielptv.simplex.shell;

public enum EditType {
EDIT("Edit"),
CONTINUE("Continue");
private final String value;

EditType(final String value) {
this.value = value;
}

@Override
public String toString() {
return value;
}

}
40 changes: 0 additions & 40 deletions src/main/java/com/danielptv/simplex/shell/InputReader.java

This file was deleted.

31 changes: 31 additions & 0 deletions src/main/java/com/danielptv/simplex/shell/InputResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.danielptv.simplex.shell;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@SuppressFBWarnings({"EI_EXPOSE_REP", "EI_EXPOSE_REP2"})
@AllArgsConstructor
@RequiredArgsConstructor
public final class InputResult implements Serializable {
@Getter
@Setter
private List<String> values = new ArrayList<>();
@Getter
@Setter
private String representation = "";
@Getter
@Setter
private String rawInput = "";

@Override
public String toString() {
return representation;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

@RequiredArgsConstructor
@SuppressFBWarnings("EI_EXPOSE_REP2")
public class ShellHelper {
public class OutputHelper {
@Value("${shell.out.info}")
private String infoColor;
@Value("${shell.out.success}")
Expand All @@ -25,11 +25,7 @@ public String getColored(final String message, final PromptColor color) {
.append(message, AttributedStyle.DEFAULT.foreground(color.toJlineAttributedStyle()))
.toAnsi();
}
public String getColoredBackground(final String message, final PromptColor color) {
return (new AttributedStringBuilder())
.append(message, AttributedStyle.DEFAULT.background(color.toJlineAttributedStyle()))
.toAnsi();
}

public String getInfoMessage(final String message) {
return getColored(message, PromptColor.valueOf(infoColor));
}
Expand Down
Loading

0 comments on commit b41d6a6

Please sign in to comment.