REM
REM This is a port of my Go panel for ScriptBasic.
REM
REM The program does not actually play Go. But it allows to edit existing
REM Tsume Go problems and checks on atari and suicide.
REM
REM The reason of this port was to see how bigger programs were behaving in BaCon.
REM
REM April 23, 2009 - PvE - GPL.
REM November 3, 2009 - better library naming.
REM ----------------------------------------------------------------------------------------------------------------
TRAP LOCAL
CATCH GOTO Handle_Error
CONST Gtk = "libgtk-x11-2.0.so.0"
CONST Gdk = "libgdk-x11-2.0.so.0"
CONST Gobject = "libgobject-2.0.so.0"
IMPORT "g_signal_connect_data" FROM Gobject TYPE void
IMPORT "gdk_color_parse" FROM Gdk TYPE void
IMPORT "gdk_draw_arc" FROM Gdk TYPE void
IMPORT "gdk_draw_line(long, long, int, int, int, int)" FROM Gdk TYPE void
IMPORT "gdk_draw_rectangle" FROM Gdk TYPE void
IMPORT "gdk_gc_new" FROM Gdk TYPE long
IMPORT "gdk_gc_set_rgb_bg_color" FROM Gdk TYPE void
IMPORT "gdk_gc_set_rgb_fg_color" FROM Gdk TYPE void
IMPORT "gdk_pixmap_new" FROM Gdk TYPE long
IMPORT "gdk_window_get_pointer" FROM Gdk TYPE long
IMPORT "gtk_button_new_with_label" FROM Gtk TYPE long
IMPORT "gtk_container_add" FROM Gtk TYPE void
IMPORT "gtk_event_box_new" FROM Gtk TYPE long
IMPORT "gtk_exit" FROM Gtk TYPE void
IMPORT "gtk_frame_new" FROM Gtk TYPE long
IMPORT "gtk_frame_set_shadow_type" FROM Gtk TYPE void
IMPORT "gtk_image_new" FROM Gtk TYPE long
IMPORT "gtk_image_set_from_pixmap" FROM Gtk TYPE void
IMPORT "gtk_init" FROM Gtk TYPE void
IMPORT "gtk_main" FROM Gtk TYPE void
IMPORT "gtk_radio_button_new_with_label_from_widget" FROM Gtk TYPE long
IMPORT "gtk_statusbar_get_context_id" FROM Gtk TYPE long
IMPORT "gtk_statusbar_new" FROM Gtk TYPE long
IMPORT "gtk_statusbar_pop" FROM Gtk TYPE void
IMPORT "gtk_statusbar_push" FROM Gtk TYPE void
IMPORT "gtk_table_attach_defaults" FROM Gtk TYPE void
IMPORT "gtk_table_new" FROM Gtk TYPE long
IMPORT "gtk_toggle_button_get_active" FROM Gtk TYPE long
IMPORT "gtk_widget_get_parent_window" FROM Gtk TYPE long
IMPORT "gtk_widget_queue_draw" FROM Gtk TYPE void
IMPORT "gtk_widget_set_size_request" FROM Gtk TYPE void
IMPORT "gtk_widget_show_all" FROM Gtk TYPE void
IMPORT "gtk_window_new" FROM Gtk TYPE long
IMPORT "gtk_window_set_position" FROM Gtk TYPE void
IMPORT "gtk_window_set_title" FROM Gtk TYPE void
REM ----------------------------------------------------------------------------------------------------------------
SUB Draw_Board
LOCAL i, j TYPE int
REM Calculate square size
xfactor = ROUND(CANVAS_WIDTH/9)
yfactor = ROUND(CANVAS_HEIGHT/9)
REM Draw vertical axes
gdk_color_parse("#000000", col)
gdk_gc_set_rgb_fg_color(gc, col)
FOR i = xfactor/2 TO CANVAS_WIDTH - xfactor/2 STEP xfactor
gdk_draw_line(pix, gc, ROUND(i), ROUND(yfactor/2), ROUND(i), ROUND(yfactor/2)+yfactor*8)
NEXT i
REM Draw horizontal axes
FOR i = yfactor/2 TO CANVAS_HEIGHT - yfactor/2 STEP yfactor
gdk_draw_line(pix, gc, ROUND(xfactor/2), ROUND(i), ROUND(xfactor/2)+xfactor*8, ROUND(i))
NEXT i
REM Draw the positions of the stones
FOR i = 1 TO 9
FOR j = 1 TO 9
IF board[i][j] EQ BLACK_STONE THEN
gdk_color_parse("#000000", col)
gdk_gc_set_rgb_fg_color(gc, col)
gdk_draw_arc(pix, gc, 1, (i-1)*xfactor, (j-1)*yfactor, xfactor-1, yfactor-1, 0, 360*64)
ELIF board[i][j] EQ WHITE_STONE THEN
gdk_color_parse("#ffffff", col)
gdk_gc_set_rgb_fg_color(gc, col)
gdk_draw_arc(pix, gc, 1, (i-1)*xfactor, (j-1)*yfactor, xfactor-1, yfactor-1, 0, 360*64)
gdk_color_parse("#000000", col)
gdk_gc_set_rgb_fg_color(gc, col)
gdk_draw_arc(pix, gc, 0, (i-1)*xfactor, (j-1)*yfactor, xfactor-1, yfactor-1, 0, 360*64)
END IF
NEXT j
NEXT i
gtk_widget_queue_draw (canvas)
END SUB
REM ----------------------------------------------------------------------------------------------------------------
SUB New_Board
LOCAL i, j TYPE int
FOR j = 1 TO 9
FOR i = 1 TO 9
board[j][i] = EMPTY
NEXT i
NEXT j
gdk_color_parse("#ffffff", col)
gdk_gc_set_rgb_fg_color(gc, col)
gdk_draw_rectangle(pix, gc, 1, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT)
CALL Draw_Board
lastmovex = 0
lastmovey = 0
capturedbywhite = 0
capturedbyblack = 0
gtk_statusbar_pop(gostatus, cid)
gtk_statusbar_push(gostatus, cid, "New game started!")
END SUB
REM ----------------------------------------------------------------------------------------------------------------
SUB Captured_Stones
LOCAL i, j, group, freedoms, counter, curr, total TYPE int
LOCAL groups[11][11] TYPE int
LOCAL posx[82], posy[82] TYPE int
REM Wipe groups board
FOR j = 0 TO 10
FOR i = 0 TO 10
groups[j][i] = FAKE
NEXT i
NEXT j
REM Copy current playing board to groups board
FOR j = 1 TO 9
FOR i = 1 TO 9
groups[j][i] = board[j][i]
NEXT i
NEXT j
REM Clear temp array's keeping stone positions
FOR i = 1 TO 81
posx[i] = 0
posy[i] = 0
NEXT i
REM Initialize used variables
total = 0
FOR j = 1 TO 9
FOR i = 1 TO 9
REM Check: place is empty and is not the last color played
IF (ABS(groups[j][i]) NE EMPTY) AND (groups[j][i] NE board[lastmovex][lastmovey]) THEN
freedoms = 0
counter = 1
curr = 1
posx[curr] = j
posy[curr] = i
group = groups[j][i]
groups[j][i] = -5*group
REPEAT
IF groups[posx[curr]-1][posy[curr]] EQ EMPTY THEN
freedoms = freedoms + 1
ELIF groups[posx[curr]-1][posy[curr]] EQ group THEN
groups[posx[curr]-1][posy[curr]] = -5*group
counter = counter + 1
posx[counter] = posx[curr]-1
posy[counter] = posy[curr]
END IF
IF groups[posx[curr]+1][posy[curr]] EQ EMPTY THEN
freedoms = freedoms + 1
ELIF groups[posx[curr]+1][posy[curr]] EQ group THEN
groups[posx[curr]+1][posy[curr]] = -5*group
counter = counter + 1
posx[counter] = posx[curr]+1
posy[counter] = posy[curr]
END IF
IF groups[posx[curr]][posy[curr]-1] EQ EMPTY THEN
freedoms = freedoms + 1
ELIF groups[posx[curr]][posy[curr]-1] EQ group THEN
groups[posx[curr]][posy[curr]-1] = -5*group
counter = counter + 1
posx[counter] = posx[curr]
posy[counter] = posy[curr]-1
END IF
IF groups[posx[curr]][posy[curr]+1] EQ EMPTY THEN
freedoms = freedoms + 1
ELIF groups[posx[curr]][posy[curr]+1] EQ group THEN
groups[posx[curr]][posy[curr]+1] = -5*group
counter = counter + 1
posx[counter] = posx[curr]
posy[counter] = posy[curr]+1
END IF
curr = curr + 1
UNTIL curr > counter
IF freedoms EQ 0 THEN
counter = 1
curr = 1
posx[curr] = j
posy[curr] = i
group = groups[j][i]
groups[j][i] = EMPTY
board[j][i] = EMPTY
REPEAT
IF groups[posx[curr]-1][posy[curr]] EQ group THEN
groups[posx[curr]-1][posy[curr]] = EMPTY
board[posx[curr]-1][posy[curr]] = EMPTY
counter = counter + 1
posx[counter] = posx[curr]-1
posy[counter] = posy[curr]
END IF
IF groups[posx[curr]+1][posy[curr]] EQ group THEN
groups[posx[curr]+1][posy[curr]] = EMPTY
board[posx[curr]+1][posy[curr]] = EMPTY
counter = counter + 1
posx[counter] = posx[curr]+1
posy[counter] = posy[curr]
END IF
IF groups[posx[curr]][posy[curr]-1] EQ group THEN
groups[posx[curr]][posy[curr]-1] = EMPTY
board[posx[curr]][posy[curr]-1] = EMPTY
counter = counter + 1
posx[counter] = posx[curr]
posy[counter] = posy[curr]-1
END IF
IF groups[posx[curr]][posy[curr]+1] EQ group THEN
groups[posx[curr]][posy[curr]+1] = EMPTY
board[posx[curr]][posy[curr]+1] = EMPTY
counter = counter + 1
posx[counter] = posx[curr]
posy[counter] = posy[curr]+1
END IF
curr = curr + 1
UNTIL curr > counter
gdk_color_parse("#ffffff", col)
gdk_gc_set_rgb_fg_color(gc, col)
gdk_draw_rectangle( pix, gc, 1, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT)
CALL Draw_Board
total = total + counter
END IF
END IF
NEXT i
NEXT j
IF total > 0 THEN
gtk_statusbar_pop(gostatus, cid)
gtk_statusbar_push(gostatus, cid, CONCAT$(STR$(total), " stones captured!"))
END IF
IF board[lastmovex][lastmovey] EQ WHITE_STONE THEN
capturedbywhite = capturedbywhite + total
END IF
IF board[lastmovex][lastmovey] EQ BLACK_STONE THEN
capturedbyblack = capturedbyblack + total
END IF
END SUB
REM ----------------------------------------------------------------------------------------------------------------
SUB Determine_Suicide
LOCAL i, j, group, freedoms, counter, curr TYPE int
LOCAL groups[11][11] TYPE int
LOCAL posx[82], posy[82] TYPE int
REM Wipe groups board with fake value
FOR j = 0 TO 10
FOR i = 0 TO 10
groups[j][i] = FAKE
NEXT i
NEXT j
REM Copy current playing board to groups board
FOR j = 1 TO 9
FOR i = 1 TO 9
groups[j][i] = board[j][i]
NEXT i
NEXT j
REM Clear temp array's keeping stone positions
FOR i = 1 TO 81
posx[i] = 0
posy[i] = 0
NEXT i
REM Initialize local variables
freedoms = 0
counter = 1
curr = 1
posx[curr] = lastmovex
posy[curr] = lastmovey
group = groups[lastmovex][lastmovey]
groups[lastmovex][lastmovey] = -1*group
REPEAT
IF groups[posx[curr]-1][posy[curr]] EQ EMPTY THEN
freedoms = freedoms + 1
ELIF groups[posx[curr]-1][posy[curr]] EQ group THEN
groups[posx[curr]-1][posy[curr]] = -1*group
counter = counter + 1
posx[counter] = posx[curr]-1
posy[counter] = posy[curr]
END IF
IF groups[posx[curr]+1][posy[curr]] EQ EMPTY THEN
freedoms = freedoms + 1
ELIF groups[posx[curr]+1][posy[curr]] EQ group THEN
groups[posx[curr]+1][posy[curr]] = -1*group
counter = counter + 1
posx[counter] = posx[curr]+1
posy[counter] = posy[curr]
END IF
IF groups[posx[curr]][posy[curr]-1] EQ EMPTY THEN
freedoms = freedoms + 1
ELIF groups[posx[curr]][posy[curr]-1] EQ group THEN
groups[posx[curr]][posy[curr]-1] = -1*group
counter = counter + 1
posx[counter] = posx[curr]
posy[counter] = posy[curr]-1
END IF
IF groups[posx[curr]][posy[curr]+1] EQ EMPTY THEN
freedoms = freedoms + 1
ELIF groups[posx[curr]][posy[curr]+1] EQ group THEN
groups[posx[curr]][posy[curr]+1] = -1*group
counter = counter + 1
posx[counter] = posx[curr]
posy[counter] = posy[curr]+1
END IF
curr = curr + 1
UNTIL curr > counter
IF freedoms EQ 0 THEN
board[lastmovex][lastmovey] = EMPTY
gdk_color_parse("#ffffff", col)
gdk_gc_set_rgb_fg_color(gc, col)
gdk_draw_rectangle(pix, gc, 1, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT)
CALL Draw_Board
gtk_statusbar_pop(gostatus, cid)
gtk_statusbar_push(gostatus, cid, "This is an illegal move! Play again...")
END IF
END SUB
REM ----------------------------------------------------------------------------------------------------------------
REM Callback to put stone on board
SUB Put_Stone(NUMBER widget, NUMBER gdkeventbutton, NUMBER userdata)
LOCAL mousex, mousey, xfactor, yfactor TYPE int
LOCAL i, j TYPE int
win = gtk_widget_get_parent_window(widget)
gdk_window_get_pointer(win, ADDRESS(mousex), ADDRESS(mousey), 0)
xfactor = ROUND(CANVAS_WIDTH/9)
yfactor = ROUND(CANVAS_HEIGHT/9)
FOR j = 1 TO 9
FOR i = 1 TO 9
IF (mousex > (j-1)*xfactor+xfactor*0.5) AND (mousex < (j-1)*xfactor+xfactor*1.5) THEN
IF (mousey > (i-1)*yfactor+yfactor*0.5) AND (mousey < (i-1)*yfactor+yfactor*1.5) THEN
IF gtk_toggle_button_get_active(radioblack) EQ 1 THEN
IF board[j][i] EQ EMPTY THEN
board[j][i] = BLACK_STONE
gtk_statusbar_pop(gostatus, cid)
gtk_statusbar_push(gostatus, cid, "Black played.")
lastmovex = j
lastmovey = i
ELSE
gtk_statusbar_pop(gostatus, cid)
gtk_statusbar_push(gostatus, cid, "Cannot play here!")
END IF
ELSE
IF board[j][i] EQ EMPTY THEN
board[j][i] = WHITE_STONE
gtk_statusbar_pop(gostatus, cid)
gtk_statusbar_push(gostatus, cid, "White played.")
lastmovex = j
lastmovey = i
ELSE
gtk_statusbar_pop(gostatus, cid)
gtk_statusbar_push(gostatus, cid, "Cannot play here!")
END IF
END IF
END IF
END IF
NEXT i
NEXT j
CALL Draw_Board
CALL Captured_Stones
CALL Determine_Suicide
END SUB
REM ----------------------------------------------------------------------------------------------------------------
REM Callback for exit
SUB Exit_Prog
gtk_exit(0)
ENDSUB
REM ----------------------------------------------------------------------------------------------------------------
SUB Initialize_Global
LOCAL i, j TYPE int
REM This array keeps the current go-board, wipe Go playing board
FOR j = 1 TO 9
FOR i = 1 TO 9
board[i][j] = EMPTY
NEXT i
NEXT j
REM These keep the coordinates of the last move played
lastmovex = 0
lastmovey = 0
REM These keep the total amount of captured stones for each color
capturedbywhite = 0
capturedbyblack = 0
END SUB
REM ----------------------------------------------------------------------------------------------------------------
SUB Show_Prisoners
gtk_statusbar_pop(gostatus, cid)
gtk_statusbar_push(gostatus, cid, CONCAT$("Captured by white: ", STR$(capturedbywhite), " - Captured by black: ", STR$(capturedbyblack)))
END SUB
REM ----------------------------------------------------------------------------------------------------------------
SUB Create_Gopanel
gtk_init(0, 0)
gopanel = gtk_window_new(0)
gtk_window_set_title(gopanel, "The Go panel Revived")
gtk_window_set_position(gopanel, 1)
gtk_widget_set_size_request(gopanel, 300, 350)
g_signal_connect_data(gopanel, "delete-event", Exit_Prog, 0, 0, 0)
gogrid = gtk_table_new(55, 50, 1)
gtk_container_add(gopanel, gogrid)
frame = gtk_frame_new(0)
gtk_table_attach_defaults(gogrid, frame, 1, 49, 1, 43)
gtk_frame_set_shadow_type(frame, 3)
canvas = gtk_image_new()
REM Create eventbox to catch mouseclick
ebox = gtk_event_box_new()
gtk_container_add(ebox, canvas)
gtk_table_attach_defaults(gogrid, ebox, 2, 48, 2, 42)
REM Connect mouse button signal to image
g_signal_connect_data(ebox, "button-press-event", Put_Stone, 0, 0, 0)
radioblack = gtk_radio_button_new_with_label_from_widget(0, "Black")
gtk_table_attach_defaults(gogrid, radioblack, 24, 36, 44, 47)
radiowhite = gtk_radio_button_new_with_label_from_widget(radioblack, "White")
gtk_table_attach_defaults(gogrid, radiowhite, 24, 36, 48, 51)
buttoncapt = gtk_button_new_with_label("Show\nprison")
gtk_table_attach_defaults(gogrid, buttoncapt, 12, 22, 44, 50)
g_signal_connect_data(buttoncapt, "clicked", Show_Prisoners, 0, 0, 0)
newbutton = gtk_button_new_with_label("New")
gtk_table_attach_defaults(gogrid, newbutton, 1, 11, 44, 50)
g_signal_connect_data(newbutton, "clicked", New_Board, 0, 0, 0)
quitbutton = gtk_button_new_with_label("Quit")
gtk_table_attach_defaults(gogrid, quitbutton, 41, 49, 44, 50)
g_signal_connect_data(quitbutton, "clicked", Exit_Prog, 0, 0, 0)
gostatus = gtk_statusbar_new()
gtk_table_attach_defaults(gogrid, gostatus, 0, 50, 52, 55)
cid = gtk_statusbar_get_context_id(gostatus, gopanel)
gtk_statusbar_push(gostatus, cid, "New game started!")
gtk_widget_show_all(gopanel)
REM Create the pixmap
gdkwin = gtk_widget_get_parent_window(canvas)
pix = gdk_pixmap_new(gdkwin, CANVAS_WIDTH, CANVAS_HEIGHT, -1)
gc = gdk_gc_new(pix)
gtk_image_set_from_pixmap(canvas, pix, 0)
REM Allocate memory for GdkColor with some random widget
col = gtk_frame_new(0)
REM Now set foreground and backgroundcolors to WHITE
gdk_color_parse("#ffffff", col)
gdk_gc_set_rgb_bg_color(gc, col)
gdk_gc_set_rgb_fg_color(gc, col)
REM Clear the complete pixmap with WHITE
gdk_draw_rectangle(pix, gc, 1, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT)
REM Show whole GUI
gtk_widget_show_all(gopanel)
END SUB
REM ----------------------------------------------------------------------------------------------------------------
REM Some globals
DECLARE board[10][10] TYPE int
CONST FAKE = 12345
CONST EMPTY = 0
CONST WHITE_STONE = -1
CONST BLACK_STONE = 1
CONST GROUPIDSTART = 10
CONST CANVAS_WIDTH = 275
CONST CANVAS_HEIGHT = 246
Create_Gopanel
Draw_Board
gtk_main
END
REM ----------------------------------------------------------------------------------------------------------------
LABEL Handle_Error
PRINT ERR$(ERROR)
END