テトリスもどき　あるいは　カリグラム的プログラム

```rust
/*cargo add getch-rs random rand*/const FW:usize=12;const FH:usize=20;const BW:usize
=4;const BS:usize=BW*BW;use getch_rs::{  Getch,Key as K};use rand::Rng;use std::sync
::{Arc,Mutex};use std::{thread as   th,     time   };fn main()->std::io::Result<()>{
let c=Arc::new(Mutex::new(Ctx::new   ())    );     println!("\x1b[2J\x1b[H\x1b[?25l"
);c.lock().unwrap().d();{let  c=Arc    ::     clone (&c);let _=th::spawn(move||{loop
{th::sleep(time::Duration    ::                 from_millis(1000));let mut c=c.lock(
).unwrap();let np=P{x:c.p                                .x,y:c.p.y+1,};if!c.collide
(&np){c.p=np;}else{ c.fix                                 ();c. el();if c.sb(){break
;}}c.d()}});}let g=   Getch              ::                  new    ();loop{match g.
getch()?{K::Left=>{                     let                          mut c=c.lock().
unwrap();let np=P{x                     :c.p                      .x.checked_sub(1).
unwrap_or(c.p.x),y:                     c.p.                       y,};c.mv(np);}K::
Right=>{let   mut c                =c    .     lock               ().   unwrap();let
np=P{x:c.p.x                    +1,y:c        .p.y,}                    ;c.mv(np);}K
::Down=>{let                 mut c=c.lock    ().unwrap(                );let np=P{x:
c.p.x,y:c.p.y              +1,};c.mv(np)    ;}K::Char(' '              )|K::Char('x'
)=>{let mut c             =c.lock().unwrap ();c.rr();}K::            Char('z')=>{let
mut c=c.lock(           ).unwrap();c.rl();}K::Esc|K::Char('q'         )=>{break;}_=>
(),}}Ok(quit(          ))}struct Ctx{f:[usize;FW*FH],p:P,bk:[        usize;BS],}impl
Ctx{fn                new()->Self{Ctx{f:[1,0,0,0,0,0,0,0,0,0,0               ,1,1,0,
0,0,0,0,             0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,             0,0,0,0,
0,0,0,0,            1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,            0,0,1,1,
0,0,0,0,0                                               ,0,0,0,0,          0,1,1,0,0
,0,0,0,0,                                                 0,0,0,0,         1,1,0,0,0
,0,0,0,0,                                                   0,0,0,1        ,1,0,0,0,
0,0,0                                                        ,0,0,0            ,0,1,
1,0,                                                         0,0,0,0            ,0,0
,0,0                                                          ,0,1,1,           0,0,
0,0,0                                                         ,0,0,0           ,0,0,
1,1,0,                                                         0,0,0           ,0,0,
0,0,0,     0,1                                                 ,1,0   ,0,0    ,0,0,0
,0,0,0    ,0,1   ,1,0,              0,0,0,0,0,0,               0,0,   0,1,    1,0,0,
0,0,      0,0,    0,0,              0,0,1,1,0,0,0              ,0,    0,0,      0,0,
0,        0,1,    1,0,              0,0,0,0,0,0,0,             0,0    ,1,1        ,0
,0         ,0     ,0,0              ,0,0,0,0,0,1,1             ,1,     1,          1
,1               ,1,1,              1,1,1,1,1,],bk            :nb()               ,p
:P::           new(),}                                        }fn d(&            mut
self)        {let mut                                        fb=self.f.        clone
();for      (p,v)in                                         self.bk.iter         ().
enumerate   (){let px=                                     p%BW;let py=p        /BW;
let         q=self.p.x                                    +px+(self.p.y+          py
)           *FW;if*v==                                    1&&q<FW*FH{fb[           q
]           =1;}}println                                   !("\x1b[H");for         (
x,          v)in fb.iter                                    ().enumerate          ()
{print      !("{}",if*                                       v==1{"#"          }else
{"."}       );if x%FW==             FW-1{                    println!          ();}}
}fn         collide(&               self,np:&P)              ->bool{for         (p,v
)in         self.bk.iter            ().enumerate              (){let             px=
p%          BW;let py=              p/BW;let q=np             .x+px+             (np
.y           +py)*FW;if             q>=FW*FH{                  continue            ;
}if          *v&self.f              [q]==1{return                true             ;}
}false                                     }fn mv                              (&mut
self,np                                    :P){if                             !self.
collide                                    (&np){                             self.p
=np;}                                      self.d                              ()}fn
fix(&                                      mut self                            ){for
(p,v                                       )in self                             .bk.
iter                                       ().                             enumerate
(){let                                     px=p%BW;                              let
py=p/BW;if                                 *v==1{self                      .f[self.p
.x+px+(self       .p.y+py)*FW]=1;}}}fn el(&mut self){for y in 1..FH       -1{let mut
can_erase          =true;for p in y*FW..(y+1)*FW{if self.f[p]==0{          can_erase
=false;             break  ;}}if can_erase{for y2 in (2..=y).              rev(){for
p in y2*                    FW..(y2+1)*FW{self.f[p]=self                    .f[p-FW]
;}}}}}fn                    sb(&mut self)->bool{self.p=P                     ::new()
;self.bk=nb()         ;if   self.collide(&self.p){self.d   ();             println!(
"Game Over!")        ;       println!("Press ESC to exit" );           return true;}
false}fn rr(&        mut     self){let mut nb:[usize;BS   ]=               Default::
default();for        p in 0  ..BS{let px=p%BW;let py=p/   BW;let      px2=py;let py2
=BW-1-px;nb[p         ]=     self.bk[px2+py2*BW];}if!self  .           collide(&self
.p){self.bk=                    nb;}self.d()}fn rl(&                   mut self){let
mut nb:[usize ;BS]=                Default::default            ();for p in 0..BS{let
px=p%BW;let py=p/BW                                              ;let px2=py;let py2
=BW-1-px;nb[px2+py2                                              *BW]=self.bk[p];}if
!self.collide(&self                                             .p){self.bk=nb;}self
.d()}}#[derive(Clone  ,Copy                                )]     struct P{x:usize,y
:usize,}impl P{fn   new()                                 ->Self {P{x:4,y:0}}}fn nb(
)->[usize;BS]{let mut rng                                  =rand::thread_rng();let p
:usize=rng.gen_range(0..7    )*16                   ;let mut r:[usize;BS]=[0;BS];for
i in 0..BS{r[i]=B[p+i];}r}   const    B      :[     usize  ;BS*7]=[0,0,0,0,0,0,0,0,1
,1,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,    1,1    ,0,    0,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,0
,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,   0,0,    0,0,   0,0,0,1,0,0,0,1,1,1,0,0,0,0,0,0,0
,0,0,0,0,1,0,1,1,1,0,0,0,0,0,0,0,0 ,0,0,1  ,0,0,1,1,1,0,0,0,0,0,];fn quit(){println!
("\x1b[?25h");}                                                                     
```

Windows11 + Rust 1.66.1 で動作確認。Windows のコマンドプロンプトで動作します。

[参考]
・Rustで作るテトリス風ゲーム入門
https://zenn.dev/kumavale/books/30efec2e1d3428/viewer/900eb4

エスケープシーケンスとキー入力の使い方など、非常に勉強になりました。
単なるコピペではなくフィールドやブロックのデータ構造を全く異なる形で実装しました。