aboutsummaryrefslogtreecommitdiff
path: root/lib/Shupai.hs
diff options
context:
space:
mode:
authorMistivia <i@mistivia.com>2025-05-27 00:56:09 +0800
committerMistivia <i@mistivia.com>2025-05-27 00:56:09 +0800
commitf9f515257c68e070f418fbfc5774282194ca7770 (patch)
tree9f8bd4b92c3fced8a36fa28aa9a779f7774f8bde /lib/Shupai.hs
init
Diffstat (limited to 'lib/Shupai.hs')
-rw-r--r--lib/Shupai.hs161
1 files changed, 161 insertions, 0 deletions
diff --git a/lib/Shupai.hs b/lib/Shupai.hs
new file mode 100644
index 0000000..b92b950
--- /dev/null
+++ b/lib/Shupai.hs
@@ -0,0 +1,161 @@
+module Shupai
+ ( shupai
+ )
+where
+
+import Data.Bits ((.&.), complement)
+import Data.Char (ord)
+import qualified Data.Map as Map
+import Data.Function ((&))
+import qualified Data.Maybe as Maybe
+import Data.List.Split (chunksOf)
+import Data.List (transpose)
+
+
+isWideChar :: Char -> Bool
+isWideChar c = inRange $ ord c where
+ inRange x
+ | x >= 0x1100 && x <= 0x115f = True
+ | x >= 0x115f && x <= 0xa4cf && x /= 0x303f
+ && (x .&. complement 0x0011) /= 0x300a = True
+ | x >= 0xac00 && x <= 0xd7a3 = True
+ | x >= 0xf900 && x <= 0xfaff = True
+ | x >= 0xfe30 && x <= 0xfe6f = True
+ | x >= 0xff00 && x <= 0xff5f = True
+ | x >= 0xffe0 && x <= 0xffe6 = True
+ | x >= 0x20000 && x <= 0x2ffff = True
+ | otherwise = False
+
+textPreprocess :: String -> String
+textPreprocess s = s & filter isValid & map toFullWidth where
+ isValid c = isWideChar c || Map.member c fullWidthMap
+ toFullWidth c = Maybe.fromMaybe c $ Map.lookup c fullWidthMap
+
+verticalFormat :: String -> String
+verticalFormat s
+ | length s < 25 = verticalCompose $ chunksOf 5 s
+ | otherwise = verticalCompose $ chunksOf (length s `div` 5 + 1) s
+
+verticalCompose :: [String] -> String
+verticalCompose lst = lst
+ & fillSpace
+ & transpose
+ & map (addSpace . reverse)
+ & unlines
+
+addSpace :: String -> String
+addSpace [] = []
+addSpace [x] = [x]
+addSpace (x:xs) = x : ' ' : addSpace xs
+
+fillSpace :: [String] -> [String]
+fillSpace [] = []
+fillSpace [x] = [x]
+fillSpace ls = go ls $ length (head ls) where
+ go :: [String] -> Int -> [String]
+ go [] _ = []
+ go [x] len = [x ++ replicate (len - length x) 'ㅤ']
+ go (x:xs) len = x : go xs len
+
+
+shupai :: String -> String
+shupai = verticalFormat . textPreprocess
+
+fullWidthMap :: Map.Map Char Char
+fullWidthMap = Map.fromList
+ [ ('!', '!')
+ , ('"', '"')
+ , ('#', '#')
+ , ('$', '$')
+ , ('%', '%')
+ , ('&', '&')
+ , ('\'', ''')
+ , ('(', '(')
+ , (')', ')')
+ , ('*', '*')
+ , ('+', '+')
+ , (',', ',')
+ , ('-', '-')
+ , ('.', '.')
+ , ('/', '/')
+ , ('0', '0')
+ , ('1', '1')
+ , ('2', '2')
+ , ('3', '3')
+ , ('4', '4')
+ , ('5', '5')
+ , ('6', '6')
+ , ('7', '7')
+ , ('8', '8')
+ , ('9', '9')
+ , (':', ':')
+ , (';', ';')
+ , ('<', '<')
+ , ('=', '=')
+ , ('>', '>')
+ , ('?', '?')
+ , ('@', '@')
+ , ('A', 'A')
+ , ('B', 'B')
+ , ('C', 'C')
+ , ('D', 'D')
+ , ('E', 'E')
+ , ('F', 'F')
+ , ('G', 'G')
+ , ('H', 'H')
+ , ('I', 'I')
+ , ('J', 'J')
+ , ('K', 'K')
+ , ('L', 'L')
+ , ('M', 'M')
+ , ('N', 'N')
+ , ('O', 'O')
+ , ('P', 'P')
+ , ('Q', 'Q')
+ , ('R', 'R')
+ , ('S', 'S')
+ , ('T', 'T')
+ , ('U', 'U')
+ , ('V', 'V')
+ , ('W', 'W')
+ , ('X', 'X')
+ , ('Y', 'Y')
+ , ('Z', 'Z')
+ , ('[', '[')
+ , ('\\', '\')
+ , (']', ']')
+ , ('^', '^')
+ , ('_', '_')
+ , ('`', '`')
+ , ('a', 'a')
+ , ('b', 'b')
+ , ('c', 'c')
+ , ('d', 'd')
+ , ('e', 'e')
+ , ('f', 'f')
+ , ('g', 'g')
+ , ('h', 'h')
+ , ('i', 'i')
+ , ('j', 'j')
+ , ('k', 'k')
+ , ('l', 'l')
+ , ('m', 'm')
+ , ('n', 'n')
+ , ('o', 'o')
+ , ('p', 'p')
+ , ('q', 'q')
+ , ('r', 'r')
+ , ('s', 's')
+ , ('t', 't')
+ , ('u', 'u')
+ , ('v', 'v')
+ , ('w', 'w')
+ , ('x', 'x')
+ , ('y', 'y')
+ , ('z', 'z')
+ , ('{', '{')
+ , ('|', '|')
+ , ('}', '}')
+ , ('~', '~')
+ , (' ', 'ㅤ')
+ ]