/* 3-7 Tetris From the manga/anime "Yu Yu Hakusho", by Yoshihiro Togashi (see anime episode 83) Programming by Stewart Wilcox */ import java.applet.*; import java.awt.*; import java.awt.event.*; import java.lang.System.*; import java.util.Vector; //-------------------------------------------------------------------------------------main class public class tetris37 extends Applet implements Runnable,KeyListener,MouseListener,MouseMotionListener,MouseWheelListener{ public String getAppletInfo(){ return "3-7 Tetris\n" +"from 'Yu Yu Hakusho', by Yoshihiro Togashi\n" +"Programming by Stewart Wilcox\n" +"Parameters[default]:\n" +"squaresize[32]: size of each square in pixels\n" +"fieldwidth[(applet width)/SZ]: width of playing field in squares\n" +"fieldheight[(applet height)/SZ-2]: height of playing field in squares\n" +"framerate[25]: length of each frame in ms\n" +"boomtime[800]: length of square clearing animation in ms\n" +"speedmod[20]: speed multiplier from pressing down"; } final int R=6; // diameter of round corners of tiles final int htime=320; // time (in ms) to move 1 square left or right final int vtime=150; // time (in ms) to move 1 pixel down... sort of final int BLANK=-10; // 3 squares will never add to 7 if one is blank final int BOOM=-11; // this index indicates a square that just disappeared final int distr[]={5,5,4,4,2,2,1,5}; // relative distribution of numbers 0-7 int distr_tot; int w,h; // size of playing field int SZ; // size of each square in pixels int[] data; // array of squares int nxt[]; // current block and next block int bt,bl,blaim; // position of block (bt in pixels, bl and blaim in blocks!) int rot; // block must be rotated rot*90 degrees clockwise int mode; int score; int speed; int bonus; // points from a given block is quadratic in the number of triples you make int speedmod; // holding down either mouse button multiplies speed by this factor - to quickly lower blocks int framerate; // ideal length of each frame in ms int boomtime; // length of BOOM animation in ms Thread t=null; long timer; Rectangle start; // position of start button Image backbuf; Graphics backgr; final Color cols[]={ // colours corresponding to each number 0 to 7 new Color(0.247f,0.541f,0.541f), new Color(0.196f,0.584f,0.388f), new Color(0.353f,0.635f,0.231f), new Color(0.373f,0.475f,0.608f), new Color(0.616f,0.498f,0.608f), new Color(0.549f,0.282f,0.373f), new Color(0.580f,0.259f,0.235f), new Color(0.502f,0.055f,0.071f) }; private int param(String name,int def){ String s=getParameter(name); return (s==null)?def:Integer.parseInt(s); } public void init(){ SZ=param("squaresize",32); w=param("fieldwidth",getSize().width/SZ); h=param("fieldheight",getSize().height/SZ-2); framerate=param("framerate",25); boomtime=param("boomtime",800); speedmod=param("speedmod",20); data=new int[w*h]; backbuf=createImage(w*SZ,(h+2)*SZ); backgr=backbuf.getGraphics(); backgr.setColor(Color.black); backgr.fillRect(0,0,w*SZ,(h+2)*SZ); backgr.setFont(new Font("Default",Font.PLAIN,SZ-4)); start=new Rectangle((w-3)/2*SZ-2,3*SZ+1,3*SZ,SZ-2); makemenu(); nxt=new int[4]; distr_tot=0; for(int i=0;i<8;++i) distr_tot+=distr[i]; addKeyListener(this); addMouseListener(this); addMouseMotionListener(this); addMouseWheelListener(this); } void makemenu(){ mode=0; backgr.setColor(new Color(0.f,0.f,0.f,.5f)); backgr.fillRect(0,0,w*SZ,(h+2)*SZ); int l=(w-5)/2; drawsq(l,SZ,3); drawsq(l+1,SZ,7); maketext(start,"START"); maketext(new Rectangle((l+2)*SZ,SZ+1,5*SZ,SZ-2),"TETRIS"); repaint(); } void maketext(Rectangle r,String s){ backgr.setColor(Color.yellow); backgr.fillRoundRect(r.x,r.y,r.width,r.height,R,R); backgr.setColor(cols[3]); backgr.fillRoundRect(r.x+2,r.y+2,r.width-4,r.height-4,R,R); backgr.setColor(cols[7]); backgr.drawString(s,r.x+4,r.y+SZ-6); } //----------------------------------------------------- Respond to mouse input //MouseMotionListener public void mouseMoved(MouseEvent e){ if(mode==2){ blaim=e.getX()/SZ; if(blaim<0) blaim=0; if(blaim>w-1) blaim=w-1; e.consume(); } } //MouseListener public void mouseDragged(MouseEvent e){ mouseMoved(e); } public void mousePressed(MouseEvent e){calcspeed(speedmod);} public void mouseReleased(MouseEvent e){calcspeed(1);} public void mouseEntered(MouseEvent e){} public void mouseExited(MouseEvent e){} public void mouseClicked(MouseEvent e){ if(mode!=0) return; int dx=e.getX()-start.x,dy=e.getY()-start.y; if(dx<0||dx>=start.width||dy<0||dy>start.height) return; // missed the button // start game // draw board backgr.setColor(Color.black); backgr.fillRect(0,0,w*SZ,(h+2)*SZ); backgr.setColor(Color.yellow); backgr.fillRect(0,h*SZ,w*SZ,SZ/2); // setup data mode=1; nxt[2]=rand(); nxt[3]=rand(); for(int i=0;i0) synchronized(this){notify();} repaint(); break; case KeyEvent.VK_LEFT: case KeyEvent.VK_A: blaim=0; break; case KeyEvent.VK_RIGHT: case KeyEvent.VK_D: blaim=w-1; break; case KeyEvent.VK_DOWN: case KeyEvent.VK_S: calcspeed(speedmod); break; case KeyEvent.VK_Q: case KeyEvent.VK_UP: --rot; break; case KeyEvent.VK_E: ++rot; break; default: return; } e.consume(); } public void keyReleased(KeyEvent e){ switch(e.getKeyCode()){ case KeyEvent.VK_LEFT: case KeyEvent.VK_A: case KeyEvent.VK_RIGHT: case KeyEvent.VK_D: blaim=bl; break; case KeyEvent.VK_DOWN: case KeyEvent.VK_S: calcspeed(1); break; default: return; } e.consume(); } //--------------------------------------------------- thread public void start(){ if(t==null){ t=new Thread(this); t.start(); } } public void stop(){ t=null; } public void run(){ boolean horizontal=true; int droptime=0; int lrtime=0; int[] comp=new int[2*w]; while(t!=null) try{ // pause if(mode<1){ synchronized(this){ while(mode<1) wait(); } timer=System.currentTimeMillis(); } // throttle long now=System.currentTimeMillis(); long diff=now-timer; if(diff=0) lrtime-=diff; if(droptime>=vtime||(blaim!=bl&&lrtime<0)||rot!=0){ backgr.setColor(Color.black); if(horizontal) backgr.fillRect(bl*SZ,bt,SZ*2,SZ); else backgr.fillRect(bl*SZ,bt,SZ,SZ*2); // move down bt+=Math.floor(droptime/vtime); droptime=droptime%vtime; int ind=(bt+SZ-1)/SZ; if(!horizontal) ++ind; while(ind>=0&&(full(bl,ind)||(horizontal&&full(bl+1,ind)))){--ind; mode=3;} if(mode==3){ if(ind<0) mode=0; else bt=(ind-(horizontal?0:1))*SZ; }else{ // rotate if(rot!=0){ if(rot<0) rot=3-(3-rot)%4; else rot=rot%4; if(horizontal){ if(full(bl,ind+1)) rot=0; }else{ if(full(bl+1,ind-1)) rot=0; } if(rot!=0){ if((rot&1)!=0){ ind+=(horizontal=!horizontal)?-1:1; } if((rot>1)^horizontal){ int tmp=nxt[1]; nxt[1]=nxt[0]; nxt[0]=tmp; } rot=0; } } if(blaim>bl&&lrtime<0&&!full(bl+(horizontal?2:1),ind)){++bl; lrtime+=htime;} if(blaim0;){ --j; if(full(i,j)){ if(comp[i]==-1){ // this column needs to go down comp[i]=j+1; mode=4; } comp[i+w]=j; }else{ if(comp[i]==0) comp[i]=-1; } } } droptime=0; bt=0; } if(mode==4){ // do the compactification if((droptime+=diff*(speed+4))>=vtime){ bt+=droptime/vtime; droptime=droptime%vtime; if(bt>SZ){bt=SZ; mode=3;} for(int i=0;i0){ backgr.setColor(Color.black); backgr.fillRect(i*SZ,comp[i+w]*SZ,SZ,(comp[i]-comp[i+w]+1)*SZ); for(int j=comp[i+w];jcomp[i+w];--j) data[i+w*j]=data[i+w*(j-1)]; data[i+w*comp[i+w]]=BLANK; } } } repaint(); } if(mode==5){ // look for 3-7's mode=1; for(int j=0;j=h||x<0||x>=w) return true; return data[x+y*w]>BLANK; } boolean scoreme(int tot){ if(tot==7||tot==21){ score+=(++bonus)*((tot==7)?10:20); return true; } return false; } void calcspeed(int mult){ speed=mult*(1+score/200); } //--------------------------------------------------- graphics void drawsq(int l,int t,int n){ // note l is in squares, t is in pixels!! (since I never draw a square with a funny horizontal position) l*=SZ; if(n<0) return; // don't draw empty squares backgr.setColor(Color.yellow); backgr.fillRoundRect(l+1,t+1,SZ-2,SZ-2,R,R); backgr.setColor(cols[n]); backgr.fillRoundRect(l+3,t+3,SZ-6,SZ-6,R,R); backgr.setColor(Color.black); backgr.drawString(Integer.toString(n),l+SZ/4,t+SZ-6); } public void update(Graphics g){ if(mode<0){ // paused g.setColor(Color.black); g.fillRect(0,0,w*SZ,(h+2)*SZ); g.setColor(Color.white); g.drawString("Press P to unpause",SZ*3,SZ*3); }else g.drawImage(backbuf,0,0,this); getToolkit().sync(); } public void paint(Graphics g){ update(g); } }