Frogger-ish game

13

Co powiesz na ożywienie dobrej, zręcznościowej gry Frogger w stylu Code Golf!

Twoim zadaniem jest stworzenie wersji tej klasycznej gry z możliwie jak najmniejszą liczbą znaków kodu. Używaj wybranego języka ( dozwolone są biblioteki, takie jak jQuery itp.).

Wymagania

  • Masz 3 życia i tracisz 1 życie z:
    • wyprowadzanie się poza scenę gry.
    • zostać potrąconym przez pojazd.
    • wskakując do wody.
    • skakanie do już zajętego domu.
    • czas się kończy.
  • Żaba porusza się za pomocą klawiszy strzałek.
  • Występuje błąd „teleportacji” z ustalonymi odstępami między pięcioma domami (odstępy między trawą u góry).
  • Dostajesz 10 punktów za krok do przodu, 200 punktów bonusowych za złapanie błędu i 500 punktów za dotarcie do pustego domu.
  • Timer tyka, szybciej na każdym poziomie (pojazdy, żaby i kłody powinny również poruszać się szybciej na każdym poziomie).
  • Powinno być 5 pasów pojazdów i 3 pasy z kłodami i 2 pasy z żółwiami.
  • Każdy pas powinien poruszać się w losowo wybranej prędkości (z uzasadnionych powodów).
  • Kiedy dostępny dom zostanie zajęty, w punkcie początkowym pojawia się żaba, a ty kontrolujesz go od tego momentu.
  • Po zajęciu wszystkich pięciu domów licznik czasu uruchamia się ponownie i domy stają się puste. Po zakończeniu gry punkty ze wszystkich poziomów są obliczane i pokazywane.

dodatkowe informacje

Ekran startowy, muzyka i tabela najlepszych wyników nie są potrzebne. Nie musisz również naśladować projektu do piksela. Chcesz to czarno-białe? Chcesz naprawdę minimalistyczny? A może sześcian zamiast żaby lub samochodu? Działa w porządku! Po prostu trzymaj kod mocno. Najkrótszy kod wygrywa!

wprowadź opis zdjęcia tutaj

brak nazwy wyświetlanej
źródło
Komentarze zostały usunięte, ponieważ były przestarzałe. Powiadom mnie o wszelkich utraconych informacjach, które mogły znajdować się w usuniętych komentarzach.
Klamka

Odpowiedzi:

3

Python 3.3 - Nieskluczony

W ogóle nie grałem w golfa, ponieważ byłem bardziej zainteresowany tym, żeby najpierw dobrze wyglądać gra. Tak naprawdę jestem zupełnie nowy w Tk, więc jeśli ktoś ma jakieś sugestie, bardzo bym je docenił. Prędkości działają teraz poprawnie. Daj mi znać, jeśli chcesz zobaczyć dodatkowe funkcje, np. Kolory.

Kod

import tkinter as tk
import queue
import random    

class Lane():
 def __init__(self, row=-1, lanetype="none", direction=0, speed=0, width=0, maxnumber=0, replenish=0, length=0, gap=0):
  self.row = row
  self.type = lanetype
  self.direction = direction
  self.speed = speed
  self.width = width
  self.maxnumber = maxnumber
  self.replenish = replenish
  self.length = length
  self.gap = gap
  self.lanelastupdate = 0
  self.objects = []
  if(self.type == "car"):
   for index in range(self.width):
    if(len(self.objects) == self.maxnumber):
     break
    if((self.maxnumber - len(self.objects) == self.width - index) or random.random() < self.maxnumber/self.width):
     self.objects.append([index*self.direction + int((self.width-1)/2 - (self.width-1)*self.direction/2), self.row])
  if(self.type == "log" or self.type == "turtle"):
   if(self.direction == 1):
    start = 0
   else:
    start = self.width - 1
   lengthcounter = 0
   gapcounter = 0
   for index in range(self.width):
    if(lengthcounter < self.length):
     self.objects.append([start + index*self.direction, self.row])
     lengthcounter += 1
    else:
     gapcounter += 1
     if(gapcounter == self.gap):
      lengthcounter = 0
      gapcounter = 0
 ### end of __init__ ###
### end of Lane class ###

class Frogger():
 def __init__(self):
  # configure 'global' variables
  self.directions = ['Up', 'Down', 'Left', 'Right']
  self.width = 25
  self.height = 13
  self.frogstart = [12, 12]
  self.pointsforup = 10
  self.pointsforhome = 500
  self.pointsforbug = 200
  self.timerthreshold = 1000
  self.timerstart = 60
  self.speedchange = 2
  self.waterbordertop = 1
  self.waterborderbottom = 5
  self.minspeed = 10
  self.maxspeed = 15
  self.minbugspeed = 50
  self.maxbugspeed = 100
  self.timerspeed = 20    

  # configure program state variables
  self.q = queue.Queue(maxsize=1)
  self.updateticks = 0

  # configure game variables
  self.gameover = False
  self.speedup = 0
  self.timer = self.timerstart
  self.lives = 3
  self.score = 0
  self.frogposition = [0, 0]
  self.frogposition[0] = self.frogstart[0]
  self.frogposition[1] = self.frogstart[1]
  self.highest = 12
  self.movedup = False

  # configure the lanes of cars, logs, and turtles
  self.init_lanes()

  # configure the homes and the bug
  self.init_special()

  # configure TK window
  self.root = tk.Tk()
  self.label = tk.Label(text="Score: "+str(self.score)+" Lives: "+str(self.lives)+" Time: "+str(self.timer))
  self.label.pack()
  self.text = tk.Text(self.root, width=self.width, height=self.height, font=("Courier New", 14))
  self.text.bind("<Key>", self.key_event)
  self.text.focus_set()
  self.text.pack()

  # configure drawing sprites
  self.init_sprites()

  # run the game
  self.update_clock()
  self.process_world()
  self.root.mainloop()
 ### end of init ###

 def init_sprites(self):
  self.symbols = {"frog":chr(0x238), "rightcar":chr(187), "leftcar":chr(171), "turtle":chr(920), "log":chr(685), "bug":chr(1217), "grass":chr(993), "freehome":chr(164), "fullhome":"@", "road":"-", "water":chr(0x2248), "saferow":"*"}
  self.sprites = {value:key for key, value in self.symbols.items()}
  self.text.tag_configure("frog", foreground="chartreuse", background="dark green")
  self.text.tag_configure("rightcar", foreground="yellow", background="black")
  self.text.tag_configure("leftcar", foreground="yellow", background="black")
  self.text.tag_configure("turtle", foreground="orange red", background="cyan")
  self.text.tag_configure("log", foreground="sienna", background="cyan")
  self.text.tag_configure("bug", foreground="maroon", background="green")
  self.text.tag_configure("grass", foreground="orange", background="green")
  self.text.tag_configure("freehome", foreground="forest green", background="green")
  self.text.tag_configure("fullhome", foreground="red", background="green")
  self.text.tag_configure("road", foreground="gray", background="black")
  self.text.tag_configure("water", foreground="navy", background="cyan")
  self.text.tag_configure("saferow", foreground="pink", background="black")
 ### end of init_sprites ###

 def update_clock(self):
  self.timer -= 1
  self.label.configure(text="Score: "+str(self.score)+" Lives: "+str(self.lives)+" Time: "+str(self.timer))
  if(self.gameover == False):
   self.root.after(max(1, self.timerthreshold - self.speedup), self.update_clock)
 ### end of update_clock ###

 def key_event(self, event):
  direction = event.keysym
  if(direction in self.directions):
   try:
    self.q.put(direction, block=False)
   except:
    pass
 ### end of key_event ###

 def process_world(self):
  # acquire user input and process it if necessary
  if(self.q.qsize() > 0):
   self.move_frog(self.q.get())

  # update the state of non-frog objects
  self.update_world()

  # draw the world
  self.draw_world()

  # schedule another pass unless the game is over
  if(self.gameover == False):
   self.root.after(self.timerspeed, self.process_world)
  else:
   self.root.after(self.timerspeed, self.gameover_screen)
 ### end of process_world ###

 def move_frog(self, d):
  x = self.frogposition[0]
  y = self.frogposition[1]
  if(d == 'Up'):
   y -= 1
  elif(d == 'Down'):
   y += 1
  elif(d == 'Left'):
   x -= 1
  else:
   x += 1
  if(x >= 0 and y >= 0 and x < self.width and y < self.height):
   self.frogposition[0] = x
   self.frogposition[1] = y
   self.movedup = False
   if(d == 'Up' and y < self.highest):
    self.movedup = True
 ### end of move_frog ###

 def gameover_screen(self):
  self.label2 = tk.Label(text="Game over! Your score was: " + str(self.score))
  self.label2.pack()
 ### end of gameover_screen ###

 def update_world(self):
  # update the internal timer
  self.updateticks += 1

  # check for loss conditions
  if((self.timer == 0) or self.hit_by_car() == True or self.in_water() == True or self.home_twice() == True or self.in_grass() == True):
   self.process_death()
   return

  # credit good moves up
  if(self.movedup == True):
   self.score += self.pointsforup
   self.highest = self.frogposition[1]
   self.movedup = False

  # check for win condition
  if(self.at_home() == True):
   self.process_victory()
   return

  # check for total win
  if(self.all_done() == True):
   self.process_win()
   return

  # update the positions of the cars, logs, and turtles
  self.update_positions()
 ### end of update_world ###

 def all_done(self):
  if(len([x for x in self.homes if x[1]==False])==0):
   return True
  return False
 ### end of all_done ###

 def process_win(self):
  self.gameover = True
  return
 ### end of process_win ###

 def process_death(self):
  self.lives -= 1
  if(self.lives < 1):
   self.gameover = True
   return
  self.frogposition[0] = self.frogstart[0]
  self.frogposition[1] = self.frogstart[1]
  self.highest = 12
  self.timer = self.timerstart
 ### end of process_death ###

 def hit_by_car(self):
  for lane in self.lanes:
   if(lane.type != "car"):
    continue
   for car in lane.objects:
    if(car == self.frogposition):
     return True
  return False
 ### end of hit_by_car

 def in_water(self):
  if(self.frogposition[1] < self.waterbordertop or self.frogposition[1] > self.waterborderbottom):
   return False
  for lane in self.lanes:
   if(lane.type == "turtle"):
    for turtle in lane.objects:
     if(turtle == self.frogposition):
      return False
   elif(lane.type == "log"):
    for log in lane.objects:
     if(log == self.frogposition):
      return False
  return True
 ### end of in_water

 def home_twice(self):
  for h in self.homes:
   if(h[0] == self.frogposition and h[1] == True):
    return True
  return False
 ### end of home_twice

 def in_grass(self):
  if(self.frogposition[1] == 0 and self.at_home() == False):
   return True
  return False
 ### end of in_grass

 def at_home(self):
  for h in self.homes:
   if(h[0] == self.frogposition):
    return True
  return False
 ### end of at_home ###

 def process_victory(self):
  self.score += self.pointsforhome
  if(self.bugposition == self.frogposition):
   self.score += self.pointsforbug
  for h in self.homes:
   if (h[0] == self.frogposition):
    h[1] = True
    break
  self.timer = self.timerstart
  self.frogposition[0] = self.frogstart[0]
  self.frogposition[1] = self.frogstart[1]
  self.highest = 12
  self.speedup += self.speedchange
 ### end of process_victory ###

 def init_lanes(self):
  random.seed()
  self.lanes = []
  self.lanes.append(Lane(row=11, lanetype="car", maxnumber=10, replenish=0.1, direction=1, width=self.width, speed=random.randint(self.minspeed, self.maxspeed)))
  self.lanes.append(Lane(row=10, lanetype="car", maxnumber=8, replenish=0.2, direction=-1, width=self.width, speed=random.randint(self.minspeed, self.maxspeed)))
  self.lanes.append(Lane(row=9, lanetype="car", maxnumber=5, replenish=0.6, direction=1, width=self.width, speed=random.randint(self.minspeed, self.maxspeed)))
  self.lanes.append(Lane(row=8, lanetype="car", maxnumber=9, replenish=0.4, direction=-1, width=self.width, speed=random.randint(self.minspeed, self.maxspeed)))
  self.lanes.append(Lane(row=7, lanetype="car", maxnumber=6, replenish=0.3, direction=1, width=self.width, speed=random.randint(self.minspeed, self.maxspeed)))
  self.lanes.append(Lane(row=5, lanetype="turtle", direction=-1, length=3, gap=4, width=self.width, speed=random.randint(self.minspeed, self.maxspeed)))
  self.lanes.append(Lane(row=4, lanetype="log", direction=1, length=3, gap=3, width=self.width, speed=random.randint(self.minspeed, self.maxspeed)))
  self.lanes.append(Lane(row=3, lanetype="log", direction=-1, length=8, gap=9, width=self.width, speed=random.randint(self.minspeed, self.maxspeed)))
  self.lanes.append(Lane(row=2, lanetype="turtle", direction=1, length=2, gap=6, width=self.width, speed=random.randint(self.minspeed, self.maxspeed)))
  self.lanes.append(Lane(row=1, lanetype="log", direction=-1, length=4, gap=4, width=self.width, speed=random.randint(self.minspeed, self.maxspeed)))
 ### end of init_lanes

 def init_special(self):
  self.bugposition = [2, 0]
  self.buglastupdate = 0
  self.bugspeed = random.randint(self.minbugspeed, self.maxbugspeed)
  self.homes = [[[2, 0], False], [[7, 0], False], [[12, 0], False], [[17, 0], False], [[22, 0], False]]
 ### end of init_special ###

 def update_positions(self):
  if(self.updateticks - self.buglastupdate >= self.bugspeed - self.speedup):
   self.buglastupdate = self.updateticks
   while(True):
    freeslots = [x for x in self.homes if x[1] == False]
    if(len(freeslots)==0):
     self.bugposition = [-1,-1]
     break
    if(len(freeslots)==1):
     self.bugposition = freeslots[0][0]
     break
    newhomeindex = random.randint(0, 4)
    if(self.homes[newhomeindex][0] != self.bugposition and self.homes[newhomeindex][1] == False):
     self.bugposition = self.homes[newhomeindex][0]
     break

  for lane in self.lanes:
   lanemovedfrog=False
   if(self.updateticks - lane.lanelastupdate >= lane.speed - self.speedup):
    lane.lanelastupdate = self.updateticks
   else:
    continue
   for o in lane.objects:
    if(o == self.frogposition and lanemovedfrog==False):
     self.move_frog(self.directions[int(0.5*lane.direction + 2.5)])
     lanemovedfrog=True
    o[0] += lane.direction
    if((o[0] < 0) or (o[0] >= self.width)):
     lane.objects.remove(o)
   if(lane.type == "car" and len(lane.objects) < lane.maxnumber and random.random() < lane.replenish):
    lane.objects.append([int((self.width-1)/2 - (self.width-1)*lane.direction/2), lane.row])
   if(lane.type == "log" or lane.type == "turtle"):
    if(lane.direction == 1):
     start = min([x[0] for x in lane.objects])
     nxt = min([x for x in range(start, self.width) if (len([y for y in lane.objects if y[0] == x]) == 0)])
     if(start >= lane.gap or (nxt - start) < lane.length):
      lane.objects.append([0, lane.row])
    else:
     start = max([x[0] for x in lane.objects])
     nxt = max([x for x in range(start, -1, -1) if (len([y for y in lane.objects if y[0] == x]) == 0)])
     if(self.width - start - 1 >= lane.gap or (start - nxt) < lane.length):
      lane.objects.append([self.width - 1, lane.row])
   lane.objects.sort()
 ### end of update_positions ###

 def draw_world(self):
  self.text.state = "normal"
  self.text.delete('1.0', str(self.width + 1) + '.' + '0')
  drawstr = ""
  # draw home row
  newstr = self.symbols["grass"] * self.width
  for h in self.homes:
   if(h[1] == False):
    if(self.bugposition == h[0]):
     newstr = self.str_replace(newstr, h[0][0], self.symbols["bug"])
    else:
     newstr = self.str_replace(newstr, h[0][0], self.symbols["freehome"])
   else:
    newstr = self.str_replace(newstr, h[0][0], self.symbols["fullhome"])
  drawstr += newstr
  drawstr += "\n"

  # draw water rows
  for index in range(self.waterborderbottom - self.waterbordertop + 1):
   newstr = self.symbols["water"] * self.width
   for lane in self.lanes:
    if(lane.row == index + self.waterbordertop):
     for o in lane.objects:
      if(lane.type == "log"):
       newstr = self.str_replace(newstr, o[0], self.symbols["log"])
      elif(lane.type == "turtle"):
       newstr = self.str_replace(newstr, o[0], self.symbols["turtle"])
   drawstr += newstr
   drawstr += "\n"

  # draw safe row
  drawstr += self.symbols["saferow"] * self.width
  drawstr += "\n"

  # draw car rows
  for index in range(len([l for l in self.lanes if l.type == "car"])):
   newstr = self.symbols["road"] * self.width
   for lane in self.lanes:
    if(lane.row == self.waterborderbottom + 2 +index):
     for o in lane.objects:
      if(lane.direction == 1):
       newstr = self.str_replace(newstr, o[0], self.symbols["rightcar"])
      elif(lane.direction == -1):
       newstr = self.str_replace(newstr, o[0], self.symbols["leftcar"])
   drawstr += newstr
   drawstr += "\n"

  # draw safe row
  drawstr += self.symbols["saferow"] * self.width

  # do actual drawing
  self.text.insert('1.0', drawstr)

  # draw frog
  self.text.delete(str(1 + self.frogposition[1]) + '.' + str(self.frogposition[0]))
  self.text.insert(str(1 + self.frogposition[1]) + '.' + str(self.frogposition[0]), self.symbols["frog"])

  # apply colors
  for sprite in self.sprites.keys():
   self.highlight_pattern(sprite, self.sprites[sprite])

  # turn off editability
  self.text.state = "disabled"
 ### end of draw_world ###

 def str_replace(self, targetstr, index, char):
  return targetstr[:index] + char + targetstr[index+1:]
 ### end of str_replace ###

 def highlight_pattern(self, sprite, tag):
  start = self.text.index("1.0")
  end = self.text.index("end")
  self.text.mark_set("matchStart", start)
  self.text.mark_set("matchEnd", start)
  self.text.mark_set("searchLimit", end)
  count = tk.IntVar()
  while True:
   index = self.text.search(sprite, "matchEnd", "searchLimit", count=count, regexp=False)
   if(index == ""):
    break
   self.text.mark_set("matchStart", index)
   self.text.mark_set("matchEnd", "%s+%sc" % (index, count.get()))
   self.text.tag_add(tag, "matchStart","matchEnd")
 ### end of highlight_pattern ###
### end of Frogger class ###

# Run the game!!!
frogger = Frogger()
RT
źródło
2
Myślę, że problem pochodzi z aktualizacji ekranu. Jeśli twój program działa z prędkością 60 klatek na sekundę, zajmuje to około 16 ms. Oznacza to, że twoja główna pętla nie może działać co 1ms. (To jest ogólna logika, ale nie mam specjalistycznej wiedzy z Tkinter lub innymi systemami GUI)
patrz
Być może warto zapytać o to SO. Proszę zamieścić link tutaj, jeśli to zrobisz.
1
Wziąłem twoją radę i zapytałem na SO: stackoverflow.com/questions/23999478/... Częstotliwość odświeżania ekranu jest ustawiana na każde 20 tyknięć aktualizacji, która powinna wynosić co 20 ms lub 50 FPS. Wygląda na to, że każdy współczesny komputer powinien być banalnie łatwy.
RT
2
W oparciu o odpowiedź SO zmieniłem program na 20-ms. W międzyczasie naprawiłem też kilka innych błędów. Jeśli jest wystarczające zainteresowanie, postaram się dodać kolory, aby łatwiej było zobaczyć ASCII. Zapraszam do komentowania sugestii, dołożę wszelkich starań, aby je wdrożyć.
RT
Działa to naprawdę dobrze (pamiętaj, aby python3 filenameraczej biegać z python filename).
1

C ++ 1710

Uruchomiłem wersję konsoli ASCII. Żaba może się poruszać. Nadal pracuję nad innymi wymaganiami. Nie wykonałem jeszcze wykrywania obiektów ani oceniania. Żaba porusza się za pomocą klawiszy w, a, s, d.

#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define P(x) cout<<x<<endl
#define R 13
#define C 25
string bank="=========================";
string water="~~~~~~~~~~~~~~~~~~~~~~~~~";
string road="-------------------------";
string log="LOG";
string car="CAR";
string frog="FROG";
string leaf="LEAF";
string rows[R];
bool gameover=false;
int frogX,frogY;

void insertObject(string obj, int row, int pos)
{
    string tmp=rows[row].erase(pos,obj.size());
    tmp.insert(pos,obj);
    rows[row]=tmp;
}

void newBoard()
{
int r,r2;
for(int i=0;i<R;i++)
{
    r=rand()%2+1;//1-3
    if(i==0||i==6||i==12)
    {
        rows[i]=bank;
    }
    else if(i>0&&i<6)
    {
        rows[i]=water;
        for(int j=0;j<r;j++)
        {
            r2=rand()%21;
            insertObject(log, i, r2);
        }
    }
    else
    {
        rows[i]=road;
        for(int j=0;j<r;j++)
        {
            r2=rand()%21;
            insertObject(car, i, r2);
        }
    }
}
insertObject(frog, 12, (int)(C-4)/2);
frogX=(int)(C-4)/2;
frogY=12;
insertObject(leaf, 0, (int)(C-4)/2);
}

void showBoard()
{
#ifdef WIN32
system("cls");
#else
system("clear");
#endif
for(int i=0;i<R;i++)
{
    P(rows[i]);
}
}

void playGame()
{
char c;
int i=0;
while(!gameover)
{
cin>>c;
switch(c)
{
case 'a':
    if(frogX!=0)frogX--;
    break;
case 'w':
    if(frogY!=0)frogY--;
    break;
case 'd':
    if(frogX<21)frogX++;
    break;
case 's':
    if(frogY!=12)frogY++;
    break;
default:
    break;
}
insertObject(frog, frogY, frogX);
showBoard();
i++;
if(i>12) gameover=true;
}
}

int main()
{
    srand(time(0));
    char play='y';
    while(play=='y')
    {
        newBoard();
        showBoard();
        playGame();
        P("Play Again (y/n)?");
        cin>>play;
    }

    return 0;
}
Bacchusbeale
źródło
#define s stringDla nieco bardziej golfa (UWAGA: To wydaje się być krótszy niż jeden znak typedef string s;) Albo można zrobić #define t typedef, to t string s;, chociaż nie wiem, czy który działa
możesz też użyć ++izamiasti++