Программирование, Путешествия, Покер

Последний пост:1 апреля
810
Статистика
Всего постов
3225
843,191 просмотров
Новых постов
+0
1 в день
Лучшие посты автора
27.09.2022 +233
21.12.2019 +196
22.02.2023 +169
04.01.2023 +166
13.07.2019 +154
Лучшие посты читателей
inpace +111
justpus7 +98
vsobakekot +88
Gtrdy +85
s4ekotilla +78
Самые активные читатели
1 7 8 9 10 29 162
  • Мой вариант для перевода римских в десятичные работает на числах от 1 до 3999, учитывает 6 обратных перестановок (IV, IX, XL, XC, CD, CM). Больше 3999 делать не стал, потому что если не используем верхние подчеркивания, то непонятно, например, что будет обозначать V : 5 или 5000.

    По алгориму:

    Римское число читаем справа налево, если встретили единичку, то сразу добавляем, если любое другое число, то смотрим число слева от него(при условии, что оно есть) и добавляем сколько нужно.


    Текст программы:

    import java.util.Scanner;

    public class Romans_to_Decimals
    {
    public static void main(String[] args)
    {
    System.out.println("Enter roman number from I to MMMCMXCIX (1 to 3999), q to quit: ");
    Scanner in = new Scanner(System.in);

    boolean done = false;
    while (!done && in.hasNext())
    {
    String number = in.next();
    if (number.equals("q"))
    {
    done = true;
    }
    else
    {
    int result = 0;
    char[] array = number.toCharArray();

    for (int i = number.length() - 1; i >= 0; i--)
    {
    switch ( array )
    {
    case 'I':
    result += 1;
    break;
    case 'X':
    if (i != 0 && array[i-1] == 'I') //IX = 9
    {
    result += 9;
    i--;
    }
    else
    {
    result += 10;
    }
    break;
    case 'C':
    if (i != 0 && array[i-1] == 'X') //XC = 90
    {
    result += 90;
    i--;
    }
    else
    {
    result += 100;
    }
    break;
    case 'M':
    if (i != 0 && array[i-1] == 'C') //CM = 900
    {
    result += 900;
    i--;
    }
    else
    {
    result += 1000;
    }
    break;
    case 'V':
    if (i != 0 && array[i-1] == 'I') //IV = 4
    {
    result += 4;
    i--;
    }
    else
    {
    result += 5;
    }
    break;
    case 'L':
    if (i != 0 && array[i-1] == 'X') //XL = 40
    {
    result += 40;
    i--;
    }
    else
    {
    result += 50;
    }
    break;
    case 'D':
    if (i != 0 && array[i-1] == 'C') //CD = 400
    {
    result += 400;
    i--;
    }
    else
    {
    result += 500;
    }
    break;
    default:
    System.out.println("Not correct roman number");
    break;
    }
    }
    System.out.println("Corresponding decimal number is: " + result);
    }
    }
    in.close();
    }
    }
    [/i][/i][/i][/i][/i][/i]


    p.s. В свитче у массива почему-то не отображается индекс и без отступов (их можно как-то сделать?) текст проги совсем фигово читается .
    10/20
    Ответить Цитировать
    0
  • Перевод из десятичных в римские, тоже работает для чисел от 1 до 3999. Я сделал простым перебором Создал 4 вспомогательных метода для перевода единиц/десятков/сотен/тысяч и вызывал нужный для перевода соответствующего разряда.

    import java.util.Scanner;

    public class Decimals_to_Romans
    {
    public static String unitConverter(int remainder)
    {
    switch(remainder)
    {
    case 1: return "I";
    case 2: return "II";
    case 3: return "III";
    case 4: return "IV";
    case 5: return "V";
    case 6: return "VI";
    case 7: return "VII";
    case 8: return "VIII";
    case 9: return "IX";
    default: return "";
    }
    }

    public static String decimalConverter(int remainder)
    {
    switch(remainder)
    {
    case 1: return "X";
    case 2: return "XX";
    case 3: return "XXX";
    case 4: return "XL";
    case 5: return "L";
    case 6: return "LX";
    case 7: return "LXX";
    case 8: return "LXXX";
    case 9: return "XC";
    default: return "";
    }
    }

    public static String hundredsConverter(int remainder)
    {
    switch(remainder)
    {
    case 1: return "C";
    case 2: return "CC";
    case 3: return "CCC";
    case 4: return "CD";
    case 5: return "C";
    case 6: return "DC";
    case 7: return "DCC";
    case 8: return "DCCC";
    case 9: return "CM";
    default: return "";
    }
    }

    public static String thousandsConverter(int remainder)
    {
    switch(remainder)
    {
    case 1: return "M";
    case 2: return "MM";
    case 3: return "MMM";
    default: return "";
    }
    }

    public static void main(String[] args)
    {
    System.out.println("Enter decimal number from 1 to 3999, -1 to quit: ");
    Scanner in = new Scanner(System.in);

    boolean done = false;
    while (!done && in.hasNextInt())
    {
    Integer number = in.nextInt();
    if (number == -1)
    {
    done = true;
    }
    else
    {
    String result = "";
    int digitNumber = 1;
    int numberLength = number.toString().length();
    for (int i = 1; i <= numberLength; i++)
    {
    int remainder = number % 10;
    switch (digitNumber)
    {
    case 1: result = unitConverter(remainder); break;
    case 2: result = decimalConverter(remainder) + result; break;
    case 3: result = hundredsConverter(remainder) + result; break;
    case 4: result = thousandsConverter(remainder) + result; break;
    }
    number /= 10;
    digitNumber++;
    }


    System.out.println("Corresponding roman number is: " + result);
    }
    }
    in.close();
    }
    }


    Теперь жду красивого решения через рекурсию или енумы)
    11/20
    Ответить Цитировать
    0
  • Цитата (FlySoHigh @ 25.10.2016)
    public static String hundredsConverter(int remainder)
    {
    switch(remainder)
    {
    case 1: return "C";
    case 2: return "CC";
    case 3: return "CCC";
    case 4: return "CD";
    case 5: return "C";


    case 5: return D ???
    3/4
    Ответить Цитировать
    1
  • Lexas, это проблемы копипаста. Со всеми бывает :)
    Кстати, копипаст при написании кода это зло. Лучше стараться этого избегать.
    74/1049
    Ответить Цитировать
    0
  • ай блин, забыл что IllegalArgumentException рантайм..
    и забыл про порядок, мой косяк, делал наспех
    8/10
    Ответить Цитировать
    0
  • Все забываю скинуть свое решение. Оно на рабочем компе и не так просто вспомнить об этом в нужный момент :) Но количество кода в предыдущем решении точно можно уменьшить.

    Когда писал про кодировки, так же вскользь упоминали даты.
    И вот буквально на днях прочитал статьи на хабре, посвященные этой теме. Первый пост и дополненный второй
    На досуге можно почитать пост об именах пользователей, вдохновивший автора двух вышеупомянутых постов про даты - ссылка (Инглиш)

    Я полез в англоязычный оригинал и начал смотреть, откуда автор брал утверждения, которые порвали мне шаблон.
    Как например:
    Цитата
    16. Субботе всегда предшествует пятница.

    Sad, but true

    Ну и завис на пару часов, читая различные пруфы. К примеру, что в Швеции было 30 февраля, в Сингапуре подкручивали время не на целое число часов, еврейский календарь это еще та штука (да и календарей разных множество) и много чего другого.

    Ну и недавно узнал, когда Григорианский календарь пришел к нам в Россию. Раньше я думал, что это произошло где-то в 18-19 веках. А все, кого я спрашивал об этом, почему-то говорили про Петра I.
    А на самом деле это случилось меньше 100 лет назад, в 1918 году. А ведь реально, какая-нибудь столетняя бабушка жила когда-то по Юлианскому календарю, что лично мне ломает напрочь все шаблоны.
    И более того, оплот российской духовности, хранители скреп всея Руси, РПЦ - юзает юлианский календарь по сей день...

    В общем, помимо того, что работа с датами это огромнейший гемор (и до недавних пор я не представлял всей его величины), это еще и нескончаемый источник различных лулзов и интересных фактов.
    Короче говоря, век живи - век учись.

    На эту тему есть еще и видео у яндекса.
    75/1049
    Ответить Цитировать
    7
  • Цитата (strkk @ 27.10.2016)
    Все забываю скинуть свое решение.


    Написал еще раз примерно по памяти, но в прошлый раз было как-то по красивее вроде бы.
    В общем, мой вариант...

    vDQWehc.png



    Текстом:
    public class RomeToArabicConverter {

    public static int convertRomeToArabic(String romeNumber) {
    if (romeNumber == null || !romeNumber.matches("\\bM{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})\\b")) {
    throw new IllegalArgumentException("invalid number");
    }

    int result = 0;
    for (int i = romeNumber.length() - 1; i > -1; i--) {
    int current = getValueForLetter(romeNumber, i);
    int prev = getValueForLetter(romeNumber, i - 1);
    if (current > prev) {
    result -= prev;
    i--;
    }
    result += current;
    }
    return result;
    }

    private static int getValueForLetter(String number, int index) {
    if (index < 0) {
    return -1;
    }
    switch (number.charAt(index)) {
    case 'I':
    return 1;
    case 'V':
    return 5;
    case 'X':
    return 10;
    case 'L':
    return 50;
    case 'C':
    return 100;
    case 'D':
    return 500;
    case 'M':
    return 1000;
    default:
    throw new IllegalArgumentException("Invalid letter");
    }
    }

    }
    76/1049
    Ответить Цитировать
    2
  • А что за магия в строке после matches? Где про нее можно почитать?
    12/20
    Ответить Цитировать
    0
  • FlySoHigh, это регулярное выражение для проверки входного текста на соответствие формату.
    77/1049
    Ответить Цитировать
    1
  • FlySoHigh, если интересно - можно погуглить по
    Джеффри Фридл
    Регулярные выражения
    хорошая и понятная книжка. и страниц 200 вроде всего.
    1/22
    Ответить Цитировать
    2
  • strkk, в твоем коде кажется ошибка. Если подать один символ, то всё сломается.
    Ну и менять счетчик в цикле for я бы не советовал, это опасное занятие. По крайней мере, взглянув на код, нельзя сообразить сходу что он корректен. Надо напрягать мозг, а лишний раз это делать не любит никто.
    1/24
    Ответить Цитировать
    3
  • spaun, Да, ты прав. Прочитав коммент сперва я возмутился, ибо "все же тесты прошло". Однако проверив еще раз увидел, что после изменений, сделанных непосредственно перед выкладыванием кода, забыл прогнать тесты. Бывает
    Впрочем, в выложенном коде достаточно поменять во втором методе -1 на Integer.MAX_VALUE и все работает нормально.

    Цитата (spaun @ 31.10.2016)
    Ну и менять счетчик в цикле for я бы не советовал, это опасное занятие. По крайней мере, взглянув на код, нельзя сообразить сходу что он корректен. Надо напрягать мозг, а лишний раз это делать не любит никто.

    Согласен.
    Посмотрел сегодня видос про стримы и решил попробовать переделать таким методом. Думал что быстро справлюсь, в итоге около часа просидел.
    Получилось что-то такое (не судите строго, пробую первый раз). Также добавил комменты.
    Кратко смысл - преобразуем каждую букву в цифру, причем для тех комбинаций, которые предполагают вычитание (типа XL = 40), делаем финт ушами - сперва добавляем цифру из первой буквы, а затем из следующей вычитаем удвоенное значение предыдущей.
    0P4K68f.png


    В этот раз убедился, что тесты (которые ниже) проходят. Цифры в последнем блоке взял с википедии, самому лень было считать
    g6GJUpE.png


    Ну и по идее, такая штука расширяема - можно пихать в енам новые кракозябры для больших чисел и код при этом будет оставаться корректным (при условии, что уменьшаемое число более чем в 2 раза больше вычитаемого).
    Сообщение отредактировал strkk - 1.11.2016, 0:08
    78/1049
    Ответить Цитировать
    2
  • Какая красота, вся программа прям как на ладони.

    romeNumber.chars().map(new IntUnaryOperator()){...} это как раз фича из стримов, которые добавили в Java 8?
    13/20
    Ответить Цитировать
    1
  • FlySoHigh, да, это фичи из 8-ой джавы. Интересно было с ними поиграться и попробоавать решить задачу (хотя в данном случае вполне можно обойтись одним проходом по массиву и, возможно, это работает быстрее)

    А у меня текущий проект предлагается писать шестой джаве, релиз которой 11 декабря отпразднует десятилетний юбилей. В следующем году уже 9 версия выходит...
    Вот такой вот суровый мир энтерпрайз разработки.
    79/1049
    Ответить Цитировать
    2
  • А на мой взгляд, код стал хуже. Я бы просто обработал случай одного символа отдельно.
    Мне кажется вполне естественным это исправление.

    Вообще, задача конечно очень простая, я бы просто прошелся по числу слева направо, и если левый символ меньше правого, то "вес" левого надо вычесть, иначе - добавить. Последний символ добавляется в любом случае, вне цикла. Вот и всё.

    З.Ы. ты сам писал регэксп?) Кажется, что он был нагуглен.
    Сообщение отредактировал spaun - 2.11.2016, 0:27
    2/24
    Ответить Цитировать
    0
  • Цитата (spaun @ 1.11.2016)
    Вообще, задача конечно очень простая

    Ну само собой. Это же для начинающих...

    Цитата (spaun @ 1.11.2016)
    Я бы просто обработал случай одного символа отдельно


    Цитата (spaun @ 1.11.2016)
    Последний символ добавляется в любом случае, вне цикла


    Вот я как раз и стремился к тому, чтобы избавится от отдельной обработки всяких граничных случаев, которые лишь мозолят (лично мне) глаза. В данном случае для каждого символа идет одинаковая обработка, что (опять же, по моему мнению) куда лучше.
    + проба стримов.

    Ну и пример кода в студию...
    80/1049
    Ответить Цитировать
    0
  • Вот. На c++. http://ideone.com/phbGgO
    3/24
    Ответить Цитировать
    0
  • По-моему, код на с++ будет принимать записи типа IXL, хотя они вроде как ошибочны. Возможно, и некоторые предыдущие варианты содержат такую же ошибку (если это считать ошибкой).
    1/38
    Ответить Цитировать
    2
  • Я считал, что ввод корректный.
    4/24
    Ответить Цитировать
    1
  • Подведу небольшой итог обсуждению этой задачки.
    Думаю, самым оптимальным решением будет следующее -
    - Осознать, что у нас стоит задача не преобразования каждой римской цифры в арабский аналог, а преобразование всего числа.
    - Ну и что для наших чисел B - A = A + (B - 2*A), что позволяет избавиться от прямого доступа по индексу к соседним элементам.
    В итоге получаем, что нам достаточно просто хранить значение предыдущего элемента и добавлять к итоговому результату либо само число А, либо В - 2 * А, в зависимости от них отношения.
    Достаточно лишь 1 цикла и смотреться будет неплохо.

    Цитата (spaun @ 1.11.2016)
    Вот. На c++. http://ideone.com/phbGgO


    Ну, на мой взгляд это решение в красивости и понятности сильно уступает моему.
    И второй цикл лишний.

    Цитата (spaun @ 1.11.2016)
    З.Ы. ты сам писал регэксп?) Кажется, что он был нагуглен.


    Загуглил. Бегло пробежался по нему глазами - вроде как нормальный.
    81/1049
    Ответить Цитировать
    -1
1 7 8 9 10 29 162
1 человек читает эту тему (1 гость):
Зачем регистрироваться на GipsyTeam?
  • Вы сможете оставлять комментарии, оценивать посты, участвовать в дискуссиях и повышать свой уровень игры.
  • Если вы предпочитаете четырехцветную колоду и хотите отключить анимацию аватаров, эти возможности будут в настройках профиля.
  • Вам станут доступны закладки, бекинг и другие удобные инструменты сайта.
  • На каждой странице будет видно, где появились новые посты и комментарии.
  • Если вы зарегистрированы в покер-румах через GipsyTeam, вы получите статистику рейка, бонусные очки для покупок в магазине, эксклюзивные акции и расширенную поддержку.