【Python】ビット演算の使い方【演算子,活用方法,ゲーム属性】

プログラム
スポンサーリンク

はじめに

今回はPythonのビット演算を使う方法を紹介します。
Pythonの導入や基本操作が行えることを前提で進めます。

↓前提知識はこちらをご覧ください↓

【Python】導入方法から基本操作について
Pythonは無料で使えるプログラミング言語でA「I開発や作業の自動化」に強いとされてます。導入は公式サイトからダウンロード。DLしたら「IDLE」を起動して動かします。2行以上のブログラムの場合は「.py」ファイルを作成する必要があります。

ビットとは(Bit)

ビットとは、コンピュータの計算装置の中の1つ単位です。
「0」と「1」を管理する機構と考えてください。

分かりやすいイメージが、電球になると思います。

コンピューターの祖先は、電球です。

この電球を改良しようとした結果、真空管が偶然発明されました。
この真空管は、電気で「オン」と「オフ」を制御できるという特徴がありました。

つまり、この段階で電気で “電気” を制御できるようになりました。

そして、この「0」と「1」を表す機構を複数組み合わせると…
様々な処理が行える事が分かりました。
↓こちらの電子楽器の原形も「0」と「1」の組み合わせを複数並べて処理を作ってます。

この「0」と「1」を処理する機構を “ビット” と呼ぶようになりました。
そして、この電球が並んだ数が… 
16個であれば “16Bit” で、32個であれば “32Bit” などと呼ばれるようになります。

そして、この真空管を大量に並べる事で “原初の” コンピューターが発明されました。
(ENIAC)

この真空管を小型化 → トランジスタの登場。
トランジスタを小型化+処理をまとめてパッケージ化 → ICやLSIの登場。
そして、今の時代のコンピューターが形になってます。

つまり、コンピューターの原形は電球であり、
内部構造はこのような “Bit” による計算が行われてます。

↓このあたりを、より詳しく知りたい方はこちらをご覧ください。

以上が “ビット” についての解説です

ビットは2の乗数で情報が増える

Bitの処理は、下図のように用意したモノの点滅パターンで決まってます。
1つなら2通り、2つなら4通り、3つなら8通りの情報を保持できます。

なので… 保持できる情報はBit数が上がるごとに2の乗数で増えていきます。

数式で表すとこちら。

以上が、ビットは2の乗数で情報が増えることの解説です。

ちなみに電球が…
・1つの状態を = 1ビット(2通り)
・4つの場合を = 1ニブル(16通り)
・8つの状態を = 1バイト(256通り)
と呼びます

ニブルについて(4Bit/16通り)

ニブルは4Bit、つまり16通りという意味です。
なぜ、この4Bitが特別扱いされてるかというと…

16通りの場合、16進数という特別な表記方法が使えます。

普通の数字のように “10” で繰り上がって2文字にせず…
A~Fまでの表記を追加し、16通りの情報を1文字で表記する処理の事です。

上の図は0スタートなので “15” の段階で16通りを使い切ってる事に注意。

主に色の表現で使われるアレになります。

色の詳細はこちらで解説。

ニブルはこの16進数で表記できる点で、よく登場します。
例えば.wavなどのファイルを任意のテキストエディターに読み込み。

ここでは、Sublime Textを使用し、ドラッグ&ドロップで読み込み

すると… 音のデータは16進数のカタマリで管理されてる事が分かります。

・1文字が1ニブル = 16通り。
・4つの束が4ニブル = 16の4条 → 65,536通り

…と莫大なデータが記録されてる事が分かります。

つまり、ニブルは4Bitというより16進数1つ的な意味で使われます。

以上が、4Bit/16通りのニブルについての解説です。

バイトについて(8Bit/16通り)

これは、人間側が扱いやすいように「まとまり」として設定された数値です。
バイトの由来は、全てのアルファベットを扱えるかどうかで決まったようです。

なので、昔のコンピューターは1バイト = 6Bitのモノもあったりしました。
その後、7Bitや9Bitなども登場してたようです。

ちなみに、昔のコンピューターは小文字が無く…
49文字で済んでいたので6Bit = 1バイトと扱われてました。

小文字などが追加され、6Bitじゃ足りなくなったので「+1Bit」 → 7Bit。
あと、パソコン的には偶数の方が扱いやすいのでさらに「+1Bi」 → 8Bitになったようです。
(偶数の方が扱いやすい性質 = パリティビット

パリティビットは “奇数” か “偶数” かを判定して、データの誤りを検知する機能のようです。
(奇数パリティ / 偶数パリティ/ パリティチェック)

これは実際、 01010001みたいな8Bitを格納するデータに、何かしらの原因、ノイズなどが入って010100010と打ち込んでしまった時のミスを検知する時に使われるようです。

(偶数のミスや、中の数値ミスは諦めましょう方式)

あとは、昔の覇権コンピューターが1バイト = 8Bit設定だったり…
後に「ISO/IEC_80000-13:2008」規格で8Bit = 1バイトと規定されたりしました。
↓1バイト = 8Bit問題はこちらの記事が非常に詳しく解説してます。

「1Byteが8bitに決まったワケ」についての長い話 まずは「バベッジの階差機関」から
Twitterで話題になっていた、「1Byteは何故8bitなのか?」という課題に、コンピュータの歴史に詳しい大原雄介さんが取り組んでくれた。

ニブルと違って、とくに “コレ” にする必要はなく…
人間側の都合で決められた数値です。

ビット演算の用途

Pythonでこのような「Bitデータ」を扱う処理をビット演算と呼びます。
この、ビット演算の用途は下記の2つ。

・複数のオン/オフを管理する(ビットフラグ)
・2つ以上の要素がある条件分岐を簡略化する

この2つについて見ていきます。

複数のオン/オフを管理する(ビットフラグ)

Pythonでビットデータを扱う場合… 頭に「0b」の文字をつけます。
これで、これ以降の数字が “ビット” ですよとパソコンに伝える事ができます。

【ビット表記の例】

0b00
0b0001

…など。

0bに続けて0と1の数字を打ち込んでいく形になります。(スペース無しで打ち込み)
この「0」と「1」の数字が先ほど説明した “電球” にあたります。

そして、Pythonはこの電球を「スイッチ」的な使い方ができます。
↓このようなイメージと考えてください。

Pythonでビットを扱う場合、電球より “スイッチ” をイメージした方が上手く行きやすいです。

そして、このスイッチを使う事で、大量の情報を管理しやすくなります。
ゲームなどのキャラクターが持つ属性データを管理する時などに有効です。
1つ1つに属性用の変数を作って処理すると…
凄く長く、管理用の変数も多い処理になります。

プログラム的に、変数は少ない方が良いとされてます。
(シンプルに変数を入力する場面が多いと、誤字エラーの確立が上がります)

このような7個の属性みたいな情報を格納するのに、ビット演算は使えます。
下図の例だと「0b000101」で水と陰属性みたいな処理を作れます。

管理的にはこんな感じになります。
下図のような感じで、属性の管理ができたりします。

設定した変数は「CharacterData」の1つだけです。
誤字などが少ない、強めのプログラム。

あと、それぞれのビットが何を表すか分からないと思います。
なので、上の方に「#」のコメントで対応を入力。

みたいなことをすれば、複数のオン/オフを管理することができます。
以上が、ビットフラグについての解説です。

2つ以上の要素がある条件分岐を簡略化する

ビット演算を使うと、2つ以上の要素がある条件分岐も簡略化できます。
普通にやると、変数が増えてif文が長くなります。

使えても2つまで。
3つ以上なると、変数で長文化して非実用レベルになります。

そこで、ビット演算を使って2つの条件を表記します。
これで変数が1で複数条件のif文が作れます。

以上が、2つ以上の要素がある条件分岐を簡略化できる事の解説です。
具体的なやり方は次の項目で解説。

ビット演算を使った複数条件if文の書き方

ビット演算を使った場合…
if 「ビット」 & 「変数名」で実行すると、ビットが一致した時に実行処理が入ります。

参考としてに見た情報の関係で… if 「ビット」 & 「変数名」の表記になってますが
if 「変数名」 & 「ビット」でも動きます。

ちなみに、ここでは「and」表記でも動きます。
「&」と「and」の違いは(こちら)で解説。

注意が必要なのは…
「1」の入力が無いと処理が入らない事です。

この「1」の入力がある事を…
「ビットが立つ」などと表現
されたりします。

00入力の場合… どこもビットが立たない → 処理無し
11入力の場合… 00は何処もどこもビットが立ってる時の条件を定義できていない
「00」だけは処理が入らない事になります。

if not 「ビット」 & 「変数名」で実行すると…
ビットが一致してない時に実行処理が入ります。

00の場合、ifであれば全部処理無し。これがnotで反転するので「すべて」実行。
11の場合、ifであれば「00」だけ処理無し。これがnotで反転して「00」だけ実行。

「&」は部分的にオンの場合使いやすいですが…
全オフ、全オンの場合は微妙に挙動が変わるので注意。

「==」や「is」を使うと、完全に一致した時だけ処理が入ります。
なので「00」のような条件分岐はこちらを使う方が安定します。

「==」とis」の違いは(こちら)で解説。

「^」を使うと、完全に一致した時以外がオンになります。
(if not 「ビット名」 == 「変数名」と同じ処理になります)

後で紹介する、ビット演算子のORを表す「 | 」を使った場合…
すべてで実行されます。
これは、条件として書いた「ビット数」で条件を満たしたと判定されてしまうようです。

なので、実用では使えません。
あと、これ以降も実用ではあまり使えないと思います。

ビット演算子の「~」はエラーが出ます。
使えません。

比較演算子は使えますが…
2Bit表記のモノを人間が頭で10進数に変換してから大小つけて操作する形になります。

2Bit(2進数)と10進数は下記のように変換できます。

・0b00 → 0
・0b01 → 1
・0b10 → 2
・0b11 → 3

↓もし使うなら、こんな感じの変換サイトが役立ちます。

https://note.cman.jp/convert/bit

コツを掴めば、扱えるかもしれませんが…
わざわざ使うモノでは無いと思います。

実用的な事を考えれば、わざわざビット演算にせず
普通に10進数を使った方が良いです。

ビット演算子のビットが立ってる場所をズラす処理は「>>」と「<<」だけなら使えます。
「<< 3」みたいな形だと動きません。

01 >> Data:の場合、1つシフトした場所が判定位置になるので…
0b01を入力すると「10」と「11」

実用的な事を考えれば、わざわざビット演算にせず
普通に10進数を使った方が良いと思います。

なので、実際使うのは「if &」「if not &」「if ==」「if ^」の4つと思います。

・「if &」 → Bitの立ってる位置が一致した場合
・「if not &」 → Bitの立ってる位置が一致 "しなかった" 場合 
・「if ==」 → 完全に一致
・「if ^」 → 完全に一致したとき"以外"

ビット演算を使った複数条件if文の書き方です。

ビット演算とビット演算子

ビット演算は「論理演算子」という記号を使う事で特殊な計算が行えます。
こちらを使えば、0b形式で入力した2つのデータを組み合わせた計算処理が行えます。

一応紹介しますが…
ビット演算子を使った計算はめったに使わないと思います。
(シンプルに使いにくい+有効そうな事例は見つけられなかった)

主なビット演算子は下記

・&(AND)
・|(OR)
・~(NOT)
・^(XOR)
・<<(左シフト)
・>>(右シフト)

この6つについて解説していきます。

「&」について

ANDは2つの入力がオンの時に有効化になる処理です。
別の言い方をすると2つともビットが立ってる時にONになります。

この処理を元ネタにした演算子が「&」です。
下図のような処理になります。

試しに「0b0001&0b0111」を入力。
すると… 「1」が出ます。

次は「0b1001&0b1111」を入力。
すると… 「9」が出ます。

これはPrintの処理が2進数対応してないのが原因です。

0b1001 & 0b1111 → 「0b1001」

「0b1001」を10進数表記にすると…「9」
なので「9」が出力されました。

このあたりは、こちらの変換ツールなどを使えば素早く検証できます。

https://note.cman.jp/convert/bit

で、この数字を「bit()」で囲むと、2進数でprint()出力できます。

試しにprint(bin())形式で「0b0001&0b0111」を実行。
すると… 「0b1」が出ます。
これは「0b0001」という出力結果が省略された形です。

前にある「0」は省略されるという点に注意してください。
以上が「&」についての基本的な解説です。

&の用途①「ビットの一致検出」

すでに紹介しましたが「if &」の形を使う事で…
ビットの立ち方が一致した時に、特定の処理を動かせます。

ビットが立ってる状態で一致した時なので…
「00」は動作しません、この点に注意。

「&」の用途は大体コレになります。
以上が、&の1つ目の用途「ビットの一致検出」です。

体感、変な感じがすると言いますが、直感的では無いですが…
if &はよく使うので、こういう “型” として覚えてください。

&の用途②「ビットマスク/抽出」

「&」はもう1つ、ビットを一部的に消す処理(マスク)が使えます。
そして、マスクされなかった部分を見ると… そこが(抽出)された形になります。

これを理解するために、②のビットが全て立ってる状態を考えてください。
この場合は「①」の結果がそのまま出力されます。

下図のような挙動になります。

そしたら、下2桁を00に設定。
すると… ②で「0」が入った時点でそのビットは「1」になる事はありません。
つまり「0」になる=マスクされます。

pythonで書くと、こんな感じになります。

つまり①のビットから、②のビットに「1」がある部分だけ抽出した形になります。
=「0」の所がマスクになります。

以上が、&の2つ目の用途、ビットマスク/抽出の解説です。

これは… 情報処理やセキュリティ系で使うようです。
一般人はそこまで使わないかなと思います。

「 | 」について(OR合成)

ORは2つの入力がオンの時に有効化になる処理です。
別の言い方をすると片側のビットのどちらかが立ってる時にONになります。

この処理を元ネタにした演算子が「|」です。
下図のような処理になります。

つまり、①と②どちらかのビットが立っていれば立つという処理です。

これは複数の1か所だけ「1」が入ったビットを合成する時に使えます。

後で紹介する、左シフト(<<)と相性がいいです。
「1 << 1 | 1 << 3」で「0b1010」みたいなビットを作れます。

以上が、「 | 」とOR合成についての解説です。

「 ~ 」について(超使いづらい反転)

NOTは入力がある時にオフ、入力がない時にオンになる処理です。
別の言い方をすると処理が反転します。

この処理を元ネタにした演算子が「~」です。
が… これは非常に使いづらいのでおすすめはしません。

「0111」を反転した場合、下図のような処理になります。

pytnonで書くとこんな感じになります。
「マイナス」が付いたこと以外… 一見、問題無さそうに動いてます。

では「0b1111」を反転させると…「-0b10000」になります。

無駄な()が入ってますが…
直しても、同じ挙動になります。

print(bin(~0b1111))

>>> -0b10000

なぜこうなったかというと… 
「NOT」は厳密には反転ではないのが原因です。
頭に「-」をつけて(入力ビット + 1)の値を出す処理になります。

-0bの「-」は、頭に無限の1がある事を伝える記号。
+1された理由は…

プラスなら「0」スタート、マイナスなら「1」スタートになるのが原因のようです。
…正直、よくわからないので触らないのが無難。

なので、ビット反転に「NOT(~)」を使うのはおすすめしません。
反転は次に紹介するXORの記号「^」を使って行うことをおすすめします。

「 ^ 」について(高性能ビット反転)

XORは2つの入力が “不一致であれば” 有効化になる処理です。
別の言い方をすると1つだけビットが立ってる時にONになります。

この処理を元ネタにした演算子が「^」です。
下図のような処理になります。

pythonで動かすと、下図のようになります。

で… 重要なのが②をすべて「1」にした時の挙動です。
2をすべて「1」にすると… ①の入力が反転します。

pythonの画面がこちら。
そう、これで私たちが思っていた “ビット反転” が行えます。

また②の入力に「0」を組み合わせれば、部分的にビット反転をかける事も可能です。

0110の場合、頭の「0」は省略されるので… 「110」になります。

以上が、XORの解説です。

とはいえ… このビット反転。
情報技術者的な人以外、そんなに使い道が無いという。

「 << 」と「 >> 」(ビットシフト)

「 << 」や「 >> 」の後に数字を入れると、その分だけビットが立っている位置をずらせます。
↓<< 2だと、下図のようにビットが左に2ズレます。

このような、ビットが立ってる位置をズラす処理を…
「ビットシフト」と呼びます。

<< と >> でズラす方向指定、後の数字でズラす数を指定。

そして、ここが重要なのですが…
右にシフトした場合、シフトした数だけ元あった情報が消えます。

Pythonで動かすと、下図のように1001から右2つが消え「0b10」になることが分かります。

そして、1<<0を入力すると… 0b1になります。

<< 0 の場合、ビットシフトが起こらない事と…
10進数の「1」を入力したけど、出力がbin()を通ったので0b1になった事に注目。

これだけだと分かりにくいので、もっと大きな数字を扱います。
10進数で「810」と打ち込み、bit()で2進数表記。
すると… 810は2進数で「0b1100101010」なことが分かりました。

そしたら、こちらにビットシフトを実行。
すると…「810」は自動で2進数に置き換わって状態で処理されます。
なので「0b1100101010」から、右に3つシフトし「0b1100101」になります。

右シフトは情報が消えます。
なので810 → 「0b1100101010」の右3つが消え…
「0b1100101」になりました。

あと、bit()を外せは、結果を2進数ではなく10進数で表示できます。
「0b1100101」を10進数にすると「101」なので、結果に「101」と表示されました。

このあたりの進数の考え方や変換方法の詳細はこちらで解説。

【Python】2,8,10,16進数の表記と変換方法
進数とは特定の数字の表現方法で、進数が変わると "1文字" で数えれる数字が変わります。Pythonだと、bin(),oct(),hex()を使えば数字の進数を変換できます。また、0b,0o,0xという形で進数を表現する事も可能です。

以上が、「 << 」と「 >> 」(ビットシフト)の解説です。

右/左シフトの使い道

右シフトはデータが消えるのでそこまで使い道がないです。
が… 左シフトは “ビット表示の簡略化” に役立ちます。

10進数でも2進数でも「1」は「1」です。(1であり、0b1でもあるという意味)
なので… 1 << 3 みたいな形にすると「0b1000」のようなビットを定義できます。

これが、ビット表示を簡略化する上で非常に便利です。
下図の様な、ちょっと目がチカチカする表現を、視覚的に分かりやすく表示できます。

0001 →  「(0b1 << 0)」 → (1 << 0)
・0010 →  「(0b1 << 1)」 → (1 << 1)
・0100 →  「(0b1 << 2)」 → (1 << 2)
・1000 →  「(0b1 << 3)」 → (1 << 3)

※2進数の「1(0b1)」と10進数の「1」は同じ「1」が使える

また、2つ以上の左シフトは「 | (OR) 」 で合成できます。

下図のように「 | 」合成が可能です。

これを使う事で、ビット表示を簡略化できます。
2属性キャラも「 | 」を使えば表現できます。

以上が、右/左シフトの使い道についての解説です。

おまけ:キャラクター属性と属性相性を作る

最後に、属性相性を使ったゲーム的な処理を作って締めます。
(作り方はかなり省きます。分かってる人向け+下にソースコード有り)

というより、生成AIの「Copilot」に色々助けてもらったので…
説明したくても、今の私の技術だと完全に理解しきれてないところがあります。

まず最初に、ビットの立ち方と内容を設定。
コメントなどで記録。(左シフトを使用し記述)

そしたら「tkinter」で画面を作るプログラムを書きます。

これで、下図のような画面が完成しました。

画面の作画処理を細かく見ると…
一番上の「import tkinter as tk」で画面を作るモジュールを読み込み。
あとは、画面サイズや基本的な文字表示枠を設定。

.pack(expand=Ture)を使うと、画面幅÷要素の数みたいな形で文字を入れれます。
なので、画面に要素を4つ作成(4つ目は余白調整用の空白要素)
これで、文字は÷4した中間に入るようになります。

この段階の私は「tkinter」を使いこなせてないので…
かなりガバガバな実装をしてます。

そしたら、左上に「リセットボタン」と画面下に「5つの属性ボタン」を追加したいので…
生成AIの「Copilot」に丸投げしました。
↓その結果をちょっと調整したモノがこちらです。

これで、元の要素の上にボタンが追加されました。

↓「tkiter」の使い方について、より詳しくしたい方はこちらをご覧ください。

【Python】tkinterモジュールの使い方【UI,作成】
tkinterはPython付属のUIを作るモジュール。ウィジットを「作成」と「配置」する2つの処理を書いてUIを作ります。ボタンやバーなどは操作すると指定した「関数」を実行可能。テキスト入力欄はget()で取得可能。こちらの使い方を解説。

この記事執筆時点では、「tkinter」について

まだ、まとめてないなかったので…
この記事の画面はかなり雑な作りとなりました( ˘ω˘ )

(たぶん、もっと賢い作り方があると思います)

そしたら、ボタンを押した時に特定の”関数”が実行されるような処理を作ります。
右側に「command = (実行したい関数名)」のような形で書きます。
※この段階で、関数名に設定した関数はできてなくて大丈夫です。

そしたら、設定した関数名で処理を作ります。
リセットボタンは random と if を使い、敵の属性を設定できるように設定。
あと、文字関係を初期化する処理を入れて、リセットした感じに見せます。

あと、この処理は関数外で変数宣言。
その後、変数内で「gllobal」= (使用する変数を入力)をしないと動きませんでした。

↓この現象の詳細はこちらでまとめてます。

【Python】変数とグローバル変数の違い【グローバル宣言,global化】
変数は普通に設定するとグローバル変数になりますが、関数の中で変数を設定するとローカル変数になります。ローカル変数はそのままでは関数外に持ち出せません。ローカル変数は「global」というグローバル宣言を行う事で関数外に内容を持ち出せます。

そして、このリセットボタン処理が起動時に実行されるように…
関数名を下の方に書き込みます。
上過ぎると、まだ読み込まれてない変数が登場してエラーを出す原因になります。
(文字表示関係の「Label」などを実行した後じゃないとエラーが出ます)

あとは、5つの属性攻撃ボタンが押された時の処理を作ります。
5つのボタンそれぞれを押した時に実行する関数で設定。
そして、既存ゲームの「5行思想」などを参考に、属性相性を設定。

ボタンを押した時点で、自分の攻撃属性は特定されるので…
あとは、敵の属性との兼ね合いでどのような文字を表示させるかを設定する流れになります。

これで、下gifのような動きになります。

リセットを連打で無属性を出すと… すべて「そこそこのダメージ」になります。
条件分岐が上手く行ってる証拠です。

こちらで完成とします。
↓以下、ソースコード。


# 1 << 0 → 無
# 1 << 1 → 火
# 1 << 2 → 土
# 1 << 3 → 金
# 1 << 4 → 水
# 1 << 5 → 木


#ーーー敵の属性をランダムで読み込みーーー



#変数宣言(グローバル)
Enemy_Data = None
Enemy_Text = None

import random
def Enemy_Element():
    global Enemy_Data, Enemy_Text
    
    Enemy_Element = random.randint(0, 5)

    if Enemy_Element == 0:
        Enemy_Data = 1 << 0
        Enemy_Text = "無属性"
    
    elif Enemy_Element == 1:
        Enemy_Data = 1 << 1
        Enemy_Text = "火属性"
    
    elif Enemy_Element == 2:
        Enemy_Data = 1 << 2
        Enemy_Text = "土属性"
    
    elif Enemy_Element == 3:
        Enemy_Data = 1 << 3
        Enemy_Text = "金属性"
    
    
    elif Enemy_Element == 4:
        Enemy_Data = 1 << 4
        Enemy_Text = "水属性"
     
    elif Enemy_Element == 5:
        Enemy_Data = 1 << 5
        Enemy_Text = "木属性"
        
    else:
        Enemy_Text = "不正な入力"#デバッグ用

    #文字枠1へ送信
    Enemy = "野獣は 「"+ str(Enemy_Text) +"」 だ"
    Label_1.configure(text = Enemy)


    #文字枠2へ送信
    Result = "【 ここに結果が出ます 】"
    ResulText.configure(text = Result)
    
    
#ーーーゲーム処理ーーーー
        

#火属性攻撃をした場合(in - 1 << 1 )
def Attack_Input_1():
    
    if (Enemy_Data & 1 << 3):
        Result = "野獣爆発!"
        
    elif Enemy_Data & 1 << 2:
        Result = "野獣生存"
        
    else :
        Result = "そこそこのダメージ"

    #文字枠2へ送信
    ResulText.configure(text = Result)
        

#土属性攻撃をした場合(in - 1 << 2 )
def Attack_Input_2():
    
    if Enemy_Data & 1 << 4:
        Result = "野獣爆発"
        
    elif Enemy_Data & 1 << 3:
        Result = "野獣生存"
        
    else :
        Result = "そこそこのダメージ"

    #文字枠2へ送信
    ResulText.configure(text = Result)
        

#金属性攻撃をした場合(in - 1 << 3 )    
def Attack_Input_3():
    
    if Enemy_Data & 1 << 5:
        Result = "野獣爆発"
        
    elif Enemy_Data & 1 << 4:
        Result = "野獣生存"

    else :
        Result = "そこそこのダメージ"

    #文字枠2へ送信
    ResulText.configure(text = Result)
        

#水属性攻撃をした場合(in - 1 << 4 )
def Attack_Input_4():
    
    if Enemy_Data & 1 << 1:
        Result = "野獣爆発"
        
    elif Enemy_Data & 1 << 5:
        Result = "野獣生存"
        
    else :
        Result = "そこそこのダメージ"

    #文字枠2へ送信
    ResulText.configure(text = Result)


#木属性攻撃をした場合(in - 1 << 5 )
def Attack_Input_5():
    
    if Enemy_Data & 1 << 2:
        Result = "野獣爆発"
        
    elif Enemy_Data & 1 << 1:
        Result = "野獣生存"
        
    else :
        Result = "そこそこのダメージ"

    #文字枠2へ送信
    ResulText.configure(text = Result)


#ーーー画面生成ーーー

    
import tkinter as tk

WindowX = 600
WindowY = 400


root = tk.Tk()
root.geometry("600x400")
root.title("先輩魔導士の野獣退治")



#文字枠1
Enemy = "野獣は 「"+ str(Enemy_Text) +"」 だ"
Label_1 = tk.Label(text = Enemy)
Label_1.pack(expand=True)


#文字枠2
ResulText = tk.Label(text = "")
ResulText.pack(expand=True)


Label_2 = tk.Label(text = "↓先輩の攻撃!(ここで選択)↓")
Label_2.pack(expand=True)



#ーー スペース調整(力業)ーー
Label_3 = tk.Label(text = "")
Label_3.pack(expand=True)



#ーー初回起動時の敵読み込みーー
Enemy_Element()



#ーー AIで作成したボタン5つ(謎)ーー
def resize(event):
    width = root.winfo_width()
    height = root.winfo_height()
    button_width = width // 5
    Button_1.place(x=0, y=height-50, width=button_width, height=50)
    Button_2.place(x=button_width*1, y=height-50, width=button_width, height=50)
    Button_3.place(x=button_width*2, y=height-50, width=button_width, height=50)
    Button_4.place(x=button_width*3, y=height-50, width=button_width, height=50)
    Button_5.place(x=button_width*4, y=height-50, width=button_width, height=50)
    
root.bind("<Configure>", resize)

Reset = tk.Button(root, text="リセット", command=Enemy_Element)
Reset.place(x=0, y=0)  

Button_1 = tk.Button(root, text="火属性", command=Attack_Input_1)
Button_1.pack(expand=True)

Button_2 = tk.Button(root, text="土属性", command=Attack_Input_2)
Button_2.pack(expand=True)

Button_3 = tk.Button(root, text="金属性", command=Attack_Input_3)
Button_3.pack(expand=True)

Button_4 = tk.Button(root, text="水属性", command=Attack_Input_4)
Button_4.pack(expand=True)

Button_5 = tk.Button(root, text="木属性", command=Attack_Input_5)
Button_5.pack(expand=True)

あとは、ボタンを押す処理を「攻撃イベント」にしたり…
属性との兼ね合いで「文字表示」ではなく「ダメージに特定の倍率設定を入れる」
みたいな感じで処理すれば、ゲームの属性っぽいモノが作れると思います。
( 後 は 各 自 で 頑 張 っ て )

まとめ

今回は、Pythonでビット演算の使い方を紹介しました。

・ビット = PC内部の「0」と「1」を計算する装置1つの単位
・ビット演算を使うと、複数の条件があるモノを手軽に管理できる
・ゲームなどの属性を作る際に役立つ
・ビット演算子をつかうと、入力したビットに変化を加える事ができる
・主に使うのは if &の形で、これを使うと指定したビットが「1」だった場合動かす処理が作れる
・左シフト「<<」を使うと、ビットの表記を簡素化できる
・ビット反転させるなら「NOT(~)」より「XOR(^)」がおすすめ

また、他にもPythonやプログラムについて解説してます。

【Python】__pycache__ファイルを作らない方法
__pycache__はモジュール読み込み時に作られるキャッシュファイルで、プログラムに特殊な処理を入れたり、コマンドプロンプトでpython -Bや「set PYTHONDONTWRITEBYTECODE=1」を使うと作られなくなります。
【Python】.pyファイルを.exeに変換する方法【自作ソフト,デスクトップアプリ開発】
.pyファイルの.exe化は「pyinstaller」を使えばできます。こちらはコマンドプロンプトで導入&操作します。.pyファイルがある場所に移動し「pyinstaller .py --追加情報」を打ち込むだけで動作します。こちらを解説。

ぜひ、こちらもご覧ください。

コメント

タイトルとURLをコピーしました