Arjen Wiersma

A blog on Emacs, self-hosting, programming and other nerdy things

Today we learned about CamelCards, a game of poker meant to play on the back of a camel. The most interesting part here was the parsing of the cards and figuring out how to properly rank them. Part 2 turned out to be as easy as tracking Jokers.

package main

import (
	"fmt"
	"sort"
	"strconv"
	"strings"
	"time"

	"arjenwiersma.nl/aoc/internal/aoc"
)

type Card struct {
	bid    int
	hand   []int
	jokers int
}

func (c *Card) strongerThen(o *Card) bool {
	for i, v := range c.hand {
		if v > o.hand[i] {
			return true
		} else if v < o.hand[i] {
			return false
		}
	}
	return false
}

func (c *Card) rank() int {
	freq := make([]int, 15)
	for _, v := range c.hand {
		if v == 1 { // skip counting the joker
			continue
		}
		freq[v]++
	}

	sort.Ints(freq)

	freq[len(freq)-1] += c.jokers
	strength := 2 * freq[len(freq)-1]
	// full house and 2 pair
	if freq[len(freq)-2] == 2 {
		strength += 1
	}
	return strength
}

func NewCard(s string, bid int, p2 bool) *Card {
	c := &Card{}
	c.bid = bid
	c.jokers = 0
	for p := 0; p < len(s); p++ {
		if s[p]-'0' >= 2 && s[p]-'0' <= 9 {
			c.hand = append(c.hand, int(s[p]-'0'))
		} else {
			x := 10
			switch s[p] {
			case 'A':
				x = 14
			case 'K':
				x = 13
			case 'Q':
				x = 12
			case 'J':
				if p2 {
					c.jokers += 1
					x = 1
				} else {
					x = 11
				}
			case 'T':
				x = 10
			}
			c.hand = append(c.hand, x)
		}
	}
	return c
}

func (c *Card) String() string {
	return fmt.Sprintf("%v (%d)", c.hand, c.bid)
}

func main() {
	content := aoc.AsLines("2023/Day07/input.txt")

	var cards []*Card
	for _, v := range content {
		p := strings.Split(v, " ")
		b, _ := strconv.Atoi(p[1])
		c := NewCard(p[0], b, false)
		cards = append(cards, c)
	}

	startTime := time.Now()
	lessFunc := func(i, j int) bool {
		if cards[i].rank() == cards[j].rank() {
			return cards[j].strongerThen(cards[i])
		}
		return cards[i].rank() < cards[j].rank()
	}

	sort.Slice(cards, lessFunc)

	res := 0
	for i, c := range cards {
		res += (i + 1) * c.bid
	}

	endTime := time.Now()
	elapsed := endTime.Sub(startTime)
	if 251216224 != res {
		panic("Wrong answer")
	}
	fmt.Printf("Part 1: %d (%v)\n", res, elapsed) // 251216224

	cards = []*Card{}
	for _, v := range content {
		p := strings.Split(v, " ")
		b, _ := strconv.Atoi(p[1])
		c := NewCard(p[0], b, true)
		cards = append(cards, c)
	}
	startTime = time.Now()

	sort.Slice(cards, lessFunc)

	res = 0
	for i, c := range cards {
		res += (i + 1) * c.bid
	}
	endTime = time.Now()
	elapsed = endTime.Sub(startTime)
	if 250825971 != res {
		panic("Wrong part 2")
	}
	fmt.Printf("Part 2: %d (%v)\n", res, elapsed) // 250825971
}

Day 6 turned out to be the easiest day in the range so far. A simple implementation of the algorithm was more than sufficient.

I later learned that it was a quadratic function. On the subreddit Deatranger999 said:

If you hold down the button for x seconds, then you will beat the distance if the quadratic x^2 – t x + d is at most 0, where t is the total time of the race and d is the distance you'd like to beat. So I just plugged each one into WolframAlpha, found the roots, and then calculated the number of integers between the two roots.

My solution was to bruteforce :)

package main

import (
	"fmt"
	"strconv"
	"strings"

	"arjenwiersma.nl/aoc/internal/aoc"
)

func main() {
	lines := aoc.AsLines("2023/Day06/input.txt")

	var times []int
	for _, t := range strings.Split(lines[0], " ")[1:] {
		s := strings.TrimSpace(t)
		if s == "" {
			continue
		}
		i, _ := strconv.Atoi(s)
		times = append(times, i)
	}
	var distances []int
	for _, t := range strings.Split(lines[1], " ")[1:] {
		s := strings.TrimSpace(t)
		if s == "" {
			continue
		}
		i, _ := strconv.Atoi(s)
		distances = append(distances, i)
	}

	result := make([]int, len(times))

	for i := 0; i < len(times); i++ {
		for t := 0; t < times[i]; t++ {
			d := t * (times[i] - t)
			if d > distances[i] {
				result[i] += 1
			}
		}
	}

	ans := 1
	for _, c := range result {
		ans *= c
	}

	fmt.Println("Part 1: ", ans)

	nT, _ := strconv.Atoi(fmt.Sprintf("%d%d%d%d", times[0], times[1], times[2], times[3]))
	nD, _ := strconv.Atoi(fmt.Sprintf("%d%d%d%d", distances[0], distances[1], distances[2], distances[3]))

	ans = 0
	for t := 0; t < nT; t++ {
		d := t * (nT - t)
		if d > nD {
			ans += 1
		}
	}
	fmt.Println("Part 2: ", ans)

}

Today was an interesting problem. We are basically given a map to follow based on a number, possibly transforming the number at each step. With a single number this is quite simple, just apply the rules and step through each set of transformations. The problem becomes tricky when it turns out we have to deal with enormous ranges of numbers. On the subreddit some people reported their implementation to take hours and use 20GB of memory.

Luckily there is always a fast solution. In this case it was using ranges of numbers to go through the transformations, so just taking the first number and then creating a (new) range out of the transformation instead of each individual number.

package main

import (
	"fmt"
	"log"
	"math"
	"os"
	"strconv"
	"strings"
	"time"

	"arjenwiersma.nl/aoc/internal/aoc"
)

type Range struct {
	d, s, r int
}

func (r *Range) transform(i int) int {
	if i >= r.s && i <= r.s+r.r-1 {
		delta := i - r.s
		return r.d + delta
	}

	return i
}

type Segment struct {
	from, to int
}

func main() {
	content, _ := os.ReadFile("2023/Day05/input.txt")
	segments := strings.Split(strings.TrimSpace(string(content)), "\n\n")

	seedStr := strings.Split(segments[0][6:], " ")
	var seed []int
	for _, x := range seedStr {
		if strings.TrimSpace(x) == "" {
			continue
		}
		s, err := strconv.Atoi(strings.TrimSpace(x))
		if err != nil {
			log.Fatal(s, err)
		}
		seed = append(seed, s)
	}
	// fmt.Println("Seeds: ", seed)

	maps := make([][]Range, len(segments)-1)
	for i, s := range segments[1:] {
		l := strings.Split(s, "\n")
		maps[i] = make([]Range, len(l)-1)
		for j, x := range l[1:] {
			var m Range
			fmt.Sscanf(x, "%d %d %d", &m.d, &m.s, &m.r)
			maps[i][j] = m
		}
	}

	startTime := time.Now()

	min := math.MaxInt
	for _, s := range seed {
		c := s
	trans:
		for _, m := range maps {
			for _, t := range m {
				source := c
				c = t.transform(c)
				if c != source {
					continue trans
				}
			}
		}
		if c < min {
			min = c
		}
	}
	endTime := time.Now()
	elapsed := endTime.Sub(startTime)
	fmt.Printf("Part 1: %d (%v)\n", min, elapsed) // 662197086

	startTime = time.Now()
	// starting segments
	var S []Segment
	for i := 0; i < len(seed); i += 2 {
		S = append(S, Segment{seed[i], seed[i] + seed[i+1]})
	}

	for _, m := range maps {
		var A []Segment
		for _, t := range m {
			var nS []Segment
			for _, s := range S {
				nA, nnS := createSegments(s, t)
				A = append(A, nA...)
				nS = append(nS, nnS...)
			}
			S = nS
		}
		S = append(S, A...)
	}
	min = math.MaxInt

	for _, s := range S {
		min = aoc.Min(s.from, min)
	}
	endTime = time.Now()
	elapsed = endTime.Sub(startTime)
	fmt.Printf("Part 2: %d (%v)\n", min, elapsed) // 52510809
}

func createSegments(s Segment, t Range) (A []Segment, nS []Segment) {
	before := Segment{s.from, aoc.Min(s.to, t.s)}
	inter := Segment{aoc.Max(s.from, t.s), aoc.Min(t.s+t.r, s.to)}
	after := Segment{aoc.Max(t.s+t.r, s.from), s.to}

	if before.to > before.from {
		nS = append(nS, before)
	}
	if inter.to > inter.from {
		inter.from = inter.from - t.s + t.d
		inter.to = inter.to - t.s + t.d
		A = append(A, inter)
	}
	if after.to > after.from {
		nS = append(nS, after)
	}

	return A, nS
}

The difficulty is going up and down. This day was quite easy in comparison to yesterday. Today it was about parsing some numbers and finding a set of winning numbers.

As I am doing these puzzles in Go I found out that there is no default set type. There is an implementation by HashiCorp named go-set that fills this void. I did not use an external package (I try to avoid them while doing AoC), but I am very tempted to pull that package in.

Here is my solution using lists.

package main

import (
	"fmt"
	"math"
	"strings"

	"arjenwiersma.nl/aoc/internal/aoc"
)

func main() {
	lines := aoc.AsLines("2023/Day04/input.txt")

	ans := 0
	counts := make([]int, len(lines))

	for x := 0; x < len(lines); x++ {
		counts[x] = 1
	}

	for i, l := range lines {
		nums := strings.Split(l, ":")
		parts := strings.Split(nums[1], "|")
		myInts := aoc.StrToInts(strings.Split(parts[1], " "))
		winInts := aoc.StrToInts(strings.Split(parts[0], " "))

		count := 0
		for _, v := range myInts {
			for _, x := range winInts {
				if x == v {
					count += 1
				}
			}
		}
		if count > 0 {
			c := int(math.Pow(2, float64(count)-1))
			for x := 1; x <= count; x++ {
				counts[i+x] += counts[i]
			}
			ans += c
		}
	}
	fmt.Println("Part 1: ", ans)
	ans = 0
	for _, v := range counts {
		ans += v
	}
	fmt.Println("Part 2: ", ans)
}

Day 3 was quite something. I think that in an attempt to make it harder for AI to solve the puzzles the creators also increased the difficulty level of the base puzzles a little too much. The test was not very clear as to what should happen with negative numbers and it might trip people up. The puzzle itself is a great to exercise grid knowledge as you have to work with neighbors and you have to extend the numbers when you find them. Part 2 was just some bookkeeping on my existing implementation, so it was not too much work.

As a note; I first started out with a list of Points, keeping track of the numbers in a coordinate system. This failed miserably :).

package main

import (
	"fmt"

	"arjenwiersma.nl/aoc/internal/aoc"
)

type Point struct {
	Y, X int
}

func IsDigit(b byte) bool {
	return b-'0' >= 0 && b-'0' <= 9
}

func main() {
	lines := aoc.AsLines("2023/Day03/input.txt")

	ygrid := len(lines)
	xgrid := len(lines[0])

	grid := make([][]byte, ygrid)
	for y, l := range lines {
		grid[y] = make([]byte, xgrid)
		for x := 0; x < len(l); x++ {
			grid[y][x] = l[x]
		}
	}

	neighbors := [][]int{
		{-1, -1}, {0, -1}, {1, -1},
		{-1, 0}, {0, 0}, {1, 0},
		{-1, 1}, {0, 1}, {1, 1},
	}

	gears := make(map[Point][]int)
	sum := 0
	for y := 0; y < ygrid; y++ {
		for x := 0; x < xgrid; x++ {
			num := 0
			hasSymbol := false
			isGear := false
			var gearCoord Point
			for IsDigit(grid[y][x]) {
				num = num*10 + int(grid[y][x]-'0')
				for _, n := range neighbors {
					if y+n[1] >= 0 && y+n[1] < ygrid &&
						x+n[0] >= 0 && x+n[0] < xgrid {
						v := grid[y+n[1]][x+n[0]]
						if !IsDigit(v) && v != '.' {
							if v == '*' {
								isGear = true
								gearCoord = Point{X: x + n[0], Y: y + n[1]}
							}
							hasSymbol = true
						}
					}
				}
				x += 1
				if x >= xgrid {
					break
				}
			}
			if num > 0 && hasSymbol {
				if isGear {
					gears[gearCoord] = append(gears[gearCoord], num)
				}
				sum += num
			}
		}
	}

	fmt.Println("Part 1: ", sum) // 498559

	sum = 0
	for _, v := range gears {
		if len(v) == 2 {
			sum += v[0] * v[1]
		}
	}
	fmt.Println("Part 2: ", sum) // 72246648
}

Day 2 was another fun challenge. Lots of splitting of strings. I wonder if there is a better way to filter out the min and max value from the separate grabs.

I am sure I will not be able to complete all challenges this year, but so far so good.

package main

import (
	"fmt"
	"os"
	"strconv"
	"strings"
)

type Grab struct {
	red, green, blue int
}

type Game struct {
	id    int
	grabs []Grab
}

func main() {
	content, _ := os.ReadFile("2023/Day02/input.txt")

	var input []Game
	for g, l := range strings.Split(strings.TrimSpace(string(content)), "\n") {
		game := Game{}
		game.id = g + 1
		parts := strings.Split(l, ":")
		grabs := strings.Split(parts[1], ";")
		for _, h := range grabs {
			grab := Grab{}
			for _, rgb := range strings.Split(h, ",") {
				color := strings.Split(strings.TrimSpace(rgb), " ")
				i, _ := strconv.Atoi(color[0])
				switch color[1] {
				case "red":
					grab.red = i
				case "green":
					grab.green = i
				case "blue":
					grab.blue = i
				}
			}
			game.grabs = append(game.grabs, grab)
		}
		input = append(input, game)
	}

	max := Grab{
		red:   12,
		green: 13,
		blue:  14,
	}

	var possible []Game
outer:
	for _, game := range input {
		for _, grab := range game.grabs {
			if grab.red > max.red || grab.green > max.green || grab.blue > max.blue {
				continue outer
			}
		}
		// fmt.Println("Possible game: ", game)
		possible = append(possible, game)
	}

	sum := 0
	for _, g := range possible {
		sum += g.id
	}
	fmt.Println("Part 1: ", sum)

	var powers []Grab
	for _, game := range input {
		min := Grab{
			red:   0,
			green: 0,
			blue:  0,
		}
		for _, grab := range game.grabs {
			if grab.red > min.red {
				min.red = grab.red
			}
			if grab.green > min.green {
				min.green = grab.green
			}
			if grab.blue > min.blue {
				min.blue = grab.blue
			}
		}
		powers = append(powers, min)
	}

	sum = 0
	for _, x := range powers {
		sum += x.red * x.green * x.blue
	}
	fmt.Println("Part 2: ", sum)
}

The Advent of Code has started again. At NOVI we participate with a group of our students. We use the AoC throughout the entire curriculum as practice exercises to learn new programming languages or the application of data-structures and algorithms.

Day 1 was a tricky start for most people. Part 1 was not too bad, but part 2 tripped most people up. I guess the idea was that you would have to solve the challenge with an array iteration, but most students tripped up. They tried to match each word and replace the occurrence in the text, running head-on into the edge-case where 2 numbers overlap, such as “eightwo”.

Here is my solution using the Go programming language:

package main

import (
	"fmt"
	"os"
	"strings"
	"unicode"
)

func part1(lines []string) {
	ans := 0
	for _, v := range lines {
		var ints []int
		for _, c := range v {
			if unicode.IsDigit(c) {
				ints = append(ints, int(c-'0'))
			}
		}
		if len(ints) == 0 {
			continue
		}
		ans += ints[0]*10 + ints[len(ints)-1]
	}
	fmt.Println("Part 1: ", ans)
}

func part2(lines []string) {
	ans := 0
	for _, v := range lines {
		var ints []int
		for x := 0; x < len(v); x++ {
			for k, val := range []string{"one", "two", "three", "four", "five", "six", "seven", "eight", "nine"} {
				if strings.HasPrefix(v[x:], val) {
					ints = append(ints, k+1)
				}
			}
			if unicode.IsDigit(rune(v[x])) {
				ints = append(ints, int(v[x]-'0'))
			}
		}

		if len(ints) == 0 {
			continue
		}
		ans += ints[0]*10 + ints[len(ints)-1]
	}

	fmt.Println("Part 2: ", ans)
}

func main() {
	content, _ := os.ReadFile("2023/Day01/input.txt")

	lines := strings.Split(string(content), "\n")

	part1(lines)
	part2(lines)
}

As the warm haze of summer gives way to the crisp air of autumn, the season marks a pivotal moment in my academic journey: the commencement of my Master's thesis project. Having successfully had my research proposal accepted earlier this year, I now face the last leg of this marathon—bringing my theoretical framework to life.

The Powerhouse Partnership: Open Universiteit and CWI {#the-powerhouse-partnership-open-universiteit-and-cwi}

While undertaking a Master's thesis is a significant endeavor on its own, I always have to make it more complex. My research will be a collaborative effort between two prominent institutions: the Open Universiteit and the Centrum Wiskunde & Informatica (CWI).

The CWI is not just another research facility; it is a cornerstone in the Dutch digital landscape. It has been the crucible for pioneering advancements that have indelibly shaped our digital world. To name a few highlights, CWI is the hallowed ground where the first-ever internet connection was established, where the Python programming language was conceived, and where countless other groundbreaking technological milestones have taken root. In my venture, I will be joining forces with the SWAT group, a team that specializes in Software Analysis and Transformation.

Introducing “BiDE”: Bridging the Gap Between Code and Visualization {#introducing-bide-bridging-the-gap-between-code-and-visualization}

At the crux of my research is the creation of a novel visual language designed to facilitate intuitive code editing. Dubbed “BiDE”, short for Bidirectional Diagrammatic Editors, this language aims to serve as a transformative tool in how we understand and manipulate code.

Imagine a scenario where you're faced with an enigmatic, complex piece of code—a labyrinth of loops, conditionals, and functions. Traditionally, you would have to painstakingly dissect each line, trying to visualize the underlying architecture mentally. With BiDE, that approach is poised to become a relic of the past. Instead, a streamlined diagrammatic representation of the code will pop up, offering you a high-level overview.

What sets BiDE apart is its bidirectional functionality. Not only can you comprehend the structure of the code through its visual depiction, but you can also make edits either in the diagrammatic interface or the source code. The brilliance lies in their synchrony; changes in one environment are automatically reflected in the other, keeping both up-to-date in real-time.

A Journey of Discovery, Planning, and Adaptation {#a-journey-of-discovery-planning-and-adaptation}

As I've begun work on my thesis, I've quickly noticed that the process is surprisingly open-ended. Aside from regular meetings with my supervisor, there's not much of a predefined structure. This makes the ability to plan and organize my work even more crucial than before. Without a strong framework, it's easy to get lost in the complexity of the project. So, while the flexibility offers a lot of freedom, it also comes with the responsibility to be my own taskmaster, making sure each piece of the puzzle fits just right.

Staying Connected {#staying-connected}

As I move forward, I will update you on the developments, challenges, and breakthroughs of this endeavor.

Working on my thesis research proposal has been quite the journey, and not always in the direction I would have chosen. A personal revelation that struck me during the process is the tight and rather vexing relationship between perfectionism, procrastination, and paralysis.

It's often said that the perfect is the enemy of the good. In my quest for the 'just right' words to articulate my thoughts, I found this saying to be glaringly accurate. The ticking clock became a dull backdrop to my cerebral scavenger hunt. My concentration started to drift and instead of zeroing in on my research proposal, I found myself fixated on, of all things, the color scheme of my desktop environment.

I got tangled up in a fascinating yet peculiar rabbit hole – the slightly discordant appearance of my Emacs compared to my i3 top bar. This, of course, necessitated immediate rectification, just as I was contemplating that elusive sentence. I spent the entire evening indulging in the color-coded symphony of Catppuccin. Updating the aesthetic of my terminal, tmux, Emacs, Firefox, and i3 configuration was a strange kind of thrill. By the end, I had a beautifully cohesive desktop environment. And yet, that pesky sentence still hung in the air, unwritten.

{{< figure src=“/ox-hugo/catppuccin.png” >}}

Dr. Karen McDowell, a noted advocate for mental wellness, hits the nail on the head when she says, “When you tackle perfectionism, you’re less likely to procrastinate.” Her wisdom tells us that striving for flawlessness not only impedes our progress but also mars the satisfaction we derive from our achievements.

So, how do we break free from this perfection-procrastination paralysis? Dr. McDowell offers a straightforward, seven-step plan:

  1. Consciously lower the bar: Acknowledge that it's okay not to be perfect.
  2. Keep your tasks bite-sized: Manageable chunks are less daunting.
  3. Track your time: Understand where your hours are going.
  4. Surround yourself with positive support: Encouragement helps to keep your spirits high.
  5. Practice saying ‘no’: Respect your capacity and set boundaries.
  6. Use the reward system: Motivate yourself with small incentives.
  7. Incorporate mindfulness: Stay in the present and appreciate your progress.

Now, bear in mind, trying to implement all these changes at once might be a bit like swallowing an elephant whole – impossible and frankly quite unpleasant. The key is to choose a few steps to begin with and gradually incorporate the others. For me, steps one to three seem like a good starting point.

As I venture on this path, I hope to transform my approach towards work, shedding the weight of perfection and embracing the joy of creation. And perhaps, in doing so, I might finally write that sentence.

#mental #health

Using AI, in particular generative models such as GPT, are in contention within academics. The purity of academics resides in students writing on their research and having their work peer-reviewed. But how can you now be sure that the student wrote the paper and how can you trust its content? Many universities, including the OU have written about it. The OU published an article in Modulair about it. Generally, the consensus seems to be that it is ok to use AI as an assistant, but you must write your texts.

For me AI has proven to be a valuable assistant. Here are some ways in which I found AI to be extremely useful:

Blank page syndrome {#blank-page-syndrome}

“Blank page syndrome” refers to the common experience of feeling stuck and overwhelmed when faced with a blank document. It can hinder productivity and creativity in academic writing. Thankfully, AI-powered tools have been developed to combat this syndrome. Utilizing natural language processing algorithms, these tools can generate ideas, provide content suggestions, and even create outlines to jumpstart the writing process. Examples of such tools include ChatGPT and LLaMA, which have proven to be invaluable resources for overcoming this challenge.

Take the following, simplified, prompt:

I am writing a blog post on using AI to write academic papers. I want to cover “blank page syndrome”, “finding related works” and “spelling and grammar correction”. Your task is to work as my writing assistant. Write an outline for this article.

Results in the following outline:

I. Introduction
A. Brief explanation of the challenges faced in academic writing
B. Introduction to the role of AI in overcoming these challenges

II. Understanding "Blank Page Syndrome"
A. Definition and common experiences associated with "blank page syndrome"
B. Causes and psychological factors contributing to the syndrome
C. Introduction to AI-powered tools that can help combat it

III. Overcoming "Blank Page Syndrome" with AI
A. AI-based content generation tools
1. Natural language processing algorithms for generating ideas
2. Examples of AI tools that provide content suggestions and outlines

IV. Finding Related Works Efficiently
A. Importance of literature review and related work in academic writing
B. Challenges in finding relevant sources and connections
C. AI-driven approaches to streamline the process
1. Text mining and semantic analysis algorithms
2. Machine learning techniques for identifying related works
D. Examples of AI tools for efficient literature search and recommendation

V. Improving Spelling and Grammar Accuracy
A. Significance of proper spelling and grammar in academic papers
B. Limitations of traditional spell checkers and grammar tools
C. AI-powered proofreading tools for enhanced accuracy
1. Natural language processing algorithms for grammar checks
2. Machine learning models for spelling and punctuation correction
D. Examples of popular AI-based writing assistant tools

VI. Ethical Considerations and Human Oversight
A. Discussing concerns regarding overreliance on AI in writing
B. Importance of human oversight and critical thinking
C. Addressing potential biases and limitations in AI-driven writing tools

VII. Benefits and Impact of AI in Academic Writing
A. Increased productivity and efficiency for researchers
B. Enhanced accuracy and clarity in written work
C. Facilitation of interdisciplinary research and collaboration

VIII. Future Possibilities and Challenges
A. Advancements in AI technologies for academic writing
B. Integration of AI into existing writing platforms and workflows
C. Challenges and considerations for the future of AI in academic writing

IX. Conclusion
A. Recap of the benefits of using AI in academic writing
B. Encouragement for researchers to explore and utilize AI tools
C. Final thoughts on the transformative potential of AI in academic writing

Make sure to expand on each section with relevant examples, case studies, and practical tips to provide a comprehensive understanding of how AI can assist in academic writing.

How is that for a starter outline? Yes, you will have to work on the structure and the ideas, but you get to start with a solid base. It frees you from the initial “get it on paper” anxiety.

Conducting a comprehensive literature review and identifying relevant related works is crucial for academic writing. However, this task can be time-consuming and overwhelming. AI-driven approaches have emerged to streamline the process and provide researchers with efficient ways to discover related works. By leveraging text mining, semantic analysis, and machine learning techniques, AI tools can analyze vast databases of scholarly articles, uncover hidden connections, and recommend relevant sources. Tools like scite_'s Assistant (https://scite.ai/assistant) have proven to be invaluable assets for researchers, enabling them to save time and access a wealth of knowledge with ease.

{{< figure src=“/ox-hugo/scite-assistant.png” >}}

Improving spelling and grammar accuracy {#improving-spelling-and-grammar-accuracy}

Accurate spelling and proper grammar are essential in academic writing to effectively convey ideas. While traditional spell checkers and grammar tools have limitations, AI-powered proofreading tools have significantly improved accuracy and efficiency. These tools leverage natural language processing algorithms and machine learning models to identify grammar mistakes, spelling errors, and punctuation inconsistencies. Grammarly, a widely recognized tool, has gained acclaim for its ability to enhance the overall quality of written work, ensuring polished and error-free academic papers.

{{< figure src=“/ox-hugo/grammarly.png” >}}

Ethical Considerations and Human Oversight {#ethical-considerations-and-human-oversight}

While AI tools provide invaluable assistance, it's important to acknowledge the importance of human oversight and critical thinking in academic writing. Researchers should exercise caution and verify the suggestions provided by AI tools. Additionally, addressing potential biases and limitations in AI-driven writing tools is crucial to ensure fair representation and accurate information.

Benefits and Impact of AI in Academic Writing {#benefits-and-impact-of-ai-in-academic-writing}

The integration of AI into academic writing processes holds tremendous potential. Researchers can benefit from increased productivity, as AI tools expedite tasks that would otherwise be time-consuming. The enhanced accuracy and clarity in written work contribute to improved quality, enabling researchers to convey their ideas more effectively. Moreover, AI-powered tools facilitate interdisciplinary research, knowledge dissemination, and collaboration, breaking down barriers and fostering innovation across academic disciplines.

Future Possibilities and Challenges {#future-possibilities-and-challenges}

The future of AI in academic writing looks promising. Advancements in AI technologies, including more sophisticated natural language processing algorithms and intelligent content generation models, will further enhance the capabilities of AI tools. Integrating AI into existing writing platforms and workflows will streamline the academic writing process, making it more accessible and user-friendly. However, challenges such as addressing

Conclusion {#conclusion}

In conclusion, the utilization of AI tools in academic writing can have a transformative impact on researchers. By leveraging AI-powered text generation and proofreading capabilities, academics can experience a multitude of benefits. Firstly, AI tooling allows for increased writing velocity, enabling researchers to produce content more efficiently. With AI's assistance, the time-consuming process of meticulously correcting spelling and grammar errors is significantly reduced, freeing up valuable time for researchers to focus on the critical thinking process. As a result, the overall quality of written work can be elevated, ensuring that ideas are effectively conveyed and scholarly contributions are of the highest standard. By embracing AI tooling, academics can embrace a more streamlined and effective approach to writing, empowering them to make significant strides in their research endeavors.

{{< figure src=“/ox-hugo/chatgpt-ai-conclusion.png” >}}