Tässä on Javalla koodattu Simonin kaltainen peli, joka vaikeutuu joka kierroksella pelaajan onnistuttua. Mikäli pelaaja häviää peli alkaa taas helpoimmasta sarjasta.
Simon on 1970-luvulla Ralp H. Baerin ja Howard J. Morrisonin kehittämä elektroniikkapeli, jossa täytyy muistaa värien oikea sarja. Peli perustuu aikaisempaan Touch Me-peliin, joka oli Atari tuottama.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Random;
public class Simon implements ActionListener {
JFrame kehys;
JButton[] nappaimet = new JButton[4];
JLabel teksti;
JPanel paneeli;
Font fontti = new Font("Arial",Font.BOLD,30);
ArrayList<Integer> varit = new ArrayList<>();
Random sattuma = new Random();
int maara = 4;
int indeksi = 0;
boolean onkoAlkanut = false;
boolean onkoVoitto = true;
public void ArvoVarit(){
int vari = 0;
int vanhaVari = 0;
//Arvotaan kyseisen kierroksen värit.
for (int i = 0; i < maara; i++){
//Arvotaan seuraava väri, joka ei saa olla sama kuin edellinen.
do {
vari = sattuma.nextInt(4);
} while (vari == vanhaVari);
varit.add(vari);
vanhaVari = vari;
}
onkoVoitto = true;
ajastin.start();
}
Timer ajastin = new Timer(750,new ActionListener(){
public void actionPerformed(ActionEvent e){
if (!onkoAlkanut && onkoVoitto){
//Näytetään kierroksen värit.
for (int i = 0; i < 4; i++){
nappaimet[i].setEnabled(false);
}
//Näytetään väri.
if (indeksi < maara){
switch (varit.get(indeksi++)){
case 0:
nappaimet[0].setBackground(Color.RED);
nappaimet[1].setBackground(Color.WHITE);
nappaimet[2].setBackground(Color.WHITE);
nappaimet[3].setBackground(Color.WHITE);
break;
case 1:
nappaimet[0].setBackground(Color.WHITE);
nappaimet[1].setBackground(Color.YELLOW);
nappaimet[2].setBackground(Color.WHITE);
nappaimet[3].setBackground(Color.WHITE);
break;
case 2:
nappaimet[0].setBackground(Color.WHITE);
nappaimet[1].setBackground(Color.WHITE);
nappaimet[2].setBackground(Color.GREEN);
nappaimet[3].setBackground(Color.WHITE);
break;
case 3:
nappaimet[0].setBackground(Color.WHITE);
nappaimet[1].setBackground(Color.WHITE);
nappaimet[2].setBackground(Color.WHITE);
nappaimet[3].setBackground(Color.BLUE);
break;
}
}
else if (indeksi ==maara){
teksti.setText("Oletko valmis?");
indeksi++;
}
else if (indeksi > maara){
teksti.setText("Pelaa");
onkoAlkanut = true;
nappaimet[0].setBackground(Color.WHITE);
nappaimet[1].setBackground(Color.WHITE);
nappaimet[2].setBackground(Color.WHITE);
nappaimet[3].setBackground(Color.WHITE);
indeksi = 0;
for (int i = 0; i < 4; i++){
nappaimet[i].setEnabled(true);
}
}
}
}
});
public void Tarkista(int ind){
//Tarkistetaan, onko väri oikein ja tarkistetaan voitto.
if (!(ind == varit.get(indeksi++))){
onkoAlkanut = false;
onkoVoitto = false;
teksti.setText("Parempi onni ensi kerralla!");
maara = 4;
}
if (indeksi >= maara && onkoVoitto && onkoAlkanut){
//Aloitetaan seuraava, vaikeampi kierros.
varit.clear();
onkoAlkanut = false;
onkoVoitto = false;
maara++;
teksti.setText("Onneksi olkoon!");
}
}
Simon(){
//Määritellään kehys.
kehys = new JFrame("Simon");
kehys.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
kehys.setSize(450,500);
teksti = new JLabel("Paina näppäintä");
kehys.setLayout(null);
//Määritellään tekstilappu.
teksti.setFont(fontti);
teksti.setBounds(0,50,300,50);
//Määritellään näppäimet.
paneeli = new JPanel();
paneeli.setBounds(0,100,400,350);
paneeli.setLayout(new GridLayout(2,2));
for (int i = 0; i < 4; i++){
nappaimet[i] = new JButton("Pelaa");
nappaimet[i].addActionListener(this);
paneeli.add(nappaimet[i]);
nappaimet[i].setFocusable(false);
}
//Lisätään kontrollit kehykseen.
kehys.add(teksti);
kehys.add(paneeli);
kehys.setVisible(true);
}
public static void main(String[] args){
final Simon simon = new Simon();
}
@Override
public void actionPerformed(ActionEvent e){
for (int i = 0; i < 4; i++){
if (e.getSource() == nappaimet[i]){
//Ensin arvotaan värit, sitten alkaa pelaajan vuoro.
if (!onkoAlkanut){
indeksi = 0;
ArvoVarit();
}
else {
Tarkista(i);
}
}
}
}
}koodaaja kirjoitti:
Tässä on Javalla koodattu Simonin kaltainen peli, joka vaikeutuu joka kierroksella pelaajan onnistuttua. Mikäli pelaaja häviää peli alkaa taas helpoimmasta sarjasta.
Olisi ehkä kivempi, jos käyttäisit värillisiä nappeja koko ajan niin väriä oikeasti voisi käyttää apuna järjestyksen muistamisessa. Samoin voisi olla kiva idea sijoittaa napit ympyrälle ja antaa väreille omat sektorinsa siitä. Ehkä helpoin parannus käyttöliittymään kuitenkin olisi sijoittaa se keskelle ikkunaa. Nyt kaikki on ihan vasemmassa reunassa ja oikealle jää tyhjää tilaa.
Hieno peli! Tässa on toteutus, kuinka Java -ohjelman saa toimimaan Grafiikkaliittymässä! Tämmöistä olen joskus haaveillut, mutta ei ole vielä ennen tullut vastaan. Tähän asti on pitänyt tehdä inputit ja outputit command prompt -ikkunan kautta. Nyt avautui uusi pelikenttä! Appletit toimivat joskus web-sivuilla, mutta enää ne ei toimi.
Jotain tämän tyylistä siis meinasin. Nappien toiminta helppo toteuttaa itse perus matematiikkaa apuna käyttäen. Tuohon keskelle meinasin laittaa pistelaskurin ja pelin viestit.
Päätinpä tehdä tästä sitten mobiiliversion. Alla kehitysversio, mistä puuttuu vielä ainakin ärsyttävät äänet mitkä esikuvassaan oli. Jos haluaa kokeilla ja verrata Java version käyttöliittymää, niin täältä voi ladata lähdekoodin ja binäärit useimmille käyttöjärjestelmille.
needs nk/gui
\ Game states
0 constant START
1 constant READY
2 constant PLAY
3 constant END
START var, game-state
0 2 n:PI n:* 4 n:/ dup >r 2 a:close constant PIE1
r@ dup 2 n:* 2 a:close constant PIE2
r@ 2 n:* dup r@ n:+ 2 a:close constant PIE3
r@ 3 n:* dup r> n:+ 2 a:close constant PIE4
[ @PIE1, @PIE2, @PIE3, @PIE4 ] constant SECTORS
var score
null var, highlight
var seq-count
var sequence
var counter
var anim-task-id
with: nk
48 font:system font:new "font1" font:atlas! drop
: new-win
{
name: "main",
wide: 640,
high: 480,
bg: "white",
title: "NOT Simon"
}
win ;
: draw-circle \ [x y] r n c --
>r >r >r
( r@ n:- ) a:map
a:open r> 2 n:* dup 4 a:close r> r> stroke-circle ;
: draw-filled-circle \ [x y] r c --
>r >r
( r@ n:- ) a:map
a:open r> 2 n:* dup 4 a:close r> fill-circle ;
: angle? \ pta2 pta1 -- radians
( n:- n:neg ) a:2map a:open swap n:atan2 dup 0 n:< if
2 n:PI n:* swap n:+
then ;
: distance? \ pta2 pta1 -- distance
( n:- n:sqr ) a:2map a:open n:+ n:sqrt ;
: center-pt \ -- center-pt
win-content-bounds rect-center nip ;
: redraw
null do ;
: draw-pie
center-pt 200 PIE1 "blue" fill-arc
center-pt 200 PIE2 "red" fill-arc
center-pt 200 PIE3 "yellow" fill-arc
center-pt 200 PIE4 "green" fill-arc ;
: draw-center
center-pt x>pt 80 "white" draw-filled-circle
center-pt x>pt 80 8 "black" draw-circle
game-state @ START n:= game-state @ READY n:= or if
win-content-bounds
0 0 game-state @ START n:= if
"PLAY"
else
"READY"
then
dup >r measure swap 4 a:close
center-rect
r> "font1" "white" "black" draw-text
else
win-content-bounds
0 0 score @ "%04d" s:strfmt dup >r
measure swap 4 a:close
center-rect
r> "font1" "white" game-state @ END n:= if
"red"
else
"black"
then draw-text
then ;
: mouse-clicked? \ -- T
0 win-content-bounds 0 clicked? ;
: sector? \ angle distance -- n | null
[ ( 2dup dup 200 n:> not swap 80 n:> and swap PIE1 a:open n:between and ), ( 2drop 0 ),
( 2dup dup 200 n:> not swap 80 n:> and swap PIE2 a:open n:between and ), ( 2drop 1 ),
( 2dup dup 200 n:> not swap 80 n:> and swap PIE3 a:open n:between and ), ( 2drop 2 ),
( 2dup dup 200 n:> not swap 80 n:> and swap PIE4 a:open n:between and ), ( 2drop 3 ),
( 2drop null ) ] a:when ;
: init-game
0 score !
null highlight !
4 seq-count !
0 counter !
a:new ( rand-pcg 4 n:mod a:push ) seq-count @ times sequence !
READY game-state !
redraw ;
: next-level
null highlight !
1 seq-count n:+!
0 counter !
a:new ( rand-pcg 4 n:mod a:push ) seq-count @ times sequence !
READY game-state !
redraw ;
: handle-highlight
highlight @ null? not if
>r center-pt 200 SECTORS r> caseof 8 "black" stroke-arc
else
drop
then ;
: handle-mouse
center-pt x>pt mouse-pos 2 a:close 2dup angle? 3rev distance? dup >r sector? null? not if
game-state @ PLAY n:= if
>r center-pt 200 SECTORS r@ caseof 0 down? if
8
else
4
then "black" stroke-arc
mouse-clicked? if
sequence @ counter @ a:@ nip r> n:= if
score @ n:1+ 10000 n:mod score !
1 counter n:+!
counter @ seq-count @ n:< not if
next-level
anim-task-id @ t:notify
then
else
END game-state !
then
else
rdrop
then
then
else
drop
then
r> 80 n:> not game-state @ START n:= game-state @ END n:= or and if
center-pt x>pt 80 0 down? if
24
else
16
then "black" draw-circle
mouse-clicked? if
game-state @ END n:= if
START game-state !
else
init-game
anim-task-id @ t:notify
then
then
then ;
: my-render
{
bg: "white",
flags: [ @WINDOW_NO_SCROLLBAR ]
}
begin
draw-pie
[ ' handle-mouse , ' handle-highlight , ' handle-mouse , ' handle-mouse ]
game-state @ case
draw-center
end ;
: animate \ m --
"sector" m:@ nip highlight ! ;
: anim-task
repeat
-1 sleep
0.5 sleep
sequence @
( 0.5 sleep m:new swap "sector" m:_! "cb" ' animate m:! do
0.5 sleep m:new "sector" null m:! "cb" ' animate m:! do
) a:each! drop
1 sleep
( PLAY game-state ! ) do
again ;
: app:main
' anim-task t:task anim-task-id !
new-win ' my-render -1 render-loop ;Aihe on jo aika vanha, joten et voi enää vastata siihen.