LoginSignup
2
0

More than 1 year has passed since last update.

にゃんこスイーパー

Last updated at Posted at 2022-12-31

Python+Cursesで、にゃんこスイーパーを書いてみました。
Ubuntuのターミナルで動きます。
ファイルに、chmod +x nyankosweeper.pyとして、実行権を付けて動かして下さい。

$./nyankosweeper.py [number of cats]として、動かします。
[number of cats]は、省略できます。省略すると、猫の数は56個となります。

スペースキーで、開き、’z’キーで、マークを付けます。カーソルは矢印キーで動かします。
’q’キーで抜け出せられます。

pyinstallerで、コンパイルできます。コンパイルしなくとも、そもそも速度はあんまり問題ないですが。

nyankosweeper.py
#!/usr/bin/python3

import curses
import random
import locale
import select
import sys


xsize = 40
ysize = 23
vvram = [[0 for i in range(ysize)] for j in range(xsize)]
mask = [["" for i in range(ysize)] for j in range(xsize)]
itod = " 123456789"
ac = "#😺?"

def getkey():
    c = stdscr.getkey()
    return c


def putchar(x, y, a):
    stdscr.addstr(y, x*2, a, curses.A_REVERSE)


def putcharr(x, y, a):
    stdscr.addstr(y, x*2, a)


def putmines(n):
    for i in range(n):
        while(True):
            (x, y) = (random.randint(0, xsize-1), random.randint(0, ysize-1))
            if (vvram[x][y] == 0):
                vvram[x][y] = '*'
                break
#


def calccell(x, y):
    if (vvram[x][y] == 0):
        cnt = 0
        for dx in range(-1, 2):
            for dy in range(-1, 2):
                if x+dx >= 0 and y+dy >= 0 and x+dx < xsize and y+dy < ysize:
                    cnt += 1 if vvram[x+dx][y+dy] == '*' else 0
        vvram[x][y] = cnt
        return(cnt)


def reveal(x, y):
    if mask[x][y] != ' ':
        mask[x][y] = ' '
        if vvram[x][y] == 0:
            for dx in range(-1, 2):
                for dy in range(-1, 2):
                    if x+dx >= 0 and y+dy >= 0 and x+dx < xsize and y+dy < ysize:
                        reveal(x+dx, y+dy)


def cursor(x, y):
    putcharr(x, y, retchar(x, y))


def printmines():
    for x in range(xsize):
        for y in range(ysize):
            c = vvram[x][y]
            if c == '*':
                putchar(x, y, "😻")
            elif (c >= 0 and c <= 9):
                putchar(x, y, itod[c])


def retchar(x, y):
    m = mask[x][y]
    if m in ac:
        return(m)
    else:
        c = vvram[x][y]
        if c >= 0 and c <= 9:
            return(itod[c])


def drawchar(x, y):
    putchar(x, y, retchar(x, y))


def drawscreen():
    for x in range(xsize):
        for y in range(ysize):
            drawchar(x, y)


def calcfield():
    for x in range(xsize):
        for y in range(ysize):
            calccell(x, y)


def endcheck():
    c = 0
    for x in range(xsize):
        for y in range(ysize):
            c += 1 if mask[x][y] in ac else 0
    return(c == mines)


def mainloop():
    (x, y) = (xsize//2, ysize//2)
    while True:
        drawscreen()
        if endcheck():
            printmines()
            putchar(0, 23, "You win. hit key")
            getkey()
            return(0)
        cursor(x, y)
        stdscr.refresh()
        c = getkey()
        if c in ('4','h',"KEY_LEFT"):
            x = x-(1 if x != 0 else 0)
        elif c in ( '6',"l","KEY_RIGHT"):
            x = x+(1 if x != xsize-1 else 0)
        elif c in ('8',"k","KEY_UP"):
            y = y-(1 if y != 0 else 0)
        elif c in ('2',"j","KEY_DOWN"):
            y = y+(1 if y != ysize-1 else 0)
        elif (c == 'z' or c=='m') and mask[x][y] != ' ':
            mask[x][y] = ac[(ac.index(mask[x][y])+1) % 3]
        elif c == ' ':
            if vvram[x][y] == '*':
                printmines()
                putchar(x, y, "")
                putchar(0, 23, "You lose. hit key")
                getkey()
                return(-1)
            reveal(x, y)
        elif c == 'q':
            return(1)


def game():
    putmines(mines)
    calcfield()
    mainloop()
    return

def main():
    try:
        game()
    except KeyboardInterrupt:
        pass
    else:
        return

def getv():
    argvs = sys.argv
    argc = len(argvs)
    m = 56

    if argc == 2:
        try:
            m = int(sys.argv[1])
            if m > 300:
                print('too many nyankos')
                exit(0)
        except ValueError:
            print('not a number')
            exit(0)
    return(m)

mines = getv()
locale.setlocale(locale.LC_ALL, '')
stdscr = curses.initscr()
stdscr.keypad(True)
curses.curs_set(0)
main()
curses.endwin()
del stdscr
2
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
2
0