001import processing.core.*; 002import processing.data.*; 003import processing.event.*; 004import processing.opengl.*; 005 006import java.util.Random; 007import java.util.concurrent.Executors; 008import java.util.concurrent.ScheduledExecutorService; 009import java.util.concurrent.TimeUnit; 010import java.util.concurrent.Executors; 011import java.util.concurrent.ScheduledExecutorService; 012import java.util.concurrent.TimeUnit; 013import javax.sound.sampled.*; 014import java.nio.ByteBuffer; 015import processing.core.*; 016import java.io.*; 017 018import java.util.HashMap; 019import java.util.ArrayList; 020import java.io.File; 021import java.io.BufferedReader; 022import java.io.PrintWriter; 023import java.io.InputStream; 024import java.io.OutputStream; 025import java.io.IOException; 026 027public class MODULO_1003_STEREO extends PApplet { 028 029 /** 030 * <h4>MODULO_1003_STEREO</h4> 031 * <br/> 032 * Copyright (C) 2019 Guido Kramann<br/> 033 * kramann@th-brandenburg.de<br/> 034 * http://www.kramann.info<br/> 035 * <br/> 036 * <p> 037 * This program is free software: you can redistribute it and/or modify 038 * it under the terms of the GNU General Public License as published by 039 * the Free Software Foundation, either version 3 of the License, or 040 * (at your option) any later version. 041 * 042 * </p> 043 * <p> 044 * This program is distributed in the hope that it will be useful, 045 * but WITHOUT ANY WARRANTY; without even the implied warranty of 046 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 047 * GNU General Public License for more details. 048 * </p> 049 * <p> 050 * You should have received a copy of the GNU General Public License 051 * along with this program (gpl.html). If not, see http://www.gnu.org/licenses/. 052 * </p> 053 */ 054 055Spieler spieler_schwarz,spieler_weiss; 056 057Rekorder rekorder = new Rekorder(86,1525); 058//Rekorder rekorder = new Rekorder(86,286); 059boolean RECORDING = false; 060 061boolean WARTUNG = false; 062 063//009: rhythmisierte Fassung: 064//Die Dauer eines Zuges wird festgelegt. 065//Der Wechsel erfolgt immer nach einer Periode, wenn gezogen wurde. 066//Wurde nicht gezogen, werden Strafpunkte abgezogen und erst wieder wenn eine weitere Periode voll ist gewechselt. 067long PULSMILLIS = 200; //... so viele Millisekunden dauert Pulse 068long PULSEPROZUG = 12; //... so viele Pulse dauert ein Zug (und auch eine gespielte Phrase) 069int STRAFPUNKTE = 50; 070 071 072 073//FEHLER: Das Entfernen von Steinen wird nicht richtig behandelt!!!! 074 075//Punkte: werden aktualisiert, wenn die Pfade aktualisiert werden! 076int PUNKTE_WEISS = 0; 077int PUNKTE_SCHWARZ = 0; 078 079//rot wenn schwarz dran ist, 080//gr\u00fcn wenn weiss dran ist 081 082//nur gerade Bewegungen auf Feld erlaubt 083//nur eigene Farbe darf bewegt werden, wenn man dran ist 084 085int[] ROT = {255,100,100}; 086int[] GRUEN = {100,255,100}; 087 088ArrayList<int[]> schwarzerpfad = null; 089ArrayList<int[]> weisserpfad = null; 090 091 092float LINIENDICKE; 093 094String[] kartentypen; 095Karte[] karte; 096Karte quelleweiss; 097Karte quelleschwarz; 098float kantex; 099float kantey; 100Spielfeld spielfeld; 101Spiel spiel; 102Spiel testspiel; //Derzeit nur zum laden und speichern von Spielzust\u00e4nden 103Spiel testspiel2; //Zwischenspeichern 104 105Zugkontrolle zugkontrolle; 106 107Karte dragged = null; 108int FELDBREITE = 101; 109int RANDBREITE = (6 + 3)*2; 110 111 112Mysoundplayer msp; 113Wav wav; 114 115public void setup() 116{ 117 int[] MIDI = {33,35,37,38,40,42,44, 47,49, 52,54,56, 59,61,63, 66,68, 71, 75, 80, 87}; //Anzahl=21 118 //Sound 119 println("midi min = "+freq2mid(55)); 120 println("midi max = "+freq2mid(1760)); 121 122// msp = new Mysoundplayer(this,2); 123 msp = new Mysoundplayer(this,4); //Jetzt 4 Kan\u00e4le 124 int midimin = 33; 125// int midimax = 93; 126 int midimax = 87; 127 int[] skala = new int[midimax-midimin+1]; 128 for(int i=midimin;i<=midimax;i++) 129 skala[i-midimin] = i; 130 float laute1 = 0.1f; 131 float laute2 = 0.2f; 132 float pan = 0.5f; 133// msp.ladeKanal(0, "/home/fhbstud/system/samples/89_marimbaneu/normal",skala,laute,pan-0.1); 134// msp.ladeKanal(0, "/home/fhbstud/system/samples/06_klavier_yamaha_c7/up106",MIDI,laute,pan-0.1); 135// msp.ladeKanal(0, "data/t35",skala,laute,pan-0.1); 136 msp.ladeKanalStereo(0, "data/t35",MIDI,laute1,pan-0.1f); 137 msp.ladeKanalStereo(1, "data/t36",MIDI,laute1,pan-0.1f); 138 139// msp.saveKanal(int kanal, String pfad, int[] midiskala) 140// msp.ladeKanal(0, "/home/fhbstud/system/samples/06_klavier_yamaha_c7/up106",skala,5.0,pan); 141// msp.saveKanal(0, "data/t35", skala); 142 143// msp.ladeKanal(1, "/home/fhbstud/system/samples/06_klavier_yamaha_c7/up98",MIDI,laute,pan+0.1); 144 msp.ladeKanalStereo(2, "data/t21",MIDI,laute2,pan+0.1f); 145 msp.ladeKanalStereo(3, "data/t22",MIDI,laute2,pan+0.1f); 146 147// msp.ladeKanal(1, "/home/fhbstud/system/samples/06_klavier_yamaha_c7/up98",skala,5.0,pan); 148// msp.saveKanal(1, "data/t36", skala); 149 150 151// msp.ladeKanal(0, "/home/fhbstud/system/samples/89_marimbaneu/normal",skala,laute,pan-0.1); 152// msp.ladeKanal(1, "/home/fhbstud/system/samples/89_marimbaneu/normal",skala,laute,pan+0.1); 153 // ladeMonostimmen(int[] skala, String[] ordner, String prefix) 154 155// msp.ladeMonostimmen(MIDI, new String[] {"a7","a8"}, "ton"); 156// msp.ladeMonostimmen(MIDI, new String[] {"a7","t35"}, new float[] {1.0,0.2}, "ton"); 157 158 //Ende Sound 159 160 float TEILER = 9.0f; 161// size(1280,720); 162// size(1100,720); 163// size(1100,640); 164 //size(640,640); 165 166// fullScreen(); 167 orientation(LANDSCAPE); 168 169 LINIENDICKE = height/300.0f; 170 strokeWeight(LINIENDICKE); 171 172 float bsoll = 1280.0f; 173 float hsoll = 720.0f; 174 float bist = width; 175 float hist = height; 176 177 if(hist/bist > hsoll/bsoll) 178 { 179 float faktor = (hsoll/bsoll) / (hist/bist); 180 181 float bb = width; 182// float kx = (5.0f/13.0f)*(height*faktor)/(float)TEILER; 183 float kx = (5.0f/13.0f)*(height)/(float)TEILER; 184 while((int)floor(bb/kx) < FELDBREITE+RANDBREITE) 185 FELDBREITE-=2; 186 187 scale(1.0f,faktor); 188 } 189 else if(hist/bist < hsoll/bsoll) 190 { 191 float faktor = (hsoll/bsoll) / (hist/bist); 192 193// float bb = width/faktor; 194 float bb = width; 195 float kx = (5.0f/13.0f)*height/(float)TEILER; 196 while((int)floor(bb/kx) < FELDBREITE+RANDBREITE) 197 FELDBREITE-=2; 198 199 scale(1.0f/faktor,1.0f); 200 201 } 202 203println(FELDBREITE); 204 205 strokeWeight(height*0.002f); 206 207 kantex = (5.0f/13.0f)*height/TEILER; 208 kantey = height/TEILER; 209 kartentypen = loadStrings("kartentypen.txt"); 210 frameRate(30); 211// spielfeld = new Spielfeld(kantex,kantey,21,9); 212 spielfeld = new Spielfeld(kantex,kantey,FELDBREITE,9); 213 karte = new Karte[9*6*2]; 214 for(int i=0;i<karte.length/2;i++) 215 { 216 float x = (i/9)*kantex; 217 float y = (i%9)*kantey; 218 karte[i] = new Karte(true,i%9,1+i/9,x,y,(5.0f/13.0f)*height/TEILER,height/TEILER); 219 } 220 221 quelleweiss = new Karte(true,9,0,kantex*7,kantey*4,(5.0f/13.0f)*height/TEILER,height/TEILER); 222 quelleschwarz = new Karte(false,9,7,width-kantex*7-kantex,kantey*4,(5.0f/13.0f)*height/TEILER,height/TEILER); 223 224 for(int i=0;i<karte.length/2;i++) 225 { 226 float x = (i/9)*kantex; 227 float y = (i%9)*kantey; 228 karte[i+karte.length/2] = new Karte(false,i%9,1+i/9,width-x-kantex,height-y-kantey,(5.0f/13.0f)*height/TEILER,height/TEILER); 229 } 230 231 spiel = new Spiel(spielfeld,karte,quelleweiss,quelleschwarz); 232 testspiel = new Spiel(spielfeld,karte,quelleweiss,quelleschwarz); 233 testspiel2 = new Spiel(spielfeld,karte,quelleweiss,quelleschwarz); 234 235 zugkontrolle = new Zugkontrolle(PULSMILLIS,PULSEPROZUG,spielfeld,STRAFPUNKTE); 236 237 //Automatische Spieler starten: 238 spieler_weiss = new Spieler(true,spielfeld,spiel,testspiel,testspiel2); 239 spieler_schwarz = new Spieler(false,spielfeld,spiel,testspiel,testspiel2); 240} 241 242public void draw() 243{ 244 strokeWeight(LINIENDICKE); 245 background(70,70,70); 246 247 248 spielfeld.draw(); 249 for(int i=0;i<karte.length;i++) 250 karte[i].draw(null); 251 252 253 if(spielfeld.WEISS_IST_DRAN && spielfeld.TIMER_WEISS_IST_DRAN) 254 quelleweiss.draw(GRUEN); //Korona 255 else 256 quelleweiss.draw(null); //Korona 257 258 259 if(!spielfeld.WEISS_IST_DRAN && !spielfeld.TIMER_WEISS_IST_DRAN) 260 quelleschwarz.draw(ROT); 261 else 262 quelleschwarz.draw(null); 263 264 265 //Pfade zeigen: (siehe mouseReleased() ganz unten!!!!) 266 // schwarzerpfad = spiel.findeNaechstenpfadWeiss(); 267 // weisserpfad = spiel.findeNaechstenpfadWeiss(); 268 stroke(GRUEN[0],GRUEN[1],GRUEN[2]); 269 if(weisserpfad!=null && weisserpfad.size()>1) 270 { 271 ArrayList<int[]> pfad = weisserpfad; 272 for(int i=0;i<pfad.size()-1;i++) 273 { 274 int ii1 = pfad.get(i)[0]; 275 int kk1 = pfad.get(i)[1]; 276 int ii2 = pfad.get(i+1)[0]; 277 int kk2 = pfad.get(i+1)[1]; 278 float x1 = spielfeld.kkoord[ii1][kk1]; 279 float y1 = spielfeld.ikoord[ii1][kk1]; 280 float x2 = spielfeld.kkoord[ii2][kk2]; 281 float y2 = spielfeld.ikoord[ii2][kk2]; 282 line(x1,y1,x2,y2); 283 } 284 } 285 286 stroke(ROT[0],ROT[1],ROT[2]); 287 if(schwarzerpfad!=null && schwarzerpfad.size()>1) 288 { 289 ArrayList<int[]> pfad = schwarzerpfad; 290 for(int i=0;i<pfad.size()-1;i++) 291 { 292 int ii1 = pfad.get(i)[0]; 293 int kk1 = pfad.get(i)[1]; 294 int ii2 = pfad.get(i+1)[0]; 295 int kk2 = pfad.get(i+1)[1]; 296 float x1 = spielfeld.kkoord[ii1][kk1]+LINIENDICKE*0.5f; 297 float y1 = spielfeld.ikoord[ii1][kk1]+LINIENDICKE*0.5f; 298 float x2 = spielfeld.kkoord[ii2][kk2]+LINIENDICKE*0.5f; 299 float y2 = spielfeld.ikoord[ii2][kk2]+LINIENDICKE*0.5f; 300 line(x1,y1,x2,y2); 301 } 302 } 303 304 305 if(dragged!=null) 306 { 307 dragged.set(mouseX,mouseY); 308 dragged.draw(null); 309 } 310} 311 312public void mousePressed() 313{ 314 if(dragged==null) 315 { 316 //ABBRUCH, wenn falsche Farbe! 317 for(int i=0;i<karte.length;i++) 318 if(karte[i].mausHatEs(mouseX,mouseY) && (spielfeld.WEISS_IST_DRAN==spiel.istWeiss(karte[i].ID) && spielfeld.WEISS_IST_DRAN==spielfeld.TIMER_WEISS_IST_DRAN)) 319 dragged = karte[i]; 320 if(quelleweiss.mausHatEs(mouseX,mouseY) && (spielfeld.WEISS_IST_DRAN==true && spielfeld.TIMER_WEISS_IST_DRAN==true)) 321 dragged = quelleweiss; 322 if(quelleschwarz.mausHatEs(mouseX,mouseY) && (spielfeld.WEISS_IST_DRAN==false && spielfeld.TIMER_WEISS_IST_DRAN==false)) 323 dragged = quelleschwarz; 324 325 326 if(dragged!=null) 327 dragged.war_auf_feld = false; 328 329 if(dragged!=null && spielfeld.istInSpielfeld(dragged)) 330 { 331 int kk = spielfeld.getNextXindex(dragged); 332 int ii = spielfeld.getNextYindex(dragged); 333 334 if(spielfeld.istFrei(ii,kk)==false) 335 { 336 spielfeld.matrix[ii][kk] = null; 337 dragged.war_auf_feld = true; 338 } 339 } 340 } 341} 342 343public void updateSpielzustand() 344{ 345 //Nur bei erfolgreicher Aktion n\u00f6tig: 346 //Anzeige der aktuellen Belegung: 347 //*********** Das hier m\u00fc\u00dfte auch bei automatischen Z\u00fcgen ausgef\u00fchrt werden: ******* 348 spiel.uebernehmeZustand(); 349 if(WARTUNG == true) 350 spiel.zeigeTestweiseDieEigenschaftenAllerKartenImSpielfeld(); 351 schwarzerpfad = spiel.findeNaechstenpfadSchwarz(); 352 weisserpfad = spiel.findeNaechstenpfadWeiss(); 353 //**************** 354 355 //Punkte aktualisieren: 356 if(spielfeld.WEISS_IST_DRAN) 357 PUNKTE_WEISS += spiel.berechnePunkte(weisserpfad); 358 if(!spielfeld.WEISS_IST_DRAN) 359 PUNKTE_SCHWARZ += spiel.berechnePunkte(schwarzerpfad); 360 361 if(WARTUNG) 362 println("W:"+PUNKTE_WEISS+" S:"+PUNKTE_SCHWARZ); 363} 364 365public void mouseReleased() 366{ 367 float mx = mouseX; 368 float my = mouseY; 369 if(dragged!=null) 370 { 371 if(spielfeld.istInSpielfeld(dragged)) //wenn Figur auf Spielfeld gezogen wurde 372 { 373 float xx = spielfeld.getNextX(dragged); 374 float yy = spielfeld.getNextY(dragged); 375 int kk = spielfeld.getNextXindex(dragged); 376 int ii = spielfeld.getNextYindex(dragged); 377 378 if(spielfeld.istFrei(ii,kk)) //Wenn Zielplatz auf Spielfeld frei ist 379 { 380 //ERFOLGREICHER ZUG! 381 dragged.setNeu(xx,yy); 382 spielfeld.matrix[ii][kk] = dragged; 383 dragged.xspielfeld=xx; 384 dragged.yspielfeld=yy; 385 386 updateSpielzustand(); //Nur bei erfolgreichen Z\u00fcgen Updtae n\u00f6tig! 387 388 //JETZT IST DER ANDERE DRAN! 389 spielfeld.WEISS_IST_DRAN = !spielfeld.WEISS_IST_DRAN; 390 } 391 else 392 { 393 if(dragged.war_auf_feld == true) 394 { 395 dragged.x = dragged.xspielfeld; 396 dragged.y = dragged.yspielfeld; 397 kk = spielfeld.getNextXindex(dragged); 398 ii = spielfeld.getNextYindex(dragged); 399 spielfeld.matrix[ii][kk] = dragged; 400 401 402 } 403 else //wenn Figur zuvor selbst schon auf Spielfeld war, dann auf alten Platz dort zur\u00fcck setzen 404 { 405 dragged.setHome(); 406 } 407 } 408 409 } 410 else //Spielfigut weg von Spielfeld ziehen 411 { 412 dragged.setHome(); 413 //Das ist auch ein erfolgreicher Zug, darum hier auch update und Wechsel!!!!: 414 updateSpielzustand(); //Nur bei erfolgreichen Z\u00fcgen Updtae n\u00f6tig! 415 416 //JETZT IST DER ANDERE DRAN! 417 spielfeld.WEISS_IST_DRAN = !spielfeld.WEISS_IST_DRAN; 418 419 } 420 421 dragged = null; 422 } 423 424 //Nur bei erfolgreicher Aktion n\u00f6tig (s. updateSpielzustand und erfolgreicher Zug!): 425 //Anzeige der aktuellen Belegung: 426 //*********** Das hier m\u00fc\u00dfte auch bei automatischen Z\u00fcgen ausgef\u00fchrt werden: ******* 427 //spiel.uebernehmeZustand(); 428 //spiel.zeigeTestweiseDieEigenschaftenAllerKartenImSpielfeld(); 429 //schwarzerpfad = spiel.findeNaechstenpfadSchwarz(); 430 //weisserpfad = spiel.findeNaechstenpfadWeiss(); 431 //**************** 432} 433 434public void keyPressed() 435{ 436 if(key=='r') 437 { 438 spiel.alleHeimschicken(); //Testweise Zustand auf Start setzen 439 spiel.zeigeTestweiseDieEigenschaftenAllerKartenImSpielfeld(); 440 } 441 else if(key=='s') //Zustand in testspiel speichern 442 { 443 testspiel.uebernehmeZustand(); 444 println("Spielzustand in Testspiel gemerkt"); 445 } 446 else if(key=='l') //Zustand VON testspiel LADEN 447 { 448 testspiel.schreibeZustand(); 449 println("Spielzustand von Testspiel geholt"); 450 } 451 else if(key==' ') 452 { 453 if(RECORDING==false) 454 { 455 RECORDING = true; 456 println("\n\nAUFNAHME START\n"); 457 } 458 else 459 { 460 RECORDING = false; 461 rekorder.save("stueck_"+System.currentTimeMillis()+".txt"); 462 println("\n\nAUFNAHME ENDE\n"); 463 } 464 } 465 466 467 468} 469 public double midi2Frequency(double midi) 470 { 471 if(midi<1.0f) 472 return 0.0f; //Nullereignisse behandeln 473 474 double freq69 = Math.pow(2.0f,69.0f/12.0f); 475 return Math.pow(2.0f,midi/12.0f)*440.0f/freq69; 476 } 477 478 public double frequency2Midi(double freq) 479 { 480 if(freq<1.0f) 481 return 0.0f; //Nullereignisse behandeln 482 483 double freq69 = Math.pow(2.0f,69.0f/12.0f); 484 return 12.0f*Math.log(freq*freq69/440.0f)/Math.log(2.0f); 485 } 486 487 public int freq2mid(int freq) 488 { 489 if(freq==0) 490 return 0; 491 else 492 return (int)Math.round(frequency2Midi((double)freq)); 493 } 494 495 public int mid2freq(int mid) 496 { 497 if(mid==0) 498 return 0; 499 else 500 return (int)Math.round(midi2Frequency((double)mid)); 501 } 502 503public class Karte 504{ 505 public boolean war_auf_feld = false; 506 507 int typ; 508 String[] pattern; 509 float kantex; 510 float kantey; 511 public float h,b,x,y,xhome,yhome,xoff,yoff,xspielfeld,yspielfeld; 512 int farbe; 513 boolean WEISS; 514 515 public int ID=0; 516 517 //typ 9 ist Quelle, 0..8== .|..|...|-|--|---|+|++|+++ 518 // 0 1 2 3 4 5 6 7 8 519 public Karte(boolean WEISS,int typ,int farbe,float x, float y, float b, float h) 520 { 521 ID = 99000 + typ*100 + farbe*10; 522 if(WEISS) 523 ID++; 524 525 526 this.xoff = 0.0f; 527 this.yoff = 0.0f; 528 this.xspielfeld = 0.0f; 529 this.yspielfeld = 0.0f; 530 531 this.WEISS = WEISS; 532 this.farbe = farbe; 533 this.typ = typ; 534 pattern = new String[13]; 535 for(int i=0;i<pattern.length;i++) 536 { 537 pattern[i] = kartentypen[typ*20+i]; 538 } 539 kantex = b/5.0f; 540 kantey = h/13.0f; 541 this.h = h; 542 this.b = b; 543 this.x = x; 544 this.y = y; 545 this.xhome = x; 546 this.yhome = y; 547 } 548 549 public void draw(int[] randfarbe) 550 { 551 if(randfarbe==null) 552 noStroke(); 553 else 554 stroke(randfarbe[0],randfarbe[1],randfarbe[2]); 555 int r = ((7-farbe)/4)%2; 556 int g = ((7-farbe)/2)%2; 557 int b = ((7-farbe)/1)%2; 558 //&&&& 559 if(WEISS) 560 { 561 fill(127+64); 562 } 563 else 564 { 565 fill(0); 566 } 567 rect(x,y,this.b,this.h,60); 568 //&&&& 569 if(WEISS) 570 { 571 fill(r*127,g*127,b*127); 572 stroke(r*127,g*127,b*127); 573 } 574 else 575 { 576 fill(r*127+64,g*127+64,b*127+64); 577 stroke(r*127+64,g*127+64,b*127+64); 578 } 579 for(int i=0;i<pattern.length;i++) 580 { 581 for(int k=0;k<pattern[i].length();k++) 582 { 583 if(pattern[i].charAt(k)=='*') 584 rect(x+kantex*(k+1),y+kantey*(i-1),kantex,kantey,3); 585 } 586 } 587 } 588 589 public boolean mausHatEs(float mx, float my) 590 { 591 if(mx>x && my>y && mx<x+b && my<y+h) 592 { 593 xoff = x-mx; 594 yoff = y-my; 595 596 return true; 597 } 598 else 599 return false; 600 } 601 602 public void set(float mx, float my) 603 { 604 x = mx+xoff; 605 y = my+yoff; 606 } 607 public void setNeu(float mx, float my) 608 { 609 x = mx; 610 y = my; 611 xoff=0.0f; 612 yoff=0.0f; 613 } 614 615 public void setHome() 616 { 617 this.x = xhome; 618 this.y = yhome; 619 xoff=0.0f; 620 yoff=0.0f; 621 } 622} 623//Spiel repr\u00e4sentiert den Spielstand / den Spielzustand 624//Mit einer Instanz testspiel, k\u00f6nnen auch nicht aktuelle Spielzust\u00e4nde \u00fcberpr\u00fcft werden (2. Instanz von spiel) 625 626public class Spiel 627{ 628 //Nur die NEUEN Punkte, nicht die aku,ulierten. 629 //Die akumulierten stehen im Haupt-Sketch 630 //werden beim Bestimmen der Pfade mit aktualisiert! 631 632 633 //Die Parameter werden aus den \u00fcbergerbenen Objekten extrahiert und 634 //die \u00fcbergebenen Parameter hier registriert 635 Spielfeld spielfeld; 636 Karte[] karte; 637 Karte quelleweiss; 638 Karte quelleschwarz; 639 640 public int[][] matrix; 641 public int[][] distmatrix; 642 643 public void kopiereAufAnderesSpiel(Spiel testspiel) 644 { 645 for(int i=0;i<matrix.length;i++) 646 for(int k=0;k<matrix[i].length;k++) 647 testspiel.matrix[i][k] = matrix[i][k]; 648 for(int i=0;i<matrix.length;i++) 649 for(int k=0;k<matrix[i].length;k++) 650 testspiel.distmatrix[i][k] = distmatrix[i][k]; 651 } 652 653 public Spiel(Spielfeld spielfeld,Karte[] karte,Karte quelleweiss,Karte quelleschwarz) 654 { 655 this.spielfeld = spielfeld; 656 this.karte = karte; 657 this.quelleweiss = quelleweiss; 658 this.quelleschwarz = quelleschwarz; 659 660 this.matrix = new int[spielfeld.matrix.length][spielfeld.matrix[0].length]; 661 this.distmatrix = new int[spielfeld.matrix.length][spielfeld.matrix[0].length]; 662 } 663 664 public void uebernehmeZustand() 665 { 666 Karte[][] mat = spielfeld.matrix; 667 668 for(int i=0;i<matrix.length;i++) 669 for(int k=0;k<matrix[i].length;k++) 670 if(mat[i][k]!=null) 671 matrix[i][k] = mat[i][k].ID; 672 else 673 matrix[i][k] = 0; 674 } 675 676 public void schreibeZustand() //in matrix gespeicherten Zustand auf das Spiel \u00fcbertragen!, praktisch f\u00fcr autom. Spiel!!!! 677 { 678 //1. Alle "heimschicken" 679 alleHeimschicken(); 680 //2. aus matrix die IDs lesen und dort die Karten in Spielfeld positionieren. 681 for(int i=0;i<matrix.length;i++) 682 { 683 for(int k=0;k<matrix[i].length;k++) 684 { 685 float xxx = spielfeld.getNextXausK(k); 686 float yyy = spielfeld.getNextYausI(i); 687 int ID = matrix[i][k]; 688 if(ID>0) 689 { 690 if(quelleweiss.ID==ID) 691 { 692 spielfeld.matrix[i][k] = quelleweiss; 693 quelleweiss.setNeu(xxx,yyy); 694 } 695 else if(quelleschwarz.ID==ID) 696 { 697 spielfeld.matrix[i][k] = quelleschwarz; 698 quelleschwarz.setNeu(xxx,yyy); 699 } 700 else 701 { 702 for(int pp=0;pp<karte.length;pp++) 703 { 704 if(karte[pp].ID==ID) 705 { 706 spielfeld.matrix[i][k] = karte[pp]; 707 karte[pp].setNeu(xxx,yyy); 708 break; 709 } 710 } 711 } 712 } 713 } 714 } 715 } 716 717 public void alleHeimschicken() 718 { 719 for(int i=0;i<karte.length;i++) 720 karte[i].setHome(); 721 quelleweiss.setHome(); 722 quelleschwarz.setHome(); 723 for(int i=0;i<spielfeld.matrix.length;i++) 724 for(int k=0;k<spielfeld.matrix[0].length;k++) 725 spielfeld.matrix[i][k]=null; 726 } 727 728 //Methoden zur Analyse der ID: 729 public boolean istWeiss(int ID) 730 { 731 if(ID%2==1) 732 return true; 733 else 734 return false; 735 } 736 737 public int farbeVonID(int ID) 738 { 739 return (ID/10)%10; 740 } 741 742 public int anzahlVonID(int ID) 743 { 744 return ((ID/100)%10)%3; 745 } 746 747 public int formVonID(int ID) 748 { 749 return ((ID/100)%10)/3; 750 } 751 752 public boolean istQuelle(int ID) 753 { 754 if( (ID/100)%10==9 ) 755 return true; 756 else 757 return false; 758 } 759 760 public boolean istAufSpielfeld(int ID) 761 { 762 for(int i=0;i<matrix.length;i++) 763 for(int k=0;k<matrix[i].length;k++) 764 if(ID==matrix[i][k]) 765 return true; 766 return false; 767 } 768 769 public void zeigeTestweiseDieEigenschaftenAllerKartenImSpielfeld() 770 { 771 println("//Angaben:"); 772 println("[zeile|spalte]"); 773 println("// S/W schwarz weiss"); 774 println("// QQQ Quelle"); 775 println("// Farbe 1..6"); 776 println("// Anzahl 1..3"); 777 println("// Form 1..3"); 778 for(int i=0;i<matrix.length;i++) 779 { 780 for(int k=0;k<matrix[i].length;k++) 781 { 782 if(matrix[i][k]>0) 783 { 784 print("["+i+"|"+k+"] "); 785 int ID = matrix[i][k]; 786 if(istWeiss(ID)) 787 print("W "); 788 else 789 print("S "); 790 if(istQuelle(ID)) 791 { 792 print("QQQ"); 793 } 794 else 795 { 796 int farbe = farbeVonID(ID); //OHNE INKR schon richtig!!! 797 int anzahl = anzahlVonID(ID)+1; //PLUS 1 !!! 798 int form = formVonID(ID)+1; //PLUS 1 !!! 799 print(farbe+""+anzahl+""+form+""); 800 } 801 print(" # "); 802 } 803 else 804 { 805 print("["+i+"|"+k+"] "); 806 print(" "); 807 print(" # "); 808 } 809 } 810 println(); 811 } 812 println(); 813 } 814 815 816 //Methoden bereitstellen, die es erlauben die G\u00fcltigkeit von Konstellationen zu untersuchen 817 //um schlie\u00dflich g\u00fcltige Z\u00fcge zu suchen und zu bewerten. 818 819 //Verboten sind Zyklen. 820 //Wie erkennt man Zyklen? 821 //Es d\u00fcrfen keine Rechtecke auftreten! Reicht das??? 822 823 //Wenn man Kreuzungen verbietet reicht das. 824 //Aber wenn nicht g\u00e4be es z.B. 8-ten als M\u00f6glichkeit von Schleifen, die keine Rechtecke sind. 825 826 //OBIGES VERWERFEN!!! 827 828 //Statt dessen N\u00e4chstenpfad OHNE Zyklen/Wdh. bilden. 829 //So braucht es sonst keine Beschr\u00e4nkungen!!!! 830 831 832 public ArrayList<int[]> findeNaechstenpfadWeiss() 833 { 834 return findeNaechstenpfad(true); 835 } 836 837 public ArrayList<int[]> findeNaechstenpfadSchwarz() 838 { 839 return findeNaechstenpfad(false); 840 } 841 842 //Nur die NEUEN Punkte, nicht die aku,ulierten. 843 //Die akumulierten stehen im Haupt-Sketch 844 //werden beim Bestimmen der Pfade mit aktualisiert! 845 846 //Formel: Anzahl_versch_farben * Anzahl_versch_formen * Anzahl_versch_Anzahlen * ANZAHLWEGSTATIONEN_OHNE_QUELLE 847 848 public int berechnePunkte(ArrayList<int[]> sammel_ik) 849 { 850 if(sammel_ik==null || sammel_ik.size()<=1) 851 return 0; //Quelle z\u00e4hlt nicht mit!!! 852 int[][] merker = new int[4][matrix[0].length]; //Zeilen: Farbe, Form, Anzahl,distanzen || Spalten werden inkrementiert, wenn korrespondierende Farbe/Form/Anzahl auftaucht. 853 for(int i=0;i<sammel_ik.size();i++) 854 { 855 int ID = matrix[sammel_ik.get(i)[0]][sammel_ik.get(i)[1]]; 856 if(ID>0 && !istQuelle(ID)) 857 { 858 int farbe = farbeVonID(ID); 859 int form = formVonID(ID); 860 int anz = anzahlVonID(ID); 861 int distanz = sammel_ik.get(i)[2]; 862 merker[0][farbe]++; 863 merker[1][form]++; 864 merker[2][anz]++; 865 merker[3][distanz]++; 866 } 867 } 868 869 int PUNKTE = sammel_ik.size()-1; 870 871 for(int i=0;i<merker.length;i++) 872 { 873 int summe = 0; 874 for(int k=0;k<merker[i].length;k++) 875 { 876 if(merker[i][k]>0) 877 summe++; 878 } 879 PUNKTE*=summe; 880 } 881 return PUNKTE; 882 } 883 884 public boolean warschon(int i,int k,ArrayList<int[]> sammel_ik) 885 { 886 for(int p=0;p<sammel_ik.size();p++) 887 if(i==sammel_ik.get(p)[0] && k==sammel_ik.get(p)[1]) 888 return true; 889 return false; 890 } 891 892 public ArrayList<int[]> findeNaechstenpfad(boolean weiss) 893 { 894//if(weiss) 895//println("Suche weiss"); 896//else 897//println("Suche schwarz"); 898 899 900 ArrayList<int[]> sammel_ik = new ArrayList<int[]>(); 901 902 //1. Startpunkt suchen: 903 println(); 904 for(int i=0;i<matrix.length;i++) 905 { 906 for(int k=0;k<matrix[i].length;k++) 907 { 908 909 int ID = matrix[i][k]; 910 if(WARTUNG) 911 { 912 if(ID==0) 913 print(0); 914 else if(istQuelle(ID) && istWeiss(ID)) 915 print("W"); 916 else if(istQuelle(ID) && !istWeiss(ID)) 917 print("S"); 918 else 919 print("x"); 920 } 921 if(weiss) 922 { 923 if(ID>0 && istQuelle(ID) && istWeiss(ID)) 924 { 925 sammel_ik.add(new int[] {i,k}); 926 } 927 } 928 else 929 { 930 if(ID>0 && istQuelle(ID) && !istWeiss(ID)) 931 { 932 sammel_ik.add(new int[] {i,k}); 933 } 934 } 935 } 936 if(WARTUNG) 937 println(); 938 } 939if(WARTUNG) 940println("Quellanz="+sammel_ik.size()); 941 //2. Immer die k\u00fcrzeste Verbindung suchen. 942 while(sammel_ik.size()>0) //Abbruch, wenn kein neuer gefunden wird. 943 { 944 int i_start = sammel_ik.get(sammel_ik.size()-1)[0]; 945 int k_start = sammel_ik.get(sammel_ik.size()-1)[1]; 946 947 int[][] merker = new int[4][4]; // i k ID dist, wenn ID 0 == nix gefunden 948 for(int p=k_start+1;p<matrix[0].length;p++) 949 { 950 int ID = matrix[i_start][p]; 951 if(istQuelle(ID)) 952 break; //andere Quelle blockiert weitergehen! 953 if(ID>0 && !istQuelle(ID) && !warschon(i_start,p,sammel_ik)) //solche, die schon waren \u00fcbergehen! 954 { 955 merker[0][0] = i_start; 956 merker[0][1] = p; 957 merker[0][2] = matrix[i_start][p]; //ID 958 merker[0][3] = p - k_start; //dist (>0) 959 break; 960 } 961 else if(warschon(i_start,p,sammel_ik)) //auch abbrechen, wenn einer im Weg ist, der schon war! 962 { 963 break; 964 } 965 } 966 //3 weitere... 967 for(int p=k_start-1;p>=0;p--) 968 { 969 int ID = matrix[i_start][p]; 970 if(istQuelle(ID)) 971 break; //andere Quelle blockiert weitergehen! 972 if(ID>0 && !istQuelle(ID) && !warschon(i_start,p,sammel_ik)) //solche, die schon waren \u00fcbergehen! 973 { 974 merker[1][0] = i_start; 975 merker[1][1] = p; 976 merker[1][2] = matrix[i_start][p]; //ID 977 merker[1][3] = k_start - p; //dist (>0) 978 break; 979 } 980 else if(warschon(i_start,p,sammel_ik)) //auch abbrechen, wenn einer im Weg ist, der schon war! 981 { 982 break; 983 } 984 } 985 for(int p=i_start+1;p<matrix.length;p++) 986 { 987 int ID = matrix[p][k_start]; 988 if(istQuelle(ID)) 989 break; //andere Quelle blockiert weitergehen! 990 if(ID>0 && !istQuelle(ID) && !warschon(p,k_start,sammel_ik)) //solche, die schon waren \u00fcbergehen! 991 { 992 merker[2][0] = p; // i k ID dist, wenn ID 0 == nix gefunden 993 merker[2][1] = k_start; 994 merker[2][2] = matrix[p][k_start]; //ID 995 merker[2][3] = p - i_start; //dist (>0) 996 break; 997 } 998 else if(warschon(p,k_start,sammel_ik)) //auch abbrechen, wenn einer im Weg ist, der schon war! 999 { 1000 break; 1001 } 1002 } 1003 for(int p=i_start-1;p>=0;p--) 1004 { 1005 int ID = matrix[p][k_start]; 1006 if(istQuelle(ID)) 1007 break; //andere Quelle blockiert weitergehen! 1008 if(ID>0 && !istQuelle(ID) && !warschon(p,k_start,sammel_ik)) //solche, die schon waren \u00fcbergehen! 1009 { 1010 merker[3][0] = p; // i k ID dist, wenn ID 0 == nix gefunden 1011 merker[3][1] = k_start; 1012 merker[3][2] = matrix[p][k_start]; //ID 1013 merker[3][3] = i_start - p; //dist (>0) 1014 break; 1015 } 1016 else if(warschon(p,k_start,sammel_ik)) //auch abbrechen, wenn einer im Weg ist, der schon war! 1017 { 1018 break; 1019 } 1020 } 1021 1022 //Pr\u00fcfen, ob Nachfolger dabei ist, oder Abbruch n\u00f6tig: 1023 int dist_best = Integer.MAX_VALUE; 1024 int dist_zweitbest = Integer.MAX_VALUE; 1025 int i_best = -1; 1026 int k_best = -1; 1027 1028 for(int i=0;i<merker.length;i++) 1029 { 1030 int i_test = merker[i][0]; 1031 int k_test = merker[i][1]; 1032 int id_test = merker[i][2]; 1033 int dist_test = merker[i][3]; 1034 1035 if(id_test>0 && dist_test<=dist_best) 1036 { 1037 dist_zweitbest = dist_best; 1038 dist_best = dist_test; 1039 i_best = i_test; 1040 k_best = k_test; 1041 } 1042 } 1043 1044 if(i_best>-1 && k_best>-1 && dist_best<dist_zweitbest && !warschon(i_best,k_best,sammel_ik)) //muss echt n\u00e4chster sein ohne Auswahlm\u00f6glichkeit 1045 { 1046 sammel_ik.add(new int[] {i_best,k_best,dist_best}); 1047 } 1048 else 1049 { 1050 break; //wenn keiner mehr gefunden wird, der echt am n\u00e4chsten an dem zuletzt gefundenen liegt ohne wdh. 1051 } 1052 } 1053 1054 return sammel_ik; 1055 } 1056} 1057 1058 1059public class Spieler implements Runnable 1060{ 1061// Random zufall = new Random(System.currentTimeMillis()); 1062 Random zufall = new Random(0); 1063 1064 boolean WEISS; 1065 Spielfeld spielfeld; 1066 Spiel spiel; 1067 Spiel testspiel; 1068 Spiel testspiel2; 1069 public Spieler(boolean WEISS, Spielfeld spielfeld, Spiel spiel, Spiel testspiel, Spiel testspiel2) 1070 { 1071 this.WEISS = WEISS; 1072 this.spiel = spiel; 1073 this.testspiel = testspiel; 1074 this.testspiel2 = testspiel2; 1075 this.spielfeld = spielfeld; 1076 1077 (new Thread(this)).start(); 1078 } 1079 1080 public void run() 1081 { 1082 while(true) 1083 { 1084 if(spielfeld.WEISS_IST_DRAN == WEISS && spielfeld.TIMER_WEISS_IST_DRAN == WEISS ) //ist dran und darf loslegen 1085 { 1086 //Pr\u00fcfen, ob schon Quelle auf dem Feld ist, wenn nicht diese setzen 1087 Karte quelle = quelleweiss; 1088 if(!WEISS) 1089 quelle = quelleschwarz; 1090 int ID = quelle.ID; 1091 if(!spiel.istAufSpielfeld(ID)) 1092 { 1093//println("Nicht auf Feld"); 1094 int i = zufall.nextInt(spiel.matrix.length); 1095 int k = zufall.nextInt(spiel.matrix[0].length); 1096 while(spiel.matrix[i][k]>0) 1097 { 1098 i = zufall.nextInt(spiel.matrix.length); 1099 k = zufall.nextInt(spiel.matrix[0].length); 1100 } 1101//println("setze auf "+i+" "+k); 1102 spiel.matrix[i][k] = ID; 1103 } 1104 else 1105 { 1106 spiel.kopiereAufAnderesSpiel(testspiel); 1107 spiel.kopiereAufAnderesSpiel(testspiel2); 1108 int punkte_best = 0; 1109 for(int i=0;i<3;i++) 1110 { 1111 spiel.kopiereAufAnderesSpiel(testspiel); 1112 int punkte = zufallszug(testspiel); 1113 if(punkte>=punkte_best) 1114 { 1115 punkte_best = punkte; 1116 testspiel.kopiereAufAnderesSpiel(testspiel2); 1117 } 1118 } 1119 testspiel2.kopiereAufAnderesSpiel(spiel); 1120 } 1121 1122 //abschliessen: 1123 //JETZT IST DER ANDERE DRAN! 1124 spiel.schreibeZustand(); 1125 updateSpielzustand(); 1126 spielfeld.WEISS_IST_DRAN = !spielfeld.WEISS_IST_DRAN; 1127 1128 1129 } 1130 1131 1132 try 1133 { 1134 Thread.sleep(1000); 1135 } 1136 catch(Exception e) 1137 { 1138 } 1139 }//while true 1140 }//run 1141 1142 1143 public boolean spielfeldVoll(Spiel spiel) 1144 { 1145 for(int i=0;i<spiel.matrix.length;i++) 1146 for(int k=0;k<spiel.matrix[0].length;k++) 1147 if(spiel.matrix[i][k]==0) 1148 return false; 1149 return true; 1150 } 1151 1152 public int spielfeldProzentVoll(Spiel spiel) 1153 { 1154 int anz = 0; 1155 int sum = spiel.matrix.length*spiel.matrix[0].length; 1156 for(int i=0;i<spiel.matrix.length;i++) 1157 for(int k=0;k<spiel.matrix[0].length;k++) 1158 if(spiel.matrix[i][k]!=0) 1159 anz++; 1160 return (anz*100)/sum; 1161 } 1162 1163 1164 public int[] zufalls_ik(Spiel spiel) 1165 { 1166 int i = zufall.nextInt(spiel.matrix.length); 1167 int k = zufall.nextInt(spiel.matrix[0].length); 1168 while(spiel.matrix[i][k]>0) 1169 { 1170 i = zufall.nextInt(spiel.matrix.length); 1171 k = zufall.nextInt(spiel.matrix[0].length); 1172 } 1173 return new int[] {i,k}; 1174 } 1175 1176 public int[] zufalls_ik_besetztEigeneFarbe(Spiel spiel) //liefert Platz, der besetrzt ist mit eigener Farbe und nicht Quelle 1177 { 1178 int i = zufall.nextInt(spiel.matrix.length); 1179 int k = zufall.nextInt(spiel.matrix[0].length); 1180 while(spiel.matrix[i][k]==0 || spiel.istWeiss(spiel.matrix[i][k])!=WEISS || spiel.istQuelle(spiel.matrix[i][k])) 1181 { 1182 i = zufall.nextInt(spiel.matrix.length); 1183 k = zufall.nextInt(spiel.matrix[0].length); 1184 } 1185 return new int[] {i,k}; 1186 } 1187 1188 1189 public void entferneID(int ID,Spiel spiel) 1190 { 1191 for(int i=0;i<spiel.matrix.length;i++) 1192 for(int k=0;k<spiel.matrix[0].length;k++) 1193 if(spiel.matrix[i][k]==ID) 1194 { 1195 spiel.matrix[i][k]=0; 1196 return; 1197 } 1198 } 1199 1200 public int bestimmePunkte(Spiel spiel, boolean WEISS) 1201 { 1202 if(WEISS) 1203 { 1204 return spiel.berechnePunkte(spiel.findeNaechstenpfadWeiss()); 1205 } 1206 else 1207 { 1208 return spiel.berechnePunkte(spiel.findeNaechstenpfadSchwarz()); 1209 } 1210 } 1211 1212 public int zufallszug(Spiel spiel) //Liefert auch mit dem Zug erreichbare Punkte 1213 { 1214 if( spielfeldProzentVoll(spiel) > 30 ) //wenn zu 60% voll, dann in jedem Fall etwas entfernen 1215 { 1216 int[] ik = zufalls_ik_besetztEigeneFarbe(spiel); //sucht besetzten Platz eigener Farbe 1217 1218 spiel.matrix[ik[0]][ik[1]] = 0; 1219 1220 1221 //return bestimmePunkte(spiel,WEISS)-bestimmePunkte(spiel,!WEISS); 1222 return bestimmePunkte(spiel,WEISS); 1223 } 1224 else if( spielfeldProzentVoll(spiel) > 10 && zufall.nextInt(100)<50) //wenn zu 60% voll, dann in jedem Fall etwas entfernen 1225 { 1226 int[] ik = zufalls_ik_besetztEigeneFarbe(spiel); //sucht besetzten Platz 1227 1228 spiel.matrix[ik[0]][ik[1]] = 0; 1229 1230 //return bestimmePunkte(spiel,WEISS)-bestimmePunkte(spiel,!WEISS); 1231 return bestimmePunkte(spiel,WEISS); 1232 } 1233 1234 int inx = zufall.nextInt(karte.length); 1235 int ID = karte[inx].ID; 1236 while(spiel.istWeiss(ID)!=WEISS) 1237 { 1238 inx = zufall.nextInt(karte.length); 1239 ID = karte[inx].ID; 1240 } 1241 1242 if(spiel.istAufSpielfeld(ID)) //dann verschieben 1243 { 1244 entferneID(ID,spiel); 1245 int[] ik = zufalls_ik(spiel); 1246 spiel.matrix[ik[0]][ik[1]] = ID; 1247 } 1248 else //dann neu setzen 1249 { 1250 int[] ik = zufalls_ik(spiel); 1251 spiel.matrix[ik[0]][ik[1]] = ID; 1252 } 1253 1254 //return bestimmePunkte(spiel,WEISS)-bestimmePunkte(spiel,!WEISS); 1255 return bestimmePunkte(spiel,WEISS); 1256 } 1257} 1258public class Spielfeld 1259{ 1260 public boolean WEISS_IST_DRAN = true; 1261 public boolean TIMER_WEISS_IST_DRAN = true; 1262 1263 public float[][] ikoord; //Koordinaten des Spielfeldes 1264 public float[][] kkoord; //Koordinaten des Spielfeldes 1265 1266 int anzx,anzy; 1267 float kantex,kantey; 1268 float mx; 1269 float my; 1270 1271 float x; 1272 float y; 1273 1274 float b,h; 1275 1276 public Karte[][] matrix; //mit belegten Feldern 1277 1278 public Spielfeld(float kantex, float kantey,int anzx, int anzy) 1279 { 1280 this.anzx=anzx; 1281 this.anzy=anzy; 1282 this.kantex=kantex; 1283 this.kantey=kantey; 1284 this.matrix = new Karte[anzy][anzx+1]; //HACK. anzx mu\u00df ungerade sein, Breite wird dann komischerweise gerade wg. Darstellung 1285 this.mx = width/2.0f; 1286 this.my = height/2.0f; 1287 1288 this.x = mx - kantex*(0.5f*(float)anzx); 1289 this.y = my - kantey*(0.5f*(float)anzy); 1290 this.b = anzx*kantex; 1291 this.h = anzy*kantey; 1292 1293 ikoord = new float[matrix.length][matrix[0].length]; 1294 kkoord = new float[matrix.length][matrix[0].length]; 1295 for(int i=0;i<matrix.length;i++) 1296 { 1297 for(int k=0;k<matrix[i].length;k++) 1298 { 1299 // rect(x+(k+i%2)*kantex-kantex*0.5f,y+i*kantey,kantex,kantey,60); 1300 float xxx = x+k*kantex-kantex*0.5f; 1301 float yyy = y+i*kantey; 1302 ikoord[i][k] = yyy + kantey*0.5f; 1303 kkoord[i][k] = xxx + kantex*0.5f; 1304 } 1305 } 1306 } 1307 1308 public void draw() 1309 { 1310 //noFill(); 1311 //stroke(95); 1312 noStroke(); 1313 fill(127); 1314 for(int i=0;i<anzy;i++) 1315 { 1316 for(int k=0;k<anzx;k+=2) 1317 { 1318 rect(x+(k+i%2)*kantex-kantex*0.5f,y+i*kantey,kantex,kantey,60); 1319 } 1320 } 1321 1322 //fill(64); 1323 for(int i=0;i<anzy;i++) 1324 { 1325 for(int k=0;k<anzx;k+=2) 1326 { 1327 rect(x+(k+(i+1)%2)*kantex-kantex*0.5f,y+i*kantey,kantex,kantey,60); 1328 } 1329 } 1330 1331 } 1332 1333 public boolean istInSpielfeld(Karte k) 1334 { 1335 float mausx = k.x - k.xoff; 1336 float mausy = k.y - k.yoff; 1337 1338 if(mausx>x-kantex*0.4f && mausx<x+b+kantex*0.4f && mausy>y && mausy<y+h) 1339 return true; 1340 else 1341 return false; 1342 } 1343 1344 public float getNextX(Karte k) 1345 { 1346 float mausx = k.x - k.xoff+kantex*0.5f; 1347 return x + kantex*floor((mausx-x)/kantex)-kantex*0.5f; 1348 } 1349 1350 public float getNextXausK(int kkk) 1351 { 1352 return x + kantex*kkk-kantex*0.5f; 1353 } 1354 1355 public float getNextY(Karte k) 1356 { 1357 float mausy = k.y - k.yoff; 1358 return y + kantey*floor((mausy-y)/kantey); 1359 } 1360 1361 public float getNextYausI(int iii) 1362 { 1363 return y + kantey*iii; 1364 } 1365 1366 1367 public int getNextXindex(Karte k) 1368 { 1369 float mausx = k.x - k.xoff+kantex*0.5f; 1370 return (int)floor((mausx-x)/kantex); 1371 } 1372 1373 public int getNextYindex(Karte k) 1374 { 1375 float mausy = k.y - k.yoff; 1376 return (int)floor((mausy-y)/kantey); 1377 } 1378 1379 public boolean istFrei(int i, int k) 1380 { 1381 if(matrix[i][k]==null) 1382 return true; 1383 else 1384 return false; 1385 } 1386 1387 public boolean istAufSpielfeld(Karte karte) 1388 { 1389 for(int i=0;i<matrix.length;i++) 1390 for(int k=0;k<matrix[i].length;k++) 1391 if(matrix[i][k]!=null && karte!=null && matrix[i][k].ID==karte.ID) 1392 return true; 1393 return false; 1394 } 1395} 1396 1397 1398 1399 1400public class Zugkontrolle implements Runnable 1401{ 1402 private long WERT_WEISS = 0; 1403 private long WERT_SCHWARZ = 0; 1404 private long FREQ_WEISS = 0; 1405 private long FREQ_SCHWARZ = 0; 1406 private long MIDI_WEISS = 0; 1407 private long MIDI_SCHWARZ = 0; 1408 1409 private long FFREQ = 0; 1410 private long MMID = 0; 1411//Basiszahl: 2*2*2*3*3*5*7 == 2520 == 7*360 1412//Faktor: 1 1413//fmin: 55 == KA 1414//fmax: 1760 == a''' 1415 1416 private long BASISZAHL = 2520; 1417 private long FAKTOR = 1; 1418 private long FMIN = 55; 1419 private long FMAX = 1760; 1420 1421 private ScheduledExecutorService schedExecService; //realtime process 1422 1423 private Spielfeld spielfeld; 1424 1425 1426 long PULSMILLIS; 1427 long PULSEPROZUG; 1428 long t; 1429 int STRAFPUNKTE; 1430 public Zugkontrolle(long PULSMILLIS, long PULSEPROZUG, Spielfeld spielfeld, int STRAFPUNKTE) 1431 { 1432 1433 this.STRAFPUNKTE = STRAFPUNKTE; 1434 this.spielfeld = spielfeld; 1435 this.PULSMILLIS = PULSMILLIS; 1436 this.PULSEPROZUG = PULSEPROZUG; 1437 1438 t=0; 1439 schedExecService = Executors.newSingleThreadScheduledExecutor(); 1440 schedExecService.scheduleAtFixedRate(this, 0, PULSMILLIS, TimeUnit.MILLISECONDS); 1441 1442 } 1443 1444 public long berechneWertAusPfad(long t,ArrayList<int[]> pfad, boolean WEISS) 1445 { 1446 long erg = t; 1447 try 1448 { 1449 for(int i=1;i<pfad.size();i++) 1450 { 1451 int ID = spiel.matrix[pfad.get(i)[0]][pfad.get(i)[1]]; 1452 long operand = spiel.farbeVonID(ID); //==farbe 1,2,3,4,5,6 1453 1454//NEU: dist ber\u00fccksichtigen 1455operand*=pfad.get(i)[2]; 1456 1457 //typ 9 ist Quelle, 0..8== .|..|...|-|--|---|+|++|+++ 1458 // 0 1 2 3 4 5 6 7 8 1459 // * / gt - = % + 1460 int operator = 3*spiel.formVonID(ID) + spiel.anzahlVonID(ID); 1461 switch(operator) 1462 { 1463 case 0: // . 1464 erg *= operand; 1465 break; 1466 case 1: // .. 1467 erg/=operand; 1468 break; 1469 case 2: // ... gemeinsame Teiler finden und durch ihre Gesamtprodukt teilen. 1470 long teiler=1; 1471 for(int p=2;p<=operand;p++) 1472 if(operand%p==0 && erg%p==0) 1473 teiler*=p; 1474 erg/=teiler; 1475 break; 1476 case 3: // - 1477 erg-=operand; 1478 if(erg<0) 1479 erg=0; 1480 break; 1481 case 4: // -- 1482 if(erg==operand) 1483 erg = operand; 1484 else 1485 erg = 0; 1486 break; 1487 case 5: // --- Modulo 1488 if(operand>0) 1489 erg%=operand; 1490 else 1491 erg = erg; 1492 break; 1493 case 6: // + 1494 erg+=operand; 1495 break; 1496 case 7: // ++ als UNGLEICH behandeln 1497 if(erg!=operand) 1498 erg = erg; 1499 else 1500 erg = 0; 1501 break; 1502 case 8: // +++ , wie ..., aber multiplizieren statt dividieren 1503 long faktor=1; 1504 for(int p=2;p<=operand;p++) 1505 if(operand%p==0 && erg%p==0) 1506 faktor*=p; 1507 erg*=faktor; 1508 break; 1509 } 1510 1511 if(erg>0 && BASISZAHL%erg==0) 1512 { 1513 FREQ_WEISS = BASISZAHL/(erg*FAKTOR); 1514 if(FREQ_WEISS<FMIN) 1515 FREQ_WEISS=0; 1516 if(FREQ_WEISS>FMAX) 1517 FREQ_WEISS=0; 1518 if(FREQ_WEISS>0) 1519 { 1520 MIDI_WEISS = freq2mid((int)FREQ_WEISS); 1521 if(MIDI_WEISS>0 && WEISS) 1522 { 1523 msp.play(0+i%2,(int)MIDI_WEISS); //2 M\u00f6gl. je nach Pos. in Kette 1524// msp.playMono(0,(int)MIDI_WEISS); 1525 if(RECORDING==true) 1526 { 1527 //add(int pulsnr, int spielernr, int steinnr, int zeile, int spalte, int midi) 1528 rekorder.add((int)t,0,i,(int)pfad.get(i)[0],(int)pfad.get(i)[1],(int)MIDI_WEISS); 1529 rekorder.addToScore(t,0,(int)MIDI_WEISS); 1530 } 1531 } 1532 else if(MIDI_WEISS>0 && !WEISS) 1533 { 1534 msp.play(2+i%2,(int)MIDI_WEISS); 1535// msp.playMono(1,(int)MIDI_WEISS); 1536 if(RECORDING==true) 1537 { 1538 //add(int pulsnr, int spielernr, int steinnr, int zeile, int spalte, int midi) 1539 rekorder.add((int)t,1,i,(int)pfad.get(i)[0],(int)pfad.get(i)[1],(int)MIDI_WEISS); 1540 rekorder.addToScore(t,1,(int)MIDI_WEISS); 1541 } 1542 } 1543 } 1544 1545 } 1546 } 1547 } 1548 catch(Exception e) 1549 { 1550 println(e); 1551 return 0; 1552 } 1553 return erg; 1554 } 1555long ANZ=0; 1556 public void run() 1557 { 1558 if(t%PULSEPROZUG==0 && t>0) 1559 { 1560 if(spielfeld.WEISS_IST_DRAN != spielfeld.TIMER_WEISS_IST_DRAN) 1561 { 1562 spielfeld.TIMER_WEISS_IST_DRAN = !spielfeld.TIMER_WEISS_IST_DRAN; 1563 } 1564 else 1565 { 1566 if(spielfeld.WEISS_IST_DRAN && PUNKTE_WEISS>=STRAFPUNKTE) 1567 PUNKTE_WEISS-=STRAFPUNKTE; 1568 else if(spielfeld.WEISS_IST_DRAN && PUNKTE_WEISS<STRAFPUNKTE) 1569 PUNKTE_WEISS=0; 1570 else if(!spielfeld.WEISS_IST_DRAN && PUNKTE_SCHWARZ>=STRAFPUNKTE) 1571 PUNKTE_SCHWARZ-=STRAFPUNKTE; 1572 else if(!spielfeld.WEISS_IST_DRAN && PUNKTE_SCHWARZ<STRAFPUNKTE) 1573 PUNKTE_SCHWARZ=0; 1574 if(WARTUNG) 1575 println("Nach Strafpunkten: W:"+PUNKTE_WEISS+" S:"+PUNKTE_SCHWARZ); 1576 } 1577 } 1578 //Werte aus Pfaden berechnen: 1579 if(weisserpfad!=null && weisserpfad.size()>1) 1580 { 1581 WERT_WEISS = berechneWertAusPfad(t,weisserpfad,true); 1582 } 1583 else 1584 { 1585 WERT_WEISS = 0; 1586 } 1587 if(schwarzerpfad!=null && schwarzerpfad.size()>1) 1588 { 1589 WERT_SCHWARZ = berechneWertAusPfad(t,schwarzerpfad,false); 1590 } 1591 else 1592 { 1593 WERT_SCHWARZ = 0; 1594 } 1595FFREQ=0; 1596 if(WERT_WEISS>0 && BASISZAHL%(WERT_WEISS*FAKTOR)==0) 1597 { 1598 FREQ_WEISS = BASISZAHL/(WERT_WEISS*FAKTOR); 1599 if(FREQ_WEISS<FMIN) 1600 FREQ_WEISS=0; 1601 if(FREQ_WEISS>FMAX) 1602 FREQ_WEISS=0; 1603 if(FREQ_WEISS>0) 1604 { 1605 MIDI_WEISS = freq2mid((int)FREQ_WEISS); 1606 FFREQ += FREQ_WEISS; 1607 } 1608 } 1609 else 1610 { 1611 FREQ_WEISS = 0; 1612 } 1613 1614 if(WERT_SCHWARZ>0 && BASISZAHL%(WERT_SCHWARZ*FAKTOR)==0) 1615 { 1616 FREQ_SCHWARZ = BASISZAHL/(WERT_SCHWARZ*FAKTOR); 1617 if(FREQ_SCHWARZ<FMIN) 1618 FREQ_SCHWARZ=0; 1619 if(FREQ_SCHWARZ>FMAX) 1620 FREQ_SCHWARZ=0; 1621 if(FREQ_SCHWARZ>0) 1622 { 1623 MIDI_SCHWARZ = freq2mid((int)FREQ_SCHWARZ); 1624 FFREQ += FREQ_SCHWARZ; 1625 } 1626 1627 } 1628 else 1629 { 1630 FREQ_WEISS = 0; 1631 } 1632 1633// if(MIDI_SCHWARZ>0) 1634// msp.play(1,(int)MIDI_SCHWARZ); 1635// if(MIDI_WEISS>0) 1636// msp.play(0,(int)MIDI_WEISS); 1637// if(FFREQ>0) 1638// { 1639// MMID = freq2mid((int)FFREQ); 1640// if(MMID>0) 1641// msp.play(0,(int)MMID); 1642// } 1643 1644 //print(WERT_WEISS+"|"+WERT_SCHWARZ+" "); 1645 print(MIDI_WEISS+"|"+MIDI_SCHWARZ+" "); 1646 1647 ANZ++; 1648 if(ANZ>=PULSEPROZUG) 1649 { 1650 println("###"); 1651 ANZ=0; 1652 } 1653 1654 t++; 1655 1656 } 1657} 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667public class FastSoundplayer implements Runnable 1668{ 1669 int MAXPOLY = 200; //Maximale Anzahl aktuell noch abzuarbeitender Samples 1670 float[][][] sample = new float[MAXPOLY][][]; 1671 int[] index = new int[MAXPOLY]; 1672 float[][] sampleMono = new float[MAXPOLY][]; 1673 float[][] panMono = new float[MAXPOLY][2]; //wird mit \u00fcbernommen! 1674 int[] indexMono = new int[MAXPOLY]; 1675 //der play-Funktion wird ein Sample \u00fcbergeben und der korrespondierende Index wird auf Null gesetzt, alles, wenn noch 1676 //Platz im Array sample. 1677 //erreicht index die L\u00e4nge des samples wird dieses entfernt und damit der Platz f\u00fcr nachfolgende Samples frei gegeben. 1678 1679 int sr = 44100; 1680 int buffsize = 512; 1681 int buffsize2 = buffsize*2; 1682 public float[] mikrofon_welle = new float[buffsize2]; 1683 float dt = 1.0f/(float)sr; 1684 float dth = 0.5f*dt; 1685 protected ScheduledExecutorService schedExecService; 1686 short[] puffer = new short[buffsize*2]; //4 Byte pro Sample == 16Bit Stereo //2 * bei short 1687 float[] fpuffer = new float[buffsize*2]; //4 Byte pro Sample == 16Bit Stereo //2 * bei short 1688 public float t=0.0f; 1689 1690 private AudiotrackMic track; 1691 1692 public void play(float[][] data) 1693 { 1694 for(int i=0;i<sample.length;i++) 1695 { 1696 if(sample[i]==null) 1697 { 1698 sample[i]=data; 1699 index[i]=0; 1700 break; 1701 } 1702 } 1703 } 1704 1705 public void playMono(float[] data) 1706 { 1707 for(int i=0;i<sampleMono.length;i++) 1708 { 1709 if(sampleMono[i]==null) 1710 { 1711 sampleMono[i]=data; 1712 indexMono[i]=0; 1713 panMono[i][0] = 0.1f; //s\u00e4ter wird von au\u00dfen die Richtung berechnet und mit \u00fcbergeben 1714 panMono[i][1] = 0.1f; 1715 break; 1716 } 1717 } 1718 } 1719 1720 1721 public FastSoundplayer() 1722 { 1723 1724 track = new AudiotrackMic(sr,buffsize); 1725 schedExecService = Executors.newSingleThreadScheduledExecutor(); 1726 long period = (buffsize*1000)/sr; //Seconds per Beat==60/BPM, die H\u00e4lfte weil 8tel, mal 1000 weil Millisekunden. 1727 schedExecService.scheduleAtFixedRate(this, 0, period, TimeUnit.MILLISECONDS); 1728 } 1729 1730 public void run() 1731 { 1732 runStereo(); 1733// runMono(); 1734 } 1735 1736 public void runStereo() 1737 { 1738 //Neues Vorgehen: 1739 for(int k=0;k<fpuffer.length;k++) 1740 fpuffer[k]=0.0f; 1741//STEREO: 1742 for(int i=0;i<sample.length;i++) 1743 { 1744 float[][] data = sample[i]; //Threadsicher machen, indem Referenz erst einmal gemerkt / gesichert wird. 1745 if(data!=null) 1746 { 1747 for(int k=0;k<puffer.length;k+=2) 1748 { 1749 if(index[i]>=data[0].length) 1750 { 1751 sample[i]=null; 1752 break; 1753 } 1754 fpuffer[k+0] += data[0][index[i]]; 1755 fpuffer[k+1] += data[1][index[i]]; 1756 index[i]++; 1757 } 1758 } 1759 } 1760 for(int k=0;k<fpuffer.length;k++) 1761 puffer[k]=(short)(32767.0f*fpuffer[k]+0.5f); 1762 1763 //audioTrack.write(puffer, 0,buffsize2); 1764 mikrofon_welle = track.write(puffer); 1765 } 1766 1767 public void runMono() 1768 { 1769 //Neues Vorgehen: 1770 for(int k=0;k<fpuffer.length;k++) 1771 fpuffer[k]=0.0f; 1772//MONO: 1773 for(int i=0;i<sampleMono.length;i++) 1774 { 1775 float[] dataMono = sampleMono[i]; //Threadsicher machen, indem Referenz erst einmal gemerkt / gesichert wird. 1776 if(dataMono!=null) 1777 { 1778 for(int k=0;k<puffer.length;k+=2) 1779 { 1780 if(indexMono[i]>=dataMono.length) 1781 { 1782 sampleMono[i]=null; 1783 break; 1784 } 1785 fpuffer[k+0] += dataMono[indexMono[i]] * panMono[i][0]; 1786 fpuffer[k+1] += dataMono[indexMono[i]] * panMono[i][1]; 1787 indexMono[i]++; 1788 } 1789 } 1790 } 1791 for(int k=0;k<fpuffer.length;k++) 1792 puffer[k]=(short)(32767.0f*fpuffer[k]+0.5f); 1793 1794 //audioTrack.write(puffer, 0,buffsize2); 1795 mikrofon_welle = track.write(puffer); 1796 } 1797 1798} 1799 1800/** 1801 * Interface f\u00fcr Audiostream mit zus\u00e4tzlichem Mikrofonkanal 1802 */ 1803public interface iAudiotrackMic 1804{ 1805 public abstract float[] write(short[] puffer); 1806} 1807 1808public class AudiotrackMic implements iAudiotrackMic 1809{ 1810 // instance variables - replace the example below with your own 1811 private iAudiotrackMic track; 1812 public short[] shortpuffer; 1813 public float[] micpuffer; 1814 protected ScheduledExecutorService schedExecService; 1815 1816 public AudiotrackMic(int SAMPLING_RATE, int buffsize) 1817 { 1818 shortpuffer = new short[buffsize*2]; //2* weil Stereo 1819 micpuffer = new float[buffsize*2]; 1820 1821 track = new AudiotrackMicPC(SAMPLING_RATE, buffsize); 1822 1823 } 1824 1825 public float[] write(short[] shortpuffer) 1826 { 1827 return track.write(shortpuffer); 1828 } 1829 1830 1831} 1832 1833public class AudiotrackMicPC implements iAudiotrackMic 1834{ 1835 int BYTEPUFFERGROESSE; 1836 int SAMPLING_RATE; 1837 1838 SourceDataLine line; 1839 TargetDataLine targetLine; //Mikrofon 1840 DataLine.Info info; 1841 DataLine.Info targetInfo; //Mikrofon 1842 1843 AudioFormat format; 1844 1845 //AudioTrack audioTrack; 1846 //int sr = 11025; 1847 //Versuchen die Qualit\u00e4t zu verbessern: 1848 1849 //int buffsize = 512; 1850 int buffsize; 1851 int buffsize2; 1852 1853 byte[] bytepuffer; 1854 byte[] targetData; 1855 float[] targetWelle; 1856 public AudiotrackMicPC(int SAMPLING_RATE, int buffsize) 1857 { 1858 this.SAMPLING_RATE = SAMPLING_RATE; 1859 this.buffsize = buffsize; 1860 this.buffsize2 = buffsize*2; 1861 this.BYTEPUFFERGROESSE = buffsize*4; 1862 1863 bytepuffer = new byte[BYTEPUFFERGROESSE]; 1864 targetData = new byte[BYTEPUFFERGROESSE]; 1865 targetWelle = new float[buffsize2]; 1866 for(int i=0;i<bytepuffer.length;i++) 1867 bytepuffer[i]=0; 1868 1869 this.format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,(float)SAMPLING_RATE, 16, 2, 4, (float)SAMPLING_RATE, false); 1870 this.info = new DataLine.Info(SourceDataLine.class, format); 1871 this.targetInfo = new DataLine.Info(TargetDataLine.class, format); 1872 if (!AudioSystem.isLineSupported(info)) 1873 { 1874 System.out.println("Line matching " + info + " is not supported."); 1875 //throw new LineUnavailableException(); 1876 } 1877 //format = new AudioFormat(SAMPLERATE, 16, 2, true, true); 1878 try 1879 { 1880 this.targetLine = (TargetDataLine) AudioSystem.getLine(targetInfo); 1881 this.targetLine.open(format); 1882 this.targetLine.start(); 1883 1884 this.line = (SourceDataLine)AudioSystem.getLine(info); 1885 this.line.open(format,BYTEPUFFERGROESSE); 1886 this.line.start(); 1887 } 1888 catch(Exception ee) 1889 { 1890 System.out.println("FEHLER: "+ee); 1891 } 1892 1893 } 1894 1895 public float[] write(short[] shortpuffer) 1896 { 1897 for (int i=0; i < buffsize; i++) 1898 { 1899 bytepuffer[i*4+1] = (byte)(shortpuffer[i*2+0]>>8); 1900 bytepuffer[i*4+0] = (byte)(shortpuffer[i*2+0] & 0xFF); 1901 bytepuffer[i*4+3] = (byte)(shortpuffer[i*2+1]>>8); 1902 bytepuffer[i*4+2] = (byte)(shortpuffer[i*2+1] & 0xFF); 1903 } 1904 targetLine.read(targetData, 0, targetData.length); 1905 line.write(bytepuffer, 0, BYTEPUFFERGROESSE); 1906 1907 for(int i=0;i<buffsize;i++) //Stereo! 1908 { 1909 //targetWelle[i*2+0] = (float)((targetData[i*4+0]<<8)+targetData[i*4+1])/32000.0f; 1910 //targetWelle[i*2+1] = (float)((targetData[i*4+2]<<8)+targetData[i*4+3])/32000.0f; 1911 targetWelle[i*2+0] = (float)((targetData[i*4+1]<<8)+targetData[i*4+0])/32000.0f; 1912 targetWelle[i*2+1] = (float)((targetData[i*4+3]<<8)+targetData[i*4+2])/32000.0f; 1913 } 1914 return targetWelle; //Mikrofondaten heraufreichen, um sie mit den anderen kan\u00e4len mischen zu k\u00f6nnen (ein paket verz\u00f6gert) 1915 1916 } 1917} 1918public class Mysoundplayer extends FastSoundplayer 1919{ 1920 Wav wav; 1921 int anzahl_kanaele; 1922 float[][][][] ton;// = new float[anzahl_kanaele][128][][]; //jeder Kanal hat 128 Pl\u00e4tze f\u00fcr 44100kHz stereo wav-Sound, belegt abh. von Skalen. 1923 1924 float[][][] mono; //Stimme, Nr, Sample 1925 1926 1927 int[] skala; 1928 int[] skalamap; 1929 1930 public Mysoundplayer(PApplet pap, int anzahl_kanaele) 1931 { 1932 this.anzahl_kanaele = anzahl_kanaele; 1933 wav = new Wav(pap); 1934 ton = new float[anzahl_kanaele][128][][]; //jeder Kanal hat 128 Pl\u00e4tze f\u00fcr 44100kHz stereo wav-Sound, belegt abh. von Skalen. 1935 } 1936 1937 public void ladeMonostimmen(int[] skala, String[] ordner, String prefix) 1938 { 1939 this.skala = skala; 1940 skalamap = new int[128]; 1941 for(int i=0;i<skala.length;i++) 1942 skalamap[skala[i]] = i; //um schnell aus Midi den Index zu gewinnen! 1943 mono = new float[ordner.length][skala.length][]; 1944 for(int i=0;i<mono.length;i++) 1945 { 1946 for(int k=0;k<mono[i].length;k++) 1947 { 1948 mono[i][k] = wav.ladeWavMix("data/"+ordner[i]+"/"+prefix+skala[k]+".wav"); 1949 } 1950 } 1951 } 1952 1953 public void ladeMonostimmen(int[] skala, String[] ordner, float[] verst, String prefix) 1954 { 1955 this.skala = skala; 1956 skalamap = new int[128]; 1957 for(int i=0;i<skala.length;i++) 1958 skalamap[skala[i]] = i; //um schnell aus Midi den Index zu gewinnen! 1959 mono = new float[ordner.length][skala.length][]; 1960 for(int i=0;i<mono.length;i++) 1961 { 1962 for(int k=0;k<mono[i].length;k++) 1963 { 1964 mono[i][k] = wav.ladeWavMix("data/"+ordner[i]+"/"+prefix+skala[k]+".wav"); 1965 } 1966 } 1967 1968 for(int i=0;i<mono.length;i++) 1969 { 1970 for(int k=0;k<mono[i].length;k++) 1971 { 1972 for(int p=0;p<mono[i][k].length;p++) 1973 mono[i][k][p] *= verst[i]; 1974 } 1975 } 1976 1977 } 1978 1979 1980 public void ladeKanal(int kanal, String ordnerpfad, int[] midiskala, float laute, float pan) 1981 { 1982 float pan_left = cos(pan*HALF_PI); 1983 float pan_right = sin(pan*HALF_PI); 1984 for(int i=0;i<midiskala.length;i++) 1985 { 1986 ton[kanal][midiskala[i]] = wav.ladeWavInterpolate(ordnerpfad,midiskala[i]); 1987 for(int k=0;k<ton[kanal][midiskala[i]][0].length;k++) 1988 { 1989 ton[kanal][midiskala[i]][0][k]*=laute*pan_left; 1990 ton[kanal][midiskala[i]][1][k]*=laute*pan_right; 1991 } 1992 } 1993 } 1994 1995 public void ladeKanalStereo(int kanal, String ordnerpfad, int[] midiskala, float laute, float pan) 1996 { 1997 float pan_left = cos(pan*HALF_PI); 1998 float pan_right = sin(pan*HALF_PI); 1999 for(int i=0;i<midiskala.length;i++) 2000 { 2001 ton[kanal][midiskala[i]] = wav.ladeWav(ordnerpfad+"/ton"+midiskala[i]+".wav"); 2002 for(int k=0;k<ton[kanal][midiskala[i]][0].length;k++) 2003 { 2004 ton[kanal][midiskala[i]][0][k]*=laute*pan_left; 2005 ton[kanal][midiskala[i]][1][k]*=laute*pan_right; 2006 } 2007 } 2008 } 2009 2010 public void saveKanal(int kanal, String pfad, int[] midiskala) 2011 { 2012 for(int i=0;i<midiskala.length;i++) 2013 { 2014 wav.saveWav(pfad+"/ton"+midiskala[i]+".wav",ton[kanal][midiskala[i]]); 2015 } 2016 } 2017 2018 public void play(int kanal, int midihoehe) 2019 { 2020 play(ton[kanal][midihoehe]); 2021 } 2022 2023 public void playMono(int kanal, int midihoehe) 2024 { 2025 playMono(mono[kanal][skalamap[midihoehe]]); 2026 } 2027 2028} 2029public class Rekorder 2030{ 2031 ArrayList<int[]> merker = new ArrayList<int[]>(); //PulsNr, SpielerNr, SteinNr., Zeile, Spalte, Midi 2032 int[][] score1; 2033 int[][] score2; 2034 long startzeit; 2035 long endzeit; 2036 public Rekorder(long startzeit, long endzeit) 2037 { 2038 this.startzeit = startzeit; 2039 this.endzeit = endzeit; 2040 score1 = new int[(int)(endzeit-startzeit+1)][128]; 2041 score2 = new int[(int)(endzeit-startzeit+1)][128]; 2042 } 2043 2044 public void saveMatrix(int[][] mat, String name) 2045 { 2046 String[] lines = new String[mat.length]; 2047 for(int i=0;i<mat.length;i++) 2048 { 2049 StringBuffer sb = new StringBuffer(); 2050 for(int k=0;k<mat[i].length;k++) 2051 { 2052 if(k<mat[i].length-1) 2053 sb.append(mat[i][k]+","); 2054 else 2055 sb.append(mat[i][k]); 2056 } 2057 lines[i] = sb.toString(); 2058 } 2059 saveStrings(name,lines); 2060 } 2061 2062 public void addToScore(long t, int spielernr, int midi) 2063 { 2064 if(t>endzeit) 2065 { 2066 return; 2067 } 2068 2069 if(spielernr==0) 2070 { 2071 score1[(int)(t-startzeit)][midi]++; 2072 } 2073 else 2074 { 2075 score2[(int)(t-startzeit)][midi]++; 2076 } 2077 2078 if(t==endzeit) 2079 { 2080 saveMatrix(score1,"score1.txt"); 2081 saveMatrix(score2,"score2.txt"); 2082 println("\n\n**** SCORE gespeichert **** \n"); 2083 return; 2084 } 2085 2086 } 2087 2088 public void add(int pulsnr, int spielernr, int steinnr, int zeile, int spalte, int midi) 2089 { 2090 merker.add(new int[] {pulsnr, spielernr, steinnr, zeile, spalte, midi}); 2091 } 2092 2093 public void save(String name) 2094 { 2095 String[] s = new String[merker.size()]; 2096 for(int i=0;i<s.length;i++) 2097 { 2098 int[] m = merker.get(i); 2099 String eintrag = ""; 2100 for(int k=0;k<m.length;k++) 2101 { 2102 if(k<m.length-1) 2103 eintrag+=""+m[k]+","; 2104 else 2105 eintrag+=""+m[k]; 2106 } 2107 s[i] = eintrag; 2108 } 2109 saveStrings(name,s); 2110 merker.clear(); 2111 } 2112 2113 public int[][] load(String name) 2114 { 2115 String[] s = loadStrings(name); 2116 int[][] erg = new int[s.length][]; 2117 for(int i=0;i<s.length;i++) 2118 { 2119 String[] spalten = PApplet.splitTokens(s[i], ","); 2120 int[] spal = new int[spalten.length]; 2121 for(int k=0;k<spal.length;k++) 2122 spal[k] = Integer.parseInt(spalten[k]); 2123 erg[i] = spal; 2124 } 2125 return erg; 2126 } 2127} 2128 2129 2130public interface iWav 2131{ 2132 public abstract void saveWav(String name, float[][] data); 2133 //float-Array wieder zur\u00fcck in ein byte-Array umwandeln (Vorbereitung speichern eines Stereokanals) 2134 public abstract byte[] toByte(float[][] data); 2135 //L\u00e4dt eine Stereo-Wav-Datei in zwei getrennten float-Arrays, Wertebereich [-1,+1]: 2136 public abstract float[][] ladeWav(String name); 2137 public abstract float[][] ladeWav(String name, int sampleanzahl); 2138 //L\u00e4dt eine Stereo-Wav-Datei, die dann zu einem Kanal gemischt wird und als float-Array zur\u00fcck gegeben wird. 2139 //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren) 2140 public abstract float[] ladeWavMix(String name); 2141 /** 2142 * L\u00e4dt eine Stereo-Datei, mixt sie zu Mono und baut sie zu einer loop-baren Variante 2143 * zusammen:<br/> 2144 * [AB] a=A ausblenden, b=B einblenden<br/> 2145 * ab + ba<br/> 2146 */ 2147 public abstract float[] ladeWavMixLoop(String name); //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren) 2148 //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren) 2149 public abstract float[] ladeWavMix(String name, int sampleanzahl); 2150 //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren) 2151 public abstract float[] ladeWavMixLoop(String name, int sampleanzahl); 2152 /** 2153 * L\u00e4dt wav-Files, die als 16-Bit Mono-Files vorliegen 2154 */ 2155 public abstract float[] ladeWavMono(String name); 2156 /** 2157 * Shows wav-data as Java-short-Array 2158 */ 2159 public abstract void showAsShortArray(float[] wav); 2160} 2161public class Wav implements iWav 2162{ 2163 private PApplet pap; 2164 2165 public Wav(PApplet pap) 2166 { 2167 this.pap = pap; 2168 } 2169 2170 2171 2172 public void saveWav(String name, float[][] data) 2173 { 2174 double gross = 0.5f*(255.0f*256.0f + 255.0f); 2175 double gesamt_links,gesamt_rechts; 2176 byte[] dat = new byte[44+data[0].length*4]; 2177 for(int i=0;i<data[0].length;i++) 2178 { 2179 float links = data[0][i]; 2180 float rechts = data[1][i]; 2181 2182 gesamt_links = Math.round( (links+gross)*gross ); 2183 gesamt_rechts = Math.round( (rechts+gross)*gross ); 2184 2185 2186 int lo_links = (int)gesamt_links%256; 2187 int lo_rechts = (int)gesamt_rechts%256; 2188 int hi_links = (int)gesamt_links/256; 2189 int hi_rechts = (int)gesamt_rechts/256; 2190 2191 hi_links-=128; 2192 hi_rechts-=128; 2193 2194 byte left_lo = (byte)lo_links; 2195 byte left_hi = (byte)hi_links; 2196 byte right_lo = (byte)lo_rechts; 2197 byte right_hi = (byte)hi_rechts; 2198 2199 dat[44+i*4+0] = left_lo; 2200 dat[44+i*4+1] = left_hi; 2201 dat[44+i*4+2] = right_lo; 2202 dat[44+i*4+3] = right_hi; 2203 } 2204 2205 //Kopf f\u00fcr wav-Datei passend erzeugen: 2206 int[] kopf = { 82, 73, 70, 70, 52, 177, 2, 0, 87, 65, 2207 86, 69, 102, 109, 116, 32, 16, 0, 0, 0, 2208 1, 0, 2, 0, 68, 172, 0, 0, 16, 177, 2209 2, 0, 4, 0, 16, 0, 100, 97, 116, 97, 2210 16, 177, 2, 0 }; 2211 int[] zahl1 = {0,0,0,0}; 2212 int[] zahl2 = {0,0,0,0}; 2213 2214 int z1 = data[0].length*4+36; 2215 int z2 = data[0].length*4; 2216 //KOPF bilden 2217 for(int i=0;i<4;i++) 2218 { 2219 zahl1[i] = z1%256; 2220 z1/=256; 2221 kopf[4+i] = zahl1[i]; 2222 } 2223 for(int i=0;i<4;i++) 2224 { 2225 zahl2[i] = z2%256; 2226 z2/=256; 2227 kopf[40+i] = zahl2[i]; 2228 } 2229 2230 for(int i=0;i<kopf.length;i++) 2231// dat[i] = (byte)(kopf[i]-128); 2232 dat[i] = (byte)(kopf[i]); 2233 2234 pap.saveBytes(name,dat); 2235 } 2236 2237 public byte[] toByte(float[][] data) 2238 { 2239 double gross = 0.5f*(255.0f*256.0f + 255.0f); 2240 double gesamt_links,gesamt_rechts; 2241 byte[] dat = new byte[data[0].length*4]; 2242 for(int i=0;i<data[0].length;i++) 2243 { 2244 float links = data[0][i]; 2245 float rechts = data[1][i]; 2246 2247 gesamt_links = Math.round( (links+gross)*gross ); 2248 gesamt_rechts = Math.round( (rechts+gross)*gross ); 2249 2250 2251 int lo_links = (int)gesamt_links%256; 2252 int lo_rechts = (int)gesamt_rechts%256; 2253 int hi_links = (int)gesamt_links/256; 2254 int hi_rechts = (int)gesamt_rechts/256; 2255 2256 hi_links-=128; 2257 hi_rechts-=128; 2258 2259 byte left_lo = (byte)lo_links; 2260 byte left_hi = (byte)hi_links; 2261 byte right_lo = (byte)lo_rechts; 2262 byte right_hi = (byte)hi_rechts; 2263 2264 dat[i*4+0] = left_lo; 2265 dat[i*4+1] = left_hi; 2266 dat[i*4+2] = right_lo; 2267 dat[i*4+3] = right_hi; 2268 } 2269 2270 return dat; 2271 } 2272 2273 /** 2274 * L\u00e4dt eine Stereo-Wav-Datei in zwei getrennten float-Arrays, Wertebereich [-1,+1] 2275 */ 2276 public float[][] ladeWav(String name) 2277 { 2278 int zl,zh,lo,gesamt; 2279 float gross = 0.5f*(255.0f*256.0f + 255.0f); 2280 2281 byte[] dat = pap.loadBytes(name); 2282 2283 int anz = dat.length; 2284 2285 float[][] y = new float[2][(anz-44)/4]; 2286 //float[][] y = new float[2][sampleanzahl]; 2287 2288 int inx=44; 2289 2290 for(int i=0;i<y[0].length;i++) 2291 { 2292 zl = dat[inx++]; 2293 zh = dat[inx++]; 2294 if(zl>127) 2295 zl-=256; 2296 2297 if(zh>127) 2298 zh-=256; 2299 2300 lo = zl; 2301 if(lo<0) 2302 lo+=256; 2303 gesamt = (zh+128)*256; 2304 gesamt+=lo; 2305 2306 y[0][i] = ((float)gesamt - gross)/gross; 2307 2308 zl = dat[inx++]; 2309 zh = dat[inx++]; 2310 if(zl>127) 2311 zl-=256; 2312 2313 if(zh>127) 2314 zh-=256; 2315 2316 lo = zl; 2317 if(lo<0) 2318 lo+=256; 2319 gesamt = (zh+128)*256; 2320 2321 gesamt+=lo; 2322 2323 y[1][i] = ((float)gesamt - gross)/gross; 2324 2325 } 2326 2327 return y; 2328 } 2329 2330 /** 2331 * Pr\u00fcft, ob pfad+"/ton"+midi+".wav" im Original existiert, sucht andernfalls nach Nachbarn und interpoliert diese. 2332 */ 2333 int[] tests = {-1,1,-2,2,-3,3,-4,4,-5,5,-6,6,-7,7,-8,8,-9,9,-10,10,-11,11,-12,12}; 2334 public float[][] ladeWavInterpolate(String pfad,int midi) 2335 { 2336 String name = pfad+"/ton"+midi+".wav"; 2337 if( (new File(name)).exists() ) 2338 { 2339 return ladeWav(name); 2340 } 2341 else 2342 { 2343 for(int i=0;i<tests.length;i++) 2344 { 2345 name = pfad+"/ton"+(midi+tests[i])+".wav"; 2346 if( (new File(name)).exists() ) 2347 { 2348 float[][] data = ladeWav(name); 2349 2350 double ineu = Math.pow(2.0f,(1.0f/12.0f)*(double)(-tests[i])); 2351 2352 float[][] data_neu = new float[2][(int)Math.round((double)data[0].length/ineu)+1]; 2353 2354 for(int k=0;k<data_neu[0].length;k++) 2355 { 2356 double inx = ineu*(double)k; 2357 double inx1 = Math.floor(inx); 2358 double inx2 = Math.ceil(inx); 2359 int iinx1 = (int)inx1; 2360 int iinx2 = (int)inx2; 2361 2362 if(iinx1==iinx2 && iinx1>=0 && iinx1<data[0].length) 2363 { 2364 data_neu[0][k] = data[0][iinx1]; 2365 data_neu[1][k] = data[1][iinx1]; 2366 } 2367 else if(iinx1!=iinx2 && iinx1>=0 && iinx1<data[0].length && iinx2>=0 && iinx2<data[0].length) 2368 { 2369 double anteil2 = inx - inx1; 2370 double anteil1 = 1.0f - anteil2; 2371 data_neu[0][k] = (float)anteil1*data[0][iinx1] + (float)anteil2*data[0][iinx2]; 2372 data_neu[1][k] = (float)anteil1*data[1][iinx1] + (float)anteil2*data[1][iinx2]; 2373 } 2374 2375 } 2376 2377 return data_neu; 2378 } 2379 } 2380 } 2381 2382 return null; 2383 } 2384 2385 /** 2386 * L\u00e4dt eine Stereo-Wav-Datei in zwei getrennten float-Arrays, Wertebereich [-1,+1] 2387 */ 2388 public float[][] ladeWav(String name, int sampleanzahl) 2389 { 2390 int zl,zh,lo,gesamt; 2391 float gross = 0.5f*(255.0f*256.0f + 255.0f); 2392 2393 byte[] dat = pap.loadBytes(name); 2394 2395 int anz = dat.length; 2396 2397 //double[][] y = new double[2][(anz-44)/4]; 2398 float[][] y = new float[2][sampleanzahl]; 2399 2400 int inx=44; 2401 2402 for(int i=0;i<y[0].length;i++) 2403 { 2404 zl = dat[inx++]; 2405 zh = dat[inx++]; 2406 if(zl>127) 2407 zl-=256; 2408 2409 if(zh>127) 2410 zh-=256; 2411 2412 lo = zl; 2413 if(lo<0) 2414 lo+=256; 2415 gesamt = (zh+128)*256; 2416 2417 gesamt+=lo; 2418 2419 y[0][i] = ((float)gesamt - gross)/gross; 2420 2421 zl = dat[inx++]; 2422 zh = dat[inx++]; 2423 if(zl>127) 2424 zl-=256; 2425 2426 if(zh>127) 2427 zh-=256; 2428 2429 lo = zl; 2430 if(lo<0) 2431 lo+=256; 2432 gesamt = (zh+128)*256; 2433 2434 gesamt+=lo; 2435 2436 y[1][i] = ((float)gesamt - gross)/gross; 2437 2438 } 2439 2440 return y; 2441 } 2442 2443 /** 2444 * L\u00e4dt eine Stereo-Wav-Datei, die dann zu einem Kanal gemischt wird und als float-Array zur\u00fcck gegeben wird. 2445 */ 2446 public float[] ladeWavMix(String name) //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren) 2447 { 2448 int zl,zh,lo,gesamt; 2449 float gross = 0.5f*(255.0f*256.0f + 255.0f); 2450 2451 byte[] dat = pap.loadBytes(name); 2452 2453 int anz = dat.length; 2454 2455 //double[][] y = new double[2][(anz-44)/4]; 2456 //float[] y = new float[sampleanzahl]; 2457 float[] y = new float[(anz-44)/4]; 2458 2459 int inx=44; 2460 2461 for(int i=0;i<y.length;i++) 2462 { 2463 zl = dat[inx++]; 2464 zh = dat[inx++]; 2465 if(zl>127) 2466 zl-=256; 2467 2468 if(zh>127) 2469 zh-=256; 2470 2471 lo = zl; 2472 if(lo<0) 2473 lo+=256; 2474 gesamt = (zh+128)*256; 2475 2476 gesamt+=lo; 2477 2478 //y[0][i] = ((float)gesamt - gross)/gross; 2479 y[i] = 0.5f*((float)gesamt - gross)/gross; 2480 2481 zl = dat[inx++]; 2482 zh = dat[inx++]; 2483 if(zl>127) 2484 zl-=256; 2485 2486 if(zh>127) 2487 zh-=256; 2488 2489 lo = zl; 2490 if(lo<0) 2491 lo+=256; 2492 gesamt = (zh+128)*256; 2493 2494 gesamt+=lo; 2495 2496 //y[1][i] = ((float)gesamt - gross)/gross; 2497 y[i] += 0.5f*((float)gesamt - gross)/gross; 2498 2499 } 2500 2501 return y; 2502 } 2503 2504 /** 2505 * L\u00e4dt eine Stereo-Datei, mixt sie zu Mono und baut sie zu einer loop-baren Variante 2506 * zusammen:<br/> 2507 * [AB] a=A ausblenden, b=B einblenden<br/> 2508 * ab + ba<br/> 2509 */ 2510 public float[] ladeWavMixLoop(String name) //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren) 2511 { 2512 float[] AB = ladeWavMix(name); 2513 for(int i=0;i<AB.length/2;i++) 2514 { 2515 AB[i] = AB[i]*(1.0f - (float)i/(float)(AB.length/2)-1); 2516 int ii = AB.length-1-i; 2517 AB[ii] = AB[ii]*(1.0f - (float)i/(float)(AB.length/2)-1); 2518 } 2519 2520 for(int i=0;i<AB.length/2;i++) 2521 { 2522 int ii = AB.length/2+i; 2523 float a = AB[i]; 2524 float b = AB[ii]; 2525 AB[i] = a+b; 2526 AB[ii] = a+b; 2527 } 2528 return AB; 2529 } 2530 2531 public float[] ladeWavMix(String name, int sampleanzahl) //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren) 2532 { 2533 float[][] stereo = ladeWav(name,sampleanzahl); 2534 for(int i=0;i<stereo[0].length;i++) 2535 stereo[0][i] = 0.5f*(stereo[0][i]+stereo[1][i]); 2536 return stereo[0]; 2537 } 2538 2539 public float[] ladeWavMixLoop(String name, int sampleanzahl) //Gleich nur Mix aus linkem und rechtem Kanal laden (aus 44100 2x16Bit extrahieren) 2540 { 2541 float[][] stereo = ladeWav(name,sampleanzahl); 2542 for(int i=0;i<stereo[0].length;i++) 2543 stereo[0][i] = 0.5f*(stereo[0][i]+stereo[1][i]); 2544 float[] AB = stereo[0]; 2545 for(int i=0;i<AB.length/2;i++) 2546 { 2547 AB[i] = AB[i]*(1.0f - (float)i/(float)(AB.length/2)-1); 2548 int ii = AB.length-1-i; 2549 AB[ii] = AB[ii]*(1.0f - (float)i/(float)(AB.length/2)-1); 2550 } 2551 2552 for(int i=0;i<AB.length/2;i++) 2553 { 2554 int ii = AB.length/2+i; 2555 float a = AB[i]; 2556 float b = AB[ii]; 2557 AB[i] = a+b; 2558 AB[ii] = a+b; 2559 } 2560 return AB; 2561 2562 } 2563 2564 /** 2565 * L\u00e4dt wav-Files, die als 16-Bit Mono-Files vorliegen 2566 */ 2567 public float[] ladeWavMono(String name) 2568 { 2569 int zl,zh,lo,gesamt; 2570 float gross = 0.5f*(255.0f*256.0f + 255.0f); 2571 2572 byte[] dat = pap.loadBytes(name); 2573 2574 int anz = dat.length; 2575 2576 //double[][] y = new double[2][(anz-44)/4]; 2577 //float[] y = new float[sampleanzahl]; 2578 //float[] y = new float[(anz-44)/4]; 2579 float[] y = new float[(anz-44)/2]; 2580 2581 int inx=44; 2582 2583 for(int i=0;i<y.length;i++) 2584 { 2585 zl = dat[inx++]; 2586 zh = dat[inx++]; 2587 if(zl>127) 2588 zl-=256; 2589 2590 if(zh>127) 2591 zh-=256; 2592 2593 lo = zl; 2594 if(lo<0) 2595 lo+=256; 2596 gesamt = (zh+128)*256; 2597 2598 gesamt+=lo; 2599 2600 //y[0][i] = ((float)gesamt - gross)/gross; 2601 y[i] = ((float)gesamt - gross)/gross; 2602 } 2603 2604 return y; 2605 } 2606 2607 /** 2608 * Shows wav-data as Java-short-Array 2609 */ 2610 public void showAsShortArray(float[] wav) 2611 { 2612 PApplet.println(); 2613 PApplet.println("private short[] data = {"); 2614 for(int i=0;i<wav.length;i++) 2615 { 2616 if(i<wav.length-1) 2617 PApplet.print((int)PApplet.round((wav[i]*32000.0f))+","); 2618 else 2619 PApplet.print((int)PApplet.round((wav[i]*32000.0f))); 2620 2621 if(i%200==0 && i>0) 2622 PApplet.println(); 2623 } 2624 PApplet.println(); 2625 PApplet.println("};"); 2626 2627 } 2628 2629 public void ueberlappendVerketten(String quelle1, String quelle2, String ziel, int samples_ueberlappung) 2630 { 2631 float[][] q1 = ladeWav(quelle1); 2632 float[][] q2 = ladeWav(quelle2); 2633 2634 float[][] z = new float[2][q1[0].length+q2[0].length-samples_ueberlappung]; 2635 2636 for(int i=0;i<q1[0].length;i++) 2637 { 2638 z[0][i] = q1[0][i]; 2639 z[1][i] = q1[1][i]; 2640 } 2641 for(int i=0;i<q2[0].length;i++) 2642 { 2643 z[0][i+q1[0].length-samples_ueberlappung] += q2[0][i]; 2644 z[1][i+q1[1].length-samples_ueberlappung] += q2[1][i]; 2645 } 2646 2647 saveWav(ziel,z); 2648 } 2649 2650} 2651 public void settings() { size(1280,640); } 2652 static public void main(String[] passedArgs) { 2653 String[] appletArgs = new String[] { "MODULO_1003_STEREO" }; 2654 if (passedArgs != null) { 2655 PApplet.main(concat(appletArgs, passedArgs)); 2656 } else { 2657 PApplet.main(appletArgs); 2658 } 2659 } 2660}