diff --git a/src/main/java/io/github/arrayv/main/ArrayVisualizer.java b/src/main/java/io/github/arrayv/main/ArrayVisualizer.java index cc7ff1e0..04306181 100644 --- a/src/main/java/io/github/arrayv/main/ArrayVisualizer.java +++ b/src/main/java/io/github/arrayv/main/ArrayVisualizer.java @@ -664,6 +664,8 @@ public void refreshSorts() { private void drawStats(Color textColor, boolean dropShadow) { int xOffset = 15; int yOffset = 30; + int drawingFirstStat = 1; + if (dropShadow) { xOffset += 3; yOffset += 3; @@ -674,14 +676,13 @@ private void drawStats(Color textColor, boolean dropShadow) { this.mainRender.setColor(textColor); - statLoop: for (StatisticType statType : statsConfig) { // System.out.println(yPos); String stat; switch (statType) { case LINE_BREAK: yPos += (int)(fontSelectionScale / 25.0 * 15); - continue statLoop; + continue; case SORT_IDENTITY: stat = statSnapshot.getSortIdentity(); break; @@ -725,6 +726,34 @@ private void drawStats(Color textColor, boolean dropShadow) { stat = null; // Unreachable } mainRender.drawString(stat, xOffset, (int)(windowRatio * yPos) + yOffset); + + if (drawingFirstStat == 1 && Highlights.getDeclaredColors().size() > 0) { + int startOffset = currentWidth(), metricFontHeight = mainRender.getFontMetrics().getHeight(), + startStat = mainRender.getFontMetrics().stringWidth(stat) + xOffset + 24, + copyYPos = (int)(windowRatio * yPos) + yOffset, textWidth; + + for (String color : Highlights.getDeclaredColors()) { + textWidth = mainRender.getFontMetrics().stringWidth(color); + startOffset -= textWidth + metricFontHeight + 20; + if (startOffset <= startStat) { + startOffset = currentWidth() - textWidth - metricFontHeight - 20; + copyYPos += metricFontHeight + 8; + } + + if (!dropShadow) { + mainRender.setColor(Highlights.getColorFromName(color)); + } + + mainRender.fillRect(startOffset, copyYPos - metricFontHeight + (metricFontHeight / 3), metricFontHeight, metricFontHeight); + + if (!dropShadow) { + mainRender.setColor(textColor); + } + + mainRender.drawString(color, startOffset + metricFontHeight + 6, copyYPos); + } + } + drawingFirstStat = 0; yPos += fontSelectionScale; } } @@ -1296,7 +1325,11 @@ public String formatTimes() { public void endSort() { this.Timer.disableRealTimer(); + this.Highlights.clearAllMarks(); + this.Highlights.clearAllColorsReferenced(); + this.Highlights.clearColorList(); + System.out.println(formatTimes()); this.isCanceled = false; diff --git a/src/main/java/io/github/arrayv/sorts/merge/BlockSwapMergeSort.java b/src/main/java/io/github/arrayv/sorts/merge/BlockSwapMergeSort.java index dcba6a75..196a3bf3 100644 --- a/src/main/java/io/github/arrayv/sorts/merge/BlockSwapMergeSort.java +++ b/src/main/java/io/github/arrayv/sorts/merge/BlockSwapMergeSort.java @@ -1,5 +1,7 @@ package io.github.arrayv.sorts.merge; +import java.awt.Color; + import io.github.arrayv.main.ArrayVisualizer; import io.github.arrayv.sorts.templates.Sort; @@ -46,14 +48,20 @@ public BlockSwapMergeSort(ArrayVisualizer arrayVisualizer) { } private void multiSwap(int[] array, int a, int b, int len) { - for(int i = 0; i < len; i++) + for(int i = 0; i < len; i++) { + Highlights.colorCode("blockswap", a+i, b+i); Writes.swap(array, a+i, b+i, 1, true, false); + } } private int binarySearchMid(int[] array, int start, int mid, int end) { int a = 0, b = Math.min(mid-start, end-mid), m = a+(b-a)/2; while(b > a) { + Highlights.colorCode("double_binsearch", mid-m-1, mid+m); + Highlights.markArray(1, mid-m-1); + Highlights.markArray(2, mid+m); + Delays.sleep(2.5); if(Reads.compareValues(array[mid-m-1], array[mid+m]) == 1) a = m+1; else @@ -80,6 +88,9 @@ public void multiSwapMerge(int[] array, int start, int mid, int end) { } public void multiSwapMergeSort(int[] array, int a, int b) { + Highlights.retainColorMarks(true);; + Highlights.defineColor("double_binsearch", new Color(128, 0, 255)); + Highlights.defineColor("blockswap", Color.ORANGE); int len = b-a, i; for(int j = 1; j < len; j *= 2) { diff --git a/src/main/java/io/github/arrayv/sorts/merge/RotateMergeSort.java b/src/main/java/io/github/arrayv/sorts/merge/RotateMergeSort.java index 5cf587c5..82864779 100644 --- a/src/main/java/io/github/arrayv/sorts/merge/RotateMergeSort.java +++ b/src/main/java/io/github/arrayv/sorts/merge/RotateMergeSort.java @@ -1,5 +1,7 @@ package io.github.arrayv.sorts.merge; +import java.awt.Color; + import io.github.arrayv.main.ArrayVisualizer; import io.github.arrayv.sorts.templates.Sort; @@ -45,8 +47,10 @@ public RotateMergeSort(ArrayVisualizer arrayVisualizer) { } private void multiSwap(int[] array, int a, int b, int len) { - for(int i = 0; i < len; i++) + for(int i = 0; i < len; i++) { + Highlights.colorCode("rotate", a+i, b+i); Writes.swap(array, a+i, b+i, 1, true, false); + } } private void rotate(int[] array, int a, int m, int b) { @@ -71,7 +75,9 @@ private void rotate(int[] array, int a, int m, int b) { private int binarySearch(int[] array, int a, int b, int value, boolean left) { while(a < b) { int m = a+(b-a)/2; - + Highlights.colorCode(m, "binsearch"); + Highlights.markArray(1, m); + Delays.sleep(2.5); boolean comp = left ? Reads.compareValues(value, array[m]) <= 0 : Reads.compareValues(value, array[m]) < 0; @@ -102,6 +108,9 @@ private void rotateMerge(int[] array, int a, int m, int b) { } protected void rotateMergeSort(int[] array, int a, int b) { + Highlights.retainColorMarks(true); + Highlights.defineColor("binsearch", Color.CYAN); + Highlights.defineColor("rotate", Color.ORANGE); int len = b-a, i; for(int j = 1; j < len; j *= 2) { diff --git a/src/main/java/io/github/arrayv/sorts/select/CycleSort.java b/src/main/java/io/github/arrayv/sorts/select/CycleSort.java index 930b93c3..72941708 100644 --- a/src/main/java/io/github/arrayv/sorts/select/CycleSort.java +++ b/src/main/java/io/github/arrayv/sorts/select/CycleSort.java @@ -1,5 +1,7 @@ package io.github.arrayv.sorts.select; +import java.awt.Color; + import io.github.arrayv.main.ArrayVisualizer; import io.github.arrayv.sorts.templates.Sort; @@ -51,8 +53,11 @@ private int countLesser(int[] array, int a, int b, int t) { Highlights.markArray(1, r); Highlights.markArray(2, i); Delays.sleep(0.01); - - r += Reads.compareValues(array[i], t) < 0 ? 1 : 0; + int cmp = Reads.compareIndexValue(array, i, t, 0.05, true) < 0 ? 1 : 0; + if(cmp == 1) { + Highlights.colorCode(i, "lower_rank"); + } + r += cmp; } Highlights.clearMark(2); return r; @@ -60,6 +65,7 @@ private int countLesser(int[] array, int a, int b, int t) { @Override public void runSort(int[] array, int length, int bucketCount) { + Highlights.defineColor("lower_rank", Color.GREEN); for(int i = 0; i < length-1; i++) { Highlights.markArray(3, i); @@ -72,11 +78,14 @@ public void runSort(int[] array, int length, int bucketCount) { int t1 = array[r]; Writes.write(array, r, t, 0.02, false, false); + + Highlights.clearAllColors(); t = t1; - + r = this.countLesser(array, i, length, t); } while(r != i); + Highlights.clearAllColors(); Writes.write(array, i, t, 0.02, false, false); } diff --git a/src/main/java/io/github/arrayv/sorts/templates/GrailSorting.java b/src/main/java/io/github/arrayv/sorts/templates/GrailSorting.java index b0e1e805..61ef2278 100644 --- a/src/main/java/io/github/arrayv/sorts/templates/GrailSorting.java +++ b/src/main/java/io/github/arrayv/sorts/templates/GrailSorting.java @@ -1,5 +1,7 @@ package io.github.arrayv.sorts.templates; +import java.awt.Color; + import io.github.arrayv.main.ArrayVisualizer; import io.github.arrayv.sorts.exchange.OptimizedGnomeSort; @@ -74,7 +76,7 @@ protected GrailSorting(ArrayVisualizer arrayVisualizer) { super(arrayVisualizer); } - protected int getStaticBuffer() { + public int getStaticBuffer() { return this.grailStaticBufferLen; } @@ -82,22 +84,31 @@ private void grailSwap(int[] arr, int a, int b) { Writes.swap(arr, a, b, 1, true, false); } - private void grailMultiSwap(int[] arr, int a, int b, int swapsLeft) { + private void grailMultiSwapCS(int[] arr, int a, int b, int swapsLeft, String usage) { + while(swapsLeft != 0) { + Highlights.colorCode(usage, a, b); + this.grailSwap(arr, a++, b++); + swapsLeft--; + } + } + + private void grailMultiSwapCSCC(int[] arr, int a, int b, int swapsLeft) { while(swapsLeft != 0) { + Highlights.swapColors(a, b); this.grailSwap(arr, a++, b++); swapsLeft--; } } protected void grailRotate(int[] array, int pos, int lenA, int lenB) { - while(lenA != 0 && lenB != 0) { + while(lenA != 0 && lenB != 0) { if(lenA <= lenB) { - this.grailMultiSwap(array, pos, pos + lenA, lenA); + this.grailMultiSwapCS(array, pos, pos + lenA, lenA, "rotate"); pos += lenA; lenB -= lenA; } else { - this.grailMultiSwap(array, pos + (lenA - lenB), pos + lenA, lenB); + this.grailMultiSwapCS(array, pos + (lenA - lenB), pos + lenA, lenB, "rotate"); lenA -= lenB; } } @@ -108,10 +119,11 @@ private void grailInsertSort(int[] arr, int pos, int len) { } //boolean argument determines direction - private int grailBinSearch(int[] arr, int pos, int len, int keyPos, boolean isLeft) { + protected int grailBinSearch(int[] arr, int pos, int len, int keyPos, boolean isLeft) { int left = -1, right = len; while(left < right - 1) { int mid = left + ((right - left) >> 1); + Highlights.colorCode("binsearch", pos + mid); if(isLeft) { if(Reads.compareValues(arr[pos + mid], arr[keyPos]) >= 0) { right = mid; @@ -128,8 +140,28 @@ private int grailBinSearch(int[] arr, int pos, int len, int keyPos, boolean isLe return right; } + //boolean argument determines direction + protected int grailBinSearchExc(int[] arr, int pos, int len, int keyPos) { + int left = -1, right = len; + while(left < right - 1) { + int mid = left + ((right - left) >> 1); + switch(Reads.compareValues(arr[pos + mid], arr[keyPos])) { + case 1: + right = mid; + break; + case 0: + return -1; + case -1: + left = mid; + break; + } + Highlights.markArray(1, pos + mid); + } + return right; + } + // cost: 2 * len + numKeys^2 / 2 - private int grailFindKeys(int[] arr, int pos, int len, int numKeys) { + public int grailFindKeys(int[] arr, int pos, int len, int numKeys) { int dist = 1, foundKeys = 1, firstKey = 0; // first key is always here while(dist < len && foundKeys < numKeys) { @@ -137,8 +169,8 @@ private int grailFindKeys(int[] arr, int pos, int len, int numKeys) { Delays.sleep(1); //Binary Search left - int loc = this.grailBinSearch(arr, pos + firstKey, foundKeys, pos + dist, true); - if(loc == foundKeys || Reads.compareValues(arr[pos + dist], arr[pos + (firstKey + loc)]) != 0) { + int loc = this.grailBinSearchExc(arr, pos + firstKey, foundKeys, pos + dist); + if(loc >= 0 || loc == foundKeys) { this.grailRotate(arr, pos + firstKey, foundKeys, dist - (firstKey + foundKeys)); firstKey = dist - foundKeys; this.grailRotate(arr, pos + (firstKey + loc), foundKeys - loc, 1); @@ -159,7 +191,7 @@ private int grailFindKeys(int[] arr, int pos, int len, int numKeys) { } // cost: min(len1, len2)^2 + max(len1, len2) - protected void grailMergeWithoutBuffer(int[] arr, int pos, int len1, int len2) { + public void grailMergeWithoutBuffer(int[] arr, int pos, int len1, int len2) { if(len1 < len2) { while(len1 != 0) { //Binary Search left @@ -218,7 +250,7 @@ private void grailMergeBuffersLeft(int[] arr, int keysPos, int midkey, int pos, int nextFrag = Reads.compareValues(arr[keysPos + keyIndex], arr[midkey]) < 0 ? 0 : 1; if(nextFrag == leftOverFrag) { - if(havebuf) this.grailMultiSwap(arr, pos + restToProcess - blockLen, pos + restToProcess, leftOverLen); + if(havebuf) this.grailMultiSwapCS(arr, pos + restToProcess - blockLen, pos + restToProcess, leftOverLen, "fragment"); restToProcess = processIndex; leftOverLen = blockLen; } else { @@ -238,7 +270,7 @@ private void grailMergeBuffersLeft(int[] arr, int keysPos, int midkey, int pos, if(lastLen != 0) { if(leftOverFrag != 0) { if(havebuf) { - this.grailMultiSwap(arr, pos + restToProcess - blockLen, pos + restToProcess, leftOverLen); + this.grailMultiSwapCS(arr, pos + restToProcess - blockLen, pos + restToProcess, leftOverLen, "fragment"); } restToProcess = processIndex; leftOverLen = blockLen * aBlockCount; @@ -254,7 +286,7 @@ private void grailMergeBuffersLeft(int[] arr, int keysPos, int midkey, int pos, } } else { if(havebuf) { - this.grailMultiSwap(arr, pos + restToProcess, pos + (restToProcess - blockLen), leftOverLen); + this.grailMultiSwapCS(arr, pos + restToProcess, pos + (restToProcess - blockLen), leftOverLen, "fragment"); } } } @@ -268,17 +300,25 @@ private void grailMergeLeft(int[] arr, int pos, int leftLen, int rightLen, int d rightLen += leftLen; while(right < rightLen) { + Highlights.colorCode(pos + dist, "leftmerge"); if(left == leftLen || Reads.compareValues(arr[pos + left], arr[pos + right]) > 0) { + Highlights.colorCode(pos + right, "buffer"); this.grailSwap(arr, pos + (dist++), pos + (right++)); + } else { + Highlights.colorCode(pos + left, "buffer"); + this.grailSwap(arr, pos + (dist++), pos + (left++)); } - else this.grailSwap(arr, pos + (dist++), pos + (left++)); Highlights.markArray(3, pos + left); Highlights.markArray(4, pos + right); } Highlights.clearMark(3); Highlights.clearMark(4); - if(dist != left) this.grailMultiSwap(arr, pos + dist, pos + left, leftLen - left); + if(dist != left) { + this.grailMultiSwapCS(arr, pos + dist, pos + left, leftLen - left, "leftmerge"); + for(int i=0; i= 0) { + Highlights.colorCode(pos + mergedPos, "rightmerge"); if(right < leftLen || Reads.compareValues(arr[pos + left], arr[pos + right]) > 0) { + Highlights.colorCode(pos + left, "buffer"); this.grailSwap(arr, pos + (mergedPos--), pos + (left--)); + } else { + Highlights.colorCode(pos + right, "buffer"); + this.grailSwap(arr, pos + (mergedPos--), pos + (right--)); } - else this.grailSwap(arr, pos + (mergedPos--), pos + (right--)); if(pos + left >= 0) Highlights.markArray(3, pos + left); Highlights.markArray(4, pos + right); } @@ -297,7 +341,11 @@ private void grailMergeRight(int[] arr, int pos, int leftLen, int rightLen, int Highlights.clearMark(4); if(right != mergedPos) { - while(right >= leftLen) this.grailSwap(arr, pos + (mergedPos--), pos + (right--)); + while(right >= leftLen) { + Highlights.colorCode(pos + mergedPos, "rightmerge"); + Highlights.colorCode(pos + right, "buffer"); + this.grailSwap(arr, pos + (mergedPos--), pos + (right--)); + } } } @@ -343,10 +391,14 @@ private GrailPair grailSmartMergeWithBuffer(int[] arr, int pos, int leftOverLen, int typeFrag = 1 - leftOverFrag; // 1 if inverted while(left < leftEnd && right < rightEnd) { + Highlights.colorCode(pos + dist, "smartmerge"); if(Reads.compareValues(arr[pos + left], arr[pos + right]) - typeFrag < 0) { + Highlights.colorCode(pos + left, "buffer"); this.grailSwap(arr, pos + (dist++), pos + (left++)); + } else { + Highlights.colorCode(pos + right, "buffer"); + this.grailSwap(arr, pos + (dist++), pos + (right++)); } - else this.grailSwap(arr, pos + (dist++), pos + (right++)); Highlights.markArray(3, pos + left); Highlights.markArray(4, pos + right); } @@ -356,7 +408,11 @@ private GrailPair grailSmartMergeWithBuffer(int[] arr, int pos, int leftOverLen, int length, fragment = leftOverFrag; if(left < leftEnd) { length = leftEnd - left; - while(left < leftEnd) this.grailSwap(arr, pos + (--leftEnd), pos + (--rightEnd)); + while(left < leftEnd) { + Highlights.colorCode(pos + (--leftEnd), "buffer"); + Highlights.colorCode(pos + (--rightEnd), "bufferrewind"); + this.grailSwap(arr, pos + leftEnd, pos + rightEnd); + } } else { length = rightEnd - right; fragment = typeFrag; @@ -522,10 +578,16 @@ private void grailBuildBlocks(int[] arr, int pos, int len, int buildLen, for(int dist = 1; dist < len; dist += 2) { extraDist = 0; if(Reads.compareValues(arr[pos + (dist - 1)], arr[pos + dist]) > 0) extraDist = 1; + Highlights.colorCode("pairing", pos+(dist-3), pos+(dist-2)); + Highlights.colorCode("buffer", pos+(dist-1), pos+dist); this.grailSwap(arr, pos + (dist - 3), pos + (dist - 1 + extraDist)); this.grailSwap(arr, pos + (dist - 2), pos + (dist - extraDist)); } - if(len % 2 != 0) this.grailSwap(arr, pos + (len - 1), pos + (len - 3)); + if(len % 2 != 0) { + Highlights.colorCode(pos+(len-1), "buffer"); + Highlights.colorCode(pos+(len-3), "pairing"); + this.grailSwap(arr, pos + (len - 1), pos + (len - 3)); + } pos -= 2; part = 2; } @@ -557,6 +619,11 @@ private void grailBuildBlocks(int[] arr, int pos, int len, int buildLen, } } + private int grailCmp(int[] arr, int a, int b, String usage) { + Highlights.colorCode(usage, a, b); + return Reads.compareIndices(arr, a, b, 1, true); + } + // keys are on the left of arr. Blocks of length buildLen combined. We'll combine them in pairs // buildLen and nkeys are powers of 2. (2 * buildLen / regBlockLen) keys are guaranteed private void grailCombineBlocks(int[] arr, int keyPos, int pos, int len, int buildLen, @@ -585,14 +652,14 @@ private void grailCombineBlocks(int[] arr, int keyPos, int pos, int len, int bui int leftIndex = index - 1; for(int rightIndex = index; rightIndex < blockCount; rightIndex++) { - int rightComp = Reads.compareValues(arr[blockPos + leftIndex * regBlockLen], - arr[blockPos + rightIndex * regBlockLen]); - if(rightComp > 0 || (rightComp == 0 && Reads.compareValues(arr[keyPos + leftIndex], arr[keyPos + rightIndex]) > 0)) { + int rightComp = grailCmp(arr, blockPos + leftIndex * regBlockLen, blockPos + rightIndex * regBlockLen, "blockselect"); + if(rightComp > 0 || (rightComp == 0 && grailCmp(arr, keyPos + leftIndex, keyPos + rightIndex, "stability") > 0)) { leftIndex = rightIndex; } } if(leftIndex != index - 1) { - this.grailMultiSwap(arr, blockPos + (index - 1) * regBlockLen, blockPos + leftIndex * regBlockLen, regBlockLen); + this.grailMultiSwapCSCC(arr, blockPos + (index - 1) * regBlockLen, blockPos + leftIndex * regBlockLen, regBlockLen); + Highlights.colorCode(keyPos+index-1, "stability"); this.grailSwap(arr, keyPos + (index - 1), keyPos + leftIndex); if(midkey == index - 1 || midkey == leftIndex) { midkey ^= (index - 1) ^ leftIndex; @@ -605,8 +672,7 @@ private void grailCombineBlocks(int[] arr, int keyPos, int pos, int len, int bui if(i == combineLen) lastLen = leftOver % regBlockLen; if(lastLen != 0) { - while(aBlockCount < blockCount && Reads.compareValues(arr[blockPos + blockCount * regBlockLen], - arr[blockPos + (blockCount - aBlockCount - 1) * regBlockLen]) < 0) { + while(aBlockCount < blockCount && grailCmp(arr, blockPos + blockCount * regBlockLen, blockPos + (blockCount - aBlockCount - 1) * regBlockLen, "blockselect") < 0) { aBlockCount++; } } @@ -624,6 +690,7 @@ private void grailCombineBlocks(int[] arr, int keyPos, int pos, int len, int bui } else if(havebuf) { while(--len >= 0) { + Highlights.swapColors(pos+len, pos + len - regBlockLen); this.grailSwap(arr, pos + len, pos + len - regBlockLen); } } @@ -656,8 +723,20 @@ protected void grailLazyStableSort(int[] arr, int pos, int len) { } } - protected void grailCommonSort(int[] arr, int pos, int len, int[] buffer, int bufferPos, int bufferLen) { + public void grailCommonSort(int[] arr, int pos, int len, int[] buffer, int bufferPos, int bufferLen) { this.grailInsertSorter = new OptimizedGnomeSort(this.arrayVisualizer); + Highlights.retainColorMarks(true); + Highlights.defineColor("bufferrewind", Color.ORANGE); + Highlights.defineColor("rotate", Color.YELLOW); + Highlights.defineColor("pairing", Color.GRAY); + Highlights.defineColor("buffer", Color.DARK_GRAY); + Highlights.defineColor("binsearch", Color.PINK); + Highlights.defineColor("smartmerge", new Color(0, 200, 255)); + Highlights.defineColor("leftmerge", new Color(200, 0, 200)); + Highlights.defineColor("rightmerge", new Color(180, 100, 0)); + Highlights.defineColor("blockselect", new Color(0, 255, 100)); + Highlights.defineColor("stability", Color.CYAN); + Highlights.defineColor("fragment", new Color(0, 0, 255)); if(len <= 16) { this.grailInsertSort(arr, pos, len); @@ -777,4 +856,4 @@ protected void grailInPlaceMergeSort(int[] arr, int start, int len) { if(rest > part) this.grailInPlaceMerge(arr, left, part, rest - part); } } -} +} \ No newline at end of file diff --git a/src/main/java/io/github/arrayv/utils/ArrayVList.java b/src/main/java/io/github/arrayv/utils/ArrayVList.java index fd67f7d5..8a093182 100644 --- a/src/main/java/io/github/arrayv/utils/ArrayVList.java +++ b/src/main/java/io/github/arrayv/utils/ArrayVList.java @@ -1,22 +1,11 @@ package io.github.arrayv.utils; -import java.util.AbstractList; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.ConcurrentModificationException; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.RandomAccess; -import java.util.Spliterator; -import java.util.function.Consumer; - import io.github.arrayv.main.ArrayVisualizer; -public class ArrayVList extends AbstractList implements RandomAccess, Cloneable, java.io.Serializable { +import java.util.*; +import java.util.function.Consumer; + +public class ArrayVList extends AbstractList implements RandomAccess, java.io.Serializable { private static final int DEFAULT_CAPACITY = 128; private static final double DEFAULT_GROW_FACTOR = 2; @@ -29,6 +18,7 @@ public class ArrayVList extends AbstractList implements RandomAccess, C int[] internal; double growFactor; int count, capacity; + boolean colorsEnabled = false; public ArrayVList() { this(DEFAULT_CAPACITY, DEFAULT_GROW_FACTOR); @@ -54,6 +44,7 @@ public ArrayVList(int capacity, double growFactor) { public void delete() { Writes.changeAllocAmount(-count); arrayVisualizer.getArrays().remove(internal); + disableColors(); this.internal = null; this.count = 0; this.capacity = 0; @@ -95,11 +86,29 @@ public T[] toArray(T[] a) { return (T[])toArray(); } + public void enableColors() { + if (!colorsEnabled) { + colorsEnabled = true; + arrayVisualizer.getHighlights().registerColorMarks(internal); + } + } + + public void disableColors() { + if (colorsEnabled) { + colorsEnabled = false; + arrayVisualizer.getHighlights().unregisterColors(internal); + } + } + protected void grow() { int newCapacity = (int)Math.ceil(capacity * growFactor); int[] newInternal = new int[newCapacity]; System.arraycopy(internal, 0, newInternal, 0, count); ArrayList arrays = arrayVisualizer.getArrays(); + if (colorsEnabled) { + arrayVisualizer.getHighlights().unregisterColors(internal); + arrayVisualizer.getHighlights().registerColorMarks(newInternal); + } arrays.set(arrays.indexOf(internal), newInternal); this.capacity = newCapacity; this.internal = newInternal; @@ -119,6 +128,39 @@ public boolean add(Integer e) { return add(e, 0, false); } + public void colorCode(int position, String alias) { + try { + if (!colorsEnabled) { + throw new Exception("ArrayVList.colorCode(): List can't be colorcoded!"); + } + arrayVisualizer.getHighlights().colorCode(internal, position, alias); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void colorCode(String alias, int... positions) { + try { + if (!colorsEnabled) { + throw new Exception("ArrayVList.colorCode(): List can't be colorcoded!"); + } + arrayVisualizer.getHighlights().colorCode(internal, alias, positions); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void rawColorCode(int position, java.awt.Color color) { // i am appalled at the lengths git wants to go to stop me from using the Color class + try { + if (!colorsEnabled) { + throw new Exception("ArrayVList.rawColorCode(): List can't be colorcoded!"); + } + arrayVisualizer.getHighlights().setRawColor(internal, position, color); + } catch (Exception e) { + e.printStackTrace(); + } + } + private void fastRemove(int index) { int numMoved = count - index - 1; if (numMoved > 0) diff --git a/src/main/java/io/github/arrayv/utils/Delays.java b/src/main/java/io/github/arrayv/utils/Delays.java index 24e4a472..23a649b5 100644 --- a/src/main/java/io/github/arrayv/utils/Delays.java +++ b/src/main/java/io/github/arrayv/utils/Delays.java @@ -99,6 +99,7 @@ public void updateDelayForTimeSort(double value) { public double getSleepRatio() { return this.sleepRatio; } + public void setSleepRatio(double sleepRatio) { this.sleepRatio = sleepRatio; } @@ -106,6 +107,7 @@ public void setSleepRatio(double sleepRatio) { public boolean skipped() { return this.skipped; } + public void changeSkipped(boolean skipped) { this.skipped = skipped; if (this.skipped) this.Sounds.changeNoteDelayAndFilter(1); @@ -114,12 +116,14 @@ public void changeSkipped(boolean skipped) { public boolean paused() { return this.paused; } + public void changePaused(boolean paused) { this.paused = paused; this.Sounds.toggleSound(!paused); } + public void togglePaused() { - this.changePaused(!this.paused);; + this.changePaused(!this.paused); } public void disableStepping() { diff --git a/src/main/java/io/github/arrayv/utils/Highlights.java b/src/main/java/io/github/arrayv/utils/Highlights.java index 1f24f2db..b62f9169 100644 --- a/src/main/java/io/github/arrayv/utils/Highlights.java +++ b/src/main/java/io/github/arrayv/utils/Highlights.java @@ -1,9 +1,15 @@ package io.github.arrayv.utils; -import java.util.Arrays; - import io.github.arrayv.main.ArrayVisualizer; import io.github.arrayv.panes.JErrorPane; +import java.awt.Color; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; + +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicInteger; /* * @@ -35,6 +41,15 @@ public final class Highlights { private volatile int[] highlights; private volatile byte[] markCounts; + // This is in desperate need of optimization. + private volatile Map colorMarks; + private volatile Map colorColors; + + private volatile boolean retainColorMarks = false; + + private volatile Map defined; + private final int[] main; + private volatile int maxHighlightMarked; // IMPORTANT: This stores the index one past the farthest highlight used, so that a value // of 0 means no highlights are in use, and iteration is more convenient. @@ -53,11 +68,11 @@ public final class Highlights { // This way, the program runs more efficiently, and looks pretty. :) - private volatile int markCount; + private final AtomicInteger markCount; private boolean showFancyFinishes; private volatile boolean fancyFinish; - private volatile int trackFinish; + private final AtomicInteger trackFinish = new AtomicInteger(); private ArrayVisualizer arrayVisualizer; private Delays Delays; @@ -66,18 +81,24 @@ public Highlights(ArrayVisualizer arrayVisualizer, int maximumLength) { this.arrayVisualizer = arrayVisualizer; try { + defined = new HashMap<>(); this.highlights = new int[maximumLength]; this.markCounts = new byte[maximumLength]; + this.colorMarks = new IdentityHashMap<>(); + this.colorColors = new IdentityHashMap<>(); } catch (OutOfMemoryError e) { JErrorPane.invokeCustomErrorMessage("Failed to allocate mark arrays. The program will now exit."); System.exit(1); } this.showFancyFinishes = true; this.maxHighlightMarked = 0; - this.markCount = 0; + this.markCount = new AtomicInteger(); Arrays.fill(highlights, -1); Arrays.fill(markCounts, (byte)0); + + this.main = arrayVisualizer.getArray(); // I refuse to remove this line of code without putting up a fight + this.registerColorMarks(main); } public void postInit() { @@ -102,13 +123,13 @@ public void toggleFancyFinish(boolean fancyFinish) { } public int getFancyFinishPosition() { - return this.trackFinish; + return this.trackFinish.get(); } public void incrementFancyFinishPosition() { - this.trackFinish++; + this.trackFinish.incrementAndGet(); } public void resetFancyFinish() { - this.trackFinish = -1; // Magic number that clears the green sweep animation + this.trackFinish.set(-1); // Magic number that clears the green sweep animation } public void toggleAnalysis(boolean analysis) { @@ -119,14 +140,14 @@ public int getMaxHighlight() { return this.maxHighlightMarked; } public int getMarkCount() { - return this.markCount; + return this.markCount.get(); } private void incrementIndexMarkCount(int i) { if (i >= markCounts.length) return; if (markCounts[i] != (byte)-1) { if (markCounts[i] == 0) { - markCount++; + markCount.incrementAndGet(); } markCounts[i]++; } @@ -144,7 +165,7 @@ private void decrementIndexMarkCount(int i) { } } } else if (markCounts[i] == 0) { - markCount--; + markCount.decrementAndGet(); } markCounts[i]--; } @@ -157,6 +178,163 @@ public boolean containsPosition(int arrayPosition) { if (arrayPosition >= markCounts.length) return false; return this.markCounts[arrayPosition] != 0; } + public Set getDeclaredColors() { + return defined.keySet(); + } + public Color getColorFromName(String color) { + return defined.getOrDefault(color, Color.WHITE); + } + public synchronized void defineColor(String alias, Color col) { + defined.put(alias, col); + } + + public synchronized boolean[] getColorMarks(int[] array) { + return colorMarks.get(array); + } + + public synchronized Color[] getColorColors(int[] array) { + return colorColors.get(array); + } + public synchronized void registerColorMarks(int[] array) { + boolean[] colorMark = new boolean[array.length]; + Color[] colorColor = new Color[array.length]; + colorMarks.putIfAbsent(array, colorMark); + colorColors.putIfAbsent(array, colorColor); + } + public synchronized void unregisterColors(int[] array) { + colorMarks.remove(array); + colorColors.remove(array); + } + // Ambitious function: Set the color directly + public synchronized void setRawColor(int[] array, int position, Color color) { + try { + if (position < 0) { + throw new Exception("Highlights.setRawColor(): Invalid position!"); + } else { + boolean[] colorMark = getColorMarks(array); + Delays.disableStepping(); + if (colorMark != null) { + colorMark[position] = true; + getColorColors(array)[position] = color; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + arrayVisualizer.updateNow(); + Delays.enableStepping(); + } + + // Convenience function: Set the color using a predefined alias + public synchronized void setRawColor(int position, Color color) { + setRawColor(main, position, color); + } + + // Convenience function: Set the color using a predefined alias + public synchronized void writeColor(int[] fromArray, int fromPosition, int[] toArray, int toPosition) { + try { + Delays.disableStepping(); + if (colorMarks.containsKey(fromArray) && colorMarks.containsKey(toArray)) { + getColorMarks(toArray)[toPosition] = getColorMarks(fromArray)[fromPosition]; + getColorColors(toArray)[toPosition] = getColorColors(fromArray)[fromPosition]; + } else { + throw new Exception("Highlights.writeColor(): One or more arrays not colorcodeable!"); + } + } catch (Exception e) { + e.printStackTrace(); + } + arrayVisualizer.updateNow(); + Delays.enableStepping(); + } + + // Convenience function: Set the color using a predefined alias + public synchronized void colorCode(int[] array, int position, String color) { + try { + if (position < 0) { + throw new Exception("Highlights.colorCode(): Invalid position!"); + } else { + boolean[] colorMark = getColorMarks(array); + Delays.disableStepping(); + if (colorMark != null) { + colorMark[position] = true; + getColorColors(array)[position] = getColorFromName(color); + } + } + } catch (Exception e) { + e.printStackTrace(); + return; + } + arrayVisualizer.updateNow(); + Delays.enableStepping(); + } + + // Convenience function: Set the color using a predefined alias + public synchronized void colorCode(int position, String color) { + colorCode(main, position, color); + } + + // Convenience function 2: Batch-colorcode a set of positions under one common name + public synchronized void colorCode(int[] array, String color, int... positions) { + for (int i : positions) { + colorCode(array, i, color); + } + } + + // Convenience function 2: Batch-colorcode a set of positions under one common name + public synchronized void colorCode(String color, int... positions) { + colorCode(main, color, positions); + } + + public synchronized void clearColor(int[] array, int position) { + boolean[] colorMark = getColorMarks(array); + if (colorMark == null) + return; + Delays.disableStepping(); + if (colorMark[position]) { + colorMark[position] = false; + getColorColors(array)[position] = null; + } + arrayVisualizer.updateNow(); + Delays.enableStepping(); + } + + public synchronized void clearColor(int position) { + clearColor(this.main, position); + } + + public synchronized boolean hasColor(int[] array, int position) { + return colorMarks.containsKey(array) && getColorMarks(array)[position]; + } + + public synchronized boolean hasColor(int position) { + return hasColor(main, position); + } + + public synchronized Color colorAt(int[] array, int position) { + return getColorColors(array)[position]; + } + + public synchronized Color colorAt(int position) { + return colorAt(main, position); + } + + public void swapColors(int[] array, int locA, int locB) { + boolean[] colorMark = getColorMarks(array); + Color[] colorColor = getColorColors(array); + if (colorMark == null) + return; + boolean t0 = colorMark[locA]; + Color t1 = colorColor[locA]; + colorMark[locA] = colorMark[locB]; + colorMark[locB] = t0; + colorColor[locA] = colorColor[locB]; + colorColor[locB] = t1; + } + + public void swapColors(int locA, int locB) { + swapColors(main, locA, locB); + } + public synchronized void markArray(int marker, int markPosition) { try { if (markPosition < 0) { @@ -171,6 +349,9 @@ public synchronized void markArray(int marker, int markPosition) { if (highlights[marker] != -1) { decrementIndexMarkCount(highlights[marker]); } + if (!retainColorMarks) { + clearColor(markPosition); + } highlights[marker] = markPosition; incrementIndexMarkCount(markPosition); @@ -184,14 +365,17 @@ public synchronized void markArray(int marker, int markPosition) { arrayVisualizer.updateNow(); Delays.enableStepping(); } + public synchronized void clearMark(int marker) { if (highlights[marker] == -1) { return; } Delays.disableStepping(); decrementIndexMarkCount(highlights[marker]); + if (!retainColorMarks) { + clearColor(highlights[marker]); + } highlights[marker] = -1; // -1 is used as the magic number to unmark a position in the main array - if (marker == this.maxHighlightMarked) { this.maxHighlightMarked = marker; while (maxHighlightMarked > 0 && highlights[maxHighlightMarked-1] == -1) { @@ -201,6 +385,38 @@ public synchronized void clearMark(int marker) { arrayVisualizer.updateNow(); Delays.enableStepping(); } + + + public synchronized void clearColorList() { + defined.clear(); + retainColorMarks = false; + } + + public synchronized void clearAllColors(int[] array) { + Delays.disableStepping(); + Arrays.fill(getColorMarks(array), false); + arrayVisualizer.updateNow(); + Delays.enableStepping(); + } + + public synchronized void clearAllColors() { + clearAllColors(main); + } + + public synchronized void clearAllColorsReferenced() { + for (boolean[] list : colorMarks.values()) { + Arrays.fill(list, false); + } + } + + public synchronized boolean isRetainingColorMarks() { + return retainColorMarks; + } + + public synchronized void retainColorMarks(boolean retainColorMarks) { + this.retainColorMarks = retainColorMarks; + } + public synchronized void clearAllMarks() { Delays.disableStepping(); for (int i = 0; i < this.maxHighlightMarked; i++) { @@ -210,7 +426,7 @@ public synchronized void clearAllMarks() { } Arrays.fill(this.highlights, 0, this.maxHighlightMarked, -1); this.maxHighlightMarked = 0; - this.markCount = 0; + this.markCount.set(0); arrayVisualizer.updateNow(); Delays.enableStepping(); } diff --git a/src/main/java/io/github/arrayv/utils/Writes.java b/src/main/java/io/github/arrayv/utils/Writes.java index 2ffb9981..7d0a6155 100644 --- a/src/main/java/io/github/arrayv/utils/Writes.java +++ b/src/main/java/io/github/arrayv/utils/Writes.java @@ -427,6 +427,7 @@ public int[] createExternalArray(int length) { public void deleteExternalArray(int[] array) { this.allocAmount -= array.length; arrayVisualizer.getArrays().remove(array); + Highlights.unregisterColors(array); arrayVisualizer.updateNow(); } diff --git a/src/main/java/io/github/arrayv/visuals/bars/BarGraph.java b/src/main/java/io/github/arrayv/visuals/bars/BarGraph.java index 799870c2..1f5dfdf8 100644 --- a/src/main/java/io/github/arrayv/visuals/bars/BarGraph.java +++ b/src/main/java/io/github/arrayv/visuals/bars/BarGraph.java @@ -24,6 +24,8 @@ public void drawVisual(int[] array, ArrayVisualizer arrayVisualizer, Renderer re else if (arrayVisualizer.colorEnabled()) { int val = arrayVisualizer.doingStabilityCheck() && arrayVisualizer.colorEnabled() ? arrayVisualizer.getIndexValue(array[i]): array[i]; this.mainRender.setColor(getIntColor(val, arrayVisualizer.getCurrentLength())); + } else if (Highlights.hasColor(array, i)) { + this.mainRender.setColor(Highlights.colorAt(array, i)); } else this.mainRender.setColor(Color.WHITE); int val = arrayVisualizer.doingStabilityCheck() && arrayVisualizer.colorEnabled() ? arrayVisualizer.getStabilityValue(array[i]): array[i]; diff --git a/src/main/java/io/github/arrayv/visuals/bars/DisparityBarGraph.java b/src/main/java/io/github/arrayv/visuals/bars/DisparityBarGraph.java index 029f8bd0..166a37e9 100644 --- a/src/main/java/io/github/arrayv/visuals/bars/DisparityBarGraph.java +++ b/src/main/java/io/github/arrayv/visuals/bars/DisparityBarGraph.java @@ -24,7 +24,8 @@ public void drawVisual(int[] array, ArrayVisualizer arrayVisualizer, Renderer re else if (arrayVisualizer.colorEnabled()) this.mainRender.setColor(getIntColor(array[i], arrayVisualizer.getCurrentLength())); - + else if (Highlights.hasColor(array, i)) + this.mainRender.setColor(Highlights.colorAt(array, i)); else this.mainRender.setColor(Color.WHITE); double disp = (1 + Math.sin((Math.PI * (array[i] - i)) / arrayVisualizer.getCurrentLength())) * 0.5; diff --git a/src/main/java/io/github/arrayv/visuals/bars/SineWave.java b/src/main/java/io/github/arrayv/visuals/bars/SineWave.java index 16737f5d..24af4cea 100644 --- a/src/main/java/io/github/arrayv/visuals/bars/SineWave.java +++ b/src/main/java/io/github/arrayv/visuals/bars/SineWave.java @@ -49,7 +49,9 @@ public void drawVisual(int[] array, ArrayVisualizer arrayVisualizer, Renderer re else if (arrayVisualizer.colorEnabled()) this.mainRender.setColor(getIntColor(array[i], arrayVisualizer.getCurrentLength())); - else this.mainRender.setColor(Color.WHITE); + else if (Highlights.hasColor(array, i)) { + this.mainRender.setColor(Highlights.colorAt(array, i)); + } else this.mainRender.setColor(Color.WHITE); int width = (int) (renderer.getXScale() * (i + 1)) - j; diff --git a/src/main/java/io/github/arrayv/visuals/circles/DisparityCircle.java b/src/main/java/io/github/arrayv/visuals/circles/DisparityCircle.java index 6c7aaa31..827a3dda 100644 --- a/src/main/java/io/github/arrayv/visuals/circles/DisparityCircle.java +++ b/src/main/java/io/github/arrayv/visuals/circles/DisparityCircle.java @@ -75,7 +75,9 @@ else if (Highlights.containsPosition(i)) { this.extraRender.drawPolygon(x, y, 3); } else if (arrayVisualizer.colorEnabled()) this.mainRender.setColor(getIntColor(array[i], arrayVisualizer.getCurrentLength())); - else this.mainRender.setColor(Color.WHITE); + else if (Highlights.hasColor(array, i)) { + this.mainRender.setColor(Highlights.colorAt(array, i)); + } else this.mainRender.setColor(Color.WHITE); this.mainRender.fillPolygon(x, y, 3); } diff --git a/src/main/java/io/github/arrayv/visuals/circles/Spiral.java b/src/main/java/io/github/arrayv/visuals/circles/Spiral.java index ae7817e7..776e17af 100644 --- a/src/main/java/io/github/arrayv/visuals/circles/Spiral.java +++ b/src/main/java/io/github/arrayv/visuals/circles/Spiral.java @@ -80,8 +80,9 @@ else if (Highlights.containsPosition(i)) { this.extraRender.drawPolygon(x, y, 3); } else if (arrayVisualizer.colorEnabled()) this.mainRender.setColor(getIntColor(array[i], arrayVisualizer.getCurrentLength())); - - else this.mainRender.setColor(Color.WHITE); + else if (Highlights.hasColor(array, i)) { + this.mainRender.setColor(Highlights.colorAt(array, i)); + } else this.mainRender.setColor(Color.WHITE); this.mainRender.fillPolygon(x, y, 3); } diff --git a/src/main/java/io/github/arrayv/visuals/dots/DisparityDots.java b/src/main/java/io/github/arrayv/visuals/dots/DisparityDots.java index 05b28fa1..523668f5 100644 --- a/src/main/java/io/github/arrayv/visuals/dots/DisparityDots.java +++ b/src/main/java/io/github/arrayv/visuals/dots/DisparityDots.java @@ -65,8 +65,9 @@ public void drawVisual(int[] array, ArrayVisualizer arrayVisualizer, Renderer re this.mainRender.setStroke(arrayVisualizer.getCustomStroke(4)); } else if (arrayVisualizer.colorEnabled()) this.mainRender.setColor(getIntColor(array[i], arrayVisualizer.getCurrentLength())); - - else this.mainRender.setColor(Color.WHITE); + else if (Highlights.hasColor(array, i)) { + this.mainRender.setColor(Highlights.colorAt(array, i)); + } else this.mainRender.setColor(Color.WHITE); disp = (1 + Math.cos((Math.PI * (array[i] - i)) / (arrayVisualizer.getCurrentLength() * 0.5))) * 0.5; int x = width/2 + (int)(disp * r * Math.cos(Math.PI * (2d*i / n - 0.5))); diff --git a/src/main/java/io/github/arrayv/visuals/dots/ScatterPlot.java b/src/main/java/io/github/arrayv/visuals/dots/ScatterPlot.java index a3b4dce0..975e2ebb 100644 --- a/src/main/java/io/github/arrayv/visuals/dots/ScatterPlot.java +++ b/src/main/java/io/github/arrayv/visuals/dots/ScatterPlot.java @@ -57,6 +57,8 @@ public void drawVisual(int[] array, ArrayVisualizer arrayVisualizer, Renderer re } else if (arrayVisualizer.colorEnabled()) { int val = arrayVisualizer.doingStabilityCheck() && arrayVisualizer.colorEnabled() ? arrayVisualizer.getIndexValue(array[i]): array[i]; this.mainRender.setColor(getIntColor(val, arrayVisualizer.getCurrentLength())); + } else if (Highlights.hasColor(array, i)) { + this.mainRender.setColor(Highlights.colorAt(array, i)); } else this.mainRender.setColor(Color.WHITE); int val = arrayVisualizer.doingStabilityCheck() && arrayVisualizer.colorEnabled() ? arrayVisualizer.getStabilityValue(array[i]): array[i]; @@ -82,6 +84,8 @@ public void drawVisual(int[] array, ArrayVisualizer arrayVisualizer, Renderer re else if (arrayVisualizer.colorEnabled()) { int val = arrayVisualizer.doingStabilityCheck() && arrayVisualizer.colorEnabled() ? arrayVisualizer.getIndexValue(array[i]): array[i]; this.mainRender.setColor(getIntColor(val, arrayVisualizer.getCurrentLength())); + } else if (Highlights.hasColor(array, i)) { + this.mainRender.setColor(Highlights.colorAt(array, i)); } else this.mainRender.setColor(Color.WHITE); int val = arrayVisualizer.doingStabilityCheck() && arrayVisualizer.colorEnabled() ? arrayVisualizer.getStabilityValue(array[i]): array[i]; diff --git a/src/main/java/io/github/arrayv/visuals/dots/SpiralDots.java b/src/main/java/io/github/arrayv/visuals/dots/SpiralDots.java index 2d72f21c..f3bda784 100644 --- a/src/main/java/io/github/arrayv/visuals/dots/SpiralDots.java +++ b/src/main/java/io/github/arrayv/visuals/dots/SpiralDots.java @@ -65,8 +65,9 @@ public void drawVisual(int[] array, ArrayVisualizer arrayVisualizer, Renderer re this.mainRender.setStroke(arrayVisualizer.getCustomStroke(4)); } else if (arrayVisualizer.colorEnabled()) this.mainRender.setColor(getIntColor(array[i], arrayVisualizer.getCurrentLength())); - - else this.mainRender.setColor(Color.WHITE); + else if (Highlights.hasColor(array, i)) { + this.mainRender.setColor(Highlights.colorAt(array, i)); + } else this.mainRender.setColor(Color.WHITE); mult = (double) array[i] / arrayVisualizer.getCurrentLength(); int x = width/2 + (int)(mult * r * Math.cos(Math.PI * (2d*i / n - 0.5))); diff --git a/src/main/java/io/github/arrayv/visuals/dots/WaveDots.java b/src/main/java/io/github/arrayv/visuals/dots/WaveDots.java index 9d9f8676..0c85a400 100644 --- a/src/main/java/io/github/arrayv/visuals/dots/WaveDots.java +++ b/src/main/java/io/github/arrayv/visuals/dots/WaveDots.java @@ -58,7 +58,9 @@ public void drawVisual(int[] array, ArrayVisualizer arrayVisualizer, Renderer re this.mainRender.setStroke(arrayVisualizer.getCustomStroke(4)); } else if (arrayVisualizer.colorEnabled()) this.mainRender.setColor(getIntColor(array[i-1], arrayVisualizer.getCurrentLength())); - else this.mainRender.setColor(Color.WHITE); + else if (Highlights.hasColor(array, i)) { + this.mainRender.setColor(Highlights.colorAt(array, i)); + } else this.mainRender.setColor(Color.WHITE); int y = (int) (((renderer.getViewSize() - 20) / 2.5) * Math.sin((2 * Math.PI * ((double) array[i] / renderer.getArrayLength()))) + renderer.halfViewSize() - 20); diff --git a/src/main/java/io/github/arrayv/visuals/image/CustomImage.java b/src/main/java/io/github/arrayv/visuals/image/CustomImage.java index 8a99b39d..a48f84c8 100644 --- a/src/main/java/io/github/arrayv/visuals/image/CustomImage.java +++ b/src/main/java/io/github/arrayv/visuals/image/CustomImage.java @@ -348,6 +348,11 @@ public void drawVisual(int[] array, ArrayVisualizer arrayVisualizer, Renderer re else this.mainRender.setColor(new Color(1, 0, 0, .5f)); this.mainRender.fillRect(j + 20, 40, Math.max(width, 2), arrayVisualizer.windowHeight()-10); + } else if (Highlights.hasColor(array, i)) { + Color original = Highlights.colorAt(array, i); + this.mainRender.setColor(new Color(original.getRed(), original.getGreen(), original.getBlue(), 63)); + + if (width > 0) this.mainRender.fillRect(j + 20, 40, width, arrayVisualizer.windowHeight()-10); } j += width; } diff --git a/src/main/java/io/github/arrayv/visuals/misc/HoopStack.java b/src/main/java/io/github/arrayv/visuals/misc/HoopStack.java index d918757a..f1d310eb 100644 --- a/src/main/java/io/github/arrayv/visuals/misc/HoopStack.java +++ b/src/main/java/io/github/arrayv/visuals/misc/HoopStack.java @@ -68,6 +68,8 @@ else if (Highlights.containsPosition(i)) { else this.mainRender.setColor(Color.WHITE); this.mainRender.setStroke(arrayVisualizer.getDefaultStroke()); + } else if (Highlights.hasColor(array, i)) { + this.mainRender.setColor(Highlights.colorAt(array, i)); } else this.mainRender.setColor(getIntColor(array[i], length)); this.drawEllipseFromCenter(width / 2, y + radiusY * 2, (int) (scale * radiusX + 0.5), (int) (scale * radiusY + 0.5));