sexta-feira, julho 26, 2013

"Heaven's Prisoners" by James Lee Burke

Heaven's Prisoners - James Lee Burke
description

My 2nd James Lee Burke.

With each book I'm getting convinced that Burke's books are more than meets the eye Crime-Fiction-wise. 

I'm also starting to realize that I don't read Burke for the plotting, which is almost non-existent, by detective story standards, ie, he is barely competent in that area. But what he lacks in terms of plotting skills, he gains by using his books as a vehicle for serious comment on society, specifically the Southern one.

Along the lines of Gonçalo M. Tavares books, James Lee Burke also writes using aphorisms. In this book it's not so pronounced as it was in "Neon Rain". I still remember one of "lines" that impressed me the most: "I don’t like the world the way it is, and I miss the past. It’s a foolish way to be.” (or something roughly similar).

In the first two novels I've read, Robicheaux reasserts the “mature” wisdom of Burke's aphorisms, as though he, after the intense turmoil depicted in the novels, finally achieves something like inner peace — with himself and with the world he does not like. 

I find some likeness between P.D. James and James Lee Burke, namely the fact that my main interest in Dalglish and Robicheaux lies not in the answers these two main characters give us but in the sort of persons they're and the answers they'll find for themselves, in their own lives. As I've stated again and again in several reviews, what interests me are neither the plotting contraptions nor the solving of mysteries. That's neither here or there.

Unlike what happened with the Matthew Scudder series by Lawrence Block, where I almost read them in one sitting, I'm going to limit myself to one or two Robicheuax's books a year...

sábado, julho 20, 2013

"Aprender a Rezar na Era da Técnica (O Reino, #4)" by Gonçalo M. Tavares

Aprender a Rezar na Era da Técnica  - Gonçalo M. TavaresCan one build his life on the refusal to really live with others? 

This is a story of a "relentless rise" and even an abrupt descent of a man that is born to be a servant of violence.

Lenz Buchmann is an utterly despicable character but what a phenomenal and satisfying portrait of a despicable character it is. Maybe that's why the book works on several levels. The thin line between melodrama and pastiche verges on the absolutely brilliant. 

The books looks to me like an instruction manual because of its structure (the finely neat division in headlines, chapters and sections and language (technical and analytical, and yet also so distant).

While reading this book Kafka and Gombrowicz comes to mind. I'll try "to verbalize" the reasons:

1 - Tavares vs Kafka: Absurdist tendencies and a very dark look towards life;

2 - Tavares vs Kafka: Aphorisms abound. One could say that the book is almost entirely written in an aphoristic style. The similarities between Kafka and Tavares kept coming to mind ("Nachgelessene Schriften und Fragmente" by Kafka is a fine example of the Art of the Aphorism). In post-modern literature I don't recall another example to keep Tavares company;

3 - Tavares vs Gombrowicz: Battle against the strictures of culture.

Is it shown here the age of the "Death of God"? And with what can we replace Him? Technology...?

Thinking material permeates the book...

sexta-feira, julho 19, 2013

"Spy in Question" by Tim Sebastian

The Spy In Question - Tim Sebastian
description 

This novel is pitch perfect. Not your normal spy story. Very realistic. It kept me up almost all night. I read it in just one sitting. The suspense builds and builds. What started as beach reading ended up being something else entirely. 
A good example of a spy novel that transcends the genre. For me the only question that matters when judging on how good a novel is, it's not whether it has spies or detectives or nurses marrying doctors. What matters is whether it shows instead of telling or whether there are literary devices that do not put me out of the story. In this case it was true on both accounts. 
Nice discovery on holidays...

quinta-feira, julho 18, 2013

"A Separate Peace" by John Knowles

A Separate Peace - John Knowles
description

This is one of my favourite books from years ago. I've read and re-read it quite a few times. As soon as I saw that the Beach Resort where I was staying had a copy I didn't look back. It was impossible for me to put it down once I began skimming it and I still own an original copy at home. It made my day. Beach Reading it is not...
Amazing how some books stick in the mind thirty years after you read them (in a British Council Literature Class). I still remember the utter shock when Finny died! It was so sad darn it!
The book shows great examples of how dramatic it is to be an adolescent.

Finny is for the ages!

terça-feira, julho 16, 2013

"LifeGuard" by James Patterson, Andrew Gross

Lifeguard - James Patterson, Andrew Gross
description

Horrible writing and a predictable, ridiculous story. One of the stupidest books I've ever read. 

I'd give it 0 stars if it were possible...

Some people should be forbidden to write! The guy should be neutered!!!

domingo, julho 14, 2013

"Wilt in Nowhere" by Tom Sharpe

Wilt In Nowhere - Tom SharpeThe guy died recently and I got my hands on the last Wilt book while on holidays. 

It's my first Tom Sharpe novel and I had great fun with the less salubrious side of the English language lol.

The plot seems to be slightly unsatisfactory in that it come to no real conclusion, but that does not matter because, the path to get there it's more important than the point of arrival. 

I found myself laughing out loud with absurdity of the situations, although one also feels that, under certain circumstances, these things might happen for real.

It' a treat to follow how the innocent actions will lead to chaotic results, and that is where the fun lies.

This's hardly great literature, but the non-stop nonsense is very enjoyable.

sábado, julho 13, 2013

"A Darkening Stain" by Robert Wilson

A Darkening Stain - Robert Wilson, Anthony Sheil
description

My first Bruce Medway novel.

It follows the queasy moral sense and impeccable scene-setting of such notable predecessors as Graham Greene and Eric Ambler.
Wilson continues to confound expectations, and strenuously resists categorization in any easy fashion. The setting in this book is much different than everything else I've read from him. Also the way the tale is told make it altogether a much grimmer kind of story.
We're not in Agatha Christie territory (whodunits and cozy mysteries with knitting themes). This's more of a sort of gritty crime noir that has been pushed to a whole new, darker level.

terça-feira, julho 09, 2013

Advanced Python Class: "PacMan" (extra-project)






Necessary Primitives/Structures:


Lists — Lists 


Lists can be constructed as a sequence of objects inside square brackets; e.g; [2,4,6]. The list function also converts other types of sequence data such as strings into lists.
Sequence operations such as indexing l[i], concatenation +, length len(l) and slicing apply to lists.
As opposed to strings, an element of a list can be mutated via assignment l[i] = x.
Lecture examples - None
More examples - Structure, True-False Quiz, Silly Words, Rainbow Canvas, Digital Numbers 

Points and vectors — Motion 


A point in 2D is represented by a pair of Cartesian coordinates.
A vector in 2D is represented by a pair of numbers (its horizontal and vertical components).
Taking the difference of two points (componentwise) yields a vector.
Vectors can be added and scaled (componentwise). Points should not be added or scaled.
Adding a point and a vector (componentwise) yields a new point. This operation can be used to animate moving points.
Lecture examples - Timer Control, Formula Control 
More examples - Drawing Vectors 

Distance computations — Collisions and reflections 


The distance between two points p0 and p1 is 
√(p0[0]-p1[0])2+(p0[1]-p1[1])2 .
The distance between a point and a circle and the distance between two circles follows from this formula.
The set of points [x,y] that satisfy the equation a*x + b*y + c == 0 is a line. The distance from this line to a point p is 
(a*p[0] + b*p[1] + c)/ √a2 + b2 
The distance from a circle to a line is the distance from the center of the circle to the line minus the radius.

Reflections — Collisions and reflections 


The direction of reflection for a ball bouncing off of a wall depends on the incoming velocity vector v and the normal vector to the wall at the point of contact.
The incoming velocity vector can be decomposed into v = vp + vn where vn is the component of v orthogonal to wall and vp is the component parallel to to the wall.
In this model, the reflected vector is v = vp - vn.
This model simplifies for horizontal and vertical walls. In particular, reflection simply negates one component of the velocity vector v.

Keyboard events — Keyboard input 


SimpleGUI suppports two event handlers for keyboard events.
The key down event handler is registered via set_keydown_handler.
The key up event handler is registered via set_keyup_handler.
The variable passed to each of these handlers is a number that can be compared at the constants in KEY_MAP to determine which key has been pressed.

Positional control — Keyboard input 


We can control the position of a point p directly using key board events.
The horizontal and vertical components of a point p's position can be increment/decrement via p[i] += c in response to key presses.

Velocity control — Velocity control 


Basic physics relates the position of a point p and its velocity v via the equation p += dt * v where dt is a small time step.
In this model, we can control the motion of p via keyup/keydown events that increment/decrement the two components of the velocity vector v via v[i] += c.


Mutable vs. immutable data — Programming tips #4 


Numbers, Booleans and strings are immutable and can not be modified. Only new copies of these kinds of data can be made.
On the other hand, parts of a list can be mutated via assignment to individual elements of the list.
Assignment of an entire list to a variable generates a reference that refers to the list. Subsequent assignment may generate multiple references to the same list.
Mutating a list with multiple references modifies all references to the list. This capability is very useful, but can generate subtle errors.


Code Implementation:

######################################
## Implementation of Pac-Man #########
##     Manuel Augusto Antao  #########
##     Python Class          #########
##     Rice University       #########
##     Extra-Project         #########
######################################

import simplegui
import math
import random
import user17_9jVc7rMrHiUCj84

# Images
board_image = simplegui.load_image("http://www.sitehacks.com/iipp/pacman/board.png?99")
ghost_image = simplegui.load_image("http://www.sitehacks.com/iipp/pacman/ghosts.png?5")
pacman_image = simplegui.load_image("http://www.sitehacks.com/iipp/pacman/pacman.png?5")
edible_image = simplegui.load_image("http://www.sitehacks.com/iipp/pacman/edibles.png?5")

# sounds
'''
Some or all of the sounds were obtained from the following sites:
http://www.playonloop.com/help-and-faqs/#faq5
http://www.noiseforfun.com/help-and-faqs/#faq5
http://www.sweetsoundeffects.com
'''
intro_sound = simplegui.load_sound("https://www.dropbox.com/s/ebm4oe6qgxwtw3i/Pacman%20Opening%20Song.mp3?dl=1")
pellet_sound = simplegui.load_sound("http://www.sitehacks.com/iipp/pacman/eatpellet.ogg?dl=1")
gotcha_sound = simplegui.load_sound("https://www.dropbox.com/s/okabhdekblptzaf/Pacman%20Dies.mp3?dl=1")
edible_sound = simplegui.load_sound("https://www.dropbox.com/s/1mcyemcpucwism8/Pacman%20Eating%20Cherry.mp3?dl=1")
eating_ghost_sound = simplegui.load_sound("https://www.dropbox.com/s/j6igmizn067frdo/Pacman%20Eating%20Ghost.mp3?dl=1")
frightened_sound = simplegui.load_sound("http://www.sitehacks.com/iipp/pacman/ateapill.ogg?dl=1")
one_up_sound = simplegui.load_sound("https://www.dropbox.com/s/ebg5xsryua99yz9/Pacman%20Extra%20Live.mp3?dl=1")

# direction_to_vel dictionary {direction: (forbidden_direction, velocity, angle)}
direction_to_vel = {"left" : ("right", (-1, 0), math.pi),
                     "right": ("left", (1, 0), 0),
                     "up"   : ("down", (0, -1), 3 * math.pi / 2),
                     "down" : ("up", (0, 1), math.pi / 2)}

# levels (waves)
levels = [[7, 27, 34, 54, 59, 79, 84],
          [7, 27, 34, 54, 59, 1092, 1093],
          [5, 25, 30, 50, 55, 1092, 1093]]

######################
# initialize globals #
######################
board = user17_9jVc7rMrHiUCj84.board
WIDTH = 448
HEIGHT = 576
PAC_INIT_POS = (14*16, 26.5*16)
pac_time = 0
cur_direction = "left"
global_timer = 0
global_dot_counter = 0
score = 0
eaten_pellets = []
level = 1
frightened_timer = 0
previous_mode = "scatter"
eaten_ghosts = []
lives = 3
flicker_timer = 0
release_ghost_timer = 0
edible_exists = False
edible_timer = 0
eatable_spawn_list = [70, 170]
started = False
popups = set()
game_timer = 0
one_up = False
eaten_fruits = [-1, -1, -1, -1, -1, -1, -1]
fruit_count = 0

###########################
# define helper functions #
###########################
def reset():
    """resets everything"""
    global board, pacman, blinky, pinky, inky, clyde, ghost_list, ghosts_in_house, edible, popups, global_timer, global_dot_counter, eaten_pellets, frightened_timer, previous_mode, eaten_ghosts, flicker_timer, release_ghost_timer, edible_exists, edible_timer, eatable_spawn_list, game_timer, cur_direction
 
    for tile in eaten_pellets:
        board[tile[0]][tile[1]] = 2
    board[6][1] = 3
    board[6][26] = 3
    board[26][1] = 3
    board[26][26] = 3
    pacman = Pacman()
    blinky = Blinky()
    pinky = Pinky()
    inky = Inky()
    clyde = Clyde()
    ghost_list = [blinky, pinky, inky, clyde]
    ghosts_in_house = [pinky, inky, clyde]
    edible = Edible()
    popups = set()
 
    global_timer = 0
    global_dot_counter = 0
    eaten_pellets = []
    frightened_timer = 0
    previous_mode = "scatter"
    flicker_timer = 0
    eatable_spawn_list = [70, 170]
    eaten_ghosts = []
    release_ghost_timer = 0
    edible_exists = False
    edible_timer = 0
    game_timer = 0
    cur_direction = "left"
    Ghost.set_mode("scatter")
 
def process_group(group, canvas):
    """Processes and draws a group"""
    for obj in group:
        obj.draw(canvas)
             
def dist(point1, point2):
    """return the distance between two points"""
    return math.sqrt((point1[0] - point2[0])**2 + (point1[1] - point2[1])**2)

def kill_pacman():
    """handle pacman's death"""
    global lives, global_timer, temp, global_dot_counter
    # decrement lives
    lives -= 1
    # play gotcha_sound
    gotcha_sound.play()
    # stop pacman where it is
    pacman.set_vel([0, 0])
    # remove ghosts from the field
    for ghost in list(ghost_list):
        ghost_list.remove(ghost)
    # reset Ghost.mode
    Ghost.set_mode("scatter")
    # kill pacman :[
    pacman.set_alive(False)
    temp = global_timer
    # reset global_dot_counter
    global_dot_counter = 1
##################
# define classes #
##################
class Pacman:
    def __init__(self):
        self.pos = list(PAC_INIT_POS)
        self.direction = "left"
        self.vel = [direction_to_vel[self.direction][1][0], direction_to_vel[self.direction][1][1]]
        self.orientation = direction_to_vel[self.direction][2]
        self.sprite_index = 0
        self.alive = True
    def draw(self, canvas):
        """draw Pacman on the board"""
        canvas.draw_image(pacman_image, (13 + 26 * self.sprite_index, 13), (26, 26), self.pos, (26, 26), self.orientation)
     
        # update
        if self.alive:
            self.update()
     
    def update(self):
        global pac_time, score, release_ghost_timer
        """Update Pacman position"""
        # move
        self.pos[0] = (self.pos[0] + 2 * self.vel[0]) % 448
        self.pos[1] += 2 * self.vel[1]
        # animate
        if self.alive:
            pac_time = (pac_time + 1) % 100
            if pac_time % 5 == 0:
                self.sprite_index = (self.sprite_index + 1) % 2
     
        if self.pos[0] % 16 == 8 and self.pos[1] % 16 == 8:
            cur_block = [self.pos[1] // 16, self.pos[0] // 16]
            # stop moving if pacman is against a wall
            if board[cur_block[0] + self.vel[1]][(cur_block[1] + self.vel[0]) % 28] == 0:
                self.vel = [0, 0]
            # eat pellets
            if board[cur_block[0]][cur_block[1]] in (2, 3):
                eaten_pellets.append(cur_block)
                # update score
                if board[cur_block[0]][cur_block[1]] == 2:
                    score += 10
                else:
                    score += 50
                    Ghost.set_mode("frightened")
                # reset release_ghost_timer
                release_ghost_timer = 0
                # play pellet_sound
                pellet_sound.play()

    def get_pos(self):
        """return position"""
        return self.pos
 
    def get_vel(self):
        """return velocity"""
        return self.vel
 
    def get_orientation(self):
        """return orientation"""
        return self.orientation
 
    def get_direction(self):
        """return direction"""
        return self.direction
 
    def get_sprite_index(self):
        """return sprite index"""
        return self.sprite_index
 
    def is_alive(self):
        """check if pacman is alive"""
        return pacman.alive
 
    def set_pos(self, pos):
        """set position"""
        self.pos = pos
 
    def set_vel(self, vel):
        """set velocity"""
        self.vel = vel
 
    def set_orientation(self, angle):
        """set orientation"""
        self.orientation = angle
     
    def set_direction(self, direction):
        """set direction"""
        self.direction = direction
     
    def set_sprite_index(self, index):
        """set sprite index"""
        self.sprite_index = index
     
    def set_alive(self, boolean):
        """set pacman's status"""
        self.alive = boolean
     
class Ghost:
    mode = "scatter"
    default_vel = 2
    def __init__(self):
        self.sprite_index = 0
        self.direction = "left"
        self.vel = direction_to_vel[self.direction][1]
        self.vel_mag = Ghost.default_vel
        self.dot_count = 0
        self.has_turned = False
     
    def draw(self, canvas):
        """draw ghost on the canvas"""
        canvas.draw_image(ghost_image, [13 + 26 * self.sprite_index, 13 + 26 * self.ghost_index], [26, 26], self.pos, [26, 26])
     
        # update ghost if not in house
        if self not in ghosts_in_house:
            self.update()
        #canvas.draw_circle([self.tile[1] * 16, self.tile[0] * 16], 3, 1, "Red", "Red")
    def update(self):
        """update ghost"""
        global eaten_ghosts_count, score, lives, frightened_timer, flicker_timer
        # turn into disembodied eyes when eaten by pacman
        if self in list(eaten_ghosts):
            # resurrect if eaten ghost reaches house
            if self.in_house:
                eaten_ghosts.remove(self)
                self.sprite_index = 0
            else:
                self.sprite_index = 3
        if self.pos[0] % 16 == 8 and self.pos[1] % 16 == 8:
            # if getting out of house, set target tile to the tile just outside the gate
            if self.in_house == True:
                self.tile = [14, 13]
            # else, if eaten by pacman, rush to house
            elif self in eaten_ghosts:
                self.tile = [17, 13]
            # else, if scatter mode, set scatter tile as the target tile
            elif Ghost.mode == "scatter":
                self.tile = self.scatter_tile
            # otherwise, update target tile
            else:
                self.tile_update()
         
            # handle movement
            cur_block = [self.pos[1] // 16, self.pos[0] // 16]
            available_directions = []
            # check if passing the gates
            if board[cur_block[0]][cur_block[1]] == 4:
                self.in_house = not self.in_house
             
            # make a list of forbidden blocks
            forbidden_blocks = [0]
            if not self.in_house and self not in eaten_ghosts:
                forbidden_blocks.append(4)
            # check all possible directions
            for direction in direction_to_vel.keys():
                # except the direction the ghost is coming from
                if direction != direction_to_vel[self.direction][0]:
                    if board[cur_block[0] + direction_to_vel[direction][1][1]][(cur_block[1] + direction_to_vel[direction][1][0]) % 28] not in forbidden_blocks:
                        available_directions.append(direction)
         
            # frightened mode
            if Ghost.mode == "frightened":
                # :)
                # make it move randomly
                if self not in eaten_ghosts:
                    chosen_direction = random.choice(available_directions)
                    self.direction = chosen_direction
                # else, make it move to the house  
                else:
                    # move to house if not in house
                    if not self.in_house:
                        min = 10000 #a large number
                        for direction in available_directions:
                            if dist([(cur_block[0] + direction_to_vel[direction][1][1]), (cur_block[1] + direction_to_vel[direction][1][0])], self.tile) < min:
                                min = dist([(cur_block[0] + direction_to_vel[direction][1][1]), (cur_block[1] + direction_to_vel[direction][1][0])], self.tile)
                                chosen_direction = direction
                        self.direction = chosen_direction
                        # increase velocity
                        self.vel_mag = 4
                     
                 
             
            # chase or scatter mode
            else:
                # make it turn
                if not self.has_turned:
                    self.turn()
                # make it chase
                min = 10000 #a large number
                for direction in available_directions:
                    if dist([(cur_block[0] + direction_to_vel[direction][1][1]), (cur_block[1] + direction_to_vel[direction][1][0])], self.tile) < min:
                        min = dist([(cur_block[0] + direction_to_vel[direction][1][1]), (cur_block[1] + direction_to_vel[direction][1][0])], self.tile)
                        chosen_direction = direction
                self.direction = chosen_direction
                 
     
            # slow down ghosts in the tunnel
            if self not in eaten_ghosts:
                if board[cur_block[0]][cur_block[1]] == 5:
                    self.vel_mag = 1
                else:
                    self.vel_mag = Ghost.default_vel
                 
        # check if eaten by pacman
        if [pacman.get_pos()[1] // 16, pacman.get_pos()[0] // 16] == [self.pos[1] // 16, self.pos[0] // 16]:
            if Ghost.mode == "frightened":
                if self not in eaten_ghosts:
                    eaten_ghosts.append(self)
                    eaten_ghosts_count += 1
                    popup = Popup(list(pacman.get_pos()), ((2**eaten_ghosts_count) * 100))
                    popups.add(popup)
                    eating_ghost_sound.play()
                    score += (2**eaten_ghosts_count) * 100
            else:
                if self not in eaten_ghosts:
                    if pacman.is_alive():
                        kill_pacman()
     
        self.pos[0] = (self.pos[0] + self.vel_mag * direction_to_vel[self.direction][1][0]) % 448
        self.pos[1] += self.vel_mag * direction_to_vel[self.direction][1][1]
         
     
    def turn(self):
        """turn the ghost in the direction it is coming from"""
        self.has_turned = True
        self.direction = direction_to_vel[self.direction][0]
 
    def get_pos(self):
        """return position"""
        return self.pos
 
    def get_direction(self):
        """return direction"""
        return self.direction
 
    def get_index(self):
        """return ghost index"""
        return self.ghost_index
 
    def get_dot_count(self):
        """return dot count"""
        return self.dot_count
 
    def get_dot_limit(self):
        """return dot limit"""
        return self.dot_limit
 
    def get_tile(self):
        """return target tile"""
        return self.tile
 
    def get_mode():
        """return mode"""
        return Ghost.mode
 
    def set_pos(self, pos):
        """set position"""
        self.pos = pos
     
    def set_direction(self, direction):
        """set direction"""
        self.direction = direction
     
    def set_dot_count(self, dot_count):
        """set dot count"""
        self.dot_count = dot_count
     
    def set_tile(self, tile):
        """set target tile"""
        self.tile = tile
     
    def set_sprite_index(self, index):
        """set sprite index"""
        self.sprite_index = index
 
    def set_mode(mode):
        """set ghost mode"""
        global previous_mode, frightened_timer, eaten_ghosts_count, flicker_timer
        # stop frightened_sound
        frightened_sound.rewind()
        # turn on mode change
        if not Ghost.mode == "frightened":
            for ghost in ghost_list:
                ghost.has_turned = False
                ghost.turn()
     
     
 
        # handle frightened mode #
        if mode == "frightened":
            # play frightened_sound
            frightened_sound.play()
            # reset eaten ghosts count
            eaten_ghosts_count = 0
            # reset flicker_timer
            flicker_timer = 0
            if Ghost.mode != "frightened":
                previous_mode = Ghost.mode
            for ghost in ghost_list:
                if ghost not in eaten_ghosts:
                    # 1. turn ghosts purple
                    ghost.sprite_index = 1
                    # 2. slow down the ghosts
                    Ghost.default_vel = 1
                    # 3. Reset frightened_timer
                    frightened_timer = 0
        else:
            for ghost in ghost_list:
                ghost.sprite_index = 0
            Ghost.default_vel = 2
             
        # change mode
        Ghost.mode = mode              
             
         
     
 
class Blinky(Ghost):
    def __init__(self):
        Ghost.__init__(self)
        self.ghost_index = 0
        self.start_pos = [14 * 16, 14.5 * 16]
        self.pos = self.start_pos
        self.scatter_tile = [2, 25]
        self.tile = [0, 0]
        self.in_house = False
        self.dot_limit = 0
     
    def tile_update(self):
        # update target tile
        self.tile = [pacman.get_pos()[1] // 16, pacman.get_pos()[0] // 16]
                 
class Pinky(Ghost):
    def __init__(self):
        Ghost.__init__(self)
        self.ghost_index = 1
        self.start_pos = [14 * 16, 17.5 * 16]
        self.pos = self.start_pos
        self.scatter_tile = [2, 2]
        self.tile = [0, 0]
        self.in_house = True
        self.dot_limit = 0
    def tile_update(self):
        # update target tile
        self.tile = [(pacman.get_pos()[1] // 16 + 4 * direction_to_vel[pacman.get_direction()][1][1]), (pacman.get_pos()[0] // 16 + 4 * direction_to_vel[pacman.get_direction()][1][0])]
     
class Inky(Ghost):
    def __init__(self):
        Ghost.__init__(self)
        self.ghost_index = 2
        self.start_pos = [12 * 16, 17.5 * 16]
        self.pos = self.start_pos
        self.scatter_tile = [34, 27]
        self.tile = [0, 0]
        self.in_house = True
        if level == 1:
            self.dot_limit = 30
        else:
            self.dot_limit = 0
    def tile_update(self):
        # update target tile
        intermediate_block = [pacman.get_pos()[1] // 16 + 2 * direction_to_vel[pacman.get_direction()][1][1], pacman.get_pos()[0] // 16 + 2 * direction_to_vel[pacman.get_direction()][1][0]]
        blinky_block = [blinky.get_pos()[1] // 16, blinky.get_pos()[0] // 16]
        difference = [intermediate_block[0] - blinky_block[0], intermediate_block[1] - blinky_block[1]]
        self.tile = [intermediate_block[0] + difference[0], intermediate_block[1] + difference[1]]
     
     
class Clyde(Ghost):
    def __init__(self):
        Ghost.__init__(self)
        self.ghost_index = 3
        self.start_pos = [16 * 16, 17.5 * 16]
        self.pos = self.start_pos
        self.scatter_tile = [34, 0]
        self.tile = [0, 0]
        self.in_house = True
        if level == 1:
            self.dot_limit = 60
        elif level == 2:
            self.dot_limit = 50
        else:
            self.dot_limit = 0
    def tile_update(self):
        # update target tile
        cur_block = [self.pos[1] // 16, self.pos[0] // 16]
        pacman_block = [pacman.get_pos()[1] // 16, pacman.get_pos()[0] // 16]
        distance = dist(cur_block, pacman_block)
        if distance > 8:
            self.tile = pacman_block
        else:
            self.tile = self.scatter_tile
         

class Popup:
    def __init__(self, pos, value):
        self.pos = pos
        self.value = value
        self.size = 12
        self.color = "White"
        self.init_pos = pos[1]
        self.vel = 1
     
    def draw(self, canvas):
        global popups
        canvas.draw_text(str(self.value), self.pos, self.size, self.color)
        self.pos[1] -= self.vel
        if self.pos[1] <= self.init_pos - 30:
            popups.remove(self)
         
class Edible:
    global level
    def __init__(self):
        self.pos = (14 * 16, 20.5 * 16)
        self.value = level * 100
        if level <= 7:
            self.sprite_index = (level - 1)
        else:
            self.sprite_index = 6
     
    def draw(self, canvas):
        """draw edible on the canvas"""
        canvas.draw_image(edible_image, (14 + (self.sprite_index * 28), 14), (28, 28), self.pos, (28, 28))
     
    def get_value(self):
        """return edible's value"""
        return self.value
 
    def get_sprite_index(self):
        """return sprite index"""
        return self.sprite_index

     
#########################
# define event handlers #
#########################
def draw(canvas):
    global started, pac_time, cur_direction, score, lives, frightened_timer, flicker_timer, global_dot_counter, release_ghost_timer, edible_exists, edible_timer, level, one_up, fruit_count
    # draw background
    canvas.draw_image(board_image, (224, 288), (448, 576), (WIDTH / 2, HEIGHT / 2), (WIDTH, HEIGHT))
 
    # blackout eaten pellets
    for i in range(4, 33):
        blackout_range = 0
        for j in range(1, 28):
            if board[i][j] == 1 :
                blackout_range += 1
            else:
                if blackout_range!=0:
                    canvas.draw_polygon([((j - blackout_range) * 16, i * 16), ((j - blackout_range) * 16, (i * 16) + 16),
                                         (j * 16, (i * 16) + 16), (j * 16, i * 16)], 1, "Black", "Black")
                    blackout_range = 0
                 
    if started:              
        # draw Pacman
        pacman.draw(canvas)
 
        # play kill animation
        if not pacman.is_alive():
            flicker_timer = (flicker_timer + 1) % 10
            if flicker_timer % 10 == 0:
                pacman.set_sprite_index(pacman.get_sprite_index() + 1)
 
        ## update pacman direction ##
        # check if pacman is in the center of a grid point
        if pacman.get_pos()[0] % 16 == 8 and pacman.get_pos()[1] % 16 == 8:
            # determine pacman's current block
            cur_block = [pacman.get_pos()[1] // 16, pacman.get_pos()[0] // 16]
            # determine if pacman can move in that direction
            if board[cur_block[0] + direction_to_vel[cur_direction][1][1]][(cur_block[1] + direction_to_vel[cur_direction][1][0]) % 28] not in [0, 4]:
                pacman.set_vel(direction_to_vel[cur_direction][1])
                pacman.set_direction(cur_direction)
                pacman.set_orientation(direction_to_vel[cur_direction][2])
        #############################
     
        # draw Ghosts
        process_group(ghost_list, canvas)
 
        # make ghosts flicker
        if Ghost.get_mode() == "frightened":
            if frightened_timer > 4:
                flicker_timer = (flicker_timer + 1) % 50
                if flicker_timer < 25:
                    for ghost in ghost_list:
                        if ghost not in eaten_ghosts:
                            ghost.set_sprite_index(2)
                else:
                    for ghost in ghost_list:
                        if ghost not in eaten_ghosts:
                            ghost.set_sprite_index(1)
 
        ## release ghosts from house ##
        # 1. determine preferred ghost
        min = 4
        for ghost in ghosts_in_house:
            if ghost.get_index() < min:
                min = ghost.get_index()
                preferred_ghost = ghost
         
        # 2. update counter whenever pacman eats a dot
        # 2.1 check if there is a ghost in house
        if ghosts_in_house:
            # 2.1. check if pacman is in the middle of a tile
            if pacman.get_pos()[0] % 16 == 8 and pacman.get_pos()[1] % 16 == 8:
                # 2.2. check if pacman's tile has a pellet in it
                cur_block = [pacman.get_pos()[1] // 16, pacman.get_pos()[0] // 16]
                if board[cur_block[0]][cur_block[1]] == 2:
                    # 3. Release ghost
                    # if global_dot_counter is enabled, use it.
                    if global_dot_counter:
                        global_dot_counter += 1
                        if global_dot_counter in [8, 18, 33]:
                            ghosts_in_house.remove(preferred_ghost)
                    # else, use individual dot counters
                    else:
                        preferred_ghost.set_dot_count(preferred_ghost.get_dot_count() + 1)
                        if preferred_ghost.get_dot_count() >= preferred_ghost.get_dot_limit():
                            ghosts_in_house.remove(preferred_ghost)
                            preferred_ghost.set_dot_count(0)
            # Alternate, timer based way of releasing ghosts
            if release_ghost_timer >= 4:
                ghosts_in_house.remove(preferred_ghost)
                release_ghost_timer = 0

    # else, display "click to start!"
    else:
        canvas.draw_text("Click to start!", (11*16, 21*16), 18, "Red")
     
    # remove eaten pellet
    for tile in eaten_pellets:
        board[tile[0]][tile[1]] = 1
     
    # draw popups
    process_group(popups, canvas)
 
    # draw edibles
    if len(eaten_pellets) in eatable_spawn_list:
        eatable_spawn_list.remove(len(eaten_pellets))
        edible_exists = True
    if edible_exists:
        edible.draw(canvas)
        if [pacman.get_pos()[1] // 16, pacman.get_pos()[0] // 16] in [[20,13], [20,14]]:
            score += edible.get_value()
            popup = Popup(list(pacman.get_pos()), edible.get_value())
            popups.add(popup)
            if edible.get_sprite_index() not in eaten_fruits:
                eaten_fruits[fruit_count] = edible.get_sprite_index()
                fruit_count += 1
            edible_sound.play()
            edible_exists = False
            edible_timer = 0
   
    # display score and level
    canvas.draw_text("Score: " + str(score), (304, 16), 16, "White")
    canvas.draw_text("Level: " + str(level), (304, 32), 16, "White")
 
    # display lives
    for i in range(lives):
        canvas.draw_image(pacman_image, (13, 13), (26, 26), (32 + (i * 30), 560), (26, 26))
     
    # update level
    if len(eaten_pellets) == 244:
        level += 1
        reset()
     

     
    # award one_up when player's score reaches 10000
    if score == 10000 and not one_up:
        lives += 1
        one_up = True
        one_up_sound.play()
     
    # draw eaten fruits
    for i in range(7):
        if eaten_fruits[i] != -1:
            canvas.draw_image(edible_image, (14 + (eaten_fruits[i] * 28), 14), (28, 28), (16 * 14 + (i * 33), 16 * 35), (28, 28))

def move(key):            
    global cur_direction
    if key == simplegui.KEY_MAP["left"]:
        cur_direction = "left"
    elif key == simplegui.KEY_MAP["right"]:
        cur_direction = "right"
    if key == simplegui.KEY_MAP["up"]:
        cur_direction = "up"
    if key == simplegui.KEY_MAP["down"]:
        cur_direction = "down"
     
def tick():
    global started, game_timer, global_timer, level, frightened_timer, previous_mode, pacman, temp, ghost_list, ghosts_in_house, cur_direction, blinky, pinky, inky, clyde, release_ghost_timer, edible_exists, edible_timer
 
    if started:
        # resurrect pacman and the ghosts
        if not pacman.is_alive():
            # wait for the kill animation to stop
            if global_timer - temp > 2:
                # check game over condition
                if lives == 0:
                    started = False
                # reset ghosts and pacman
                else:
                    blinky = Blinky()
                    pinky = Pinky()
                    inky = Inky()
                    clyde = Clyde()
                    pacman = Pacman()
                    cur_direction = "left"
                    ghost_list = [blinky, pinky, inky, clyde]
                    ghosts_in_house = [pinky, inky, clyde]
                    Ghost.set_mode("scatter")
                    global_timer = 0
                    release_ghost_timer = 0
     
        if not Ghost.get_mode() == "frightened":
            global_timer += 1
            if level == 1:
                wave_set = 0
            elif level in range(2, 5):
                wave_set = 1
            else:
                wave_set = 2
     
 
            if global_timer == levels[wave_set][0]:
                Ghost.set_mode("chase")
            elif global_timer == levels[wave_set][1]:
                Ghost.set_mode("scatter")
            elif global_timer == levels[wave_set][2]:
                Ghost.set_mode("chase")
            elif global_timer == levels[wave_set][3]:
                Ghost.set_mode("scatter")
            elif global_timer == levels[wave_set][4]:
                Ghost.set_mode("chase")
            elif global_timer == levels[wave_set][5]:
                Ghost.set_mode("scatter")
            elif global_timer == levels[wave_set][6]:
                Ghost.set_mode("chase")
 
        else:
            frightened_timer += 1
            if frightened_timer == 7:
                Ghost.set_mode(previous_mode)
         
        # update release_ghost_timer
        release_ghost_timer += 1
 
        # edible timer
        if edible_exists:
            edible_timer += 1
            if edible_timer >= 10:
                edible_exists = False
                edible_timer = 0
 
    # update game_timer
    if game_timer:
        game_timer += 1
        if game_timer == 5:
            reset()
            started = True
            game_timer = 0
     
def start_game(pos):
    global started, game_timer, lives, score, level, one_up, eaten_fruits, fruit_count
    # start the game if it hasn't already started
    if not started:
        # reset lives, score and level
        lives = 3
        score = 0
        level = 1
        one_up = False
        eaten_fruits = [-1, -1, -1, -1, -1, -1, -1]
        fruit_count = 0
        # play intro music
        intro_sound.play()
        # set game_timer
        game_timer = 1
     
################
# create frame #
################
frame = simplegui.create_frame("Pac-Man - Manuel Augusto Antao - 2013-07-09", WIDTH, HEIGHT)

###########################
# register event handlers #
###########################
frame.set_draw_handler(draw)
frame.set_keydown_handler(move)
frame.set_mouseclick_handler(start_game)
main_timer = simplegui.create_timer(1000, tick)

######################
# set things rolling #
######################
frame.start()
main_timer.start()

"Her Last Call to Louis MacNeice" by Ken Bruen

Her Last Call to Louis MacNeice (Five Star Paperback) - Ken Bruen
description

There's just something about Ken's writing and his characters that reaches into me...
There's not much to speak of in terms of plot, but I was so caught up with Bruen's storytelling and voice that it obliterated everything else. There's no story? No big deal. The characters are an archetype? Most of them are, at their core. But the voice, the sheer, barely concealed rage of it, is what grabbes me.

Ken Bruen is still writing some of the most original, noir, gritty and visceral crime fiction there is about at the moment. 

Hard-Boil at its best. 

sábado, julho 06, 2013

Personal Take on the Book "Foxtrot Oscar" by Charlie Owen

 description

As in the first book ("Horse's Arse"), it gripped me from page one. The characters, the plot-lines and the especially the dialogue were so vivid:

Taken from Pages 21, 25:

'Your worships, the police consider the prisoner is likely to abscond prior to trial as he has no local ties, is of no fixed abode and is a foreign national'.
'A foreign national? From where??'
'He's German, your worships.'
'GERMAN??' shouted Mortimer, who despised the sausage-eating bastards even more than he did the French, before quickly noticing his colleagues' looks of concern and repeating more quietly, 'German?'
[...]
'Where's the interpreter?' asked Mortimer testily, keen to get Herman the German banged up quickly.
'Inspector, where's the interpreter? queried the clerk.
'John, where's the interpreter?' hissed the court inspector to DC Benson, sitting behind him in the body of the court.
'Fuck' replied Benson, acknowledging that he'd completely forgotten to book one.
'You twat,' growled the inspector before getting to his feet and addressing the bench.
[...]
'Is there anyone in the court who speaks German who could help with a basic interpretation?', asked the clerk getting to his feet.
Inspiration had struck, and Psycho had spotted the opportunity quickly. Getting to his feet alongside the dock, he announced dramatically, 'I may be able to help your worships. I speak a little German.' He felt those present in the court gaze at him with new-found respect. Jesus, a copper who spoke German, what next?
'Oh no, stop him for fuck's sake,' hissed Benson urgently to the court inspector.
'Thank you, Constable." He smiled at Psycho. 'Please ask the prisoner to confirm his name and date of birth for the court.'
'Clearing his throat loudly, Psycho tuned to Gunther and said his best Colditz guard accent,  'Vot ist your name?'
'Benson and the court inspector dropped their heads on to the desks in front of them as as incredulous Colonel Mortimer bellowed, 'What did you say?'
Psycho repeated himself, 'Get him to the cells"' and pandemonium ensued.
[...]

Foul-mouthed and amusing in equal measure. That's Charlie Owen...

It's 1976 and England is sweating its nuts off...As an unrelenting heatwave beats down on Britain, the residents of Horse's Arse in North Manchester are reaching melting point. Wading into the middle of this scorching weather are the Grim Brothers, Psycho, Lly, all of them Horse's finest and hardest boiled coppers I'll ever meet lol.

What a laugh this book was. The first volume also inhabited the Laugh Factory, but this one surpasses it by a mile.

The book does not ask for believability, in fact it would be utterly unbelievable if it wasn't for the mundane streak that runs through its pages. So many of the pranks lack a punchline, so many characters' stories are left unresolved, and you quickly realize that this is a novel with roots very much in the real world (Charlie Owen was a Police Inspector in Britain).

The book has two drawbacks:

1 - Its episodic quality. But what it lacks in depth gains from the fact that it's a frequently hilarious book, a snapshot of a summer long ago, when anarchy was very real.

2 - The writing is extremely jarring and confusing. Many times Owen changes the single point of view within each scene. The third person narrator takes over and we'll follow a character down the corridor, leap into the back-story of another character for an unrelated anecdote and then back to first character, all within the same scene. "No can do..."

But oh God, it was a belly laugh!

Two down, two to go ("Bravo Jubilee" and "Two Tribes").


"Analyzing the Analyzers" by Harlan D. Harris, Sean Patrick Murphy

Analyzing the Analyzers: An Introspective Survey of Data Scientists and Their Work - Harlan Harris, Sean Murphy, Marck Vaisman
description 

Your data is part of your biz differentiation, the trick is to maximize its value, and the people working in the field.

At last someone who tries and succeeds to put some order in the field of Data Science.

10 years ago Statistics was the next sexy job. Five years ago it Big Data. But what does that statement mean? Why do we suddenly care about statistics and about data? And the answer is because the web is full of data-driven apps, ie, almost any e-commerce application is a data-driven application. 

There’s a database behind a web front end and middleware that talks to a number of other databases and data services (credit card processing companies, banks, and so on). But merely using data it's not really what we mean by “data science.” A data application acquires its value from the data itself, and creates more data as a result. It’s not just an application with data; it’s a data product. Data science enables the creation of data products.

The ability to take data, ie, to be able to understand it, to process it, to extract value from it, to visualize it, to communicate it -- that’s going to be a hugely important skill in the next decades.