diff --git a/README.md b/README.md new file mode 100644 index 0000000..738a6da --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# CardCode + +A system for encoding text into card deck permutations. + +## Links + +- **[How it works](https://asherfalcon.com/blog/posts/3)** - Detailed writeup of the algorithm and implementation +- **[Live Demo](https://deckcrypt.github.io)** - Try it out in your browser + +## Credits + +- Theme for web version: [Catppuccin](https://github.com/catppuccin) +- Header-only bignum library: [983](https://github.com/983) \ No newline at end of file diff --git a/main.py b/main.py index 34eaf72..33ad571 100644 --- a/main.py +++ b/main.py @@ -35,17 +35,11 @@ def convertToPermutation(number: int, permutationElements: int) -> [int]: global factorials if(number >= factorials[permutationElements]): raise ValueError("Given number is outside of permutation range") - return - factoradic = convertToFactoradic(number) - while len(factoradic) < permutationElements: factoradic.insert(0,0) - available = list(range(permutationElements)) - permutation = [] - for i in factoradic: permutation.append(available[i]) available.pop(i) @@ -62,6 +56,7 @@ def convertToDecimal(permutation: [int]) -> int: index = numbers.index(i) factoradic.append(index) numbers.pop(index) + print(factoradic) return convertToDenary(factoradic) def textToPackOfCards(text: str) -> [int]: @@ -71,15 +66,11 @@ def textToPackOfCards(text: str) -> [int]: for i in text.lower(): if not i in alphabet: raise ValueError("Text must only be characters A-Z or '., -\"/' in order to use 5bit") - return data = 0 for i in text.lower(): - data<<=(4 if not i else 5) + data<<=5 data|=alphabet.index(i) - print(bin(data)) data <<= (5*(45-len(text))) - print(f"bin: {bin(data)}") - print(f"num: {data}") return convertToPermutation(data, 52) def packOfCardsToText(cards: [int]) -> str: global alphabet @@ -107,11 +98,20 @@ def packOfCardsToText(cards: [int]) -> str: #print(convertToPermutation(tnum, 52)) #print(convertToDecimal(convertToPermutation(tnum, 52))) tstr = "hello world" -secretcards = textToPackOfCards(tstr) -#for i in secretcards: -# print(cards[i]) +c = textToPackOfCards(tstr) +print(c) +for i in c: + print(cards[i], end=" ") +# secretcards = textToPackOfCards(tstr) + +# #for i in secretcards: +# # print(cards[i]) +# print(textToPackOfCards(tstr)) print(textToPackOfCards(tstr)) print(packOfCardsToText(textToPackOfCards(tstr))) -print(packOfCardsToText([0, 24, 4, 46, 19, 51, 20, 23, 21, 7, 14, 48, 43, 34, 17, 15, 13, 3, 42, 36, 50, 25, 32, 12, 33, 27, 1, 47, 37, 39, 31, 2, 18, 6, 22, 38, 30, 41, -28, 10, 26, 29, 40, 35, 49, 16, 45, 8, 5, 9, 11, 44])) +# print(packOfCardsToText([0, 24, 4, 46, 19, 51, 20, 23, 21, 7, 14, 48, 43, 34, 17, 15, 13, 3, 42, 36, 50, 25, 32, 12, 33, 27, 1, 47, 37, 39, 31, 2, 18, 6, 22, 38, 30, 41, +# 28, 10, 26, 29, 40, 35, 49, 16, 45, 8, 5, 9, 11, 44])) + +# print(convertToDecimal([3,1,2,4,0])) +# print(convertToFactoradic(17)) \ No newline at end of file diff --git a/web/README.md b/web/README.md new file mode 100644 index 0000000..8a4cd8e --- /dev/null +++ b/web/README.md @@ -0,0 +1,7 @@ +# DeckCrypt 🃏 + +Convert your message into the order of a deck of playing cards and vice versa. + +## Credits + +Styled with [Catppuccin](https://catppuccin.com) theme. \ No newline at end of file diff --git a/web/src/App.jsx b/web/src/App.jsx index 388ce9f..0e03284 100644 --- a/web/src/App.jsx +++ b/web/src/App.jsx @@ -26,6 +26,11 @@ function App() { const [decodedText, setDecodedText] = useState(''); const [dragIdx, setDragIdx] = useState(null); const [overIdx, setOverIdx] = useState(null); + + // touch drag states for mobile + const [touchDragIdx, setTouchDragIdx] = useState(null); + const [touchOverIdx, setTouchOverIdx] = useState(null); + const [isDragging, setIsDragging] = useState(false); // encryption const [useEncryption, setUseEncryption] = useState(false); @@ -113,21 +118,69 @@ function App() { // drag handlers for decode reorder const handleDrop = useCallback( (targetIdx) => { + const sourceIdx = dragIdx !== null ? dragIdx : touchDragIdx; setOrder((prev) => { - if (dragIdx === null || dragIdx === targetIdx) return prev; + if (sourceIdx === null || sourceIdx === targetIdx) return prev; const newOrder = [...prev]; // Remove the dragged item from its current position - const draggedItem = newOrder.splice(dragIdx, 1)[0]; + const draggedItem = newOrder.splice(sourceIdx, 1)[0]; // Insert it at the target position newOrder.splice(targetIdx, 0, draggedItem); return newOrder; }); setDragIdx(null); setOverIdx(null); + setTouchDragIdx(null); + setTouchOverIdx(null); + setIsDragging(false); }, - [dragIdx] + [dragIdx, touchDragIdx] ); + // touch event handlers for mobile + const handleTouchStart = useCallback((e, idx) => { + e.preventDefault(); + setTouchDragIdx(idx); + setIsDragging(true); + }, []); + + const handleTouchMove = useCallback((e) => { + if (!isDragging || touchDragIdx === null) return; + e.preventDefault(); + + const touch = e.touches[0]; + const elementBelow = document.elementFromPoint(touch.clientX, touch.clientY); + + if (elementBelow) { + const cardElement = elementBelow.closest('[data-card-index]'); + if (cardElement) { + const targetIdx = parseInt(cardElement.getAttribute('data-card-index')); + setTouchOverIdx(targetIdx); + } else { + setTouchOverIdx(null); + } + } + }, [isDragging, touchDragIdx]); + + const handleTouchEnd = useCallback((e) => { + if (!isDragging || touchDragIdx === null) { + setIsDragging(false); + setTouchDragIdx(null); + setTouchOverIdx(null); + return; + } + + e.preventDefault(); + + if (touchOverIdx !== null && touchOverIdx !== touchDragIdx) { + handleDrop(touchOverIdx); + } else { + setTouchDragIdx(null); + setTouchOverIdx(null); + setIsDragging(false); + } + }, [isDragging, touchDragIdx, touchOverIdx, handleDrop]); + const resetDecode = () => { setOrder(Array.from({ length: 52 }, (_, i) => i)); setDecodedText(''); @@ -143,9 +196,20 @@ function App() {

Made by Asher Falcon

+ + + + + View Source Code +

Read the blog post to learn how it works @@ -153,6 +217,10 @@ function App() {

+ +

+ Convert your message into the order of a deck of playing cards and vice versa +

{/* Mode Toggle - Segmented Control */}
@@ -266,21 +334,32 @@ function App() {

Drag Cards to Reorder

{/* draggable card grid */} -
+
{order.map((cardIdx, gridIdx) => ( - setDragIdx(gridIdx)} - onDragOver={(e) => { - e.preventDefault(); - setOverIdx(gridIdx); - }} - onDrop={() => handleDrop(gridIdx)} - onDragLeave={() => setOverIdx(null)} - dropTarget={overIdx === gridIdx && dragIdx !== gridIdx} - /> +
+ setDragIdx(gridIdx)} + onDragOver={(e) => { + e.preventDefault(); + setOverIdx(gridIdx); + }} + onDrop={() => handleDrop(gridIdx)} + onDragLeave={() => setOverIdx(null)} + onTouchStart={(e) => handleTouchStart(e, gridIdx)} + dropTarget={(overIdx === gridIdx && dragIdx !== gridIdx) || (touchOverIdx === gridIdx && touchDragIdx !== gridIdx)} + style={{ + opacity: touchDragIdx === gridIdx ? 0.5 : 1, + transform: touchDragIdx === gridIdx ? 'scale(1.05)' : 'scale(1)', + transition: touchDragIdx === gridIdx ? 'none' : 'transform 0.2s ease', + }} + /> +
))}
@@ -304,31 +383,6 @@ function App() {
)}
- - {/* Credits section */} -
); }