Kumite (ko͞omiˌtā) is the practice of taking techniques learned from Kata and applying them through the act of freestyle sparring.
You can create a new kumite by providing some initial code and optionally some test cases. From there other warriors can spar with you, by enhancing, refactoring and translating your code. There is no limit to how many warriors you can spar with.
A great use for kumite is to begin an idea for a kata as one. You can collaborate with other code warriors until you have it right, then you can convert it to a kata.
class Trie: def __init__(self): """ Initializes the trie object. """ self.children = {} self.is_word = False def insert(self, word: str) -> None: """ Inserts a word into the trie. """ # create a 'ptr' to the first node. node = self # loop through all the chars. for char in word: # insert a new instance of Trie if a letter isnt found. if char not in node.children: node.children[char] = Trie() # move to next node node = node.children[char] # once you get to the end mark this node as an end node. node.is_word = True def search(self, word: str) -> bool: """ Returns if the word is in the trie. """ # create a 'ptr' to the first node. node = self for char in word: # if at any point we dont find our current char. then we know the word is not in the Trie. if char not in node.children: return False # move to next node node = node.children[char] # if we get to the end then we know all the chars are in the trie. But we return weather or not we are at the end of a word. Since this could be a "starts with match". return node.is_word def startsWith(self, prefix: str) -> bool: """ Returns if there is any word in the trie that starts with the given prefix. """ # same as search()... node = self for char in prefix: if char not in node.children: return False node = node.children[char] #... except that regardless of the .is_word value we will return true. return True
- class Trie:
- def __init__(self):
- """
- Initializes the trie object.
- """
pass # Replace with your code- self.children = {}
- self.is_word = False
- def insert(self, word: str) -> None:
- """
- Inserts a word into the trie.
- """
pass # Replace with your code- # create a 'ptr' to the first node.
- node = self
- # loop through all the chars.
- for char in word:
- # insert a new instance of Trie if a letter isnt found.
- if char not in node.children:
- node.children[char] = Trie()
- # move to next node
- node = node.children[char]
- # once you get to the end mark this node as an end node.
- node.is_word = True
- def search(self, word: str) -> bool:
- """
- Returns if the word is in the trie.
- """
pass # Replace with your code- # create a 'ptr' to the first node.
- node = self
- for char in word:
- # if at any point we dont find our current char. then we know the word is not in the Trie.
- if char not in node.children:
- return False
- # move to next node
- node = node.children[char]
- # if we get to the end then we know all the chars are in the trie. But we return weather or not we are at the end of a word. Since this could be a "starts with match".
- return node.is_word
- def startsWith(self, prefix: str) -> bool:
- """
- Returns if there is any word in the trie that starts with the given prefix.
- """
pass # Replace with your code- # same as search()...
- node = self
- for char in prefix:
- if char not in node.children:
- return False
- node = node.children[char]
- #... except that regardless of the .is_word value we will return true.
- return True
This works.. somehow. lol.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #define ONES_SIZE 10 #define TEENS_SIZE 6 #define TENS_SIZE 8 #define MAX_DOLLAR_SIZE 40 /* Returns(in place): the integer and fractional parts of the double... ...effectively the left and right sides of the double. */ void double_to_ints(const double num, int *integer_part, int *fractional_part, const int decimal_places) { *integer_part = (int)num; double fractional = num - (double)*integer_part; *fractional_part = (int)round(fractional * pow(10, decimal_places)); } /* Returns: the index of where the key is in the array... ...or -1 if the value is not found. */ int find_val_in_array(int *array, int key, int array_size) { for (int i = 0; i < array_size; i++) { if (key == array[i]){ return i; } } return -1; } /* Arguments: - amount = a double betwen 0.01 and 99.99. Representing the check dollars and cents to convert. Returns: A string with the text representation of 'amount'.... ...or NULL if the value is not found. */ char *checkAmount(double amount) { // input validate if (0.00 >= amount || amount > 99.99) { return NULL; } char * return_val = NULL; // define key value pair of words and their equivelant value as an int. int ones_key[] = {0,1,2,3,4,5,6,7,8,9}; char ones_value[ONES_SIZE][MAX_DOLLAR_SIZE] = {"ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE"}; int teens_key[] = {10,11,12,13,14,15}; char teens_value[TEENS_SIZE][MAX_DOLLAR_SIZE] = {"TEN", "ELEVEN", "TWELVE", "THIRTEEN", "FOURTEEN", "FIFTEEN"}; int tens_key[] = {20,30,40,50,60,70,80,90}; char tens_value[TENS_SIZE][MAX_DOLLAR_SIZE] = {"TWENTY", "THIRTY", "FORTY", "FIFTY", "SIXTY", "SEVENTY", "EIGHTY", "NINETY"}; // define vars! int *integer_part = calloc(1, sizeof(int)); if (NULL == integer_part){ perror("malloc failed"); return NULL; } int *fractional_part = calloc(1, sizeof(int)); if (NULL == fractional_part){ perror("malloc failed"); return NULL; } int found_pos = -1; int len = 0; int tens = 0; char temp[MAX_DOLLAR_SIZE]; char *list = NULL; char *dollars = calloc(1, MAX_DOLLAR_SIZE); if (NULL == dollars){ perror("malloc failed"); return NULL; } // extract integer and fraction from double. double_to_ints(amount, integer_part, fractional_part, 2); // For each _key list we are checking if the '*integer_part' is in the list. if it is we updated "list" to point to the corresponding _value list... if ((found_pos = find_val_in_array(ones_key, *integer_part, ONES_SIZE)) != -1) { list = ones_value[found_pos]; } else if ((found_pos = find_val_in_array(teens_key, *integer_part, TEENS_SIZE)) != -1) { list = teens_value[found_pos]; } else if ((found_pos = find_val_in_array(tens_key, *integer_part, TENS_SIZE)) != -1) { list = tens_value[found_pos]; } else { // ... if we dont find a match then its likely that we got 16-19 or something like: [24, 56, 91, ...] // we divide by 10 so we can drop the value in the ones place [16 -> 1, 24 -> 2, ...] tens = *integer_part / 10; if (tens == 1) { // if we have a ten then we handle it special due to the 'teens'. get the "ones_key" and append "TEEN" to it... // ... for example: ["NINE" + "TEEN" = "NINETEEN"] found_pos = find_val_in_array(ones_key, (*integer_part - 10), ONES_SIZE); strncpy(temp, ones_value[found_pos], sizeof(temp)); // EIGHTEEN is a special case since "EIGHT" and "TEEN" share a "T". So we trim the "T" if (strncmp(temp, "EIGHT", 6) == 0) { strcat(temp, "EEN"); } else { strcat(temp, "TEEN"); } } else { // non-tens are handled different. exmple: 25 // find and update temp = "TWENTY" found_pos = find_val_in_array(tens_key, (tens * 10), TENS_SIZE); strncpy(temp, tens_value[found_pos], sizeof(temp)); // find and update temp = "TWENTY FIVE" int val = (*integer_part % 10); strcat(temp, " "); strcat(temp, ones_value[val]); } list = temp; } if (list != NULL) { // Ensure null termination len = strlen(list); strncpy(dollars, list, len); dollars[len] = '\0'; } else { // This should not happen, but handle it anyway free(integer_part); free(fractional_part); free(dollars); return NULL; } // get cent value char cents[256]; int cent_size = sprintf(cents," and %d/100", *fractional_part); free(integer_part); free(fractional_part); // put everything together. return_val = calloc(1, (strlen(dollars) + cent_size + 1)); if (NULL == return_val){ perror("malloc failed"); free(dollars); return NULL; } strncpy(return_val, dollars, strlen(dollars)); strcat(return_val, cents); strcat(return_val, "\0"); free(dollars); return return_val; }
#include <string.h>- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #define ONES_SIZE 10
- #define TEENS_SIZE 6
- #define TENS_SIZE 8
- #define MAX_DOLLAR_SIZE 40
- /*
- Returns(in place): the integer and fractional parts of the double...
- ...effectively the left and right sides of the double.
- */
- void double_to_ints(const double num, int *integer_part, int *fractional_part, const int decimal_places) {
- *integer_part = (int)num;
- double fractional = num - (double)*integer_part;
- *fractional_part = (int)round(fractional * pow(10, decimal_places));
- }
- /*
- Returns: the index of where the key is in the array...
- ...or -1 if the value is not found.
- */
- int find_val_in_array(int *array, int key, int array_size) {
- for (int i = 0; i < array_size; i++) {
- if (key == array[i]){
- return i;
- }
- }
- return -1;
- }
- /*
- Arguments:
- - amount = a double betwen 0.01 and 99.99. Representing the check dollars and cents to convert.
- Returns: A string with the text representation of 'amount'....
- ...or NULL if the value is not found.
- */
- char *checkAmount(double amount) {
char * return_val = NULL;// Your code here!- // input validate
- if (0.00 >= amount || amount > 99.99) {
- return NULL;
- }
return return_val;- char * return_val = NULL;
- // define key value pair of words and their equivelant value as an int.
- int ones_key[] = {0,1,2,3,4,5,6,7,8,9};
- char ones_value[ONES_SIZE][MAX_DOLLAR_SIZE] = {"ZERO", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE"};
- int teens_key[] = {10,11,12,13,14,15};
- char teens_value[TEENS_SIZE][MAX_DOLLAR_SIZE] = {"TEN", "ELEVEN", "TWELVE", "THIRTEEN", "FOURTEEN", "FIFTEEN"};
- int tens_key[] = {20,30,40,50,60,70,80,90};
- char tens_value[TENS_SIZE][MAX_DOLLAR_SIZE] = {"TWENTY", "THIRTY", "FORTY", "FIFTY", "SIXTY", "SEVENTY", "EIGHTY", "NINETY"};
- // define vars!
- int *integer_part = calloc(1, sizeof(int));
- if (NULL == integer_part){
- perror("malloc failed");
- return NULL;
- }
- int *fractional_part = calloc(1, sizeof(int));
- if (NULL == fractional_part){
- perror("malloc failed");
- return NULL;
- }
- int found_pos = -1;
- int len = 0;
- int tens = 0;
- char temp[MAX_DOLLAR_SIZE];
- char *list = NULL;
- char *dollars = calloc(1, MAX_DOLLAR_SIZE);
- if (NULL == dollars){
- perror("malloc failed");
- return NULL;
- }
- // extract integer and fraction from double.
- double_to_ints(amount, integer_part, fractional_part, 2);
- // For each _key list we are checking if the '*integer_part' is in the list. if it is we updated "list" to point to the corresponding _value list...
- if ((found_pos = find_val_in_array(ones_key, *integer_part, ONES_SIZE)) != -1) {
- list = ones_value[found_pos];
- } else if ((found_pos = find_val_in_array(teens_key, *integer_part, TEENS_SIZE)) != -1) {
- list = teens_value[found_pos];
- } else if ((found_pos = find_val_in_array(tens_key, *integer_part, TENS_SIZE)) != -1) {
- list = tens_value[found_pos];
- } else {
- // ... if we dont find a match then its likely that we got 16-19 or something like: [24, 56, 91, ...]
- // we divide by 10 so we can drop the value in the ones place [16 -> 1, 24 -> 2, ...]
- tens = *integer_part / 10;
- if (tens == 1) {
- // if we have a ten then we handle it special due to the 'teens'. get the "ones_key" and append "TEEN" to it...
- // ... for example: ["NINE" + "TEEN" = "NINETEEN"]
- found_pos = find_val_in_array(ones_key, (*integer_part - 10), ONES_SIZE);
- strncpy(temp, ones_value[found_pos], sizeof(temp));
- // EIGHTEEN is a special case since "EIGHT" and "TEEN" share a "T". So we trim the "T"
- if (strncmp(temp, "EIGHT", 6) == 0) {
- strcat(temp, "EEN");
- } else {
- strcat(temp, "TEEN");
- }
- }
- else {
- // non-tens are handled different. exmple: 25
- // find and update temp = "TWENTY"
- found_pos = find_val_in_array(tens_key, (tens * 10), TENS_SIZE);
- strncpy(temp, tens_value[found_pos], sizeof(temp));
- // find and update temp = "TWENTY FIVE"
- int val = (*integer_part % 10);
- strcat(temp, " ");
- strcat(temp, ones_value[val]);
- }
- list = temp;
- }
- if (list != NULL) {
- // Ensure null termination
- len = strlen(list);
- strncpy(dollars, list, len);
- dollars[len] = '\0';
- } else {
- // This should not happen, but handle it anyway
- free(integer_part);
- free(fractional_part);
- free(dollars);
- return NULL;
- }
- // get cent value
- char cents[256];
- int cent_size = sprintf(cents," and %d/100", *fractional_part);
- free(integer_part);
- free(fractional_part);
- // put everything together.
- return_val = calloc(1, (strlen(dollars) + cent_size + 1));
- if (NULL == return_val){
- perror("malloc failed");
- free(dollars);
- return NULL;
- }
- strncpy(return_val, dollars, strlen(dollars));
- strcat(return_val, cents);
- strcat(return_val, "\0");
- free(dollars);
- return return_val;
- }
import codewars_test as test # TODO Write tests import solution # or from solution import example # test.assert_equals(actual, expected, [optional] message) @test.describe("Example") def test_group(): @test.it("test case") def test_case(): test.assert_equals(a([1, 3]), 4) test.assert_equals(a([1, 52, 40, 30]), 123)
- import codewars_test as test
- # TODO Write tests
- import solution # or from solution import example
- # test.assert_equals(actual, expected, [optional] message)
- @test.describe("Example")
- def test_group():
- @test.it("test case")
- def test_case():
test.assert_equals(add([1, 3]), 4)test.assert_equals(add([1, 52, 40, 30]), 123)- test.assert_equals(a([1, 3]), 4)
- test.assert_equals(a([1, 52, 40, 30]), 123)
class IsPrimeNumber: """Returns True if n is a prime number, False otherwise""" def __init__(self, n): self.n = n def calculate(self): # Guard clause if self.n <= 1: return False for i in range(2, int(self.n ** 0.5) + 1): if self.n % i == 0: return False return True # If no divisors found, it's prime class Fizz(IsPrimeNumber): """Returns True if n is divisible by 3, False otherwise""" def calculate(self): return self.n % 3 == 0 class Buzz(IsPrimeNumber): """Returns True if n is divisible by 5, False otherwise""" def calculate(self): return self.n % 5 == 0 class FizzBuzz(IsPrimeNumber): """Returns True if n is divisible by 3 and 5, False otherwise""" def calculate(self): return Fizz(self.n).calculate() and Buzz(self.n).calculate() class CodeWarKata776: """Executes the Fizz, Bizz, FizzBuzz Prime sequence.""" def __init__(self, n): self.n = n def calculate_prime(self): return IsPrimeNumber(self.n).calculate() def calculate_fizz(self): return Fizz(self.n).calculate() def calculate_buzz(self): return Buzz(self.n).calculate() def calculate_fizzbuzz(self): return FizzBuzz(self.n).calculate() def execute(self): if IsPrimeNumber(self.n).calculate(): return 'Prime' if FizzBuzz(self.n).calculate(): return 'FizzBuzz' if Fizz(self.n).calculate(): return 'Fizz' if Buzz(self.n).calculate(): return 'Buzz' return self.n
- class IsPrimeNumber:
- """Returns True if n is a prime number, False otherwise"""
- def __init__(self, n):
- self.n = n
- def calculate(self):
if self.n > 1:for i in range(2, int(self.n ** 0.5) + 1):if self.n % i == 0:return Falsereturn True # If no divisors found, it's primereturn False- # Guard clause
- if self.n <= 1:
- return False
- for i in range(2, int(self.n ** 0.5) + 1):
- if self.n % i == 0:
- return False
- return True # If no divisors found, it's prime
- class Fizz(IsPrimeNumber):
- """Returns True if n is divisible by 3, False otherwise"""
- def calculate(self):
- return self.n % 3 == 0
- class Buzz(IsPrimeNumber):
- """Returns True if n is divisible by 5, False otherwise"""
- def calculate(self):
- return self.n % 5 == 0
- class FizzBuzz(IsPrimeNumber):
- """Returns True if n is divisible by 3 and 5, False otherwise"""
- def calculate(self):
- return Fizz(self.n).calculate() and Buzz(self.n).calculate()
- class CodeWarKata776:
- """Executes the Fizz, Bizz, FizzBuzz Prime sequence."""
- def __init__(self, n):
- self.n = n
- def calculate_prime(self):
- return IsPrimeNumber(self.n).calculate()
- def calculate_fizz(self):
- return Fizz(self.n).calculate()
- def calculate_buzz(self):
- return Buzz(self.n).calculate()
- def calculate_fizzbuzz(self):
- return FizzBuzz(self.n).calculate()
- def execute(self):
- if IsPrimeNumber(self.n).calculate():
- return 'Prime'
- if FizzBuzz(self.n).calculate():
- return 'FizzBuzz'
elif Fizz(self.n).calculate():- if Fizz(self.n).calculate():
- return 'Fizz'
elif Buzz(self.n).calculate():- if Buzz(self.n).calculate():
- return 'Buzz'
- return self.n
Driving Test Examiner on an Alien Planet
Problem Description
You work as a driving test examiner on an alien planet. Your task is to evaluate whether an examinee has passed the exam based on the data you receive and the rules described below.
Input Data
You receive two strings:
-
Indications: Represents the signs and instructions encountered during the exam.
Format:"t=time SYMBOL;"
Example:"t=30 STOP;"
means a STOP sign was encountered at second 30. -
Actions: The examinee's registered actions every second, showing speed and turns if any.
Format: Speeds and turns separated by spaces.
Example:"29 28 28< 27 29 27 0 0 0 0 23> 24 ..."
Legend of Indications and Expected Behavior
Indication | Symbol | Expected Behavior |
---|---|---|
STOP | STOP |
Stop at least 3 seconds with no cars passing |
STOP with cars |
STOP3 (3 cars) |
Stop 3 seconds + 2 seconds for each passing car |
YIELD | YIELD |
Stop ONLY if there are cars passing (2 seconds per car) |
YIELD with cars |
YIELD2 (2 cars) |
Stop according to number of cars (2 seconds per car) |
Speed Limit | SL50 |
Do not exceed the speed limit until another SL appears |
Turn |
TURNL , TURNR
|
Turn left or right as indicated |
Red Light | REDLIGHT3 |
Stop for the specified number of seconds |
Format of Actions
- Data is recorded each and every second of the exam.
- Turns are represented by
<
(left) and>
(right).
Example:78>
means at speed 78, a right turn was made.
Infractions and Evaluation
Minor Infractions (3 minors disqualify)
Infraction | Description |
---|---|
Speeding | Driving over speed limit for 3 consecutive seconds |
Wrong turn | Not turning, turning when not indicated or turning in the wrong direction |
Eliminatory Infractions (1 eliminates immediately)
Infraction | Description |
---|---|
Running a red light | Not stopping or moving before the light turns green |
STOP related infraction | Not stopping at a STOP sign or stopping for less time than required |
Running into traffic | Not waiting necessary time for cars to pass at STOP or YIELD |
Reckless driving | Exceeding speed limit by more than 10 units at any time |
Important Notes
- There will always be a speed limit sign at
t=1
. - Inputs are always valid, no validation required.
- Return
true
if the examinee passes the test,false
otherwise.
Example Input
indications = "t=1 SL30 ; t=7 YIELD2 ; t=13 SL90 ; t=15 TURNR; t=21 REDLIGHT8 ; t=30 STOP;"
actions = "29 28 28 27 29 27 0 0 0 0 23 24 67 72 78> 85 87 86 84 89 0 0 0 0 0 0 0 0 25 0 0 0 34 56"
import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.BiConsumer; import java.util.regex.Matcher; import java.util.regex.Pattern; class DrivingTestEvaluator { static Map<String, BiConsumer<Integer, String>> rules = new HashMap(); static int speedLimit = 0; static int indexLastSpeedLimit = 1; static int indexIndicationList = 0; static int indexActionList = 0; static int minorMistakes = 0; static boolean isEliminated = false; static int currentTime = 0; static int secondsInfringement = 0; static List<String> indicationList; static List<String> actionList; public static boolean evaluate(String indications, String actions) { clearState(); indicationList = Arrays.stream(indications.split(";")).toList(); actionList = Arrays.stream(actions.split(" ")).toList(); refillRules(); for (String indication : indicationList) { processIndication(indication); } return 3 > minorMistakes && !isEliminated; } private static void refillRules() { rules.put("STOP", (DrivingTestEvaluator::processStop)); rules.put("SL", (DrivingTestEvaluator::processSpeedLimit)); rules.put("YIELD", (DrivingTestEvaluator::processYield)); rules.put("TURN", (DrivingTestEvaluator::processTurn)); rules.put("REDLIGHT", (DrivingTestEvaluator::processRedLight)); } private static void processIndication(String indication) { Pattern pattern = Pattern.compile("t=(\\d+)\\s+(\\S+)"); Matcher matcher = pattern.matcher(indication); if (matcher.find()) { Integer time = Integer.valueOf(matcher.group(1)); String instruction = matcher.group(2); rules.keySet().stream().filter(instruction::contains).findFirst() .ifPresent(key -> rules.get(key).accept(time, indication)); } } private static void processTurn(Integer t, String signal) { String direction = ""; Pattern pattern = Pattern.compile("TURN([A-Z])"); Matcher matcher = pattern.matcher(signal); if (matcher.find()) { direction = matcher.group(1); } if (actionList.get(t - 1).endsWith(">") || actionList.get(t - 1).endsWith("<")) { if (actionList.get(t - 1).endsWith(">") && direction.equals("L") || actionList.get(t - 1).endsWith("<") && direction.equals("R")) minorMistakes++; } else { minorMistakes++; } } private static void processRedLight(Integer time, String signal) { Pattern pattern = Pattern.compile("REDLIGHT(\\d+)"); Matcher matcher = pattern.matcher(signal); if (matcher.find()) { processCorrectlyStopped(time, Integer.valueOf(matcher.group(1))); } } private static void processYield(Integer time, String signal) { Integer secondsToStop = 0; Pattern pattern = Pattern.compile("YIELD(\\d+)"); Matcher matcher = pattern.matcher(signal); if (matcher.find()) { secondsToStop += (2 * Integer.valueOf(matcher.group(1))); processCorrectlyStopped(time, secondsToStop); } else { if (Integer.parseInt(actionList.get(time - 1)) == 0) isEliminated = true; } } private static void processStop(Integer time, String signal) { Integer secondsToStop = 3; Pattern pattern = Pattern.compile("STOP(\\d+)"); Matcher matcher = pattern.matcher(signal); if (matcher.find()) { secondsToStop += Integer.parseInt(matcher.group(1)) * 2; } processCorrectlyStopped(time, secondsToStop); } private static void processCorrectlyStopped(Integer time, Integer secondsToStop) { if (Integer.parseInt(actionList.get(time - 1)) > 0) { isEliminated = true; return; } while (secondsToStop != 0) { if (time > actionList.size() || Integer.parseInt(actionList.get(time - 1)) > 0) { isEliminated = true; return; } time++; secondsToStop--; } } private static void processSpeedLimit(Integer time, String signal) { Integer digits = 0; for (int i = indexLastSpeedLimit; i < time; i++) { String velocity = actionList.get(i); Pattern pattern = Pattern.compile("(\\d+)"); Matcher matcher = pattern.matcher(velocity); if (matcher.find()) { digits = Integer.parseInt(matcher.group(1)); } if (digits > speedLimit) { secondsInfringement++; } else { secondsInfringement = 0; } if (secondsInfringement > 2) minorMistakes++; } Pattern pattern = Pattern.compile("SL(\\d+)"); Matcher matcher = pattern.matcher(signal); if (matcher.find()) { speedLimit = Integer.valueOf(matcher.group(1)); } indexLastSpeedLimit = time - 1; } private static void clearState() { speedLimit = 0; indexLastSpeedLimit = 1; indexIndicationList = 0; indexActionList = 0; minorMistakes = 0; isEliminated = false; currentTime = 0; secondsInfringement = 0; } }
- import java.util.Arrays;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.function.BiConsumer;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- class DrivingTestEvaluator {
- static Map<String, BiConsumer<Integer, String>> rules = new HashMap();
- static int speedLimit = 0;
- static int indexLastSpeedLimit = 1;
- static int indexIndicationList = 0;
- static int indexActionList = 0;
- static int minorMistakes = 0;
- static boolean isEliminated = false;
- static int currentTime = 0;
- static int secondsInfringement = 0;
- static List<String> indicationList;
- static List<String> actionList;
- public static boolean evaluate(String indications, String actions) {
- clearState();
- indicationList = Arrays.stream(indications.split(";")).toList();
- actionList = Arrays.stream(actions.split(" ")).toList();
- refillRules();
- for (String indication : indicationList) {
- processIndication(indication);
- }
- return 3 > minorMistakes && !isEliminated;
- }
- private static void refillRules() {
- rules.put("STOP", (DrivingTestEvaluator::processStop));
- rules.put("SL", (DrivingTestEvaluator::processSpeedLimit));
- rules.put("YIELD", (DrivingTestEvaluator::processYield));
- rules.put("TURN", (DrivingTestEvaluator::processTurn));
- rules.put("REDLIGHT", (DrivingTestEvaluator::processRedLight));
- }
- private static void processIndication(String indication) {
- Pattern pattern = Pattern.compile("t=(\\d+)\\s+(\\S+)");
- Matcher matcher = pattern.matcher(indication);
- if (matcher.find()) {
- Integer time = Integer.valueOf(matcher.group(1));
- String instruction = matcher.group(2);
- rules.keySet().stream().filter(instruction::contains).findFirst()
- .ifPresent(key -> rules.get(key).accept(time, indication));
- }
- }
- private static void processTurn(Integer t, String signal) {
- String direction = "";
- Pattern pattern = Pattern.compile("TURN([A-Z])");
- Matcher matcher = pattern.matcher(signal);
- if (matcher.find()) {
- direction = matcher.group(1);
- }
- if (actionList.get(t - 1).endsWith(">") || actionList.get(t - 1).endsWith("<")) {
- if (actionList.get(t - 1).endsWith(">") && direction.equals("L")
- || actionList.get(t - 1).endsWith("<") && direction.equals("R"))
- minorMistakes++;
- } else {
- minorMistakes++;
- }
- }
- private static void processRedLight(Integer time, String signal) {
- Pattern pattern = Pattern.compile("REDLIGHT(\\d+)");
- Matcher matcher = pattern.matcher(signal);
- if (matcher.find()) {
- processCorrectlyStopped(time, Integer.valueOf(matcher.group(1)));
- }
- }
- private static void processYield(Integer time, String signal) {
- Integer secondsToStop = 0;
- Pattern pattern = Pattern.compile("YIELD(\\d+)");
- Matcher matcher = pattern.matcher(signal);
- if (matcher.find()) {
- secondsToStop += (2 * Integer.valueOf(matcher.group(1)));
- processCorrectlyStopped(time, secondsToStop);
- } else {
- if (Integer.parseInt(actionList.get(time - 1)) == 0)
- isEliminated = true;
- }
- }
- private static void processStop(Integer time, String signal) {
- Integer secondsToStop = 3;
- Pattern pattern = Pattern.compile("STOP(\\d+)");
- Matcher matcher = pattern.matcher(signal);
- if (matcher.find()) {
- secondsToStop += Integer.parseInt(matcher.group(1)) * 2;
- }
- processCorrectlyStopped(time, secondsToStop);
- }
- private static void processCorrectlyStopped(Integer time, Integer secondsToStop) {
- if (Integer.parseInt(actionList.get(time - 1)) > 0) {
- isEliminated = true;
- return;
- }
- while (secondsToStop != 0) {
- if (time > actionList.size() || Integer.parseInt(actionList.get(time - 1)) > 0) {
- isEliminated = true;
- return;
- }
- time++;
- secondsToStop--;
- }
- }
- private static void processSpeedLimit(Integer time, String signal) {
- Integer digits = 0;
- for (int i = indexLastSpeedLimit; i < time; i++) {
- String velocity = actionList.get(i);
- Pattern pattern = Pattern.compile("(\\d+)");
- Matcher matcher = pattern.matcher(velocity);
- if (matcher.find()) {
- digits = Integer.parseInt(matcher.group(1));
- }
- if (digits > speedLimit) {
- secondsInfringement++;
- } else {
- secondsInfringement = 0;
- }
- if (secondsInfringement > 2)
- minorMistakes++;
- }
- Pattern pattern = Pattern.compile("SL(\\d+)");
- Matcher matcher = pattern.matcher(signal);
- if (matcher.find()) {
- speedLimit = Integer.valueOf(matcher.group(1));
- }
- indexLastSpeedLimit = time - 1;
- }
- private static void clearState() {
- speedLimit = 0;
- indexLastSpeedLimit = 1;
- indexIndicationList = 0;
- indexActionList = 0;
- minorMistakes = 0;
- isEliminated = false;
- currentTime = 0;
- secondsInfringement = 0;
- }
public class DrivingTestEvaluator {static int knockoutFoul;static int mildFoul;static List<String> actions;static int currentIndex;public static boolean evaluate(String exam, String road) {knockoutFoul = 0;mildFoul = 0;currentIndex = 0;actions = Arrays.asList(exam.trim().split("\\s+"));List<String> rules = Arrays.asList(road.trim().split("\\s+"));for (String rule : rules) {if (rule.startsWith("SL")) {comprobateSpeedLimit(rule);} else if (rule.startsWith("STOP")) {comprobateStop(rule);} else if (rule.startsWith("YIELD")) {comprobateYield(rule);} else if (rule.startsWith("TURN")) {comprobateTurn(rule);} else if (rule.startsWith("R")) {comprobateRedLight(rule);}if (knockoutFoul > 0) return false;}return mildFoul < 3;}public static void comprobateSpeedLimit(String rule) {String[] parts = rule.substring(2).split("_");int speedLimit = Integer.parseInt(parts[0]);int duration = Integer.parseInt(parts[1]);int overLimitCounter = 0;boolean minorCounted = false;for (int i = 0; i < duration && currentIndex + i < actions.size(); i++) {int speed = extractSpeed(actions.get(currentIndex + i));if (speed > speedLimit + 10) {knockoutFoul++;return;}if (speed > speedLimit) {overLimitCounter++;} else {overLimitCounter = 0;}if (overLimitCounter >= 3 && !minorCounted) {mildFoul++;minorCounted = true;}}currentIndex += Math.min(duration, actions.size() - currentIndex);}public static void comprobateStop(String rule) {int cars = rule.length() > 4 ? Integer.parseInt(rule.substring(4)) : 0;int requiredStop = 3 + (2 * cars);int stopCount = 0;while (currentIndex < actions.size() && extractSpeed(actions.get(currentIndex)) == 0) {stopCount++;currentIndex++;}if (stopCount == 0) {knockoutFoul++;} else if (stopCount < requiredStop) {if (stopCount >= 2 * cars) mildFoul++;else knockoutFoul++;}}public static void comprobateYield(String rule) {int cars = rule.length() > 5 ? Integer.parseInt(rule.substring(5)) : 0;int requiredStop = 2 * cars;int stopCount = 0;while (currentIndex < actions.size() && extractSpeed(actions.get(currentIndex)) == 0) {stopCount++;currentIndex++;}if (cars == 0) {if (stopCount >= 2) knockoutFoul++;} else {if (stopCount < requiredStop) {knockoutFoul++;} else if (stopCount < requiredStop + 3) {mildFoul++;}}}public static void comprobateTurn(String rule) {String requiredDirection = rule.equals("TURNR") ? ">" : "<";boolean turned = false;for (int i = currentIndex; i < actions.size(); i++) {if (actions.get(i).endsWith(requiredDirection)) {turned = true;currentIndex = i + 1;break;}}if (!turned) {mildFoul++;}}public static void comprobateRedLight(String rule) {int duration = Integer.parseInt(rule.substring(1));boolean failed = false;for (int i = 0; i < duration && currentIndex + i < actions.size(); i++) {if (extractSpeed(actions.get(currentIndex + i)) != 0) {failed = true;}}if (failed) {knockoutFoul++;}currentIndex += Math.min(duration, actions.size() - currentIndex);}public static int extractSpeed(String action) {if (action.endsWith("<") || action.endsWith(">")) {return Integer.parseInt(action.substring(0, action.length() - 1));}return Integer.parseInt(action);}- }
import static org.junit.jupiter.api.Assertions.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Random; import org.junit.jupiter.api.Test; class test { @Test void SampleTest() { assertTrue(DrivingTestEvaluator.evaluate("t=1 SL30;t=5 TURNR;t=6 SL35;t=14 STOP1;", "28 27 30 29 25> 33 30 31 30 29 32 30 31 0 0 0 0 0")); assertFalse(DrivingTestEvaluator.evaluate("t=1 SL30;t=5 TURNR;t=6 SL35;t=14 STOP1;", "28 27 30 29 25> 33 30 31 30 29 32 30 31 0 0 50 0 0")); assertTrue( DrivingTestEvaluator.evaluate("t=1 SL50;t=3 SL30;t=7 TURNR;t=8 TURNL;", "48 49 28 30 29 30 25> 20<")); assertTrue(DrivingTestEvaluator.evaluate("t=1 SL30;t=5 TURNR;t=6 SL35;t=13 YIELD2;", "28 29 30 30 25> 32 33 31 30 34 30 33 0 0 0 0")); assertFalse(DrivingTestEvaluator.evaluate("t=1 SL30;t=5 TURNR;t=6 SL35;t=13 YIELD2;", "28 29 30 30 25> 32 33 31 30 34 30 33 10 9 8 7")); } @Test void ComplexesTest() { assertTrue( DrivingTestEvaluator.evaluate("t=1 SL25;t=5 TURNL;t=6 SL30;t=9 SL20;t=13 TURNR;t=14 SL40;t=22 STOP1;", "25 24 25 20 18< 22 30 28 18 20 19 20 19> 38 39 35 40 39 40 38 40 0 0 0 0 0")); assertTrue(DrivingTestEvaluator.evaluate( "t=1 SL30;t=6 TURNL;t=7 SL40;t=13 SL25;t=17 TURNR;t=18 SL50;t=26 SL35;t=30 STOP1;", "30 29 30 28 26 25< 35 38 40 39 40 38 22 24 23 25 20> 45 48 50 49 50 45 47 49 30 32 35 34 0 0 0 0 0")); assertFalse(DrivingTestEvaluator.evaluate( "t=1 SL20;t=5 TURNR;t=6 SL30;t=11 SL45;t=17 TURNL;t=18 SL50;t=25 SL40;t=29 STOP1;", "20 19 18 17 15> 25 30 29 28 27 50 47 46 48 45 44 45 43 49 50 48 49 45 38 39 37 40 10 5 5 5 5")); assertTrue(DrivingTestEvaluator.evaluate("t=1 SL25;t=5 STOP1;t=10 SL20;", "25 24 25 23 0 0 0 0 0 18 20 19 20")); assertTrue( DrivingTestEvaluator.evaluate("t=1 SL25;t=5 TURNL;t=6 SL30;t=9 SL20;t=13 TURNR;t=14 SL40;t=22 STOP1;", "25 24 25 26 25< 30 28 30 22 20 19 20 19> 38 39 35 40 39 40 38 40 0 0 0 0 0")); assertTrue(DrivingTestEvaluator.evaluate( "t=1 SL30;t=6 TURNL;t=7 SL40;t=13 SL25;t=17 TURNR;t=18 SL50;t=26 SL35;t=30 STOP1;", "30 29 30 31 30 25 35 38 40 39 40 38 22 24 23 25 20 20 45 48 50 49 50 45 47 49 30 32 35 0 0 0 0 0")); assertTrue(DrivingTestEvaluator.evaluate("t=1 SL50;t=11 TURNL;t=12 STOP1;", "50 49 50 48 47 46 45 44 43 42 30< 0 0 0 0 0")); assertFalse(DrivingTestEvaluator.evaluate( "t=1 SL30;t=6 TURNL;t=7 SL40;t=13 YIELD;t=14 SL25;t=18 TURNR;t=19 SL50;t=27 SL35;t=31 STOP1;", "30 29 30 31 30 25 35 38 40 39 40 38 0 0 25 24 23 25 20 50 49 50 48 50 49 50 50 35 34 35 0 0 0 0 0")); assertFalse(DrivingTestEvaluator.evaluate( "t=1 SL25;t=5 TURNL;t=6 SL30;t=9 YIELD;t=10 SL20;t=14 TURNR;t=15 SL40;t=23 STOP1;", "25 24 25 26 25< 30 28 30 0 0 20 19 18 20 19> 38 39 35 40 39 40 0 0 0 0 0")); assertTrue(DrivingTestEvaluator.evaluate( "t=1 SL25;t=5 TURNL;t=6 SL30;t=9 YIELD2;t=11 SL20;t=15 TURNR;t=16 SL40;t=24 STOP1;", "25 24 25 26 25< 30 28 30 0 0 0 0 22 20 19 20 19 38 39 35 40 39 40 0 0 0 0 0")); } @Test void StopTest() { assertTrue(DrivingTestEvaluator.evaluate("t=1 STOP;", "0 0 0")); assertTrue(DrivingTestEvaluator.evaluate("t=1 STOP3;", "0 0 0 0 0 0 0 0 0")); assertTrue(DrivingTestEvaluator.evaluate("t=1 STOP1;", "0 0 0 0 0")); assertFalse(DrivingTestEvaluator.evaluate("t=1 STOP3;", "0 0 0 0 2 2 2 2 2")); assertFalse(DrivingTestEvaluator.evaluate("t=1 STOP1;", "0 0")); assertFalse(DrivingTestEvaluator.evaluate("t=1 STOP2;", "0 0 0 0 0 0")); } @Test void TurnTest() { assertTrue(DrivingTestEvaluator.evaluate("t=1 TURNR;t=2 SL25;", "20> 25")); assertTrue(DrivingTestEvaluator.evaluate("t=1 TURNR;t=2 SL25;t=3 TURNR;t=4 SL25;t=5 TURNL;t=6 SL25;", "22> 25 23> 25 15< 25")); assertTrue(DrivingTestEvaluator.evaluate( "t=1 TURNR;t=2 SL25;t=3 SL25;t=4 TURNR;t=5 SL25;t=6 TURNL;t=7 SL25;t=8 TURNR;t=9 SL25;t=10 TURNR;t=11 SL25;", "10> 25 24 19> 25 18< 25 22> 25 23> 25")); assertFalse(DrivingTestEvaluator.evaluate( "t=1 TURNL;t=2 SL25;t=3 TURNR;t=4 SL25;t=5 TURNL;t=6 SL25;t=7 TURNL;t=8 SL25;t=9 TURNR;t=10 SL25;", "20 25 19 25 18 25 17 25 16 25")); assertTrue(DrivingTestEvaluator.evaluate("t=1 TURNR;t=2 SL25;", "30< 25")); assertFalse(DrivingTestEvaluator.evaluate( "t=1 TURNL;t=2 SL25;t=3 TURNR;t=4 SL25;t=5 TURNR;t=6 SL25;t=7 TURNL;t=8 SL25;t=9 TURNR;t=10 SL25;", "22 25 23 25 21 25 19 25 18> 25")); } @Test void SpeedLimitTest() { assertTrue(DrivingTestEvaluator.evaluate("t=1 SL20;t=6 TURNR;t=7 SL40;t=13 STOP1;t=18 SL50", "20 19 18 17 20 15> 38 40 39 40 38 37 0 0 0 0 0 48 45")); assertFalse(DrivingTestEvaluator.evaluate("t=1 SL30;t=6 SL40;t=13 STOP1;", "30 29 28 27 30 35 45 39 40 38 37 0 0 0 0 0")); assertTrue(DrivingTestEvaluator.evaluate("t=1 SL50;t=11 TURNL;", "50 49 50 48 47 46 45 44 43 42 30<")); assertTrue(DrivingTestEvaluator.evaluate("t=1 SL50;t=11 TURNL;", "50 49 50 48 47 60 45 44 43 42 30")); } @Test void YieldTest() { assertTrue(DrivingTestEvaluator.evaluate("t=1 YIELD;t=1 SL25;t=6 STOP1;", "20 22 25 24 23 0 0 0 0 0")); assertFalse(DrivingTestEvaluator.evaluate("t=1 YIELD;t=3 SL25;t=8 STOP1;", "0 15 20 22 25 24 23 0 0 0 0 0")); assertTrue(DrivingTestEvaluator.evaluate("t=1 YIELD2;t=5 SL30;t=9 TURNR;", "0 0 0 0 28 29 30 25 22>")); assertFalse(DrivingTestEvaluator.evaluate("t=1 YIELD2;t=4 SL30;t=9 TURNR;", "0 10 0 0 28 29 30 25 22>")); } @Test void RandomTest() { for (int i = 0; i < 1000; i++) { String indications = generateIndications(); String actions = generateActions(indications); assertTrue(DrivingTestEvaluator.evaluate(indications, actions)); } } public static String generateIndications() { ArrayList<String> types = new ArrayList<>(Arrays.asList("SL", "TURNL", "TURNR", "YIELD", "STOP", "REDLIGHT")); StringBuilder sb = new StringBuilder(); Random random = new Random(); int currentTime = 1; sb.append("t=").append(currentTime).append(" SL").append(random.nextInt(50) + 20).append(";"); String prev = "SL"; for (int i = 0; i < 8; i++) { Collections.shuffle(types); String current = types.get(0); while ("SL".equals(current) && "SL".equals(prev)) { Collections.shuffle(types); current = types.get(0); } int timeGap = random.nextInt(4) + 1; currentTime += timeGap; sb.append("t=").append(currentTime).append(" ").append(current); if ("SL".equals(current)) { int limit = random.nextInt(50) + 20; sb.append(limit); } else if ("YIELD".equals(current)) { int cars = random.nextInt(5); if (cars > 0) sb.append(cars); currentTime += cars * 2; } else if ("STOP".equals(current)) { int cars = random.nextInt(5); if (cars > 0) sb.append(cars); currentTime += 3 + cars * 2; } else if ("REDLIGHT".equals(current)) { int seconds = random.nextInt(5) + 1; sb.append(seconds); currentTime += seconds; } sb.append(";"); prev = current; } return sb.toString().trim(); } public static String generateActions(String indications) { String[] trafficSigns = indications.split(";"); List<String> actions = new ArrayList<>(); Random random = new Random(); int currentSecond = 1; int speedLimit = 80; int SignalNumberIteration = 0; for (String signEntry : trafficSigns) { SignalNumberIteration++; signEntry = signEntry.trim(); if (signEntry.isEmpty()) continue; String[] parts = signEntry.split(" "); int time = Integer.parseInt(parts[0].substring(2)); String sign = parts[1]; while (currentSecond < time) { int limit = speedLimit + 1; int v = Math.max(1, random.nextInt(limit)); actions.add(String.valueOf(v)); currentSecond++; } if (sign.startsWith("SL")) { speedLimit = Integer.parseInt(sign.substring(2)); actions.add(String.valueOf(random.nextInt(speedLimit + 1))); currentSecond++; } else if (sign.startsWith("YIELD")) { if (SignalNumberIteration == 9 && sign.matches("YIELD")) { actions.add(String.valueOf(random.nextInt(1, speedLimit))); } int cars = (sign.length() > 5) ? Integer.parseInt(sign.substring(5)) : 0; int secs = cars * 2; for (int j = 0; j < secs; j++) { actions.add("0"); currentSecond++; } } else if (sign.startsWith("STOP")) { int cars = (sign.length() > 4) ? Integer.parseInt(sign.substring(4)) : 0; int secs = 3 + 2 * cars; for (int j = 0; j < secs; j++) { actions.add("0"); currentSecond++; } } else if (sign.startsWith("REDLIGHT")) { int secs = Integer.parseInt(sign.substring(8)); for (int j = 0; j < secs; j++) { actions.add("0"); currentSecond++; } } else if (sign.equals("TURNL")) { actions.add(random.nextInt(speedLimit + 1) + "<"); currentSecond++; } else if (sign.equals("TURNR")) { actions.add(random.nextInt(speedLimit + 1) + ">"); currentSecond++; } } return String.join(" ", actions); } }
- import static org.junit.jupiter.api.Assertions.*;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collections;
- import java.util.List;
- import java.util.Random;
- import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;// TODO: Replace examples and use TDD by writing your own tests- class test {
class SolutionTest {@Test- @Test
- void SampleTest() {
assertTrue(DrivingTestEvaluator.evaluate("SL30_4 TURNR SL35_8 STOP1", "28 27 30 29> 36 38 37 0 0 0 0 0"));assertFalse(DrivingTestEvaluator.evaluate("SL30_4 TURNR SL35_8 STOP1", "28 27 30 29> 36 38 37 0 0 0 50 30"));assertTrue(DrivingTestEvaluator.evaluate("SL50_2 SL30_4 TURNR TURNL", "48 51 21> 28 30< 22"));assertFalse(DrivingTestEvaluator.evaluate("SL30_4 TURNR SL35_7 YIELD2", "28 27 30 32> 36 38 0 0 0 0 60"));assertTrue(DrivingTestEvaluator.evaluate("SL40_3 YIELD SL25_5 TURNR", "39 40 41 24 25 23 25> 22"));- assertTrue(DrivingTestEvaluator.evaluate("t=1 SL30;t=5 TURNR;t=6 SL35;t=14 STOP1;",
- "28 27 30 29 25> 33 30 31 30 29 32 30 31 0 0 0 0 0"));
- assertFalse(DrivingTestEvaluator.evaluate("t=1 SL30;t=5 TURNR;t=6 SL35;t=14 STOP1;",
- "28 27 30 29 25> 33 30 31 30 29 32 30 31 0 0 50 0 0"));
- assertTrue(
- DrivingTestEvaluator.evaluate("t=1 SL50;t=3 SL30;t=7 TURNR;t=8 TURNL;", "48 49 28 30 29 30 25> 20<"));
- assertTrue(DrivingTestEvaluator.evaluate("t=1 SL30;t=5 TURNR;t=6 SL35;t=13 YIELD2;",
- "28 29 30 30 25> 32 33 31 30 34 30 33 0 0 0 0"));
- assertFalse(DrivingTestEvaluator.evaluate("t=1 SL30;t=5 TURNR;t=6 SL35;t=13 YIELD2;",
- "28 29 30 30 25> 32 33 31 30 34 30 33 10 9 8 7"));
- }
- @Test
- void ComplexesTest() {
assertTrue(DrivingTestEvaluator.evaluate("SL25_4 TURNL SL30_3 SL20_4 TURNR SL40_8 STOP1","25 24 25 26> 30 29 30 22 18 20 24> 40 39 40 0 0 0 0 0"));assertTrue(DrivingTestEvaluator.evaluate("SL30_5 TURNL SL40_6 SL25_4 TURNR SL50_8 SL35_3 STOP1","30 29 30 31 30> 40 39 38 40 39 40> 25 24 23 25> 50 49 50 48 50 49 50 50> 35 34 35 0 0 0 0 0"));assertFalse(DrivingTestEvaluator.evaluate("SL20_4 TURNR SL30_5 SL45_6 TURNL SL50_7 SL40_4 STOP1","20 19 20 21> 30 29 30 31 32> 45 44 46 45 47 48> 50 49 50 51 50 52 53> 40 39 40 10 5 5 5 5"));assertFalse(DrivingTestEvaluator.evaluate("SL25_4 STOP1 SL20_4", "30 29 30 31 0 0 0 0 0 < 13 15 18 15"));assertTrue(DrivingTestEvaluator.evaluate("SL25_4 TURNL SL30_3 SL20_4 TURNR SL40_8 STOP1","25 24 25 26> 30 29 30 22 18 20 24> 40 39 40 0 0 0 0 0"));assertFalse(DrivingTestEvaluator.evaluate("SL30_5 TURNL SL40_6 SL25_4 TURNR SL50_8 SL35_3 STOP1","30 29 30 31 30> 40 39 38 40 39 40> 25 24 23 25> 50 49 50 48 50 49 50 50> 35 34 35 0 0 0 0 0"));assertTrue(DrivingTestEvaluator.evaluate("SL50_10 TURNL R", "50 49 50 48 50 49 50 50 > 0 0 0 0 0"));assertFalse(DrivingTestEvaluator.evaluate("SL30_5 TURNL SL40_6 YIELD SL25_4 TURNR SL50_8 SL35_3 STOP1","30 29 30 31 30> 40 39 38 40 39 40 0 0 25 24 23 25> 50 49 50 48 50 49 50 50> 35 34 35 0 0 0 0 0"));assertTrue(DrivingTestEvaluator.evaluate("SL25_4 TURNL SL30_3 YIELD SL20_4 TURNR SL40_8 STOP1","25 24 25 26> 30 29 30 22 18 20 24> 40 39 40 0 0 0 0 0"));assertTrue(DrivingTestEvaluator.evaluate("SL25_4 TURNL SL30_3 YIELD2 SL20_4 TURNR SL40_8 STOP1","25 24 25 26> 30 29 30 0 0 0 0 22 18 20 24> 40 39 40 0 0 0 0 0"));- assertTrue(
- DrivingTestEvaluator.evaluate("t=1 SL25;t=5 TURNL;t=6 SL30;t=9 SL20;t=13 TURNR;t=14 SL40;t=22 STOP1;",
- "25 24 25 20 18< 22 30 28 18 20 19 20 19> 38 39 35 40 39 40 38 40 0 0 0 0 0"));
- assertTrue(DrivingTestEvaluator.evaluate(
- "t=1 SL30;t=6 TURNL;t=7 SL40;t=13 SL25;t=17 TURNR;t=18 SL50;t=26 SL35;t=30 STOP1;",
- "30 29 30 28 26 25< 35 38 40 39 40 38 22 24 23 25 20> 45 48 50 49 50 45 47 49 30 32 35 34 0 0 0 0 0"));
- assertFalse(DrivingTestEvaluator.evaluate(
- "t=1 SL20;t=5 TURNR;t=6 SL30;t=11 SL45;t=17 TURNL;t=18 SL50;t=25 SL40;t=29 STOP1;",
- "20 19 18 17 15> 25 30 29 28 27 50 47 46 48 45 44 45 43 49 50 48 49 45 38 39 37 40 10 5 5 5 5"));
- assertTrue(DrivingTestEvaluator.evaluate("t=1 SL25;t=5 STOP1;t=10 SL20;", "25 24 25 23 0 0 0 0 0 18 20 19 20"));
- assertTrue(
- DrivingTestEvaluator.evaluate("t=1 SL25;t=5 TURNL;t=6 SL30;t=9 SL20;t=13 TURNR;t=14 SL40;t=22 STOP1;",
- "25 24 25 26 25< 30 28 30 22 20 19 20 19> 38 39 35 40 39 40 38 40 0 0 0 0 0"));
- assertTrue(DrivingTestEvaluator.evaluate(
- "t=1 SL30;t=6 TURNL;t=7 SL40;t=13 SL25;t=17 TURNR;t=18 SL50;t=26 SL35;t=30 STOP1;",
- "30 29 30 31 30 25 35 38 40 39 40 38 22 24 23 25 20 20 45 48 50 49 50 45 47 49 30 32 35 0 0 0 0 0"));
- assertTrue(DrivingTestEvaluator.evaluate("t=1 SL50;t=11 TURNL;t=12 STOP1;",
- "50 49 50 48 47 46 45 44 43 42 30< 0 0 0 0 0"));
- assertFalse(DrivingTestEvaluator.evaluate(
- "t=1 SL30;t=6 TURNL;t=7 SL40;t=13 YIELD;t=14 SL25;t=18 TURNR;t=19 SL50;t=27 SL35;t=31 STOP1;",
- "30 29 30 31 30 25 35 38 40 39 40 38 0 0 25 24 23 25 20 50 49 50 48 50 49 50 50 35 34 35 0 0 0 0 0"));
- assertFalse(DrivingTestEvaluator.evaluate(
- "t=1 SL25;t=5 TURNL;t=6 SL30;t=9 YIELD;t=10 SL20;t=14 TURNR;t=15 SL40;t=23 STOP1;",
- "25 24 25 26 25< 30 28 30 0 0 20 19 18 20 19> 38 39 35 40 39 40 0 0 0 0 0"));
- assertTrue(DrivingTestEvaluator.evaluate(
- "t=1 SL25;t=5 TURNL;t=6 SL30;t=9 YIELD2;t=11 SL20;t=15 TURNR;t=16 SL40;t=24 STOP1;",
- "25 24 25 26 25< 30 28 30 0 0 0 0 22 20 19 20 19 38 39 35 40 39 40 0 0 0 0 0"));
- }
- @Test
- void StopTest() {
assertTrue(DrivingTestEvaluator.evaluate("STOP", "0 0"));assertTrue(DrivingTestEvaluator.evaluate("STOP3", "0 0 0 0 0 0 0 0"));assertTrue(DrivingTestEvaluator.evaluate("STOP1", "0 0 0 0"));assertFalse(DrivingTestEvaluator.evaluate("STOP3", "0 0 0 0 2 2 2"));assertFalse(DrivingTestEvaluator.evaluate("STOP", "0 "));assertFalse(DrivingTestEvaluator.evaluate("STOP2", "0 0 "));- assertTrue(DrivingTestEvaluator.evaluate("t=1 STOP;", "0 0 0"));
- assertTrue(DrivingTestEvaluator.evaluate("t=1 STOP3;", "0 0 0 0 0 0 0 0 0"));
- assertTrue(DrivingTestEvaluator.evaluate("t=1 STOP1;", "0 0 0 0 0"));
- assertFalse(DrivingTestEvaluator.evaluate("t=1 STOP3;", "0 0 0 0 2 2 2 2 2"));
- assertFalse(DrivingTestEvaluator.evaluate("t=1 STOP1;", "0 0"));
- assertFalse(DrivingTestEvaluator.evaluate("t=1 STOP2;", "0 0 0 0 0 0"));
- }
- @Test
- void TurnTest() {
assertTrue(DrivingTestEvaluator.evaluate("TURNR SL25_1 ", "> 60"));assertTrue(DrivingTestEvaluator.evaluate("TURNR SL25_1 TURNR SL25_1 TURNL SL25_1 ", "> 20 > 25 < 15 "));- assertTrue(DrivingTestEvaluator.evaluate("t=1 TURNR;t=2 SL25;", "20> 25"));
- assertTrue(DrivingTestEvaluator.evaluate("t=1 TURNR;t=2 SL25;t=3 TURNR;t=4 SL25;t=5 TURNL;t=6 SL25;",
- "22> 25 23> 25 15< 25"));
- assertTrue(DrivingTestEvaluator.evaluate(
"TURNR SL25_1 SL25_1 TURNR SL25_1 TURNL SL25_1 TURNR SL25_1 TURNR SL25_1 ","> 10 > 20 < 25 > 15 > 20"));assertFalse(DrivingTestEvaluator.evaluate("TURNL SL25_1 TURNR SL25_1 TURNL SL25_1 TURNL SL25_1 TURNR SL25_1 ","> 50 > 60 < 40 < 30 > 70 "));assertFalse(DrivingTestEvaluator.evaluate("TURNL SL25_1 TURNR SL25_1 TURNR SL25_1 TURNL SL25_1 TURNR SL25_1 ","> 50 > 60 > 70 < 40 > 30"));assertFalse(DrivingTestEvaluator.evaluate("TURNL SL25_1 TURNR SL25_1 TURNL SL25_1 TURNL SL25_1 TURNR SL25_1 ","> 50 < 30 < 40 > 60 > 70 "));assertFalse(DrivingTestEvaluator.evaluate("TURNR SL25_1 ", "< 40 "));assertFalse(DrivingTestEvaluator.evaluate("TURNL SL25_1 TURNR SL25_1 TURNR SL25_1 TURNL SL25_1 TURNR SL25_1 ","> 50 > 60 > 70 < 40 > 30"));- "t=1 TURNR;t=2 SL25;t=3 SL25;t=4 TURNR;t=5 SL25;t=6 TURNL;t=7 SL25;t=8 TURNR;t=9 SL25;t=10 TURNR;t=11 SL25;",
- "10> 25 24 19> 25 18< 25 22> 25 23> 25"));
- assertFalse(DrivingTestEvaluator.evaluate(
- "t=1 TURNL;t=2 SL25;t=3 TURNR;t=4 SL25;t=5 TURNL;t=6 SL25;t=7 TURNL;t=8 SL25;t=9 TURNR;t=10 SL25;",
- "20 25 19 25 18 25 17 25 16 25"));
- assertTrue(DrivingTestEvaluator.evaluate("t=1 TURNR;t=2 SL25;", "30< 25"));
- assertFalse(DrivingTestEvaluator.evaluate(
- "t=1 TURNL;t=2 SL25;t=3 TURNR;t=4 SL25;t=5 TURNR;t=6 SL25;t=7 TURNL;t=8 SL25;t=9 TURNR;t=10 SL25;",
- "22 25 23 25 21 25 19 25 18> 25"));
- }
- @Test
- void SpeedLimitTest() {
- assertTrue(DrivingTestEvaluator.evaluate("t=1 SL20;t=6 TURNR;t=7 SL40;t=13 STOP1;t=18 SL50",
- "20 19 18 17 20 15> 38 40 39 40 38 37 0 0 0 0 0 48 45"));
- assertFalse(DrivingTestEvaluator.evaluate("t=1 SL30;t=6 SL40;t=13 STOP1;",
- "30 29 28 27 30 35 45 39 40 38 37 0 0 0 0 0"));
- assertTrue(DrivingTestEvaluator.evaluate("t=1 SL50;t=11 TURNL;", "50 49 50 48 47 46 45 44 43 42 30<"));
- assertTrue(DrivingTestEvaluator.evaluate("t=1 SL50;t=11 TURNL;", "50 49 50 48 47 60 45 44 43 42 30"));
- }
- @Test
- void YieldTest() {
- assertTrue(DrivingTestEvaluator.evaluate("t=1 YIELD;t=1 SL25;t=6 STOP1;", "20 22 25 24 23 0 0 0 0 0"));
- assertFalse(DrivingTestEvaluator.evaluate("t=1 YIELD;t=3 SL25;t=8 STOP1;", "0 15 20 22 25 24 23 0 0 0 0 0"));
- assertTrue(DrivingTestEvaluator.evaluate("t=1 YIELD2;t=5 SL30;t=9 TURNR;", "0 0 0 0 28 29 30 25 22>"));
- assertFalse(DrivingTestEvaluator.evaluate("t=1 YIELD2;t=4 SL30;t=9 TURNR;", "0 10 0 0 28 29 30 25 22>"));
- }
- @Test
- void RandomTest() {
- for (int i = 0; i < 1000; i++) {
- String indications = generateIndications();
- String actions = generateActions(indications);
- assertTrue(DrivingTestEvaluator.evaluate(indications, actions));
- }
- }
public static String generateIndications() {ArrayList<String> types = new ArrayList<>(Arrays.asList("SL", "TURNL", "TURNR", "YIELD", "STOP", "R"));- public static String generateIndications() {
- ArrayList<String> types = new ArrayList<>(Arrays.asList("SL", "TURNL", "TURNR", "YIELD", "STOP", "REDLIGHT"));
- StringBuilder sb = new StringBuilder();
StringBuilder sb2 = new StringBuilder();- Random random = new Random();
sb2.append(types.get(0) + random.nextInt(20, 70) + "_" + random.nextInt(1, 10));sb.append(sb2 + " ");- int currentTime = 1;
- sb.append("t=").append(currentTime).append(" SL").append(random.nextInt(50) + 20).append(";");
- String prev = "SL";
- for (int i = 0; i < 8; i++) {
sb2.setLength(0);- Collections.shuffle(types);
if (types.get(0) == "YIELD" || types.get(0) == "STOP" || types.get(0) == "R") {int aleatorio = random.nextInt(0, 5);if (aleatorio == 0) {sb2.append(types.get(0));} else {sb2.append(types.get(0) + aleatorio);}} else if (types.get(0) == "SL") {sb2.append(types.get(0) + random.nextInt(20, 70) + "_" + random.nextInt(1, 10));} else {sb2.append(types.get(0));- String current = types.get(0);
- while ("SL".equals(current) && "SL".equals(prev)) {
- Collections.shuffle(types);
- current = types.get(0);
- }
sb.append(sb2 + " ");- int timeGap = random.nextInt(4) + 1;
- currentTime += timeGap;
- sb.append("t=").append(currentTime).append(" ").append(current);
- if ("SL".equals(current)) {
- int limit = random.nextInt(50) + 20;
- sb.append(limit);
- } else if ("YIELD".equals(current)) {
- int cars = random.nextInt(5);
- if (cars > 0)
- sb.append(cars);
- currentTime += cars * 2;
- } else if ("STOP".equals(current)) {
- int cars = random.nextInt(5);
- if (cars > 0)
- sb.append(cars);
- currentTime += 3 + cars * 2;
- } else if ("REDLIGHT".equals(current)) {
- int seconds = random.nextInt(5) + 1;
- sb.append(seconds);
- currentTime += seconds;
- }
- sb.append(";");
- prev = current;
- }
- return sb.toString().trim();
- }
public static String generateGoodActions(String indications) {String[] trafficSigns = indications.split("\\s+");- public static String generateActions(String indications) {
- String[] trafficSigns = indications.split(";");
- List<String> actions = new ArrayList<>();
- Random random = new Random();
Matcher matcher;for (String sing : trafficSigns) {if ((matcher = Pattern.compile("SL(\\d+)_(\\d+)").matcher(sing)).matches()) {int limit = Integer.parseInt(matcher.group(1));int duration = Integer.parseInt(matcher.group(2));for (int i = 0; i < duration; i++) {actions.add(String.valueOf(random.nextInt(limit + 1)));- int currentSecond = 1;
- int speedLimit = 80;
- int SignalNumberIteration = 0;
- for (String signEntry : trafficSigns) {
- SignalNumberIteration++;
- signEntry = signEntry.trim();
- if (signEntry.isEmpty())
- continue;
- String[] parts = signEntry.split(" ");
- int time = Integer.parseInt(parts[0].substring(2));
- String sign = parts[1];
- while (currentSecond < time) {
- int limit = speedLimit + 1;
- int v = Math.max(1, random.nextInt(limit));
- actions.add(String.valueOf(v));
- currentSecond++;
- }
- if (sign.startsWith("SL")) {
- speedLimit = Integer.parseInt(sign.substring(2));
- actions.add(String.valueOf(random.nextInt(speedLimit + 1)));
- currentSecond++;
- } else if (sign.startsWith("YIELD")) {
- if (SignalNumberIteration == 9 && sign.matches("YIELD")) {
- actions.add(String.valueOf(random.nextInt(1, speedLimit)));
- }
} else if ((matcher = Pattern.compile("YIELD(\\d*)").matcher(sing)).matches()) {int cars = matcher.group(1).isEmpty() ? 1 : Integer.parseInt(matcher.group(1));for (int i = 0; i < cars * 2; i++) {- int cars = (sign.length() > 5) ? Integer.parseInt(sign.substring(5)) : 0;
- int secs = cars * 2;
- for (int j = 0; j < secs; j++) {
- actions.add("0");
- currentSecond++;
- }
} else if ((matcher = Pattern.compile("STOP(\\d*)").matcher(sing)).matches()) {int cars = matcher.group(1).isEmpty() ? 0 : Integer.parseInt(matcher.group(1));for (int i = 0; i < 3 + 2 * cars; i++) {- } else if (sign.startsWith("STOP")) {
- int cars = (sign.length() > 4) ? Integer.parseInt(sign.substring(4)) : 0;
- int secs = 3 + 2 * cars;
- for (int j = 0; j < secs; j++) {
- actions.add("0");
- currentSecond++;
- }
} else if ((matcher = Pattern.compile("R(\\d+)").matcher(sing)).matches()) {int secs = Integer.parseInt(matcher.group(1));for (int i = 0; i < secs; i++) {- } else if (sign.startsWith("REDLIGHT")) {
- int secs = Integer.parseInt(sign.substring(8));
- for (int j = 0; j < secs; j++) {
- actions.add("0");
- currentSecond++;
- }
} else if ("TURNL".equals(sing) && !actions.isEmpty()) {int last = actions.size() - 1;actions.set(last, actions.get(last) + "<");} else if ("TURNR".equals(sing) && !actions.isEmpty()) {int last = actions.size() - 1;actions.set(last, actions.get(last) + ">");- } else if (sign.equals("TURNL")) {
- actions.add(random.nextInt(speedLimit + 1) + "<");
- currentSecond++;
- } else if (sign.equals("TURNR")) {
- actions.add(random.nextInt(speedLimit + 1) + ">");
- currentSecond++;
- }
- }
- return String.join(" ", actions);
- }
@Testvoid RandomTest() {String indications = generateIndications();String actions = generateGoodActions(indications);System.out.println(indications);System.out.println(actions);}- }
Trains and Trails
It's been a while since you saw your friends and you are eager to meet them.
You all agreed to meet at a point, but each one of your friends could arrive at a different station.
You've arrived early, so you are waiting for your friends to come.
Since you are impatient, and have nothing better to do, you try to guess the place and order in which your friends will arrive, if they do.
You know each one of them is in a different train, labeled from A to Z.
So you take a look at the map:
A----\ 1
------\
B--¡------------2
C-------) ---/
D-------/ 3
The map leyend reads:
Character | Description | Time Value |
---|---|---|
0-9 |
Different stations | |
A-Z |
Different trains your friends are in | |
) |
Indicates a tunel. The trains that enter it will be lost | |
- |
Indicates a rail for the train to move forward | 1 |
\ |
Indicates a turn. The train will move down and forward | 2 |
/ |
Indicates a turn. The train will move up and forward | 2 |
¡ |
Indicates a traffic light. The train will wait 1 turn and continue | 3 |
In this example we can see that all the trains will arrive at station 2. So the trains there will be :
- Train A takes 21 units of time to arrive
- Train B takes 16 units of time to arrive
- Train D takes 17 units of time to arrive
- Train C goes into a tunnel so we dont count it
Having this in mind, our result will be:
{
'2' : ( 'B', 'D', 'A' )
}
In java the result is a Map\<Character,List\<Character\>\>
Edge cases:
- If 2 trains take the same time to arrive at the station, they should be ordered alphaberically
- Collisions between trains do not affect them
- If the trains get out of the map, dont count them
import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.RepeatedTest; import java.util.Arrays; import java.util.Map; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Random; import java.lang.Math; import java.util.Map.Entry; import java.util.Comparator; class SolutionTest { private String printTracks (char[][] tracks) { return Arrays.stream(tracks) .map(String::valueOf) .map(s -> String.join(s,"\n"+s)) .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append) .toString(); } void pass(char[][] s, Map<Character, List<Character>> map) { assertEquals(map, TrainsAndRailways.travel(s), printTracks(s)); } void dontPass(char[][] s) { assertEquals(new java.util.HashMap<Character, List<Character>>(), TrainsAndRailways.travel(s), printTracks(s)); } @Test void exclusivePassTest() { pass(new char[][] {"A---------------1".toCharArray()}, Map.of('1', List.of('A'))); pass(new char[][] {"A----------¡-----1".toCharArray()}, Map.of('1', List.of('A'))); pass(new char[][] {"A-----------\\ -----------1".toCharArray(), " -------------/ ".toCharArray()}, Map.of('1', List.of('A'))); pass(new char[][] {"A-------- 1".toCharArray(), "B---------------2".toCharArray()}, Map.of('2', List.of('B'))); pass(new char[][] {"A----) 1".toCharArray(), "B-----------------2".toCharArray()}, Map.of('2', List.of('B'))); } @Test void exclusiveNotPassTest() { dontPass(new char[][] {"A-------- 1".toCharArray()}); dontPass(new char[][] {{}}); dontPass(new char[][] {"A----) 1".toCharArray()}); dontPass(new char[][] {"A----\\ ".toCharArray(), " --------1".toCharArray()}); dontPass(new char[][] {"A---------------------".toCharArray(), " 1".toCharArray()}); } private static char[][] generateRandomTracks() { char[][] matrix = new char[new Random().nextInt(5, 15)][new Random().nextInt(10, 25)]; int area = matrix.length * matrix[0].length; int numberOfStations = Math.min((int) new Random().nextDouble( 0.5 * matrix.length,matrix.length), 10); int numberOfTrains = Math.min((int) new Random().nextDouble( 0.5 * matrix.length,matrix.length), 26); int numberOfSemaphores = (int) new Random().nextDouble(area / 20, area / 8); int numberOfTunnels = (int) new Random().nextDouble(area / 30, area / 10); int numberOfLeftTracks = (int) new Random().nextDouble(area / 30, area / 15); int numberOfRightTracks = (int) new Random().nextDouble(area / 30, area / 15); List<Character> charsList = new ArrayList<Character>(); int i = 0; while (i < numberOfStations) { charsList.add(Character.forDigit(i++, 10)); } i = 0; while (i < numberOfTrains) { charsList.add((char) (i++ + 65)); } i = 0; while (i++ < numberOfSemaphores) { charsList.add('¡'); } i = 0; while (i++ < numberOfTunnels) { charsList.add(')'); } i = 0; while (i++ < numberOfLeftTracks) { charsList.add('/'); } i = 0; while (i++ < numberOfRightTracks) { charsList.add('\\'); } Collections.shuffle(charsList); int counter = 0; for (int x = 0; x < matrix.length; x++) { for (int y = 0; y < matrix[x].length; y++) { if ((charsList.get(counter) == '/' || charsList.get(counter) == '\\') && x != 0 && x != matrix.length - 1 && y != 0 && y != matrix[y].length) { matrix[x][y] = charsList.get(counter++); if (counter == charsList.size()) { counter = 0; } } } } for (int x = 0; x < matrix.length; x++) { for (int y = 0; y < matrix[x].length; y++) { if (matrix[x][y] == '\u0000') { matrix[x][y] = '-'; } } } return matrix; } @RepeatedTest(50) void randomTests() { char [][] matrix = generateRandomTracks(); assertEquals(travel(matrix), TrainsAndRailways.travel(matrix), printTracks(matrix)); } @Test void baseTest() { char[][] input = { {'A','-','-','-','-','-','\\','-','-','-','-','-','-','-','1'}, {'B','-','-','-','-','-','-','/',' '}, {' ',' ',' ',' ',' ',' ','-','-','-','-','-','2'}, {'C',' ','-','-','-','-','-','/',' '}, {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','3'}, {'D','-','-','-','-','-','-','-','-','-','-','-','-','-','4'} }; assertEquals(Map.of('1', List.of('B', 'A'), '4', List.of('D')), TrainsAndRailways.travel(input), printTracks(input)); char[][] input2 = { {'A', '-', '-', '¡', '\\', '¡', ' ', ' ', ' ', ' ', ' ', ' ', ' ', }, {'B', '-', '-', '-', '-', '\\', ' ', ' ', ' ', ' ', ' ', ' ', ' ', }, {' ', ' ', ' ', ' ', '-', '-', '\\', ' ', ' ', ' ', ' ', ' ', ' ', }, {'C', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '1', }, {'D', '-', '-', '-', '-', '-', '-', ')', ' ', ' ', ' ', ' ', ' ', }, {'E', '-', '-', '-', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '2', }, }; assertEquals(Map.of('1', List.of('C', 'B', 'A')), TrainsAndRailways.travel(input2), printTracks(input2)); char[][] input3 = { {'A', '-', '-', '-', '\\', '-', '-', '-', '1', }, {' ', ' ', ' ', ' ', '-', '-', '-', '-', '2', }, {'B', '-', '¡', '-', '/', ' ', '-', '/', ' ', }, {'C', '-', '-', '/', ' ', '-', '/', ' ', ' ', }, {' ', ' ', ' ', ' ', '-', '/', ' ', ' ', ' ', }, {'D', '-', '-', '-', '/', ' ', ' ', ' ', ' ', }, }; assertEquals(Map.of('2', List.of('A', 'C', 'B', 'D')), TrainsAndRailways.travel(input3), printTracks(input3)); char[][] input4 = { {'A', '-', '-', '-', ')', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', }, {' ', ' ', ' ', ' ', '-', '\\', ' ', ' ', ' ', ' ', ' ', ' ', ' ', }, {'B', '-', '-', '-', '/', '-', '-', '-', '-', '\\', ' ', ' ', ' ', }, {'C', '-', '-', '¡', '-', '-', '-', '¡', '-', '-', '-', '-', '1', }, {'D', '-', '-', '-', '-', '-', '/', ' ', ' ', ' ', ' ', ' ', ' ', }, {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '-', '2', }, {'E', '-', '-', '-', '\\', ' ', ' ', ' ', ' ', ' ', '-', '/', ' ', }, {' ', ' ', ' ', ' ', '-', '-', '-', '-', '-', '-', '/', ' ', ' ', }, {'F', '-', '-', '¡', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', }, }; assertEquals(Map.of('1', List.of('B','D','C'), '2', List.of('E', 'F')), TrainsAndRailways.travel(input4), printTracks(input4)); } @Test void moreTest() { char[][] input = { {'A', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '1', }, }; assertEquals(Map.of('1', List.of('A')), TrainsAndRailways.travel(input), printTracks(input)); char[][] input2 = { {'A', '¡', '¡', '¡', '¡', '¡', '\\', '¡', '¡', '¡', '¡', '¡', '1', }, {'B', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '2', }, }; assertEquals(Map.of('2', List.of('A', 'B')), TrainsAndRailways.travel(input2), printTracks(input2)); } @Test void edgeCases() { char[][] input1 = { {'A', '1', }, {'B', '2', }, {'C', '3', }, {'D', '4', }, {'E', '5', }, {'F', '6', }, }; assertEquals(Map.of('1', List.of('A'),'2', List.of('B'), '3', List.of('C'),'4', List.of('D'), '5', List.of('E'),'6', List.of('F') ), TrainsAndRailways.travel(input1), printTracks(input1)); char[][] input2 = { {'-', '-', '-', '-', '-', '-', '-', '\\', '-'}, {'A', '-', '-', '-', '/', '-', '-', '\\', ' ', }, {'B', '-', '-', '-', '-', '-', '-', '-', '1', }, {'-', '-', '-', '-', '-', '-', '-', '-', '-'}, }; assertEquals(Map.of('1', List.of('B')), TrainsAndRailways.travel(input2), printTracks(input2)); char[][] input3 = { {'A', '-', '-', '¡', '1', '-', '-', '-', '2', }, }; assertEquals(Map.of('1', List.of('A')), TrainsAndRailways.travel(input3), printTracks(input3)); char[][] input4 = { {'A', '-', '-', '-', '-', '-', '\\', '-', '-', '-', '-', '-', '\\', ' ', }, {'B', '¡', '¡', '-', '-', '-', '-', '/', '-', '-', '-', '-', '-', '1', }, {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', }, {'C', '-', '-', '-', '¡', '-', '-', '-', '-', '-', '-', '-', '-', '2', }, }; assertEquals(Map.of('1', List.of('A','B'), '2', List.of('C')), TrainsAndRailways.travel(input4), printTracks(input4)); char[][] input5 = { {'A', '-', '-', '-', '-', '-', '-', ')', ' ', ' ', ' ', }, {'C', '-', '-', '-', '-', '\\', ' ', ' ', ' ', ' ', ' ', }, {' ', ' ', ' ', ' ', ' ', '-', '-', '-', '-', '-', '1', }, {'B', '-', '-', '-', '-', '/', ' ', ' ', ' ', ' ', ' ', }, }; assertEquals(Map.of('1',List.of('B','C')), TrainsAndRailways.travel(input5), printTracks(input5)); } private Map<Character, List<Character>> travel(char[][] tracks) { Map<Character,List<Map.Entry<Character,Integer>>> result = new java.util.HashMap<>(); for (int row = 0; row < tracks.length; row++) { for (int column = 0; column < tracks[row].length; column++) { if (isTrain(tracks[row][column])) { Map.Entry<Character, Integer> train = new java.util.AbstractMap.SimpleEntry(tracks[row][column],0); goOnTraveling(tracks, row, column+1,train, result); } } } Map<Character,List<Character>> sortedShipOnStations = new java.util.HashMap<>(); result.forEach((k,v) -> sortedShipOnStations.put(k,sortTrains(v))); return sortedShipOnStations; } private boolean isTrain(char piece) { return piece >= 65 && piece <= 90; } private boolean isStation (char piece) { return piece >= 48 && piece <= 57; } private void goOnTraveling(char[][] tracks, int row, int column, Entry<Character, Integer> train, Map<Character, List<Map.Entry<Character, Integer>>> result) { while (column < tracks[row].length) { switch (tracks[row][column]) { case '¡': { train.setValue(train.getValue()+2); break; } case '-': { break; } case '/': { train.setValue(train.getValue()+1); row--; break; } case '\\': { train.setValue(train.getValue()+1); row++; break; } case ')': { return; } default: { if (isStation(tracks[row][column])) { result.putIfAbsent(tracks[row][column], new java.util.LinkedList<Map.Entry<Character,Integer>>()); result.get(tracks[row][column]).add(train); } return; } } train.setValue(train.getValue()+1); column++; } } private static List<Character> sortTrains (List<Entry<Character, Integer>> stationArrivals) { List<Character> orderedTrains = new java.util.LinkedList<>(); stationArrivals.forEach(e -> orderedTrains.add(e.getKey())); return stationArrivals.stream() .sorted(Comparator.comparing(Entry<Character, Integer>::getValue) .thenComparing(Entry::getKey)) .map(Map.Entry::getKey) .toList(); } }
- import org.junit.jupiter.api.Test;
- import static org.junit.jupiter.api.Assertions.assertEquals;
- import org.junit.jupiter.api.RepeatedTest;
- import java.util.Arrays;
- import java.util.Map;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.List;
- import java.util.Random;
- import java.lang.Math;
import java.util.Map;- import java.util.Map.Entry;
- import java.util.Comparator;
- class SolutionTest {
- private String printTracks (char[][] tracks) {
- return Arrays.stream(tracks)
- .map(String::valueOf)
- .map(s -> String.join(s,"\n"+s))
- .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
- .toString();
- }
- void pass(char[][] s, Map<Character, List<Character>> map) {
- assertEquals(map, TrainsAndRailways.travel(s), printTracks(s));
- }
- void dontPass(char[][] s) {
- assertEquals(new java.util.HashMap<Character, List<Character>>(), TrainsAndRailways.travel(s), printTracks(s));
- }
- @Test
- void exclusivePassTest() {
- pass(new char[][] {"A---------------1".toCharArray()}, Map.of('1', List.of('A')));
- pass(new char[][] {"A----------¡-----1".toCharArray()}, Map.of('1', List.of('A')));
- pass(new char[][] {"A-----------\\ -----------1".toCharArray(),
- " -------------/ ".toCharArray()}, Map.of('1', List.of('A')));
- pass(new char[][] {"A-------- 1".toCharArray(), "B---------------2".toCharArray()}, Map.of('2', List.of('B')));
- pass(new char[][] {"A----) 1".toCharArray(), "B-----------------2".toCharArray()}, Map.of('2', List.of('B')));
- }
- @Test
- void exclusiveNotPassTest() {
- dontPass(new char[][] {"A-------- 1".toCharArray()});
- dontPass(new char[][] {{}});
- dontPass(new char[][] {"A----) 1".toCharArray()});
- dontPass(new char[][] {"A----\\ ".toCharArray(),
- " --------1".toCharArray()});
- dontPass(new char[][] {"A---------------------".toCharArray(),
- " 1".toCharArray()});
- }
- private static char[][] generateRandomTracks() {
- char[][] matrix = new char[new Random().nextInt(5, 15)][new Random().nextInt(10, 25)];
- int area = matrix.length * matrix[0].length;
- int numberOfStations = Math.min((int) new Random().nextDouble( 0.5 * matrix.length,matrix.length), 10);
- int numberOfTrains = Math.min((int) new Random().nextDouble( 0.5 * matrix.length,matrix.length), 26);
- int numberOfSemaphores = (int) new Random().nextDouble(area / 20, area / 8);
- int numberOfTunnels = (int) new Random().nextDouble(area / 30, area / 10);
- int numberOfLeftTracks = (int) new Random().nextDouble(area / 30, area / 15);
- int numberOfRightTracks = (int) new Random().nextDouble(area / 30, area / 15);
- List<Character> charsList = new ArrayList<Character>();
- int i = 0;
- while (i < numberOfStations) {
- charsList.add(Character.forDigit(i++, 10));
- }
- i = 0;
- while (i < numberOfTrains) {
- charsList.add((char) (i++ + 65));
- }
- i = 0;
- while (i++ < numberOfSemaphores) {
- charsList.add('¡');
- }
- i = 0;
- while (i++ < numberOfTunnels) {
- charsList.add(')');
- }
- i = 0;
- while (i++ < numberOfLeftTracks) {
- charsList.add('/');
- }
- i = 0;
- while (i++ < numberOfRightTracks) {
- charsList.add('\\');
- }
- Collections.shuffle(charsList);
- int counter = 0;
- for (int x = 0; x < matrix.length; x++) {
- for (int y = 0; y < matrix[x].length; y++) {
- if ((charsList.get(counter) == '/' || charsList.get(counter) == '\\') && x != 0 && x != matrix.length - 1 && y != 0 && y != matrix[y].length) {
- matrix[x][y] = charsList.get(counter++);
- if (counter == charsList.size()) {
- counter = 0;
- }
- }
- }
- }
- for (int x = 0; x < matrix.length; x++) {
- for (int y = 0; y < matrix[x].length; y++) {
- if (matrix[x][y] == '\u0000') {
- matrix[x][y] = '-';
- }
- }
- }
- return matrix;
- }
- @RepeatedTest(50)
- void randomTests() {
- char [][] matrix = generateRandomTracks();
- assertEquals(travel(matrix), TrainsAndRailways.travel(matrix), printTracks(matrix));
- }
- @Test
- void baseTest() {
- char[][] input = {
- {'A','-','-','-','-','-','\\','-','-','-','-','-','-','-','1'},
- {'B','-','-','-','-','-','-','/',' '},
- {' ',' ',' ',' ',' ',' ','-','-','-','-','-','2'},
- {'C',' ','-','-','-','-','-','/',' '},
- {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','3'},
- {'D','-','-','-','-','-','-','-','-','-','-','-','-','-','4'}
- };
- assertEquals(Map.of('1', List.of('B', 'A'), '4', List.of('D')), TrainsAndRailways.travel(input), printTracks(input));
- char[][] input2 = {
- {'A', '-', '-', '¡', '\\', '¡', ' ', ' ', ' ', ' ', ' ', ' ', ' ', },
- {'B', '-', '-', '-', '-', '\\', ' ', ' ', ' ', ' ', ' ', ' ', ' ', },
- {' ', ' ', ' ', ' ', '-', '-', '\\', ' ', ' ', ' ', ' ', ' ', ' ', },
- {'C', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '1', },
- {'D', '-', '-', '-', '-', '-', '-', ')', ' ', ' ', ' ', ' ', ' ', },
- {'E', '-', '-', '-', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '2', },
- };
- assertEquals(Map.of('1', List.of('C', 'B', 'A')), TrainsAndRailways.travel(input2), printTracks(input2));
- char[][] input3 = {
- {'A', '-', '-', '-', '\\', '-', '-', '-', '1', },
- {' ', ' ', ' ', ' ', '-', '-', '-', '-', '2', },
- {'B', '-', '¡', '-', '/', ' ', '-', '/', ' ', },
- {'C', '-', '-', '/', ' ', '-', '/', ' ', ' ', },
- {' ', ' ', ' ', ' ', '-', '/', ' ', ' ', ' ', },
- {'D', '-', '-', '-', '/', ' ', ' ', ' ', ' ', },
- };
- assertEquals(Map.of('2', List.of('A', 'C', 'B', 'D')), TrainsAndRailways.travel(input3), printTracks(input3));
- char[][] input4 = {
- {'A', '-', '-', '-', ')', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', },
- {' ', ' ', ' ', ' ', '-', '\\', ' ', ' ', ' ', ' ', ' ', ' ', ' ', },
- {'B', '-', '-', '-', '/', '-', '-', '-', '-', '\\', ' ', ' ', ' ', },
- {'C', '-', '-', '¡', '-', '-', '-', '¡', '-', '-', '-', '-', '1', },
- {'D', '-', '-', '-', '-', '-', '/', ' ', ' ', ' ', ' ', ' ', ' ', },
- {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '-', '2', },
- {'E', '-', '-', '-', '\\', ' ', ' ', ' ', ' ', ' ', '-', '/', ' ', },
- {' ', ' ', ' ', ' ', '-', '-', '-', '-', '-', '-', '/', ' ', ' ', },
- {'F', '-', '-', '¡', '/', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', },
- };
- assertEquals(Map.of('1', List.of('B','D','C'), '2', List.of('E', 'F')), TrainsAndRailways.travel(input4), printTracks(input4));
- }
- @Test
- void moreTest() {
- char[][] input = {
- {'A', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '1', },
- };
- assertEquals(Map.of('1', List.of('A')), TrainsAndRailways.travel(input), printTracks(input));
- char[][] input2 = {
- {'A', '¡', '¡', '¡', '¡', '¡', '\\', '¡', '¡', '¡', '¡', '¡', '1', },
- {'B', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '¡', '2', },
- };
- assertEquals(Map.of('2', List.of('A', 'B')), TrainsAndRailways.travel(input2), printTracks(input2));
- }
- @Test
- void edgeCases() {
- char[][] input1 = {
- {'A', '1', },
- {'B', '2', },
- {'C', '3', },
- {'D', '4', },
- {'E', '5', },
- {'F', '6', },
- };
- assertEquals(Map.of('1', List.of('A'),'2', List.of('B'),
- '3', List.of('C'),'4', List.of('D'),
- '5', List.of('E'),'6', List.of('F')
- ), TrainsAndRailways.travel(input1), printTracks(input1));
- char[][] input2 = {
- {'-', '-', '-', '-', '-', '-', '-', '\\', '-'},
- {'A', '-', '-', '-', '/', '-', '-', '\\', ' ', },
- {'B', '-', '-', '-', '-', '-', '-', '-', '1', },
- {'-', '-', '-', '-', '-', '-', '-', '-', '-'},
- };
- assertEquals(Map.of('1', List.of('B')), TrainsAndRailways.travel(input2), printTracks(input2));
- char[][] input3 = {
- {'A', '-', '-', '¡', '1', '-', '-', '-', '2', },
- };
- assertEquals(Map.of('1', List.of('A')), TrainsAndRailways.travel(input3), printTracks(input3));
- char[][] input4 = {
- {'A', '-', '-', '-', '-', '-', '\\', '-', '-', '-', '-', '-', '\\', ' ', },
- {'B', '¡', '¡', '-', '-', '-', '-', '/', '-', '-', '-', '-', '-', '1', },
- {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', },
- {'C', '-', '-', '-', '¡', '-', '-', '-', '-', '-', '-', '-', '-', '2', },
- };
- assertEquals(Map.of('1', List.of('A','B'), '2', List.of('C')), TrainsAndRailways.travel(input4), printTracks(input4));
- char[][] input5 = {
- {'A', '-', '-', '-', '-', '-', '-', ')', ' ', ' ', ' ', },
- {'C', '-', '-', '-', '-', '\\', ' ', ' ', ' ', ' ', ' ', },
- {' ', ' ', ' ', ' ', ' ', '-', '-', '-', '-', '-', '1', },
- {'B', '-', '-', '-', '-', '/', ' ', ' ', ' ', ' ', ' ', },
- };
- assertEquals(Map.of('1',List.of('B','C')), TrainsAndRailways.travel(input5), printTracks(input5));
- }
- private Map<Character, List<Character>> travel(char[][] tracks) {
- Map<Character,List<Map.Entry<Character,Integer>>> result = new java.util.HashMap<>();
- for (int row = 0; row < tracks.length; row++) {
- for (int column = 0; column < tracks[row].length; column++) {
- if (isTrain(tracks[row][column])) {
- Map.Entry<Character, Integer> train = new java.util.AbstractMap.SimpleEntry(tracks[row][column],0);
- goOnTraveling(tracks, row, column+1,train, result);
- }
- }
- }
- Map<Character,List<Character>> sortedShipOnStations = new java.util.HashMap<>();
- result.forEach((k,v) -> sortedShipOnStations.put(k,sortTrains(v)));
- return sortedShipOnStations;
- }
- private boolean isTrain(char piece) {
- return piece >= 65 && piece <= 90;
- }
- private boolean isStation (char piece) {
- return piece >= 48 && piece <= 57;
- }
- private void goOnTraveling(char[][] tracks, int row, int column, Entry<Character, Integer> train, Map<Character, List<Map.Entry<Character, Integer>>> result) {
- while (column < tracks[row].length) {
- switch (tracks[row][column]) {
- case '¡': {
- train.setValue(train.getValue()+2);
- break;
- }
- case '-': {
- break;
- }
- case '/': {
- train.setValue(train.getValue()+1);
- row--;
- break;
- }
- case '\\': {
- train.setValue(train.getValue()+1);
- row++;
- break;
- }
- case ')': {
- return;
- }
- default: {
- if (isStation(tracks[row][column])) {
- result.putIfAbsent(tracks[row][column], new java.util.LinkedList<Map.Entry<Character,Integer>>());
- result.get(tracks[row][column]).add(train);
- }
- return;
- }
- }
- train.setValue(train.getValue()+1);
- column++;
- }
- }
- private static List<Character> sortTrains (List<Entry<Character, Integer>> stationArrivals) {
- List<Character> orderedTrains = new java.util.LinkedList<>();
- stationArrivals.forEach(e -> orderedTrains.add(e.getKey()));
- return stationArrivals.stream()
- .sorted(Comparator.comparing(Entry<Character, Integer>::getValue)
- .thenComparing(Entry::getKey))
- .map(Map.Entry::getKey)
- .toList();
- }
- }