J'ai créé une application Othello en utilisant kivy, une bibliothèque open source pour développer des applications multi-tap en Python. Enfin, je l'ai construit avec (xcode) dans le simulateur iOS.
python: 3.7.7 kivy: 1.11.1 xcode: 11.7
Formulaire rempli
J'expliquerai en suivant l'ordre dans lequel l'application Othello créée cette fois a été développée.
Créer jusqu'à l'état suivant
class OthelloApp(App):
title = 'Othello'
def build(self):
return OthelloGrid()
OthelloApp().run()
Retour de la classe OthelloGrid dans la classe APP. Le traitement de cette application se fait dans cette classe OthelloGrid.
class OthelloGrid(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.num = 8
self.tile = [[' ' for x in range(self.num)] for x in range(self.num)]
self.turn = 'W'
self.grid = GridLayout(cols=self.num, spacing=[3,3], size=(Window.width, Window.height))
for x in range(self.num):
for y in range(self.num):
if x == 3 and y == 3 or x == 4 and y == 4:
self.grid.add_widget(WhiteStone())
self.tile[x][y] = 'W'
elif x == 4 and y == 3 or x == 3 and y == 4:
self.grid.add_widget(BlackStone())
self.tile[x][y] = 'B'
else:
self.grid.add_widget(PutButton(background_color=(0.451,0.3059,0.1882,1), background_normal='', tile_id=[x, y]))
self.add_widget(self.grid)
self.num
est le nombre de carrés verticaux et horizontaux sur le plateau d'Othello.
self.tile
est une liste pour mémoriser l'état du tableau. Lorsque le blanc est placé'W'
, lorsque le noir est placé
B', rien n'est placé. Prend la valeur de quand `` '' '.
self.turnse souvient si le virage actuel est noir ou blanc et commence initialement par un virage blanc. Le plateau qui est réellement dessiné sur l'écran est défini par
self.grid (GridLayout), et pour le carré où la pierre est déjà placée, la
classe WhiteStone pour les pierres blanches et la classe
BlackStone pour les pierres noires. On ajoute_widget ʻet add_widget PutButton class
aux carrés où aucune pierre n'a encore été placée.
class WhiteStone(Label):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.bind(pos=self.update)
self.bind(size=self.update)
self.update()
def update(self, *args):
self.canvas.clear()
self.canvas.add(Color(0.451,0.3059,0.1882,1))
self.canvas.add(Rectangle(pos=self.pos, size=self.size))
self.canvas.add(Color(1,1,1,1))
self.canvas.add(Ellipse(pos=self.pos, size=self.size))
class BlackStone(Label):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.bind(pos=self.update)
self.bind(size=self.update)
self.update()
def update(self, *args):
self.canvas.clear()
self.canvas.add(Color(0.451,0.3059,0.1882,1))
self.canvas.add(Rectangle(pos=self.pos, size=self.size))
self.canvas.add(Color(0,0,0,1))
self.canvas.add(Ellipse(pos=self.pos, size=self.size))
class PutButton(Button):
def __init__(self, tile_id, **kwargs):
super().__init__(**kwargs)
self.tile_id = tile_id
Les classes WhiteStone
et BlackStone
héritent de la classe Label et ont simplement une pierre elliptique ʻEllipse (pos = self.pos) au-dessus de la masse Rectangle (pos = self.pos, size = self.size)
. , size = self.size) ʻest juste dessiné.
La classe PutButton
hérite de la classe Button, et il n'y a pas de traitement lorsqu'elle est encore enfoncée.
En tant que tile_id
, l'instance elle-même peut se souvenir de la position sur la grille
.
Créer jusqu'à l'état suivant
Créez une fonction ʻon_press dans la classe
PutButton` comme indiqué ci-dessous, et ajoutez le traitement lorsque la cellule est tapée.
Classe PutButton
def on_press(self):
put_x = self.tile_id[0]
put_y = self.tile_id[1]
turn = self.parent.parent.turn
self.parent.parent.tile[put_x][put_y] = turn
self.parent.parent.put_stone()
Remplacez "put_x" et "put_y" par le numéro de cellule tapé et remplacez le tour actuel par "turn".
Appelez la fonction put_stone
en affectant la valeur de turn
à l'emplacement de la cellule tapée de tile
dans la classe parent (ʻOthelloGrid).
put_stone est une fonction créée dans ʻOthello Grid
comme indiqué ci-dessous, et est une fonction pour recréer le tableau à partir du contenu de tile
.
Classe OthelloGrid
def put_stone(self):
self.clear_widgets()
self.grid = GridLayout(cols=self.num, spacing=[3,3], size=(Window.width, Window.height))
next_turn = 'W' if self.turn == 'B' else 'B'
for x in range(self.num):
for y in range(self.num):
if self.tile[x][y] == 'W':
self.grid.add_widget(WhiteStone())
elif self.tile[x][y] == 'B':
self.grid.add_widget(BlackStone())
else:
self.grid.add_widget(PutButton(background_color=(0.451,0.3059,0.1882,1), background_normal='', tile_id=[x, y]))
Créer jusqu'à l'état suivant
Ajoutez les fonctions can_reverse_check
et reverse_list
à la classe ʻOthelloGrid` pour vérifier s'il y a des pierres qui peuvent être retournées à partir des coordonnées de la masse et du tour actuel comme indiqué ci-dessous.
Classe OthelloGrid
def can_reverse_check(self, check_x, check_y, turn):
check =[]
#Confirmation en haut à gauche
check += self.reverse_list(check_x, check_y, -1, -1, turn)
#Confirmé ci-dessus
check += self.reverse_list(check_x, check_y, -1, 0, turn)
#Confirmation en haut à droite
check += self.reverse_list(check_x, check_y, -1, 1, turn)
#Bonne confirmation
check += self.reverse_list(check_x, check_y, 0, 1, turn)
#Confirmation en bas à droite
check += self.reverse_list(check_x, check_y, 1, 1, turn)
#Vérifiez ci-dessous
check += self.reverse_list(check_x, check_y, 1, 0, turn)
#Confirmation en bas à gauche
check += self.reverse_list(check_x, check_y, 1, -1, turn)
#Confirmation gauche
check += self.reverse_list(check_x, check_y, 0, -1, turn)
return check
def reverse_list(self, check_x, check_y, dx, dy, turn):
tmp = []
while True:
check_x += dx
check_y += dy
if check_x < 0 or check_x > 7:
tmp = []
break
if check_y < 0 or check_y > 7:
tmp = []
break
if self.tile[check_x][check_y] == turn:
break
elif self.tile[check_x][check_y] == ' ':
tmp = []
break
else:
tmp.append((check_x, check_y))
return tmp
can_reverse_check
appelle reverse_list
, qui est une fonction pour vérifier s'il y a une pierre qui peut être retournée dans chaque direction à partir du carré où la pierre doit être placée.
En tant que valeur de retour, une liste des coordonnées des pierres qui peuvent être retournées est renvoyée.
Comme indiqué ci-dessous, ce can_reverse_check
est appelé lorsque la classe PutButton
est tapée (dans ʻon_press), et s'il y a un contenu dans la liste des valeurs de retour, la valeur de
tileest mise à jour et le tableau est affiché. Recréez (appelez
put_stone`).
Si la liste est vide, ne faites rien.
Classe PutButton
def on_press(self):
put_x = self.tile_id[0]
put_y = self.tile_id[1]
check =[]
turn = self.parent.parent.turn
check += self.parent.parent.can_reverse_check(self.tile_id[0], self.tile_id[1], turn)
if check:
self.parent.parent.tile[put_x][put_y] = turn
for x, y in check:
self.parent.parent.tile[x][y] = turn
self.parent.parent.put_stone()
Fonction de passage quand il n'y a pas de place pour mettre des pierres
Jugement gagnant / perdant à la fin de la partie
ʻExtend the put_stone
de la classe OthelloGrid` comme suit
Classe OthelloGrid
def put_stone(self):
pass_flag = True
finish_flag = True
check = []
self.clear_widgets()
self.grid = GridLayout(cols=self.num, spacing=[3,3], size=(Window.width, Window.height))
next_turn = 'W' if self.turn == 'B' else 'B'
for x in range(self.num):
for y in range(self.num):
if self.tile[x][y] == 'W':
self.grid.add_widget(WhiteStone())
elif self.tile[x][y] == 'B':
self.grid.add_widget(BlackStone())
else:
self.grid.add_widget(PutButton(background_color=(0.451,0.3059,0.1882,1), background_normal='', tile_id=[x, y]))
for x in range(self.num):
for y in range(self.num):
if self.tile[x][y] == ' ':
finish_flag = False
check += self.can_reverse_check(x, y, next_turn)
if check:
pass_flag = False
break
if finish_flag:
content = Button(text=self.judge_winner())
popup = Popup(title='Game set!', content=content, auto_dismiss=False, size_hint=(None, None), size=(Window.width, Window.height/3))
content.bind(on_press=popup.dismiss)
popup.open()
else:
if pass_flag:
skip_turn_text = 'White Turn' if self.turn == 'B' else 'Black Turn'
content = Button(text='OK')
popup = Popup(title=skip_turn_text+' Skip!', content=content, auto_dismiss=False, size_hint=(None, None), size=(Window.width, Window.height/3))
content.bind(on_press=popup.dismiss)
popup.open()
else:
self.turn = next_turn
self.add_widget(self.grid)
Préparez pass_flag
et finish_flag
et utilisez-les pour juger de la réussite ou de la fin de la partie.
Pour toutes les cases vides de «tuile» (cases avec une valeur de «» »), vérifiez s'il y a une pierre à retourner lorsque le joueur pose une pierre sur cette case au tour suivant. Sinon, sautez le tour suivant.
À ce moment-là, affichez sur l'écran que vous avez ignoré avec Popup.
S'il n'y a pas d'espace vide dans tile
, on considère que le jeu est terminé, et la fonction juge_winner
suivante détermine celui qui gagne et l'affiche à l'écran avec Popup.
Classe OthelloGrid
def judge_winner(self):
white = 0
black = 0
for x in range(self.num):
for y in range(self.num):
if self.tile[x][y] == 'W':
white += 1
elif self.tile[x][y] == 'B':
black += 1
print(white)
print(black)
return 'White Win!' if white >= black else 'Black Win!'
C'est la fin du traitement d'Othello.
Nous avons également ajouté ResetButton et une étiquette qui affiche le virage, mais veuillez vérifier l'intégralité du code source ci-dessous pour cette zone. (Je le donne aussi à git. Https://github.com/fu-yuta/kivy-project/tree/master/Othello)
main.py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from kivy.graphics import Color, Ellipse, Rectangle
class OthelloGrid(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.num = 8
self.tile = [[' ' for x in range(self.num)] for x in range(self.num)]
self.turn = 'W'
self.grid = GridLayout(cols=self.num, spacing=[3,3], size_hint_y=7)
for x in range(self.num):
for y in range(self.num):
if x == 3 and y == 3 or x == 4 and y == 4:
self.grid.add_widget(WhiteStone())
self.tile[x][y] = 'W'
elif x == 4 and y == 3 or x == 3 and y == 4:
self.grid.add_widget(BlackStone())
self.tile[x][y] = 'B'
else:
self.grid.add_widget(PutButton(background_color=(0.451,0.3059,0.1882,1), background_normal='', tile_id=[x, y]))
self.creat_view('White Turn')
def put_stone(self):
self.grid = GridLayout(cols=self.num, spacing=[3,3], size_hint_y=7)
pass_flag = True
finish_flag = True
check = []
next_turn = 'W' if self.turn == 'B' else 'B'
for x in range(self.num):
for y in range(self.num):
if self.tile[x][y] == 'W':
self.grid.add_widget(WhiteStone())
elif self.tile[x][y] == 'B':
self.grid.add_widget(BlackStone())
else:
self.grid.add_widget(PutButton(background_color=(0.451,0.3059,0.1882,1), background_normal='', tile_id=[x, y]))
for x in range(self.num):
for y in range(self.num):
if self.tile[x][y] == ' ':
finish_flag = False
check += self.can_reverse_check(x, y, next_turn)
if check:
pass_flag = False
break
if finish_flag:
content = Button(text=self.judge_winner())
popup = Popup(title='Game set!', content=content, auto_dismiss=False, size_hint=(None, None), size=(Window.width, Window.height/3))
content.bind(on_press=popup.dismiss)
popup.open()
self.restart_game()
else:
if pass_flag:
skip_turn_text = 'White Turn' if self.turn == 'B' else 'Black Turn'
content = Button(text='OK')
popup = Popup(title=skip_turn_text+' Skip!', content=content, auto_dismiss=False, size_hint=(None, None), size=(Window.width, Window.height/3))
content.bind(on_press=popup.dismiss)
popup.open()
else:
self.turn = next_turn
turn_text = 'Black Turn' if self.turn == 'B' else 'White Turn'
self.creat_view(turn_text)
def can_reverse_check(self, check_x, check_y, turn):
check =[]
#Confirmation en haut à gauche
check += self.reverse_list(check_x, check_y, -1, -1, turn)
#Confirmé ci-dessus
check += self.reverse_list(check_x, check_y, -1, 0, turn)
#Confirmation en haut à droite
check += self.reverse_list(check_x, check_y, -1, 1, turn)
#Bonne confirmation
check += self.reverse_list(check_x, check_y, 0, 1, turn)
#Confirmation en bas à droite
check += self.reverse_list(check_x, check_y, 1, 1, turn)
#Vérifiez ci-dessous
check += self.reverse_list(check_x, check_y, 1, 0, turn)
#Confirmation en bas à gauche
check += self.reverse_list(check_x, check_y, 1, -1, turn)
#Confirmation gauche
check += self.reverse_list(check_x, check_y, 0, -1, turn)
return check
def reverse_list(self, check_x, check_y, dx, dy, turn):
tmp = []
while True:
check_x += dx
check_y += dy
if check_x < 0 or check_x > 7:
tmp = []
break
if check_y < 0 or check_y > 7:
tmp = []
break
if self.tile[check_x][check_y] == turn:
break
elif self.tile[check_x][check_y] == ' ':
tmp = []
break
else:
tmp.append((check_x, check_y))
return tmp
def judge_winner(self):
white = 0
black = 0
for x in range(self.num):
for y in range(self.num):
if self.tile[x][y] == 'W':
white += 1
elif self.tile[x][y] == 'B':
black += 1
print(white)
print(black)
return 'White Win!' if white >= black else 'Black Win!'
def restart_game(self):
print("restart game")
self.tile = [[' ' for x in range(self.num)] for x in range(self.num)]
self.turn = 'W'
self.grid = GridLayout(cols=self.num, spacing=[3,3], size_hint_y=7)
for x in range(self.num):
for y in range(self.num):
if x == 3 and y == 3 or x == 4 and y == 4:
self.grid.add_widget(WhiteStone())
self.tile[x][y] = 'W'
elif x == 4 and y == 3 or x == 3 and y == 4:
self.grid.add_widget(BlackStone())
self.tile[x][y] = 'B'
else:
self.grid.add_widget(PutButton(background_color=(0.451,0.3059,0.1882,1), background_normal='', tile_id=[x, y]))
self.creat_view('White Turn')
def creat_view(self, turn_text):
self.clear_widgets()
self.turn_label = Label(text=turn_text, width=Window.width , size_hint_y=1, font_size='30sp')
self.restart_button = RestartButton(text='Restart')
self.layout = BoxLayout(orientation='vertical', spacing=10, size=(Window.width, Window.height))
self.layout.add_widget(self.turn_label)
self.layout.add_widget(self.grid)
self.layout.add_widget(self.restart_button)
self.add_widget(self.layout)
class WhiteStone(Label):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.bind(pos=self.update)
self.bind(size=self.update)
self.update()
def update(self, *args):
self.canvas.clear()
self.canvas.add(Color(0.451,0.3059,0.1882,1))
self.canvas.add(Rectangle(pos=self.pos, size=self.size))
self.canvas.add(Color(1,1,1,1))
self.canvas.add(Ellipse(pos=self.pos, size=self.size))
class BlackStone(Label):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.bind(pos=self.update)
self.bind(size=self.update)
self.update()
def update(self, *args):
self.canvas.clear()
self.canvas.add(Color(0.451,0.3059,0.1882,1))
self.canvas.add(Rectangle(pos=self.pos, size=self.size))
self.canvas.add(Color(0,0,0,1))
self.canvas.add(Ellipse(pos=self.pos, size=self.size))
class PutButton(Button):
def __init__(self, tile_id, **kwargs):
super().__init__(**kwargs)
self.tile_id = tile_id
def on_press(self):
print(self.tile_id)
put_x = self.tile_id[0]
put_y = self.tile_id[1]
check =[]
turn = self.parent.parent.parent.turn
check += self.parent.parent.parent.can_reverse_check(self.tile_id[0], self.tile_id[1], turn)
if check:
self.parent.parent.parent.tile[put_x][put_y] = turn
for x, y in check:
self.parent.parent.parent.tile[x][y] = turn
self.parent.parent.parent.put_stone()
class RestartButton(Button):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def on_press(self):
content = Button(text='OK')
popup = Popup(title='Restart Game!', content=content, auto_dismiss=False, size_hint=(None, None), size=(Window.width, Window.height/3))
content.bind(on_press=popup.dismiss)
popup.open()
self.parent.parent.restart_game()
class OthelloApp(App):
title = 'Othello'
def build(self):
return OthelloGrid()
OthelloApp().run()
J'ai fait référence à l'article suivant. https://qiita.com/sobassy/items/b06e76cf23046a78ba05
Si l'outil de ligne de commande Xcode n'est pas inclus, exécutez la commande suivante.
xcode-select --install
Installer les dépendances
brew install autoconf automake libtool pkg-config
brew link libtool
Installez Cython
pip install cython
git clone kivy-ios.
git clone https://github.com/kivy/kivy-ios.git
cd kivy-ios
Exécutez la commande suivante pour générer kivy pour iOS (cela peut prendre des dizaines de minutes)
python toolchain.py build kivy
Une fois ce qui précède terminé, créez le programme kivy pour Xcode.
python toolchain.py create [Nom du projet Xcode (n'importe quel nom)] [nom du dossier du programme kivy]
À ce stade, le nom du fichier programme kivy doit être «main.py».
Si le nom du projet Xcode est ʻApp, un répertoire appelé ʻApp-ios
est créé et ʻApp.xcodeproj` est créé dans ce répertoire.
Ouvrez ce projet dans Xcode.
open App.xcodeproj
Si vous spécifiez Simulator dans Xcode et que vous le construisez, l'application démarre. Si vous mettez à jour le programme kivy, vous devez également mettre à jour le projet Xcode avec la commande suivante.
python toolchain.py update App
J'ai créé une application Othello en utilisant kivy, l'une des bibliothèques python, et l'ai construite avec Simulater sur iOS. Cette fois, j'ai écrit tout le traitement dans main.py, mais kivy est un langage kv, et wighet etc. peut être écrit séparément, donc j'aimerais envisager de porter vers cela. De plus, nous aimerions intégrer l'IA d'Othello et ajouter une fonction de combat joueur-processeur à l'avenir.
https://qiita.com/sobassy/items/b06e76cf23046a78ba05 https://github.com/PrestaMath/reverse_tile
Recommended Posts