après avoir passé du temps à chercher un code qui ne crash pas d'entrée de jeu, j'ai trouvé celui ci sur github.
Il n'est pas exempt de bugs mais a quand même un intérêt pédagogique. Je voudrai voir les limites de ce qu'offre les curses,ncurses,unicurses
et autres consoles. Si vous avez un pacman , scrabble ou autres bidouilleries intéressantes pour l'apprentissage des curses , postez donc.
PINGO.PY
#!/usr/bin/python3
"""
Copyright (c) 2013, Jesse Jaara <jesse.jaara@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms,
with or without modification, are permitted provided
that the following conditions are met:
* Redistributions of source code must retain the
above copyright notice, this list of conditions
and the following disclaimer.
* Redistributions in binary form must reproduce
the above copyright notice, this list of conditions
and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
"""
##Error codes
#5: too small screen.
import random
import math
import time
import sys
import platform # Needed to detect if we are running on OSX
import curses
from curses import panel
# We need a workaround for OSX, which doesn't like set_curs() function.
if platform.system() == 'Darwin':
def show_cursor(value):
return True
else:
def show_cursor(value):
curses.curs_set(value)
min_width = 54 # Determinated by header banner
min_height = 20
card_header = {
9: 'P I N G O',
16: ' P I N G O ',
25: 'P I N G O',
36: ' P I N G O ',
49: ' P I N G O '
}
class card:
def __init__(self, size, level, y, x):
self.size = size
self.level = level
self.numbers = []
self.y = y
self.x = x
self.dimension = int(math.sqrt(self.size))
def fill(self):
rints = [i for i in # As in random ints
range(1, int(self.size + ((self.size / 4) * self.level)))]
random.shuffle(rints)
for row in range(0, self.dimension):
self.numbers.append([])
for column in range(0, self.dimension):
self.numbers[row].append(rints[(row*self.dimension+column)])
def draw(self, wnumbers):
for row in range(0, self.dimension):
if row == 0:
cwin.move(self.y, self.x)
cwin.addstr('|' + ('----' * self.dimension)[:-1] + '|')
cwin.move(cwin.getyx()[0] + 1, self.x)
cwin.addstr('| ')
cwin.attron(curses.A_BLINK)
cwin.attron(curses.color_pair(1))
cwin.addstr(card_header[self.size])
cwin.refresh()
cwin.attroff(curses.A_BLINK)
cwin.attroff(curses.color_pair(1))
cwin.addstr(' |')
cwin.move(cwin.getyx()[0] + 1, self.x)
cwin.addstr('|---' * self.dimension + '|')
cwin.move(cwin.getyx()[0] + 1, self.x)
for col in range(0, self.dimension):
if self.numbers[row][col] in wnumbers:
color = 2 # Magenta on black
else:
color = 3 # Green on black
if self.numbers[row][col] >= 10:
cwin.addstr('| ')
cwin.attron(curses.color_pair(color))
cwin.addstr(str(self.numbers[row][col]))
cwin.attroff(curses.color_pair(color))
else:
cwin.addstr('| ')
cwin.attron(curses.color_pair(color))
cwin.addstr(str(self.numbers[row][col]))
cwin.attroff(curses.color_pair(color))
cwin.addstr(' ')
cwin.addstr('|')
cwin.move(cwin.getyx()[0] + 1, self.x)
cwin.addstr('|---' * self.dimension + '|')
def check(self, wnumbers):
vert = 0
horz = 0
topbot = 0
for row in range(0, self.dimension):
if set(self.numbers[row]).issubset(set(wnumbers)):
horz += 1
for col in range(0, self.dimension):
column = []
for row in self.numbers:
column.append(row[col])
if set(column).issubset(set(wnumbers)):
vert += 1
tb_array = []
for i in range(0, self.dimension):
tb_array.append(self.numbers[i][i])
if set(tb_array).issubset(set(wnumbers)):
topbot += 1
tb_array = []
for i in range(0, self.dimension):
tb_array.append(self.numbers[self.dimension - 1 - i][i])
if set(tb_array).issubset(set(wnumbers)):
topbot += 1
return (vert, horz, topbot) # Number of vertical, horizontal and top
# to bottom/left to right (MAX 2) bingos
def get_answer():
mwin.move(mwin.getyx()[0] + 2, 1)
mwin.addstr('q: quit', curses.color_pair(1))
curses.echo()
mwin.move(mwin.getyx()[0] + 1, 1)
mwin.addstr(':> ')
show_cursor(1)
answer = mwin.getstr()
show_cursor(0)
curses.noecho()
if str(answer, 'UTF-8') == 'q':
curses.endwin()
exit(0)
else:
return answer
def menu_size():
mwin.erase() # Make sure the screen is clean
mwin.border()
mwin.move(1, 1)
mwin.addstr('Choose card size:')
for size in card_sizes:
mwin.move(mwin.getyx()[0] + 1, 1)
if size == 25:
mwin.addstr(
' %d:\t%dx%d *' % (size, math.sqrt(size), math.sqrt(size)))
else:
mwin.addstr(
' %d:\t%dx%d' % (size, math.sqrt(size), math.sqrt(size)))
answer = get_answer()
try:
int(answer)
except ValueError:
return (menu_size())
if not int(answer) in card_sizes:
return(menu_size())
else:
return float(answer)
def menu_level(size):
max_level = 1
while int(size + ((size / 4) * (max_level + 1))) < 100:
max_level += 1
mwin.erase() # Make sure the screen is clean
mwin.border()
mwin.move(1, 1)
mwin.addstr('Choose game level:')
mwin.move(mwin.getyx()[0] + 1, 1)
mwin.addstr('MIN:\t1')
mwin.move(mwin.getyx()[0] + 1, 1)
mwin.addstr('MAX:\t%d' % max_level)
answer = get_answer()
try:
int(answer)
except ValueError:
return(menu_level(size))
if not int(answer) in range(1, max_level + 1):
return(menu_level(size))
else:
return float(answer)
def menu_cards(size):
yc = 0 # How many fits to the Y-axis
xc = 0 # How many fits to the X-axis
card_cordinates = [] # List of card's starting points
y_size = int(math.sqrt(size) * 2) + 4
x_size = int(math.sqrt(size) * 4) + 2
while True: # Determinate how many fits to the Y-axis
if (cwin.getmaxyx()[0] - 2) - (yc * y_size) >= y_size:
yc += 1
else:
break
while True: # Determinate how many fits to the X-axis
if (cwin.getmaxyx()[1] - 2) - (xc * x_size) >= x_size:
xc += 1
else:
break
count = yc * xc
mwin.erase() # Make sure the screen is clean
mwin.border()
mwin.move(1, 1)
mwin.addstr('How many cards: ')
mwin.move(mwin.getyx()[0] + 1, 1)
mwin.addstr('MIN: 1')
mwin.move(mwin.getyx()[0] + 1, 1)
mwin.addstr('MAX: %d' % count)
answer = get_answer()
try:
int(answer)
except ValueError:
return(menu_cards(size))
if not int(answer) in range(1, count + 1):
return(menu_cards(size))
else:
i = 0
_x = 0
y = 1
while i < int(answer):
while _x < xc and i < int(answer):
card_cordinates.append([int(y), int((_x * x_size) + 1)])
i += 1
_x += 1
_x = 0
y += int(y_size)
return(card_cordinates)
def draw_scores(win, results): # Touple of 3
win.erase()
win.border()
win.move(1, 1)
win.addstr('Your scores:', curses.color_pair(1))
win.move(win.getyx()[0] + 2, 1)
win.addstr("'|' bingos: ", curses.color_pair(3))
win.move(win.getyx()[0] + 1, 1)
win.addstr("'-' bingos: ", curses.color_pair(3))
win.move(win.getyx()[0] + 1, 1)
win.addstr("'/' bingos: ", curses.color_pair(3))
win.move(win.getyx()[0] - 2, 13)
win.addstr(str(results[0]), curses.color_pair(2))
win.move(win.getyx()[0] + 1, 13)
win.addstr(str(results[1]), curses.color_pair(2))
win.move(win.getyx()[0] + 1, 13)
win.addstr(str(results[2]), curses.color_pair(2))
win.refresh()
def display_scores(results):
rpan.top()
rpan.move(int((HEIGHT - 9) / 2), int((WIDTH - 30) / 2))
rpan.show()
draw_scores(rwin, results)
rwin.move(rwin.getyx()[0] + 1, 1)
rwin.addstr('n: new game | q: quit', curses.color_pair(1))
rwin.move(rwin.getyx()[0] + 1, 1)
curses.echo()
rwin.addstr(':> ')
curses.noecho()
rwin.refresh()
show_cursor(1)
answer = rwin.getstr()
if str(answer, 'UTF-8') == 'q':
curses.endwin()
exit(0)
elif str(answer, 'UTF-8') == 'n':
rpan.hide()
run_game()
else:
return(display_scores(results))
def new_game():
size = menu_size()
level = menu_level(size)
cards = menu_cards(size)
return (size, level, cards)
def init_header():
hwin.erase()
hwin.border()
hwin.move(1, 1)
hwin.addstr(' ' * int((WIDTH - 53) / 2))
hwin.addstr('Welcome to play ')
hwin.attron(curses.A_BLINK)
hwin.attron(curses.color_pair(1))
hwin.addstr(card_header[9])
hwin.attroff(curses.A_BLINK)
hwin.attroff(curses.color_pair(1))
hwin.addstr(' where luck is all you need')
hwin.move(3, 1)
hwin.addstr("Today's lucky numbers are: ")
hwin.refresh()
def results(cards, numbers): # cards = array of cards
x = 0
y = 0
z = 0
for card in cards:
_y, _x, _z = card.check(numbers)
y += _y
x += _x
z += _z
return (y, x, z)
def run_game():
cwin.erase()
cwin.border()
cwin.refresh()
init_header()
size, level, cards = new_game()
myCards = []
for yx in cards:
new_card = card(size, level, yx[0], yx[1])
new_card.fill()
myCards.append(new_card)
wnumbers = [i for i in range(1, int(size + ((size / 4) * level)))]
random.shuffle(wnumbers)
i = 0
drawn = []
position = []
line_buffer = ''
while i < myCards[0].size:
drawn.append(wnumbers[i])
if hwin.getyx()[0] == 4 and hwin.getyx()[1] > (WIDTH - 5):
hwin.move(3, 28)
hwin.addstr(' ' * (WIDTH - 30)) # Clean the 1st wnumber row
hwin.move(3, 28)
hwin.addstr(line_buffer) # write the buffer back on line 1
line_buffer = ''
hwin.move(4, 28)
hwin.addstr(' ' * (WIDTH - 30)) # Clean the 2nd wnumber row
hwin.move(4, 28)
if hwin.getyx()[1] > (WIDTH - 5):
hwin.move(4, 28)
if hwin.getyx()[0] == 4:
if hwin.getyx()[1] == 28:
line_buffer += str(wnumbers[i])
else:
line_buffer += (', ' + str(wnumbers[i]))
if hwin.getyx()[1] == 28:
hwin.addstr(str(wnumbers[i]))
else:
hwin.addstr(', ' + str(wnumbers[i]))
i += 1
position = hwin.getyx()
hwin.move(4, 1)
hwin.attron(curses.color_pair(1))
hwin.addstr('[%d/%d]' % (i, size))
hwin.attroff(curses.color_pair(1))
draw_scores(mwin, results(myCards, drawn))
hwin.move(position[0], position[1])
hwin.refresh()
for myCard in myCards:
myCard.draw(drawn)
cwin.refresh()
time.sleep(1)
display_scores(results(myCards, drawn))
def __main__(screen):
global hwin, cwin, mwin, HEIGHT, WIDTH, card_sizes, rwin, rpan
HEIGHT, WIDTH = screen.getmaxyx()
if HEIGHT < min_height or WIDTH < min_width:
curses.endwin()
sys.stderr.write(
'Your terminal is too small to run this application.\n' +
'If you are on a unix console (not in X11 terminal application,)' +
'you could try to see if there is smaller consolefont awaiable ' +
'and use setfont command to use it.\n')
exit(5) # Too small screen
hwin = screen.subwin(6, WIDTH, 0, 0) # Header and winning numbers
cwin = screen.subwin(HEIGHT - 6, WIDTH - 21, 6, 0) # Players cards
mwin = screen.subwin(14, 21, 6, WIDTH - 21) # Menu and results
rwin = screen.subwin(9, 30, 0, 0) # Panel showing results and asking for
rpan = panel.new_panel(rwin) # if user want a new game
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK)
curses.init_pair(2, curses.COLOR_MAGENTA, curses.COLOR_BLACK)
curses.init_pair(3, curses.COLOR_GREEN, curses.COLOR_BLACK)
card_sizes = []
for size in (3, 4, 5, 6, 7):
if (((size * 2) + 5) <= cwin.getmaxyx()[0] and
((size * 3) + 3) <= cwin.getmaxyx()[1]):
card_sizes.append(size ** 2)
run_game()
curses.wrapper(__main__)
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Matrix-Curses
# See how deep the rabbit hole goes.
# Copyright (c) 2012 Tom Wallroth
#
# Sources on github:
# http://github.com/devsnd/matrix-curses/
#
# licensed under GNU GPL version 3 (or later)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
#
import time
import curses
import random
from collections import namedtuple
import sys
PYTHON2 = sys.version_info.major < 3
########################################################################
# TUNABLES
DROPPING_CHARS = 50
MIN_SPEED = 1
MAX_SPEED = 7
RANDOM_CLEANUP = 100
WINDOW_CHANCE = 50
WINDOW_SIZE = 25
WINDOW_ANIMATION_SPEED = 3
FPS = 25
SLEEP_MILLIS = 1.0/FPS
USE_COLORS = True
SCREENSAVER_MODE = True
if PYTHON2:
# ASCII ONLY FOR PYTHON 2
MATRIX_CODE_CHARS = "'`´\$%&/()=?#+~><:;{}^°"
else:
# FUNKY UTF CHARACTERS FOR PYTHON 3!
MATRIX_CODE_CHARS = "ɀɁɂŧϢϣϤϥϦϧϨϫϬϭϮϯϰϱϢϣϤϥϦϧϨϩϪϫϬϭϮϯϰ߃߄༣༤༥༦༧༩༪༫༬༭༮༯༰༱༲༳༶"
########################################################################
# CODE
COLOR_CHAR_NORMAL = 1
COLOR_CHAR_HIGHLIGHT = 2
COLOR_WINDOW = 3
class FallingChar(object):
matrixchr = list(MATRIX_CODE_CHARS)
normal_attr = curses.A_NORMAL
highlight_attr = curses.A_REVERSE
def __init__(self, width, MIN_SPEED, MAX_SPEED):
self.x = 0
self.y = 0
self.speed = 1
self.char = ' '
self.reset(width, MIN_SPEED, MAX_SPEED)
def reset(self, width, MIN_SPEED, MAX_SPEED):
self.char = random.choice(FallingChar.matrixchr)
self.x = randint(1, width - 1)
self.y = 0
self.speed = randint(MIN_SPEED, MAX_SPEED)
# offset makes sure that chars with same speed don't move all in same frame
self.offset = randint(0, self.speed)
def tick(self, scr, steps):
height, width = scr.getmaxyx()
if self.advances(steps):
# if window was resized and char is out of bounds, reset
self.out_of_bounds_reset(width, height)
# make previous char curses.A_NORMAL
if USE_COLORS:
scr.addch(self.y, self.x, self.char, curses.color_pair(COLOR_CHAR_NORMAL))
else:
scr.addch(self.y, self.x, self.char, curses.A_NORMAL)
# choose new char and draw it A_REVERSE if not out of bounds
self.char = random.choice(FallingChar.matrixchr)
self.y += 1
if not self.out_of_bounds_reset(width, height):
if USE_COLORS:
scr.addch(self.y, self.x, self.char, curses.color_pair(COLOR_CHAR_HIGHLIGHT))
else:
scr.addch(self.y, self.x, self.char, curses.A_REVERSE)
def out_of_bounds_reset(self, width, height):
if self.x > width-2:
self.reset(width, MIN_SPEED, MAX_SPEED)
return True
if self.y > height-2:
self.reset(width, MIN_SPEED, MAX_SPEED)
return True
return False
def advances(self, steps):
if steps % (self.speed + self.offset) == 0:
return True
return False
def step(self, steps, scr):
return -1, -1, None
class WindowAnimation(object):
def __init__(self, x, y):
self.x = x
self.y = y
self.step = 0
def tick(self, scr, steps):
if self.step > WINDOW_SIZE:
#stop window animation after some steps
self.draw_frame(scr, self.x - self.step, self.y - self.step,
self.x + self.step, self.y + self.step,
curses.A_NORMAL)
return False
# clear all characters covered by the window frame
for i in range(WINDOW_ANIMATION_SPEED):
anistep = self.step + i
self.draw_frame(scr, self.x - anistep, self.y - anistep,
self.x + anistep, self.y + anistep,
curses.A_NORMAL, ' ')
#cancel last animation
self.draw_frame(scr, self.x - self.step, self.y - self.step,
self.x + self.step, self.y + self.step,
curses.A_NORMAL)
#next step
self.step += WINDOW_ANIMATION_SPEED
#draw outer frame
self.draw_frame(scr, self.x - self.step, self.y - self.step,
self.x + self.step, self.y + self.step,
curses.A_REVERSE)
return True
def draw_frame(self, scr, x1, y1, x2, y2, attrs, clear_char=None):
if USE_COLORS:
if attrs == curses.A_REVERSE:
attrs = curses.color_pair(COLOR_WINDOW)
h, w = scr.getmaxyx()
for y in (y1, y2):
for x in range(x1, x2+1):
if x < 0 or x > w-1 or y < 0 or y > h-2:
continue
if clear_char is None:
scr.chgat(y, x, 1, attrs)
else:
scr.addch(y, x, clear_char, attrs)
for x in (x1, x2):
for y in range(y1, y2+1):
if x < 0 or x > w-1 or y < 0 or y > h-2:
continue
if clear_char is None:
scr.chgat(y, x, 1, attrs)
else:
scr.addch(y, x, clear_char, attrs)
# we don't need a good PRNG, just something that looks a bit random.
def rand():
# ~ 2 x as fast as random.randint
a = 9328475634
while True:
a ^= (a << 21) & 0xffffffffffffffff;
a ^= (a >> 35);
a ^= (a << 4) & 0xffffffffffffffff;
yield a
r = rand()
def randint(_min, _max):
if PYTHON2:
n = r.next()
else:
n = r.__next__()
return (n % (_max - _min)) + _min
def main():
steps = 0
scr = curses.initscr()
scr.nodelay(1)
curses.curs_set(0)
curses.noecho()
if USE_COLORS:
curses.start_color()
curses.use_default_colors()
curses.init_pair(COLOR_CHAR_NORMAL, curses.COLOR_GREEN, curses.COLOR_BLACK)
curses.init_pair(COLOR_CHAR_HIGHLIGHT, curses.COLOR_WHITE, curses.COLOR_GREEN)
curses.init_pair(COLOR_WINDOW, curses.COLOR_GREEN, curses.COLOR_GREEN)
height, width = scr.getmaxyx()
window_animation = None
lines = []
for i in range(DROPPING_CHARS):
l = FallingChar(width, MIN_SPEED, MAX_SPEED)
l.y = randint(0, height-2)
lines.append(l)
scr.refresh()
while True:
height, width = scr.getmaxyx()
for line in lines:
line.tick(scr, steps)
for i in range(RANDOM_CLEANUP):
x = randint(0, width-1)
y = randint(0, height-1)
scr.addch(y, x, ' ')
if randint(0, WINDOW_CHANCE) == 1:
if window_animation is None:
#start window animation
line = random.choice(lines)
window_animation = WindowAnimation(line.x, line.y)
if not window_animation is None:
still_active = window_animation.tick(scr, steps)
if not still_active:
window_animation = None
scr.refresh()
time.sleep(SLEEP_MILLIS)
if SCREENSAVER_MODE:
key_pressed = scr.getch() != -1
if key_pressed:
raise KeyboardInterrupt()
steps += 1
try:
main()
except KeyboardInterrupt:
curses.endwin()
curses.curs_set(1)
curses.reset_shell_mode()
curses.echo()
Comment fait on des caracteres "funky" comme à la ligne 54 ?
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.