0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

コンソールゲーム あるいは カリグラム的プログラム

Last updated at Posted at 2023-05-15

コンソールで動作するゲームを Rust で実装しました。
(世の中はゼルダ新作でにぎわっているというのに)

コード

(コードの解説はしません。各自ハックしてみてください)

/* cargo add getch_rs rand; cargo run */ const FW:usize        =80;const FH:usize=25
;const FZ:usize=100;const   FS:usize=FW*FH;const FR:             usize=10;const CS:&
str="\x1b[";const C1:&str     ="255;000;000";const C2:&           str="000;000;255";
const C3:&str="000;255;000"   ;const C4:&str="000;250;154"           ;const C5:&str=
"144;238;144";const C6:&str    ="034;139;034";const C7:&str          ="000;100;000";
const C8:&str="047;079;079"    ;const C9:&str="112;128;144"         ;const C10:&str=
"128;128;128";const C11:       &str="192;192;192";const C12                  :&str =
"245;245;245";const C13:       &str="255;255;255";const C14                   :&str=
"255;255;000";const C15        :&str="255;000;000";const M1                   :&str=
"Perfect!";const M2:&str       ="Bye.";use getch_rs::{Getch                 as G,Key
::{Left as KL,Right as         KR,Up as KU,Down as KD                           ,Esc
as KE,Char as KC}};use         rand::Rng;use                                   std::
sync::{Arc,Mutex};use         std::{thread,time                            };fn main
()->std::io::Result<             ()>{cls();let mut                  c=C::new();c.g()
;c.d();let c=Arc::new                (Mutex::new(c));              {let c=Arc::clone
(&c);let _=thread::                      spawn(move||{loop        {thread::sleep(time
::Duration::                              from_millis(             1000));let mut c=
c.lock().unwrap(            )               ;let mut nb                  :Vec<B>=vec
![];if c.bb.len            ()>0               {for b   in                   &c.bb{if
b.t<4{nb.push(            B::new              (b.x,b.y,b.                     t+1));
}}c.bb=nb;c.u            ();}c.               d();c.cb();                      }});}
let mut bp=             false;               let g=G                         ::new()
;loop{match            g.getch     ()?{KL=>{let                         mut c=c.lock
().unwrap(            );c.mw();bp=c.bp;}KR=>{                       let mut c=c.lock
().unwrap             ();c.me   ();bp=c.bp;}KU=>{                 let mut c=c.lock()
.unwrap(            );            c.mn();bp=c.bp;}KD=>{let           mut c=c.lock().
unwrap(                            );c.ms();bp=c.bp;}KC(' '     )=>{let mut c=c.lock
().                                unwrap();c.ad();}KE|KC(        'q')=>{      break
;}_=>                              (),}if bp{break;}}Ok(q(
bp))          }                   struct C{fd:[usize;FS]
,p:         P,bb:Vec            <B>,bp:bool,}impl C
{fn      new()->Self{         C{fd:[0;FS],p:P
::     new(),bb:vec!        [],bp:false,
     }}fn ad(&mut         self){self.                         bb.push(B::new(
   self.p.x-1,self       .p.y-1,0));}                 fn g(&mut self){let mut r=rand
::thread_rng();let        mut ks:Vec<K          >=vec![];for _ in 0..r.gen_range(5..
FS/20){let x=r.     gen_range     (1..FW);let y=r.gen_range(1..FH);let z=r.gen_range
(1..FZ);let s=r.  gen_range(1..FW);ks.push(  K::new(x,y,z,s));}let mut max=0;let mut
cnt=0;let mut   lcnt       =100  ;while(max<10||cnt>=FS/2)&&lcnt        >0{max=0;cnt
=0;for p in 0..FS{for               k in&ks{self.fd[p]+=k.val               (p%FW,p/
FW);}if self.fd[p]>FZ                {self.fd[p]=FZ;}if                      self.fd
[p]>max{max=self.fd[                  p];}if self.fd [         p]<10{        cnt+=1;
}}lcnt-=1;}for x                      in 0..FW{self.  fd[x]=0;self.fd[        FS-FW+
x]=0;}for y in                 0..FH{self.fd[y*FW]=   0;self.fd[(y+1)         *FW-1]
=0;}}fn u                   (&mut self){for p in 0..   FS{for b in&self       .bb{if
b.ib(p%FW                  ,p/FW)&&self.fd[p]>=10{     self.fd[p]-=5;         }}}for
x in 0..FW{                 self.fd[x]=0;self.fd[FS     -FW+x]=0;}for y     in 0..FH
{self.fd[y*FW      ]       =0;self.fd[(y+1)*FW-1]=     0;}}fn    d(&          self){
print!("{}H",CS);for       (p,v     )in self.fd.iter               ()         .
enumerate(){let mut        bp=       false;for b in                           &self.
bb{if b.ib(p%FW,p/FW       ){bp=       true;break;                            }}print
!(       "{}48;2;{}m {}m"  ,CS,if       bp{C1}else                            if*v<10
{C2}else   if*v<15{C3      }else         if*v<20{                   C4          }else
if*v<30{    C5}else        if*v<         40{C6}else     if*v      <50        {C7}else
if*v<60{    C8}else        if*v          <70{C9}        else    if*v<          80{C10
}else if     *v<90{        C11}         else if*v       <100  {C12}else        {C13},
CS);if p     %FW==         FW-         1{println!       ()   ;}}print              !(
"{}{};{}H"    ,    CS      ,          self.p.y,self     .  p.x);print              !(
"{}48;2;{}m"       ,       CS        ,C14);print        !("{}38;2;{}m+"       ,CS,C15
);println         !(       "{}m"    ,CS);}fn me(        &mut self){if          self.p
.x<FW-1          {self             .p.x+=1;}self           .d();}fn mw          (&mut
self){if         self             .p.x>2{self.p.                               x-=1;}
self.d(         );}             fn mn(&mut self)                                  {if
self.p.        y>2{            self.p.y-=1;}self       .d                      ();}fn
ms(&mut       self)           {        if self.        p.y      <FH-1{         self.p
.y+=1;}       self.                      d();}fn       cb(&mut self){if       self.bp
{return}for  (p,v)in                      self.        fd.iter   ().        enumerate
(){let x=p% FW;let y                      =p/FW        ;if x   ==0||x==        FW-1||
y==0||y==FH-1{                           continue      ;}if*v    >=10{        self.bp
=false;return}}                       self.bp=         true}}     struct         P{x:
usize,y:usize                     ,}impl P{fn         new()->       Self      {P{x:FW
/2+1,y:FH/                   2+1,}}}struct B{x        :usize,y                 :usize
,t:                      usize,r:f64,}impl B{fn       new(x:usize            ,y:usize
,t:                   usize)->Self{let mut r=         rand::               thread_rng
();                 B{x:x,y:y,t:t,r:r.gen_range       (2..=FR)as               f64,}}
fn ib             (&self,x:usize,y:usize)->bool       {let r=self              .r*f64
::sin(          (self.t as f64)*std::f64::consts     ::PI/4.0);let            x=(x as
f64)-(        self.x as f64);let y=(y as f64)-(      self.y as f64            );x*x+y
*y<=r*r}}fn cls(){print!("{}2J",CS);print!("{}H"     ,CS);print!(            "{}?25l"
,CS);}fn q(bp:bool){cls();println!("{}?25h",CS);    println!("{}",if       bp{M1}else
{M2})}struct K{x:usize,y:usize,z:usize,n:N,}impl K  {fn new(x:usize,y       :usize,z:
usize,s:usize)->Self{let n=N::new(0.0,s as f64);K{ x,y,z,n}}fn val(&     self,x:usize
,y:usize)->usize{let dx=(self.x as f64)-(x as f64);let dy=(self.y as   f64)-(y as f64
);let d=(dx*dx+dy*dy).sqrt();(self.n.pdf(d)*(self.z as f64))as usize}} #[derive(Clone
)]struct N{m:f64,s:f64,}impl N{fn new(m:f64,s:f64)->Self{N{m,s}}fn pdf(&self,x:f64)->
f64 {let x2=x-self.m; let s2=self.s*self.s*2.0;(-x2*x2/s2).exp() / (s2*2.0).sqrt()}}

"rust" = 「錆」ということで。

Tシャツにするとこんな具合になりそうですが、まだまだ修行が足りませんね。

image.png

動作確認環境

Windows11 + Rust1.66.1

インストール&起動手順

  1. cargo new bomb を実行
  2. bomb/src/main.rs に上のコードをコピペ
  3. cd bomb して cargo add getch_rs rand を実行
  4. コンソールのプロパティで横80文字・縦25文字よりも大きくしておく
  5. cargo run で起動

あそびかた

起動直後の画面

image.png

マップは毎回ランダムになります。
青は海、地面は黄緑から海抜が高くなるごとに濃くなりますが一番高いところは白になります。

カーソルの移動

image.png

中心の黄色いカーソルは矢印キーで上下左右に移動できます。

爆発

image.png

スペースキーを押すとカーソルの位置に「発破」が仕掛けられ、爆発します。
赤い爆炎が広がっていき、やがて小さくなります。

爆発後

image.png

爆発により地面は吹き飛びます。
地面は削られ、だんだん地面の高度は下がります。
最後は海抜0となると青くなります。

すべての地面を爆発で吹き飛ばすと完了です。

途中で終了させたい場合は ESC キーか q キーで終了できます。

キー操作まとめ

キー 操作
カーソルを上に移動
カーソルを右に移動
カーソルを下に移動
カーソルを左に移動
スペース 発破のセット
ESC もしくは q 終了

以上。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?