Auto Added by WPeMatico

Become a Kotlin Google Summer of Code Contributor: Make an Impact!

The Kotlin Foundation has been accepted as a mentor organization for Google Summer of Code 2024! 

GSoC is a global online program focused on bringing new contributors into open-source software development. Contributors work on a 12-week programming project under the guidance of Kotlin Foundation mentors from Google, Gradle, and JetBrains.

What does this mean for you? 

As a potential contributor, this is your chance to explore open-source development with Kotlin. If you are a student or a beginner, GSoC offers an opportunity to work on meaningful projects, gain hands-on experience, and connect with mentors from the Kotlin community.

Why participate? 

By joining us for GSoC 2024, you’ll have the chance to:

  • Gain real-world development experience and enhance technical skills.
  • Contribute to a real Kotlin project with a global impact and play a part in expanding the Kotlin ecosystem.
  • Learn from experienced mentors and connect with the Kotlin community.
  • Receive a stipend and build your resume.

How do I get started?

  • Explore the exciting projects we have lined up and check out our GSoC guidelines.
  • Find a project that interests you and send questions to the potential mentors in Slack to prepare your application.
  • Between March 18 and April 2, apply via the GSoC website. Don’t forget to include a code sample and tell us why you’re passionate about Kotlin!

Resources

Project ideas

Here’s a sneak peek at the projects we have in store this year:

  • Incremental compilation for the Kotlin-to-WebAssembly compiler
  • Compose Multiplatform with Node.js native bindings for Skia
  • Compose Multiplatform component gallery generator
  • Kotlin DSL improvements for declarative Gradle
  • Kotlin DSL documentation samples test framework
  • Gradle build server – support for Android projects
  • Implement memory usage profiling for Kotlin/Native benchmarks
  • Support Android target in kotlinx-benchmark
  • Enabling click-to-run for kotlinx-benchmark benchmarks in IntelliJ IDEA

Read more about the projects

Thank you for your interest in Google Summer of Code with Kotlin. Let’s make this summer a memorable one for Kotlin!

Continue ReadingBecome a Kotlin Google Summer of Code Contributor: Make an Impact!

Advent of Code in Kotlin: Celebrating Our Participants and Their Solutions

A big thank you goes out to everyone who joined us for Advent of Code in Kotlin this year! We’re thrilled that JetBrains was a part of this yearly tradition once again as one of the Advent of Code sponsors.

From December 1 through 12, we shared daily livestreams of puzzle solutions presented by our host Sebastian Aigner and his fantastic guests. If you missed any of the action, you can watch the recordings on our YouTube playlist. Dive into Kotlin discussions, learn something new, and enjoy the good vibes:

This year, we again threw the challenge to the community, inviting you all to solve puzzles using Kotlin – and the response was phenomenal!

Here’s a quick recap:

  • 1,400 repositories were labeled with the “aoc-2023-in-kotlin” topic and were therefore included in the challenge.
  • We featured a total of 12 guests on our 12 daily livestreams.

We invited everyone to join one of our leaderboards and start solving the Advent of Code puzzles in Kotlin. Now, we’d like to take a moment to congratulate our 15 standout winners, who will soon be receiving some exclusive prizes!

Here are the top five performers from the combined Kotlin leaderboards, which had a total of 1,320 participants:

These five winners were selected randomly from the 1,400 repositories:

And here are our community stars:

A massive round of applause to all our participants and winners, and a special thank you to Eric Wastl and the entire Advent of Code organizational team!

We hope you had fun, and we’re looking forward to seeing you all for the next edition of Advent of Code in Kotlin! Meanwhile, check out the following links and keep exploring the language:

Continue ReadingAdvent of Code in Kotlin: Celebrating Our Participants and Their Solutions

Results of Google Summer of Code With Kotlin

2023 marked Kotlin’s first-ever participation in Google Summer of Code (GSoC), a global online program focused on bringing new contributors into open-source development. Contributors worked on 12-week programming projects with the Kotlin Foundation under the guidance of mentors from JetBrains, Google, and Gradle, and gained experience on real-world projects. We would like to share the results achieved during GSoC 2023.

We kicked off the program in March with a lineup of diverse projects, which reflected the versatility of Kotlin’s applications, and a call for proposals:

  • Kotlin Multiplatform protobufs
  • Kotlin Compiler error messages
  • Groovy to Kotlin Gradle DSL converter
  • Eclipse Gradle KTS editing
  • Improve support for parameter forwarding in the Kotlin plugin for IntelliJ IDEA
  • Enhance the kotlinx-benchmark library API and user experience
  • Parallel stacks for Kotlin Coroutines in the debugger

We received 65 high-quality proposals from potential contributors.

After careful evaluation, mentors and organization admins selected the top 5 contributors to work on projects that promised to make a significant impact on the Kotlin community. Halfway through the program, one of the selected contributors withdrew from the “Improve support for parameter forwarding in the Kotlin plugin for IntelliJ IDEA” project, so the final list shrank to 4 projects.

Here is the final list of projects that we worked on last summer, along with reviews from mentors and contributors:

Kotlin Multiplatform library version of Flogger

Enhance the kotlinx-benchmark library API and user experience

Eclipse Gradle KTS editing

Parallel stacks for Kotlin coroutines in the debugger

We’re grateful to everyone who participated in Google Summer of Code with the Kotlin Foundation. We are determined to make participating in GSoC a tradition.

Thank you for being a part of this journey with us!

Continue ReadingResults of Google Summer of Code With Kotlin

Tackle Advent of Code 2023 With Kotlin and Win Prizes!

Unwrap the joy of coding challenges as we gear up for Advent of Code, which JetBrains is proud to be sponsoring for a third consecutive year! Starting December 1, the JetBrains community will be diving into 25 days of coding challenges at adventofcode.com, and we warmly invite you to participate using Kotlin.

Advent of Code is a great way to discover new Kotlin features, enhance your problem-solving skills, and engage with a fantastic community. Take part for some friendly competition, valuable learning experiences, and the chance to win exclusive Kotlin prizes!

Watch on YouTube

Livestreams

Starting December 1, we’ll be holding livestreams every day at 5:00 pm UTC to discuss the puzzle of the day, giving you 12 hours to solve the puzzle before we go through it together. We’ll be joined by guests from the Kotlin team and the community to discuss possible approaches to the problems. It’s a great way to tackle the challenges together and learn some cool Kotlin tricks!

Community

Join the discussion in the Advent of Code channel on the Kotlinlang Slack, and share tips and tricks with other participants. Each day we’ll post a new thread where you can share your puzzle solutions. The most active community members will get some neat rewards!

Join Our Slack

Advent of Code Leaderboards

Take part in our dedicated Kotlin leaderboards. We’ll randomly pick several winners from among those who submit their solutions on GitHub, and the top scorers will also get some fantastic prizes.

Since the leaderboard space is limited and in high demand, we’ve created seven leaderboards to fit everyone interested. To join, head to the Leaderboard section in your Advent of Code profile and enter one of the codes below:

Leaderboard 1: 2553782-b2a92b30

Leaderboard 2: 3240090-7d776460

Leaderboard 3: 3240094-c8ce397b

Leaderboard 4: 3240651-e9dd79d4

Leaderboard 5: 3240655-edd1d88b

Please join only one leaderboard. Thank you!

Resources

We’ve compiled some useful Advent of Code resources to help you get in the spirit:

  • The Advent of Code in Kotlin GitHub template.
  • Previous years’ solutions to Advent of Code puzzles in idiomatic Kotlin.
  • The Tips and Tricks for Solving Advent of Code blog post.
  • The Algorithmic Challenges in Kotlin plugin-based course.

Template

Make the most of our GitHub template, which is designed to streamline the structure of your solutions. This repository template is specifically for use with Kotlin, and it offers a solid foundation for your solutions, allowing you to get set up quickly so you can dive right into the problems.

To create a new project with this template, simply log in to your GitHub account, follow the link below, and click the green Use this template button. Please do not fork it!

Use the template

Advent of Code in Kotlin Template

This is a fork of the main Advent of Code Kotlin Template repository that uses the Amper tool for project configuration, recently introduced by JetBrains. With this version, we swapped the standard Gradle build configuration with the module.yaml Amper file.

Prizes

For a chance to grab some fantastic prizes by participating in Advent of Code with Kotlin, be sure to follow these steps:

  • Tackle at least three days of Advent of Code 2023 challenges in Kotlin.
  • Share your solutions publicly on GitHub.
  • Have your contact details (email address or Twitter handle) available in your GitHub profile.
  • Follow the Advent of Code guidelines, which forbid you from using AI or LLMs to solve the puzzles.
  • Add the topic “aoc-2023-in-kotlin” to your repository.

To include the “aoc-2023-in-kotlin” topic in your repository, edit the repository details by clicking the gear icon in the top right-hand corner of the repository page. Next, in the topics field, add the value:

Advent of Code in Kotlin Topic

We genuinely appreciate everyone’s enthusiasm for this friendly competition! Our aim is to provide you with an enjoyable experience as you explore the beauty of solving holiday puzzles in idiomatic Kotlin.

Join us for Advent of Code 2023 with Kotlin for a chance to learn, have fun, and be a part of a fantastic community! 

Happy coding!

Continue ReadingTackle Advent of Code 2023 With Kotlin and Win Prizes!

KotlinConf 2024 Tickets Are Now Available! 

KotlinConf is bringing the Kotlin community together for the fifth time, from May 22 to 24, 2024, at the Bella Center in Copenhagen, Denmark!

KotlinConf’24 will feature one day of workshops followed by two consecutive days of content and networking, including sessions, expo booths, and other fun activities. Secure your tickets, organize your travel, and get ready to come together for the biggest Kotlin event around.

Book your tickets now!

On May 22, 2024, you’ll have the opportunity to immerse yourself in one of six expert-led workshops covering some of the most popular Kotlin topics. Seats for each are limited, so register soon if you’d like to attend. 

Choose your workshop:

  • Asynchronous Programming With Kotlin Coroutines by Sebastian Aigner and Roman Elizarov. 
  • Kotlin Multiplatform Beyond the Basics by Garth Gilmour and Pamela Hill. 
  • Functional Programming in Kotlin by Simon Vergauwen and Francisco Diaz Rodriguez.
  • Hands-On Kotlin Web Development with Ktor by Anton Arhipov, Pasha Finkelshtein and Leonid Stashevsky.
  • Mastering Kotlin Refactoring – Tools and Techniques by Duncan McGregor and Nat Pryce.
  • Reactive Spring Boot With Coroutines and Virtual Threads by Urs Peter.

KotlinConf tickets always go fast. The last conference was completely sold out around 4 months in advance, so we recommend getting your tickets now.

Secure your spot

To get a glimpse of what’s in store for you at the conference, you can watch the recordings of the KotlinConf 2023 talks online.

Be sure to check out kotlinconf.com for more information and follow KotlinConf on Twitter for news, updates, and special announcements.

Continue ReadingKotlinConf 2024 Tickets Are Now Available! 

Join Us Live at the ICPC World Finals for a Stellar Kotlin Lockout Match

Watch the Livestream

JetBrains has been a proud sponsor of the International Collegiate Programming Contest for a number of years. This year, we’re proud to support the 45th ICPC World Finals taking place in Dhaka, Bangladesh. 

To unveil the full power of Kotlin and JetBrains tools, as well as their advantages in algorithmic problem-solving, we’ve invited two competitive programming stars to match their skills in solving Kotlin problems on stage at the ICPC World Finals. Andrew ‘ecnerwala’ He, one of the top competitive programmers in the world, will compete in a lockout session against Gennady ‘tourist’ Korotkevich, the world’s most awarded competitive programmer and a repeat winner of Kotlin Heroes. The match will be commentated by none other than Roman Elizarov. 

We are going to livestream this event on November 7, 2022, and we invite you to join us!

Watch the Livestream

To refresh your knowledge about Kotlin and learn more about competitive programming, check out our competitive programming tutorial and watch the videos from our Competitive Programming YouTube playlist.

We look forward to seeing you soon on the livestream!

Continue ReadingJoin Us Live at the ICPC World Finals for a Stellar Kotlin Lockout Match

Join Us Live at the ICPC World Finals for a Stellar Kotlin Match

JetBrains has been a proud sponsor of the International Collegiate Programming Contest for a number of years. This year, we’re proud to support the 45th ICPC World Finals taking place in Dhaka, Bangladesh. 

To unveil the full power of Kotlin and JetBrains tools, as well as their advantages in algorithmic problem-solving, we’ve invited two competitive programming stars to match their skills in solving Kotlin problems on stage at the ICPC World Finals. Andrew ‘ecnerwala’ He, one of the top competitive programmers in the world, will compete in a lockout session against Kamil ‘Errichto’ Debowski, Codeforces “Legendary Grandmaster” and Topcoder “Target”. The match will be commentated by none other than Roman Elizarov. 

We are going to livestream this event on November 7, 2022, and we invite you to join us!

Watch the Livestream

To refresh your knowledge about Kotlin and learn more about competitive programming, check out our competitive programming tutorial and watch the videos from our Competitive Programming YouTube playlist.

We look forward to seeing you soon on the livestream!

Update: Due to unforeseen circumstances, Kamil ‘Errichto’ Debowski replaced Gennady ‘tourist’ Korotkevich in this ICPC World Finals Kotlin lockout match.

Continue ReadingJoin Us Live at the ICPC World Finals for a Stellar Kotlin Match

KotlinConf가 2023년 4월 암스테르담에서 다시 개최됩니다!

기쁘다는 말로는 부족한 소식이 있습니다. 바로 KotlinConf가 다시 개최된다는 매우 기대되고, 기쁨과 즐거움이 넘치는 소식입니다!

🌷 2023년 4월 12~14일에 암스테르담에서 KotlinConf 행사가 개최됩니다. 마침내 다시 한자리에 모여 Kotlin과 관련한 흥미로운 소식을 전해 드릴 수 있습니다!

올해의 행사에서 Kotlin 커뮤니티와 함께하려면 지금 등록하세요. 워크숍, 토크, fun이 함께합니다! 티켓이 매진되기 전에 구매하세요!

티켓 구매하기

워크숍 데이

워크숍 첫날인 2023년 4월 12일, KotlinConf가 시작됩니다. 각 워크숍에 인원 제한이 있으므로 워크숍에 참석하고 싶다면 바로 등록하세요.

컨퍼런스 패스와 함께 워크숍 참여권 1개를 구매할 수 있습니다. 아래의 내용을 확인하고 원하는 워크숍을 선택하세요.

Building Android Apps With Jetpack Compose(Jetpack Compose로 Android 앱 빌드하기) – Florina Muntenescu

이 워크숍을 통해 기초를 단단히 다지고 상태, 레이아웃, 디자인 시스템 및 애니메이션을 사용하는 선언형 사고 방식의 기초를 학습할 수 있습니다. 또한 뷰 기반 앱에서 Compose로의 실제 마이그레이션 과정을 살펴보고, Jetpack Compose에서 레이아웃의 작동 방식을 상세히 알아보며 워크숍을 마무리할 예정입니다.

Kotlin Multiplatform Mobile in Production(프로덕션 단계에서 Kotlin Multiplatform Mobile의 활용) – Kevin Galligan, Tadeas Kriz, Russell Wolf

이 워크숍에서는 빌드 시스템 및 도구 통합, iOS 측 SDK 디자인, 팀 구조, ‘Kotlin으로 개발하는 사람’ 등 Kotlin Multiplatform Mobile을 프로덕션에 적용하는 몇 가지 실습 중심의 예시를 살펴봅니다.

Kotlin TDD Masterclass(Kotlin TDD 마스터 클래스) – Nat Pryce, Duncan McGregor

테스트 주도 개발(TDD)과 관련한 실습 중심의 이 워크숍에서 TDD에 활용 가능한 Kotlin의 기능 및 TDD 방식이 Kotlin에 제공하는 이점을 살펴볼 예정입니다. 함수형 스타일이 테스트 및 디자인에 어떤 영향을 미칠까요? 모킹을 피할 수 있을까요? 과연 그렇게 하는 게 맞을까요? 테스트 중 타입 시스템의 역할은 무엇일까요? 워크숍을 통해 이와 같은 질문의 답을 함께 찾아보세요.

Building Scalable Microservices With Ktor and Kafka(Ktor 및 Kafka를 사용하여 확장 가능한 마이크로서비스 구축) – Anton Arhipov, Viktor Gamov

이 워크숍에서는 서버 측 개발을 위한 3가지 K(Kotlin 프로그래밍 언어, Ktor 서비스 프레임워크, 이벤트 스트리밍을 위한 Kafka)를 설명합니다. 워크숍을 마치면 다음과 같은 지식을 습득할 수 있습니다.

  • Ktor를 사용하여 유연한 RESTful 서비스를 만들고 배포하는 방법.
  • 추가 구성이 필요한 외부 라이브러리와 Ktor를 통합하는 방법.
  • Kafka 스트리밍과 같은 다양한 도구를 사용하여 서비스를 유연하게 연결하는 방법.

Asynchronous Programming With Kotlin Coroutines(Kotlin 코루틴을 사용한 비동기 프로그래밍) – Svetlana Isakova, Sebastian Aigner, Roman Elizarov

이 워크숍에서는 Kotlin 코루틴을 활용하여 생산성을 향상하는 데 필요한 모든 것을 학습합니다. 워크숍을 완료하면 코루틴 관련 용어를 익히고, 일반적 문제를 발견하고 예방하는 방법을 이해할 수 있습니다. 또한 프로젝트에서 코루틴을 효과적으로, 자신감 있게 사용할 수 있습니다.

Reactive Spring Boot With Coroutines(코루틴을 사용한 반응형 Spring Boot) – Urs Peter

이 워크숍에서는 Spring Boot의 코루틴 지원이 미흡한 Webflux 접근 방식의 모든 단점을 제거하고, 복잡하지 않게 반응형 기능을 제공하는 방식을 학습할 수 있습니다.

Kotlin Multiplatform 입문 – Romain Boisselle, Salomon Brys

이 워크숍을 통해 Jetpack Compose로 Android에서, Swift UI로 iOS, JetBrains Compose Web으로 웹에서, JetBrains Compose Desktop으로 데스크톱 JVM에서 실행되는 작은 애플리케이션을 개발합니다. 이러한 애플리케이션은 네이티브 룩앤필을 제공하고 완전히 테스트를 거쳐 일관성 있는 비즈니스 레이어를 재사용할 수 있습니다.

Kotlin을 사용한 함수형 프로그래밍 – Raúl Raja Martínez, Alejandro Serrano Mena, Simon Vergauwen

이 워크숍에서는 Kotlin 코드에 직접 적용 가능한 함수형 프로그래밍의 개념을 살펴봅니다. Arrow가 지원 라이브러리로 사용됩니다. 이 라이브러리는 함수형 스타일을 한층 잘 활용할 수 있도록 유용한 타입 및 확장자를 제공합니다.

KotlinConf 등록하기

발표자 모집

KotlinConf는 커뮤니티 이벤트로, 많은 분들의 참여를 기다립니다. 지금 발표자를 모집하고 있습니다!

발표 주제를 제출하고 여러분의 경험을 공유해 주세요. Kotlin을 사용한 혁신적인 방법, 여러분이 경험한 문제, 직접 제작한 프레임워크 또는 다른 사람에게 도움이 될 만한 정보라면 무엇이든 발표 주제가 될 수 있습니다.

발표 주제 제출하기


KotlinConf’23에 대한 자세한 내용을 알아보려면 kotlinconf.com을 방문하고 트위터에서 KotlinConf를 팔로우해 주세요.

게시물 원문 작성자

Ksenia Shneyveys

Continue ReadingKotlinConf가 2023년 4월 암스테르담에서 다시 개최됩니다!

KotlinConf 将于 2023 年 4 月在阿姆斯特丹回归!

KotlinConf 回来了! 我们很高兴宣布这个消息,实在是迫不期待了!

🌷 下一届 KotlinConf 将于 2023 年 4 月 12 日至 14 日在阿姆斯特丹线下举行。 我们终于可以再次聚在一起,分享 Kotlin 的精彩之处了。

立即注册,加入 Kotlin 社区的年度盛会。 将有研讨会、演讲,并且保证充满乐趣! 抓紧时间购买门票,以免售罄!

购买门票

研讨会日

我们将在 KotlinConf 的第一天(2023 年 4 月 12 日)举行研讨会。 每个研讨会的席位有限,因此如果您有兴趣参加,请尽快注册。

除了购买会议通行证之外,还可以购买研讨会门票。 选择您喜欢的研讨会

Building Android Apps with Jetpack Compose(使用 Jetpack Compose 构建 Android 应用),主持人:Florina Muntenescu

在这个研讨会中,您将从打下坚实的基础开始,学习声明式思维的基本原理,使用状态、布局、设计系统和动画。 然后,您将完成一个从基于视图的应用到 Compose 的实际迁移,最后深入了解布局在 Jetpack Compose 中的运作方式。

Kotlin Multiplatform Mobile in Production(在生产中使用 Kotlin Multiplatform Mobile),主持人:Kevin Galligan、Tadeas Kriz 和 Russell Wolf

在这个研讨会中,我们将通过一些动手示例,将 Kotlin Multiplatform Mobile 投入生产,包括构建系统和工具集成、iOS 端 SDK 设计、团队结构和“谁编写 Kotlin?”等。

Kotlin TDD Masterclass(Kotlin TDD 大师班),主持人:Nat Pryce 和 Duncan McGregor

在这个关于测试驱动型开发的动手研讨会上,我们将探讨 Kotlin 和 TDD 给彼此带来了什么。 函数式编程是如何影响测试和设计的? 我们能不能避免模拟,我们是否应该避免? 在有测试的情况下,类型系统扮演什么角色? 加入我们并找出答案!

Building Scalable Microservices With Ktor and Kafka(使用 Ktor 和 Kafka 构建可扩缩的微服务),主持人:Anton Arhipov 和 Viktor Gamov

在这个研讨会中,我们将介绍服务器端开发的三个 K:Kotlin 编程语言、Ktor 服务框架和用于事件流的 Kafka。 在研讨会结束时,您将了解:

  • 如何使用 Ktor 创建和部署弹性 RESTful 服务。
  • 如何将 Ktor 与需要额外配置的外部库集成。
  • 如何使用各种工具(如 Kafka 流)灵活地连接服务。

Asynchronous Programming With Kotlin Coroutines(使用 Kotlin 协同程序进行异步编程),主持人:Svetlana Isakova、Sebastian Aigner 和 Roman Elizarov

在这个研讨会中,您将学习在 Kotlin 中使用协同程序提高效率所需的一切。 研讨会结束时,您将增强自己的协同程序词汇,了解如何发现和避免常见问题,并能够在您自己的项目中有效且自信地使用协同程序。

Reactive Spring Boot With Coroutines(反应式 Spring Boot 与协同程序),主持人:Urs Peter

在这个研讨会中,您将了解 Spring Boot 的协同程序支持如何消除“原始”Webflux 方式的所有缺点,并为您提供毫不复杂的反应式特性。

Getting Started With Kotlin Multiplatform(Kotlin Multiplatform 使用入门),主持人:Romain Boisselle 和 Salomon Brys

在这个研讨会中,我们将构建一个小型应用程序:使用 Jetpack Compose 构建在 Android 上运行的变体,使用 Swift UI 构建在 iOS 上运行的变体,使用 JetBrains Compose Web 构建在网络上运行的变体,使用 JetBrains Compose Desktop 构建在桌面 JVM 上运行的变体,提供原生外观,同时重用一个经过充分测试的连贯业务层。

Functional Programming in Kotlin(Kotlin 中的函数式编程),主持人:Raúl Raja Martínez、Alejandro Serrano Mena 和 Simon Vergauwen

在这个研讨会中,我们将研究直接适用于 Kotlin 代码的函数式编程的概念。 我们将使用 Arrow 作为支持库,它包括许多有用的类型和扩展,能够使函数式编程体验更加愉悦。

预定席位

演讲嘉宾招募

KotlinConf 是一个社区活动,因此我们希望您能参加。论文征集现已开放!

提交演讲主题并分享您的经历,无论是寻找使用 Kotlin 的创新方式、您面临的挑战、您创建的框架,还是您想分享的任何可以帮助其他人的内容。

提交您的演讲主题


有关 KotlinConf’23 的更多信息,请访问 kotlinconf.com 并在 Twitter 上关注 KotlinConf

本博文英文原作者:

Ksenia Shneyveys

Continue ReadingKotlinConf 将于 2023 年 4 月在阿姆斯特丹回归!

KotlinConf returns to Amsterdam in April 2023!

We’re happy – no, strike that! – we’re thrilled, ecstatic, and overjoyed to announce that KotlinConf is back!

🌷 The next KotlinConf will take place in person in Amsterdam on April 12–14, 2023. Finally we’ll be able to get together again and share the exciting things going on with Kotlin. 

Register now to join the Kotlin community at the event of the year. Workshops, talks, and fun are guaranteed! Get your tickets before they run out!

Get tickets

Workshop Day

We’ll kick off KotlinConf with the first day of workshops – April 12, 2023. The seats for each workshop are limited, so please register soon if you are interested in attending. 

One workshop can be bought in addition to the conference pass. Choose your favorite:

Building Android Apps With Jetpack Compose, by Florina Muntenescu

In this workshop, you’ll start by building a solid foundation and learn the fundamentals of declarative thinking, working with states, layouts, design systems, and animation. You’ll then walk through a practical migration of a View-based app to Compose, and finish by diving deeper into how layouts work in Jetpack Compose.

Kotlin Multiplatform Mobile in Production, by Kevin Galligan, Tadeas Kriz, and Russell Wolf

In this workshop, we’ll work through some hands-on examples of putting Kotlin Multiplatform Mobile into production, including build system and tooling integration, iOS-side SDK design, team structure and “Who writes Kotlin?”, and more.

Kotlin TDD Masterclass, by Nat Pryce and Duncan McGregor

In this hands-on Test Driven Development workshop, we’ll explore what Kotlin brings to TDD, and what TDD brings to Kotlin. How does a functional style affect testing and design? Can we avoid mocking, and should we? What role does the type system play when we have tests? Join us and find out.

Building Scalable Microservices With Ktor and Kafka, by Anton Arhipov and Viktor Gamov

In this workshop, we will cover the three Ks for server-side development: the Kotlin programming language, the Ktor services framework, and Kafka for event streaming. By the end of the workshop you will know:

  • How to create and deploy resilient RESTful services using Ktor.
  • How to integrate Ktor with external libraries that require additional configuration.
  • How to flexibly connect services using a variety of tools, such as Kafka streams.

Asynchronous Programming With Kotlin Coroutines, by Svetlana Isakova, Sebastian Aigner, and Roman Elizarov

In this workshop, you’ll learn everything you need to become productive with coroutines in Kotlin. By the end, you’ll have enhanced your coroutines-related vocabulary, understand how to spot and avoid common problems, and will be able to effectively and confidently use coroutines in your own projects.

Reactive Spring Boot With Coroutines, by Urs Peter

In this workshop, you’ll learn how Spring Boot’s Coroutine support wipes out all of the downsides of the ‘raw’ Webflux approach and provides you with reactive characteristics without the complexity.

Getting Started With Kotlin Multiplatform, by Romain Boisselle and Salomon Brys

In this workshop, we’ll be building a small application that runs on Android with Jetpack Compose, on iOS with Swift UI, on the web with JetBrains Compose Web, and on desktop JVMs with JetBrains Compose Desktop, providing a native look and feel while reusing a fully tested and coherent business layer. 

Functional Programming in Kotlin, by Raúl Raja Martínez, Alejandro Serrano Mena, and Simon Vergauwen

In this workshop, we’ll look at concepts from functional programming that are directly applicable to Kotlin code. We’ll use Arrow as a supporting library, which includes many useful types and extensions to make a functional style even more pleasant.

Secure your spot

Call for speakers

KotlinConf is a community event, so we would love for you to take part. The call for papers is now open!

Submit a talk and share your experience, whether it’s about finding innovative ways to use Kotlin, the challenges you’ve faced, a framework you’ve created, or anything you’d like to share that could help others along their journey.

Submit your talk


For more information on KotlinConf’23, be sure to visit kotlinconf.com and follow KotlinConf on Twitter.

Continue ReadingKotlinConf returns to Amsterdam in April 2023!

Tips and Tricks for Solving Advent of Code

Advent Of Code is currently ongoing and many people all over the world are taking part. We’d like to share some tips and tricks for solving the puzzles in Kotlin – we hope you find some of them helpful! Feel free to add your favorite tips or thoughts in the comments!.

If you’re solving the puzzles in Kotlin, don’t forget to add the aoc-2021-in-kotlin topic to your repo to take part in our giveaway! If you’re starting from scratch, consider using our prepared Github template.

How do you usually go about solving the puzzles? First of all, you read and parse the input data. Let’s start with some tips for this process, and then discuss tips for writing the actual solutions in Kotlin.

1. Jumping between sample and real input

All of the Advent of Code puzzles provide your own “personal” input and the sample input to check your solution. You often need to switch back and forth between the sample and real input. If the solution for the first part works for the sample input, you then need to run it on the real input to get your result. If the solution then works on the real input, you likely switch back to the sample input to start solving the second part of the puzzle.

One of the ways to switch between two inputs quickly is by using comments with the IntelliJ IDEA action “Comment with Line Comment”. This changes the line state and removes the comment from the commented line, rather than simply adding a comment.

You can put the sample and real inputs in different files and toggle between comments for the file names by pressing the Ctrl+/ shortcut twice:

Comment line action

These small things make a difference and make working with IntelliJ IDEA a pleasure!

2. Parsing input

The next thing to do after reading the input is to parse it. You can either use the Kotlin library functions for working with strings or regular expressions. Library functions like substringBefore() and substringAfter() cover lots of cases and are often enough. Use String.toInt() and Char.digitToInt() to convert the string content or characters into integers.

For more complicated scenarios, there are regular expressions. Use the destructured function to assign the output to different variables right away:

val inputLineRegex = """(d+),(d+) -> (d+),(d+)""".toRegex()

val (startX, startY, endX, endY) = inputLineRegex
    .matchEntire(s)
    ?.destructured
    ?: throw IllegalArgumentException("Incorrect input line $s")

The action “Check RegExp” in IntelliJ IDEA allows you to quickly check whether the sample input satisfies your regular expression.

Comment line action

3. Storing input

It’s often helpful to introduce domain types, even for smaller tasks like these puzzles. Solving the task for Cells and Boards, or for Segments and SevenSegmentDigits can be much easier than working directly with Ints, List of Lists of Ints, or Chars and Sets of Chars. Types help to direct your thinking to the heart of the problem.

Kotlin makes this really easy – define a one-line data class and that’s it. You don’t need a separate file, like in Java, since it’s in your main file with the rest of your solution code:

data class Step(val direction: Direction, val units: Int)

In Kotlin, you can use an extension to convert an input line directly to a required type:

fun String.toStep(): Step
fun String.toTicket(): Ticket
fun String.toSevenSegmentDigitList(): List<SevenSegmentDigit>

Then your typical starter code will look like this:

val steps = readInput(fileName).map(String::toStep)

You can either use the function reference String::toStep or the lambda expression map { it.toStep() }.

4. Enumerations instead of strings

It might be tempting to manipulate the string literals directly, but making them enum constants makes it easier to write the code and reason about how it works. You never know what comes in the second part of the puzzle!

enum class Direction { UP, DOWN, FORWARD }
data class Step(val direction: Direction, val units: Int)

It is easy to convert an input string to an enum and use the EnumClassName.valueOf("") function to get the constant by name:

// "forward 8"
fun String.toStep() = Step(
   Direction.valueOf(substringBefore(" ").uppercase()),
   substringAfter(" ").toInt()
)

With when expressions you can check all of the options and you don’t need to include the else branch:

Comment line action

IntelliJ IDEA can generate all the branches automatically.

for ((direction, units) in steps) {
   when (direction) {
       UP -> depth -= units
       DOWN -> depth += units
       FORWARD -> horizontalPosition += units
   }
}

Note that in the destructuring declaration syntax in the for loop, you automatically assign two properties, the contents of each Step, into two loop variables.

5. From typealias to a class

If working with primitives is easier at first, and defining a separate class looks too cumbersome, consider defining a typealias. You can convert it into a class later, if needed. When you replace a typealias with a class, most of the code continues to compile, and you immediately see which functions are missing.

typealias Segment = Char
data class SevenSegmentDigit(val segments: Set<Segment>) {
   constructor(s: String): this(s.toSet())
   override fun toString() = segments.toList().sorted().joinToString("")
}

For example, the characters from 'a' to 'g' used to encode the seven-segment display can be referred to as Segments in the code and be regular Chars underneath. You can define the SevenSegmentDigit class first as a typealias for Set and later convert it to a class, for example, if you want to replace a default toString with a custom one.

6. Building lists and maps

In addition to the standard listOf(), mutableListOf(), and similar functions, you can use other methods to build collections.

You can call the List function that looks like a constructor (but is not!) to provide a way to calculate each element:

List(4) { it * it } // [0, 1, 4, 9]

Use buildList and buildMap functions to build data structures imperatively:

val monsters: List<Position> = buildList {
   for (y in 0..tile.size - Monster.height) {
       for (x in 0..tile.size - Monster.width) {
           if (monsterAt(tileRotation, x, y)) {
               add(Position(x, y))
           }
       }
   }
}

In this example, we call add on a MutableList inside the lambda, and the resulting type is the read-only List.

The similar sequence {..} function builds a Sequence lazily yielding values one by one.

7. Associate and group

The task of building a map from a list occurs quite often, and associate and groupBy functions make this operation straightforward. You can group elements by the provided property with groupBy, use elements as map keys to provide a way to build values (associateWith), use elements as values (associateBy), or provide a way to build a key-value pair from each element (associate).

The groupBy function groups the elements with the specified value used as a map key:

val occurrences: Map<Int, List<Segment>> =
   segments.groupBy { countSegmentInAllDigits(it) }
// {8=[a, b], 9=[c], 7=[d, g], 4=[e], 6=[f]}

The result of calling countSegmentInAllDigits in this example becomes the key in the map.

If you don’t need the groups directly, but you need to find the size of each group, use a lazy counterpart to groupBy: the groupingBy function. It doesn’t return a map straightaway, but it allows you to analyze the groups in a lazy manner:

listOf("abc", "c", "ad", "bc", "ab", "ca")
   .groupingBy(String::first)
   .eachCount() // {a=3, e=2, d=1}

If the property you’re using to group the elements is unique, use associateBy. For instance, if you need to access elements by their indexes, associateBy will build a map from indexes to elements for you:

val rulesMap: Map<Int, Rule> = rules.associateBy { it.index }

Let’s imagine you need to build a map representing an initial state by associating each of the input numbers with the corresponding Node. Use associateWith:

val initialState: Map<Int, Node> = numbers.associateWith { Node(it) }

If you need more complicated keys and values, use associate:

val bagRuleMap: Map<Bag, List<Content>> = bagRules.associate { it.bag to it.contentList }

If you don’t remember which associate function you need, choose the general associate one, and IntelliJ IDEA will suggest a better one automatically:

Comment line action

8. Sliding by windows

Sliding a list to get chunks of a given size is often useful, like in this year’s first puzzle.

numbers.windowed(2).count { (first, second) -> first < second }
"abcde".windowed(2) // [ab, bc, cd, de]

An alternative to building a list of chunks of size 2 is to use zipWithNext().

9. Sum of, min of

You don’t need to map the elements first to later find the resulting sum – the sumOf function combines these two operations. IntelliJ IDEA even suggests these replacements automatically:

Comment line action

There are similar functions maxOf and minOf for finding the maximum and minimum among the transformed values.

10. Adding index

Need to perform computations with an element index? In addition to the withIndex() extension that returns a list of pairs to iterate through, you can use many “indexed” counterparts for standard library functions, such as forEachIndexed, filterIndexed, mapIndexed, foldIndexed, and so on.

In the following example, the final calculateScore function uses the indexed version of fold to include an index into a computation of the result:

fun RoundConfiguration.calculateScore(): Long {
   val winner = listOf(playerA, playerB).maxByOrNull { it.size }!!
   return winner
       .cards()
       .foldIndexed(0L) { index, acc, element ->
           acc + (winner.size - index) * element
       }
}

Note how we marked 0 as a Long constant here (0L) to perform the computation on Long values.

11. Also logging

If the puzzle answer isn’t correct and you want to track the intermediate results step by step, you can print or log the intermediate values. The also function allows you to include println or log directives in the middle of the call chain or display the function result if you use an expression-body syntax.

In this example, we return the result of the function and also do some logging:

private fun checkRow(row: List<Int>, visited: Set<Int>) =
   row.all { elem -> elem in visited }
       .also { result -> log("Checking row $row $visited: $result") }

Here, we insert also calls in the middle of the call chain to observe the intermediate results of the computation:

val differences = input
   .windowed(2)
   .also(::log)
   .map { (first, second) -> second - first }
   .also(::log)
   .sorted()

If you need to print each list element on a separate line, you can include .onEach(::println) to the middle of the call chain. onEach performs an operation on each element and returns the unmodified list.

To avoid commenting on the lines with println, make a habit of using your own small log function instead. This way, you only need to change it in one place to stop printing all of the intermediate values for your solution.

12. Queue and stack together

Need a queue or a stack to implement an algorithm when solving the puzzle? Use ArrayDeque, a double-ended queue that provides quick access to both ends. It can be used either as a queue or a stack when needed.

For instance, in a classic implementation of a depth-first search, create a queue as an ArrayDeque and call its add and removeFirst methods inside:

fun dfs(board: Board, initial: Cell): Set<Cell> {
   val visited = mutableSetOf<Cell>()
   val queue = ArrayDeque<Cell>()
   queue += initial
   while (queue.isNotEmpty()) {
       val cell = queue.removeFirst()
       visited += cell
       queue += board.getUpperNeighbors(cell)
   }
   return visited
}

In this example, we use the short syntax += to call the plusAssign(element: T) and plusAssign(elements: Iterable) operators, which simply redirect to the corresponding add functions.

Of course, the ArrayDeque structure is useful any time you need quick access to both the start and end of the list of elements.

13. Operators

Operator overloading, which looks like mostly library or DSL-magic functionality, might also be useful when solving such small puzzles.

Consider overloading get and set operators to simplify the code for working with your class. For instance, by providing the get operator that takes Cell as an argument for the following class you can access its content more easily:

dataclass Board(val content: List<List<Int>>) {
   operator fun get(cell: Cell) =
       content.getOrNull(cell.i)?.getOrNull(cell.j)
}

Instead of writing board.content[cell.i][cell.j] for all invocations, you write

board[cell]. You can provide the set operator for mutable content accordingly.

Using the contains operator might make the code cleaner:

data class Line(val start: Point, val end: Point) {
   operator fun contains(point: Point): Boolean { … }
}

Then you can call it via the in keyword:

inputLines.count { line -> point in line }

If your elements are comparable, you can make them implement the Comparable interface, and then compare the elements using the standard <, <=, >, and >= operations.

———

Last but not least, consider creating a collection of your utilities specifically for solving Advent of Code puzzles. For example, you’ll definitely find a task that requires a point with two integer coordinates and uses its neighboring points!

That’s all for now! We hope that you enjoy solving the AdventOfCode puzzles as much as we do, and find these small tips useful!

Continue ReadingTips and Tricks for Solving Advent of Code

Advent of Code 2021 in Kotlin, Day 3: Binary Diagnostic

The nautical advent-ure continues with the third day of AOC 2021, which we will, of course, once more solve in Kotlin! This time, it will involve wrangling binary numbers in all sorts of ways. Check out the solution and a detailed explanation on YouTube, or follow along as we explain our solution in this blog post!

Solving part 1

We’re on maintenance duty today: That means we’re working with a report of binary numbers. Our goal is to calculate two values in order to get our gold star. They are referred to as the gamma and epsilon rate in the original problem description, which you can find on adventofcode.com.

We calculate the gamma rate by determining the most common bit for each position of the binary numbers in our input. When there’s more “1” bits than “0” bits in a column, the resulting number will be a “1”. Or when it is the other way around, and we see more “0” bits than “1” bits, our result will have a “0” in that position. We repeat that process for each column in our inputs until we get the final gamma rate in binary representation.

The epsilon rate is calculated analogously to the gamma rate, only this time, it always looks at the least common bit in each position.

Once both numbers are calculated, we arrive at the answer – the power consumption of our submarine – by converting the two numbers to decimal, and multiplying them.

Let’s turn our intuitive understanding into a Kotlin program! These examples use the scaffolding provided by the Advent of Code Kotlin Template, but a standalone solution would look very similar.

fun main() {
    fun part1(input: List<String>): Int {
        TODO()
    }

    val testInput = readInput("Day03_test")
    val input = readInput("Day03")
    println("P1 Test: " + part1(testInput))
    check(part1(testInput) == 198)
    println("P1 Result: " + part1(input))
}

Gamma rate: Most popular bits

From the problem description, we know that we are going to need to iterate our list of inputs (a list of binary strings) column by column. We can assume that all numbers in the input have the same length, so we can use the zero’th element, and save its indices into a variable via the indices function.

We can then loop over all the column indices, and count the number of ones and zeroes in that column to help us decide what we should do next. Ideally, we would like to use a function such as the following:

val columns = input[0].indices
for(column in columns) {
    input.countBitsInColumn(column)
}

Since this is a pretty problem-specific function, the standard library does not come with an implementation for it. But with the power of extension functions, we can build this exact function ourselves! A simple implementation looks like this:

private fun List<String>.countBitsInColumn(column: Int): Pair<Int, Int> {
    var zeroes = 0
    var ones = 0
    for(line in this) {
        if(line[column] == '0') zeroes++ else ones++
    }
    return zeroes to ones
}

The function keeps track of the ones and zeroes, and returns them as a Pair (constructed via the infix function to).

We can still make this code a bit more expressive, by replacing the Pair return type with our own custom data class:

private data class BitCount(val zeroes: Int, val ones: Int)

By having the function return an instance of BitCount, the zeroes and ones can be accessed explicitly, and our code has become a little bit more expressive:

val bitCount = input.countBitsInColumn(column)
val zeroes = bitCount.zeroes
val ones = bitCount.ones

Since BitCount is a data class, we can use a destructuring declaration to elegantly access the zeroes and ones directly instead of having to write the three lines above. This single line has the same effect:

val (zeroes, ones) = input.countBitsInColumn(column)

Creating the string of binary numbers that makes up the gamma rate is now a matter of figuring out which bit is more popular, and concatenating all of these bits into a single string. To do so, we can use Kotlin’s buildString function, which gives us access to a StringBuilder. We can combine that with a short if-expression, and append the most common bit to the gammaRate string:

val gammaRate = buildString {
    for (column in columns) {
        val (zeroes, ones) = input.countBitsInColumn(column)
        val commonBit = if (zeroes > ones) "0" else "1"
        append(commonBit)
    }
}

This makes up the first half of the solution for part 1. To see the calculated value, we can turn this string of binary digits back into a real integer using the toInt function, and telling it we’re looking at a base-2 number:

return gammaRate.toInt(2)

This outputs “22”! We can confirm that this is indeed the correct gamma rate for the given sample input by going back to adventofcode.com and carefully re-reading the instructions. Great!

Epsilon rate: The binary inverse

Moving on to the epsilon rate, we make use of the property we observed in our initial discussion: the epsilon rate is just the binary inverse of the gamma rate. Where you see a “1” in the gamma rate, there’s a “0” in the epsilon rate, and vice versa. Once again, using an extension function, the call site for the epsilon rate looks like this:

val epsilonRate = gammaRate.invertBinaryString()

We can use a few primitives from the standard library to assemble the implementation for invertBinaryString: we use the asIterable function to get access to the individual characters, and use the joinToString function to turn each “0” into a “1” and each “1” into a “0”:

private fun String.invertBinaryString() = this
    .asIterable()
    .joinToString("") { if (it == '0') "1" else "0" }

To get the final result, we multiply these two numbers together, and obtain the power consumption of the submarine, which we can submit and get our first gold star for the day!

return gammaRate.toInt(2) * epsilonRate.toInt(2)

Intermission: An alternative approach for the gamma rate

Before moving on to part 2 of the challenge, let’s reuse our knowledge that joinToString takes a transform function, and attempt to write a more functional version of the algorithm that calculates the gamma rate in this problem. We can combine the map function, a destructuring declaration, and joinToString to get the same result as the solution that uses a for-loop, buildString, and append:

val gammaRate2 = columns
    .map { input.countBitsInColumn(it) }
    .joinToString("") { (zeroes, ones) ->
        if (zeroes > ones) "0" else "1"
    }

check(gammaRate == gammaRate2)

Having seen both solutions, which one do you prefer? Feel free to let us know in the comments below, or on our YouTube video!

Here’s the complete implementation of part 1 again, for reference:

fun part1(input: List<String>): Int {
    val columns = input[0].indices
    val gammaRate = buildString {
        for (column in columns) {
            val (zeroes, ones) = input.countBitsInColumn(column)
            val commonBit = if (zeroes > ones) "0" else "1"
            append(commonBit)
        }
    }
    val gammaRate2 = columns
        .map { input.countBitsInColumn(it) }
        .joinToString("") { (zeroes, ones) ->
            if (zeroes > ones) "0" else "1"
        }
    check(gammaRate == gammaRate2)
    val epsilonRate = gammaRate.invertBinaryString()
    return gammaRate.toInt(2) * epsilonRate.toInt(2)
}

private fun String.invertBinaryString() = this
   .asIterable()
   .joinToString("") { if (it == '0') "1" else "0" }

private fun List<String>.countBitsInColumn(column: Int): BitCount {
   var zeroes = 0
   var ones = 0
   for (line in this) {
       if (line[column] == '0') zeroes++ else ones++
   }
   return BitCount(zeroes, ones)
}

Solving part 2

For part 2, we once again multiply numbers together: this time, the oxygen generator rating, and the CO2 scrubber rating! You can find detailed instructions on how to calculate these numbers on adventofcode.com. We’ll also discuss the computation of the oxygen generator rating here as an example.

The algorithm once again iterates the numbers column by column again, determining the most frequent bit (or, in the case of the CO2 scrubber rating, the least frequent bit). Then, the process of elimination is applied: all numbers that don’t have the most frequent bit are removed, and only the numbers which have the most popular bit in the given position remain. Tiebreakers go to the numbers with “1” in a given position for the oxygen generator rating, and the inverse for the CO2 scrubber.

This process is repeated until only one number remains, which is our result.

Computing the oxygen generator rating

Let’s start by defining a small local function for it, and let’s fill in some logic. We can structure the function similarly to our solution for part 1. To implement the process of elimination, we need to keep track of all the candidate numbers (starting with all of the input). We then need to repeatedly filter the list to make sure only the numbers with the most common bit at any given position remain.

We can reuse our countBitsInColumn implementation to arrive at a solution that looks like this:

fun oxyRating(): String {
    val columns = input[0].indices
    var candidates = input
    for(column in columns) {
        val (zeroes, ones) = candidates.countBitsInColumn(column)
        val mostCommon = if (zeroes > ones) '0' else '1'
        candidates = candidates.filter { it[column] == mostCommon }
        if(candidates.size == 1) break
    }
    return candidates.single()
}

When coming up with this snippet, it’s important we take great care to ensure the if-condition handles tiebreakers correctly: If “0” and “1” are equally common, it keeps values with a “1” in the position being considered.

Because I made the choice to use an immutable list here, removing elements is done via the filter function, which creates a new list. This list can then be assigned to the candidates variable again. If you’d like, you can also try to use a mutable list, and use the removeIf function for this algorithm, instead.

The only candidate that should remain can be extracted from the collection via the single function, and then returned. This allows us to already check our first partial result:

return oxyRating().toInt(2)

Copy-pasting the CO2 implementation

We can get our quick-and-dirty implementation of the CO2 scrubber rating by copy-pasting the code we wrote a moment ago, and adjusting the filter condition to keep only those candidates that don’t have the most common bit:

fun co2Rating(): String {
    val columns = input[0].indices
    var candidates = input
    for (column in columns) {
        val (zeroes, ones) = candidates.countBitsInColumn(column)
        val mostCommon = if (zeroes > ones) '0' else '1'
        candidates = candidates.filter { it[column] != mostCommon }
        if(candidates.size == 1) break
    }
    return candidates.single()
}

Together with our previous partial solution, this is actually enough to get our second gold star for the day – multiply the numbers, run the program, and get your reward:

return oxyRating().toInt(2) * co2Rating().toInt(2)

Removing duplication

Hopefully, you’ll agree at this point that our code could still be improved before we check it into our repository. Both co2Rating and oxyRating are essentially the same function, just with a different parameter. We only changed a single line of code in them – why would we want to have all that other code lying around as well? We can do better. We can define an enum class RatingType to distinguish between the types of ratings we want to calculate:

private enum class RatingType {
    OXYGEN,
    CO2
}

We can then turn one of the two rating functions into a multi-purpose implementation by using a when-statement based on the requested RatingType:

fun part2(input: List<String>): Int {
    fun rating(type: RatingType): String {
        val columns = input[0].indices
        var candidates = input
        for (column in columns) {
            val (zeroes, ones) = candidates.countBitsInColumn(column)
            val mostCommon = if (zeroes > ones) '0' else '1'
            candidates = candidates.filter {
                when (type) {
                    RatingType.OXYGEN -> it[column] == mostCommon
                    RatingType.CO2 -> it[column] != mostCommon
                }
            }
            if (candidates.size == 1) break
        }
        return candidates.single()
    }
    return rating(RatingType.OXYGEN).toInt(2) * rating(RatingType.CO2).toInt(2)
}

This code works the same, but is much more concise, and doesn’t contain duplications anymore. That’s much better!

We’re done!

That’s it! This code can go into our repository, and we can celebrate another problem solved, and hopefully some more Kotlin lessons learned.

If you’re coming up with your own solutions for Advent of Code, or if you’ve coded along to our videos, make sure to share your code on GitHub, and add the topic aoc-21-in-kotlin to your repo! This way you have a chance to win some Kotlin swag this holiday season! Check out the “Advent of Code 2021 in Kotlin” blog post for more details.

Enjoy yourself, keep warm, and take care!

Continue ReadingAdvent of Code 2021 in Kotlin, Day 3: Binary Diagnostic

End of content

No more pages to load