{"id":102,"date":"2026-08-21T16:40:41","date_gmt":"2026-08-21T08:40:41","guid":{"rendered":"https:\/\/www.mrsfa.com\/?page_id=102"},"modified":"2026-08-21T16:40:41","modified_gmt":"2026-08-21T08:40:41","slug":"american-mahjong-trainer","status":"publish","type":"page","link":"https:\/\/www.mrsfa.com\/index.php\/american-mahjong-trainer\/","title":{"rendered":"Free American Mahjong Charleston Trainer for Beginners"},"content":{"rendered":"<style>:root{--ink:#17231d;--muted:#64736b;--cream:#f5f1e7;--card:#fffdf8;--green:#124e3a;--green2:#1c6a50;--gold:#d9a441;--line:#dcd8cc;--shadow:0 20px 60px rgba(31,50,40,.13)}\n*{box-sizing:border-box}body{margin:0;background:radial-gradient(circle at 85% 0,#e4efe7 0,transparent 32%),var(--cream);color:var(--ink);font-family:Inter,ui-sans-serif,system-ui,-apple-system,\"Segoe UI\",sans-serif}.shell{width:min(1180px,calc(100% - 32px));margin:auto;padding:28px 0 72px}.hero{position:relative;overflow:hidden;border-radius:28px;background:linear-gradient(125deg,#0d3d2e,#1d624a);color:white;padding:24px 32px 32px;box-shadow:var(--shadow)}.hero:after{content:\"\ud83c\udc04\";position:absolute;right:-12px;top:-56px;font-size:210px;opacity:.06;transform:rotate(12deg)}.brand{display:inline-flex;gap:7px;color:white;text-decoration:none;font-weight:900;letter-spacing:.08em}.brand span{font-weight:500;opacity:.76}.hero-copy{max-width:700px;padding:52px 0 38px}.eyebrow{margin:0 0 9px;color:#e7bd62;font-size:13px;font-weight:800;letter-spacing:.14em;text-transform:uppercase}.hero h1{font-family:Georgia,serif;font-size:clamp(42px,7vw,76px);line-height:.96;margin:0 0 20px}.hero-copy>p:last-child{font-size:18px;line-height:1.65;color:#dceae4;max-width:650px}.stats{display:flex;gap:10px;position:absolute;right:28px;bottom:28px;z-index:1}.stats div{min-width:88px;background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.16);border-radius:15px;padding:11px 14px;text-align:center;backdrop-filter:blur(8px)}.stats strong,.stats span{display:block}.stats strong{font-size:20px}.stats span{font-size:11px;text-transform:uppercase;letter-spacing:.1em;opacity:.7;margin-top:2px}.game-card{margin-top:24px;background:var(--card);border:1px solid #e5e0d4;border-radius:28px;padding:32px;box-shadow:var(--shadow)}.game-topline,.selection-bar{display:flex;justify-content:space-between;align-items:center;gap:20px}.step{margin:0 0 6px;color:var(--green2);font-size:12px;font-weight:900;letter-spacing:.13em}.game-topline h2{margin:0;font-family:Georgia,serif;font-size:clamp(23px,3vw,34px)}button,select{font:inherit}.quiet-button{border:1px solid var(--line);background:white;border-radius:12px;padding:10px 15px;color:var(--ink);font-weight:700;cursor:pointer}.coach{display:flex;align-items:flex-start;gap:13px;background:#edf5ef;border-left:4px solid var(--green2);border-radius:12px;padding:15px 17px;margin:24px 0}.coach-icon{display:grid;place-items:center;flex:0 0 27px;height:27px;border-radius:50%;background:var(--green);color:white}.coach p{margin:1px 0;line-height:1.55;color:#365247}.rack-wrap{overflow-x:auto;padding:25px 8px 10px}.rack{display:flex;gap:8px;justify-content:center;min-width:800px;position:relative;z-index:2}.tile{width:57px;height:78px;flex:0 0 57px;border:0;border-radius:9px 9px 6px 6px;background:linear-gradient(145deg,#fff,#f3f0e8);box-shadow:0 5px 0 #c8c3b7,0 8px 13px rgba(32,43,37,.18);padding:6px 3px;cursor:pointer;transition:.17s transform,.17s box-shadow;display:flex;flex-direction:column;align-items:center;justify-content:center}.tile:hover{transform:translateY(-4px)}.tile.selected{transform:translateY(-12px);box-shadow:0 5px 0 var(--gold),0 13px 18px rgba(140,94,16,.22);outline:3px solid #edc470}.tile .symbol{font-family:Georgia,serif;font-size:28px;line-height:1;color:#1e513f}.tile.crak .symbol{color:#ac332e}.tile.dot .symbol{color:#225c8a}.tile.honor .symbol{color:#233c77}.tile.flower .symbol{font-size:26px}.tile.joker .symbol{font-size:19px;color:#873e91;font-weight:900}.tile small{margin-top:7px;font-size:9px;color:#66726b;text-transform:uppercase;font-weight:800}.rack-base{height:17px;min-width:800px;margin:-2px auto 0;border-radius:5px 5px 13px 13px;background:linear-gradient(#7d3d2b,#54281f);box-shadow:0 7px 12px rgba(57,31,22,.22)}.selection-bar{border-top:1px solid #ebe7de;margin-top:25px;padding-top:24px}.selection-bar p{margin:0;color:var(--muted)}.primary-button{border:0;border-radius:14px;background:var(--green);color:white;padding:14px 20px;font-weight:850;cursor:pointer;box-shadow:0 8px 18px rgba(18,78,58,.22)}.primary-button:disabled{background:#b6c0ba;box-shadow:none;cursor:not-allowed}.primary-button span{margin-left:12px}.insight-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin:20px 0}.insight-grid article{background:rgba(255,253,248,.72);border:1px solid #e3ded1;border-radius:18px;padding:22px}.insight-grid .icon{display:grid;place-items:center;width:38px;height:38px;border-radius:10px;background:#e4eee7;color:var(--green);font-weight:900}.insight-grid h3{font-family:Georgia,serif;font-size:19px;margin:15px 0 7px}.insight-grid p{margin:0;color:var(--muted);line-height:1.55;font-size:14px}.learn-more{display:grid;grid-template-columns:1fr 1fr;gap:55px;background:#17231d;color:white;border-radius:24px;padding:34px;margin-top:20px}.learn-more h2{font-family:Georgia,serif;font-size:31px;margin:0 0 12px}.learn-more>div>p:last-child{color:#b8c8c0;line-height:1.6}.learn-more nav{display:grid;align-content:center}.learn-more nav a{display:flex;justify-content:space-between;color:#eef7f2;text-decoration:none;padding:14px 2px;border-bottom:1px solid rgba(255,255,255,.14)}.learn-more nav a:hover{color:#f2c76c}.game-controls{display:flex;align-items:center;justify-content:flex-end;gap:8px;flex-wrap:wrap}.game-controls label{display:flex;align-items:center;gap:7px;color:var(--muted);font-size:12px;font-weight:800}.game-controls select,.icon-button{border:1px solid var(--line);background:#fff;border-radius:12px;padding:10px;color:var(--ink);font-weight:700}.icon-button{width:40px;cursor:pointer}.result-card{margin-top:20px;background:#fffdf8;border:1px solid #e2d9c5;border-radius:24px;padding:28px;box-shadow:var(--shadow)}.result-card[hidden]{display:none}.result-heading{display:flex;justify-content:space-between;align-items:center}.result-heading h2{font-family:Georgia,serif;margin:0;font-size:30px}.result-heading>strong{display:grid;place-items:center;width:65px;height:65px;border-radius:50%;background:var(--green);color:#fff;font:700 34px Georgia}.result-score{margin:22px 0}.result-score span{font-size:48px;font-weight:900;color:var(--green)}.result-score small{color:var(--muted);margin-left:8px}.result-details{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}.result-details article{background:#f2f4ee;border-radius:13px;padding:14px}.result-details strong,.result-details span,.result-details small{display:block}.result-details span{color:var(--green2);margin:5px 0;font-size:13px}.result-details small{color:var(--muted);line-height:1.4}.result-tip{background:#fff4d9;border-left:4px solid var(--gold);padding:14px 16px;border-radius:9px;line-height:1.55}@media(max-width:760px){.shell{width:min(100% - 20px,1180px);padding-top:10px}.hero,.game-card{border-radius:20px;padding:22px}.hero-copy{padding:38px 0 100px}.stats{left:20px;right:auto;bottom:20px}.stats div{min-width:76px}.game-topline{align-items:flex-start;flex-direction:column}.game-controls{justify-content:flex-start}.rack{justify-content:flex-start}.selection-bar{align-items:stretch;flex-direction:column}.primary-button{width:100%}.insight-grid,.learn-more,.result-details{grid-template-columns:1fr}.learn-more{gap:15px;padding:25px}.tile{width:52px;flex-basis:52px;height:72px}}\n.selection-bar>div{min-width:0}.selection-reasons{display:grid;gap:5px;margin-top:8px;max-width:700px}.selection-reasons span{font-size:12px;line-height:1.4;color:#65736c}.selection-reasons strong{color:#244b3d}.legal-note{margin-top:20px;padding:23px 28px;border:1px solid #ded9cd;border-radius:18px;background:rgba(255,253,248,.7)}.legal-note h2{margin:0 0 8px;font:700 21px Georgia,serif}.legal-note p{margin:0;color:var(--muted);font-size:13px;line-height:1.65}.onboarding{position:fixed;inset:0;z-index:9999;display:grid;place-items:center;padding:18px;background:rgba(10,27,21,.76);backdrop-filter:blur(8px)}.onboarding[hidden]{display:none}.onboarding-card{width:min(520px,100%);border-radius:25px;background:#fffdf8;padding:34px;text-align:center;box-shadow:0 30px 90px rgba(0,0,0,.35)}.onboarding-number{display:inline-block;padding:6px 11px;border-radius:99px;background:#e5efe8;color:var(--green);font-size:12px;font-weight:900;letter-spacing:.08em}.onboarding h2{margin:20px 0 10px;font:700 32px Georgia,serif}.onboarding p{color:var(--muted);line-height:1.6}.onboarding-visual{margin:24px 0;padding:22px;border-radius:14px;background:#eef3ed;color:#1c5e47;font:700 23px Georgia,serif;letter-spacing:.04em}.onboarding .primary-button{display:block;width:100%}.skip-button{border:0;background:none;color:var(--muted);padding:14px;cursor:pointer}.tile:focus-visible,.primary-button:focus-visible,.icon-button:focus-visible,.quiet-button:focus-visible{outline:3px solid #e5b85c;outline-offset:3px}@media(max-width:760px){.selection-reasons{max-width:100%}.onboarding-card{padding:25px}.onboarding h2{font-size:27px}.legal-note{padding:20px}}\n.faq{margin-top:20px;padding:30px;background:#fffdf8;border:1px solid #e2ddd1;border-radius:22px}.faq h2{margin:0 0 20px;font:700 30px Georgia,serif}.faq details{border-top:1px solid #e3ded3;padding:15px 2px}.faq summary{cursor:pointer;font-weight:800}.faq details p{color:var(--muted);line-height:1.6;margin:10px 0 2px}\n<\/style>\n<p><main class=\"shell\"><\/p>\n<header class=\"hero\">\n      <a class=\"brand\" href=\"https:\/\/www.mrsfa.com\/\">MRSFA <span>Mahjong<\/span><\/a><\/p>\n<div class=\"hero-copy\">\n<p class=\"eyebrow\" id=\"heroEyebrow\">Free American Mahjong Practice<\/p>\n<h1 id=\"heroTitle\">Charleston Trainer<\/h1>\n<p id=\"heroDescription\">Build a direction, choose three tiles to pass, and learn why each decision helps\u2014or limits\u2014your hand.<\/p>\n<\/p><\/div>\n<div class=\"stats\" aria-label=\"Practice statistics\">\n<div><strong id=\"roundLabel\">Ready<\/strong><span id=\"roundText\">Round<\/span><\/div>\n<div><strong id=\"scoreLabel\">0<\/strong><span id=\"scoreText\">Score<\/span><\/div>\n<div><strong id=\"bestLabel\">0<\/strong><span id=\"bestText\">Best<\/span><\/div>\n<\/p><\/div>\n<\/header>\n<section class=\"game-card\" aria-labelledby=\"gameHeading\">\n<div class=\"game-topline\">\n<div>\n<p class=\"step\" id=\"directionLabel\">RIGHT PASS \u00b7 SELECT 3 TILES<\/p>\n<h2 id=\"gameHeading\">Choose tiles that least support your rack<\/h2>\n<\/div>\n<div class=\"game-controls\">\n          <label><span id=\"levelText\">Level<\/span> <select id=\"difficulty\"><option value=\"easy\">Easy<\/option><option value=\"normal\" selected>Normal<\/option><option value=\"hard\">Hard<\/option><\/select><\/label><br \/>\n          <button class=\"icon-button\" id=\"languageButton\" type=\"button\" aria-label=\"Switch coaching language\">\u4e2d<\/button><br \/>\n          <button class=\"icon-button\" id=\"soundButton\" type=\"button\" aria-label=\"Toggle sound\">\u266a<\/button><br \/>\n          <button class=\"quiet-button\" id=\"newGameButton\" type=\"button\">New rack<\/button>\n        <\/div>\n<\/p><\/div>\n<div class=\"coach\" id=\"coach\" role=\"status\" aria-live=\"polite\">\n        <span class=\"coach-icon\">\u25ce<\/span><\/p>\n<p><strong>Coach:<\/strong> Start by finding pairs, repeated numbers, and your strongest suit. Pass tiles that support none of those clues.<\/p>\n<\/p><\/div>\n<div class=\"rack-wrap\">\n<div class=\"rack\" id=\"rack\" aria-label=\"Your American Mahjong rack\"><\/div>\n<div class=\"rack-base\"><\/div>\n<\/p><\/div>\n<div class=\"selection-bar\">\n<div>\n<p><strong id=\"selectedCount\">0 of 3<\/strong> <span id=\"selectedText\">selected<\/span><\/p>\n<div class=\"selection-reasons\" id=\"selectionReasons\" aria-live=\"polite\"><\/div>\n<\/div>\n<p>        <button class=\"primary-button\" id=\"passButton\" type=\"button\" disabled>Pass selected tiles <span>\u2192<\/span><\/button>\n      <\/div>\n<\/section>\n<section class=\"result-card\" id=\"resultCard\" hidden aria-labelledby=\"resultTitle\">\n<div class=\"result-heading\">\n<div>\n<p class=\"eyebrow\">Practice review<\/p>\n<h2 id=\"resultTitle\">Your Charleston analysis<\/h2>\n<\/div>\n<p><strong id=\"resultGrade\">B<\/strong><\/div>\n<div class=\"result-score\"><span id=\"resultScore\">0<\/span><small>out of 300<\/small><\/div>\n<div class=\"result-details\" id=\"resultDetails\"><\/div>\n<p class=\"result-tip\" id=\"resultTip\">\n<\/section>\n<section class=\"insight-grid\">\n<article><span class=\"icon\">\u25eb<\/span><\/p>\n<h3>Read your rack<\/h3>\n<p>Pairs, clusters, and suit concentration are useful early clues\u2014not permanent commitments.<\/p>\n<\/article>\n<article><span class=\"icon\">\u2197<\/span><\/p>\n<h3>Protect flexibility<\/h3>\n<p>Keep tiles that work in more than one possible card line while your direction is forming.<\/p>\n<\/article>\n<article><span class=\"icon\">\u2713<\/span><\/p>\n<h3>Learn from feedback<\/h3>\n<p>After every pass, compare your choice with a structure-based recommendation.<\/p>\n<\/article>\n<\/section>\n<section class=\"learn-more\">\n<div>\n<p class=\"eyebrow\">Build the fundamentals<\/p>\n<h2>Turn practice into confident play<\/h2>\n<p>The trainer teaches general decision skills and does not reproduce any annual NMJL card.<\/p>\n<\/div>\n<nav aria-label=\"Related learning guides\">\n        <a href=\"https:\/\/www.mrsfa.com\/index.php\/2026\/08\/17\/how-to-read-nmjl-card\/\">How to Read the NMJL Card <span>\u2192<\/span><\/a><br \/>\n        <a href=\"https:\/\/www.mrsfa.com\/index.php\/2026\/08\/02\/what-to-pass-in-the-charleston\/\">What to Pass in the Charleston <span>\u2192<\/span><\/a><br \/>\n        <a href=\"https:\/\/www.mrsfa.com\/index.php\/2026\/07\/30\/american-mahjong-joker-rules\/\">American Mahjong Joker Rules <span>\u2192<\/span><\/a><br \/>\n      <\/nav>\n<\/section>\n<section class=\"legal-note\">\n<h2 id=\"privacyTitle\">Practice safely and privately<\/h2>\n<p id=\"privacyText\">No account is required. Scores and preferences stay in your browser and are not sent to MRSFA. This independent learning tool is not affiliated with or endorsed by the National Mah Jongg League and does not reproduce any annual card.<\/p>\n<\/section>\n<section class=\"faq\" id=\"faq\">\n<p class=\"eyebrow\">Common questions<\/p>\n<h2>American Mahjong Charleston practice FAQ<\/h2>\n<details>\n<summary>What is the Charleston in American Mahjong?<\/summary>\n<p>The Charleston is a structured series of three-tile passes used before normal play. It helps players improve their racks and begin identifying possible hands.<\/p>\n<\/details>\n<details>\n<summary>Does this trainer use the current NMJL card?<\/summary>\n<p>No. The trainer teaches general skills such as protecting pairs, recognizing clusters, and preserving flexibility. It does not display or reproduce any annual card.<\/p>\n<\/details>\n<details>\n<summary>Do I need an account?<\/summary>\n<p>No. The trainer runs in your browser. Your best score and preferences remain on your own device.<\/p>\n<\/details>\n<details>\n<summary>Can complete beginners use it?<\/summary>\n<p>Yes. The introduction, tile-by-tile explanations, three difficulty levels, and optional Chinese coaching are designed for new players.<\/p>\n<\/details>\n<\/section>\n<p>    <script type=\"application\/ld+json\">{\"@context\":\"https:\/\/schema.org\",\"@type\":\"WebApplication\",\"name\":\"MRSFA American Mahjong Charleston Trainer\",\"applicationCategory\":\"GameApplication\",\"operatingSystem\":\"Any\",\"isAccessibleForFree\":true,\"description\":\"A free browser-based American Mahjong Charleston practice tool with instant beginner feedback.\",\"url\":\"https:\/\/www.mrsfa.com\/american-mahjong-trainer\/\",\"publisher\":{\"@type\":\"Organization\",\"name\":\"MRSFA\",\"url\":\"https:\/\/www.mrsfa.com\/\"}}<\/script><br \/>\n  <\/main><script>const suits=[['dot','\u25cf'],['bam','\u25a5'],['crak','\u842c']],honors=[['honor','E'],['honor','S'],['honor','W'],['honor','N'],['honor','R'],['honor','G'],['honor','0']],flowers=[['flower','\u273f'],['flower','\u2740'],['flower','\u273e'],['flower','\u2741']];\nconst directions=['RIGHT PASS','ACROSS PASS','LEFT PASS'],directionZh=['\u5411\u53f3\u4f20\u724c','\u5bf9\u9762\u4f20\u724c','\u5411\u5de6\u4f20\u724c'];\nconst ui={en:{eyebrow:'Free American Mahjong Practice',title:'Charleston Trainer',description:'Build a direction, choose three tiles to pass, and learn why each decision helps\u2014or limits\u2014your hand.',round:'Round',score:'Score',best:'Best',heading:'Choose tiles that least support your rack',level:'Level',selected:'selected',pass:'Pass selected tiles \u2192',privacyTitle:'Practice safely and privately',privacy:'No account is required. Scores and preferences stay in your browser and are not sent to MRSFA. This independent learning tool is not affiliated with or endorsed by the National Mah Jongg League and does not reproduce any annual card.',easy:'Easy',normal:'Normal',hard:'Hard'},zh:{eyebrow:'\u514d\u8d39\u7f8e\u5f0f\u9ebb\u5c06\u7ec3\u4e60',title:'Charleston \u4f20\u724c\u7ec3\u4e60\u5668',description:'\u5224\u65ad\u624b\u724c\u65b9\u5411\uff0c\u9009\u62e9\u4e09\u5f20\u724c\u4f20\u51fa\uff0c\u5e76\u4e86\u89e3\u6bcf\u4e2a\u51b3\u5b9a\u4e3a\u4f55\u6709\u5e2e\u52a9\u6216\u4f1a\u9650\u5236\u540e\u7eed\u9009\u62e9\u3002',round:'\u8f6e\u6b21',score:'\u5f97\u5206',best:'\u6700\u9ad8\u5206',heading:'\u9009\u62e9\u5bf9\u5f53\u524d\u724c\u67b6\u5e2e\u52a9\u6700\u5c0f\u7684\u4e09\u5f20\u724c',level:'\u96be\u5ea6',selected:'\u5df2\u9009\u62e9',pass:'\u4f20\u51fa\u6240\u9009\u724c \u2192',privacyTitle:'\u5b89\u5168\u3001\u79c1\u5bc6\u5730\u7ec3\u4e60',privacy:'\u65e0\u9700\u6ce8\u518c\u8d26\u53f7\u3002\u5f97\u5206\u548c\u504f\u597d\u53ea\u4fdd\u5b58\u5728\u4f60\u7684\u6d4f\u89c8\u5668\u4e2d\uff0c\u4e0d\u4f1a\u53d1\u9001\u7ed9 MRSFA\u3002\u672c\u5de5\u5177\u4e3a\u72ec\u7acb\u5b66\u4e60\u4ea7\u54c1\uff0c\u4e0e National Mah Jongg League \u65e0\u96b6\u5c5e\u6216\u8ba4\u53ef\u5173\u7cfb\uff0c\u4e5f\u4e0d\u4f1a\u590d\u5236\u4efb\u4f55\u5e74\u5ea6\u724c\u5361\u5185\u5bb9\u3002',easy:'\u7b80\u5355',normal:'\u666e\u901a',hard:'\u56f0\u96be'}};\nconst onboardingSteps={en:[['Find the shape of your rack','Look for pairs, repeated numbers, nearby tiles, and the suit you hold most often.','2\u25cf 2\u25cf \u00a0 5\u25a5 6\u25a5 7\u25a5'],['Select exactly three tiles','Tap a tile to select it. Tap it again to change your mind. Each selected tile gets a short explanation.','\u2460 Select \u00a0 \u2461 Review \u00a0 \u2462 Pass'],['Learn from every pass','Computer players pass at the same time. After three rounds, you receive a score and a detailed review.','RIGHT \u2192 ACROSS \u2192 LEFT']],zh:[['\u5148\u770b\u724c\u67b6\u7ed3\u6784','\u5bfb\u627e\u5bf9\u5b50\u3001\u91cd\u590d\u6570\u5b57\u3001\u76f8\u90bb\u6570\u5b57\uff0c\u4ee5\u53ca\u6570\u91cf\u6700\u591a\u7684\u82b1\u8272\u3002','2\u25cf 2\u25cf \u00a0 5\u25a5 6\u25a5 7\u25a5'],['\u6b63\u597d\u9009\u62e9\u4e09\u5f20\u724c','\u70b9\u51fb\u724c\u5373\u53ef\u9009\u62e9\uff0c\u518d\u70b9\u4e00\u6b21\u53ef\u4ee5\u53d6\u6d88\u3002\u6bcf\u5f20\u9009\u4e2d\u7684\u724c\u90fd\u4f1a\u663e\u793a\u7b80\u77ed\u89e3\u91ca\u3002','\u2460 \u9009\u62e9 \u00a0 \u2461 \u68c0\u67e5 \u00a0 \u2462 \u4f20\u724c'],['\u4ece\u6bcf\u8f6e\u4f20\u724c\u4e2d\u5b66\u4e60','\u7535\u8111\u73a9\u5bb6\u4f1a\u540c\u65f6\u4f20\u724c\u3002\u5b8c\u6210\u4e09\u8f6e\u540e\uff0c\u4f60\u4f1a\u5f97\u5230\u603b\u5206\u548c\u8be6\u7ec6\u5206\u6790\u3002','\u5411\u53f3 \u2192 \u5bf9\u9762 \u2192 \u5411\u5de6']]};\nconst copy={en:{coach:'Start by finding pairs, repeated numbers, and your strongest suit. Pass tiles that support none of those clues.',excellent:'Excellent pass. You protected your strongest relationships and removed three low-connection tiles.',strong:'Strong choice. Two selections matched the structure-based recommendation.',weak:'This pass reduced some flexibility. Look again for pairs, clusters, and the suit with the most support.',pair:' One selected tile belonged to a pair, which is usually worth protecting early.',select:'SELECT 3 TILES',complete:'PRACTICE COMPLETE',another:'Practice another rack'},zh:{coach:'\u5148\u627e\u5bf9\u5b50\u3001\u91cd\u590d\u6570\u5b57\u548c\u6570\u91cf\u6700\u591a\u7684\u82b1\u8272\u3002\u4f18\u5148\u4f20\u8d70\u4e0e\u8fd9\u4e9b\u7ebf\u7d22\u90fd\u6ca1\u6709\u5173\u7cfb\u7684\u724c\u3002',excellent:'\u9009\u62e9\u975e\u5e38\u597d\u3002\u4f60\u4fdd\u7559\u4e86\u724c\u67b6\u4e2d\u6700\u5f3a\u7684\u7ec4\u5408\u5173\u7cfb\uff0c\u5e76\u4f20\u8d70\u4e86\u4e09\u5f20\u8054\u7cfb\u8f83\u5f31\u7684\u724c\u3002',strong:'\u9009\u62e9\u4e0d\u9519\uff0c\u5176\u4e2d\u4e24\u5f20\u7b26\u5408\u7ed3\u6784\u5206\u6790\u5efa\u8bae\u3002',weak:'\u8fd9\u6b21\u4f20\u724c\u635f\u5931\u4e86\u4e00\u4e9b\u7075\u6d3b\u6027\u3002\u518d\u68c0\u67e5\u5bf9\u5b50\u3001\u76f8\u90bb\u6570\u5b57\u548c\u6700\u5f3a\u82b1\u8272\u3002',pair:' \u5176\u4e2d\u4e00\u5f20\u5c5e\u4e8e\u5bf9\u5b50\uff0c\u65b0\u624b\u524d\u671f\u901a\u5e38\u5e94\u8be5\u4fdd\u7559\u5bf9\u5b50\u3002',select:'\u8bf7\u9009\u62e9 3 \u5f20\u724c',complete:'\u7ec3\u4e60\u5b8c\u6210',another:'\u518d\u7ec3\u4e00\u5c40'}};\nlet hands=[],selected=new Set(),round=0,score=0,history=[],language='en',sound=true;\nconst rackEl=document.querySelector('#rack'),passButton=document.querySelector('#passButton'),coach=document.querySelector('#coach'),selectedCount=document.querySelector('#selectedCount'),roundLabel=document.querySelector('#roundLabel'),scoreLabel=document.querySelector('#scoreLabel'),bestLabel=document.querySelector('#bestLabel'),resultCard=document.querySelector('#resultCard');\nbestLabel.textContent=localStorage.getItem('mrsfa-charleston-best')||0;\nfunction pool(){const p=[];for(const [s,mark] of suits)for(let n=1;n<=9;n++)for(let i=0;i<4;i++)p.push({s,mark,n,id:crypto.randomUUID()});for(const [s,mark] of honors)for(let i=0;i<4;i++)p.push({s,mark,n:mark,id:crypto.randomUUID()});for(const [s,mark] of flowers)p.push({s,mark,n:'Flower',id:crypto.randomUUID()});for(let i=0;i<8;i++)p.push({s:'joker',mark:'J',n:'Joker',id:crypto.randomUUID()});return p.sort(()=>Math.random()-.5)}\nfunction orderRack(r){const order={dot:0,bam:1,crak:2,honor:3,flower:4,joker:5};r.sort((a,b)=>order[a.s]-order[b.s]||(Number(a.n)||20)-(Number(b.n)||20))}\nfunction tileName(t){if(['dot','bam','crak'].includes(t.s))return `${t.n} ${t.s==='dot'?'Dot':t.s==='bam'?'Bam':'Crak'}`;return String(t.n)}\nfunction strength(t,r=hands[0]){let value=0,same=r.filter(x=>x.s===t.s&&x.n===t.n).length;if(same>1)value+=same*3;const suitCount=r.filter(x=>x.s===t.s).length;if(['dot','bam','crak'].includes(t.s)){value+=suitCount*.35;value+=r.filter(x=>x.s===t.s&&typeof x.n==='number'&&Math.abs(x.n-t.n)<=2).length*.7}else if(t.s==='joker')value+=8;else if(t.s==='flower')value+=2;else value+=same;return value}\nfunction bestPass(r=hands[0]){return [...r].sort((a,b)=>strength(a,r)-strength(b,r)).slice(0,3)}\nfunction computerChoice(r){const mode=document.querySelector('#difficulty').value,ranked=[...r].sort((a,b)=>strength(a,r)-strength(b,r));if(mode==='easy')return [...ranked].sort(()=>Math.random()-.5).slice(0,3);if(mode==='hard')return ranked.slice(0,3);return [ranked[0],ranked[1],ranked[Math.min(4,ranked.length-1)]]}\nfunction reason(t){const same=hands[0].filter(x=>x.s===t.s&&x.n===t.n).length,suitCount=hands[0].filter(x=>x.s===t.s).length,near=hands[0].filter(x=>x.s===t.s&&typeof x.n==='number'&&Math.abs(x.n-t.n)<=2).length;if(t.s==='joker')return language==='zh'?'Joker \u7075\u6d3b\u6027\u5f88\u9ad8\uff0c\u901a\u5e38\u4e0d\u5e94\u4f20\u8d70\u3002':'Jokers are highly flexible and usually worth keeping.';if(same>1)return language==='zh'?`\u8fd9\u662f ${same} \u5f20\u76f8\u540c\u724c\u7684\u4e00\u90e8\u5206\uff0c\u62c6\u5f00\u4f1a\u635f\u5931\u7ec4\u5408\u3002`:`Part of ${same} matching tiles; passing it breaks a useful group.`;if(['dot','bam','crak'].includes(t.s)&&near>=3)return language==='zh'?'\u5b83\u4e0e\u9644\u8fd1\u6570\u5b57\u6709\u8054\u7cfb\uff0c\u53ef\u652f\u6301\u8fde\u7eed\u7ed3\u6784\u3002':'It connects with nearby numbers and supports flexible runs.';if(['dot','bam','crak'].includes(t.s)&&suitCount>=5)return language==='zh'?'\u5b83\u5c5e\u4e8e\u5f53\u524d\u6570\u91cf\u6700\u591a\u7684\u82b1\u8272\uff0c\u4ecd\u6709\u6f5c\u5728\u4ef7\u503c\u3002':'It belongs to a strong suit and may still be useful.';return language==='zh'?'\u76ee\u524d\u4e0e\u5176\u4ed6\u724c\u8054\u7cfb\u8f83\u5f31\uff0c\u662f\u8f83\u5408\u7406\u7684\u4f20\u724c\u5019\u9009\u3002':'It has few current connections, making it a reasonable pass candidate.'}\nfunction renderReasons(){const box=document.querySelector('#selectionReasons'),chosen=hands[0].filter(t=>selected.has(t.id));box.innerHTML=chosen.map(t=>`<span><strong>${tileName(t)}<\/strong> \u2014 ${reason(t)}<\/span>`).join('')}\nfunction render(){orderRack(hands[0]);rackEl.innerHTML='';hands[0].forEach(t=>{const b=document.createElement('button');b.type='button';b.className=`tile ${t.s}${selected.has(t.id)?' selected':''}`;b.setAttribute('aria-pressed',selected.has(t.id));b.setAttribute('aria-label',tileName(t));b.innerHTML=`<span class=\"symbol\">${t.s==='dot'?t.n+'\u25cf':t.s==='bam'?t.n+'\u25a5':t.s==='crak'?t.n+'\u842c':t.mark}<\/span><small>${tileName(t)}<\/small>`;b.onclick=()=>toggle(t.id);rackEl.appendChild(b)});selectedCount.textContent=round<3?`${selected.size} of 3`:(language==='zh'?'\u4e09\u8f6e\u4f20\u724c\u5b8c\u6210':'3 passes complete');passButton.disabled=round<3?selected.size!==3:false;roundLabel.textContent=round<3?`${round+1} \/ 3`:(language==='zh'?'\u5b8c\u6210':'Done');scoreLabel.textContent=score;document.querySelector('#directionLabel').textContent=round<3?`${language==='zh'?directionZh[round]:directions[round]} \u00b7 ${copy[language].select}`:copy[language].complete;renderReasons()}\nfunction toggle(id){if(round>=3)return;if(selected.has(id))selected.delete(id);else if(selected.size<3)selected.add(id);render()}\nfunction beep(f=520,d=.08){if(!sound)return;try{const a=new AudioContext(),o=a.createOscillator(),g=a.createGain();o.frequency.value=f;g.gain.value=.04;o.connect(g);g.connect(a.destination);o.start();g.gain.exponentialRampToValueAtTime(.001,a.currentTime+d);o.stop(a.currentTime+d)}catch{}}\nfunction rotatePasses(choices){const offset=[1,2,3][round],chosenIds=new Set(choices.flat().map(c=>c.id)),next=hands.map(r=>r.filter(t=>!chosenIds.has(t.id)));for(let from=0;from<4;from++)next[(from+offset)%4].push(...choices[from]);hands=next}\nfunction passTiles(){const chosen=hands[0].filter(t=>selected.has(t.id)),recommended=bestPass(),bestIds=new Set(recommended.map(t=>t.id)),matches=chosen.filter(t=>bestIds.has(t.id)).length,mode=document.querySelector('#difficulty').value,points=Math.min(100,(matches===3?100:matches===2?75:matches===1?45:20)+(mode==='hard'?5:0));score+=points;const brokePair=chosen.some(t=>hands[0].filter(x=>x.s===t.s&&x.n===t.n).length>1),text=matches===3?copy[language].excellent:matches===2?copy[language].strong:copy[language].weak;history.push({round:round+1,points,matches,brokePair,passed:chosen.map(tileName)});coach.innerHTML=`<span class=\"coach-icon\">${matches===3?'\u2713':'\u25ce'}<\/span><\/p>\n<p><strong>+${points} points.<\/strong> ${text}${brokePair?copy[language].pair:''}<\/p>\n<p>`;rotatePasses([chosen,...hands.slice(1).map(computerChoice)]);selected.clear();round++;beep(matches===3?720:480);if(round===3)finish();else passButton.textContent='Pass selected tiles \u2192';render()}\nfunction finish(){const best=Number(localStorage.getItem('mrsfa-charleston-best')||0);if(score>best)localStorage.setItem('mrsfa-charleston-best',score);bestLabel.textContent=Math.max(score,best);passButton.textContent=copy[language].another;passButton.onclick=newGame;resultCard.hidden=false;document.querySelector('#resultScore').textContent=score;document.querySelector('#resultGrade').textContent=score>=270?'A':score>=210?'B':score>=150?'C':'D';document.querySelector('#resultDetails').innerHTML=history.map(h=>`<\/p>\n<article><strong>Round ${h.round}: +${h.points}<\/strong><span>${h.matches}\/3 recommended choices<\/span><small>Passed: ${h.passed.join(', ')}<\/small><\/article>\n<p>`).join('');const matched=history.reduce((n,h)=>n+h.matches,0),pairBreaks=history.filter(h=>h.brokePair).length;document.querySelector('#resultTip').textContent=language==='zh'?`\u603b\u7ed3\uff1a\u4f60\u6709 ${matched} \u5f20\u724c\u7b26\u5408\u5efa\u8bae\uff0c\u62c6\u5f00\u5bf9\u5b50 ${pairBreaks} \u6b21\u3002\u4e0b\u5c40\u5c3d\u91cf\u4fdd\u7559\u5bf9\u5b50\u548c\u591a\u7528\u9014\u724c\u3002`:`Summary: ${matched} of your choices matched the recommendation and you broke ${pairBreaks} pair${pairBreaks===1?'':'s'}. Next game, protect pairs and multi-purpose tiles.`;resultCard.scrollIntoView({behavior:'smooth',block:'nearest'})}\nfunction applyLanguage(){const t=ui[language];document.documentElement.lang=language==='zh'?'zh-Hans':'en';document.querySelector('#heroEyebrow').textContent=t.eyebrow;document.querySelector('#heroTitle').textContent=t.title;document.querySelector('#heroDescription').textContent=t.description;document.querySelector('#roundText').textContent=t.round;document.querySelector('#scoreText').textContent=t.score;document.querySelector('#bestText').textContent=t.best;document.querySelector('#gameHeading').textContent=t.heading;document.querySelector('#levelText').textContent=t.level;document.querySelector('#selectedText').textContent=t.selected;document.querySelector('#privacyTitle').textContent=t.privacyTitle;document.querySelector('#privacyText').textContent=t.privacy;const options=document.querySelector('#difficulty').options;options[0].text=t.easy;options[1].text=t.normal;options[2].text=t.hard;if(round<3)passButton.textContent=t.pass;document.querySelector('#languageButton').textContent=language==='en'?'\u4e2d':'EN';coach.innerHTML=`<span class=\"coach-icon\">\u25ce<\/span><\/p>\n<p><strong>Coach:<\/strong> ${copy[language].coach}<\/p>\n<p>`;render()}\nfunction newGame(){const deck=pool();hands=[deck.splice(0,14),deck.splice(0,14),deck.splice(0,14),deck.splice(0,14)];selected.clear();round=0;score=0;history=[];passButton.textContent=ui[language].pass;passButton.onclick=passTiles;coach.innerHTML=`<span class=\"coach-icon\">\u25ce<\/span><\/p>\n<p><strong>Coach:<\/strong> ${copy[language].coach}<\/p>\n<p>`;resultCard.hidden=true;render()}\nlet onboardingIndex=0;const onboarding=document.querySelector('#onboarding');function showOnboarding(){const s=onboardingSteps[language][onboardingIndex];document.querySelector('#onboardingNumber').textContent=`${onboardingIndex+1} \/ 3`;document.querySelector('#onboardingTitle').textContent=s[0];document.querySelector('#onboardingBody').textContent=s[1];document.querySelector('#onboardingVisual').textContent=s[2];document.querySelector('#onboardingNext').innerHTML=onboardingIndex===2?(language==='zh'?'\u5f00\u59cb\u7ec3\u4e60':'Start practice'):`${language==='zh'?'\u4e0b\u4e00\u6b65':'Next'} <span>\u2192<\/span>`;document.querySelector('#onboardingSkip').textContent=language==='zh'?'\u8df3\u8fc7\u4ecb\u7ecd':'Skip introduction';onboarding.hidden=false}function closeOnboarding(){onboarding.hidden=true;localStorage.setItem('mrsfa-charleston-intro','seen')}document.querySelector('#onboardingNext').onclick=()=>{if(onboardingIndex<2){onboardingIndex++;showOnboarding()}else closeOnboarding()};document.querySelector('#onboardingSkip').onclick=closeOnboarding;\npassButton.onclick=passTiles;document.querySelector('#newGameButton').onclick=newGame;document.querySelector('#difficulty').onchange=newGame;document.querySelector('#soundButton').onclick=e=>{sound=!sound;e.currentTarget.textContent=sound?'\u266a':'\u00d7';e.currentTarget.setAttribute('aria-pressed',sound);if(sound)beep()};document.querySelector('#languageButton').onclick=()=>{language=language==='en'?'zh':'en';applyLanguage();if(!onboarding.hidden)showOnboarding()};newGame();applyLanguage();if(!localStorage.getItem('mrsfa-charleston-intro'))showOnboarding();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Practice the American Mahjong Charleston online for free. Choose three tiles, receive instant feedback, and build better beginner habits.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-102","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Free American Mahjong Charleston Trainer for Beginners - mahjong tiles online,free majong,Mahjong Strategy Guide<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.mrsfa.com\/index.php\/american-mahjong-trainer\/\" \/>\n<meta property=\"og:locale\" content=\"zh_CN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Free American Mahjong Charleston Trainer for Beginners - mahjong tiles online,free majong,Mahjong Strategy Guide\" \/>\n<meta property=\"og:description\" content=\"Practice the American Mahjong Charleston online for free. Choose three tiles, receive instant feedback, and build better beginner habits.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.mrsfa.com\/index.php\/american-mahjong-trainer\/\" \/>\n<meta property=\"og:site_name\" content=\"mahjong tiles online,free majong,Mahjong Strategy Guide\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4\" \/>\n\t<meta name=\"twitter:data1\" content=\"2 \u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.mrsfa.com\\\/index.php\\\/american-mahjong-trainer\\\/\",\"url\":\"https:\\\/\\\/www.mrsfa.com\\\/index.php\\\/american-mahjong-trainer\\\/\",\"name\":\"Free American Mahjong Charleston Trainer for Beginners - mahjong tiles online,free majong,Mahjong Strategy Guide\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.mrsfa.com\\\/#website\"},\"datePublished\":\"2026-08-21T08:40:41+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.mrsfa.com\\\/index.php\\\/american-mahjong-trainer\\\/#breadcrumb\"},\"inLanguage\":\"zh-Hans\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.mrsfa.com\\\/index.php\\\/american-mahjong-trainer\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.mrsfa.com\\\/index.php\\\/american-mahjong-trainer\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"\u9996\u9875\",\"item\":\"https:\\\/\\\/www.mrsfa.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Free American Mahjong Charleston Trainer for Beginners\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.mrsfa.com\\\/#website\",\"url\":\"https:\\\/\\\/www.mrsfa.com\\\/\",\"name\":\"mahjong tiles online,free majong,Mahjong Strategy Guide\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.mrsfa.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"zh-Hans\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Free American Mahjong Charleston Trainer for Beginners - mahjong tiles online,free majong,Mahjong Strategy Guide","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.mrsfa.com\/index.php\/american-mahjong-trainer\/","og_locale":"zh_CN","og_type":"article","og_title":"Free American Mahjong Charleston Trainer for Beginners - mahjong tiles online,free majong,Mahjong Strategy Guide","og_description":"Practice the American Mahjong Charleston online for free. Choose three tiles, receive instant feedback, and build better beginner habits.","og_url":"https:\/\/www.mrsfa.com\/index.php\/american-mahjong-trainer\/","og_site_name":"mahjong tiles online,free majong,Mahjong Strategy Guide","twitter_card":"summary_large_image","twitter_misc":{"\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4":"2 \u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.mrsfa.com\/index.php\/american-mahjong-trainer\/","url":"https:\/\/www.mrsfa.com\/index.php\/american-mahjong-trainer\/","name":"Free American Mahjong Charleston Trainer for Beginners - mahjong tiles online,free majong,Mahjong Strategy Guide","isPartOf":{"@id":"https:\/\/www.mrsfa.com\/#website"},"datePublished":"2026-08-21T08:40:41+00:00","breadcrumb":{"@id":"https:\/\/www.mrsfa.com\/index.php\/american-mahjong-trainer\/#breadcrumb"},"inLanguage":"zh-Hans","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.mrsfa.com\/index.php\/american-mahjong-trainer\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.mrsfa.com\/index.php\/american-mahjong-trainer\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"\u9996\u9875","item":"https:\/\/www.mrsfa.com\/"},{"@type":"ListItem","position":2,"name":"Free American Mahjong Charleston Trainer for Beginners"}]},{"@type":"WebSite","@id":"https:\/\/www.mrsfa.com\/#website","url":"https:\/\/www.mrsfa.com\/","name":"mahjong tiles online,free majong,Mahjong Strategy Guide","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.mrsfa.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"zh-Hans"}]}},"_links":{"self":[{"href":"https:\/\/www.mrsfa.com\/index.php\/wp-json\/wp\/v2\/pages\/102","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mrsfa.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.mrsfa.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.mrsfa.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mrsfa.com\/index.php\/wp-json\/wp\/v2\/comments?post=102"}],"version-history":[{"count":4,"href":"https:\/\/www.mrsfa.com\/index.php\/wp-json\/wp\/v2\/pages\/102\/revisions"}],"predecessor-version":[{"id":107,"href":"https:\/\/www.mrsfa.com\/index.php\/wp-json\/wp\/v2\/pages\/102\/revisions\/107"}],"wp:attachment":[{"href":"https:\/\/www.mrsfa.com\/index.php\/wp-json\/wp\/v2\/media?parent=102"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}