Voilà une première version de ma participation en Python 3 pur (aucune dépendance nécessaire).
Il écrit son animation aléatoire dans un GIF animé, comme celui-ci :
J'ai commencé à m'amuser un peu avec les patterns mais globalement le code est encore direct et non-obfusqué (bref, encore lisible).
#!/usr/bin/env python3
from random import choice, randrange as rand
PATTERNS=(((0,0,2,0,2,0,0, ## ##
0,2,2,2,2,2,0, ##########
0,2,0,2,0,2,0, ## ## ##
0,2,0,2,0,2,0, ## ## ##
2,2,2,2,2,2,2, ##############
2,0,2,0,2,0,2), ## ## ## ##
(16,23),(18,25)),
((0,0,0,2,2,0,0,0, ####
0,0,2,2,2,2,0,0, ########
0,2,0,2,2,0,2,0, ## #### ##
2,2,0,2,2,0,2,2, #### #### ####
2,2,2,2,2,2,2,2, ################
0,0,2,0,0,2,0,0, ## ##
0,2,0,2,2,0,2,0, ## #### ##
2,0,2,0,0,2,0,2), ## ## ## ##
(18,26),(21,29)),
((0,0,0,2,2,0,0,0, ####
0,0,2,2,2,2,0,0, ########
0,2,0,2,2,0,2,0, ## #### ##
2,2,0,2,2,0,2,2, #### #### ####
2,2,2,2,2,2,2,2, ################
0,2,0,2,2,0,2,0, ## #### ##
2,0,0,0,0,0,0,2, ## ##
0,2,0,0,0,0,2,0), ## ##
(18,26),(21,29)),
((0,0,2,0,0,0,0,0,2,0,0, ## ##
0,0,0,2,0,0,0,2,0,0,0, ## ##
0,0,2,2,2,2,2,2,2,0,0, ##############
0,2,2,0,2,2,2,0,2,2,0, #### ###### ####
2,2,2,0,2,2,2,0,2,2,2, ###### ###### ######
2,0,2,2,2,2,2,2,2,0,2, ## ############## ##
2,0,2,0,0,0,0,0,2,0,2, ## ## ## ##
0,0,0,2,2,0,2,2,0,0,0), #### ####
(36,47),(40,51)),
((0,0,0,0,2,2,2,2,0,0,0,0, ########
0,2,2,2,2,2,2,2,2,2,2,0, ####################
2,2,2,2,2,2,2,2,2,2,2,2, ########################
2,2,2,0,0,2,2,0,0,2,2,2, ###### #### ######
2,2,2,2,2,2,2,2,2,2,2,2, ########################
0,0,0,2,2,0,0,2,2,0,0,0, #### ####
0,0,2,2,0,2,2,0,2,2,0,0, #### #### ####
2,2,0,0,0,0,0,0,0,0,2,2), #### ####
(39,40),(43,44)))
HDR = bytes([0x47,0x49,0x46,0x38,0x39,0x61,0x20,0x03,0x58,0x02,0xC1,
0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0x00,
0x00,0x00,0xFF,0x21,0xFF,0x0B,0x4e,0x45,0x54,0x53,0x43,
0x41,0x50,0x45,0x32,0x2e,0x30,0x03,0x01,0x00,0x00,0x00,
0x21,0xF9,0x04,0x09,0x01,0x00,0x00,0x00,0x2C,0x00,0x00,
0x00,0x00,0x20,0x03,0x58,0x02,0x81,0xFF,0xFF,0xFF,0x00,
0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0xFF])
def lzw(stream, bpp):
table, CC, bits = {}, 1 << bpp, bpp + 1
EOI, code, cmax = CC+1, CC+2, 1<< bits
bb, off, pixnum = 0, 0, 0
res, buf = bytearray([bpp]), bytearray()
def pack(c=None):
nonlocal bb, off, cmax, bits, res, buf
if c is None:
while bb > 0:
buf, bb, off = buf + bytes([bb & 0xFF]), bb >> 8, off-8
res, buf = res + bytes([len(buf)]) + buf, bytearray()
else:
bb |= (c << off) & 0xffffffff
off += bits
while off >= 8:
buf, bb, off = buf + bytes([bb & 0xFF]), bb >> 8, off - 8
if len(buf) == 255:
res, buf = res + bytes([len(buf)]) + buf, bytearray()
if code >= cmax and c <= 0xFFF:
bits = bits + 1
cmax = 1 << bits
pack(CC)
cur = stream[0]
for pixel in stream[1:]:
key = (cur << 8) | pixel
if key in table:
cur = table[key]
else:
pack(cur)
cur = pixel
if code >= 0xFFF:
pack(CC)
code, bits = CC + 2, bpp + 1
cmax, table = 1 << bits, {}
else:
table[key], code = code, code + 1
pack(cur)
pack(EOI)
pack()
res.append(0)
return res
def mk_hdr(w, h):
xo, yo = rand(800-w), rand(600-h)
xm, xl = xo >> 8, xo & 0xff
ym, yl = yo >> 8, yo & 0xff
wm, wl = w >> 8, w & 0xff
hm, hl = h >> 8, h & 0xff
r, g, b = rand(256), rand(256), rand(256)
return bytes([0x21,0xF9,0x04,0x09,0x48,0x00,0x00,0x00,0x2C,
xl,xm,yl,ym,wl,wm,hl,hm,0x81,0xFF,0xFF,0xFF,
0x00,0x00,0x00,r,g,b,0x00,0x00,0xFF])
def inflate(data, w, h, ss):
new_img = [0] * w * ss * h * ss
for x in range(1,ss-1):
for y in range(1,ss-1):
for i in range(w):
for j in range(h):
new_img[w * ss * (y + j * ss) + ss * i + x] = data[w * j + i]
return new_img
def mk_pat():
p,lp,rp = choice(PATTERNS)
pat = list(p)
pat[choice(lp)] = pat[choice(rp)] = 1
return pat
def mk_img():
p = mk_pat()
pw, ph = {42:(7,6),64:(8,8),96:(12,8),88:(11,8)}[len(p)]
ss = rand(12,28)
return mk_hdr(pw*ss,ph*ss) + lzw(inflate(p,pw,ph,ss),2)
img = open('space_invader.gif', 'wb')
img.write(HDR + lzw([0] * 800 * 600, 2))
for _ in range(20):
img.write(mk_img())
img.write(bytes([0x3b]))
img.close()
Histoire que ça soit un peu un challenge, je me suis donné comme contrainte de coder complètement la génération de l'image. Ça m'aura fait découvrir l'algo de compression LZW (et la façon dont il est implémenté dans le format GIF).
J'éditerai peut-être quand j'aurai pris un peu plus de temps pour obfusquer le code. Mais en attendant je me suis dit que le poster tel quel pourrait en intéresser certains.
Bon la je fait dans la catégorie le code plus inutilement compliqué, je l'ai amélioré pour gérer plusieurs Invaders, avec chacun sa couleur, son type (au passage, j'ai rajouté 2 types d'invaders).
Pour éviter que ça fasse une bouillie de pixels, j'ai mis une gestion des collisions, avec tout de même une limite pour éviter de surcharger le proc.
La page se trouve ici, vous pouvez fouiller dans mon code, j'ai relativement bien commenté (en tout cas plus que d'habitude ^^).
Je projette encore de faire une version géré par NodeJS, et que la position/la couleur/le type/le spawn des invaders se fasse coté serveur, et que du coup, via des WebSockets, qu'il y ai la même chose chez tout le monde en même temps
Deux corps différents (c'était juste pour pas en avoir qu'un) et les 4 types d'yeux. Change toutes les 3 secondes, Control + Q pour quitter. C'est pas beau (ni le rendu ni le code, d'ailleurs) mais ça fait ce qu'on lui demande :3.
space invaders :
bloc :: rectangle, largeur=10, hauteur=10, plein="oui"
début
tant que vrai, lis
x & y <- hasard(500)
couleur@bloc = couleurs{hasard(x/2)}
pour chaque {2,4,8,9,10,11,12,15,17,19,22,24,26,28,29,30,31,32,33,34,35,37,39,41}, lis
x@bloc = x + joker mod 7*11; y@bloc = y + entier(joker/7)*11
projette clone(bloc)
ferme
couleur@bloc = "noir"
x@bloc = x + 2 * 11; y@bloc = y + (2 + x mod 2) * 11
projette clone(bloc)
x@bloc = x + 4 * 11; y@bloc = y + (2 + y mod 2) * 11
projette clone(bloc)
attends 1 seconde
efface toile
ferme
Et voilà le résultat :
Ajouté le 28 avril, une version extra courte inspirée de l'algo de emixam150 :
b:
x&y<-hasard 500
b::rectangle,largeur=8,hauteur=8,plein="oui",couleur=couleurs{x/2}
début
projette b
pour chaque {2,4,8,9,10,11,12,15,17,19,22,24,26,28,29,30,31,32,33,34,35,37,39,41},lis
x@b=x+joker mod 7*9;y@(#b)=y+entier(joker/7)*9
ferme
couleur@b=0;x@b=x+18;y@(#b)=y+(2+x mod 2)*9;x@b=x+36;y@b=y+(2+y mod 2)*9
attends 1 seconde;efface toile
va vers b
Génial ton GIF nohar ! Joli boulot, surtout le fait de coder le GIF en "bas niveau" sans bibliothèque adaptée.
Bon, j'ai vu que personne ne l'avait fait en Java, alors je me suis dit que c'était nécessaire. En temps normal, je suis plutôt HTML/CSS/JS (et ça peut paraître bizarre, j'aime pas Java). Je me suis basé sur la librairie StdDraw de l'université de Princeton, elle même basée sur AWT.
Voilà le JAR : https://www.dropbox.com/s/zfnltnu1d4z15x0/Invaders.jar
Sous Windows un double-clic devrait suffire, sous Linux : java -jar Invaders.jar
import java.awt.Dimension;
import java.awt.Color;
import java.util.Random;
import java.lang.Thread;
class Invaders
{
public static void main(String[] args)
{
Random rdm = new Random(System.nanoTime());
Dimension screenDim = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
StdDraw.setCanvasSize((int)screenDim.getWidth(), (int)screenDim.getHeight());
StdDraw.setXscale(0, screenDim.getWidth());
StdDraw.setYscale(0, screenDim.getHeight());
Invader invader;
int size, posX, posY;
while(true)
{
invader = new Invader(rdm.nextInt(25) + 50);
posX = rdm.nextInt((int)screenDim.getWidth() - Invader.invaderShape[0].length * (invader.squaresSize+5));
posY = rdm.nextInt((int)screenDim.getHeight() - Invader.invaderShape.length * (invader.squaresSize+5));
invader.draw(posX, posY);
try
{
Thread.sleep(3000);
}
catch(java.lang.Exception e)
{}
StdDraw.clear();
}
}
}
class Invader
{
public int squaresSize;
public Color color;
public static int[][] invaderShape = {{0,0,1,0,1,0,0},{0,1,1,1,1,1,0},{0,1,2,1,2,1,0},{0,1,0,1,0,1,0},{1,1,1,1,1,1,1},{1,0,1,0,1,0,1}};
private Random rdm = new Random(System.nanoTime());
public Invader(int size)
{
squaresSize = size;
color = new Color(rdm.nextInt(220), rdm.nextInt(220), rdm.nextInt(220));
}
public void draw(int posX, int posY)
{
double size = squaresSize/2;
int screenHeight = (int)java.awt.Toolkit.getDefaultToolkit().getScreenSize().getHeight();
posY = screenHeight - posY;
int x = 0, y = 0;
StdDraw.setPenColor(color);
for(int i=0; i<invaderShape.length; i++)
{
for(int j=0; j<invaderShape[i].length; j++)
{
if(invaderShape[i][j] == 1)
{
StdDraw.filledRectangle(posX+x,posY-y,size,size);
}
else
{
StdDraw.setPenColor();
if(invaderShape[i][j] == 2)
{
StdDraw.filledRectangle(posX+x,posY-y-((squaresSize+5)*rdm.nextInt(2)),size,size);
}
StdDraw.setPenColor(color);
}
x += squaresSize + 5;
}
y += squaresSize + 5;
x = 0;
}
}
}
Donc en gros, j'ai un Raspberry Pi (Google pour ceux qui savent pas ce que c'est), sous Raspbian, avec un serveur NodeJS.
Il fait office de serveur Web, et c'est lui qui gère le spawn, destruction, le type, la couleur, la taille des invaders...
Tout ca est envoyé au client via un script JS (WebSockets powa! \o/), et le client peut admirer et faire spawner des invaders, le tout synchro avec le server !
Vous pouvez donc afficher 2 fois la page cote à cote, vous aurez la meme chose, à quelques millisecondes près
Pour aller encore plus loin, il est possible de le faire marcher le script via un bookmarklet, il suffit de glisser le lien "bookmarklet" dans votre barre de favoris, et de le lancer depuis n'importe quel site !
Donc voici le SDZ infesté de Space Invaders !
Quelques précisions:
Le script est optimisé pour une résolution 1600x1000. Si votre écran est trop petit, ils risquent de sortir de l'écran...
J'ai mis une limite de spawn à 16 Invaders, pour éviter de faire cramer mon cher Raspberry Pi, et ils meurent au bout d'un certain nombre (aléatoire) de déplacements
Il y a une detection de collisions entre les invaders, pour éviter qu'ils se superposent, mais je l'ai quand meme limité pour éviter que ça prenne trop de temps a calculer, donc il y a de temps en temps quelques "superpositions"...
Le code source est dispo sur la page, les seuls dépendances de cette app, c'est Socket.io, parce que je suis pas un expert en matière de WebSocket, et UglifyJS pour minimifier les scripts à la volée
Je sais pas si je vais laisser mon Raspberry Pi allumé H24, donc paniquez pas si ça marche plus d'un coup
Enjoy!
Sandhose
EDIT: Entre-temps, je me suis acheté un nom de domaine Le script se trouve donc maintenant sur http://sandhose.fr/invaders/
Des zéros de la section électronique et des curieux se demande souvent ce que l'on peut faire avec une Arduino, alors voila un exemple...
(On avait bien dit "écran" au sens large et pas précisé ordinateur non )
Voici donc le résultat, petit message d'accueil puis un invader spawn aléatoirement sur l'écran puis disparait, puis reviens, puis repart, puis reviens, puis repart...
@CaptainYop : Ne ré-appelle pas srand à chaque fois que tu veux générer un nombre (pseudo-)aléatoire. Si il s'est écoulé un temps inférieur à la granularité impliquée par time entre les deux appels, la séquence générée sera identique. Pour le coup, tu peux simplement effectuer un appel à srand en début de programme, puis appeler rand indépendamment dans ta boucle.
Une petite variante de mon premier code, ici je stocke les donnée en indiquant a compien de case se trouvent la prochaine remplie (2,2,4,1,1 ect..) et il s'utilise maintenant en bookmarker, le tous en 541 caractères
function f(){(x=(c=y.lastChild).getContext("2d")).clearRect(0,0,380,320);i=0;p="#"+(r=Math.random)().toString(16).substr(2,6);d="22411113"+((a=r()<.5)?11:2)+((b=r()<.5)?113:23)+(!a?11:2)+(!b?11:2)+21111111222;(s=c.style).left=r()*(y.clientWidth-380)+"px";s.top=r()*(y.clientHeight-320)+"px";while(d[0]){i+=+d[0];d=d.slice(1);x.fillStyle=i-16&&i-18&&i-23&&i-25?p:"#000";x.fillRect(i%7*54,54*~~(i/7),50,50)}setTimeout(f,3e3)}(y=document.body).insertAdjacentHTML("beforeend","<canvas width=380 height=320 style=position:absolute></canvas>");f()
Mais bon au départ je poste ce message surtout pour ma version WTF: Un space invader en OOK
Cet exercice me parût un bon entraînement pour apprendre la librairie LOVE2D
Ce code est sûrement très "porc"
function love.load()
modes = love.graphics.getModes()
table.sort(modes, function(a, b) return a.width*a.height < b.width*b.height end)
resol = modes[table.getn(modes)]
love.graphics.setMode(resol["width"], resol["height"])
love.graphics.setCaption("Space Bitton")
end
function love.draw()
love.graphics.setColor(255, 255, 255)
love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight())
local r = math.random(0, 255)
local g = math.random(0, 255)
local b = math.random(0, 255)
local carre = 50
local x = math.random(0, love.graphics.getWidth()-10*carre)
local y = math.random(0, love.graphics.getHeight()-10*carre)
local alien = {
{0, 0, 1, 0, 1, 0, 0},
{0, 1, 1, 1, 1, 1, 0},
{0, 1, 0, 1, 0, 1, 0},
{0, 1, 0, 1, 0, 1, 0},
{1, 1, 1, 1, 1, 1, 1},
{1, 0, 1, 0, 1, 0, 1}
}
y_yeux1 = math.random(3, 4)
y_yeux2 = math.random(3, 4)
x_yeux1 = 3
x_yeux2 = 5
alien[y_yeux1][x_yeux1] = 2
alien[y_yeux2][x_yeux2] = 2
for i, l in ipairs(alien) do
for ii, num in ipairs(alien[i]) do
if num == 0 then
love.graphics.setColor(255, 255, 255)
elseif num == 1 then
love.graphics.setColor(r, g, b)
elseif num == 2 then
love.graphics.setColor(0, 0, 0)
end
love.graphics.rectangle("fill", x+ii*carre, y+i*carre, carre-4, carre-4)
end
end
love.timer.sleep(3)
end
Rien d'exceptionnel par rapport à ce qui à déjà été posté mais je suis content d'avoir un code qui fonctionne
et ça m'aura permis de decouvrir SVG! hehe
J'ai essayé d'utiliser CSS3 à la place de javascript mais il n'est apparement pas possible de générer des valeurs au hasard. Dommage, ça serait bien utile
Voici ma vision des choses (première version), elle est composé d'un fichier html, js, css, htaccess (pour url rewriting). Actuellement il manque juste l'animation des yeux (dont gérer dynamiquement la position et la taille des yeux), et une petite optimisation du code.
J'ai fais un petit éditeur pour pouvoir paramétrer l'animation (et on peu dessiner son propre space invader de la taille voulu (min 5x5 et max 32x32).
Les particularités :
Les couleurs ne sont pas définit par un simple random mais en fonction de la position de la souris ou du space invader. Cette méthode permet d'éviter un changement de couleur "trop surprenante".
Mise en place d'un système de sauvegarde/partage. Qui génère le lien correspondant.
J'ai divisé la taille par deux pour plus de liberté.
Voici ma participation en canvas HTML5 avec KineticJs.
Tout d'abord, le code :
<script>
function supportsCanvas(){return !!document.createElement('canvas').getContext;}
if(supportsCanvas()){
// Vars
var timer=setInterval("drawSpace()", 2000);
var sW=document.body.clientWidth;
var sH=document.body.clientHeight;
var _tW=50;
var _tH=50;
// Stage
var stage = new Kinetic.Stage({container: 'container',width:sW,height:sH});
var layer=new Kinetic.Layer();
// Draw Rect
function drawRect(obj,_px,_py,_col){
obj=new Kinetic.Rect({x:_px,y:_py,width:_tW,height:_tH,fill:_col,stroke:"#fff",strokeWidth:4})
layer.add(obj);
}
// Draw SpaceInvaders
function drawSpace(){
// Init
layer.remove();
layer=new Kinetic.Layer();
var t=new Array(new Array([0,0,1,0,1,0,0],[0,1,1,1,1,1,0],[0,1,2,1,4,1,0],[0,1,3,1,5,1,0],[1,1,1,1,1,1,1],[1,0,1,0,1,0,1]), new Array([0,0,0,1,1,0,0,0],[0,0,1,1,1,1,0,0],[0,1,2,1,1,4,1,0],[1,1,3,1,1,5,1,1],[1,1,1,1,1,1,1,1],[0,0,1,0,0,1,0,0],[0,1,0,1,1,0,1,0],[1,0,1,0,0,1,0,1]), new Array([0,0,0,1,1,0,0,0],[0,0,1,1,1,1,0,0],[0,1,2,1,1,4,1,0],[1,1,3,1,1,5,1,1],[1,1,1,1,1,1,1,1],[0,1,0,1,1,0,1,0],[1,0,0,0,0,0,0,1],[0,1,0,0,0,0,1,0]), new Array([0,0,1,0,0,0,0,0,1,0,0],[0,0,0,1,0,0,0,1,0,0,0],[0,0,1,1,1,1,1,1,1,0,0],[0,1,1,2,1,1,1,4,1,1,0],[1,1,1,3,1,1,1,5,1,1,1],[1,0,1,1,1,1,1,1,1,0,1],[1,0,1,0,0,0,0,0,1,0,1],[0,0,0,1,1,0,1,1,0,0,0]), new Array([0,0,0,0,1,1,1,1,0,0,0,0],[0,1,1,1,1,1,1,1,1,1,1,0],[1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,2,3,1,1,4,5,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1],[0,0,0,1,1,0,0,1,1,0,0,0],[0,0,1,1,0,1,1,0,1,1,0,0],[1,1,0,0,0,0,0,0,0,0,1,1]), new Array([0,0,0,1,1,0,0,0],[0,0,1,1,1,1,0,0],[0,1,1,1,1,1,1,0],[1,2,3,1,1,4,5,1],[1,1,1,1,1,1,1,1],[0,0,1,0,0,1,0,0],[0,1,0,1,1,0,1,0],[1,0,1,0,0,1,0,1]), new Array([0,1,0,0,1,0,0,1,0,1,1,1,0,1,0,1,0,0,1,0],[1,0,1,0,1,1,0,1,0,0,1,0,0,1,0,1,0,1,0,1],[1,1,1,0,1,0,1,1,0,0,1,0,0,1,1,1,0,1,0,1],[1,0,1,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0]), new Array([0,1,1,0,0,1,1,0],[1,0,0,1,0,0,0,1],[1,0,0,1,0,0,0,1],[0,1,1,0,0,1,1,0],[1,0,0,1,0,0,0,1],[1,0,0,1,0,0,0,1],[0,1,1,0,0,1,1,0]) );
var rect=new Array();
var _color="#"+(0x1000000+(Math.random())*0xffffff).toString(16).substr(1,6);
var _pX=0,_pY=0,nbRect=0;
var lEye=Math.ceil(Math.random()*2+1);
var rEye=Math.ceil(Math.random()*2+3);
var form=Math.floor(Math.random()*(t.length));
var margX=Math.random()*sW-(t[form][0].length*_tW);
var margY=Math.random()*sH-(t[form].length*_tH);
if(margX<0){margX+=-margX;}
if(margY<0){margY+=-margY;}
// For
for(var j=0;j<t[form].length;j++){
for(var i=0;i<t[form][j].length;i++){
_pX=(i*_tW)+margX;
_pY=(j*_tH)+margY;
switch(t[form][j][i]){
case 1:drawRect(rect[nbRect],_pX,_pY,_color);break;
case lEye:drawRect(rect[nbRect],_pX,_pY,"#000");break;
case rEye:drawRect(rect[nbRect],_pX,_pY,"#000");break;
}
nbRect++;
}
} stage.add(layer);
} drawSpace();
}else{alert("Votre navigateur ne supporte pas canvas. ;o");}
</script>
× 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.
World of Potion | Discord 3D [FR] | Direct Quiz
N'utilisez JAMAIS alert() pour debugger. Utilisez console.log()
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.
Retrouvez moi sur mon blog et ma chaine Youtube !
Retrouvez moi sur mon blog et ma chaine Youtube !