From 1c59b549fb7842e7443b4dccee50d31efb90540c Mon Sep 17 00:00:00 2001 From: p1gushka Date: Fri, 6 Feb 2026 23:35:21 +0300 Subject: [PATCH 01/12] added front rotation --- .../hse/java/practice/task1/RubiksCube.java | 146 +++++++++++++++++- 1 file changed, 144 insertions(+), 2 deletions(-) diff --git a/src/main/java/hse/java/practice/task1/RubiksCube.java b/src/main/java/hse/java/practice/task1/RubiksCube.java index 2091b657..2e8ca77e 100644 --- a/src/main/java/hse/java/practice/task1/RubiksCube.java +++ b/src/main/java/hse/java/practice/task1/RubiksCube.java @@ -6,7 +6,7 @@ * Необходимо реализовать интерфейс Cube * При повороте передней грани, меняются верх низ право и лево */ -public class RubiksCube { +public class RubiksCube implements Cube { private static final int EDGES_COUNT = 6; @@ -26,10 +26,152 @@ public RubiksCube() { } } + private CubeColor[][] copyParts(CubeColor[][] otherParts) { + CubeColor[][] parts = new CubeColor[3][3]; + for (int i = 0; i < 3; i++) { + System.arraycopy(otherParts[i], 0, parts[i], 0, 3); + } + return parts; + } + + private void rotateInnerClockwise(EdgePosition position) { + CubeColor[][] parts = edges[position.ordinal()].getParts(); + CubeColor[][] newParts = new CubeColor[3][3]; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + newParts[2 - j][i] = parts[i][j]; + } + } + + edges[4].setParts(newParts); + } + + @Override + public void up(RotateDirection direction) { + switch (direction) { + case CLOCKWISE -> { + rotateUpClockwise(); + } + case COUNTERCLOCKWISE -> { + rotateUpClockwise(); + rotateUpClockwise(); + rotateUpClockwise(); + } + } + } + + private void rotateUpClockwise() { + rotateInnerClockwise(EdgePosition.UP); + } + + @Override + public void down(RotateDirection direction) { + switch (direction) { + case CLOCKWISE -> { + rotateDownClockwise(); + } + case COUNTERCLOCKWISE -> { + rotateDownClockwise(); + rotateDownClockwise(); + rotateDownClockwise(); + } + } + + } + + private void rotateDownClockwise() { + rotateInnerClockwise(EdgePosition.DOWN); + } + + @Override + public void left(RotateDirection direction) { + switch (direction) { + case CLOCKWISE -> { + rotateLeftClockwise(); + } + case COUNTERCLOCKWISE -> { + rotateLeftClockwise(); + rotateLeftClockwise(); + rotateLeftClockwise(); + } + } + } + + private void rotateLeftClockwise() { + rotateInnerClockwise(EdgePosition.LEFT); + } + + @Override + public void right(RotateDirection direction) { + switch (direction) { + case CLOCKWISE -> { + rotateRightClockwise(); + } + case COUNTERCLOCKWISE -> { + rotateRightClockwise(); + rotateRightClockwise(); + rotateRightClockwise(); + } + } + } + + private void rotateRightClockwise() { + rotateInnerClockwise(EdgePosition.RIGHT); + } + public void front(RotateDirection direction) { + switch (direction) { + case CLOCKWISE -> { + rotateFrontClockwise(); + } + case COUNTERCLOCKWISE -> { + rotateFrontClockwise(); + rotateFrontClockwise(); + rotateFrontClockwise(); + } + } + } + private void rotateFrontClockwise() { + rotateInnerClockwise(EdgePosition.FRONT); + + CubeColor[][] upParts = edges[0].getParts(); + CubeColor[][] leftParts = edges[2].getParts(); + CubeColor[][] rightParts = edges[3].getParts(); + CubeColor[][] downParts = edges[1].getParts(); + + CubeColor[][] upPartsCopy = copyParts(upParts); + CubeColor[][] leftPartsCopy = copyParts(leftParts); + CubeColor[][] rightPartsCopy = copyParts(rightParts); + CubeColor[][] downPartsCopy = copyParts(downParts); + + for (int i = 0; i < 3; i++) { + upParts[2][i] = leftPartsCopy[i][2]; + rightParts[i][0] = upPartsCopy[2][i]; + downParts[0][i] = rightPartsCopy[i][0]; + leftParts[i][2] = downPartsCopy[0][i]; + } } - + + @Override + public void back(RotateDirection direction) { + switch (direction) { + case CLOCKWISE -> { + rotateBackClockwise(); + } + case COUNTERCLOCKWISE -> { + rotateBackClockwise(); + rotateBackClockwise(); + rotateBackClockwise(); + } + } + } + + private void rotateBackClockwise() { + rotateInnerClockwise(EdgePosition.BACK); + } + public Edge[] getEdges() { return edges; } From e941edbf43706b6995f24579dec505eda6e6003e Mon Sep 17 00:00:00 2001 From: p1gushka Date: Sat, 7 Feb 2026 01:01:02 +0300 Subject: [PATCH 02/12] added othersides rotation --- .../hse/java/practice/task1/RubiksCube.java | 89 ++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/src/main/java/hse/java/practice/task1/RubiksCube.java b/src/main/java/hse/java/practice/task1/RubiksCube.java index 2e8ca77e..2993a3c1 100644 --- a/src/main/java/hse/java/practice/task1/RubiksCube.java +++ b/src/main/java/hse/java/practice/task1/RubiksCube.java @@ -63,6 +63,23 @@ public void up(RotateDirection direction) { private void rotateUpClockwise() { rotateInnerClockwise(EdgePosition.UP); + + CubeColor[][] upParts = edges[5].getParts(); + CubeColor[][] leftParts = edges[2].getParts(); + CubeColor[][] rightParts = edges[3].getParts(); + CubeColor[][] downParts = edges[4].getParts(); + + CubeColor[][] upPartsCopy = copyParts(upParts); + CubeColor[][] leftPartsCopy = copyParts(leftParts); + CubeColor[][] rightPartsCopy = copyParts(rightParts); + CubeColor[][] downPartsCopy = copyParts(downParts); + + for (int i = 0; i < 3; i++) { + upParts[0][i] = leftPartsCopy[0][i]; + rightParts[0][i] = upPartsCopy[0][i]; + downParts[0][i] = rightPartsCopy[0][i]; + leftParts[0][i] = downPartsCopy[0][i]; + } } @Override @@ -82,6 +99,23 @@ public void down(RotateDirection direction) { private void rotateDownClockwise() { rotateInnerClockwise(EdgePosition.DOWN); + + CubeColor[][] upParts = edges[4].getParts(); + CubeColor[][] leftParts = edges[2].getParts(); + CubeColor[][] rightParts = edges[3].getParts(); + CubeColor[][] downParts = edges[5].getParts(); + + CubeColor[][] upPartsCopy = copyParts(upParts); + CubeColor[][] leftPartsCopy = copyParts(leftParts); + CubeColor[][] rightPartsCopy = copyParts(rightParts); + CubeColor[][] downPartsCopy = copyParts(downParts); + + for (int i = 0; i < 3; i++) { + upParts[2][i] = leftPartsCopy[2][i]; + rightParts[2][i] = upPartsCopy[2][i]; + downParts[2][i] = rightPartsCopy[2][i]; + leftParts[2][i] = downPartsCopy[2][i]; + } } @Override @@ -100,6 +134,23 @@ public void left(RotateDirection direction) { private void rotateLeftClockwise() { rotateInnerClockwise(EdgePosition.LEFT); + + CubeColor[][] upParts = edges[0].getParts(); + CubeColor[][] leftParts = edges[5].getParts(); + CubeColor[][] rightParts = edges[4].getParts(); + CubeColor[][] downParts = edges[1].getParts(); + + CubeColor[][] upPartsCopy = copyParts(upParts); + CubeColor[][] leftPartsCopy = copyParts(leftParts); + CubeColor[][] rightPartsCopy = copyParts(rightParts); + CubeColor[][] downPartsCopy = copyParts(downParts); + + for (int i = 0; i < 3; i++) { + upParts[i][0] = leftPartsCopy[2-i][2]; + rightParts[i][0] = upPartsCopy[i][0]; + downParts[i][0] = rightPartsCopy[i][0]; + leftParts[i][2] = downPartsCopy[0][2-i]; + } } @Override @@ -118,6 +169,23 @@ public void right(RotateDirection direction) { private void rotateRightClockwise() { rotateInnerClockwise(EdgePosition.RIGHT); + + CubeColor[][] upParts = edges[0].getParts(); + CubeColor[][] leftParts = edges[4].getParts(); + CubeColor[][] rightParts = edges[5].getParts(); + CubeColor[][] downParts = edges[1].getParts(); + + CubeColor[][] upPartsCopy = copyParts(upParts); + CubeColor[][] leftPartsCopy = copyParts(leftParts); + CubeColor[][] rightPartsCopy = copyParts(rightParts); + CubeColor[][] downPartsCopy = copyParts(downParts); + + for (int i = 0; i < 3; i++) { + upParts[i][2] = leftPartsCopy[i][2]; + rightParts[i][0] = upPartsCopy[2-i][2]; + downParts[i][2] = rightPartsCopy[2-i][0]; + leftParts[i][2] = downPartsCopy[i][2]; + } } public void front(RotateDirection direction) { @@ -147,9 +215,9 @@ private void rotateFrontClockwise() { CubeColor[][] downPartsCopy = copyParts(downParts); for (int i = 0; i < 3; i++) { - upParts[2][i] = leftPartsCopy[i][2]; + upParts[2][i] = leftPartsCopy[2-i][2]; rightParts[i][0] = upPartsCopy[2][i]; - downParts[0][i] = rightPartsCopy[i][0]; + downParts[0][i] = rightPartsCopy[2-i][0]; leftParts[i][2] = downPartsCopy[0][i]; } } @@ -170,6 +238,23 @@ public void back(RotateDirection direction) { private void rotateBackClockwise() { rotateInnerClockwise(EdgePosition.BACK); + + CubeColor[][] upParts = edges[0].getParts(); + CubeColor[][] leftParts = edges[3].getParts(); + CubeColor[][] rightParts = edges[2].getParts(); + CubeColor[][] downParts = edges[1].getParts(); + + CubeColor[][] upPartsCopy = copyParts(upParts); + CubeColor[][] leftPartsCopy = copyParts(leftParts); + CubeColor[][] rightPartsCopy = copyParts(rightParts); + CubeColor[][] downPartsCopy = copyParts(downParts); + + for (int i = 0; i < 3; i++) { + upParts[0][i] = leftPartsCopy[i][2]; + rightParts[i][0] = upPartsCopy[0][2-i]; + downParts[2][i] = rightPartsCopy[i][0]; + leftParts[i][2] = downPartsCopy[2][2-i]; + } } public Edge[] getEdges() { From 32fdbacda4f89b921b8566c4efa0312816a1c0d8 Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 7 Feb 2026 13:14:53 +0300 Subject: [PATCH 03/12] lecture 3 --- .../java/lectures/lecture3/examples/Box.java | 14 + .../lectures/lecture3/examples/Generics.java | 43 +++ .../java/lectures/lecture3/examples/Main.java | 18 ++ .../lectures/lecture3/examples/Methods.java | 10 + .../lecture3/examples/TryCatchThrows.java | 79 +++++ .../java/lectures/lecture3/tasks/atm/Atm.java | 19 +- .../hse/java/practice/task1/RubiksCube.java | 30 +- .../lectures/lecture3/tasks/atm/AtmTest.java | 38 +-- .../java/practice/task1/CubeSimpleTest.java | 277 ++++++++++++++++++ 9 files changed, 495 insertions(+), 33 deletions(-) create mode 100644 src/main/java/hse/java/lectures/lecture3/examples/Box.java create mode 100644 src/main/java/hse/java/lectures/lecture3/examples/Generics.java create mode 100644 src/main/java/hse/java/lectures/lecture3/examples/Main.java create mode 100644 src/main/java/hse/java/lectures/lecture3/examples/Methods.java create mode 100644 src/main/java/hse/java/lectures/lecture3/examples/TryCatchThrows.java create mode 100644 src/test/java/hse/java/practice/task1/CubeSimpleTest.java diff --git a/src/main/java/hse/java/lectures/lecture3/examples/Box.java b/src/main/java/hse/java/lectures/lecture3/examples/Box.java new file mode 100644 index 00000000..6c3ccf57 --- /dev/null +++ b/src/main/java/hse/java/lectures/lecture3/examples/Box.java @@ -0,0 +1,14 @@ +package hse.java.lectures.lecture3.examples; + +public class Box { + + private T item; + + public void put(T item) { + this.item = item; + } + + public T get() { + return item; + } +} diff --git a/src/main/java/hse/java/lectures/lecture3/examples/Generics.java b/src/main/java/hse/java/lectures/lecture3/examples/Generics.java new file mode 100644 index 00000000..4fe8a270 --- /dev/null +++ b/src/main/java/hse/java/lectures/lecture3/examples/Generics.java @@ -0,0 +1,43 @@ +package hse.java.lectures.lecture3.examples; + +import java.util.ArrayList; +import java.util.List; + +public class Generics { + + + + public T getType(T type) { + System.out.println(type.getClass()); + return type; + } + + public static void write(List list, T value) { + list.add(value); + } + + public static > T get(T value) { + return value; + } + + public static void testGenerics() { + // get(1.).compareTo() + write(List.of(1), 1); + write(List.of(), 1.2); + List ints = new ArrayList<>(); + ints.add(1); + ints.add(2); + // PECS + List nums = ints; + List si = ints; + si.add(1); + si.get(1); + } + + public static void main(String[] args) { + List il = new ArrayList<>(); + write(il, 5); + System.out.println(il); + } + +} diff --git a/src/main/java/hse/java/lectures/lecture3/examples/Main.java b/src/main/java/hse/java/lectures/lecture3/examples/Main.java new file mode 100644 index 00000000..d4279be4 --- /dev/null +++ b/src/main/java/hse/java/lectures/lecture3/examples/Main.java @@ -0,0 +1,18 @@ +package hse.java.lectures.lecture3.examples; + +import java.util.ArrayList; +import java.util.concurrent.Callable; + +public class Main { + public static void main(String[] args) { + Box box = new Box<>(); + Box dBox = new Box<>(); + Callable callable; + + int x = new Integer(3); + Integer y = 5; + + Box nBox = box; + new Methods().get(new ArrayList()).add(1); + } +} diff --git a/src/main/java/hse/java/lectures/lecture3/examples/Methods.java b/src/main/java/hse/java/lectures/lecture3/examples/Methods.java new file mode 100644 index 00000000..cac365d7 --- /dev/null +++ b/src/main/java/hse/java/lectures/lecture3/examples/Methods.java @@ -0,0 +1,10 @@ +package hse.java.lectures.lecture3.examples; + +public class Methods { + + + public T get(T type) { + return type; + } + +} diff --git a/src/main/java/hse/java/lectures/lecture3/examples/TryCatchThrows.java b/src/main/java/hse/java/lectures/lecture3/examples/TryCatchThrows.java new file mode 100644 index 00000000..0d972ac3 --- /dev/null +++ b/src/main/java/hse/java/lectures/lecture3/examples/TryCatchThrows.java @@ -0,0 +1,79 @@ +package hse.java.lectures.lecture3.examples; + +import java.io.*; + +public class TryCatchThrows { + + public void testRuntime() throws RuntimeException { + throw new RuntimeException("Test runtime"); + } + + public void testException() throws Exception { + throw new Exception("test exception"); + } + + public void testError() throws Error { + throw new Error("test error"); + } + + public void testTryRuntime() { + try { + testRuntime(); + } catch (RuntimeException e) { + System.out.println("Catch " + e.getMessage()); + } finally { + System.out.println("finally"); + } + } + + public void testTryException() { + try { + testException(); + } catch (Exception e) { + System.out.println("Catch " + e.getMessage()); + } finally { + System.out.println("finally"); + } + } + + public void testTryError() { + // testError(); + try { + testError(); + } catch (Error e) { + System.out.println("Catch " + e.getMessage()); + } finally { + System.out.println("finally"); + } + } + + public static void foo() { + throw new RuntimeException("My runtime"); + } + + public static void bar() throws Exception { + throw new Exception("My exception"); + } + + public static void main(String[] args) { + // foo(); +// try { +// bar(); +// } catch (Exception e) { +// System.err.println("Hello exception"); +// } finally { +// +// } + +// try (BufferedReader br = new BufferedReader(new FileReader(""))) { +// +// } catch (IOException e) { +// throw new RuntimeException(e); +// } + + // int x = 1/ 0; + int[] a = new int[1]; + System.out.println(a[2]); + } + +} diff --git a/src/main/java/hse/java/lectures/lecture3/tasks/atm/Atm.java b/src/main/java/hse/java/lectures/lecture3/tasks/atm/Atm.java index 3fa91909..08f551e4 100644 --- a/src/main/java/hse/java/lectures/lecture3/tasks/atm/Atm.java +++ b/src/main/java/hse/java/lectures/lecture3/tasks/atm/Atm.java @@ -1,14 +1,9 @@ package hse.java.lectures.lecture3.tasks.atm; -import java.util.Collections; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; +import java.util.*; public class Atm { - private enum Denomination { + public enum Denomination { D50(50), D100(100), D500(500), @@ -24,6 +19,12 @@ private enum Denomination { int value() { return value; } + + public static Denomination fromInt(int value) { + return Arrays.stream(values()).filter(v -> v.value == value) + .findFirst() + .orElse(null); + } } private final Map banknotes = new EnumMap<>(Denomination.class); @@ -31,9 +32,9 @@ int value() { public Atm() { } - public void deposit(Map banknotes){} + public void deposit(Map banknotes){} - public Map withdraw(int amount) { + public Map withdraw(int amount) { return Map.of(); } diff --git a/src/main/java/hse/java/practice/task1/RubiksCube.java b/src/main/java/hse/java/practice/task1/RubiksCube.java index 2091b657..d986f9f0 100644 --- a/src/main/java/hse/java/practice/task1/RubiksCube.java +++ b/src/main/java/hse/java/practice/task1/RubiksCube.java @@ -6,7 +6,7 @@ * Необходимо реализовать интерфейс Cube * При повороте передней грани, меняются верх низ право и лево */ -public class RubiksCube { +public class RubiksCube implements Cube { private static final int EDGES_COUNT = 6; @@ -26,10 +26,36 @@ public RubiksCube() { } } + @Override + public void up(RotateDirection direction) { + + } + + @Override + public void down(RotateDirection direction) { + + } + + @Override + public void left(RotateDirection direction) { + + } + + @Override + public void right(RotateDirection direction) { + + } + + @Override public void front(RotateDirection direction) { } - + + @Override + public void back(RotateDirection direction) { + + } + public Edge[] getEdges() { return edges; } diff --git a/src/test/java/hse/java/lectures/lecture3/tasks/atm/AtmTest.java b/src/test/java/hse/java/lectures/lecture3/tasks/atm/AtmTest.java index 9e3994a6..5e83fcae 100644 --- a/src/test/java/hse/java/lectures/lecture3/tasks/atm/AtmTest.java +++ b/src/test/java/hse/java/lectures/lecture3/tasks/atm/AtmTest.java @@ -15,6 +15,7 @@ import java.util.Map; import java.util.stream.Stream; +import static hse.java.lectures.lecture3.tasks.atm.Atm.Denomination.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -30,18 +31,11 @@ void initialBalanceIsZero() { @Test void depositIncreasesBalance() { Atm atm = new Atm(); - atm.deposit(Map.of(100, 10, 500, 5)); + atm.deposit(Map.of(D100, 10, D500, 5)); assertEquals(3500, atm.getBalance()); } - @Test - void depositRejectsInvalidDenominationAndKeepsState() { - Atm atm = new Atm(); - atm.deposit(Map.of(100, 1)); - assertThrows(InvalidDepositException.class, () -> atm.deposit(Map.of(30, 1))); - assertEquals(100, atm.getBalance()); - } - + @Test void depositRejectsNullMap() { Atm atm = new Atm(); @@ -51,8 +45,8 @@ void depositRejectsNullMap() { @Test void depositRejectsNonPositiveCountAndKeepsState() { Atm atm = new Atm(); - atm.deposit(Map.of(100, 1)); - assertThrows(InvalidDepositException.class, () -> atm.deposit(Map.of(100, 0))); + atm.deposit(Map.of(D100, 1)); + assertThrows(InvalidDepositException.class, () -> atm.deposit(Map.of(D100, 0))); assertEquals(100, atm.getBalance()); } @@ -60,11 +54,11 @@ void depositRejectsNonPositiveCountAndKeepsState() { void withdrawGreedyAndUpdatesBalance() { Atm atm = new Atm(); // 2000 - atm.deposit(Map.of(1000, 1, 500, 1, 100, 5)); + atm.deposit(Map.of(D1000, 1, D500, 1, D100, 5)); - Map result = atm.withdraw(1700); + Map result = atm.withdraw(1700); - assertEquals(Map.of(1000, 1, 500, 1, 100, 2), result); + assertEquals(Map.of(D1000, 1, D500, 1, D100, 2), result); assertEquals(300, atm.getBalance()); } @@ -78,14 +72,14 @@ void withdrawRejectsInvalidAmount() { @Test void withdrawRejectsInsufficientFunds() { Atm atm = new Atm(); - atm.deposit(Map.of(100, 2)); + atm.deposit(Map.of(D100, 2)); assertThrows(InsufficientFundsException.class, () -> atm.withdraw(300)); } @Test void withdrawRejectsUnmakeableAmountAndKeepsState() { Atm atm = new Atm(); - atm.deposit(Map.of(500, 1, 100, 1)); + atm.deposit(Map.of(D500, 1, D100, 1)); assertThrows(CannotDispenseException.class, () -> atm.withdraw(150)); assertEquals(600, atm.getBalance()); } @@ -96,7 +90,7 @@ void additionalTests(AtmCase atmCase) { Atm atm = new Atm(); for (Map deposit : atmCase.deposits) { - atm.deposit(toIntMap(deposit)); + atm.deposit(toMap(deposit)); } if (atmCase.expect.exception != null) { @@ -105,8 +99,8 @@ void additionalTests(AtmCase atmCase) { "Case: " + atmCase.name); assertEquals(atmCase.expect.balance, atm.getBalance(), "Case: " + atmCase.name); } else { - Map result = atm.withdraw(atmCase.withdraw); - assertEquals(toIntMap(atmCase.expect.dispense), result, "Case: " + atmCase.name); + Map result = atm.withdraw(atmCase.withdraw); + assertEquals(toMap(atmCase.expect.dispense), result, "Case: " + atmCase.name); assertEquals(atmCase.expect.balance, atm.getBalance(), "Case: " + atmCase.name); } } @@ -126,10 +120,10 @@ private static List loadCases() throws IOException { } } - private Map toIntMap(Map source) { - Map result = new HashMap<>(); + private Map toMap(Map source) { + Map result = new HashMap<>(); for (Map.Entry entry : source.entrySet()) { - result.put(Integer.parseInt(entry.getKey()), entry.getValue()); + result.put(Atm.Denomination.fromInt(Integer.parseInt(entry.getKey())), entry.getValue()); } return result; } diff --git a/src/test/java/hse/java/practice/task1/CubeSimpleTest.java b/src/test/java/hse/java/practice/task1/CubeSimpleTest.java new file mode 100644 index 00000000..b13c4af7 --- /dev/null +++ b/src/test/java/hse/java/practice/task1/CubeSimpleTest.java @@ -0,0 +1,277 @@ +package hse.java.practice.task1; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +public class CubeSimpleTest { + + private static final ObjectMapper MAPPER = new ObjectMapper(); + + @Test + void printTest() { + RubiksCube cube = new RubiksCube(); + CubeColor[] colors = CubeColor.values(); + for (int i = 0; i < 6; i++) { + Edge edge = cube.getEdges()[i]; + CubeColor[][] edgeColors = edge.getParts(); + for (CubeColor[] row : edgeColors) { + for (CubeColor color : row) { + Assertions.assertEquals(color, colors[i]); + } + } + } + } + + @Test + void frontClockwise() { + RubiksCube cube = new RubiksCube(); + cube.front(RotateDirection.CLOCKWISE); + + CubeColor[][][] state = readStateFromFile("frontClockwieseState.json"); + + CubeColor[][][] actuallyState = Arrays.stream(cube.getEdges()) + .map(Edge::getParts) + .toArray(CubeColor[][][]::new); + + Assertions.assertArrayEquals(state, actuallyState); + } + + @Test + void frontCounterclockwise() { + RubiksCube cube = new RubiksCube(); + // Поворот против часовой стрелки = 3 поворота по часовой стрелке + cube.front(RotateDirection.COUNTERCLOCKWISE); + + // Проверяем, что 4 поворота против часовой возвращают в исходное состояние + cube.front(RotateDirection.COUNTERCLOCKWISE); + cube.front(RotateDirection.COUNTERCLOCKWISE); + cube.front(RotateDirection.COUNTERCLOCKWISE); + + CubeColor[] colors = CubeColor.values(); + for (int i = 0; i < 6; i++) { + Edge edge = cube.getEdges()[i]; + CubeColor[][] edgeColors = edge.getParts(); + for (CubeColor[] row : edgeColors) { + for (CubeColor color : row) { + Assertions.assertEquals(colors[i], color); + } + } + } + } + + @Test + void upClockwise() { + RubiksCube cube = new RubiksCube(); + cube.up(RotateDirection.CLOCKWISE); + + CubeColor[][][] state = readStateFromFile("upClockwiseState.json"); + + CubeColor[][][] actuallyState = Arrays.stream(cube.getEdges()) + .map(Edge::getParts) + .toArray(CubeColor[][][]::new); + + Assertions.assertArrayEquals(state, actuallyState); + } + + @Test + void upCounterclockwise() { + RubiksCube cube = new RubiksCube(); + cube.up(RotateDirection.COUNTERCLOCKWISE); + cube.up(RotateDirection.COUNTERCLOCKWISE); + cube.up(RotateDirection.COUNTERCLOCKWISE); + cube.up(RotateDirection.COUNTERCLOCKWISE); + + CubeColor[] colors = CubeColor.values(); + for (int i = 0; i < 6; i++) { + Edge edge = cube.getEdges()[i]; + CubeColor[][] edgeColors = edge.getParts(); + for (CubeColor[] row : edgeColors) { + for (CubeColor color : row) { + Assertions.assertEquals(colors[i], color); + } + } + } + } + + @Test + void downClockwise() { + RubiksCube cube = new RubiksCube(); + cube.down(RotateDirection.CLOCKWISE); + + CubeColor[][][] state = readStateFromFile("downClockwiseState.json"); + + CubeColor[][][] actuallyState = Arrays.stream(cube.getEdges()) + .map(Edge::getParts) + .toArray(CubeColor[][][]::new); + + Assertions.assertArrayEquals(state, actuallyState); + } + + @Test + void downCounterclockwise() { + RubiksCube cube = new RubiksCube(); + cube.down(RotateDirection.COUNTERCLOCKWISE); + cube.down(RotateDirection.COUNTERCLOCKWISE); + cube.down(RotateDirection.COUNTERCLOCKWISE); + cube.down(RotateDirection.COUNTERCLOCKWISE); + + CubeColor[] colors = CubeColor.values(); + for (int i = 0; i < 6; i++) { + Edge edge = cube.getEdges()[i]; + CubeColor[][] edgeColors = edge.getParts(); + for (CubeColor[] row : edgeColors) { + for (CubeColor color : row) { + Assertions.assertEquals(colors[i], color); + } + } + } + } + + @Test + void leftClockwise() { + RubiksCube cube = new RubiksCube(); + cube.left(RotateDirection.CLOCKWISE); + + CubeColor[][][] state = readStateFromFile("leftClockwiseState.json"); + + CubeColor[][][] actuallyState = Arrays.stream(cube.getEdges()) + .map(Edge::getParts) + .toArray(CubeColor[][][]::new); + + Assertions.assertArrayEquals(state, actuallyState); + } + + @Test + void leftCounterclockwise() { + RubiksCube cube = new RubiksCube(); + cube.left(RotateDirection.COUNTERCLOCKWISE); + cube.left(RotateDirection.COUNTERCLOCKWISE); + cube.left(RotateDirection.COUNTERCLOCKWISE); + cube.left(RotateDirection.COUNTERCLOCKWISE); + + CubeColor[] colors = CubeColor.values(); + for (int i = 0; i < 6; i++) { + Edge edge = cube.getEdges()[i]; + CubeColor[][] edgeColors = edge.getParts(); + for (CubeColor[] row : edgeColors) { + for (CubeColor color : row) { + Assertions.assertEquals(colors[i], color); + } + } + } + } + + @Test + void rightClockwise() { + RubiksCube cube = new RubiksCube(); + cube.right(RotateDirection.CLOCKWISE); + + CubeColor[][][] state = readStateFromFile("rightClockwiseState.json"); + + CubeColor[][][] actuallyState = Arrays.stream(cube.getEdges()) + .map(Edge::getParts) + .toArray(CubeColor[][][]::new); + + Assertions.assertArrayEquals(state, actuallyState); + } + + @Test + void rightCounterclockwise() { + RubiksCube cube = new RubiksCube(); + cube.right(RotateDirection.COUNTERCLOCKWISE); + cube.right(RotateDirection.COUNTERCLOCKWISE); + cube.right(RotateDirection.COUNTERCLOCKWISE); + cube.right(RotateDirection.COUNTERCLOCKWISE); + + CubeColor[] colors = CubeColor.values(); + for (int i = 0; i < 6; i++) { + Edge edge = cube.getEdges()[i]; + CubeColor[][] edgeColors = edge.getParts(); + for (CubeColor[] row : edgeColors) { + for (CubeColor color : row) { + Assertions.assertEquals(colors[i], color); + } + } + } + } + + @Test + void backClockwise() { + RubiksCube cube = new RubiksCube(); + cube.back(RotateDirection.CLOCKWISE); + + CubeColor[][][] state = readStateFromFile("backClockwiseState.json"); + + CubeColor[][][] actuallyState = Arrays.stream(cube.getEdges()) + .map(Edge::getParts) + .toArray(CubeColor[][][]::new); + + Assertions.assertArrayEquals(state, actuallyState); + } + + @Test + void backCounterclockwise() { + RubiksCube cube = new RubiksCube(); + cube.back(RotateDirection.COUNTERCLOCKWISE); + cube.back(RotateDirection.COUNTERCLOCKWISE); + cube.back(RotateDirection.COUNTERCLOCKWISE); + cube.back(RotateDirection.COUNTERCLOCKWISE); + + CubeColor[] colors = CubeColor.values(); + for (int i = 0; i < 6; i++) { + Edge edge = cube.getEdges()[i]; + CubeColor[][] edgeColors = edge.getParts(); + for (CubeColor[] row : edgeColors) { + for (CubeColor color : row) { + Assertions.assertEquals(colors[i], color); + } + } + } + } + + @Test + void combinedRotations() { + RubiksCube cube = new RubiksCube(); + + // Выполняем последовательность поворотов + cube.front(RotateDirection.CLOCKWISE); + cube.right(RotateDirection.CLOCKWISE); + cube.up(RotateDirection.CLOCKWISE); + + // Выполняем обратную последовательность + cube.up(RotateDirection.COUNTERCLOCKWISE); + cube.right(RotateDirection.COUNTERCLOCKWISE); + cube.front(RotateDirection.COUNTERCLOCKWISE); + + // Должны вернуться в исходное состояние + CubeColor[] colors = CubeColor.values(); + for (int i = 0; i < 6; i++) { + Edge edge = cube.getEdges()[i]; + CubeColor[][] edgeColors = edge.getParts(); + for (CubeColor[] row : edgeColors) { + for (CubeColor color : row) { + Assertions.assertEquals(colors[i], color); + } + } + } + } + + private CubeColor[][][] readStateFromFile(String fileName) { + String resourcePath = "hse/java/practice/task1/" + fileName; + try (InputStream is = CubeSimpleTest.class.getClassLoader().getResourceAsStream(resourcePath)) { + if (is == null) { + throw new IllegalArgumentException("Resource not found: " + resourcePath); + } + String json = new String(is.readAllBytes(), StandardCharsets.UTF_8); + return MAPPER.readValue(json, CubeColor[][][].class); + } catch (IOException e) { + throw new RuntimeException("Failed to read/parse state file: " + fileName, e); + } + } +} From 4d8f99add7ea332d992260dfd34e3f5a46f1c6a9 Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 7 Feb 2026 18:08:33 +0300 Subject: [PATCH 04/12] practice 2: RandomSet --- .github/workflows/pr-tests.yml | 38 ++++++++++++-- commander/commander.iml | 9 ---- pom.xml | 9 +++- .../java/lectures/lecture3/examples/Main.java | 1 + .../practice/randomSet/EmptySetException.java | 7 +++ .../practice/randomSet/RandomSet.java | 21 ++++++++ .../lecture3/practice/randomSet/task.md | 50 +++++++++++++++++++ .../practice/randomSet/RandomSetBaseTest.java | 28 +++++++++++ 8 files changed, 148 insertions(+), 15 deletions(-) delete mode 100644 commander/commander.iml create mode 100644 src/main/java/hse/java/lectures/lecture3/practice/randomSet/EmptySetException.java create mode 100644 src/main/java/hse/java/lectures/lecture3/practice/randomSet/RandomSet.java create mode 100644 src/main/java/hse/java/lectures/lecture3/practice/randomSet/task.md create mode 100644 src/test/java/hse/java/lectures/lecture3/practice/randomSet/RandomSetBaseTest.java diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/pr-tests.yml index 8c507688..7272e99b 100644 --- a/.github/workflows/pr-tests.yml +++ b/.github/workflows/pr-tests.yml @@ -36,13 +36,41 @@ jobs: - name: Copy test files run: | - echo "Copying test data" - mkdir -p src/test/resources + echo "Copying hidden tests" + mkdir -p src/test/java src/test/resources + cp -R hidden-tests/src/test/java/. src/test/java/ cp -R hidden-tests/src/test/resources/. src/test/resources/ echo "" echo "Скопированы файлы:" - find src/test/resources -type f | sort | while read f; do echo " $f"; done + find src/test/java src/test/resources -type f | sort | while read f; do echo " $f"; done rm -rf hidden-tests - + + - name: Run honors no-collections test + id: honors_test + continue-on-error: true + run: mvn -B -Dtest=hse.java.lectures.lecture3.practice.randomSet.RandomSetBytecodeTest test + + - name: Comment on PR for honors solution + if: steps.honors_test.outcome == 'success' + uses: actions/github-script@v7 + with: + script: | + const pr = context.payload.pull_request; + if (!pr) { + core.info('No PR context, skipping comment.'); + return; + } + const body = [ + 'Поздравляем! 🎉', + '', + 'Вы решили сложную версию: решение прошло проверку «без коллекций».' + ].join('\\n'); + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + body + }); + - name: Run tests - run: mvn -B test + run: mvn -B -Dtest='!**/RandomSetBytecodeTest' test diff --git a/commander/commander.iml b/commander/commander.iml deleted file mode 100644 index 68a9707e..00000000 --- a/commander/commander.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/pom.xml b/pom.xml index ade43fe2..648f8788 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,13 @@ ${junit.version} test + + + org.ow2.asm + asm + 9.8 + test + com.fasterxml.jackson.core @@ -65,4 +72,4 @@ - \ No newline at end of file + diff --git a/src/main/java/hse/java/lectures/lecture3/examples/Main.java b/src/main/java/hse/java/lectures/lecture3/examples/Main.java index d4279be4..116ff543 100644 --- a/src/main/java/hse/java/lectures/lecture3/examples/Main.java +++ b/src/main/java/hse/java/lectures/lecture3/examples/Main.java @@ -14,5 +14,6 @@ public static void main(String[] args) { Box nBox = box; new Methods().get(new ArrayList()).add(1); + } } diff --git a/src/main/java/hse/java/lectures/lecture3/practice/randomSet/EmptySetException.java b/src/main/java/hse/java/lectures/lecture3/practice/randomSet/EmptySetException.java new file mode 100644 index 00000000..c7820ac5 --- /dev/null +++ b/src/main/java/hse/java/lectures/lecture3/practice/randomSet/EmptySetException.java @@ -0,0 +1,7 @@ +package hse.java.lectures.lecture3.practice.randomSet; + +public class EmptySetException extends RuntimeException { + public EmptySetException(String message) { + super(message); + } +} diff --git a/src/main/java/hse/java/lectures/lecture3/practice/randomSet/RandomSet.java b/src/main/java/hse/java/lectures/lecture3/practice/randomSet/RandomSet.java new file mode 100644 index 00000000..8af477b5 --- /dev/null +++ b/src/main/java/hse/java/lectures/lecture3/practice/randomSet/RandomSet.java @@ -0,0 +1,21 @@ +package hse.java.lectures.lecture3.practice.randomSet; + +public class RandomSet { + + public boolean insert(T value) { + throw new UnsupportedOperationException("Not implemented"); + } + + public boolean remove(T value) { + throw new UnsupportedOperationException("Not implemented"); + } + + public boolean contains(T value) { + throw new UnsupportedOperationException("Not implemented"); + } + + public T getRandom() { + throw new UnsupportedOperationException("Not implemented"); + } + +} diff --git a/src/main/java/hse/java/lectures/lecture3/practice/randomSet/task.md b/src/main/java/hse/java/lectures/lecture3/practice/randomSet/task.md new file mode 100644 index 00000000..05e9740b --- /dev/null +++ b/src/main/java/hse/java/lectures/lecture3/practice/randomSet/task.md @@ -0,0 +1,50 @@ +# Случайное множество (RandomSet) + +## Условие + +Реализовать класс `RandomSet`, который хранит множество целых чисел и поддерживает операции вставки, удаления и получения случайного элемента. + +## Требования к асимптотике + +- `insert(x)` — **O(log n) or O(1)** +- `remove(x)` — **O(log n) or O(1)** +- `contains(x)` — **(log n) or O(1)** +- `getRandom()` — **O(1)** + +Не допускается использование стандартных коллекций Java. + +## Публичный API + +1. `RandomSet()` — создаёт пустое множество. +1. `boolean insert(T value)` — добавляет `value` в множество. + - Возвращает `true`, если элемент добавлен. + - Возвращает `false`, если элемент уже был в множестве. +1. `boolean remove(T value)` — удаляет `value` из множества. + - Возвращает `true`, если элемент был удалён. + - Возвращает `false`, если элемента не было. +1. `boolean contains(T value)` — проверяет наличие `value` в множестве. + - Возвращает `true`, если элемент есть. + - Возвращает `false`, если элемента нет. +1. `T getRandom()` — возвращает случайный элемент из множества. + - Если множество пустое, выбрасывает `EmptySetException`. + +## Исключения + +- `EmptySetException` — попытка получить случайный элемент из пустого множества. + +## Пример + +```java +RandomSet set = new RandomSet<>(); +set.insert(10); // true +set.insert(20); // true +set.insert(10); // false + +int x = set.getRandom(); // 10 или 20 + +set.remove(10); // true +set.remove(10); // false + +set.contains(20); // true +set.contains(30); // false +``` diff --git a/src/test/java/hse/java/lectures/lecture3/practice/randomSet/RandomSetBaseTest.java b/src/test/java/hse/java/lectures/lecture3/practice/randomSet/RandomSetBaseTest.java new file mode 100644 index 00000000..37c38ab1 --- /dev/null +++ b/src/test/java/hse/java/lectures/lecture3/practice/randomSet/RandomSetBaseTest.java @@ -0,0 +1,28 @@ +package hse.java.lectures.lecture3.practice.randomSet; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class RandomSetBaseTest { + + @Test + void insertRemoveContains() { + RandomSet set = new RandomSet<>(); + + assertTrue(set.insert(10)); + assertTrue(set.insert(20)); + assertFalse(set.insert(10)); + + assertTrue(set.contains(10)); + assertTrue(set.contains(20)); + assertFalse(set.contains(30)); + + assertTrue(set.remove(10)); + assertFalse(set.remove(10)); + + assertFalse(set.contains(10)); + assertTrue(set.contains(20)); + } + +} From 478a8786566f9004c63f67fc06fff6a46519b66a Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 7 Feb 2026 18:25:21 +0300 Subject: [PATCH 05/12] fix ci --- .github/workflows/pr-tests.yml | 59 ++++++++++++++++++- README-commit-format.md | 20 +++++++ .../lecture3/practice/randomSet/task.md | 2 + .../java/lectures/lecture3/tasks/atm/task.md | 2 + .../java/lectures/lecture3/tasks/html/task.md | 2 + src/main/java/hse/java/practice/task1/task.md | 2 + 6 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 README-commit-format.md diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/pr-tests.yml index 7272e99b..b296bc45 100644 --- a/.github/workflows/pr-tests.yml +++ b/.github/workflows/pr-tests.yml @@ -45,9 +45,37 @@ jobs: find src/test/java src/test/resources -type f | sort | while read f; do echo " $f"; done rm -rf hidden-tests + - name: Select test pattern from PR labels + id: select_tests + uses: actions/github-script@v7 + with: + script: | + const pr = context.payload.pull_request; + if (!pr) { + core.setOutput('pattern', ''); + return; + } + const repo = { owner: context.repo.owner, repo: context.repo.repo }; + const { data: commit } = await github.rest.repos.getCommit({ + ...repo, + ref: pr.head.sha + }); + const msg = (commit.commit.message || '').toLowerCase(); + + const patterns = []; + const add = (p) => { if (!patterns.includes(p)) patterns.push(p); }; + + if (msg.startsWith('atm:')) add('**/atm/*Test'); + if (msg.startsWith('html:')) add('**/html/*Test'); + if (msg.startsWith('randomset:')) add('**/randomSet/*Test'); + + // If no task prefix, run all tests + core.setOutput('pattern', patterns.length ? patterns.join(',') : ''); + - name: Run honors no-collections test id: honors_test continue-on-error: true + if: steps.select_tests.outputs.pattern == '**/randomSet/*Test' run: mvn -B -Dtest=hse.java.lectures.lecture3.practice.randomSet.RandomSetBytecodeTest test - name: Comment on PR for honors solution @@ -73,4 +101,33 @@ jobs: }); - name: Run tests - run: mvn -B -Dtest='!**/RandomSetBytecodeTest' test + run: | + if [ -n "${{ steps.select_tests.outputs.pattern }}" ]; then + echo "Running selected tests: ${{ steps.select_tests.outputs.pattern }}" + mvn -B -Dtest='${{ steps.select_tests.outputs.pattern }}' test + else + echo "No task prefix found. Skipping tests." + fi + + - name: Comment on PR when no task prefix + if: steps.select_tests.outputs.pattern == '' + uses: actions/github-script@v7 + with: + script: | + const pr = context.payload.pull_request; + if (!pr) { + core.info('No PR context, skipping comment.'); + return; + } + const body = [ + 'Тесты не запускались.', + '', + 'Укажите задачу в начале сообщения коммита:', + '`atm: ...`, `html: ...`, `randomset: ...`' + ].join('\\n'); + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + body + }); diff --git a/README-commit-format.md b/README-commit-format.md new file mode 100644 index 00000000..24c170a4 --- /dev/null +++ b/README-commit-format.md @@ -0,0 +1,20 @@ +# Формат коммитов для запуска тестов + +## Зачем это нужно +CI запускает тесты выборочно. Чтобы он знал, какие тесты запускать, сообщение коммита должно начинаться с названия задачи. + +## Формат +Используйте префикс в начале сообщения коммита: + +- `atm: ...` +- `html: ...` +- `randomset: ...` + +Тег задачи указывается в описании каждой задачи + +Пример: +``` +randomset: implement getRandom and contains +``` + +Если префикс не указан, CI **не запускает тесты** и оставляет комментарий в PR. diff --git a/src/main/java/hse/java/lectures/lecture3/practice/randomSet/task.md b/src/main/java/hse/java/lectures/lecture3/practice/randomSet/task.md index 05e9740b..fb987780 100644 --- a/src/main/java/hse/java/lectures/lecture3/practice/randomSet/task.md +++ b/src/main/java/hse/java/lectures/lecture3/practice/randomSet/task.md @@ -1,5 +1,7 @@ # Случайное множество (RandomSet) +Tag: randomset + ## Условие Реализовать класс `RandomSet`, который хранит множество целых чисел и поддерживает операции вставки, удаления и получения случайного элемента. diff --git a/src/main/java/hse/java/lectures/lecture3/tasks/atm/task.md b/src/main/java/hse/java/lectures/lecture3/tasks/atm/task.md index 3845672e..6d574e19 100644 --- a/src/main/java/hse/java/lectures/lecture3/tasks/atm/task.md +++ b/src/main/java/hse/java/lectures/lecture3/tasks/atm/task.md @@ -1,5 +1,7 @@ # Банкомат (ATM) +Tag: atm + ## Условие Реализовать класс `Atm`, который хранит купюры фиксированных номиналов и выполняет операции пополнения и выдачи наличных. При ошибках операции должны завершаться выбросом исключения без изменения состояния банкомата. diff --git a/src/main/java/hse/java/lectures/lecture3/tasks/html/task.md b/src/main/java/hse/java/lectures/lecture3/tasks/html/task.md index 4ec71b18..2160175f 100644 --- a/src/main/java/hse/java/lectures/lecture3/tasks/html/task.md +++ b/src/main/java/hse/java/lectures/lecture3/tasks/html/task.md @@ -1,5 +1,7 @@ # Валидация HTML-документа +Tag: html + ## Условие Реализовать класс `HtmlDocument`, который читает HTML-текст из файла и проверяет корректность структуры. Если документ невалиден, при создании объекта выбрасывается исключение. diff --git a/src/main/java/hse/java/practice/task1/task.md b/src/main/java/hse/java/practice/task1/task.md index 235cc660..60dc4533 100644 --- a/src/main/java/hse/java/practice/task1/task.md +++ b/src/main/java/hse/java/practice/task1/task.md @@ -1,5 +1,7 @@ Необходимо реализовать методы поворота кубика Рубика. +Tag: cube + Кубик представляет собой классический куб 3×3×3: - 6 граней; - каждая грань состоит из 9 элементов (стикеров); From f38eb12110f50ce3f8b18b525464953b7dcc8d48 Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 7 Feb 2026 18:27:32 +0300 Subject: [PATCH 06/12] fix ci --- .github/workflows/pr-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/pr-tests.yml index b296bc45..aa378cae 100644 --- a/.github/workflows/pr-tests.yml +++ b/.github/workflows/pr-tests.yml @@ -68,6 +68,7 @@ jobs: if (msg.startsWith('atm:')) add('**/atm/*Test'); if (msg.startsWith('html:')) add('**/html/*Test'); if (msg.startsWith('randomset:')) add('**/randomSet/*Test'); + if (msg.startsWith('cube:')) add('**/CubeSimpleTest'); // If no task prefix, run all tests core.setOutput('pattern', patterns.length ? patterns.join(',') : ''); From 96778a4bc9c92207c03f34343ccc272cb2f8c260 Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 7 Feb 2026 18:33:08 +0300 Subject: [PATCH 07/12] fix ci --- .github/workflows/pr-tests.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/pr-tests.yml index aa378cae..da9457f0 100644 --- a/.github/workflows/pr-tests.yml +++ b/.github/workflows/pr-tests.yml @@ -45,7 +45,7 @@ jobs: find src/test/java src/test/resources -type f | sort | while read f; do echo " $f"; done rm -rf hidden-tests - - name: Select test pattern from PR labels + - name: Select test pattern from commit message id: select_tests uses: actions/github-script@v7 with: @@ -70,7 +70,6 @@ jobs: if (msg.startsWith('randomset:')) add('**/randomSet/*Test'); if (msg.startsWith('cube:')) add('**/CubeSimpleTest'); - // If no task prefix, run all tests core.setOutput('pattern', patterns.length ? patterns.join(',') : ''); - name: Run honors no-collections test @@ -93,7 +92,7 @@ jobs: 'Поздравляем! 🎉', '', 'Вы решили сложную версию: решение прошло проверку «без коллекций».' - ].join('\\n'); + ].join('\n'); await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, @@ -107,7 +106,8 @@ jobs: echo "Running selected tests: ${{ steps.select_tests.outputs.pattern }}" mvn -B -Dtest='${{ steps.select_tests.outputs.pattern }}' test else - echo "No task prefix found. Skipping tests." + echo "No task prefix found. Failing." + exit 1 fi - name: Comment on PR when no task prefix @@ -124,8 +124,8 @@ jobs: 'Тесты не запускались.', '', 'Укажите задачу в начале сообщения коммита:', - '`atm: ...`, `html: ...`, `randomset: ...`' - ].join('\\n'); + 'atm: ..., html: ..., randomset: ...' + ].join('\n'); await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, From 7913bd6d3118c20ae2a286087920953d0fa9f8bf Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 7 Feb 2026 18:37:15 +0300 Subject: [PATCH 08/12] fix CI --- .github/workflows/pr-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/pr-tests.yml index da9457f0..d9a5bdfc 100644 --- a/.github/workflows/pr-tests.yml +++ b/.github/workflows/pr-tests.yml @@ -104,7 +104,7 @@ jobs: run: | if [ -n "${{ steps.select_tests.outputs.pattern }}" ]; then echo "Running selected tests: ${{ steps.select_tests.outputs.pattern }}" - mvn -B -Dtest='${{ steps.select_tests.outputs.pattern }}' test + mvn -B -Dtest='${{ steps.select_tests.outputs.pattern }},!**/RandomSetBytecodeTest' test else echo "No task prefix found. Failing." exit 1 From 308f24ceff27c6e93d3bc3b2b9eadf0ffe136452 Mon Sep 17 00:00:00 2001 From: p1gushka Date: Fri, 6 Feb 2026 23:35:21 +0300 Subject: [PATCH 09/12] added front rotation --- .../hse/java/practice/task1/RubiksCube.java | 205 +++++++++++++++++- src/test/test.iml | 11 + 2 files changed, 214 insertions(+), 2 deletions(-) create mode 100644 src/test/test.iml diff --git a/src/main/java/hse/java/practice/task1/RubiksCube.java b/src/main/java/hse/java/practice/task1/RubiksCube.java index d986f9f0..d3bb1de2 100644 --- a/src/main/java/hse/java/practice/task1/RubiksCube.java +++ b/src/main/java/hse/java/practice/task1/RubiksCube.java @@ -26,34 +26,235 @@ public RubiksCube() { } } + private CubeColor[][] copyParts(CubeColor[][] otherParts) { + CubeColor[][] parts = new CubeColor[3][3]; + for (int i = 0; i < 3; i++) { + System.arraycopy(otherParts[i], 0, parts[i], 0, 3); + } + return parts; + } + + private void rotateInnerClockwise(EdgePosition position) { + CubeColor[][] parts = edges[position.ordinal()].getParts(); + CubeColor[][] newParts = new CubeColor[3][3]; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + newParts[2 - j][i] = parts[i][j]; + } + } + + edges[4].setParts(newParts); + } + @Override public void up(RotateDirection direction) { + switch (direction) { + case CLOCKWISE -> { + rotateUpClockwise(); + } + case COUNTERCLOCKWISE -> { + rotateUpClockwise(); + rotateUpClockwise(); + rotateUpClockwise(); + } + } + } + + private void rotateUpClockwise() { + rotateInnerClockwise(EdgePosition.UP); + + CubeColor[][] upParts = edges[5].getParts(); + CubeColor[][] leftParts = edges[2].getParts(); + CubeColor[][] rightParts = edges[3].getParts(); + CubeColor[][] downParts = edges[4].getParts(); + CubeColor[][] upPartsCopy = copyParts(upParts); + CubeColor[][] leftPartsCopy = copyParts(leftParts); + CubeColor[][] rightPartsCopy = copyParts(rightParts); + CubeColor[][] downPartsCopy = copyParts(downParts); + + for (int i = 0; i < 3; i++) { + upParts[0][i] = leftPartsCopy[0][i]; + rightParts[0][i] = upPartsCopy[0][i]; + downParts[0][i] = rightPartsCopy[0][i]; + leftParts[0][i] = downPartsCopy[0][i]; + } } @Override public void down(RotateDirection direction) { + switch (direction) { + case CLOCKWISE -> { + rotateDownClockwise(); + } + case COUNTERCLOCKWISE -> { + rotateDownClockwise(); + rotateDownClockwise(); + rotateDownClockwise(); + } + } } + private void rotateDownClockwise() { + rotateInnerClockwise(EdgePosition.DOWN); + + CubeColor[][] upParts = edges[4].getParts(); + CubeColor[][] leftParts = edges[2].getParts(); + CubeColor[][] rightParts = edges[3].getParts(); + CubeColor[][] downParts = edges[5].getParts(); + + CubeColor[][] upPartsCopy = copyParts(upParts); + CubeColor[][] leftPartsCopy = copyParts(leftParts); + CubeColor[][] rightPartsCopy = copyParts(rightParts); + CubeColor[][] downPartsCopy = copyParts(downParts); + + for (int i = 0; i < 3; i++) { + upParts[2][i] = leftPartsCopy[2][i]; + rightParts[2][i] = upPartsCopy[2][i]; + downParts[2][i] = rightPartsCopy[2][i]; + leftParts[2][i] = downPartsCopy[2][i]; + } + } + @Override public void left(RotateDirection direction) { + switch (direction) { + case CLOCKWISE -> { + rotateLeftClockwise(); + } + case COUNTERCLOCKWISE -> { + rotateLeftClockwise(); + rotateLeftClockwise(); + rotateLeftClockwise(); + } + } + } + private void rotateLeftClockwise() { + rotateInnerClockwise(EdgePosition.LEFT); + + CubeColor[][] upParts = edges[0].getParts(); + CubeColor[][] leftParts = edges[5].getParts(); + CubeColor[][] rightParts = edges[4].getParts(); + CubeColor[][] downParts = edges[1].getParts(); + + CubeColor[][] upPartsCopy = copyParts(upParts); + CubeColor[][] leftPartsCopy = copyParts(leftParts); + CubeColor[][] rightPartsCopy = copyParts(rightParts); + CubeColor[][] downPartsCopy = copyParts(downParts); + + for (int i = 0; i < 3; i++) { + upParts[i][0] = leftPartsCopy[2-i][2]; + rightParts[i][0] = upPartsCopy[i][0]; + downParts[i][0] = rightPartsCopy[i][0]; + leftParts[i][2] = downPartsCopy[0][2-i]; + } } @Override public void right(RotateDirection direction) { + switch (direction) { + case CLOCKWISE -> { + rotateRightClockwise(); + } + case COUNTERCLOCKWISE -> { + rotateRightClockwise(); + rotateRightClockwise(); + rotateRightClockwise(); + } + } + } + private void rotateRightClockwise() { + rotateInnerClockwise(EdgePosition.RIGHT); + + CubeColor[][] upParts = edges[0].getParts(); + CubeColor[][] leftParts = edges[4].getParts(); + CubeColor[][] rightParts = edges[5].getParts(); + CubeColor[][] downParts = edges[1].getParts(); + + CubeColor[][] upPartsCopy = copyParts(upParts); + CubeColor[][] leftPartsCopy = copyParts(leftParts); + CubeColor[][] rightPartsCopy = copyParts(rightParts); + CubeColor[][] downPartsCopy = copyParts(downParts); + + for (int i = 0; i < 3; i++) { + upParts[i][2] = leftPartsCopy[i][2]; + rightParts[i][0] = upPartsCopy[2-i][2]; + downParts[i][2] = rightPartsCopy[2-i][0]; + leftParts[i][2] = downPartsCopy[i][2]; + } } - @Override public void front(RotateDirection direction) { + switch (direction) { + case CLOCKWISE -> { + rotateFrontClockwise(); + } + case COUNTERCLOCKWISE -> { + rotateFrontClockwise(); + rotateFrontClockwise(); + rotateFrontClockwise(); + } + } + } + + private void rotateFrontClockwise() { + rotateInnerClockwise(EdgePosition.FRONT); + + CubeColor[][] upParts = edges[0].getParts(); + CubeColor[][] leftParts = edges[2].getParts(); + CubeColor[][] rightParts = edges[3].getParts(); + CubeColor[][] downParts = edges[1].getParts(); + CubeColor[][] upPartsCopy = copyParts(upParts); + CubeColor[][] leftPartsCopy = copyParts(leftParts); + CubeColor[][] rightPartsCopy = copyParts(rightParts); + CubeColor[][] downPartsCopy = copyParts(downParts); + + for (int i = 0; i < 3; i++) { + upParts[2][i] = leftPartsCopy[2-i][2]; + rightParts[i][0] = upPartsCopy[2][i]; + downParts[0][i] = rightPartsCopy[2-i][0]; + leftParts[i][2] = downPartsCopy[0][i]; + } } @Override public void back(RotateDirection direction) { + switch (direction) { + case CLOCKWISE -> { + rotateBackClockwise(); + } + case COUNTERCLOCKWISE -> { + rotateBackClockwise(); + rotateBackClockwise(); + rotateBackClockwise(); + } + } + } + + private void rotateBackClockwise() { + rotateInnerClockwise(EdgePosition.BACK); + + CubeColor[][] upParts = edges[0].getParts(); + CubeColor[][] leftParts = edges[3].getParts(); + CubeColor[][] rightParts = edges[2].getParts(); + CubeColor[][] downParts = edges[1].getParts(); + CubeColor[][] upPartsCopy = copyParts(upParts); + CubeColor[][] leftPartsCopy = copyParts(leftParts); + CubeColor[][] rightPartsCopy = copyParts(rightParts); + CubeColor[][] downPartsCopy = copyParts(downParts); + + for (int i = 0; i < 3; i++) { + upParts[0][i] = leftPartsCopy[i][2]; + rightParts[i][0] = upPartsCopy[0][2-i]; + downParts[2][i] = rightPartsCopy[i][0]; + leftParts[i][2] = downPartsCopy[2][2-i]; + } } public Edge[] getEdges() { @@ -64,4 +265,4 @@ public Edge[] getEdges() { public String toString() { return Arrays.toString(edges); } -} +} \ No newline at end of file diff --git a/src/test/test.iml b/src/test/test.iml new file mode 100644 index 00000000..2185ddd0 --- /dev/null +++ b/src/test/test.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file From 615025cc669742282209147381b49b2fb479c276 Mon Sep 17 00:00:00 2001 From: p1gushka Date: Sat, 7 Feb 2026 20:50:27 +0300 Subject: [PATCH 10/12] cube: rerun tests --- src/main/java/hse/java/practice/task1/RubiksCube.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/main/java/hse/java/practice/task1/RubiksCube.java b/src/main/java/hse/java/practice/task1/RubiksCube.java index d3bb1de2..0ef457c5 100644 --- a/src/main/java/hse/java/practice/task1/RubiksCube.java +++ b/src/main/java/hse/java/practice/task1/RubiksCube.java @@ -2,23 +2,12 @@ import java.util.Arrays; -/** - * Необходимо реализовать интерфейс Cube - * При повороте передней грани, меняются верх низ право и лево - */ public class RubiksCube implements Cube { private static final int EDGES_COUNT = 6; private final Edge[] edges = new Edge[EDGES_COUNT]; - /** - * Создать валидный собранный кубик - * грани разместить по ордеру в енуме цветов - * грань 0 -> цвет 0 - * грань 1 -> цвет 1 - * ... - */ public RubiksCube() { CubeColor[] colors = CubeColor.values(); for (int i = 0; i < 6; i++) { From a60527a92fb2b8cc344ed2ceebfff98460a58a13 Mon Sep 17 00:00:00 2001 From: p1gushka Date: Sat, 7 Feb 2026 23:56:44 +0300 Subject: [PATCH 11/12] cube: fixed rotateInnerClockwise --- src/main/java/hse/java/practice/task1/RubiksCube.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/hse/java/practice/task1/RubiksCube.java b/src/main/java/hse/java/practice/task1/RubiksCube.java index 0ef457c5..79a9d339 100644 --- a/src/main/java/hse/java/practice/task1/RubiksCube.java +++ b/src/main/java/hse/java/practice/task1/RubiksCube.java @@ -25,15 +25,15 @@ private CubeColor[][] copyParts(CubeColor[][] otherParts) { private void rotateInnerClockwise(EdgePosition position) { CubeColor[][] parts = edges[position.ordinal()].getParts(); - CubeColor[][] newParts = new CubeColor[3][3]; + CubeColor[][] partsCopy = new CubeColor[3][3]; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - newParts[2 - j][i] = parts[i][j]; + partsCopy[j][2-i] = parts[i][j]; } } - edges[4].setParts(newParts); + edges[4].setParts(partsCopy); } @Override From f102111136ae98683785ae93e225066ddd82b60f Mon Sep 17 00:00:00 2001 From: p1gushka Date: Sun, 8 Feb 2026 00:24:12 +0300 Subject: [PATCH 12/12] cube: fixed bags --- src/main/java/hse/java/practice/task1/RubiksCube.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/hse/java/practice/task1/RubiksCube.java b/src/main/java/hse/java/practice/task1/RubiksCube.java index 79a9d339..a05ec963 100644 --- a/src/main/java/hse/java/practice/task1/RubiksCube.java +++ b/src/main/java/hse/java/practice/task1/RubiksCube.java @@ -33,7 +33,7 @@ private void rotateInnerClockwise(EdgePosition position) { } } - edges[4].setParts(partsCopy); + edges[position.ordinal()].setParts(partsCopy); } @Override @@ -138,7 +138,7 @@ private void rotateLeftClockwise() { upParts[i][0] = leftPartsCopy[2-i][2]; rightParts[i][0] = upPartsCopy[i][0]; downParts[i][0] = rightPartsCopy[i][0]; - leftParts[i][2] = downPartsCopy[0][2-i]; + leftParts[i][2] = downPartsCopy[2-i][0]; } }