Skip to content

Instantly share code, notes, and snippets.

@think49
Last active February 2, 2019 06:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save think49/2a30b4e865f3dca4043440fb9b99a448 to your computer and use it in GitHub Desktop.
Save think49/2a30b4e865f3dca4043440fb9b99a448 to your computer and use it in GitHub Desktop.
create-square-aa.js: 四角形のASCII Artを生成する
/**
* create-square-aa-1.0.1.js
* create ASCII art square.
*
* @version 1.0.1
* @author think49
* @url https://gist.github.com/think49/2a30b4e865f3dca4043440fb9b99a448
* @license http://www.opensource.org/licenses/mit-license.php (The MIT License)
*/
'use strict';
var createSquareAa = (function (_min) {
return function createSquareAa (width, height, x, y, radius) {
var min = _min, canvas ='', whiteMark = '〇', blackMark = '◎', widthPlus, currentWidth, remainingHeight, whiteLine, leftWhiteLine, whiteWidth, whiteHeight, blackLine, blackSideLine, blackInnerWidth, blackInnerHeight;
width = +width || 0;
height = +height || 0;
x = +x || 0;
y = +y || 0;
radius = +radius || 0;
widthPlus = width + 1;
whiteLine = '\n'.padStart(widthPlus, whiteMark);
whiteWidth = x - radius;
whiteHeight = y - radius;
if (whiteWidth >= width || whiteHeight >= height) {
return ''.padEnd(widthPlus * height, whiteLine);
}
canvas = ''.padEnd(widthPlus * whiteHeight, whiteLine);
remainingHeight = height - (whiteHeight > 0 ? whiteHeight : 0);
blackInnerWidth = radius * 2 - 1;
if (whiteHeight >= 0) {
leftWhiteLine = ''.padEnd(whiteWidth, whiteMark);
blackLine = leftWhiteLine.padEnd(min(whiteWidth + blackInnerWidth + 2, width), blackMark).padEnd(width, whiteMark) + '\n';
canvas += blackLine;
if (! --remainingHeight) {
return canvas;
}
}
if (radius > 0) {
blackInnerHeight = min(blackInnerWidth, whiteHeight + blackInnerWidth + 1, remainingHeight);
if (blackInnerHeight > 0) {
// console.log(blackInnerWidth, blackInnerHeight)
leftWhiteLine = leftWhiteLine || ''.padEnd(whiteWidth, whiteMark);
currentWidth = whiteWidth + 1;
blackSideLine = leftWhiteLine.padEnd(min(currentWidth, width), blackMark).padEnd(min(currentWidth += blackInnerHeight, width), whiteMark).padEnd(min(++currentWidth, width), blackMark).padEnd(width, whiteMark) + '\n';
remainingHeight -= blackInnerHeight;
canvas += blackSideLine.padEnd(widthPlus * blackInnerHeight, blackSideLine);
if (!remainingHeight) {
return canvas;
}
}
if (blackInnerHeight >= 0) {
canvas += blackLine || (leftWhiteLine || ''.padEnd(whiteWidth, whiteMark)).padEnd(min(whiteWidth + blackInnerWidth + 2, width), blackMark).padEnd(width, whiteMark) + '\n';
}
if (!--remainingHeight) {
return canvas;
}
}
return canvas.padEnd(widthPlus * height, whiteLine);
};
}(Math.min));
<!DOCTYPE html>
<head>
<meta charset="UTF-8" />
<title>test - create-square-aa.js</title>
<style>
pre {
color: black;
background-color: #eee;
font-size: 50px;
font-family: monospace;
}
</style>
</head>
<body>
<pre id="canvas"></pre>
<script src="create-square-aa-1.0.1.js"></script>
<script>
'use strict';
function appendTextNode (element, string) {
var doc = element.ownerDocument;
element.appendChild(doc.createTextNode(string + '\n\n'));
}
function main () {
var canvas = this.document.getElementById('canvas')
console.assert(createSquareAa(5, 5, 2, 2, 0) === '〇〇〇〇〇\n〇〇〇〇〇\n〇〇◎〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n'); // 5x5 中央位置(半径0)
console.assert(createSquareAa(5, 5, 2, 2, 1) === '〇〇〇〇〇\n〇◎◎◎〇\n〇◎〇◎〇\n〇◎◎◎〇\n〇〇〇〇〇\n'); // 5x5 中央位置(半径1)
console.assert(createSquareAa(5, 5, 2, 1, 1) === '〇◎◎◎〇\n〇◎〇◎〇\n〇◎◎◎〇\n〇〇〇〇〇\n〇〇〇〇〇\n'); // 5x5 上にシフトする(半径1)
console.assert(createSquareAa(5, 5, 2, 0, 1) === '〇◎〇◎〇\n〇◎◎◎〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n');
console.assert(createSquareAa(5, 5, 2, -1, 1) === '〇◎◎◎〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n');
console.assert(createSquareAa(5, 5, 2, -2, 1) === '〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n');
console.assert(createSquareAa(5, 5, 3, 2, 1) === '〇〇〇〇〇\n〇〇◎◎◎\n〇〇◎〇◎\n〇〇◎◎◎\n〇〇〇〇〇\n'); // 5x5 右にシフトする(半径1)
console.assert(createSquareAa(5, 5, 4, 2, 1) === '〇〇〇〇〇\n〇〇〇◎◎\n〇〇〇◎〇\n〇〇〇◎◎\n〇〇〇〇〇\n');
console.assert(createSquareAa(5, 5, 5, 2, 1) === '〇〇〇〇〇\n〇〇〇〇◎\n〇〇〇〇◎\n〇〇〇〇◎\n〇〇〇〇〇\n');
console.assert(createSquareAa(5, 5, 6, 2, 1) === '〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n');
console.assert(createSquareAa(5, 5, 1, 2, 1) === '〇〇〇〇〇\n◎◎◎〇〇\n◎〇◎〇〇\n◎◎◎〇〇\n〇〇〇〇〇\n'); // 5x5 左にシフトする(半径1)
console.assert(createSquareAa(5, 5, 0, 2, 1) === '〇〇〇〇〇\n◎◎〇〇〇\n〇◎〇〇〇\n◎◎〇〇〇\n〇〇〇〇〇\n');
console.assert(createSquareAa(5, 5, -1, 2, 1) === '〇〇〇〇〇\n◎〇〇〇〇\n◎〇〇〇〇\n◎〇〇〇〇\n〇〇〇〇〇\n');
console.assert(createSquareAa(5, 5, -2, 2, 1) === '〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n');
console.assert(createSquareAa(5, 5, 2, 3, 1) === '〇〇〇〇〇\n〇〇〇〇〇\n〇◎◎◎〇\n〇◎〇◎〇\n〇◎◎◎〇\n'); // 5x5 下にシフトする(半径1)
console.assert(createSquareAa(5, 5, 2, 4, 1) === '〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇◎◎◎〇\n〇◎〇◎〇\n');
console.assert(createSquareAa(5, 5, 2, 5, 1) === '〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇◎◎◎〇\n');
console.assert(createSquareAa(5, 5, 2, 6, 1) === '〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n');
console.assert(createSquareAa(5, 5, 2, 2, 2) === '◎◎◎◎◎\n◎〇〇〇◎\n◎〇〇〇◎\n◎〇〇〇◎\n◎◎◎◎◎\n'); // 5x5 中央位置(半径2)
console.assert(createSquareAa(5, 5, 2, 2, 3) === '〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n〇〇〇〇〇\n'); // 5x5 中央位置(半径3)
appendTextNode(canvas, createSquareAa(5, 5, 2, 2, 0)); // 5x5 中央位置(半径0)
appendTextNode(canvas, createSquareAa(5, 5, 2, 2, 1)); // 5x5 中央位置(半径1)
appendTextNode(canvas, createSquareAa(5, 5, 2, 1, 1)); // 5x5 上にシフトする(半径1)
appendTextNode(canvas, createSquareAa(5, 5, 2, 0, 1));
appendTextNode(canvas, createSquareAa(5, 5, 2, -1, 1));
appendTextNode(canvas, createSquareAa(5, 5, 2, -2, 1));
appendTextNode(canvas, createSquareAa(5, 5, 3, 2, 1)); // 5x5 右にシフトする(半径1)
appendTextNode(canvas, createSquareAa(5, 5, 4, 2, 1));
appendTextNode(canvas, createSquareAa(5, 5, 5, 2, 1));
appendTextNode(canvas, createSquareAa(5, 5, 6, 2, 1));
appendTextNode(canvas, createSquareAa(5, 5, 1, 2, 1)); // 5x5 左にシフトする(半径1)
appendTextNode(canvas, createSquareAa(5, 5, 0, 2, 1));
appendTextNode(canvas, createSquareAa(5, 5, -1, 2, 1));
appendTextNode(canvas, createSquareAa(5, 5, -2, 2, 1));
appendTextNode(canvas, createSquareAa(5, 5, 2, 3, 1)); // 5x5 下にシフトする(半径1)
appendTextNode(canvas, createSquareAa(5, 5, 2, 4, 1));
appendTextNode(canvas, createSquareAa(5, 5, 2, 5, 1));
appendTextNode(canvas, createSquareAa(5, 5, 2, 6, 1));
appendTextNode(canvas, createSquareAa(5, 5, 2, 2, 2)); // 5x5 中央位置(半径2)
appendTextNode(canvas, createSquareAa(5, 5, 2, 2, 3)); // 5x5 中央位置(半径3)
}
main.call(this);
</script>
</body>
</html>
@think49
Copy link
Author

think49 commented Sep 19, 2017

teratail

teratailの下記質問の要件を元にコードを書きました。

Polyfill

本コードでは、ES2017 規定の String.prototype.padStart, String.prototype.padEnd を利用しており、未対応ブラウザの為にPolyfillが必要となります。

ベンチマーク

「キャンバスサイズの最大値: 1010 (※1)」「繰り返し回数: 1000回」でベンチマークをとってみました。

回数 think49 Lhankor_Mhy(初版) te2ji(type1 初版) raccy
1回目 10.128173828125ms 39301.115966796875ms 測定不能(エラー) 125472.5986328125ms
2回目 1.7138671875ms 36288.373779296875ms 測定不能(エラー) 124575.38696289062ms
3回目 1.626953125ms 35011.963623046875ms 測定不能(エラー) 125737.03271484375ms
4回目 2.990966796875ms 36570.126953125ms 測定不能(エラー) 131851.31713867188ms
5回目 1.56005859375ms 39585.26806640625ms 測定不能(エラー) 128274.21826171875ms

Lhankor_Mhy(初版), te2ji(type1 初版) に手を加えたコードの結果がこちら。

回数 Lhankor_Mhy(初版) Lhankor_Mhy(改訂版1) Lhankor_Mhy(改訂版2) Lhankor_Mhy(改訂版3) te2ji(type1 改訂版1)
1回目 39301.115966796875ms 12114.286865234375ms 12167.263916015625ms 13070.504150390625ms 17185.240966796875ms
2回目 36288.373779296875ms 12250.916015625ms 12209.571044921875ms 13132.1572265625ms 16331.541259765625ms
3回目 35011.963623046875ms 12381.442138671875ms 12042.466064453125ms 13132.1572265625ms 17234.682861328125ms
4回目 36570.126953125ms 12274.921142578125ms 12375.59814453125ms 12552.7861328125ms 131851.31713867188ms
5回目 39585.26806640625ms 12051.870849609375ms 12160.140869140625ms 13023.833984375ms 17187.80712890625ms

次の環境で実行しています。

名前
OS Windows 10 Home 64bit
Browser Google Chrome 60.0.3112.113

(※1) テキストボックス入力値は「1000」ですが、関数 benchmark の処理で +10 しています。0x0のキャンバスでは有効値が取れないと思われる為の措置です。
(※2) ベンチマーク処理の都合上、引数の順番等の処理を一部変更しています。特に、raccyさんのコードは設計思想が大きく異なり、rect サイズを指定する為に追加処理を入れています。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment