אתגר תכנות: בואו נפתור את Advent Of Code יחד

עשיתי זאת !
ואכן קיבלתי כוכב :slight_smile:

עשיתי פיתרון בג’אווה
עובד מצוין בדוגמאות סטנדרטיות כמו שכולם ניסו פה
הבעיה שבבעיה האישית שהוא נותן לי כדי לקבל כוכב הוא נותן מספר בין כמה מאות ספרות שג’אווה הסטנדרטי לא מתמודד איתם
וצריך להשתמש אולי ב BigInteger או משהו כזה

זה הפיתרון שלי בJAVA
(העדפתי להמיר אותו קודם למערך בשביל יעילות טובה יותר)

    public static int puzzle(int intPuzzle) {
        int length = String.valueOf(intPuzzle).length();
        int[] array = new int[length];
        for (int i = length-1; i >=0; i--) {
            array[i] = intPuzzle % 10;
            intPuzzle=intPuzzle/10;
        }
        int count = 0;
        for (int i = 0; i < array.length-1; i++) {
            if (array[i] == array[i + 1]) {
                count+=array[i];
            }
        }
        if (array[array.length - 1] == array[0]) {
            count+=array[array.length-1];
        }
        return count;
    }

למה הפונקציה צריכה לקבל int? לא עדיף שתתחיל עם String ואותו תמיר למערך ? (ככה גם תקבל את הכוכב)

2 לייקים

יום 1 - חלק שני

הי,
אז @1116 ספלינטור הזכיר לי שיש חלק שני לתרגילים האלה וכדאי להתקדם גם אליו (כמובטח מחר אני מסכם את היום הראשון ונתחיל את התרגיל השני, כך שאין הרבה זמן).

מסתבר שבשביל לעבור בדלת עלינו לחשב את סכום הספרות שזהות לסיפרה שנמצאת בחצי הדרך קדימה מאיתנו. במילים אחרות אם יש ברשימה 10 איברים, חצי מ-10 זה 5 ולכן יש לחשב רק את סכום הספרות שהסיפרה שנמצאת 5 מקומות אחריהן זהה לה.

לדוגמא עבור הקלט 1212 הסכום יהיה 6 מאחר ויש בקלט 4 ספרות, חצי מ-4 זה 2 וכל ארבעת הספרות מקיימות את התנאי (הסיפרה במקום הראשון זהה לזו שבמקום השלישי, הסיפרה במקום השני זהה לזו שבמקום הרביעי, הסיפרה במקום השלישי זהה לזו שבמקום הראשון והסיפרה במקום הרביעי זהה לזו שבמקום השני).
מכל סיפרה מתקדמים שני צעדים ורואים אם הסיפרה שיש שם זהה.

או למשל הקלט 1221 נותן תוצאה 0 מאחר וכל ההשוואות הן בין 1 ל-2.

הקלט 123425 נותן את התוצאה 4 מאחר ושני ה-2 מתאימים אחד לשני (אחד במקום השני והשני במקום החמישי וגודל הקפיצה הוא 3).

הקלט 123123 נותן 12

והקלט 12131415 נותן 4

מוזמנים להדביק את העדכון שלכם לתרגיל. מחר בבוקר נתקדם ליום 2.

הפתרון שלי ב-JavaScript לחלק הראשון מצריך רק שינוי קל בשביל החלק השני:

function inverseCaptcha2(s) {
	return s.split('').reduce((sum, current, index) => sum + (s[(index + s.length/2) % s.length] === current ? +current : 0), 0);
}

לייק 1

כן זה יתרון גדול בהשוואה לביטוי הרגולרי שלי

זה בג’אווה לשאלה הראשונה

 public static int puzzle(String str) {
        String[] array = str.split("");
        int[] arrayInt = Arrays.asList(array).stream().mapToInt(Integer::parseInt).toArray();
        int count = 0;
        for (int i = 0; i < arrayInt.length - 1; i++) {
            if (arrayInt[i] == arrayInt[i + 1]) {
                count += arrayInt[i];
            }
        }
        if (arrayInt[arrayInt.length - 1] == arrayInt[0]) {
            count += arrayInt[arrayInt.length - 1];
        }
        return count;
    }

וזה לשאלה השנייה


    public static int puzzle2(String str) {
        String[] arrayStr = str.split("");
        int[] arrayInt = Arrays.asList(arrayStr).stream().mapToInt(Integer::parseInt).toArray();
        int jamp = arrayInt.length / 2;
        int count = 0;
        for (int i = 0; i < arrayInt.length - jamp; i++) {
            if (arrayInt[i] == arrayInt[i + jamp]) {
                count += arrayInt[i];
            }
        }
        for (int i = 1; i <= jamp; i++) {
            int p = jamp - i;
            if (arrayInt[arrayInt.length - i] == arrayInt[p]) {
                count += arrayInt[arrayInt.length - i];
            }
        }
        return count;
    }

אני יודע שזה לא קוד קסם כמו של המקצוענים פה… אבל זה עושה את העבודה
ותודה לינון על הטיפ בדרך

לייק 1

הפיתרון שלי בשפת Perl

use warnings;
use List::Util qw/sum0/;

while(<>) {
  chomp;
  # Part 1
  my $input1 = $_ . substr($_, 0, 1);
  my @digits1 = ($input1 =~ /([0-9])(?=\1)/g);
  say sum0(@digits1);

  # Part 2
  my $len = length;
  my $step = ($len / 2) - 1;
  my $input2 = $_ . substr($_, 0, $len / 2);
  my @digits2 = ($input2 =~ /(.)(?=.{$step}\1)/g);
  say sum0(@digits2);
}


@YOEL, @Amirkr
שימו לב לאופרטור % ולשימוש בו כדי לרוץ על מערך בצורה מעגלית. האופרטור % מחזיר את שארית החלוקה לדוגמא:

5 % 2 == 1

בגלל שהכפולה של 2 שהכי קרובה ל-5 היא המספר 4 (זה הכי קרוב שנגיע ל-5), ונשאר עוד 1 שנקרא שארית.

שיטה די מקובלת לרוץ בצורה מעגלית על מערך היא להסתכל על שארית החלוקה באורך המערך. לדוגמא נניח שיש לנו את המערך הבא:

arr = [10, 20, 30, 40]

באורך 4. לכן קל לשאול מה האיבר באינדקס 0 (זה 10) או באינדקס 2 (זה 30). אבל, מה האיבר באינדקס 4? באינדקס 10? באינדקס 12? כלומר מה יקרה כשתקדם במערך אחרי האורך שלו?

במצב הרגיל בשפת תכנות נקבל שגיאה. שימוש ב % יאפשר להתמודד עם זה ולדמיין שאנחנו רצים במעגלים בתוך המערך וכל פעם שהגענו לסוף מתחילים שוב מהתחלה. למשל בשביל למצוא את האיבר באינדקס i נבצע:

real_index = i % len(arr)

לדוגמא האינדקסים שכתבתי קודם:

arr[4 % len(arr)] == arr[0] == 10

arr[5 % len(arr)] == arr[1] == 20

arr[10 % len(arr)] == arr[2] == 30

arr[12 % len(arr)] == arr[0] == 10

הקוד שספלינטור כתב משתמש בדיוק בטריק הזה כדי להצליח לקרוא ״אחרי״ סוף המערך ולקבל את האיברים המתאימים מההתחלה.

כדאי לזכור את הטריק הזה כי הוא ילווה אותנו בעוד תרגילים נוספים בסידרה כאן ובחיים בכלל.

2 לייקים

אני לא מבין.
לפי מה אתה מחליט את מה לחלק באורך המערך?
לדוגמא בדוגמא לעיל אם היינו מחלקים את המספר 6 באורך המערך גם היינו מגיעים לאינדקס 2.
ומה זה נותן לי שזה חוזר בצורה מעגלית?

קח לדוגמא את האתגר הראשון - בו אתה בדקת שהאיבר האחרון זהה לאיבר הראשון

מה שספלינטור עשה היה להשוות את האיבר האחרון לאיבר שבא אחריו אבל בצורה מעגלית, כך שאם יש למשל 5 איברים הוא ניסה לבדוק אם החמישי זהה לשישי. כמובן שאי אפשר להסתכל מה יש באינדקס חמש (כי אין כזה) - ובשביל זה נעזרים בפעולת השארית:

מחשבים כמה שארית מתקבלת כשמחלקים את אורך המערך האמיתי באינדקס שמחפשים - כלומר מחלקים את 5 ב-5. התוצאה היא שארית 0 ולכן במקום להשוות לאינדקס 5 שלא קיים משווים לאינדקס 0 שכן קיים.

או במילים אחרות מסתכלים על המערך כאילו הוא טבעת והפעולה % ממפה בין אינדקס בטבעת לאינדקס במערך. בשביל למצוא את האינדקס מסתכלים על שארית החלוקה של ״מספר הצעדים בטבעת״ ל״גודל המערך״

imagehttps://upload.wikimedia.org/wikipedia/commons/thumb/f/fd/Circular_Buffer_Animation.gif/400px-Circular_Buffer_Animation.gif

2 לייקים

אם אני מבין נכון הכוונה רק לתנאי בו אני מוודא שאני נמצא באיבר האחרון.
אם כך, אשמח שתראה לי את התיקון על הקוד שכתבתי כי נסיתי בכל מיני צורות וזה לא עבד
תודה

מימוש בJava:

חלק א’:

	public static int sumSequence(String digits) {
		char [] arr = digits.toCharArray();
		int sumSeq = 0, last = arr.length - 1;
		for(int i=0; i < last; i++) {
			if(arr[i] == arr[i+1])
				sumSeq += fromChar(arr[i]);
		}
		if (arr[0] == arr[last])
			sumSeq += fromChar(arr[0]);
		return sumSeq;
	}

חלק ב’:

public static int sumSequenceHalfway(String digits) {
		char [] arr = digits.toCharArray();
		int sumSeq = 0, n = arr.length, mid = n/2;
		for(int i=0; i < mid; i++) {
			if(arr[i] == arr[i+mid])
				sumSeq += fromChar(arr[i]) * 2;
		}
		return sumSeq;
	}

פונקציית עזר:

public static int fromChar(char c) {
		return c - '0';
	}
לייק 1

לגבי חלק ב - זה עובד לך? כי מקריאת הקוד של חלק ב נראה שדילגת על הטיפול במעגליות (מה שבחלק א התיחסת עם ההשוואה בין האיבר הראשון לאחרון)

חלק ב’ עובד גם ללא מעגליות. מכיוון שמובטח בהוראות שהקלט באורך זוגי, כל איבר שנמצא אחרי החצי ייבדק מול האיבר שבדקנו לפני כן. כלומר, בקלט 123456, הזוגות שיבדקו הם:
(1,4), (2,5), (3,6)
וההפכים שלהם
(4,1), (5,2) ו-(6,3).
לכן עברתי על חצי מערך ועבור איברים תואמים סכמתי פעמיים :slight_smile:

3 לייקים

כנראה שהוא צודק
זה עובד בכל ניסיון
כל הכבוד הוצאת אותנו טיפשים לגמרי
עשיתי הדפסות של כל ההשוואות לפלט שהוא נתן לי ניתן לראות שכל אינדקס נבדק פעמיים מול אותו אינדקס רק בהפוך

|23 1078|1078 23|
|28 1083|1083 28|
|36 1091|1091 36|
|37 1092|1092 37|
|40 1095|1095 40|
|56 1111|1111 56|
|86 1141|1141 86|
|94 1149|1149 94|
|103 1158|1158 103|
|106 1161|1161 106|
|108 1163|1163 108|
|114 1169|1169 114|
|124 1179|1179 124|
|130 1185|1185 130|
|133 1188|1188 133|
|137 1192|1192 137|
|149 1204|1204 149|
|156 1211|1211 156|
|163 1218|1218 163|
|166 1221|1221 166|
|169 1224|1224 169|
|170 1225|1225 170|
|176 1231|1231 176|
|182 1237|1237 182|
|194 1249|1249 194|
|197 1252|1252 197|
|201 1256|1256 201|
|211 1266|1266 211|
|222 1277|1277 222|
|243 1298|1298 243|
|257 1312|1312 257|
|259 1314|1314 259|
|267 1322|1322 267|
|277 1332|1332 277|
|286 1341|1341 286|
|292 1347|1347 292|
|294 1349|1349 294|
|308 1363|1363 308|
|313 1368|1368 313|
|315 1370|1370 315|
|323 1378|1378 323|
|329 1384|1384 329|
|333 1388|1388 333|
|336 1391|1391 336|
|337 1392|1392 337|
|341 1396|1396 341|
|342 1397|1397 342|
|344 1399|1399 344|
|358 1413|1413 358|
|394 1449|1449 394|
|410 1465|1465 410|
|415 1470|1470 415|
|420 1475|1475 420|
|421 1476|1476 421|
|431 1486|1486 431|
|441 1496|1496 441|
|445 1500|1500 445|
|449 1504|1504 449|
|454 1509|1509 454|
|471 1526|1526 471|
|487 1542|1542 487|
|490 1545|1545 490|
|495 1550|1550 495|
|509 1564|1564 509|
|510 1565|1565 510|
|513 1568|1568 513|
|525 1580|1580 525|
|527 1582|1582 527|
|528 1583|1583 528|
|530 1585|1585 530|
|534 1589|1589 534|
|544 1599|1599 544|
|548 1603|1603 548|
|585 1640|1640 585|
|589 1644|1644 589|
|596 1651|1651 596|
|604 1659|1659 604|
|609 1664|1664 609|
|611 1666|1666 611|
|623 1678|1678 623|
|646 1701|1701 646|
|654 1709|1709 654|
|655 1710|1710 655|
|659 1714|1714 659|
|664 1719|1719 664|
|667 1722|1722 667|
|673 1728|1728 673|
|677 1732|1732 677|
|692 1747|1747 692|
|696 1751|1751 696|
|697 1752|1752 697|
|712 1767|1767 712|
|717 1772|1772 717|
|722 1777|1777 722|
|726 1781|1781 726|
|733 1788|1788 733|
|735 1790|1790 735|
|743 1798|1798 743|
|756 1811|1811 756|
|774 1829|1829 774|
|777 1832|1832 777|
|780 1835|1835 780|
|789 1844|1844 789|
|799 1854|1854 799|
|802 1857|1857 802|
|820 1875|1875 820|
|823 1878|1878 823|
|824 1879|1879 824|
|832 1887|1887 832|
|834 1889|1889 834|
|842 1897|1897 842|
|846 1901|1901 846|
|848 1903|1903 848|
|852 1907|1907 852|
|853 1908|1908 853|
|855 1910|1910 855|
|858 1913|1913 858|
|865 1920|1920 865|
|873 1928|1928 873|
|880 1935|1935 880|
|882 1937|1937 882|
|887 1942|1942 887|
|900 1955|1955 900|
|920 1975|1975 920|
|926 1981|1981 926|
|929 1984|1984 929|
|933 1988|1988 933|
|941 1996|1996 941|
|951 2006|2006 951|
|954 2009|2009 954|
|958 2013|2013 958|
|960 2015|2015 960|
|969 2024|2024 969|
|970 2025|2025 970|
|974 2029|2029 974|
|975 2030|2030 975|
|976 2031|2031 976|
|982 2037|2037 982|
|985 2040|2040 985|
|999 2054|2054 999|
|1000 2055|2055 1000|
|1020 2075|2075 1020|
|1034 2089|2089 1034|
|1037 2092|2092 1037|
|1040 2095|2095 1040|
לייק 1

קצת באיחור, רעיון מאוד נחמד. יש לי 2 פתרונות, אחד קריא השני מאוד פונקציונלי אך פחות קריא. אם שואלים אותי, רוב הפעמים אעדיף את הפתרון הקריא.

פתרון קריא:

function solveCaptcha(input){
	let result = 0;
	for(let i = 0; i < input.length; i++){
		if(input[i] == input[(i+1) % input.length]){
			result += Number(input[i]);
		}
	}
	return result
}

פתרון פונקציונלי:

function sc(input){
	return input.split('').reduce((acc, cur, idx, inp) => {
		return acc + ((cur == inp[(idx + 1) % inp.length]) ? Number(cur) : 0);
	}, 0);
}
לייק 1

כיף שהצטרפת ובכלל לא באיחור יש 24 חידות :slight_smile:

לגבי הפיתרון השני אני חושב שהבעיה היא לא שכתיב פונקציונאלי הוא לא קריא אלא שניסית לבנות לוגיקה אימפרטיבית בכלים של תכנות פונקציונאלי וזה לא עובד כל כך טוב.

מה היה קורה אם היינו חושבים על הבעיה כך - נניח שמתחילים עם הטקסט 1231:

  1. קודם כל הופכים את המחרוזת למערך כך שמקבלים:
[1, 2, 3, 1]
  1. אחרי זה מצמידים לכל איבר את זה שאחריו כדי לקבל את המערך:
[[1, 2], [2, 3], [3, 1], [1, 1]]
  1. אחרי זה משאירים רק את הזוגות הזהים:
[[1, 1]]
  1. הופכים כל זוג לערך הראשון ממנו ומקבלים:
[1]
  1. סוכמים את התוצאות

עכשיו יש לנו 5 שלבים אז אפשר לכתוב קוד פונקציונאלי עבורם (יוצא טיפה יותר מסורבל כי צריך גם להמיר למספרים):

function sc(input) {
  return (
    input
    .split('')                // convert to array
    .map((x, i) => [x, input[(i + 1) % input.length]]) // create pairs of [char, next-char]
    .map(pair => [Number(pair[0]), Number(pair[1])]) // convert everything to numbers
    .filter(pair => pair[0] === pair[1]) // leave only pairs that are equal
    .map(pair => pair[0]) // take only one value from the pair
    .reduce((acc, val) => acc + val, 0) // sum
  );
}

כמובן ככל שהשפה היא יותר ״פונקציונאלית״ יהיו לך יותר סוגים של פונקציות להפעיל על המידע ואז הקוד הרבה פעמים יהיה יותר קצר ממה שאני כתבתי כאן. העניין בכתיב פונקציונאלי הוא היכולת להסתכל על משימה בתור הרכבה של משימות קטנות יותר שמרכיבות אותה וכל אחת פועלת על התוצאה של הקודמת.

לייק 1

מעניין מאוד. עכשיו בהחלט הפתרון הפונקציונאלי הרבה יותר מובן. אנסה לחדד את המחשבה שלי בחידות הבאות. תודה

הצטרפתי מעט מאוחר, ננסה לעמוד בקצב…
הפיתרון שלי לשני החלקים, בשפת C#:



     public static int day1_1(string capcha)
        {
            
            var intList = capcha.Select(x => Convert.ToInt32(x.ToString())).ToList();
            int i = 0;
            return intList.Where(x => intList.ElementAt(i % intList.Count) == intList.ElementAt((++i) % intList.Count)).Sum(x => intList.ElementAt(i - 1));

        }

        public static int day1_2(string capcha)
        {
            //string to list of int
            var intList = capcha.Select(x => Convert.ToInt32(x.ToString())).ToList();
            int i = 0;
            int halfCount = intList.Count/2;
            return intList.Where(x => intList.ElementAt(i % intList.Count) == intList.ElementAt(((i++)+halfCount) % intList.Count)).Sum(x => intList.ElementAt(i - 1));

        }

'''
לייק 1