summaryrefslogtreecommitdiff
path: root/ipl/gpacks/xtiles/xtiles.icn
diff options
context:
space:
mode:
Diffstat (limited to 'ipl/gpacks/xtiles/xtiles.icn')
-rw-r--r--ipl/gpacks/xtiles/xtiles.icn881
1 files changed, 881 insertions, 0 deletions
diff --git a/ipl/gpacks/xtiles/xtiles.icn b/ipl/gpacks/xtiles/xtiles.icn
new file mode 100644
index 0000000..ed43b80
--- /dev/null
+++ b/ipl/gpacks/xtiles/xtiles.icn
@@ -0,0 +1,881 @@
+# tiles.icn
+
+# tiles puzzle
+
+# $Id: X-Tiles.icn,v 3.9 1997/02/21 11:35:38 espie Exp espie $
+# minor mods 2000/12/23 gmt
+
+link graphics
+
+
+$define SMILEY_SIZE 40
+
+$define DEFAULT_TSIZE 35
+$define MIN_TSIZE 10
+$define MAX_TSIZE 100
+$define MINSIZE 256
+
+# we use globals as this is mostly a hack
+
+
+
+# individual tiles size (in pixels)
+
+global tile_width, tile_height
+
+
+
+
+# total playfield size
+global n, m
+
+
+
+
+
+global tiles_win, tiles_bw_win # graphics context used to draw tiles
+
+
+# tiles can be shown as normal, highlighted or shadowed border,
+# or even patterned b&w if /normal
+record color_set(normal, highlight, shadow, pattern, name)
+
+
+
+
+global colors # color array to map tiles colors
+global black, white, bgcolor
+
+
+global smiley1, smiley2, smiley3 # smiley images in the lower-right corner
+
+global bgimage # image to put in as background
+
+
+
+
+#################################################################
+#
+# graphics rendering
+#
+#################################################################
+
+# replaces background with my own Image
+procedure my_erase_area(win, x, y, w, h)
+ /x := 0
+ /y := 0
+ /w := WAttrib(win, "width") - x
+ /h := WAttrib(win, "height") - y
+ CopyArea(bgimage, win, x, y, w, h, x, y)
+end
+
+procedure my_draw_string(win, x, y, s)
+ Fg(white)
+ DrawString(win, x+1, y+1, s)
+ Fg(black)
+ DrawString(win, x, y, s)
+end
+
+
+procedure write_score(score)
+ Fg(black)
+ # erase old score, that means the lower band of the window
+ # except the SMILEY_SIZE x SMILEY_SIZE lower-right smiley
+ EraseArea(&window, 0, m * tile_height,
+ n * tile_width-SMILEY_SIZE, SMILEY_SIZE)
+ my_draw_string(&window, 10, m * tile_height + 15, score)
+end
+
+
+procedure draw_smiley(image)
+ DrawImage(&window, n * tile_width-SMILEY_SIZE, m*tile_height,
+ SMILEY_SIZE||",c1,"||image)
+end
+
+
+# ask the user if he wants to replay, new, quit
+procedure user_entry()
+ static buttons
+ initial
+ {
+ buttons := ["(r)eplay ", "(n)ew ", "(q)uit "]
+ }
+
+ # write the button and record corresponding areas
+ leading := WAttrib("ascent") + 5
+ s1 := TextWidth(buttons[1])
+ s2 := TextWidth(buttons[2])
+ s3 := TextWidth(buttons[3])
+ my_draw_string(&window, 5, leading, buttons[1]||buttons[2]||buttons[3])
+ repeat
+ {
+ e := Event()
+ case e of
+ {
+ &lrelease | &mrelease | &rrelease:
+ {
+ # hardcoded button area check
+ if 0 <= &y <= WAttrib("fheight") + 10 then
+ {
+ if (5 <= &x < 5 + s1) then return "r"
+ if (5 + s1 <= &x < 5 + s1 + s2) then return "n"
+ if (5 + s1 + s2 <= &x < 5 + s1 + s2 + s3) then return "q"
+ }
+ if (WAttrib("height")-SMILEY_SIZE < &y < WAttrib("height") &
+ WAttrib("width")-SMILEY_SIZE < &x < WAttrib("width")) then
+ return "u"
+ }
+ "q"|"n"|"r"|"u":
+ {
+ return e
+ }
+ }
+ }
+end
+
+
+# setup tiles color mapping
+procedure setup_colors(color_mode)
+
+ # setup color mode correctly
+ if WAttrib("depth") = 1 then
+ insert(color_mode, "bw")
+ every member(color_mode, "bw") &
+ member(color_mode, m <- "pastel"|"reduced"|"lighter"|"darker") do
+ write("Warning: "||m||" makes no sense in black and white mode")
+ if member(color_mode, "darker") & member(color_mode, "lighter") then
+ write("Warning: lighter and darker specified both, uses darker")
+ # establish possible set of colors/patterns
+ color_names := set([
+ ["red", "darkgray"],
+ ["green", "gray"],
+ ["blue", "lightgray"],
+ ["yellow", "vertical"],
+ ["grey", "diagonal"],
+ ["purple", "horizontal"],
+ ["orange", "grid"],
+ ["magenta", "trellis"],
+ ["cyan", "checkers"],
+ ["blue-cyan", "grains"],
+ ["brown", "scales"],
+ ["bluish green", "waves"]
+ ])
+
+ colors := []
+ # create randomized mapping
+ if member(color_mode, "pastel") then saturation := "moderate "
+ else saturation := ""
+ lightness := ["pale", "light ", "medium ", "dark ", "deep "]
+ if member(color_mode, "darker") then
+ correction := 1
+ else if member(color_mode, "lighter") then
+ correction := -1
+ else
+ correction := 0
+ while c := ?color_names do
+ {
+ delete(color_names, c)
+ put(colors, color_set(&null, white, black, c[2], saturation||c[1]) )
+ member(color_mode, "bw") |
+ {
+ colors[-1].normal :=
+ ColorValue(lightness[3+correction]||colors[-1].name)
+ }
+ }
+ member(color_mode, "bw" | "reduced") |
+ every c := !colors do
+ {
+ c.highlight := \ColorValue(lightness[2+correction]||\c.name) | white
+ c.shadow := \ColorValue(lightness[4+correction]||\c.name) | black
+ }
+ return ColorValue(lightness[3+correction]||"gray")
+end
+
+procedure setup_graphics(color_mode)
+
+ if /bgimage then dummy := WOpen("canvas=hidden", "width=1", "height=1")
+ # assume the background image first pixel is background
+ if /&window then
+ stop("Error: could not open window. Check your display/xauth.")
+ bgcolor := ColorValue(Pixel(\bgimage))
+ black := ColorValue("black") | stop()
+ white := ColorValue("white") | stop()
+ if \bgcolor == black then black :=: white
+ # These sizes MUST be real to match the background image size
+ tile_width := (MINSIZE < WAttrib(\bgimage, "width"))/real(n) |
+ DEFAULT_TSIZE
+ tile_height :=
+ ((MINSIZE < WAttrib(\bgimage, "height"))+SMILEY_SIZE)/real(m) |
+ DEFAULT_TSIZE
+ tile_width >:= MAX_TSIZE
+ tile_height >:= MAX_TSIZE
+
+ # compute and adjust window width/tiles width
+ dwidth := WAttrib(&window, "displaywidth")
+ if dwidth < n * tile_width then
+ # leave one tile margin
+ tile_width := dwidth / (n+1)
+
+ # compute and adjust window height/tiles height
+ dheight := WAttrib(&window, "displayheight")
+ if dheight < m * tile_height + SMILEY_SIZE then
+ # leave one tile margin
+ tile_height := (dheight - SMILEY_SIZE) / (m+1)
+
+ tile_width <:= MIN_TSIZE
+ tile_height <:= MIN_TSIZE
+
+ width := n * tile_width
+ height := m * tile_height + SMILEY_SIZE
+
+ tile_width := integer(tile_width)
+ tile_height := integer(tile_height)
+
+ &window := WOpen("label=the X-Tiles",
+ "bg="||(\bgcolor|white),
+ "font=sans,bold,proportional",
+ "width="||width, "height="||height)
+
+ WClose(\dummy)
+ if bsize := MINSIZE > WAttrib(\bgimage, "width") then
+ {
+ WAttrib(bgimage, "width="||width)
+ every dest := bsize to width by bsize do
+ CopyArea(bgimage, bgimage, 0, 0, bsize, &null, dest, 0)
+ }
+ if bsize := MINSIZE > WAttrib(\bgimage, "height") then
+ {
+ WAttrib(bgimage, "height="||height - SMILEY_SIZE)
+ every dest := bsize to height by bsize do
+ CopyArea(bgimage, bgimage, 0, 0, &null, bsize, 0, dest)
+ }
+
+ tiles_bw_win := Clone(&window, "fillstyle=textured",
+ "fg="||white,"bg="||black)
+ newbg := setup_colors(color_mode)
+ /bgcolor := newbg
+ Bg(bgcolor)
+ EraseArea(&window)
+ tiles_win := Clone(&window)
+
+ smiley1 :=
+$include "smiley1.icn"
+ smiley2 :=
+$include "smiley2.icn"
+ smiley3 :=
+$include "smiley3.icn"
+end
+
+
+#################################################################
+#
+# tiles and tiles rendering
+#
+#################################################################
+
+
+
+# Tiles are saved in a 2-dimensional array
+# Each tile is a unique individual (useful for set entries)
+# that records its own position column/line as well as color
+# /color for empty tiles
+
+
+record tile_square(column, line, color, connect)
+
+procedure t(i, j)
+ static h, empty
+ initial
+ {
+ h := list(n)
+ every h[1 to n] := list(m)
+ every a := 1 to n do
+ every b := 1 to m do
+ h[a][b] := tile_square(a, b, &null)
+ empty := tile_square()
+ }
+ if (1 <= i <= n) & (1 <= j <= m) then
+ return h[i][j]
+ else
+ return empty
+end
+
+
+# compute the connectivity of a given tile (north, south, east, west)
+# suspends with neighboring tiles whose connectivity may have changed
+# PLEASE NOTE: compute_connectivity is definitily NOT purely functional
+# For the computation to be correct, the generator MUST suspends ALL its
+# results
+procedure compute_connectivity(p)
+ /p.connect := ''
+ "ewsn" ?
+ {
+ every q := neighbor(p) do
+ {
+ if \p.color = \q.color | (/p.color & /q.color) then
+ {
+ if not any(p.connect) then
+ {
+ p.connect ++:= move(1)
+ suspend q
+ }
+ else
+ move(1)
+ }
+ else
+ {
+ if any(p.connect) then
+ {
+ p.connect --:= move(1)
+ suspend q
+ }
+ else
+ move(1)
+ }
+ }
+ }
+end
+
+
+# draw bevel around a tile, recessed if /bevel
+procedure draw_bevel(tile, bevel)
+ if /tile.color then fail
+ x := (tile.column - 1) * tile_width
+ y := (m - tile.line) * tile_height
+ x1 := x + tile_width - 1
+ y1 := y + tile_height - 1
+ c1 := colors[tile.color].highlight
+ c2 := colors[tile.color].shadow
+ if \bevel then
+ c1 :=: c2
+
+ # draw bevel areas only if the corresponding connectivity does
+ # NOT exist
+ Fg(c1)
+ "n" ? any(tile.connect) |
+ DrawRectangle(x, y, tile_width-1, 1)
+ "e" ? any(tile.connect) |
+ DrawRectangle(x, y, 1, tile_height-1)
+ Fg(c2)
+ "s" ? any(tile.connect) |
+ DrawRectangle(x, y1-1, tile_width-1, 1)
+ "w" ? any(tile.connect) |
+ DrawRectangle(x1-1, y, 1, tile_height-1)
+end
+
+
+# draw tile itself, including bevel
+procedure draw_tile(tile, bevel)
+ x := (\tile.column - 1) * tile_width | fail
+ y := (m - tile.line) * tile_height
+ if /tile.color then
+ {
+ EraseArea(&window, x, y, tile_width, tile_height)
+ }
+ else
+ {
+ if Fg(tiles_win, \colors[tile.color].normal) then
+ FillRectangle(tiles_win, x, y, tile_width, tile_height)
+ else
+ {
+ WAttrib(tiles_bw_win,
+ "pattern="||colors[tile.color].pattern)|stop(colors[tile.color].pattern)
+ FillRectangle(tiles_bw_win, x, y, tile_width, tile_height)
+ }
+ draw_bevel(tile, bevel)
+ }
+ return
+end
+
+
+procedure draw_bevel_set(s, bevel)
+ if *s <= 1 then fail
+ every draw_bevel(!s, bevel)
+end
+
+#################################################################
+#
+# the game
+#
+#################################################################
+
+
+# suspend a tile's neighbors
+
+procedure neighbor(p)
+ suspend t(\p.column - 1 | \p.column + 1, p.line) |
+ t(\p.column, p.line - 1 | p.line + 1)
+end
+
+# suspend a tile's upwards neighbors, enough for checking that moves remain
+procedure up_neighbor(p)
+ suspend t(p.column + 1, p.line) | t(p.column, p.line + 1)
+end
+
+
+
+# Ye old connected component algorithm
+# start at t(i, j) and maps connected component.
+# return &null if set is empty,
+# and the old set if it is the same set
+
+procedure connected_set(old, i, j)
+ p := t(i, j)
+ if member(\old, p) then return old
+ c := \p.color | return &null
+ s := set()
+ l := [p]
+ while p := pop(l) do
+ if not member(s, p) then
+ {
+ insert(s, p)
+ every q := neighbor(p) & \q.color = c do
+ put(l, q)
+ }
+ return s
+end
+
+
+# suspends all current columns. Assumes a stable game, stops
+# at first empty column
+procedure columns()
+ every i := seq() do
+ {
+ if /t(i, 1).color then fail
+ suspend i
+ }
+end
+
+# suspend all current lines for column c. Stops at first empty line
+# Note that the game is always stable: the first empty tile means the
+# top of the column
+procedure lines(c)
+ every j := seq() do
+ {
+ if /t(c, j).color then fail
+ suspend j
+ }
+end
+
+procedure used_tiles()
+ suspend t(c := columns(), lines(c))
+end
+
+# check whether you can still play
+procedure remains_move()
+ every p := used_tiles() do
+ if \p.color = \up_neighbor(p).color then return
+ fail
+end
+
+
+# compute the interval of columns spanned by a set
+# Note that all columns must be present as the set if 4-connected
+procedure columns_of_set(s)
+ local cmin, cmax
+
+ # you can check that the following test does indeed set up cmin
+ # and cmax correctly
+ every c := (!s).column do
+ (/cmin := c & /cmax := c) | (cmin >:= c) | (cmax <:= c)
+ return [cmin, cmax]
+end
+
+
+# make tiles fall down in individual columns
+procedure remove_individual_tiles(remember, saved, to_draw, s, cmin, cmax)
+ # for each involved column
+ every col := cmin to cmax do
+ {
+ # j: tile line # to replace, k: tile line # to replace it with
+ # find the lowest removable tile
+ if member(s, t(col, j := lines(col))) then
+ {
+ k := j
+ # as long as we did not get outside
+ while \t(col, j).color do
+ {
+ # find non erased tile
+ k +:= 1
+ while member(s, t(col, k)) do
+ k +:= 1
+
+ # and replace it
+ p := t(col, j)
+ put(remember, copy(p))
+ insert(saved, p)
+ put(to_draw, p)
+ p.color := t(col, k).color
+ j +:= 1
+ }
+ }
+ }
+end
+
+# remove empty columns
+procedure remove_columns(remember, saved, to_draw, cmin, cmax)
+ # now check for empty columns in known range
+ if /t(col := cmin to cmax, 1).color then
+ {
+ # if we did find one, we have to check all columns
+ colp := col
+ while col <= n do
+ {
+ colp +:= 1
+ # skip over empty columns... well stop when you get outside
+ while /t(colp, 1).color & colp <= cmax do
+ colp +:= 1
+
+ # copy one column: do every line
+ every j := seq() do
+ {
+ p := t(col, j)
+ q := t(colp, j)
+ # stop when BOTH columns (src and dest) are empty
+ if /p.color & /q.color then break
+ member(saved, p) |
+ {
+ put(remember, copy(p))
+ insert(saved, p)
+ put(to_draw, p)
+ }
+ p.color := q.color
+ }
+ col +:= 1
+ }
+ }
+
+end
+
+procedure remove_tiles(s)
+ cols := columns_of_set(s)
+
+ # first we move tiles around
+ backtrack := [] # copy of tiles that where changed
+ to_draw := [] # list of tiles to draw
+ saved := set() # tiles that changed
+ # note that to_draw and saved hold the same tiles.
+ # saved is used for membership, and to_draw to display tiles
+ # in linear order, which is less confusing
+ remove_individual_tiles(backtrack, saved, to_draw, s, cols[1], cols[2])
+ remove_columns(backtrack, saved, to_draw, cols[1], cols[2])
+
+ # then we update needed connectivities
+ other := rebuild_connectivity(saved)
+ # and finally we redraw tiles
+ redraw_tiles(to_draw, other)
+ return backtrack
+end
+
+
+# redraw the list in order, followed by the set.
+procedure redraw_tiles(l, s)
+ every p := !l do
+ {
+ # there may be duplicates
+ delete(s, p)
+ draw_tile(p)
+ }
+ every draw_tile(!s)
+end
+
+
+# rebuild the connectivity of the whole game, knowing the set of tiles
+# that changed colors
+procedure rebuild_connectivity(s)
+ changed := set()
+ neigh := set()
+
+ # for each tile of the set
+ every p := !s do
+ {
+ q := &null
+ # recompute its connectivity and mark its neighbors that have
+ # changed
+ every q := compute_connectivity(p) do
+ member(s, q) | insert(neigh, q)
+
+ # connectivity changed iff there was such a neighbor !
+ if \q then
+ insert(changed, p)
+ }
+
+ # neighbors are simpler, as we just have to update their connectivity
+ # watch out ! we have to use ALL the results of the generator
+ # compute_connectivity for the computation to be correct
+ every compute_connectivity(!neigh)
+ changed ++:= neigh
+ return changed
+end
+
+procedure undo(changes)
+ c := set()
+ l := []
+
+ # backtrack changes, remember what to draw
+ every p := !changes do
+ {
+ q := t(p.column, p.line)
+ q.color := p.color
+ # easier to build BOTH the list (for non confusing redraw)
+ # and the set (needed by rebuild_connectivity)
+ insert(c, q)
+ put(l, q)
+ }
+ other := rebuild_connectivity(c)
+ redraw_tiles(l, other)
+end
+
+procedure usage()
+ return "Usage: X-Tiles [-v] [-h] _
+[-bw] [-pastel] [-reduced] [-darker] [-lighter] _
+[colors] [columns] [lines] [seed] [bg]"
+end
+
+
+procedure whoami()
+# $Id: X-Tiles.icn,v 3.9 1997/02/21 11:35:38 espie Exp espie $
+ name := ""
+ "$Id: X-Tiles.icn,v 3.9 1997/02/21 11:35:38 espie Exp espie $" ?
+ {
+ ="$Id: "
+ name ||:= tab(find(".icn,v"))
+ =".icn,v "
+ name ||:= " version "||tab(upto(' '))||move(1)||tab(upto(' '))
+ }
+ return name||" by Marc Espie (Marc.Espie@ens.fr)"
+end
+
+
+procedure new_game(r)
+
+ # build a playable game
+ repeat
+ {
+ every t(1 to n, 1 to m).color := ?r
+ if remains_move() then
+ break
+ }
+
+ every compute_connectivity(t(1 to n, 1 to m))
+
+ # draw initial setup
+ EraseArea(&window)
+ draw_smiley(smiley1)
+ every draw_tile(used_tiles())
+
+
+ # remove left over events from last game
+ while *Pending() > 0 do
+ Event()
+end
+
+
+procedure adjust_end_score()
+ # adjust end score
+ count := 0
+ every used_tiles() do
+ count +:= 1
+ if count > 0 then
+ {
+ draw_smiley(smiley2)
+ return -count
+ }
+ else
+ {
+ draw_smiley(smiley3)
+ return 1000
+ }
+end
+
+
+
+procedure main(L)
+ parms := []
+ color_mode := set()
+
+ # process all options
+ every p := !L do
+ map(p) ?
+ {
+ {=("-bw"|"-reduced"|"-pastel"|"-lighter"|"-darker") & pos(0) & insert(color_mode, tab(2)) }|
+ {=("-help"|"-h") & pos(0) & stop(usage())} |
+ {=("-v"|"-version") & pos(0) & stop(whoami())} |
+ {i := integer(tab(0)) & put(parms, i)} |
+ {any('-') & stop("Unknown option "||tab(0)||"\n"||usage())} |
+ # if we have a background image
+ {bgimage := WOpen("canvas=hidden", "image="||p, "gamma=1.0") &
+ # use our own flavour of EraseArea
+ EraseArea := my_erase_area} |
+ {stop("Can't load background image "||tab(0))}
+
+ }
+
+
+ r := get(parms) | 4
+ n := get(parms) | 10
+ m := get(parms) | n
+ last_random := get(parms) | map(&clock, ':', '9')
+ r <:= 2
+ n <:= 4
+ n >:= 40
+ m <:= 4
+ m >:= 40
+ &random := map(&clock, ':', '9')
+
+ # we have the game size and the background image,
+ # so we can open the window
+ setup_graphics(color_mode)
+ r >:= *colors
+ &random := last_random
+
+ while not (\last == "q") do
+ {
+ # setup for new game or replay
+ if \last == "r" then
+ {
+ /best_score := \score
+ &random := last_random
+ }
+ else
+ {
+ last_random := &random
+ best_score := &null
+ }
+ writes("Playing tiles ", r, " ", n, " ", m, " ",
+ left(&random, 12))
+
+ new_game(r)
+ lasti := &null
+ s := &null
+ changes := []
+ log := []
+ score := 0
+ write_score(score)
+
+ repeat
+ {
+ # either get pending event, or busy-peek the mouse pointer position
+ if *Pending() > 0 then
+ {
+ e := Event()
+ i := &x/tile_width+1
+ j := m - &y/tile_height
+ }
+ else
+ {
+ e := &null
+ i := WAttrib("pointerx")/tile_width+1
+ j := m - WAttrib("pointery")/tile_height
+ }
+
+ # check whether tile position changed
+ if (i = \lasti) & (j = \lastj) then
+ {
+ # if busy-peeking, add suitable delay
+ if /e then delay(50)
+ }
+ else
+ {
+ lasti := i
+ lastj := j
+ # build new connected set
+ sp := connected_set(s, i, j)
+
+ # if a new set
+ if sp ~=== s then
+ {
+ # un highlight old set (if needed)
+ draw_bevel_set(\s)
+ s := sp
+ # highlight new set
+ draw_bevel_set(\s, 1)
+ if *\s > 2 then
+ write_score(score||" (+"||(*s-2)*(*s-2)||")")
+ else
+ write_score(score)
+ }
+ }
+
+ if e === "c" then
+ {
+ setup_colors(color_mode)
+ if *\s < 2 then s := &null
+ every p := used_tiles() do
+ draw_tile(p, member(\s, p) | &null)
+ }
+
+ # check whether actually zapping
+ if e === (&lrelease | &mrelease | &rrelease) & *\s >= 2 then
+ {
+ push(changes, [score, remove_tiles(s)])
+ put(log, [i, j])
+ # adjust score
+ score +:= (*s-2)*(*s-2)
+ write_score(score)
+
+ # setup `virgin' highlighted set/position
+ lasti := &null
+ s := &null
+ e := &null
+
+ # check for end
+ if not remains_move() then
+ {
+ score +:= adjust_end_score()
+ if \best_score <:= score then
+ {
+ prompt := "Best "
+ best_log := log
+ }
+ else
+ prompt := "End "
+
+ write_score(prompt||score)
+ write(" Final score ", score)
+ last := user_entry()
+ if last == "u" then
+ {
+ EraseArea(0, 0, &null, WAttrib("leading")+10)
+ to_undo := pop(changes)
+ score := to_undo[1]
+ write_score(score)
+ draw_smiley(smiley1)
+ undo(to_undo[2])
+ }
+ else
+ break
+ }
+ }
+ if (
+ (e === (&lrelease | &mrelease | &rrelease) &
+ WAttrib("height")-SMILEY_SIZE < &y < WAttrib("height") &
+ WAttrib("width")-SMILEY_SIZE < &x < WAttrib("width")) |
+ e === "u"
+ ) & *changes > 0 then
+ {
+ draw_bevel_set(\s)
+ s := &null
+ lasti := &null
+ to_undo := pop(changes)
+ score := to_undo[1]
+ write_score(score)
+ undo(to_undo[2])
+ }
+ # check if user wants to quit prematurely
+ if e === "q" then
+ {
+ write_score("Sure ?")
+ e := Event()
+ if (e == ("o" | "y" | "q")) then
+ {
+ last := "q"
+ write()
+ break
+ }
+ else
+ write_score(score)
+ }
+ }
+ }
+end