カストロイデスのページ
🦖
🦕
🦖
🦕
🦖
🦕
🦖
🦕
🦖
🦕

【Windows】仕事してる風に見えるbat処理考えてみた


会社でちょっとサボタージュするときに仕事してる感を出したくて作ってみました。
コマンドライン上で以下のように動きます。

www.youtube.com


コード全体

とりあえず以下が今回作ったコードの全体像です。

@echo off

echo --------------------------------------------------------
echo Run Start: %date% %time%
echo;

rem 遅延環境変数の展開をOKにするおまじない
SETLOCAL ENABLEDELAYEDEXPANSION

rem 変数初期化
set RNG=0
set wt=0

for /l %%c in (1, 1, 10) do (

    if %%c neq 1 (
        set /p prefix="Next process...["< nul
    ) else (
        set /p prefix="Process start...["< nul
    )
    
    for /l %%n in (1, 1, 30) do (
        set /p p_var="#"< nul

        rem 3桁の乱数作成
        set /a RNG=!RANDOM! %% 1000

        rem 生成した乱数が900以上なら
        if !RNG! geq 900 (
            set /a wt=!RANDOM! %% 10
            timeout /t !wt! > nul
        ) else (
            timeout /t 0 > nul
        )
    )
    set /p suffix="]"< nul
    echo;
    echo;
)

echo;
echo The program finished successfully.
echo End Time: %date% %time%
echo --------------------------------------------------------


@echo off について

@echo off

echo --------------------------------------------------------
echo Run Start: %date% %time%
echo;


まず、冒頭の@echo offは、コマンドラインを見やすくするためのコマンドです。
これを書くことでecho毎の冗長出力を阻止しています。

詳細は以下のサイトを確認ください。
バッチファイルによく出てくる@echo offの意味 #Windows - Qiita


遅延環境変数の展開について

rem 遅延環境変数の展開をOKにするおまじない
SETLOCAL ENABLEDELAYEDEXPANSION


SETLOCAL ENABLEDELAYEDEXPANSIONは、遅延環境変数展開のためのおまじないです。
遅延環境変数展開って字面が難しそうに見えますね。
雑にいうと、batファイルはコードの読み込み時に変数の中身を固定してしまうので、読み込んだ後の値の更新も展開してくれってこの部分でお願いしてます。

以下のサイトがすごくわかりやすいです。
遅延環境変数とは|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典


使用変数の解説

本コードでは5つの変数をはじめに初期化してます。
それぞれ役割をメモ程度に書いときます。

rem 変数初期化
set RNG=0 生成した三桁の乱数を保持する
set wt=0 待ち時間を保持する


メイン処理

このbatファイルのメイン部分は以下の繰り返し処理です。

for /l %%c in (1, 1, 10) do (

    if %%c neq 1 (
        set /p prefix="Next process...["< nul
    ) else (
        set /p prefix="Process start...["< nul
    )
    
    for /l %%n in (1, 1, 30) do (
        set /p p_var="#"< nul

        rem 3桁の乱数作成
        set /a RNG=!RANDOM! %% 1000

        rem 生成した乱数が900以上なら
        if !RNG! geq 900 (
            set /a wt=!RANDOM! %% 10
            timeout /t !wt! > nul
        ) else (
            timeout /t 0 > nul
        )
    )
    set /p suffix="]"< nul
    echo;
    echo;
)


改行なしで出力するためにset /pを使う

batファイルはechoで出力する毎に改行が入ってしまうので、プログレスバーを再現するためにset /pを使ってます。
set /pのように/pオプションを使うことで、ユーザの入力を促すことができます。
本来はprefixという変数に代入する値をユーザに入力させる効果があるのですが、set /p 変数名="値"< nulとすることで値を代入&改行なしで出力しています。


待機時間の生成

以下の処理では、PCに何かしら処理をさせている感を出すために乱数を生成して、次の「#」出力までの待機時間を演出しています。

rem 3桁の乱数作成
set /a RNG=!RANDOM! %% 1000

rem 生成した乱数が900以上なら
if !RNG! geq 900 (
     set /a wt=!RANDOM! %% 10
     timeout /t !wt! > nul
) else (
      timeout /t 0 > nul
)


batファイルでは「ミリ秒待機」が使えない

なんで乱数の生成をこんなにもややこしくしてるか、ちゃんとこだわりあります。
まず、batファイルではtimeout /t 待機時間(秒)> nulでプログラムの実行を待機させることができます。しかしミリ秒が扱えないようです。

ミリ秒が扱えないということは、例えば「待機時間を毎回0~9の中から無作為に選ぶ」としたとき、プログレスバー(もどき)の進行は0を引かない限り毎度毎度止まります。
通常待機0秒で進行し、たまに数秒待たされるプログレスバーを再現するために試行錯誤した結果がこのbatファイルです。
rem powershell -Command "sleep -m !wt!"ように、powershell側でミリ秒 sleep(待機)させるのもアリ。


乱数生成

上記理由があるため、0~999までの範囲で乱数を生成して、その乱数が900より大きい場合は1~9秒待機という方法を取っています。こうすることで10回に1回程度、プログレスバーの進行を待機させています。
set /a/aは、set /a 変数名=計算式のように右辺計算式の結果を変数名に代入させるオプションです。

rem 3桁の乱数作成
set /a RNG=!RANDOM! %% 1000

RANDOMで0~32,767(15bit?)までの乱数を生成できます。
普通batファイルで変数を扱うときは%RANDOM%のように「%」で変数名を囲うのですが、「!」で囲っているのは上述した遅延環境変数展開のためです。
また!RANDOM! %% 1000のように、生成した乱数を1,000で割ったときの余りを出してます。こうすることで0~999までの乱数に整えています。
※batでは%%で余剰をだせる。


ループ処理について

このbatファイルでは繰り返し処理(for文)を入れ子にしています。

for /l %%c in (1, 1, 10) do (
    外側処理
    for /l %%n in (1, 1, 30) do (
        内側処理
    )
)

構造としては以下のようになっています。
「#」出力を30回実行したら次のプログレスバー出力に移行し、これを10回ループしています。


batファイル結構楽しい

こんな感じでbatファイル作っといて、コーヒー買いに行くときとかに実行しとけば「PCに仕事させてて終わるの待ってんのかな」って上司に思わせることができそうです。

batファイルで遊ぶの、結構楽しくてハマりそう。


ブラウザ上でも動くようにJavascriptでも作ってみました。
デスクトップなら綺麗に動くはず。(スマホだと描画位置がズレます)
https://castoroides.github.io/others/MimicryWorker.html

以下、実行画面。

www.youtube.com

NoxPlayerでアビスリウムのイベントアイテム回収を自動化してみた

最近、アビスリウムにハマりました。

スマホゲームです。

apps.apple.com

「アビスリウム – タップで育つ水族館」は、忙しい日常で疲れたあなたを癒す放置型癒し系ゲームです。癒しが必要な可愛い魚たちを深海のアクアリウムに招き、癒されながら成長の喜びを味わうことができます。"静かな水族館を賑やかにし、干からびた日常に癒しを与え、水族館を成長させながらたくさんの可愛い魚たちに出会える、放置型癒し系ゲーム「アビスリウム」をあなたにおすすめします。"


雑に言うと、タップしまくって水族館を成長させるゲームです。


このゲーム、イベント時はタップするのがめんどくさいです。なのでNoxplayerを使ってタップを自動化したいと思います。
※イベント時:2秒に1回程度 魚がアイテムを吐くので、それをタップして回収しなければならない。

NoxPlayer

NoxPlayerはAndroid アプリを PC で動かすための無料ソフトウェアです。
jp.bignox.com

PCに接続しているキーボードやマウスが利用できるので、ゲームによっては快適にプレイできます。

NoxPlayerはマクロを組むことができます。つまり単純操作の自動化が可能になっています。
ちなみに、「スクリプト」という機能でExcelのマクロのように操作を記録することもできます。(中華ゲームとかでやるとチート扱いされてBANされるかもです)


NoxPlayerのマクロによるタップ自動化

仮想キーの作成

まず、Noxplayerでアビスリウムを開きます。

右上に「仮想キーの設定」があるのでこちらをマウスでクリックします。

「マクロ」をクリックします。

ここで作成された円をクリックすることでマクロが起動します。そのため、画面の端っこに置いておくのが良いです。

円をクリックしなくてもマクロを実行させるショートカットキーを設定できます。今回はCtrl+Aに設定してみました。


マクロの設定

ショートカットを設定した後は右下の鉛筆マークをクリックしてのエディターを開きます。

マクロエディターでは、例えばクリック操作をさせたい場合はクリックの X か Y どちらかのテキストボックスをアクティブにした状態で、実際にゲーム画面をクリックすることで該当の座標が入力されます。その状態で以下画像右の「+」ボタンを押すとマクロキーエディットにコードが追加されます。

色んなことができそうなパーツが揃っています。(今回は「クリック」と「ループ」以外は使いませんが)

要するに、今回組んだのはイベントアイテムやその他時間経過により出現するアイテムが取得できるよう「画面全体をまんべんなくタップさせる」というマクロです。

以下、コードの全容です。

loop 1000000

click 50 200
click 100 200
click 150 200
click 200 200
click 250 200
click 300 200
click 350 200
click 400 200
click 450 200
click 500 200

click 50 300
click 100 300
click 150 300
click 200 300
click 250 300
click 300 300
click 350 300
click 400 300
click 450 300
click 460 320
click 500 300

click 50 400
click 100 400
click 150 400
click 200 400
click 250 400
click 300 400
click 350 400
click 400 400
click 450 400
click 500 400

click 50 500
click 100 500
click 150 500
click 200 500


click 350 500
click 400 500
click 450 500
click 500 500

click 50 600
click 100 600
click 150 600
click 200 600
click 250 600
click 300 600
click 350 600
click 400 600
click 450 600
click 500 600

click 190 800


無限ループのやり方がわからなかったので、力技です。
loop 1000000で、それより以下の処理を1,000,000回ループさせています。

画面の左上から右下までをざっと散らしてタップさせています。
ところどころ虫食い状態になっているのは、動画視聴の宝箱等を避けるためです。降りてくる最中のものはクリックしちゃいますが許容です。

最後のclick 190 800は、動画視聴の宝箱をクリックしてしまったときに「取り消し」を選択できるように加えています。


動かしてみた

動かしてみるとこんな感じです。

youtu.be



タップゲーを自動化するとつまらなくなりました。

フリーセルクリア後のシャーッてなるやつ作ってみた

懐かしのフリーセルについて

子供のころ、PCのフリーセルピンボールが大好きでした。
フリーセルは最後にシャーッてなるのがいいんですよね。さて、あれをJavascriptで再現してみようと思います。


ちなみに昔と違って、今のWindowsはストアからフリーセルをインストールする必要があるみたいです。
www.microsoft.com


今でもシャーやってくれるみたいです。


と、思ったら別のアニメーションも用意されてました。


このアニメーションをJSで組んでみる



2日後

アニメーションこだわり過ぎて2日掛かってました。
作ったスクリプト全体は以下の通りです。

コード全体

<canvas id="canvas"></canvas>

<style>
#canvas{
	width: 100%;
	height: 90vh;
}
</style>

<script>
// 画像読み込み
let imageWidth = 409
let imageHeight = 600
data = new Array(
	"https://3.bp.blogspot.com/-x1YD4kp-X9E/WQBAA3RKDbI/AAAAAAABD9M/5K8vEH6kYSo5M9r2jzxheGlnup2k-El5gCLcB/s800/card_heart_02.png",
	"https://2.bp.blogspot.com/-S-31SRfkS1o/WQBAEtCo1nI/AAAAAAABD98/fzjjCIIibhMkeoKx9NfyTo3i1TjRaONPQCLcB/s800/card_spade_01.png",
	"https://4.bp.blogspot.com/-hIKME4x_kbQ/WQA_3IHzulI/AAAAAAABD7o/Ft4JOq2ydaEHteja59Zzv_i3ieXnmONwwCLcB/s800/card_club_03.png",
	"https://4.bp.blogspot.com/-WNnDDDnVkrs/WQA_9vUTTJI/AAAAAAABD8g/PSyYSizOnVkaC37L7bLn82Ex83Tvm0BKACLcB/s800/card_diamond_04.png",
	"https://4.bp.blogspot.com/-bvSGYORb6Xg/WQBAF61kUOI/AAAAAAABD-Q/SalVkKKYYt85TNJJsOjmgNwfT0ao3foewCLcB/s800/card_spade_05.png",
	"https://3.bp.blogspot.com/-w5tuOxBszlU/WQBABseF49I/AAAAAAABD9c/9yF8y-6012MKF5UlSz-dxORnZU_YhEuxgCLcB/s800/card_heart_06.png",
	"https://2.bp.blogspot.com/-LXJw0prlZp0/WQA_6wZyEVI/AAAAAAABD74/eFWVHzCtgLMj_C-JPzjOd7YfhiveHytlQCLcB/s800/card_club_07.png",
	"https://1.bp.blogspot.com/-FZGbdtedARU/WQA__nBH5iI/AAAAAAABD84/X9BsjJbBLZcuGBr5VT2EeisGjlp0wtJpwCLcB/s800/card_diamond_08.png",
	"https://1.bp.blogspot.com/-lYcdLoEoqhk/WQBAGkz_02I/AAAAAAABD-Y/BzeTL07VRhc9viqmclMywil_LqOdQGL5QCLcB/s800/card_spade_09.png",
	"https://4.bp.blogspot.com/-Dj2Yzi1XR-E/WQBADWUni-I/AAAAAAABD9s/2Cy3plnNZGwt9sV3vDO4eCvJSSg9DGx-wCLcB/s800/card_heart_10.png"
)
imag= new Array();
for (i=0; i<data.length; i++){
	imag[i] = new Image();
	imag[i].src = data[i];
}

// getContextメソッドで描画機能を有効にする
var canvas = document.querySelector("canvas");
var context = canvas.getContext('2d');

// canvas の幅と高さの指定
var canvas = document.getElementById("canvas");
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;

// トランプのクラス
var Card = function(scale, color, vx, vxs, vy, gv) {
	this.scale = scale; // 縮尺
	this.dstWidth = dstWidth;
	this.dstHeight = dstHeight;
	this.kind = kind; // トランプの種類
	this.vx = vx; // X速度
	this.vxs = vxs; // 退場時の速度
	this.vy = vy; // Y速度
	this.gv = gv; // 重力
	this.position = { // 位置
		x: 0,
		y: 0
	};
};

// 変数宣言
var Cards = []; // トランプをまとめる配列
var kind;
var scale;
var dstWidth;
var dstHeight;
var x;
var xs;
var y;
var g;
var indx;
var startDate = new Date();
var interval = 2000;

// ループ処理
function animloop(){
	
	requestAnimFrame(animloop);
	
	// カードの追加
	if(new Date() - startDate > interval){
		startDate = new Date();
		
		// 詳細値の作成
		//Math.random() * (max - min) + min;
		kind = Math.random() * 10;
		scale = Math.random() * (0.25 - 0.1) + 0.1;
		dstWidth = imageWidth * scale;
		dstHeight = imageHeight * scale;
		x = Math.random() * (10) -5;
		xs = x / 10;
		y = Math.random()* 9 + 4;
		g = Math.random()* 0.2 + 0.3;
		indx = Cards.length;
		
		Cards[indx] = new Card(scale, kind, x, xs, -y, g);
		Cards[indx].position.x = Math.random() * (canvas.width);
		Cards[indx].position.y = 100;
	}
	// カードの更新
	for (var i in Cards) {
		Cards[i].update();
	}
}

// コピペ from https://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
window.requestAnimFrame = (function(){
  return  window.requestAnimationFrame       ||
          window.webkitRequestAnimationFrame ||
          window.mozRequestAnimationFrame    ||
          function( callback ){
            window.setTimeout(callback, 1000 / 60);
          };
})();

// 座標の更新
Card.prototype.update = function() {
	this.vy += this.gv;
	this.position.x += this.vx;
	this.position.y += this.vy;
	
	// 地面の衝突判定
	if (this.position.y > canvas.height - this.dstHeight) {
		this.vy *= -0.8;
		this.vx *= 0.85;
		this.position.y = canvas.height - this.dstHeight;
		if(Math.abs(this.vx) < 0.8){
			this.position.x += this.vxs;
		}
	}
	this.draw();
};

// canvasに描画
Card.prototype.draw = function() {
	context.beginPath();
	context.arc(this.position.x, this.position.y, this.scale, 0, 2*Math.PI, false);
	context.fillStyle = this.color;
	//context.fill();
	console.log(Math.floor(this.kind))
	context.drawImage(imag[Math.floor(this.kind)], this.position.x, this.position.y, this.dstWidth, this.dstHeight);
};

// アニメーションの起点
animloop();

</script>


画像読み込み

まず、冒頭で画像の読み込み等をしてます。(いらすとや からお借りしてます)

// 画像読み込み
let imageWidth = 409
let imageHeight = 600
data = new Array(
	"https://3.bp.blogspot.com/-x1YD4kp-X9E/WQBAA3RKDbI/AAAAAAABD9M/5K8vEH6kYSo5M9r2jzxheGlnup2k-El5gCLcB/s800/card_heart_02.png",
	"https://2.bp.blogspot.com/-S-31SRfkS1o/WQBAEtCo1nI/AAAAAAABD98/fzjjCIIibhMkeoKx9NfyTo3i1TjRaONPQCLcB/s800/card_spade_01.png",
	"https://4.bp.blogspot.com/-hIKME4x_kbQ/WQA_3IHzulI/AAAAAAABD7o/Ft4JOq2ydaEHteja59Zzv_i3ieXnmONwwCLcB/s800/card_club_03.png",
	"https://4.bp.blogspot.com/-WNnDDDnVkrs/WQA_9vUTTJI/AAAAAAABD8g/PSyYSizOnVkaC37L7bLn82Ex83Tvm0BKACLcB/s800/card_diamond_04.png",
	"https://4.bp.blogspot.com/-bvSGYORb6Xg/WQBAF61kUOI/AAAAAAABD-Q/SalVkKKYYt85TNJJsOjmgNwfT0ao3foewCLcB/s800/card_spade_05.png",
	"https://3.bp.blogspot.com/-w5tuOxBszlU/WQBABseF49I/AAAAAAABD9c/9yF8y-6012MKF5UlSz-dxORnZU_YhEuxgCLcB/s800/card_heart_06.png",
	"https://2.bp.blogspot.com/-LXJw0prlZp0/WQA_6wZyEVI/AAAAAAABD74/eFWVHzCtgLMj_C-JPzjOd7YfhiveHytlQCLcB/s800/card_club_07.png",
	"https://1.bp.blogspot.com/-FZGbdtedARU/WQA__nBH5iI/AAAAAAABD84/X9BsjJbBLZcuGBr5VT2EeisGjlp0wtJpwCLcB/s800/card_diamond_08.png",
	"https://1.bp.blogspot.com/-lYcdLoEoqhk/WQBAGkz_02I/AAAAAAABD-Y/BzeTL07VRhc9viqmclMywil_LqOdQGL5QCLcB/s800/card_spade_09.png",
	"https://4.bp.blogspot.com/-Dj2Yzi1XR-E/WQBADWUni-I/AAAAAAABD9s/2Cy3plnNZGwt9sV3vDO4eCvJSSg9DGx-wCLcB/s800/card_heart_10.png"
)
imag= new Array();
for (i=0; i<data.length; i++){
	imag[i] = new Image();
	imag[i].src = data[i];
}

// getContextメソッドで描画機能を有効にする
var canvas = document.querySelector("canvas");
var context = canvas.getContext('2d');


クラスの定義

ここはクラスを定義しています。

// トランプのクラス
var Card = function(scale, color, vx, vxs, vy, gv) {
	this.scale = scale; // 縮尺
	this.dstWidth = dstWidth;
	this.dstHeight = dstHeight;
	this.kind = kind; // トランプの種類
	this.vx = vx; // X速度
	this.vxs = vxs; // 退場時の速度
	this.vy = vy; // Y速度
	this.gv = gv; // 重力
	this.position = { // 位置
		x: 0,
		y: 0
	};
};


メインのループ処理

ここはメインのループ処理です。

// ループ処理
function animloop(){
	requestAnimFrame(animloop);

	// カードの追加
	if(new Date() - startDate > interval){
		startDate = new Date();
		
		// 詳細値の作成
		kind = Math.random() * 10;
		scale = Math.random() * (0.25 - 0.1) + 0.1;
		dstWidth = imageWidth * scale;
		dstHeight = imageHeight * scale;
		x = Math.random() * (10) -5;
		xs = x / 10;
		y = Math.random()* 9 + 4;
		g = Math.random()* 0.2 + 0.3;
		indx = Cards.length;
		
		Cards[indx] = new Card(scale, kind, x, xs, -y, g);
		Cards[indx].position.x = Math.random() * (canvas.width);
		Cards[indx].position.y = 100;
	}
	
	// カードの更新
	for (var i in Cards) {
		Cards[i].update();
	}
}

この部分でクラス追加の制御をしてます。

// カードの追加
	if(new Date() - startDate > interval){
		startDate = new Date();</code>

今回はvar interval = 2000;に設定しているので2秒間隔です。


クラスの更新

Cards[i].update();で以下の処理を呼び出してます。

// 座標の更新
Card.prototype.update = function() {
	this.vy += this.gv;
	this.position.x += this.vx;
	this.position.y += this.vy;
	
	// 地面の衝突判定
	if (this.position.y > canvas.height - this.dstHeight) {
		this.vy *= -0.8;
		this.vx *= 0.85;
		this.position.y = canvas.height - this.dstHeight;
		if(Math.abs(this.vx) < 0.8){
			this.position.x += this.vxs;
		}
	}
	this.draw();
};

地面に衝突する(y座標がcanvasの大きさに達する)と、y軸の速度[vy]をマイナスにすることでトランプを上に描画しています。
x軸の速度が絶対値で0.8以下となった際は、これ以上バウンドしないと判断し、生成時の速度×0.1で等速に動かしています。


動かしてみた

以下リンクよりブラウザでお試しいただけます。
https://castoroides.github.io/others/Freecell_fall.html

動かしてみると、こんな感じです。
youtu.be

ブラウザクラッシャーを作りたい

有名ブラクラ、「you are an idiot」を拝見して面白かったので似たものを作ってみました。

you are an idiot について

ジョークプログラムの一種ですが、置いてあるサイトはすでにリンク切れとなっているようです。

挙動は以下の通り。
www.youtube.com
「you are an idiot」と音を出しながら、ウィンドウが無限増殖していきます。
放っておくとブラウザおよびPCが負荷に耐えられず、落ちてしまうといった挙動らしいです。
ただ、所詮はブラウザ内で動くプログラムなので危険性は低いです。(タスクマネージャーから強制終了できるから)


このようにブラウザを操作してユーザに嫌がらせをするサイトをブラウザクラッシャー、略してブラクラといいます。
ちなみに、少し前に高校生が遊びで作って「警察から連絡来た」みたいな事案あったらしいので、くれぐれもガチで組んではいけません。



簡単なブラクラを組んでみる

デモ1:アラートのポップアップ

軽い嫌がらせみたいなプログラムを書いてみました。
以下、デモページです。
https://castoroides.github.io/burakura/burakura_1.html

設定してあるプログラムはこんな感じ。

<script>
function buttonClick(){
  
  for(i=10; i>0; i--){
    alert("あと" + i + "回押してね");
  }
}
</script>

「クリック」を押すとアラートが10回表示されるってだけです。


デモ2:タブ無限増殖(フレーム処理)

これだとつまらないので、フレーム毎にタブが増殖していくパターンも作ってみました。
https://castoroides.github.io/burakura/burakura_2.html

<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>
<script>
const url = "https://castoroides.github.io/burakura/burakura_2.html"

// ページが読みこまれた際に実行される、1フレーム(1/60秒)ごとに実行される関数
function draw() {
	//無限タブ増殖
	window.open(url, "_blank")
}

// Close字のメッセージ
window.onbeforeunload = function(e) {
	e.returnValue = "また来てね";
}
</script>


まずは1行目、
src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"で、
フレーム処理を行うためのスクリプト「p5.js」を読み込んでます。

これは本来、アニメーションを組む際に利用するオープンソースライブラリです。これを読み込むことでfunction draw() が使えるようになります。


そしてブロック内のwindow.open(url, "_blank")であらかじめ設定していたURL(本コードでは自分自身)を呼び出して、新規ウィンドウとしてオープンしています。


最後のここで、ウィンドウクローズ時にポップアップを表示させるよう設定しています。
e.returnValue = "また来てね";でテキストを変更できるみたいですが2021年現在ではほとんどのブラウザで定型文が用意され、反映されないようになってるぽいです。

// Close字のメッセージ
window.onbeforeunload = function(e) {
	e.returnValue = "また来てね";
}</code>


動かしてみると
さっそくブラウザで動かしてみます、、、が、
ブラウザにブロックされてしまいました。ちゃんとしてますねクロームは。

テストしたいのでブロックを解除します。
その瞬間タブがものすごい勢いで錬成されていきます。

しばらくして処理が重すぎたのかブラウザが落ちました。
フレーム毎にタブを増殖させたのはやり過ぎたかもです。


デモ3:タブ無限増殖(0.2秒間隔)

ボタンクリックで無限ループに入るように変更しました。
またフレーム処理だとブラウザへの負荷がひどかったので、0.2秒間隔でタブが増えるようにしています。

<script>
  const url = "https://castoroides.github.io/burakura/burakura_3.html"

  function buttonClick(){
    
    // 無限ループでタブを増やす
    while(true){
      window.open(url, "_blank")
      // 0.2秒待機
      let startDate = new Date();
      while (new Date() - startDate < 200);
    }
  }
</script>

new Dateで最新の時間が取得できるので、変数startDateに保存しといた時間と照合させて待機させています。

0.2秒間隔でのタブ増殖だとこんな感じです。


このくらいならきっと大丈夫

ブラクラもどきを作ってみて、ちゃんとブロックしてくれるブラウザのセキュリティはすごいんだなと思いました。
以下、最終版のデモページです。ぜひブラウザのセキュリティを外してお試しください。
https://castoroides.github.io/burakura/index.html


Excel VBAで0.5秒ずつ文字色が変わっていくマクロ組んでみた

久しぶりにエクセルでVBA扱いたくなってこの記事書いてます。
そういうことなので、0.5秒ずつ文字色が変わっていくマクロを作成していきます。


ステップ1:Excelの購入

衝動的にVBA触りたくなったので、まずはライセンスを購入します。
Officeアプリはもはや高級品だと思ってます。


アマゾンへ向かう


インストール

インストール完了です。


ステップ2:文字を打ち込む(読まなくていいです)

この文字列を1文ずつ分割してセルに入れていきます。

数式で分割します。
=MID($A1,COLUMN()-1,1)

数式をコピーするとこんな感じ。

いい感じです。


ステップ3:マクロ作成

ここからが本番です。

まずは個人用マクロブックをエクセル君に生成してもらおうと思います。


「表示」→「再表示」→「PERSONAL.XLSB」を選択し、
「OK」を押して個人用マクロブックを開きます。


「開発」タブから「マクロ記録」


ショートカットも一応設定しておきます。

あとは即「マクロの記録」を終了し、具体的な処理はVBで組んでいきます。
(もっといいやり方ありそう)


コード(最終版)は以下の通り。

Const col_max As Integer = 200 '書式の上限
Dim i As Integer
Dim rng, c As Range
Dim col_list() As Variant
'キー入力取得のおまじない
Private Declare PtrSafe Function GetAsyncKeyState Lib "User32.dll" (ByVal vKey As Long) As Long

Sub fever_string()
'
' fever_string Macro
' Let's Fever!!!!!
'
' Keyboard Shortcut: Ctrl+Shift+F
'
    MsgBox "Let's Fever!!!!!    " & vbCrLf & "(EnterキーでStop)    "

    init_color '文字色の作成
    
    Dim t_cnt As Long: t_cnt = 0
    Do While t_cnt < 1000
        Application.Wait [Now()] + 500 / 86400000
        t_cnt = t_cnt + 1
        
        change_color '文字色の変更
        
        'Enter入力で停止
        If GetAsyncKeyState(vbKeyReturn) Then
            Exit Sub
        End If
    Loop
End Sub

Sub init_color() '書式の制限回避
    Dim col_1, col_2, col_3 As Integer
    For i = 0 To col_max
        'Int(Rnd() * (最大値 - 最小値 + 1) + 最小値)
        col_1 = Int(Rnd() * 256)
        col_2 = Int(Rnd() * 256)
        col_3 = Int(Rnd() * 256)
        
        ReDim Preserve col_list(i)
        col_list(i) = RGB(col_1, col_2, col_3)
    Next i
End Sub

Sub change_color()
    'Set rng = Selection 'アクティブセルの場合
    Set rng = Range("A1", "AC20") 'ここを毎回指定
    
    For Each c In rng
        i = Int(Rnd() * col_max + 1)
        c.Cells.Font.Color = col_list(i)
    Next c
End Sub


init_color()であらかじめ文字色を規定数作成しています。
これはExcelでは1ブックあたりの書式の上限数が決まっているからです。

公式サポートページでは以下のように書かれています。

固有のフォントの種類
1,024 個のグローバル フォントを使用可能 (ブックあたり 512 個)

support.microsoft.com


文字色は512種類が限界みたいですね(おそらく)
このマクロは実行毎に200色ランダム生成するので3回目で以下のエラーが出てしまいます。

エラーが出たら一度ブックを閉じて使用文字色のリセットをします。
文字色の候補を減らせばいいだけですがめんどくさいのでこのままで行きます。


文字色を生成した後はApplication.Wait [Now()] + 500 / 86400000
0.5秒ずつ時間を止めつつchange_color()でセルごとに色を変更しています。

86400000は1日を秒換算した値みたいですね。


動かすとこんな感じです。
youtu.be

人生で初めて作ったプログラム

人生で初めて作成したプログラムのこと、覚えていますか?
私はしっかり覚えています。以下となりますご査収ください。


犬変換プログラム(Python

犬変換.py
# 入力した文字をすべて犬に変換する関数を作る
print("入力した文字が全て犬に変換されます。")

# 関数を定義
def dog(tmp):
	lis = [tm for tm in tmp]
	num = len( lis)
	return ("犬" * num)

# 引数を犬に変換する
td = dog (str(input("なにか入力してください: ")))
print("\n" + td + "\n")

tmp = str(input("Enterで終了"))


(読まなくていいです)
inputで入力された文字列をPythonの内包表記で1文字ずつ取り出しリスト化。
その後リストの長さをlenで取得し、その長さの分だけ「犬」を出力。

わざわざリスト化しなくてもreturn ("犬" * len(tmp))でいいじゃんとか、そもそも関数にするほどの処理じゃねーだろとか、しっかりクソですね。


暇だったのでJavascriptで書き直してみました。


犬変換プログラム(JavaScript
何か入力してください:



以下Javascriptでのソース

<form>
何か入力してください:
<textarea rows="2" cols="40" id="tarea"></textarea>
<input type="button" value="変換" onclick="func()">
</form>
<script>
let func = (button) => {
	let element = document.getElementById('tarea');
	element.value = '犬'.repeat(element.value.length); 
}
</script>


ちなみにこのプログラム、就活で提出したら内定出ました。
ホントです。